]>
Commit | Line | Data |
---|---|---|
2c00a5a8 | 1 | macro_rules! impl_write_unsigned_leb128 { |
dfeec247 | 2 | ($fn_name:ident, $int_ty:ident) => { |
2c00a5a8 | 3 | #[inline] |
8faf50e0 | 4 | pub fn $fn_name(out: &mut Vec<u8>, mut value: $int_ty) { |
74b04a01 XL |
5 | loop { |
6 | if value < 0x80 { | |
7 | out.push(value as u8); | |
2c00a5a8 | 8 | break; |
74b04a01 XL |
9 | } else { |
10 | out.push(((value & 0x7f) | 0x80) as u8); | |
11 | value >>= 7; | |
2c00a5a8 XL |
12 | } |
13 | } | |
9cc50fc6 | 14 | } |
dfeec247 | 15 | }; |
476ff2be SL |
16 | } |
17 | ||
2c00a5a8 XL |
18 | impl_write_unsigned_leb128!(write_u16_leb128, u16); |
19 | impl_write_unsigned_leb128!(write_u32_leb128, u32); | |
20 | impl_write_unsigned_leb128!(write_u64_leb128, u64); | |
21 | impl_write_unsigned_leb128!(write_u128_leb128, u128); | |
22 | impl_write_unsigned_leb128!(write_usize_leb128, usize); | |
23 | ||
2c00a5a8 | 24 | macro_rules! impl_read_unsigned_leb128 { |
dfeec247 | 25 | ($fn_name:ident, $int_ty:ident) => { |
2c00a5a8 XL |
26 | #[inline] |
27 | pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) { | |
74b04a01 | 28 | let mut result = 0; |
2c00a5a8 XL |
29 | let mut shift = 0; |
30 | let mut position = 0; | |
74b04a01 XL |
31 | loop { |
32 | let byte = slice[position]; | |
2c00a5a8 | 33 | position += 1; |
2c00a5a8 | 34 | if (byte & 0x80) == 0 { |
74b04a01 XL |
35 | result |= (byte as $int_ty) << shift; |
36 | return (result, position); | |
37 | } else { | |
38 | result |= ((byte & 0x7F) as $int_ty) << shift; | |
2c00a5a8 XL |
39 | } |
40 | shift += 7; | |
41 | } | |
2c00a5a8 | 42 | } |
dfeec247 | 43 | }; |
9cc50fc6 SL |
44 | } |
45 | ||
2c00a5a8 XL |
46 | impl_read_unsigned_leb128!(read_u16_leb128, u16); |
47 | impl_read_unsigned_leb128!(read_u32_leb128, u32); | |
48 | impl_read_unsigned_leb128!(read_u64_leb128, u64); | |
49 | impl_read_unsigned_leb128!(read_u128_leb128, u128); | |
50 | impl_read_unsigned_leb128!(read_usize_leb128, usize); | |
51 | ||
476ff2be SL |
52 | #[inline] |
53 | /// encodes an integer using signed leb128 encoding and stores | |
54 | /// the result using a callback function. | |
55 | /// | |
56 | /// The callback `write` is called once for each position | |
57 | /// that is to be written to with the byte to be encoded | |
58 | /// at that position. | |
8faf50e0 | 59 | pub fn write_signed_leb128_to<W>(mut value: i128, mut write: W) |
dfeec247 XL |
60 | where |
61 | W: FnMut(u8), | |
476ff2be | 62 | { |
9cc50fc6 SL |
63 | loop { |
64 | let mut byte = (value as u8) & 0x7f; | |
65 | value >>= 7; | |
dfeec247 XL |
66 | let more = |
67 | !(((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && ((byte & 0x40) != 0))); | |
32a655c1 | 68 | |
9cc50fc6 SL |
69 | if more { |
70 | byte |= 0x80; // Mark this byte to show that more bytes will follow. | |
71 | } | |
72 | ||
8faf50e0 | 73 | write(byte); |
9cc50fc6 SL |
74 | |
75 | if !more { | |
76 | break; | |
77 | } | |
78 | } | |
476ff2be SL |
79 | } |
80 | ||
b7449926 | 81 | #[inline] |
8faf50e0 | 82 | pub fn write_signed_leb128(out: &mut Vec<u8>, value: i128) { |
74b04a01 | 83 | write_signed_leb128_to(value, |v| out.push(v)) |
9cc50fc6 SL |
84 | } |
85 | ||
c30ab7b3 | 86 | #[inline] |
32a655c1 | 87 | pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i128, usize) { |
9cc50fc6 SL |
88 | let mut result = 0; |
89 | let mut shift = 0; | |
90 | let mut position = start_position; | |
91 | let mut byte; | |
92 | ||
93 | loop { | |
94 | byte = data[position]; | |
95 | position += 1; | |
dc9dc135 | 96 | result |= i128::from(byte & 0x7F) << shift; |
9cc50fc6 SL |
97 | shift += 7; |
98 | ||
99 | if (byte & 0x80) == 0 { | |
100 | break; | |
101 | } | |
102 | } | |
103 | ||
104 | if (shift < 64) && ((byte & 0x40) != 0) { | |
105 | // sign extend | |
32a655c1 | 106 | result |= -(1 << shift); |
9cc50fc6 SL |
107 | } |
108 | ||
109 | (result, position - start_position) | |
110 | } |