use crate::error::ErrorKind;
type Result<T> = ::std::result::Result<T, Box<ErrorKind>>;
pub trait Leb128: Sized {
fn read_leb128(bytes: &[u8]) -> Result<(Self, usize)>;
}
impl Leb128 for u64 {
fn read_leb128(bytes: &[u8]) -> Result<(Self, usize)> {
read_64(bytes, false)
}
}
impl Leb128 for u32 {
fn read_leb128(bytes: &[u8]) -> Result<(Self, usize)> {
read_32(bytes, false)
}
}
impl Leb128 for i64 {
fn read_leb128(bytes: &[u8]) -> Result<(Self, usize)> {
let (u, size) = read_64(bytes, true)?;
Ok((u as i64, size))
}
}
impl Leb128 for i32 {
fn read_leb128(bytes: &[u8]) -> Result<(Self, usize)> {
let (u, size) = read_32(bytes, true)?;
Ok((u as i32, size))
}
}
fn read_64(bytes: &[u8], signed: bool) -> Result<(u64, usize)> {
let mut ret = 0;
for (idx, b) in bytes.iter().copied().enumerate() {
if idx > 9 || idx == 9 && (!signed && b > 1 || signed && b != 0 && b != 0x7f) {
let ty = if signed { "i64" } else { "u64" };
return Err(Box::new(ErrorKind::IntOverflow { ty, got: None }));
}
ret |= ((b & 0b0111_1111) as u64) << (idx * 7);
if b & 0b1000_0000 == 0 {
let len = idx + 1;
if signed && len < 10 && b & 0b0100_0000 != 0 {
ret |= !0 << (len * 7);
}
return Ok((ret, len));
}
}
Err(Box::new(ErrorKind::UnexpectedEof {
expected: "part of LEB128-encoded integer",
}))
}
fn read_32(bytes: &[u8], signed: bool) -> Result<(u32, usize)> {
let mut ret = 0;
for (idx, b) in bytes.iter().copied().enumerate() {
if idx > 4 || idx == 4 && (!signed && b > 0b1111 || signed && b > 0b0111 && b < 0b111_1000) {
let ty = if signed { "i32" } else { "u32" };
return Err(Box::new(ErrorKind::IntOverflow { ty, got: None }));
}
ret |= ((b & 0b0111_1111) as u32) << (idx * 7);
if b & 0b1000_0000 == 0 {
let len = idx + 1;
if signed && len < 5 && b & 0b0100_0000 != 0 {
ret |= !0 << (len * 7);
}
return Ok((ret, len));
}
}
Err(Box::new(ErrorKind::UnexpectedEof {
expected: "part of LEB128-encoded integer",
}))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn i32_value_ok() {
for (input, expected) in vec![
(vec![0x00], 0),
(vec![0x80, 0x01], 128),
(vec![0xc0, 0xc4, 0x07], 123456),
(vec![0x01], 1),
(vec![0xff, 0xff, 0xff, 0xff, 0x07], i32::MAX),
(vec![0xc0, 0xbb, 0x78], -123456),
(vec![0x7f], -1),
(vec![0x80, 0x7f], -128),
(vec![0x80, 0x80, 0x80, 0x80, 0x78], i32::MIN),
] {
let (i, s) = i32::read_leb128(&input).unwrap();
assert_eq!(i, expected, "expected {} but got {} for {:?}", expected, i, input,);
assert_eq!(
s,
input.len(),
"expected size {} but got {} for {:?}",
input.len(),
s,
input,
);
}
}
#[test]
fn i64_value_ok() {
for (input, expected) in vec![
(vec![0x00], 0),
(vec![0x80, 0x01], 128),
(vec![0xc0, 0xc4, 0x07], 123456),
(vec![0x01], 1),
(vec![0xff, 0xff, 0xff, 0xff, 0x07], i32::MAX as i64),
(
vec![
0b10011111, 0b11111111, 0b11000111, 0b11000100, 0b11010110, 0b11111101, 0b00000000,
],
4318196531103,
),
(
vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0],
i64::MAX,
),
(vec![0xc0, 0xbb, 0x78], -123456),
(vec![0x7f], -1),
(vec![0x80, 0x7f], -128),
(
vec![
0b11100001, 0b10000000, 0b10111000, 0b10111011, 0b10101001, 0b10000010, 0b1111111,
],
-4318196531103,
),
(vec![0x80, 0x80, 0x80, 0x80, 0x08], i32::MIN as u32 as i64),
(
vec![0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f],
i64::MIN,
),
] {
let (i, s) = i64::read_leb128(&input).unwrap();
assert_eq!(i, expected, "expected {} but got {} for {:?}", expected, i, input,);
assert_eq!(
s,
input.len(),
"expected size {} but got {} for {:?}",
input.len(),
s,
input,
);
}
}
#[test]
fn u32_value_ok() {
for (input, expected) in vec![
(vec![0x00], 0),
(vec![0x80, 0x01], 128),
(vec![0xc0, 0xc4, 0x07], 123456),
(vec![0x01], 1),
(vec![0xff, 0xff, 0xff, 0xff, 0x0f], u32::MAX),
] {
let (i, s) = u32::read_leb128(&input).unwrap();
assert_eq!(i, expected, "expected {} but got {} for {:?}", expected, i, input,);
assert_eq!(
s,
input.len(),
"expected size {} but got {} for {:?}",
input.len(),
s,
input,
);
}
}
#[test]
fn u64_value_ok() {
for (input, expected) in vec![
(vec![0x00], 0),
(vec![0x80, 0x01], 128),
(vec![0xc0, 0xc4, 0x07], 123456),
(vec![0x01], 1),
(vec![0xff, 0xff, 0xff, 0xff, 0x0f], u32::MAX as u64),
(vec![0x9f, 0xff, 0xc5, 0xaf, 0x91, 0xa2, 0x1c], 124318196531103),
(
vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1],
u64::MAX,
),
] {
let (i, s) = u64::read_leb128(&input).unwrap();
assert_eq!(i, expected, "expected {} but got {} for {:?}", expected, i, input,);
assert_eq!(
s,
input.len(),
"expected size {} but got {} for {:?}",
input.len(),
s,
input,
);
}
}
#[test]
fn other_bytes_follow() {
let (i, s) = i32::read_leb128(&[0xc0, 0xbb, 0x78, 0x12, 0x34, 0xff]).unwrap();
assert_eq!(i, -123456, "0x{:x}", i);
assert_eq!(s, 3);
}
#[test]
fn overflow_error() {
let b = [0xff, 0xff, 0xff, 0xff, 0x10]; assert!(matches!(
*i32::read_leb128(&b).unwrap_err(),
ErrorKind::IntOverflow { .. }
));
let b = [0x80, 0x80, 0x80, 0x80, 0x77]; assert!(matches!(
*i32::read_leb128(&b).unwrap_err(),
ErrorKind::IntOverflow { .. }
));
let b = [0xff, 0xff, 0xff, 0xff, 0x10]; assert!(matches!(
*u32::read_leb128(&b).unwrap_err(),
ErrorKind::IntOverflow { .. }
));
let b = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1]; assert!(matches!(
*i64::read_leb128(&b).unwrap_err(),
ErrorKind::IntOverflow { .. }
));
let b = [0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7e]; assert!(matches!(
*i64::read_leb128(&b).unwrap_err(),
ErrorKind::IntOverflow { .. }
));
let b = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2]; assert!(matches!(
*u64::read_leb128(&b).unwrap_err(),
ErrorKind::IntOverflow { .. }
));
}
#[test]
fn unexpected_eof() {
let b = [0xc0, 0xc4];
assert!(matches!(
*i32::read_leb128(&b).unwrap_err(),
ErrorKind::UnexpectedEof { .. }
));
let b = [0xff, 0xff, 0xff, 0xff];
assert!(matches!(
*i64::read_leb128(&b).unwrap_err(),
ErrorKind::UnexpectedEof { .. }
));
}
}