Skip to main content

basn1/
intenc.rs

1//! Integer encoding used in ASN.1
2//!
3//! * 7bit highest-continuation encoding
4//! * 8bit variable encoding encoding slice
5
6/// A simple encoded variable size integer where limbs
7/// are 7 bits, and big endian, and continuation of
8/// the encoding is indicated by having the highest bit set
9#[derive(Debug, PartialEq, Eq, Hash)]
10pub(crate) struct IntegerContBit7([u8]);
11
12macro_rules! to_primitive7 {
13    ($type: ident, $name: ident) => {
14        /// Try to convert to the primitive
15        ///
16        /// If there's an overflown then nothing is returned
17        pub fn $name(&self) -> Option<$type> {
18            // this function assume that the data has been checked properly
19            // so that the first byte is not a long zero,
20            // and that the continuation bit are correctly set
21            // for each byte limb.
22            let mut acc = (self.0[0] & 0b0111_1111) as $type;
23            for c in &self.0[1..] {
24                acc = acc
25                    .checked_shl(7)?
26                    .checked_add((c & 0b0111_1111) as $type)?
27            }
28            Some(acc)
29        }
30    };
31}
32
33impl IntegerContBit7 {
34    /// transform a raw slice into a IntegerContBit7 slice,
35    /// no verification is done by this call
36    /// one should use parse_from_slice for safe parsing+verification
37    pub(crate) fn unverified_from_slice(slice: &[u8]) -> &Self {
38        cast_slice_u8_to_typed_slice!(slice, Self)
39    }
40
41    /// Try to parse from a slice
42    pub fn parse_from_slice(slice: &[u8]) -> Result<(&Self, usize), ()> {
43        if slice.is_empty() {
44            return Err(());
45        }
46        if slice[0] == 0b1000_0000 {
47            return Err(());
48        }
49        let mut i = 0;
50        while (slice[i] & 0b1000_0000) != 0 {
51            i += 1;
52            if i == slice.len() {
53                return Err(());
54            }
55        }
56        let r = Self::unverified_from_slice(&slice[0..1 + i]);
57        Ok((r, 1 + i))
58    }
59
60    to_primitive7!(u128, to_u128);
61    to_primitive7!(u64, to_u64);
62    to_primitive7!(u32, to_u32);
63    to_primitive7!(u16, to_u16);
64    to_primitive7!(u8, to_u8);
65
66    /*
67    pub fn as_be() -> BeIntegerBytes<'a> {
68        todo!()
69    }
70
71    pub fn as_le() -> LeIntegerBytes<'a> {
72        todo!()
73    }
74    */
75}
76
77slice_reexport_asref!(IntegerContBit7);
78
79/// An encoded integer where each limbs is 8bits and in big endian
80#[derive(Debug, PartialEq, Eq, Hash)]
81pub(crate) struct Integer8Bit([u8]);
82
83macro_rules! to_primitive8 {
84    ($type: ident, $name: ident) => {
85        /// Try to convert to the primitive
86        ///
87        /// If there's an overflown then nothing is returned
88        pub fn $name(&self) -> Option<$type> {
89            // this function assume that the data has been checked properly
90            // so that the first byte is not a long zero,
91            // and that the continuation bit are correctly set
92            // for each byte limb.
93            let mut acc = self.0[0] as $type;
94            for c in &self.0[1..] {
95                acc = acc.checked_shl(8)?.checked_add(*c as $type)?
96            }
97            Some(acc)
98        }
99    };
100}
101
102impl Integer8Bit {
103    /// transform a raw slice into a Integer8Bit slice,
104    /// no verification is done by this call
105    pub(crate) fn unverified_from_slice(slice: &[u8]) -> &Self {
106        cast_slice_u8_to_typed_slice!(slice, Self)
107    }
108
109    /// Try to parse from a slice
110    pub fn from_slice(slice: &[u8]) -> Result<&Self, ()> {
111        if slice.is_empty() || slice[0] == 0 {
112            return Err(());
113        }
114        Ok(Self::unverified_from_slice(slice))
115    }
116
117    to_primitive8!(u128, to_u128);
118    to_primitive8!(u64, to_u64);
119    to_primitive8!(u32, to_u32);
120    to_primitive8!(u16, to_u16);
121    to_primitive8!(u8, to_u8);
122
123    /*
124    pub fn as_be() -> BeIntegerBytes<'a> {}
125
126    pub fn as_le() -> LeIntegerBytes<'a> {
127        todo!()
128    }
129    */
130}
131
132slice_reexport_asref!(Integer8Bit);