use crate::CompressionError;
pub trait CustomDecompression: Send + Sync {
fn decompress(
&self,
data: &[u8],
algorithm: &str,
out: &mut Vec<u8>,
) -> Result<usize, CompressionError>;
}
impl CustomDecompression for () {
fn decompress(&self, _: &[u8], _: &str, _: &mut Vec<u8>) -> Result<usize, CompressionError> {
Err(CompressionError::Unsupported)
}
}
pub trait CustomCompression: Send + Sync {
fn compress(
&self,
data: &[u8],
algorithm: &str,
out: &mut Vec<u8>,
) -> Result<(), CompressionError>;
}
impl CustomCompression for () {
fn compress(&self, _: &[u8], _: &str, _: &mut Vec<u8>) -> Result<(), CompressionError> {
Err(CompressionError::Unsupported)
}
}
#[cfg(test)]
mod test {
use crate::{
ChunkIter, Compression, CompressionError, CustomCompression, CustomDecompression, McaError,
RegionReader, RegionWriter, regions::*,
};
use lzma_rust2::{Lzma2Options, Lzma2Reader, Lzma2Writer, LzmaOptions};
use na_nbt::ValueRef;
use std::io::{Read, Write};
struct LZMA2Format;
impl LZMA2Format {
const ID: &'static str = "lzma";
pub fn compression() -> Compression {
Compression::new_custom(Self::ID)
}
}
impl CustomCompression for LZMA2Format {
fn compress(
&self,
data: &[u8],
algorithm: &str,
out: &mut Vec<u8>,
) -> Result<(), crate::CompressionError> {
if algorithm != Self::ID {
return Err(CompressionError::Unsupported);
}
let mut writer = Lzma2Writer::new(out, Lzma2Options::default());
writer.write_all(&data).unwrap();
writer.finish().unwrap();
Ok(())
}
}
impl CustomDecompression for LZMA2Format {
fn decompress(
&self,
data: &[u8],
algorithm: &str,
out: &mut Vec<u8>,
) -> Result<usize, CompressionError> {
if algorithm != Self::ID {
return Err(CompressionError::Unsupported);
}
let mut reader = Lzma2Reader::new(data, LzmaOptions::DICT_SIZE_DEFAULT, None);
Ok(reader
.read_to_end(out)
.map_err(|e| CompressionError::Custom(Box::new(e)))?)
}
}
#[test]
fn custom_compression_roundtrip() -> Result<(), McaError> {
let mut region = RegionReader::new(FULL)?;
let mut writer = RegionWriter::new_with_compression(LZMA2Format);
for (x, z) in ChunkIter::new() {
if let Some(chunk) = region.chunk(x, z)? {
writer.set_chunk(x, z, chunk.to_vec(), LZMA2Format::compression())?;
};
}
let mut lzma_region = Vec::new();
writer.write(&mut lzma_region)?;
let mut new_lzma_region = RegionReader::new_with_decompression(&lzma_region, LZMA2Format)?;
for (x, z) in ChunkIter::new() {
if let Some(chunk) = new_lzma_region.chunk(x, z)? {
let nbt = na_nbt::read_borrowed::<na_nbt::BE>(chunk).unwrap();
let nbt = nbt.root();
let status = nbt
.get_::<na_nbt::tag::String>("Status")
.unwrap()
.to_utf8_string();
assert!(status.starts_with("minecraft:"));
}
}
Ok(())
}
}