diff --git a/shen-nbt5/Cargo.toml b/shen-nbt5/Cargo.toml index 4b12897..34612a3 100644 --- a/shen-nbt5/Cargo.toml +++ b/shen-nbt5/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shen-nbt5" -version = "0.4.3" +version = "0.4.4" edition = "2021" description = "Just A FASSST NBT parser/writer" homepage = "https://github.com/shenjackyuanjie/nbt-rust" diff --git a/shen-nbt5/src/lib.rs b/shen-nbt5/src/lib.rs index 00fb695..de4fa83 100644 --- a/shen-nbt5/src/lib.rs +++ b/shen-nbt5/src/lib.rs @@ -237,7 +237,7 @@ impl std::fmt::Display for NbtError { } /// 核心 Value -/// +/// /// 暂时不支持 `from_value` 和 `to_value` /// https://github.com/shenjackyuanjie/nbt-rust/issues/1 #[derive(Debug, Clone, PartialEq)] diff --git a/shen-nbt5/src/reader.rs b/shen-nbt5/src/reader.rs index 2418e09..a15f6f4 100644 --- a/shen-nbt5/src/reader.rs +++ b/shen-nbt5/src/reader.rs @@ -721,6 +721,26 @@ impl NbtReader<'_> { self.cursor += len; value } + /// 读取指定长度的 i16 数组 + /// + /// # 安全性 + /// + /// 长度溢出会导致 UB + #[inline] + pub unsafe fn read_be_i16_array_unsafe(&mut self, len: usize) -> Vec { + let mut value: Vec = Vec::with_capacity(len); + std::ptr::copy_nonoverlapping( + self.data[self.cursor..].as_ptr() as *const u8, + value.as_ptr() as *mut u8, + len * 2, + ); + value.set_len(len); + for n in &mut value { + *n = n.to_be(); + } + self.cursor += len * 2; + value + } /// 读取指定长度的 i32 数组 /// /// # 安全性 @@ -728,15 +748,39 @@ impl NbtReader<'_> { /// 长度溢出会导致 UB #[inline] pub unsafe fn read_be_i32_array_unsafe(&mut self, len: usize) -> Vec { - let value = - std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i32, len); - let mut value = value.to_vec(); + let mut value: Vec = Vec::with_capacity(len); + std::ptr::copy_nonoverlapping( + self.data[self.cursor..].as_ptr() as *const u8, + value.as_ptr() as *mut u8, + len * 4, + ); + value.set_len(len); for n in &mut value { *n = n.to_be(); } self.cursor += len * 4; value } + /// 读取指定长度的 i64 数组 + /// + /// # 安全性 + /// + /// 长度溢出会导致 UB + #[inline] + pub unsafe fn read_be_i64_array_unsafe(&mut self, len: usize) -> Vec { + let mut value: Vec = Vec::with_capacity(len); + std::ptr::copy_nonoverlapping( + self.data[self.cursor..].as_ptr() as *const u8, + value.as_ptr() as *mut u8, + len * 8, + ); + value.set_len(len); + for n in &mut value { + *n = n.to_be(); + } + self.cursor += len * 8; + value + } /// 读取指定长度的 i32 数组 /// /// # 安全性 @@ -755,22 +799,6 @@ impl NbtReader<'_> { /// /// # 安全性 /// - /// 长度溢出会导致 UB - #[inline] - pub unsafe fn read_be_i64_array_unsafe(&mut self, len: usize) -> Vec { - let value = - std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i64, len); - let mut value = value.to_vec(); - for n in &mut value { - *n = n.to_be(); - } - self.cursor += len * 8; - value - } - /// 读取指定长度的 i64 数组 - /// - /// # 安全性 - /// /// 长度溢出会导致 panic #[inline] pub fn read_be_i64_array(&mut self, len: usize) -> Vec { diff --git a/shen-nbt5/src/tests.rs b/shen-nbt5/src/tests.rs index 5e07b82..ec0ff31 100644 --- a/shen-nbt5/src/tests.rs +++ b/shen-nbt5/src/tests.rs @@ -280,6 +280,46 @@ mod unsafe_test { assert_eq!(reader.cursor, 100 * 8); } } + + /// 未对齐的地址 + #[test] + fn unaligned_read_u16_array() { + let mut value = vec![0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04]; + let mut reader = NbtReader::new(&mut value); + let value = reader.read_u8(); + assert_eq!(value, 0x01); + assert_eq!(reader.cursor, 1); + unsafe { + // 读取 u16 数组 + let array = reader.read_be_i16_array_unsafe(3); + assert_eq!(array, vec![0x0203, 0x0401, 0x0203]); + assert_eq!(reader.cursor, 7); + let value = reader.read_u8(); + assert_eq!(value, 0x04); + assert_eq!(reader.cursor, 8); + } + } + + /// 依然是未对齐 + /// 只不过是 u32/i32 + #[test] + fn unaligned_read_x32_array() { + let mut value = gen_datas(202); + let mut reader = NbtReader::new(&mut value); + let value = reader.read_u8(); + assert_eq!(value, 0x00); + assert_eq!(reader.cursor, 1); + unsafe { + let array = reader.read_be_i32_array_unsafe(50); + reader.roll_back(50 * 4); + let safe_array = reader.read_be_i32_array(50); + assert_eq!(array, safe_array); + assert_eq!(reader.cursor, 201); + } + let value = reader.read_u8(); + assert_eq!(value, 201); + assert_eq!(reader.cursor, 202); + } } mod nbt {