From 5073d9780ad8f3c0c10f85dffa797c6251a8391d Mon Sep 17 00:00:00 2001 From: shenjack <3695888@qq.com> Date: Sun, 10 Mar 2024 14:22:54 +0800 Subject: [PATCH] =?UTF-8?q?=E7=90=86=E8=AE=BA=E4=B8=8A=E5=A5=BD=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shen-nbt5/src/reader.rs | 62 ++++++-- shen-nbt5/src/tests.rs | 8 +- shen-nbt5/src/writer.rs | 336 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 392 insertions(+), 14 deletions(-) diff --git a/shen-nbt5/src/reader.rs b/shen-nbt5/src/reader.rs index 8ec715f..2418e09 100644 --- a/shen-nbt5/src/reader.rs +++ b/shen-nbt5/src/reader.rs @@ -29,13 +29,13 @@ impl nbt_version::NbtReadTrait for nbt_version::Java { #[inline] fn read_i32_array(reader: &mut NbtReader) -> NbtResult> { let len = reader.read_be_i32() as usize; - let value = reader.read_i32_array(len); + let value = reader.read_be_i32_array(len); Ok(value) } #[inline] fn read_i64_array(reader: &mut NbtReader) -> NbtResult> { let len = reader.read_be_i32() as usize; - let value = reader.read_i64_array(len); + let value = reader.read_be_i64_array(len); Ok(value) } #[inline] @@ -159,13 +159,13 @@ impl NbtReadTrait for BedrockDisk { #[inline] fn read_i32_array(reader: &mut NbtReader) -> NbtResult> { let len = reader.read_le_i32() as usize; - let value = reader.read_i32_array(len); + let value = reader.read_le_i32_array(len); Ok(value) } #[inline] fn read_i64_array(reader: &mut NbtReader) -> NbtResult> { let len = reader.read_le_i32() as usize; - let value = reader.read_i64_array(len); + let value = reader.read_le_i64_array(len); Ok(value) } #[inline] @@ -256,12 +256,12 @@ impl NbtReadTrait for BedrockNetVarInt { } fn read_i32_array(reader: &mut NbtReader) -> NbtResult> { let len = reader.read_zigzag_var_i32()? as usize; - let value = reader.read_i32_array(len); + let value = reader.read_le_i32_array(len); Ok(value) } fn read_i64_array(reader: &mut NbtReader) -> NbtResult> { let len = reader.read_zigzag_var_i32()? as usize; - let value = reader.read_i64_array(len); + let value = reader.read_le_i64_array(len); Ok(value) } fn read_compound(reader: &mut NbtReader) -> NbtResult> { @@ -727,7 +727,7 @@ impl NbtReader<'_> { /// /// 长度溢出会导致 UB #[inline] - pub unsafe fn read_i32_array_unsafe(&mut self, len: usize) -> Vec { + 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(); @@ -743,7 +743,7 @@ impl NbtReader<'_> { /// /// 长度溢出会导致 panic #[inline] - pub fn read_i32_array(&mut self, len: usize) -> Vec { + pub fn read_be_i32_array(&mut self, len: usize) -> Vec { let value = self.data[self.cursor..self.cursor + len * 4] .chunks_exact(4) .map(|n| i32::from_be_bytes(n[0..4].try_into().unwrap())) @@ -757,7 +757,7 @@ impl NbtReader<'_> { /// /// 长度溢出会导致 UB #[inline] - pub unsafe fn read_i64_array_unsafe(&mut self, len: usize) -> Vec { + 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(); @@ -773,7 +773,7 @@ impl NbtReader<'_> { /// /// 长度溢出会导致 panic #[inline] - pub fn read_i64_array(&mut self, len: usize) -> Vec { + pub fn read_be_i64_array(&mut self, len: usize) -> Vec { let value = self.data[self.cursor..self.cursor + len * 8] .chunks_exact(8) .map(|n| i64::from_be_bytes(n[0..8].try_into().unwrap())) @@ -781,6 +781,48 @@ impl NbtReader<'_> { self.cursor += len * 8; value } + /// 读取指定长度的 le i16 数组 + /// + /// # 安全性 + /// + /// 长度溢出会导致 panic + #[inline] + pub fn read_le_i16_array(&mut self, len: usize) -> Vec { + let value = self.data[self.cursor..self.cursor + len * 2] + .chunks_exact(2) + .map(|n| i16::from_le_bytes(n[0..2].try_into().unwrap())) + .collect(); + self.cursor += len * 2; + value + } + /// 读取指定长度的 le i32 数组 + /// + /// # 安全性 + /// + /// 长度溢出会导致 panic + #[inline] + pub fn read_le_i32_array(&mut self, len: usize) -> Vec { + let value = self.data[self.cursor..self.cursor + len * 4] + .chunks_exact(4) + .map(|n| i32::from_le_bytes(n[0..4].try_into().unwrap())) + .collect(); + self.cursor += len * 4; + value + } + /// 读取指定长度的 le i64 数组 + /// + /// # 安全性 + /// + /// 长度溢出会导致 panic + #[inline] + pub fn read_le_i64_array(&mut self, len: usize) -> Vec { + let value = self.data[self.cursor..self.cursor + len * 8] + .chunks_exact(8) + .map(|n| i64::from_le_bytes(n[0..8].try_into().unwrap())) + .collect(); + self.cursor += len * 8; + value + } /// 读取指定长度的 utf-8 字符串 /// /// # 安全性 diff --git a/shen-nbt5/src/tests.rs b/shen-nbt5/src/tests.rs index 81f9214..5e07b82 100644 --- a/shen-nbt5/src/tests.rs +++ b/shen-nbt5/src/tests.rs @@ -260,9 +260,9 @@ mod unsafe_test { let mut value = gen_datas(4 * 100); let mut reader = NbtReader::new(&mut value); unsafe { - let value = reader.read_i32_array_unsafe(100); + let value = reader.read_be_i32_array_unsafe(100); reader.roll_back(100 * 4); - let safe_value = reader.read_i32_array(100); + let safe_value = reader.read_be_i32_array(100); assert_eq!(value, safe_value); assert_eq!(reader.cursor, 100 * 4); } @@ -273,9 +273,9 @@ mod unsafe_test { let mut value = gen_datas(8 * 100); let mut reader = NbtReader::new(&mut value); unsafe { - let value = reader.read_i64_array_unsafe(100); + let value = reader.read_be_i64_array_unsafe(100); reader.roll_back(100 * 8); - let safe_value = reader.read_i64_array(100); + let safe_value = reader.read_be_i64_array(100); assert_eq!(value, safe_value); assert_eq!(reader.cursor, 100 * 8); } diff --git a/shen-nbt5/src/writer.rs b/shen-nbt5/src/writer.rs index e2f9824..0c604d3 100644 --- a/shen-nbt5/src/writer.rs +++ b/shen-nbt5/src/writer.rs @@ -202,3 +202,339 @@ impl NbtWriteTrait for JavaNetAfter1_20_2 { Ok(buff) } } + +/// 比较痛苦的一集 +impl NbtWriteTrait for BedrockDisk { + #[inline] + fn write_i8_array(writer: &mut Vec, data: &[i8]) { + // 写入长度 + writer.extend_from_slice(&(data.len() as i32).to_le_bytes()); + // 写入数据 + writer.extend_from_slice(data.iter().map(|x| *x as u8).collect::>().as_slice()); + } + #[inline] + fn write_i32_array(writer: &mut Vec, data: &[i32]) { + // 写入长度 + writer.extend_from_slice(&(data.len() as i32).to_le_bytes()); + // 写入数据 + writer.extend_from_slice( + &data.iter().map(|x| x.to_le_bytes()).collect::>().concat(), + ); + } + #[inline] + fn write_i64_array(writer: &mut Vec, data: &[i64]) { + // 写入长度 + writer.extend_from_slice(&(data.len() as i32).to_le_bytes()); + // 写入数据 + writer.extend_from_slice( + &data.iter().map(|x| x.to_le_bytes()).collect::>().concat(), + ); + } + #[inline] + fn write_nbt_string(writer: &mut Vec, data: &str) { + // 写入长度 + writer.extend_from_slice(&(data.len() as u16).to_le_bytes()); + // 写入数据 + writer.extend_from_slice(data.as_bytes()); + } + #[inline] + fn write_list(writer: &mut Vec, data: &[NbtValue]) -> NbtResult<()> { + if data.is_empty() { + // 写入一个空的 tag + writer.extend_from_slice(&0i8.to_le_bytes()); + return Ok(()); + } + // 遍历检查一遍所有的 tag 是否一致 + let tag = data.first().unwrap().tag(); + if !data.iter().all(|x| x.tag() == tag) { + return Err(NbtError::ListTypeNotSame(data.iter().map(|x| x.tag()).collect())); + } + // 写入 tag + writer.push(tag); + // 写入长度 + writer.extend_from_slice(&(data.len() as i32).to_le_bytes()); + // 写入数据 + for i in data { + match i { + NbtValue::Byte(x) => writer.push(*x as u8), + NbtValue::Short(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Int(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Long(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Float(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Double(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::ByteArray(x) => Self::write_i8_array(writer, x), + NbtValue::IntArray(x) => Self::write_i32_array(writer, x), + NbtValue::LongArray(x) => Self::write_i64_array(writer, x), + NbtValue::String(x) => Self::write_nbt_string(writer, x), + NbtValue::List(x) => Self::write_list(writer, x)?, + NbtValue::Compound(name, data) => { + Self::write_compound(writer, name.as_ref(), data)? + } + } + } + Ok(()) + } + #[inline] + fn write_compound( + writer: &mut Vec, + name: Option<&String>, + data: &[(String, NbtValue)], + ) -> NbtResult<()> { + // 写入自己的名字 + Self::write_nbt_string(writer, name.unwrap_or(&"".to_string())); + for (key, value) in data { + // 写入 tag + writer.push(value.tag()); + // 写入 key + Self::write_nbt_string(writer, key); + // 写入 value + match value { + NbtValue::Byte(x) => writer.push(*x as u8), + NbtValue::Short(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Int(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Long(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Float(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Double(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::ByteArray(x) => Self::write_i8_array(writer, x), + NbtValue::IntArray(x) => Self::write_i32_array(writer, x), + NbtValue::LongArray(x) => Self::write_i64_array(writer, x), + NbtValue::String(x) => Self::write_nbt_string(writer, x), + NbtValue::List(x) => Self::write_list(writer, x)?, + NbtValue::Compound(name, data) => { + Self::write_compound(writer, name.as_ref(), data)? + } + } + } + // 写入结束 tag + writer.push(0); + Ok(()) + } + + fn write_to(value: &NbtValue, buff: &mut Vec) -> NbtResult<()> { + // 写入 tag + match value { + NbtValue::Compound(name, data) => { + buff.push(value.tag()); + Self::write_compound(buff, name.as_ref(), data)? + } + NbtValue::List(data) => { + buff.push(value.tag()); + Self::write_list(buff, data)? + } + x => return Err(NbtError::WrongRootType(x.tag())), + } + Ok(()) + } + + fn write_to_with_name(name: &str, value: &NbtValue, buff: &mut Vec) -> NbtResult<()> { + // 写入 tag + buff.push(value.tag()); + // 写入 key + Self::write_nbt_string(buff, name); + // 写入 value + Self::write_to(value, buff)?; + Ok(()) + } + + fn to_binary(value: &NbtValue) -> NbtResult> { + let mut buff = Vec::new(); + BedrockDisk::write_to(value, &mut buff)?; + Ok(buff) + } +} + +pub fn var_i32_to_bytes(value: i32) -> Vec { + let mut buff = Vec::new(); + let mut value = value; + loop { + let mut temp = (value & 0b01111111) as u8; + value >>= 7; + if value != 0 { + temp |= 0b10000000; + } + buff.push(temp); + if value == 0 { + break; + } + } + buff +} + +pub fn var_i64_to_bytes(value: i64) -> Vec { + let mut buff = Vec::new(); + let mut value = value; + loop { + let mut temp = (value & 0b01111111) as u8; + value >>= 7; + if value != 0 { + temp |= 0b10000000; + } + buff.push(temp); + if value == 0 { + break; + } + } + buff +} + +pub fn zigzag_var_i32_to_bytes(value: i32) -> Vec { + let mut buff = Vec::new(); + let mut value = (value << 1) ^ (value >> 31); + loop { + let mut temp = (value & 0b01111111) as u8; + value >>= 7; + if value != 0 { + temp |= 0b10000000; + } + buff.push(temp); + if value == 0 { + break; + } + } + buff +} + +pub fn zigzag_var_i64_to_bytes(value: i64) -> Vec { + let mut buff = Vec::new(); + let mut value = (value << 1) ^ (value >> 63); + loop { + let mut temp = (value & 0b01111111) as u8; + value >>= 7; + if value != 0 { + temp |= 0b10000000; + } + buff.push(temp); + if value == 0 { + break; + } + } + buff +} + +/// 最痛苦的一集 +impl NbtWriteTrait for BedrockNetVarInt { + fn write_i8_array(writer: &mut Vec, data: &[i8]) { + // zigzag var i32 + writer.extend_from_slice(&zigzag_var_i32_to_bytes(data.len() as i32)); + writer.extend_from_slice(data.iter().map(|x| *x as u8).collect::>().as_slice()); + } + fn write_i32_array(writer: &mut Vec, data: &[i32]) { + // zigzag var i32 + writer.extend_from_slice(&zigzag_var_i32_to_bytes(data.len() as i32)); + writer.extend_from_slice( + &data.iter().map(|x| x.to_le_bytes()).collect::>().concat(), + ); + } + fn write_i64_array(writer: &mut Vec, data: &[i64]) { + // zigzag var i32 + writer.extend_from_slice(&zigzag_var_i32_to_bytes(data.len() as i32)); + writer.extend_from_slice( + &data.iter().map(|x| x.to_le_bytes()).collect::>().concat(), + ); + } + fn write_nbt_string(writer: &mut Vec, data: &str) { + // zigzag var i32 + writer.extend_from_slice(&zigzag_var_i32_to_bytes(data.len() as i32)); + writer.extend_from_slice(data.as_bytes()); + } + fn write_list(writer: &mut Vec, data: &[NbtValue]) -> NbtResult<()> { + if data.is_empty() { + // 写入一个空的 tag + writer.extend_from_slice(&0i8.to_le_bytes()); + return Ok(()); + } + // 遍历检查一遍所有的 tag 是否一致 + let tag = data.first().unwrap().tag(); + if !data.iter().all(|x| x.tag() == tag) { + return Err(NbtError::ListTypeNotSame(data.iter().map(|x| x.tag()).collect())); + } + // 写入 tag + writer.push(tag); + // zigzag var i32 + writer.extend_from_slice(&zigzag_var_i32_to_bytes(data.len() as i32)); + // 写入数据 + for i in data { + match i { + NbtValue::Byte(x) => writer.push(*x as u8), + NbtValue::Short(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Int(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Long(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Float(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Double(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::ByteArray(x) => Self::write_i8_array(writer, x), + NbtValue::IntArray(x) => Self::write_i32_array(writer, x), + NbtValue::LongArray(x) => Self::write_i64_array(writer, x), + NbtValue::String(x) => Self::write_nbt_string(writer, x), + NbtValue::List(x) => Self::write_list(writer, x)?, + NbtValue::Compound(name, data) => { + Self::write_compound(writer, name.as_ref(), data)? + } + } + } + Ok(()) + } + fn write_compound( + writer: &mut Vec, + name: Option<&String>, + data: &[(String, NbtValue)], + ) -> NbtResult<()> { + // 写入自己的名字 + Self::write_nbt_string(writer, name.unwrap_or(&"".to_string())); + for (key, value) in data { + // 写入 tag + writer.push(value.tag()); + // 写入 key + Self::write_nbt_string(writer, key); + // 写入 value + match value { + NbtValue::Byte(x) => writer.push(*x as u8), + NbtValue::Short(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Int(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Long(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Float(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::Double(x) => writer.extend_from_slice(&x.to_le_bytes()), + NbtValue::ByteArray(x) => Self::write_i8_array(writer, x), + NbtValue::IntArray(x) => Self::write_i32_array(writer, x), + NbtValue::LongArray(x) => Self::write_i64_array(writer, x), + NbtValue::String(x) => Self::write_nbt_string(writer, x), + NbtValue::List(x) => Self::write_list(writer, x)?, + NbtValue::Compound(name, data) => { + Self::write_compound(writer, name.as_ref(), data)? + } + } + } + // 写入结束 tag + writer.push(0); + Ok(()) + } + + fn write_to(value: &NbtValue, buff: &mut Vec) -> NbtResult<()> { + // 写入 tag + match value { + NbtValue::Compound(name, data) => { + buff.push(value.tag()); + Self::write_compound(buff, name.as_ref(), data)? + } + NbtValue::List(data) => { + buff.push(value.tag()); + Self::write_list(buff, data)? + } + x => return Err(NbtError::WrongRootType(x.tag())), + } + Ok(()) + } + fn write_to_with_name(name: &str, value: &NbtValue, buff: &mut Vec) -> NbtResult<()> { + // 写入 tag + buff.push(value.tag()); + // 写入 key + Self::write_nbt_string(buff, name); + // 写入 value + Self::write_to(value, buff)?; + Ok(()) + } + fn to_binary(value: &NbtValue) -> NbtResult> { + let mut buff = Vec::new(); + BedrockNetVarInt::write_to(value, &mut buff)?; + Ok(buff) + } +}