nbt-rust/shen-nbt5/src/lib.rs

200 lines
5.5 KiB
Rust

pub mod reader;
use reader::NbtReader;
#[cfg(test)]
mod tests;
/// 后面也许会实现的
///
/// 不同版本的 Nbt 数据细节不同
/// 老要命了
///
/// - `Java`
/// Java 版除了 1.20.2+(协议号) 及以后的网络 NBT 格式
/// - `JavaNetAfter1_20_2`
/// 1.20.2+(协议号 >= 764) 及以后的网络 NBT 格式
/// - `BedrockDisk`
/// 基岩版 实际用于存储的 NBT 格式
/// - `BedrockNetVarInt`
/// 基岩版 网络 NBT 格式
// pub enum NbtVersion {
// Java,
// JavaNetAfter1_20_2,
// BedrockDisk,
// BedrockNetVarInt,
// }
pub mod nbt_version {
use super::{NbtReader, NbtResult, NbtValue};
pub trait NbtReadTrait {
fn read_i8_array(reader: &mut NbtReader) -> NbtResult<Vec<i8>>;
fn read_i32_array(reader: &mut NbtReader) -> NbtResult<Vec<i32>>;
fn read_i64_array(reader: &mut NbtReader) -> NbtResult<Vec<i64>>;
fn read_nbt_string(reader: &mut NbtReader) -> NbtResult<String>;
fn read_list(reader: &mut NbtReader) -> NbtResult<Vec<NbtValue>>;
fn read_compound(reader: &mut NbtReader) -> NbtResult<Vec<(String, NbtValue)>>;
fn from_reader(reader: NbtReader) -> NbtResult<NbtValue>;
}
/// Java 版 绝大部分的 NBT 格式
///
/// 除了 1.20.2+(协议号 >= 764) 及以后 的网路传输 NBT 格式 都是这个
///
/// 上面说的那玩意 请使用 `JavaNetAfter1_20_2`
///
/// # 编码特点
///
/// 大端, 大端, 还是 xx 的 大端!
pub enum Java {}
pub enum JavaNetAfter1_20_2 {}
pub enum BedrockDisk {}
pub enum BedrockNetVarInt {}
}
pub type NbtTypeId = u8;
/// 把 u8 转换成对应的 Nbt 类型名称
pub trait NbtTypeConversion {
/// 把 u8 转换成对应的 Nbt 类型名称
fn as_nbt_type_name(&self) -> String;
}
impl NbtTypeConversion for NbtTypeId {
fn as_nbt_type_name(&self) -> String {
if *self > 12 {
return format!("未知类型({})", *self);
}
match *self {
0 => "NBT_End(0)",
1 => "NBT_Byte(1)",
2 => "NBT_Short(2)",
3 => "NBT_Int(3)",
4 => "NBT_Long(4)",
5 => "NBT_Float(5)",
6 => "NBT_Double(6)",
7 => "NBT_ByteArray(7)",
8 => "NBT_String(8)",
9 => "NBT_List(9)",
10 => "NBT_Compound(10)",
11 => "NBT_IntArray(11)",
12 => "NBT_LongArray(12)",
_ => unreachable!(),
}
.to_string()
}
}
/// Error
#[derive(Debug, Clone, PartialEq)]
pub enum NbtError {
/// 未知错误
UnknownErr(String),
/// 根节点类型错误
WrongRootType(u8),
/// 根节点无名称
RootWithoutName,
/// 未知类型
UnknownType(u8),
/// 名称读取错误
NameRead(String),
/// 指针超出范围
///
/// cursor, len, data.len()
/// 三个参数分别表示
/// - 当前指针
/// - 数据长度
/// - 数据总长度
CursorOverflow(usize, usize, usize),
/// Varint 过大
VarIntTooBig(usize),
/// Varlong 过大
VarlongTooBig(usize),
}
pub type NbtResult<T> = Result<T, NbtError>;
impl std::fmt::Display for NbtError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NbtError::UnknownErr(s) => write!(f, "未知错误: {}", s),
NbtError::WrongRootType(n) => {
match n {
9 => {
write!(f, "根节点为 NbtList(9) 类型, 是否应该使用 BedrockDisk/BedrockNetVarInt 解析?")
}
_ => {
write!(f, "根节点类型错误: {}, 应为 NbtCompound/NbtList(bedrock only)", n)
}
}
}
NbtError::RootWithoutName => {
write!(f, "根节点无名称, 是否应该使用 JavaNetAfter1_20_2 解析?")
}
NbtError::UnknownType(n) => {
if *n == 0 {
write!(f, "未知类型: NBTEnd(0), 请检查数据是否正确")
} else {
write!(f, "未知类型: {}", n)
}
}
NbtError::NameRead(s) => write!(f, "名称读取错误: {}", s),
NbtError::CursorOverflow(cursor, len, data_len) => write!(
f,
"指针超出范围: cursor: {}, len: {}, cursor+len: {}, data.len(): {}",
cursor,
len,
cursor + len,
data_len
),
NbtError::VarIntTooBig(n) => write!(f, "VarInt 过大: {} 最大长度为 5", n),
NbtError::VarlongTooBig(n) => write!(f, "VarLong 过大: {} 最大长度为 10", n),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum NbtValue {
// end: 0
/// 1: Byte
Byte(i8),
/// 2
Short(i16),
/// 3
Int(i32),
/// 4
Long(i64),
/// 5
Float(f32),
/// 6
Double(f64),
/// 7
/// 长度: i32
ByteArray(Vec<i8>),
/// 8
/// 或者叫 u8 array
/// 长度: u16
String(String),
/// 9
/// 长度: i32
List(Vec<NbtValue>),
/// 10
Compound(Option<String>, Vec<(String, NbtValue)>),
/// 11
/// 长度: i32
IntArray(Vec<i32>),
/// 12
/// 长度: i32
LongArray(Vec<i64>),
}
impl NbtValue {
pub fn from_binary<T>(data: &mut [u8]) -> NbtResult<NbtValue>
where
T: nbt_version::NbtReadTrait,
{
let reader = NbtReader::new(data);
T::from_reader(reader)
}
}