Coverage Report

Created: 2025-07-18 06:08

/rust/registry/src/index.crates.io-6f17d22bba15001f/scroll-0.10.2/src/leb128.rs
Line
Count
Source (jump to first uncovered line)
1
use core::u8;
2
use core::convert::{From, AsRef};
3
use core::result;
4
use crate::Pread;
5
use crate::ctx::TryFromCtx;
6
use crate::error;
7
8
#[derive(Debug, PartialEq, Copy, Clone)]
9
/// An unsigned leb128 integer
10
pub struct Uleb128 {
11
    value: u64,
12
    count: usize,
13
}
14
15
impl Uleb128 {
16
    #[inline]
17
    /// Return how many bytes this Uleb128 takes up in memory
18
0
    pub fn size(&self) -> usize {
19
0
        self.count
20
0
    }
21
    #[inline]
22
    /// Read a variable length u64 from `bytes` at `offset`
23
0
    pub fn read(bytes: &[u8], offset: &mut usize) -> error::Result<u64> {
24
0
        let tmp = bytes.pread::<Uleb128>(*offset)?;
25
0
        *offset += tmp.size();
26
0
        Ok(tmp.into())
27
0
    }
28
}
29
30
impl AsRef<u64> for Uleb128 {
31
0
    fn as_ref(&self) -> &u64 {
32
0
        &self.value
33
0
    }
34
}
35
36
impl From<Uleb128> for u64 {
37
    #[inline]
38
0
    fn from(uleb128: Uleb128) -> u64 {
39
0
        uleb128.value
40
0
    }
41
}
42
43
#[derive(Debug, PartialEq, Copy, Clone)]
44
/// An signed leb128 integer
45
pub struct Sleb128 {
46
    value: i64,
47
    count: usize,
48
}
49
50
impl Sleb128 {
51
    #[inline]
52
    /// Return how many bytes this Sleb128 takes up in memory
53
0
    pub fn size(&self) -> usize {
54
0
        self.count
55
0
    }
56
    #[inline]
57
    /// Read a variable length i64 from `bytes` at `offset`
58
0
    pub fn read(bytes: &[u8], offset: &mut usize) -> error::Result<i64> {
59
0
        let tmp = bytes.pread::<Sleb128>(*offset)?;
60
0
        *offset += tmp.size();
61
0
        Ok(tmp.into())
62
0
    }
63
}
64
65
impl AsRef<i64> for Sleb128 {
66
0
    fn as_ref(&self) -> &i64 {
67
0
        &self.value
68
0
    }
69
}
70
71
impl From<Sleb128> for i64 {
72
    #[inline]
73
0
    fn from(sleb128: Sleb128) -> i64 {
74
0
        sleb128.value
75
0
    }
76
}
77
78
// Below implementation heavily adapted from: https://github.com/fitzgen/leb128
79
const CONTINUATION_BIT: u8 = 1 << 7;
80
const SIGN_BIT: u8 = 1 << 6;
81
82
#[inline]
83
0
fn mask_continuation(byte: u8) -> u8 {
84
0
    byte & !CONTINUATION_BIT
85
0
}
86
87
// #[inline]
88
// fn mask_continuation_u64(val: u64) -> u8 {
89
//     let byte = val & (u8::MAX as u64);
90
//     mask_continuation(byte as u8)
91
// }
92
93
impl<'a> TryFromCtx<'a> for Uleb128 {
94
    type Error = error::Error;
95
    #[inline]
96
0
    fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error> {
97
0
        let mut result = 0;
98
0
        let mut shift = 0;
99
0
        let mut count = 0;
100
        loop {
101
0
            let byte: u8 = src.pread(count)?;
102
103
0
            if shift == 63 && byte != 0x00 && byte != 0x01 {
104
0
                return Err(error::Error::BadInput{ size: src.len(), msg: "failed to parse"})
105
0
            }
106
0
107
0
            let low_bits = u64::from(mask_continuation(byte));
108
0
            result |= low_bits << shift;
109
0
110
0
            count += 1;
111
0
            shift += 7;
112
0
113
0
            if byte & CONTINUATION_BIT == 0 {
114
0
                return Ok((Uleb128 { value: result, count }, count));
115
0
            }
116
        }
117
0
    }
118
}
119
120
impl<'a> TryFromCtx<'a> for Sleb128 {
121
    type Error = error::Error;
122
    #[inline]
123
0
    fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error> {
124
0
        let o = 0;
125
0
        let offset = &mut 0;
126
0
        let mut result = 0;
127
0
        let mut shift = 0;
128
0
        let size = 64;
129
        let mut byte: u8;
130
        loop {
131
0
            byte = src.gread(offset)?;
132
133
0
            if shift == 63 && byte != 0x00 && byte != 0x7f {
134
0
                return Err(error::Error::BadInput{size: src.len(), msg: "failed to parse"})
135
0
            }
136
0
137
0
            let low_bits = i64::from(mask_continuation(byte));
138
0
            result |= low_bits << shift;
139
0
            shift += 7;
140
0
141
0
            if byte & CONTINUATION_BIT == 0 {
142
0
                break;
143
0
            }
144
        }
145
146
0
        if shift < size && (SIGN_BIT & byte) == SIGN_BIT {
147
0
            // Sign extend the result.
148
0
            result |= !0 << shift;
149
0
        }
150
0
        let count = *offset - o;
151
0
        Ok((Sleb128{ value: result, count }, count))
152
0
    }
153
}
154
155
#[cfg(test)]
156
mod tests {
157
    use super::{Uleb128, Sleb128};
158
    use super::super::LE;
159
160
    const CONTINUATION_BIT: u8 = 1 << 7;
161
    //const SIGN_BIT: u8 = 1 << 6;
162
163
    #[test]
164
    fn uleb_size() {
165
        use super::super::Pread;
166
        let buf = [2u8 | CONTINUATION_BIT, 1];
167
        let bytes = &buf[..];
168
        let num = bytes.pread::<Uleb128>(0).unwrap();
169
        println!("num: {:?}", &num);
170
        assert_eq!(130u64, num.into());
171
        assert_eq!(num.size(), 2);
172
173
        let buf = [0x00,0x01];
174
        let bytes = &buf[..];
175
        let num = bytes.pread::<Uleb128>(0).unwrap();
176
        println!("num: {:?}", &num);
177
        assert_eq!(0u64, num.into());
178
        assert_eq!(num.size(), 1);
179
180
        let buf = [0x21];
181
        let bytes = &buf[..];
182
        let num = bytes.pread::<Uleb128>(0).unwrap();
183
        println!("num: {:?}", &num);
184
        assert_eq!(0x21u64, num.into());
185
        assert_eq!(num.size(), 1);
186
    }
187
188
    #[test]
189
    fn uleb128() {
190
        use super::super::Pread;
191
        let buf = [2u8 | CONTINUATION_BIT, 1];
192
        let bytes = &buf[..];
193
        let num = bytes.pread::<Uleb128>(0).expect("Should read Uleb128");
194
        assert_eq!(130u64, num.into());
195
        assert_eq!(386, bytes.pread_with::<u16>(0, LE).expect("Should read number"));
196
    }
197
198
    #[test]
199
    fn uleb128_overflow() {
200
        use super::super::Pread;
201
        let buf = [2u8 | CONTINUATION_BIT,
202
                   2 | CONTINUATION_BIT,
203
                   2 | CONTINUATION_BIT,
204
                   2 | CONTINUATION_BIT,
205
                   2 | CONTINUATION_BIT,
206
                   2 | CONTINUATION_BIT,
207
                   2 | CONTINUATION_BIT,
208
                   2 | CONTINUATION_BIT,
209
                   2 | CONTINUATION_BIT,
210
                   2 | CONTINUATION_BIT,
211
                   1];
212
        let bytes = &buf[..];
213
        assert!(bytes.pread::<Uleb128>(0).is_err());
214
    }
215
216
    #[test]
217
    fn sleb128() {
218
        use super::super::Pread;
219
        let bytes = [0x7fu8 | CONTINUATION_BIT, 0x7e];
220
        let num: i64 = bytes.pread::<Sleb128>(0).expect("Should read Sleb128").into();
221
        assert_eq!(-129, num);
222
    }
223
}