diff --git a/shen-nbt5/src/lib.rs b/shen-nbt5/src/lib.rs index 448732d..83d6593 100644 --- a/shen-nbt5/src/lib.rs +++ b/shen-nbt5/src/lib.rs @@ -16,36 +16,37 @@ pub struct NbtReader<'data> { // pub endian: Endian, } -macro_rules! read { +macro_rules! read_uncheck { ($name:ident, $ty:ty, $size:literal) => { #[doc = concat!("读取 ", stringify!($ty), " 类型 ", $size, " 长度的数据")] /// #[doc = "转换大小端"] - pub fn $name(&mut self) -> $ty { - unsafe { - // 使用 std::ptr::read_unaligned 解决未对齐地址问题 - let value = - std::ptr::read_unaligned(self.data[self.cursor..].as_ptr() as *const $ty); - self.cursor += std::mem::size_of::<$ty>(); - value.to_be() - } - } - }; - ($name:ident, $ty:ty, $size:literal, false) => { - #[doc = concat!("读取 ", stringify!($ty), " 类型 ", $size, " 长度的数据")] - /// - #[doc = "不转换大小端"] - pub fn $name(&mut self) -> $ty { - unsafe { - // 使用 std::ptr::read_unaligned 解决未对齐地址问题 - let value = - std::ptr::read_unaligned(self.data[self.cursor..].as_ptr() as *const $ty); - self.cursor += std::mem::size_of::<$ty>(); - value - } + /// + /// # 安全性 + /// 允许未对齐的地址 + /// 长度溢出会导致 UB + pub unsafe fn $name(&mut self) -> $ty { + // 使用 std::ptr::read_unaligned 解决未对齐地址问题 + let value = std::ptr::read_unaligned(self.data[self.cursor..].as_ptr() as *const $ty); + self.cursor += std::mem::size_of::<$ty>(); + value.to_be() } }; } + +macro_rules! read { + ($name:ident, $ty:ty, $size:literal) => { + #[doc = concat!("读取 ", stringify!($ty), " 类型 ", $size, " 长度的数据")] + pub fn $name(&mut self) -> $ty { + let value = self.data[self.cursor..self.cursor + $size] + .iter() + .fold(0, |acc, &x| (acc << 8) | x as $ty); + self.cursor += $size; + value + } + }; +} + impl NbtReader<'_> { pub fn new(data: &mut [u8]) -> NbtReader { NbtReader { @@ -64,14 +65,35 @@ impl NbtReader<'_> { /// 读取一个 i8 类型的数据 #[inline] pub fn read_i8(&mut self) -> i8 { self.read_u8() as i8 } - read!(read_i16_unchecked, i16, 2); - read!(read_u16_unchecked, u16, 2); - read!(read_i32_unchecked, i32, 4); - read!(read_u32_unchecked, u32, 4); - read!(read_i64_unchecked, i64, 8); - read!(read_u64_unchecked, u64, 8); - read!(read_f32_unchecked, f32, 4, false); - read!(read_f64_unchecked, f64, 8, false); + read_uncheck!(read_i16_unchecked, i16, 2); + read_uncheck!(read_u16_unchecked, u16, 2); + read_uncheck!(read_i32_unchecked, i32, 4); + read_uncheck!(read_u32_unchecked, u32, 4); + read_uncheck!(read_i64_unchecked, i64, 8); + read_uncheck!(read_u64_unchecked, u64, 8); + /// 读取一个 f32 类型的数据 + /// + /// 转换大小端 + /// + /// # 安全性 + /// 允许未对齐的地址 + /// 长度溢出会导致 UB + pub unsafe fn read_f32_unchecked(&mut self) -> f32 { + let value = std::ptr::read_unaligned(self.data[self.cursor..].as_ptr() as *const u32); + self.cursor += 4; + f32::from_bits(value.to_be()) + } + /// 读取一个 f64 类型的数据 + /// 转换大小端 + /// + /// # 安全性 + /// 允许未对齐的地址 + /// 长度溢出会导致 UB + pub unsafe fn read_f64_unchecked(&mut self) -> f64 { + let value = std::ptr::read_unaligned(self.data[self.cursor..].as_ptr() as *const u64); + self.cursor += 8; + f64::from_bits(value.to_be()) + } pub fn read_u8_array(&mut self, len: usize) -> &[u8] { let value = &self.data[self.cursor..self.cursor + len]; diff --git a/shen-nbt5/src/tests.rs b/shen-nbt5/src/tests.rs index fec1bdc..24dcc77 100644 --- a/shen-nbt5/src/tests.rs +++ b/shen-nbt5/src/tests.rs @@ -39,32 +39,16 @@ fn read_one_bytes() { } #[test] -fn read_data_unchecked() { - let mut datas = gen_datas(100); - let mut reader = NbtReader::new(&mut datas); +fn read_data_safe() { + let mut data = vec![0x01, 0x02, 0x03, 0x04]; + let mut reader = NbtReader::new(&mut data); assert_eq!(reader.read_u8(), 0x00); assert_eq!(reader.cursor, 1); assert_eq!(reader.read_i8(), 0x01); assert_eq!(reader.cursor, 2); assert_eq!(reader.read_u8(), 0x02); assert_eq!(reader.cursor, 3); - assert_eq!(reader.read_i16_unchecked(), 0x0304); - assert_eq!(reader.cursor, 5); - assert_eq!(reader.read_u16_unchecked(), 0x0506); - assert_eq!(reader.cursor, 7); - assert_eq!(reader.read_i32_unchecked(), 0x0708090A); - assert_eq!(reader.cursor, 11); - assert_eq!(reader.read_u32_unchecked(), 0x0B0C0D0E); - assert_eq!(reader.cursor, 15); - assert_eq!(reader.read_i64_unchecked(), 0x0F10111213141516); - assert_eq!(reader.cursor, 23); - assert_eq!(reader.read_u64_unchecked(), 0x1718191A1B1C1D1E); - assert_eq!(reader.cursor, 31); - assert_eq!(reader.read_f32_unchecked().to_ne_bytes(), [0x1F, 0x20, 0x21, 0x22]); - assert_eq!( - reader.read_f64_unchecked().to_ne_bytes(), - [0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A] - ); + } #[test]