asnom 0.1.0

A ASN.1 BER Parser&Writer based on Nom
Documentation
use structure::{StructureTag, PL};
use common::TagStructure;
use common::TagClass;

use nom;
use nom::InputLength;

named!(class_bits<(&[u8], usize), TagClass>,
    map_opt!(
        take_bits!(u8, 2),
        TagClass::from_u8
    )
);

named!(pc_bit<(&[u8], usize), TagStructure>,
    map_opt!(
        take_bits!(u8, 1),
        TagStructure::from_u8
    )
);

named!(tagnr_bits<(&[u8], usize), u64>,
    take_bits!(u64, 5)
);

named!(pub parse_type_header<(TagClass, TagStructure, u64)>, bits!(
    do_parse!(
        class: class_bits >>
        pc: pc_bit >>
        tagnr: tagnr_bits >>
        ((class, pc, tagnr))
   )
));

named!(pub parse_length<u64>,
    alt!(
        bits!(
            do_parse!(
                // Short length form
                tag_bits!(u8, 1, 0u8) >>
                len: take_bits!(u64, 7) >>
                (len)
            )
        )
    |
        length_value!(
            bits!(
                do_parse!(
                    /* // TODO: Fix nom to be able to do this.
                     *return_error!(nom::ErrorKind::Custom(1),
                     *    not!(tag_bits!(u8, 8, 255u8))
                     *) >>
                     */
                    // Long length form
                    tag_bits!(u8, 1, 1u8) >>
                    len: take_bits!(u8, 7) >>
                    (len)
                )
            ),
            parse_uint
        )
    )
);



pub fn parse_uint(i: &[u8]) -> nom::IResult<&[u8], u64> {
    match i.len() {
        1 => nom::be_u8(i).map(|x| x as u64),
        2 => nom::be_u16(i).map(|x| x as u64),
        3 => nom::be_u32(i).map(|x| x as u64),
        8 => nom::be_u64(i),
        _ => unimplemented!()
    }
}

pub fn parse_tag(i: &[u8]) -> nom::IResult<&[u8], StructureTag> {
    let (mut i, ((class, structure, id),len)) = try_parse!(i, do_parse!(
        hdr: parse_type_header >>
        len: parse_length >>
        ((hdr, len))
    ));

    let pl: PL = match structure {
        TagStructure::Primitive => {
            let (j, content) = try_parse!(i, length_data!(value!(len)));
            i = j;

            PL::P(content.to_vec())
        }
        TagStructure::Constructed => {
            let (j, mut content) = try_parse!(i, length_bytes!(value!(len)));
            i = j;

            let mut tv: Vec<StructureTag> = Vec::new();
            while content.input_len() > 0 {
                let pres = try_parse!(content, call!(parse_tag));
                content = pres.0;
                let res: StructureTag = pres.1;
                tv.push(res);
            }

            PL::C(tv)
        }
    };

    nom::IResult::Done(i, StructureTag {
        class: class,
        id: id,
        payload: pl,
    })
}

#[cfg(test)]
mod test {
    use super::*;
    use nom::IResult;
    use common::{TagClass, TagStructure};
    use structure::{StructureTag, PL};

    #[test]
    fn test_primitive() {
        let bytes: Vec<u8> = vec![2, 2, 255, 127];
        let result_tag = StructureTag {
            class: TagClass::Universal,
            id: 2u64,
            payload: PL::P( vec![255,127] )
        };
        let rest_tag: Vec<u8> = vec![];

        let tag = parse_tag(&bytes[..]);

        assert_eq!(tag, IResult::Done(&rest_tag[..], result_tag));
    }

    #[test]
    fn test_constructed() {
        let bytes: Vec<u8> = vec![48,14,12,12,72,101,108,108,111,32,87,111,114,108,100,33];
        let result_tag = StructureTag {
            class: TagClass::Universal,
            id: 16u64,
            payload: PL::C(vec![StructureTag {
                class: TagClass::Universal,
                id: 12u64,
                payload: PL::P(vec![72,101,108,108,111,32,87,111,114,108,100,33]),
            }]),
        };
        let rest_tag: Vec<u8> = vec![];

        let tag = parse_tag(&bytes[..]);

        assert_eq!(tag, IResult::Done(&rest_tag[..], result_tag));
    }

    #[test]
    fn test_long_length() {
        let bytes: Vec<u8> = vec![
            0x30, 0x82, 0x01, 0x01,
            0x80, 0x0C, 0x4A, 0x75,
            0x73, 0x74, 0x41, 0x4C,
            0x6F, 0x6E, 0x67, 0x54,
            0x61, 0x67, 0x81, 0x81,
            0xF0, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67,
        ];

        let result_tag = StructureTag {
            class: TagClass::Universal,
            id: 16u64,
            payload: PL::C(vec![StructureTag {
                class: TagClass::Context,
                id: 0,
                payload: PL::P(vec![74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103])
            },
            StructureTag {
                class: TagClass::Context,
                id: 1,
                payload: PL::P(vec![74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103, 74, 117, 115, 116, 65, 76, 111, 110, 103, 84, 97, 103])
            }]),
        };

        let rest_tag = Vec::new();

        let tag = parse_tag(&bytes[..]);
        assert_eq!(tag, IResult::Done(&rest_tag[..], result_tag));

    }
}