tracklib/decode/
varint.rs1use 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 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}