#![cfg(feature = "bits")]
use assert_hex::assert_eq_hex;
use deku::prelude::*;
#[test]
fn test_lsb_le_misaligned_middle() {
#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(bit_order = "lsb", endian = "little")]
pub struct TestStruct {
#[deku(bits = 1)]
pub field_a: u8, #[deku(bits = 1)]
pub field_b: u8, #[deku(bits = 1)]
pub field_c: u8, #[deku(bits = 27)]
pub field_d: u32, #[deku(bits = 2)]
pub field_e: u8, }
const RAW_DATA: &[u8] = &[0xAD, 0xDC, 0x32, 0xF1];
let parsed = TestStruct::from_bytes((RAW_DATA, 0)).unwrap().1;
let expected = TestStruct {
field_a: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0x0000_0001) as u8),
field_b: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0x0000_0002) >> 1) as u8,
field_c: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0x0000_0004) >> 2) as u8,
field_d: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0x3FFF_FFF8) >> 3),
field_e: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0xC000_0000) >> 30) as u8,
};
assert_eq_hex!(
expected,
TestStruct {
field_a: 0x1,
field_b: 0x0,
field_c: 0x1,
field_d: 0x6265B95,
field_e: 0x3,
},
"Incorrect manual calculation"
);
assert_eq_hex!(parsed, expected, "Invalid deku calculation");
}
#[test]
fn test_lsb_le_misaligned_right() {
#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(bit_order = "lsb", endian = "little")]
pub struct TestStruct {
#[deku(bits = 5)]
pub field_a: u8, #[deku(bits = 27)]
pub field_b: u32, }
const RAW_DATA: &[u8] = &[0xAD, 0xDC, 0x32, 0xF1];
let parsed = TestStruct::from_bytes((RAW_DATA, 0)).unwrap().1;
let expected = TestStruct {
field_a: (u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0x0000_001F) as u8,
field_b: (u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0xFFFF_FFE0) >> 5,
};
assert_eq_hex!(
expected,
TestStruct {
field_a: 0xD,
field_b: 0x0789_96E5,
},
"Incorrect manual calculation"
);
assert_eq_hex!(parsed, expected, "Invalid deku calculation");
}
#[test]
fn test_lsb_le_misaligned_left() {
#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(bit_order = "lsb", endian = "little")]
pub struct TestStruct {
#[deku(bits = 27)]
pub field_a: u32, #[deku(bits = 5)]
pub field_b: u8, }
const RAW_DATA: &[u8] = &[0xAD, 0xDC, 0x32, 0xF1];
let parsed = TestStruct::from_bytes((RAW_DATA, 0)).unwrap().1;
let expected = TestStruct {
field_a: (u32::from_le_bytes(RAW_DATA.try_into().unwrap())) & 0x07FF_FFFF,
field_b: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0xF800_0000) >> 27) as u8,
};
assert_eq_hex!(
expected,
TestStruct {
field_a: 0x0132_DCAD,
field_b: 0x1E,
},
"Incorrect manual calculation"
);
assert_eq_hex!(parsed, expected, "Invalid deku calculation");
}
#[test]
fn test_lsb_le_aligned_right() {
#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(bit_order = "lsb", endian = "little")]
pub struct TestStruct {
#[deku(bits = 8)]
pub field_a: u8, #[deku(bits = 24)]
pub field_b: u32, }
const RAW_DATA: &[u8] = &[0xAD, 0xDC, 0x32, 0xF1];
let parsed = TestStruct::from_bytes((RAW_DATA, 0)).unwrap().1;
let expected = TestStruct {
field_a: (u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0x0000_00FF) as u8,
field_b: (u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0xFFFF_FF00) >> 8,
};
assert_eq_hex!(
expected,
TestStruct {
field_a: 0xAD,
field_b: 0x00F1_32DC,
},
"Incorrect manual calculation"
);
assert_eq_hex!(parsed, expected, "Invalid deku calculation");
}
#[test]
fn test_lsb_le_aligned_left() {
#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(bit_order = "lsb", endian = "little")]
pub struct TestStruct {
#[deku(bits = 24)]
pub field_a: u32, #[deku(bits = 8)]
pub field_b: u8, }
const RAW_DATA: &[u8] = &[0xAD, 0xDC, 0x32, 0xF1];
let parsed = TestStruct::from_bytes((RAW_DATA, 0)).unwrap().1;
let expected = TestStruct {
field_a: (u32::from_le_bytes(RAW_DATA.try_into().unwrap())) & 0x00FF_FFFF,
field_b: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0xFF00_0000) >> 24) as u8,
};
assert_eq_hex!(
expected,
TestStruct {
field_a: 0x0032_DCAD,
field_b: 0xF1,
},
"Incorrect manual calculation"
);
assert_eq_hex!(parsed, expected, "Invalid deku calculation");
}
#[test]
fn test_lsb_le_aligned_mixed() {
#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(bit_order = "lsb", endian = "little")]
pub struct TestStruct {
#[deku(bits = 16)]
pub field_a: u16, #[deku(bits = 1)]
pub field_b: u8, #[deku(bits = 2)]
pub field_c: u8, #[deku(bits = 4)]
pub field_d: u8, #[deku(bits = 6)]
pub field_e: u8, #[deku(bits = 3)]
pub field_f: u8, }
const RAW_DATA: &[u8] = &[0xAD, 0xDC, 0x32, 0xF1];
let parsed = TestStruct::from_bytes((RAW_DATA, 0)).unwrap().1;
let expected = TestStruct {
field_a: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0x0000_FFFF) as u16),
field_b: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0x0001_0000) >> 16) as u8,
field_c: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0x0006_0000) >> 17) as u8,
field_d: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0x0078_0000) >> 19) as u8,
field_e: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0x1F80_0000) >> 23) as u8,
field_f: ((u32::from_le_bytes(RAW_DATA.try_into().unwrap()) & 0xE000_0000) >> 29) as u8,
};
assert_eq_hex!(
expected,
TestStruct {
field_a: 0xDCAD,
field_b: 0x0,
field_c: 0x1,
field_d: 0x6,
field_e: 0x22,
field_f: 0x7,
},
"Incorrect manual calculation"
);
assert_eq_hex!(parsed, expected, "Invalid deku calculation");
}
#[test]
#[cfg(feature = "alloc")]
fn test_lsb_le_misaligned_2() {
#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(endian = "little", bit_order = "lsb")]
struct Header {
#[deku(bits = 20)]
foo: u32,
#[deku(bits = 12)]
bar: u32,
}
let reference = Header {
foo: 0xabc,
bar: 0xdef,
};
let data = reference.to_bytes().unwrap();
assert_eq!(data, b"\xbc\x0a\xf0\xde");
let (_, actual) = Header::from_bytes((&data[..], 0)).unwrap();
assert_eq!(actual, reference);
}
#[test]
#[cfg(feature = "alloc")]
fn test_invalid_lsb_bit_split_squashfs_v3() {
#[derive(Debug, DekuRead, DekuWrite, PartialEq)]
#[deku(endian = "little", bit_order = "lsb")]
pub struct Dir {
#[deku(bits = "19")]
pub file_size: u32,
#[deku(bits = "13")]
pub offset: u16,
}
let expected_file_size = 38u32;
let expected_offset = 44u16;
let combined = ((expected_offset as u32) << 19) | expected_file_size;
let test_data = combined.to_le_bytes();
let (_, result) = Dir::from_bytes((&test_data, 0)).unwrap();
assert_eq!(result.file_size, expected_file_size);
assert_eq!(result.offset, expected_offset);
assert_eq!(test_data, &*result.to_bytes().unwrap());
}
#[test]
fn test_misaligned_pad_bits_aaelf32_flags() {
env_logger::init();
#[derive(Debug, DekuRead, DekuWrite, PartialEq)]
#[deku(endian = "little", bit_order = "lsb")]
pub struct AaElf32Flags {
#[deku(bits = "1", pad_bits_before = "9")]
ef_arm_abi_float_soft: bool,
#[deku(bits = "1")]
ef_arm_abi_float_hard: bool,
#[deku(bits = "1", pad_bits_before = "11")]
ef_arm_gccmask: bool,
#[deku(bits = "1")]
ef_arm_be8: bool,
ef_arm_abimask: u8,
}
let word = 83886592u32;
let bytes = word.to_le_bytes();
let (_, flags) = AaElf32Flags::from_bytes((&bytes, 0)).unwrap();
assert_eq!(
AaElf32Flags {
ef_arm_abi_float_soft: true,
ef_arm_abi_float_hard: false,
ef_arm_gccmask: false,
ef_arm_be8: false,
ef_arm_abimask: 5,
},
flags
);
}