Compare commits
4 Commits
1d8a7400eb
...
ec6600e123
Author | SHA1 | Date | |
---|---|---|---|
ec6600e123 | |||
04b4cf3047 | |||
90ab2135ed | |||
395a26bd41 |
12
README.md
12
README.md
@ -1,4 +1,4 @@
|
||||
# nbt-rust
|
||||
# shen-nbt5
|
||||
|
||||
一个 "全功能" 的 "快速" NBT 解析器
|
||||
|
||||
@ -64,9 +64,11 @@ writen in rust!
|
||||
|
||||
## 感谢
|
||||
|
||||
感谢 @langyo 和 @InfyniteHeap
|
||||
感谢 [@langyo](https://github.com/langyo) 和 [@InfyniteHeap](https://github.com/InfyniteHeap)
|
||||
在编写过程中的帮助(
|
||||
|
||||
感谢 [mat](https://github.com/mat-1) 的 simd-nbt 中 [`mutf8.rs`](https://github.com/azalea-rs/simdnbt/blob/master/simdnbt/benches/mutf8.rs) 的实现
|
||||
|
||||
感谢 [wiki.vg](https://wiki.vg/NBT) 存储的 NBT 格式的详细信息
|
||||
|
||||
## 概况
|
||||
@ -137,3 +139,9 @@ speed: 2483288579.985664 (bytes/s)
|
||||
2368.2485389572753 (MB/s)
|
||||
2.312742713825464 (GB/s)
|
||||
```
|
||||
|
||||
shen-nbt5 通过了作者电脑上 所有 .nbt 格式的文件的读取测试
|
||||
|
||||
```text
|
||||
total: 6063, open failed: 25, parse failed: 0, gzip parse: 6013, normal parse: 25
|
||||
```
|
||||
|
@ -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"
|
||||
@ -20,3 +20,9 @@ serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
[features]
|
||||
default = []
|
||||
serde = ["dep:serde"]
|
||||
test = []
|
||||
|
||||
# test dep
|
||||
[dev-dependencies]
|
||||
# gzip
|
||||
flate2 = "1.0"
|
||||
|
@ -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)]
|
||||
|
@ -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<i16> {
|
||||
let mut value: Vec<i16> = 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<i32> {
|
||||
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<i32> = 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<i64> {
|
||||
let mut value: Vec<i64> = 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<i64> {
|
||||
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<i64> {
|
||||
|
@ -280,9 +280,51 @@ 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 {
|
||||
use std::io::Read;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
@ -471,4 +513,65 @@ mod nbt {
|
||||
assert!(value.is_ok());
|
||||
// 其他版本
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "test")]
|
||||
fn file_sys_test() {
|
||||
// 测试所有能直接找到的 .nbt 文件
|
||||
// es -r .*\.nbt
|
||||
// command
|
||||
// 总计数, 文件打开失败计数, 解析失败计数, gzip 解析计数, 普通解析计数
|
||||
let mut counter: Vec<i32> = vec![0; 5];
|
||||
|
||||
let find_paths = std::process::Command::new("es")
|
||||
.arg("-r")
|
||||
.arg(r".*\.nbt$")
|
||||
.output()
|
||||
.expect("failed to execute process");
|
||||
let find_paths = String::from_utf8_lossy(find_paths.stdout.as_slice());
|
||||
let find_paths = find_paths.split("\n").collect::<Vec<&str>>();
|
||||
for path in find_paths {
|
||||
if path.len() == 0 {
|
||||
continue;
|
||||
}
|
||||
counter[0] += 1;
|
||||
let path = path.trim();
|
||||
// println!("path: {}", path);
|
||||
let file = std::fs::File::open(path);
|
||||
if file.is_err() {
|
||||
println!("open file failed: {}", path);
|
||||
counter[1] += 1;
|
||||
continue;
|
||||
}
|
||||
let file = file.unwrap();
|
||||
let mut data = file.bytes().collect::<Result<Vec<u8>, _>>().unwrap();
|
||||
|
||||
// 检查一下是否是 gzip
|
||||
if data[0] == 0x1F && data[1] == 0x8B {
|
||||
let mut decoder = flate2::read::GzDecoder::new(data.as_slice());
|
||||
let mut data = Vec::with_capacity(data.len());
|
||||
decoder.read_to_end(&mut data).unwrap();
|
||||
let value = NbtValue::from_binary::<nbt_version::Java>(&mut data);
|
||||
if !value.is_ok() {
|
||||
counter[2] += 1;
|
||||
println!("failed: {} {:?}", path, value.as_ref());
|
||||
assert!(value.is_ok());
|
||||
}
|
||||
counter[3] += 1;
|
||||
} else {
|
||||
let value = NbtValue::from_binary::<nbt_version::Java>(&mut data);
|
||||
if !value.is_ok() {
|
||||
counter[2] += 1;
|
||||
println!("failed: {} {:?}", path, value.as_ref());
|
||||
assert!(value.is_ok());
|
||||
}
|
||||
counter[4] += 1;
|
||||
}
|
||||
}
|
||||
// 输出统计结果
|
||||
println!(
|
||||
"total: {}, open failed: {}, parse failed: {}, gzip parse: {}, normal parse: {}",
|
||||
counter[0], counter[1], counter[2], counter[3], counter[4]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ impl NbtWriteTrait for JavaNetAfter1_20_2 {
|
||||
buff.push(0);
|
||||
Ok(())
|
||||
}
|
||||
x => return Err(NbtError::WrongRootType(x.tag())),
|
||||
x => Err(NbtError::WrongRootType(x.tag())),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
|
Loading…
Reference in New Issue
Block a user