diff --git a/sercon-backends/Cargo.toml b/sercon-backends/Cargo.toml index 48638a9..e0d3e27 100644 --- a/sercon-backends/Cargo.toml +++ b/sercon-backends/Cargo.toml @@ -12,7 +12,8 @@ serde = "1.0" serde-value = "0.7" ciborium = "0.2.0" -hematite-nbt = "0.5.2" +fastnbt = "2.1.0" +flate2 = "1.0.23" ron = "0.7.0" serde-lexpr = "0.1.2" serde-xml-rs = "0.5.1" diff --git a/sercon-backends/src/backends/nbt.rs b/sercon-backends/src/backends/nbt.rs index 3be9122..eb8d8e6 100644 --- a/sercon-backends/src/backends/nbt.rs +++ b/sercon-backends/src/backends/nbt.rs @@ -1,5 +1,10 @@ use std::io::{Read, Write}; +use flate2::{ + bufread::{GzDecoder, ZlibDecoder}, + write::GzEncoder, + Compression, +}; use miette::{Context, IntoDiagnostic}; use sercon_base::Backend; use serde_value::Value; @@ -9,16 +14,53 @@ pub struct NbtBackend; impl Backend for NbtBackend { fn serialize(&self, out: &mut dyn Write, data: Value) -> miette::Result<()> { - nbt::to_writer(out, &data, None) + let gz = GzEncoder::new(out, Compression::new(5)); + fastnbt::to_writer(gz, &data) .into_diagnostic() - .wrap_err("NBT serialization error") + .wrap_err("failed to serialize NBT data")?; + + Ok(()) } fn deserialize(&self, data: &mut dyn Read) -> miette::Result { - nbt::from_reader(data) + let mut vec = vec![]; + data.read_to_end(&mut vec).into_diagnostic()?; + + let compression = vec + .get(0..2) + .map(|m| match m { + [0x1f, 0x8b] => CompressionType::Gzip, + [0x78, 0x01] | [0x78, 0x9C] | [0x78, 0xDA] => CompressionType::Zlib, + _ => CompressionType::None, + }) + .unwrap_or(CompressionType::None); + let mut decomp = vec![]; + match compression { + CompressionType::Gzip => { + GzDecoder::new(&vec[..]) + .read_to_end(&mut decomp) + .into_diagnostic() + .wrap_err("data gz decompression failed")?; + }, + CompressionType::Zlib => { + ZlibDecoder::new(&vec[..]) + .read_to_end(&mut decomp) + .into_diagnostic() + .wrap_err("data zlib decompression failed")?; + }, + CompressionType::None => decomp.copy_from_slice(&vec), + } + + fastnbt::from_bytes(&decomp) .into_diagnostic() - .wrap_err("NBT deserialization error") + .wrap_err("NBT deserialization failed") } } impl_filetype_backend!(NbtBackend, ["nbt"]); + +enum CompressionType { + Gzip, + Zlib, + None, +}