tracklib/decode/
varint.rs

1use nom::{Context, IResult, Err, ErrorKind, Needed, take};
2
3pub const CONTINUATION_BIT: u8 = 1 << 7;
4pub const SIGN_BIT: u8 = 1 << 6;
5
6pub(crate) fn take_unsigned_leb128(i: &[u8]) -> IResult<&[u8], u64> {
7    let mut result: u64 = 0;
8    let mut remainder = i;
9    let mut shift = 0;
10
11    let mut byte;
12
13    loop {
14        match take!(remainder, 1) {
15            Ok((rest, bytes)) => {
16                remainder = rest;
17                byte = bytes[0];
18
19                if shift == 63 && byte != 0b0000_0000 && byte != 0b0000_0001 {
20                    return Err(Err::Error(Context::Code(i, ErrorKind::Custom(0))))
21                }
22
23                let low_bits = (byte & !CONTINUATION_BIT) as u64;
24
25                result |= low_bits << shift;
26                shift += 7;
27
28                if byte & CONTINUATION_BIT == 0 {
29                    return Ok((remainder, result))
30                }
31            }
32            Err(_) => return Err(Err::Incomplete(Needed::Unknown))
33        }
34    }
35}
36
37pub(crate) fn take_signed_leb128(i: &[u8]) -> IResult<&[u8], i64> {
38    let mut result: i64 = 0;
39    let size = 64;
40    let mut remainder = i;
41    let mut shift = 0;
42
43    let mut byte;
44
45    loop {
46        match take!(remainder, 1) {
47            Ok((rest, bytes)) => {
48                remainder = rest;
49                byte = bytes[0];
50
51                if shift == 63 && byte != 0b0000_0000 && byte != 0b0111_1111 {
52                    return Err(Err::Error(Context::Code(i, ErrorKind::Custom(0))))
53                }
54
55                let low_bits = (byte & !CONTINUATION_BIT) as i64;
56
57                result |= low_bits << shift;
58                shift += 7;
59
60                if byte & CONTINUATION_BIT == 0 {
61                    break;
62                }
63            }
64            Err(_) => return Err(Err::Incomplete(Needed::Unknown))
65        }
66    }
67
68    // sign extend the result
69    if shift < size && (SIGN_BIT & byte) == SIGN_BIT {
70        result |= !0 << shift;
71    }
72
73    return Ok((remainder, result));
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79
80    fn signed_helper(n: i64) {
81        let mut buf = vec![];
82        assert!(leb128::write::signed(&mut buf, n).is_ok());
83        let r = take_signed_leb128(&buf);
84        assert!(r.is_ok());
85        let (rest, d) = r.unwrap();
86        assert_eq!(0, rest.len());
87        assert_eq!(n, d);
88    }
89
90    #[test]
91    fn test_signed_roundtrips() {
92        signed_helper(0);
93        signed_helper(1);
94        signed_helper(-1);
95        signed_helper(50);
96        signed_helper(-50);
97        signed_helper(500);
98        signed_helper(-500);
99        signed_helper(std::i16::MIN as i64);
100        signed_helper(std::i16::MAX as i64);
101        signed_helper(std::i32::MIN as i64);
102        signed_helper(std::i32::MAX as i64);
103        signed_helper(std::i64::MIN as i64);
104        signed_helper(std::i64::MAX as i64);
105    }
106
107    fn unsigned_helper(n: u64) {
108        let mut buf = vec![];
109        assert!(leb128::write::unsigned(&mut buf, n).is_ok());
110        let r = take_unsigned_leb128(&buf);
111        assert!(r.is_ok());
112        let (rest, d) = r.unwrap();
113        assert_eq!(0, rest.len());
114        assert_eq!(n, d);
115    }
116
117    #[test]
118    fn test_unsigned_roundtrips() {
119        unsigned_helper(0);
120        unsigned_helper(1);
121        unsigned_helper(50);
122        unsigned_helper(500);
123        unsigned_helper(std::u16::MAX as u64);
124        unsigned_helper(std::u32::MAX as u64);
125        unsigned_helper(std::u64::MAX as u64);
126    }
127}