diff --git a/avbroot/src/format/compression.rs b/avbroot/src/format/compression.rs index 4ea050a..1776eae 100644 --- a/avbroot/src/format/compression.rs +++ b/avbroot/src/format/compression.rs @@ -10,14 +10,22 @@ use flate2::{read::GzDecoder, write::GzEncoder, Compression}; use lz4_flex::frame::FrameDecoder; use serde::{Deserialize, Serialize}; use thiserror::Error; +use xz2::{ + read::XzDecoder, + stream::{Check, Stream}, + write::XzEncoder, +}; static GZIP_MAGIC: &[u8; 2] = b"\x1f\x8b"; static LZ4_LEGACY_MAGIC: &[u8; 4] = b"\x02\x21\x4c\x18"; +static XZ_MAGIC: &[u8; 6] = b"\xfd\x37\x7a\x58\x5a\x00"; #[derive(Debug, Error)] pub enum Error { #[error("Unknown compression format")] UnknownFormat, + #[error("XZ stream error")] + XzStream(#[from] xz2::stream::Error), #[error("I/O error")] Io(#[from] io::Error), } @@ -102,25 +110,29 @@ pub enum CompressedFormat { None, Gzip, Lz4Legacy, + Xz, } pub enum CompressedReader { None(R), Gzip(GzDecoder), Lz4(FrameDecoder), + Xz(XzDecoder), } impl CompressedReader { pub fn new(mut reader: R, raw_if_unknown: bool) -> Result { - let mut magic = [0u8; 4]; + let mut magic = [0u8; 6]; reader.read_exact(&mut magic)?; reader.rewind()?; if &magic[0..2] == GZIP_MAGIC { Ok(Self::Gzip(GzDecoder::new(reader))) - } else if &magic == LZ4_LEGACY_MAGIC { + } else if &magic[0..4] == LZ4_LEGACY_MAGIC { Ok(Self::Lz4(FrameDecoder::new(reader))) + } else if &magic == XZ_MAGIC { + Ok(Self::Xz(XzDecoder::new(reader))) } else if raw_if_unknown { Ok(Self::None(reader)) } else { @@ -133,6 +145,7 @@ impl CompressedReader { Self::None(_) => CompressedFormat::None, Self::Gzip(_) => CompressedFormat::Gzip, Self::Lz4(_) => CompressedFormat::Lz4Legacy, + Self::Xz(_) => CompressedFormat::Xz, } } @@ -141,6 +154,7 @@ impl CompressedReader { Self::None(r) => r, Self::Gzip(r) => r.into_inner(), Self::Lz4(r) => r.into_inner(), + Self::Xz(r) => r.into_inner(), } } } @@ -151,6 +165,7 @@ impl Read for CompressedReader { Self::None(r) => r.read(buf), Self::Gzip(r) => r.read(buf), Self::Lz4(r) => r.read(buf), + Self::Xz(r) => r.read(buf), } } } @@ -159,6 +174,7 @@ pub enum CompressedWriter { None(W), Gzip(GzEncoder), Lz4Legacy(Lz4LegacyEncoder), + Xz(XzEncoder), } impl CompressedWriter { @@ -169,6 +185,11 @@ impl CompressedWriter { Ok(Self::Gzip(GzEncoder::new(writer, Compression::default()))) } CompressedFormat::Lz4Legacy => Ok(Self::Lz4Legacy(Lz4LegacyEncoder::new(writer)?)), + CompressedFormat::Xz => { + // Some kernels are compiled without support for the default CRC64. + let stream = Stream::new_easy_encoder(6, Check::Crc32)?; + Ok(Self::Xz(XzEncoder::new_stream(writer, stream))) + } } } @@ -177,6 +198,7 @@ impl CompressedWriter { Self::None(_) => CompressedFormat::None, Self::Gzip(_) => CompressedFormat::Gzip, Self::Lz4Legacy(_) => CompressedFormat::Lz4Legacy, + Self::Xz(_) => CompressedFormat::Xz, } } @@ -185,6 +207,7 @@ impl CompressedWriter { Self::None(w) => Ok(w), Self::Gzip(w) => w.finish(), Self::Lz4Legacy(w) => w.finish(), + Self::Xz(w) => w.finish(), } } } @@ -195,6 +218,7 @@ impl Write for CompressedWriter { Self::None(w) => w.write(buf), Self::Gzip(w) => w.write(buf), Self::Lz4Legacy(w) => w.write(buf), + Self::Xz(w) => w.write(buf), } } @@ -203,6 +227,7 @@ impl Write for CompressedWriter { Self::None(w) => w.flush(), Self::Gzip(w) => w.flush(), Self::Lz4Legacy(w) => w.flush(), + Self::Xz(w) => w.flush(), } } }