rw_utils/
leb128_read.rs

1use std::io;
2use std::io::{ErrorKind, Read};
3use std::mem::size_of;
4
5///
6/// Trait that provides various methods to read leb128 (little endian base 128) encoded numbers.
7/// Automatically implemented for all implementations of io::Read.
8/// This trait is sealed and cannot be implemented manually.
9///
10pub trait Leb128Read : private::Sealed {
11    ///
12    /// Reads a unsigned leb128 as u16.
13    /// Fails if the leb128 doesn't fit.
14    ///
15    fn read_leb128_u16(&mut self) -> io::Result<u16>;
16
17    ///
18    /// Reads a signed leb128 as i16.
19    /// Fails if the leb128 doesn't fit.
20    ///
21    fn read_leb128_i16(&mut self) -> io::Result<i16>;
22
23    ///
24    /// Reads a unsigned leb128 as u32.
25    /// Fails if the leb128 doesn't fit.
26    ///
27    fn read_leb128_u32(&mut self) -> io::Result<u32>;
28
29    ///
30    /// Reads a signed leb128 as i32.
31    /// Fails if the leb128 doesn't fit.
32    ///
33    fn read_leb128_i32(&mut self) -> io::Result<i32>;
34
35    ///
36    /// Reads a unsigned leb128 as u64.
37    /// Fails if the leb128 doesn't fit.
38    ///
39    fn read_leb128_u64(&mut self) -> io::Result<u64>;
40
41    ///
42    /// Reads a signed leb128 as i64.
43    /// Fails if the leb128 doesn't fit.
44    ///
45    fn read_leb128_i64(&mut self) -> io::Result<i64>;
46
47    ///
48    /// Reads a unsigned leb128 as u128.
49    /// Fails if the leb128 doesn't fit.
50    ///
51    fn read_leb128_u128(&mut self) -> io::Result<u128>;
52
53    ///
54    /// Reads a signed leb128 as i128.
55    /// Fails if the leb128 doesn't fit.
56    ///
57    fn read_leb128_i128(&mut self) -> io::Result<i128>;
58
59    ///
60    /// Reads a signed leb128 of arbitrary length.
61    /// The returned value is always in little endian.
62    /// The max_size parameter controls the maximum size of the returned Vec, not the amount of data to be read.
63    ///
64    fn read_leb128_large_signed(&mut self, max_size: usize) -> io::Result<Vec<u8>>;
65
66    ///
67    /// Reads an unsigned leb128 of arbitrary length.
68    /// The returned value is always in little endian.
69    /// The max_size parameter controls the maximum size of the returned Vec, not the amount of data to be read.
70    ///
71    fn read_leb128_large_unsigned(&mut self, max_size: usize) -> io::Result<Vec<u8>>;
72}
73
74fn next<T: Read>(s: &mut T) -> io::Result<u8> {
75    let mut buf = [0u8];
76    s.read_exact(buf.as_mut_slice())?;
77    return Ok(buf[0]);
78}
79
80fn finish_large_leb_read(mut shift: u32, mut acc: u64, max_size: usize, mut result: Vec<u8>, is_negative: bool) -> io::Result<Vec<u8>> {
81    while shift > 0 {
82        shift = shift.saturating_sub(8);
83
84        let to_push = (acc & 0xFFu64) as u8;
85
86        if result.len()+1 > max_size {
87            if shift != 0 {
88                return Err(io::Error::new(ErrorKind::InvalidData, "leb128 larger than desired maximum size"));
89            }
90
91            if is_negative {
92                if to_push == u8::MAX {
93                    //0xFF leading in twos complement can be discarded.
94                    return Ok(result);
95                }
96            } else {
97                if to_push == u8::MIN {
98                    //Leading 0 bytes are not needed and don't count.
99                    return Ok(result);
100                }
101            }
102
103            return Err(io::Error::new(ErrorKind::InvalidData, "leb128 larger than desired maximum size"));
104        }
105        result.push(to_push);
106        acc >>= 8;
107    }
108
109    return Ok(result);
110}
111
112fn push_next_large_leb_block(result : &mut Vec<u8>, max_size: usize, acc: u64) -> io::Result<()>{
113    if result.len()+7 > max_size {
114        return Err(io::Error::new(ErrorKind::InvalidData, "leb128 larger than desired maximum size"));
115    }
116    result.push(((acc >> 0) & 0xFFu64) as u8);
117    result.push(((acc >> 8) & 0xFFu64) as u8);
118    result.push(((acc >> 16) & 0xFFu64) as u8);
119    result.push(((acc >> 24) & 0xFFu64) as u8);
120    result.push(((acc >> 32) & 0xFFu64) as u8);
121    result.push(((acc >> 40) & 0xFFu64) as u8);
122    result.push(((acc >> 48) & 0xFFu64) as u8);
123    return Ok(());
124}
125
126
127macro_rules! read_unsigned_leb {
128    ($type:ty, $name:ident, $err:expr) => {
129        fn $name(&mut self) -> io::Result<$type> {
130            let mut acc : $type = 0;
131            let mut shift = 0u32;
132            let size = (size_of::<$type>() * 8) as u32;
133            loop {
134                if shift >= size {
135                    return Err(io::Error::new(ErrorKind::InvalidData, $err));
136                }
137                let n : u8 = next(self)?;
138                acc |= ((n & 0b0111_1111u8) as $type) << shift;
139                shift+=7;
140                if n & 0b1000_0000u8 == 0 {
141                    return Ok(acc);
142                }
143            }
144        }
145    }
146}
147
148macro_rules! read_signed_leb {
149    ($type:ty, $helper:ty, $name:ident, $err:expr) => {
150        fn $name(&mut self) -> io::Result<$type> {
151            let mut acc : $helper = 0;
152            let mut shift = 0u32;
153            let size = (size_of::<$helper>() * 8) as u32;
154            loop {
155                if shift >= size {
156                    return Err(io::Error::new(ErrorKind::InvalidData, $err));
157                }
158                let n : u8 = next(self)?;
159                acc |= ((n & 0b0111_1111u8) as $helper) << shift;
160
161                shift+=7;
162                if n & 0b1000_0000u8 == 0 {
163                    if n & 0b0100_0000u8 != 0 && shift < size{
164                        let ext : $helper = 1;
165                        acc |= !((ext << shift) -1);
166                    }
167                    return Ok(acc as $type);
168                }
169            }
170        }
171    }
172}
173
174impl <T> Leb128Read for T where T: Read {
175
176    read_signed_leb!(i16, u16, read_leb128_i16, "leb128 larger than i16");
177    read_signed_leb!(i32, u32, read_leb128_i32, "leb128 larger than i32");
178    read_signed_leb!(i64, u64, read_leb128_i64, "leb128 larger than i64");
179    read_signed_leb!(i128, u128, read_leb128_i128, "leb128 larger than i128");
180
181    read_unsigned_leb!(u16, read_leb128_u16, "leb128 larger than u16");
182    read_unsigned_leb!(u32, read_leb128_u32, "leb128 larger than u32");
183    read_unsigned_leb!(u64, read_leb128_u64, "leb128 larger than u64");
184    read_unsigned_leb!(u128, read_leb128_u128, "leb128 larger than u128");
185    fn read_leb128_large_signed(&mut self, max_size: usize) -> io::Result<Vec<u8>> {
186        let mut acc : u64 = 0;
187        let mut shift = 0u32;
188        let mut result : Vec<u8> = Vec::with_capacity(max_size);
189        loop {
190            if shift >= 54 {
191                push_next_large_leb_block(&mut result, max_size, acc)?;
192                shift = 0;
193                acc = 0;
194            }
195            let n : u8 = next(self)?;
196            acc |= ((n & 0b0111_1111u8) as u64) << shift;
197            shift+=7;
198            if n & 0b1000_0000u8 == 0 {
199                if n & 0b0100_0000u8 != 0 {
200                    acc |= !((1u64 << shift) -1);
201                    return finish_large_leb_read(shift, acc, max_size, result, true);
202                }
203
204                return finish_large_leb_read(shift, acc, max_size, result, false);
205            }
206        }
207    }
208
209    fn read_leb128_large_unsigned(&mut self, max_size: usize) -> io::Result<Vec<u8>> {
210        let mut acc : u64 = 0;
211        let mut shift = 0u32;
212        let mut result : Vec<u8> = Vec::with_capacity(max_size);
213        loop {
214            if shift >= 54 {
215                push_next_large_leb_block(&mut result, max_size, acc)?;
216                shift = 0;
217                acc = 0;
218            }
219            let n : u8 = next(self)?;
220            acc |= ((n & 0b0111_1111u8) as u64) << shift;
221            shift+=7;
222            if n & 0b1000_0000u8 == 0 {
223                return finish_large_leb_read(shift, acc, max_size, result, false);
224            }
225        }
226    }
227}
228
229mod private {
230    use std::io::Read;
231
232    impl <T> Sealed for T where T: Read {}
233    pub trait Sealed {
234
235    }
236}