理论上好了
This commit is contained in:
parent
393083891c
commit
5073d9780a
@ -29,13 +29,13 @@ impl nbt_version::NbtReadTrait for nbt_version::Java {
|
||||
#[inline]
|
||||
fn read_i32_array(reader: &mut NbtReader) -> NbtResult<Vec<i32>> {
|
||||
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<Vec<i64>> {
|
||||
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<Vec<i32>> {
|
||||
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<Vec<i64>> {
|
||||
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<Vec<i32>> {
|
||||
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<Vec<i64>> {
|
||||
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<Vec<(String, NbtValue)>> {
|
||||
@ -727,7 +727,7 @@ impl NbtReader<'_> {
|
||||
///
|
||||
/// 长度溢出会导致 UB
|
||||
#[inline]
|
||||
pub unsafe fn read_i32_array_unsafe(&mut self, len: usize) -> Vec<i32> {
|
||||
pub unsafe fn read_be_i32_array_unsafe(&mut self, len: usize) -> Vec<i32> {
|
||||
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<i32> {
|
||||
pub fn read_be_i32_array(&mut self, len: usize) -> Vec<i32> {
|
||||
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<i64> {
|
||||
pub unsafe fn read_be_i64_array_unsafe(&mut self, len: usize) -> Vec<i64> {
|
||||
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<i64> {
|
||||
pub fn read_be_i64_array(&mut self, len: usize) -> Vec<i64> {
|
||||
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<i16> {
|
||||
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<i32> {
|
||||
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<i64> {
|
||||
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 字符串
|
||||
///
|
||||
/// # 安全性
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -202,3 +202,339 @@ impl NbtWriteTrait for JavaNetAfter1_20_2 {
|
||||
Ok(buff)
|
||||
}
|
||||
}
|
||||
|
||||
/// 比较痛苦的一集
|
||||
impl NbtWriteTrait for BedrockDisk {
|
||||
#[inline]
|
||||
fn write_i8_array(writer: &mut Vec<u8>, 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::<Vec<u8>>().as_slice());
|
||||
}
|
||||
#[inline]
|
||||
fn write_i32_array(writer: &mut Vec<u8>, 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::<Vec<[u8; 4]>>().concat(),
|
||||
);
|
||||
}
|
||||
#[inline]
|
||||
fn write_i64_array(writer: &mut Vec<u8>, 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::<Vec<[u8; 8]>>().concat(),
|
||||
);
|
||||
}
|
||||
#[inline]
|
||||
fn write_nbt_string(writer: &mut Vec<u8>, 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<u8>, 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<u8>,
|
||||
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<u8>) -> 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<u8>) -> 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<Vec<u8>> {
|
||||
let mut buff = Vec::new();
|
||||
BedrockDisk::write_to(value, &mut buff)?;
|
||||
Ok(buff)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn var_i32_to_bytes(value: i32) -> Vec<u8> {
|
||||
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<u8> {
|
||||
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<u8> {
|
||||
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<u8> {
|
||||
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<u8>, 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::<Vec<u8>>().as_slice());
|
||||
}
|
||||
fn write_i32_array(writer: &mut Vec<u8>, 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::<Vec<[u8; 4]>>().concat(),
|
||||
);
|
||||
}
|
||||
fn write_i64_array(writer: &mut Vec<u8>, 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::<Vec<[u8; 8]>>().concat(),
|
||||
);
|
||||
}
|
||||
fn write_nbt_string(writer: &mut Vec<u8>, 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<u8>, 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<u8>,
|
||||
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<u8>) -> 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<u8>) -> 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<Vec<u8>> {
|
||||
let mut buff = Vec::new();
|
||||
BedrockNetVarInt::write_to(value, &mut buff)?;
|
||||
Ok(buff)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user