diff options
| author | mat <github@matdoes.dev> | 2022-04-24 17:37:57 -0500 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2022-04-24 17:37:57 -0500 |
| commit | 3e507f0db4020eaf406ba69aae3d4dc1301d29ac (patch) | |
| tree | ca6c127c9db6dfd14511e98944fc031fe5f1e43a /azalea-nbt/src | |
| parent | 9f576c5600ba9a244bc0d433bb7de174284066a2 (diff) | |
| parent | b7641ff308aab7840d2a2253ae50f8ee496b2a97 (diff) | |
| download | azalea-drasl-3e507f0db4020eaf406ba69aae3d4dc1301d29ac.tar.xz | |
Merge branch 'main' into auth
Diffstat (limited to 'azalea-nbt/src')
| -rwxr-xr-x[-rw-r--r--] | azalea-nbt/src/decode.rs | 35 | ||||
| -rwxr-xr-x[-rw-r--r--] | azalea-nbt/src/encode.rs | 231 | ||||
| -rwxr-xr-x[-rw-r--r--] | azalea-nbt/src/error.rs | 11 | ||||
| -rwxr-xr-x[-rw-r--r--] | azalea-nbt/src/lib.rs | 0 | ||||
| -rwxr-xr-x[-rw-r--r--] | azalea-nbt/src/tag.rs | 108 |
5 files changed, 301 insertions, 84 deletions
diff --git a/azalea-nbt/src/decode.rs b/azalea-nbt/src/decode.rs index 41689a46..3e2f7adb 100644..100755 --- a/azalea-nbt/src/decode.rs +++ b/azalea-nbt/src/decode.rs @@ -11,16 +11,17 @@ async fn read_string<R>(stream: &mut R) -> Result<String, Error> where R: AsyncRead + std::marker::Unpin, { - let length = stream.read_u16().await.map_err(|_| Error::InvalidTag)?; + let length = stream.read_u16().await?; let mut buf = Vec::with_capacity(length as usize); for _ in 0..length { - buf.push(stream.read_u8().await.map_err(|_| Error::InvalidTag)?); + buf.push(stream.read_u8().await?); } - String::from_utf8(buf).map_err(|_| Error::InvalidTag) + Ok(String::from_utf8(buf)?) } impl Tag { + #[inline] #[async_recursion] async fn read_known<R>(stream: &mut R, id: u8) -> Result<Tag, Error> where @@ -31,26 +32,26 @@ impl Tag { // a TAG_Compound, and is not named despite being in a TAG_Compound 0 => Tag::End, // A single signed byte - 1 => Tag::Byte(stream.read_i8().await.map_err(|_| Error::InvalidTag)?), + 1 => Tag::Byte(stream.read_i8().await?), // A single signed, big endian 16 bit integer - 2 => Tag::Short(stream.read_i16().await.map_err(|_| Error::InvalidTag)?), + 2 => Tag::Short(stream.read_i16().await?), // A single signed, big endian 32 bit integer - 3 => Tag::Int(stream.read_i32().await.map_err(|_| Error::InvalidTag)?), + 3 => Tag::Int(stream.read_i32().await?), // A single signed, big endian 64 bit integer - 4 => Tag::Long(stream.read_i64().await.map_err(|_| Error::InvalidTag)?), + 4 => Tag::Long(stream.read_i64().await?), // A single, big endian IEEE-754 single-precision floating point // number (NaN possible) - 5 => Tag::Float(stream.read_f32().await.map_err(|_| Error::InvalidTag)?), + 5 => Tag::Float(stream.read_f32().await?), // A single, big endian IEEE-754 double-precision floating point // number (NaN possible) - 6 => Tag::Double(stream.read_f64().await.map_err(|_| Error::InvalidTag)?), + 6 => Tag::Double(stream.read_f64().await?), // A length-prefixed array of signed bytes. The prefix is a signed // integer (thus 4 bytes) 7 => { - let length = stream.read_i32().await.map_err(|_| Error::InvalidTag)?; + let length = stream.read_i32().await?; let mut bytes = Vec::with_capacity(length as usize); for _ in 0..length { - bytes.push(stream.read_i8().await.map_err(|_| Error::InvalidTag)?); + bytes.push(stream.read_i8().await?); } Tag::ByteArray(bytes) } @@ -67,8 +68,8 @@ impl Tag { // another reference implementation by Mojang uses 1 instead; // parsers should accept any type if the length is <= 0). 9 => { - let type_id = stream.read_u8().await.map_err(|_| Error::InvalidTag)?; - let length = stream.read_i32().await.map_err(|_| Error::InvalidTag)?; + let type_id = stream.read_u8().await?; + let length = stream.read_i32().await?; let mut list = Vec::with_capacity(length as usize); for _ in 0..length { list.push(Tag::read_known(stream, type_id).await?); @@ -94,20 +95,20 @@ impl Tag { // signed integer (thus 4 bytes) and indicates the number of 4 byte // integers. 11 => { - let length = stream.read_i32().await.map_err(|_| Error::InvalidTag)?; + let length = stream.read_i32().await?; let mut ints = Vec::with_capacity(length as usize); for _ in 0..length { - ints.push(stream.read_i32().await.map_err(|_| Error::InvalidTag)?); + ints.push(stream.read_i32().await?); } Tag::IntArray(ints) } // A length-prefixed array of signed longs. The prefix is a signed // integer (thus 4 bytes) and indicates the number of 8 byte longs. 12 => { - let length = stream.read_i32().await.map_err(|_| Error::InvalidTag)?; + let length = stream.read_i32().await?; let mut longs = Vec::with_capacity(length as usize); for _ in 0..length { - longs.push(stream.read_i64().await.map_err(|_| Error::InvalidTag)?); + longs.push(stream.read_i64().await?); } Tag::LongArray(longs) } diff --git a/azalea-nbt/src/encode.rs b/azalea-nbt/src/encode.rs index 9ce4faf4..20d13793 100644..100755 --- a/azalea-nbt/src/encode.rs +++ b/azalea-nbt/src/encode.rs @@ -2,96 +2,197 @@ use crate::Error; use crate::Tag; use byteorder::{WriteBytesExt, BE}; use flate2::write::{GzEncoder, ZlibEncoder}; +use std::collections::HashMap; use std::io::Write; +// who needs friends when you've got code that runs in nanoseconds? + #[inline] fn write_string(writer: &mut dyn Write, string: &str) -> Result<(), Error> { - writer - .write_i16::<BE>(string.len() as i16) - .map_err(|_| Error::WriteError)?; - writer - .write_all(string.as_bytes()) - .map_err(|_| Error::WriteError)?; + writer.write_i16::<BE>(string.len() as i16)?; + writer.write_all(string.as_bytes())?; Ok(()) } -impl Tag { - pub fn write_without_end(&self, writer: &mut dyn Write) -> Result<(), Error> { - match self { +#[inline] +fn write_compound( + writer: &mut dyn Write, + value: &HashMap<String, Tag>, + end_tag: bool, +) -> Result<(), Error> { + for (key, tag) in value { + match tag { Tag::End => {} - Tag::Byte(value) => writer.write_i8(*value).map_err(|_| Error::WriteError)?, - Tag::Short(value) => writer - .write_i16::<BE>(*value) - .map_err(|_| Error::WriteError)?, - Tag::Int(value) => writer - .write_i32::<BE>(*value) - .map_err(|_| Error::WriteError)?, - Tag::Long(value) => writer - .write_i64::<BE>(*value) - .map_err(|_| Error::WriteError)?, - Tag::Float(value) => writer - .write_f32::<BE>(*value) - .map_err(|_| Error::WriteError)?, - Tag::Double(value) => writer - .write_f64::<BE>(*value) - .map_err(|_| Error::WriteError)?, + Tag::Byte(value) => { + writer.write_u8(1)?; + write_string(writer, key)?; + writer.write_i8(*value)? + } + Tag::Short(value) => { + writer.write_u8(2)?; + write_string(writer, key)?; + writer.write_i16::<BE>(*value)? + } + Tag::Int(value) => { + writer.write_u8(3)?; + write_string(writer, key)?; + writer.write_i32::<BE>(*value)? + } + Tag::Long(value) => { + writer.write_u8(4)?; + write_string(writer, key)?; + writer.write_i64::<BE>(*value)? + } + Tag::Float(value) => { + writer.write_u8(5)?; + write_string(writer, key)?; + writer.write_f32::<BE>(*value)? + } + Tag::Double(value) => { + writer.write_u8(6)?; + write_string(writer, key)?; + writer.write_f64::<BE>(*value)? + } Tag::ByteArray(value) => { - writer - .write_i32::<BE>(value.len() as i32) - .map_err(|_| Error::WriteError)?; + writer.write_u8(7)?; + write_string(writer, key)?; + writer.write_i32::<BE>(value.len() as i32)?; for &byte in value { - writer.write_i8(byte).map_err(|_| Error::WriteError)?; + writer.write_i8(byte)?; } } Tag::String(value) => { - write_string(writer, value)?; + writer.write_u8(8)?; + write_string(writer, key)?; + write_string(writer, value)? } Tag::List(value) => { - // we just get the type from the first item, or default the type to END - if value.is_empty() { - writer.write_i8(0).map_err(|_| Error::WriteError)?; - writer.write_i32::<BE>(0).map_err(|_| Error::WriteError)?; - } else { - let type_id = value[0].id(); - writer.write_u8(type_id).map_err(|_| Error::WriteError)?; - writer - .write_i32::<BE>(value.len() as i32) - .map_err(|_| Error::WriteError)?; - for tag in value { - tag.write_without_end(writer)?; - } - } + writer.write_u8(9)?; + write_string(writer, key)?; + write_list(writer, value)? } Tag::Compound(value) => { - for (key, tag) in value { - writer.write_u8(tag.id()).map_err(|_| Error::WriteError)?; - write_string(writer, key)?; - tag.write_without_end(writer)?; - } - writer - .write_u8(Tag::End.id()) - .map_err(|_| Error::WriteError)?; + writer.write_u8(10)?; + write_string(writer, key)?; + write_compound(writer, value, true)? } Tag::IntArray(value) => { - writer - .write_i32::<BE>(value.len() as i32) - .map_err(|_| Error::WriteError)?; + writer.write_u8(11)?; + write_string(writer, key)?; + writer.write_i32::<BE>(value.len() as i32)?; for &int in value { - writer.write_i32::<BE>(int).map_err(|_| Error::WriteError)?; + writer.write_i32::<BE>(int)?; } } Tag::LongArray(value) => { - writer - .write_i32::<BE>(value.len() as i32) - .map_err(|_| Error::WriteError)?; + writer.write_u8(12)?; + write_string(writer, key)?; + writer.write_i32::<BE>(value.len() as i32)?; for &long in value { - writer - .write_i64::<BE>(long) - .map_err(|_| Error::WriteError)?; + writer.write_i64::<BE>(long)?; + } + } + } + } + if end_tag { + writer.write_u8(Tag::End.id())?; + } + return Ok(()); +} + +#[inline] +fn write_list(writer: &mut dyn Write, value: &[Tag]) -> Result<(), Error> { + // we just get the type from the first item, or default the type to END + if value.is_empty() { + writer.write_all(&[0; 5])?; + } else { + let first_tag = &value[0]; + writer.write_u8(first_tag.id())?; + writer.write_i32::<BE>(value.len() as i32)?; + match first_tag { + Tag::Int(_) => { + for tag in value { + writer.write_i32::<BE>( + *tag.as_int().expect("List of Int should only contains Int"), + )?; + } + } + Tag::String(_) => { + for tag in value { + write_string( + writer, + tag.as_string() + .expect("List of String should only contain String"), + )?; + } + } + Tag::Compound(_) => { + for tag in value { + write_compound( + writer, + tag.as_compound() + .expect("List of Compound should only contain Compound"), + true, + )?; + } + } + _ => { + for tag in value { + tag.write_without_end(writer)?; } } } + } + + Ok(()) +} + +#[inline] +fn write_bytearray(writer: &mut dyn Write, value: &Vec<i8>) -> Result<(), Error> { + writer.write_i32::<BE>(value.len() as i32)?; + for &byte in value { + writer.write_i8(byte)?; + } + Ok(()) +} + +#[inline] +fn write_intarray(writer: &mut dyn Write, value: &Vec<i32>) -> Result<(), Error> { + writer.write_i32::<BE>(value.len() as i32)?; + for &int in value { + writer.write_i32::<BE>(int)?; + } + Ok(()) +} + +#[inline] +fn write_longarray(writer: &mut dyn Write, value: &Vec<i64>) -> Result<(), Error> { + writer.write_i32::<BE>(value.len() as i32)?; + for &long in value { + writer.write_i64::<BE>(long)?; + } + Ok(()) +} + +impl Tag { + #[inline] + pub fn write_without_end(&self, writer: &mut dyn Write) -> Result<(), Error> { + match self { + Tag::End => {} + Tag::Byte(value) => writer.write_i8(*value)?, + Tag::Short(value) => writer.write_i16::<BE>(*value)?, + Tag::Int(value) => writer.write_i32::<BE>(*value)?, + Tag::Long(value) => writer.write_i64::<BE>(*value)?, + Tag::Float(value) => writer.write_f32::<BE>(*value)?, + Tag::Double(value) => writer.write_f64::<BE>(*value)?, + Tag::ByteArray(value) => write_bytearray(writer, value)?, + Tag::String(value) => write_string(writer, value)?, + Tag::List(value) => write_list(writer, value)?, + Tag::Compound(value) => write_compound(writer, value, true)?, + Tag::IntArray(value) => write_intarray(writer, value)?, + Tag::LongArray(value) => write_longarray(writer, value)?, + } Ok(()) } @@ -99,11 +200,7 @@ impl Tag { pub fn write(&self, writer: &mut impl Write) -> Result<(), Error> { match self { Tag::Compound(value) => { - for (key, tag) in value { - writer.write_u8(tag.id()).map_err(|_| Error::WriteError)?; - write_string(writer, key)?; - tag.write_without_end(writer)?; - } + write_compound(writer, value, false)?; Ok(()) } _ => Err(Error::InvalidTag), diff --git a/azalea-nbt/src/error.rs b/azalea-nbt/src/error.rs index 05ff15e0..219921e4 100644..100755 --- a/azalea-nbt/src/error.rs +++ b/azalea-nbt/src/error.rs @@ -14,3 +14,14 @@ impl std::fmt::Display for Error { } } } + +impl From<std::io::Error> for Error { + fn from(_: std::io::Error) -> Self { + Error::WriteError + } +} +impl From<std::string::FromUtf8Error> for Error { + fn from(_: std::string::FromUtf8Error) -> Self { + Error::WriteError + } +} diff --git a/azalea-nbt/src/lib.rs b/azalea-nbt/src/lib.rs index d14fd929..d14fd929 100644..100755 --- a/azalea-nbt/src/lib.rs +++ b/azalea-nbt/src/lib.rs diff --git a/azalea-nbt/src/tag.rs b/azalea-nbt/src/tag.rs index f11b8889..61bd15ba 100644..100755 --- a/azalea-nbt/src/tag.rs +++ b/azalea-nbt/src/tag.rs @@ -36,4 +36,112 @@ impl Tag { Tag::LongArray(_) => 12, } } + + #[inline] + pub fn as_byte(&self) -> Option<&i8> { + if let Tag::Byte(v) = self { + Some(v) + } else { + None + } + } + + #[inline] + pub fn as_short(&self) -> Option<&i16> { + if let Tag::Short(v) = self { + Some(v) + } else { + None + } + } + + #[inline] + pub fn as_int(&self) -> Option<&i32> { + if let Tag::Int(v) = self { + Some(v) + } else { + None + } + } + + #[inline] + pub fn as_long(&self) -> Option<&i64> { + if let Tag::Long(v) = self { + Some(v) + } else { + None + } + } + + #[inline] + pub fn as_float(&self) -> Option<&f32> { + if let Tag::Float(v) = self { + Some(v) + } else { + None + } + } + + #[inline] + pub fn as_double(&self) -> Option<&f64> { + if let Tag::Double(v) = self { + Some(v) + } else { + None + } + } + + #[inline] + pub fn as_string(&self) -> Option<&str> { + if let Tag::String(v) = self { + Some(v) + } else { + None + } + } + + #[inline] + pub fn as_compound(&self) -> Option<&HashMap<String, Tag>> { + if let Tag::Compound(v) = self { + Some(v) + } else { + None + } + } + + #[inline] + pub fn as_bytearray(&self) -> Option<&Vec<i8>> { + if let Tag::ByteArray(v) = self { + Some(v) + } else { + None + } + } + + #[inline] + pub fn as_intarray(&self) -> Option<&Vec<i32>> { + if let Tag::IntArray(v) = self { + Some(v) + } else { + None + } + } + + #[inline] + pub fn as_longarray(&self) -> Option<&Vec<i64>> { + if let Tag::LongArray(v) = self { + Some(v) + } else { + None + } + } + + #[inline] + pub fn as_list(&self) -> Option<&[Tag]> { + if let Tag::List(v) = self { + Some(v) + } else { + None + } + } } |
