理论上好了

This commit is contained in:
shenjack 2024-03-10 14:22:54 +08:00
parent 393083891c
commit 5073d9780a
Signed by: shenjack
GPG Key ID: 7B1134A979775551
3 changed files with 392 additions and 14 deletions

View File

@ -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 字符串
///
/// # 安全性

View File

@ -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);
}

View File

@ -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)
}
}