use core::fmt;
use std::sync::Arc;
use crate::traits::CompressionAction;
#[cfg(feature = "v3")]
use crate::v3::compressor::DefaultCompressor as V3DefaultCompressor;
#[cfg(feature = "v3_lzma")]
use crate::v3_lzma::compressor::LzmaAdaptiveCompressor as V3LzmaCompressor;
#[cfg(feature = "v3_lzma")]
use crate::v3_lzma::standard_compressor::LzmaStandardCompressor as V3LzmaStandardCompressor;
use crate::v4::compressor::DefaultCompressor as V4DefaultCompressor;
#[cfg(feature = "v3_lzma")]
static V3_LZMA_STANDARD_COMPRESSOR: V3LzmaStandardCompressor = V3LzmaStandardCompressor;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Magic {
Little,
Big,
}
impl Magic {
fn magic(self) -> [u8; 4] {
match self {
Self::Little => *b"hsqs",
Self::Big => *b"sqsh",
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Endian {
Little,
Big,
}
#[derive(Clone)]
pub enum VersionedCompressor {
#[cfg(feature = "v3")]
V3(&'static V3DefaultCompressor),
#[cfg(feature = "v3_lzma")]
V3Lzma(&'static V3LzmaCompressor),
#[cfg(feature = "v3_lzma")]
V3LzmaStandard(&'static V3LzmaStandardCompressor),
V4(&'static V4DefaultCompressor),
CustomV4(
&'static (
dyn crate::traits::CompressionAction<
Error = crate::BackhandError,
Compressor = crate::v4::compressor::Compressor,
FilesystemCompressor = crate::v4::filesystem::writer::FilesystemCompressor,
SuperBlock = crate::v4::squashfs::SuperBlock,
> + Send
+ Sync
),
),
}
impl VersionedCompressor {
pub fn decompress(
&self,
bytes: &[u8],
out: &mut Vec<u8>,
compressor: Option<crate::traits::types::Compressor>,
) -> Result<(), crate::BackhandError> {
match self {
#[cfg(feature = "v3")]
VersionedCompressor::V3(comp) => comp.decompress(bytes, out, None),
#[cfg(feature = "v3_lzma")]
VersionedCompressor::V3Lzma(comp) => comp.decompress(bytes, out, None),
#[cfg(feature = "v3_lzma")]
VersionedCompressor::V3LzmaStandard(comp) => comp.decompress(bytes, out, None),
VersionedCompressor::V4(comp) => {
let v4_compressor =
compressor.ok_or(crate::BackhandError::MissingCompressor)?.into();
comp.decompress(bytes, out, v4_compressor)
}
VersionedCompressor::CustomV4(comp) => {
let v4_compressor =
compressor.ok_or(crate::BackhandError::MissingCompressor)?.into();
comp.decompress(bytes, out, v4_compressor)
}
}
}
}
#[derive(Clone)]
pub struct InnerKind {
pub(crate) magic: [u8; 4],
pub(crate) type_endian: deku::ctx::Endian,
pub(crate) data_endian: deku::ctx::Endian,
pub(crate) version_major: u16,
pub(crate) version_minor: u16,
pub(crate) compressor: VersionedCompressor,
#[allow(dead_code)]
pub(crate) bit_order: Option<deku::ctx::Order>,
}
#[derive(Clone)]
pub struct Kind {
pub(crate) inner: Arc<InnerKind>,
}
impl fmt::Debug for Kind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FilesystemWriter")
.field("magic", &self.inner.magic)
.field("type_endian", &self.inner.type_endian)
.field("data_endian", &self.inner.data_endian)
.field("version_major", &self.inner.version_major)
.field("version_minor", &self.inner.version_minor)
.finish()
}
}
impl Kind {
pub fn new_v4<C>(compression: &'static C) -> Self
where
C: crate::traits::CompressionAction<
Error = crate::BackhandError,
Compressor = crate::v4::compressor::Compressor,
FilesystemCompressor = crate::v4::filesystem::writer::FilesystemCompressor,
SuperBlock = crate::v4::squashfs::SuperBlock,
> + Send
+ Sync,
{
Kind {
inner: Arc::new(InnerKind {
magic: LE_V4_0.magic,
type_endian: LE_V4_0.type_endian,
data_endian: LE_V4_0.data_endian,
version_major: LE_V4_0.version_major,
version_minor: LE_V4_0.version_minor,
compressor: VersionedCompressor::CustomV4(compression),
bit_order: LE_V4_0.bit_order,
}),
}
}
pub fn new_v4_with_const<C>(compression: &'static C, inner: InnerKind) -> Self
where
C: crate::traits::CompressionAction<
Error = crate::BackhandError,
Compressor = crate::v4::compressor::Compressor,
FilesystemCompressor = crate::v4::filesystem::writer::FilesystemCompressor,
SuperBlock = crate::v4::squashfs::SuperBlock,
> + Send
+ Sync,
{
Kind {
inner: Arc::new(InnerKind {
magic: inner.magic,
type_endian: inner.type_endian,
data_endian: inner.data_endian,
version_major: inner.version_major,
version_minor: inner.version_minor,
compressor: VersionedCompressor::CustomV4(compression),
bit_order: inner.bit_order,
}),
}
}
pub fn from_target(s: &str) -> Result<Kind, String> {
let kind = match s {
"be_v4_0" => BE_V4_0,
"le_v4_0" => LE_V4_0,
"avm_be_v4_0" => AVM_BE_V4_0,
#[cfg(feature = "v3")]
"be_v3_0" => BE_V3_0,
#[cfg(feature = "v3")]
"le_v3_0" => LE_V3_0,
#[cfg(feature = "v3_lzma")]
"le_v3_0_lzma" => LE_V3_0_LZMA,
#[cfg(feature = "v3_lzma")]
"be_v3_0_lzma" => BE_V3_0_LZMA,
#[cfg(feature = "v3_lzma")]
"netgear_be_v3_0_lzma" => NETGEAR_BE_V3_0_LZMA,
#[cfg(feature = "v3_lzma")]
"netgear_be_v3_0_lzma_standard" => NETGEAR_BE_V3_0_LZMA_STANDARD,
#[cfg(feature = "v3_lzma")]
"le_v3_1_lzma_swap" => LE_V3_1_LZMA_SWAP,
#[cfg(feature = "v3_lzma")]
"be_v3_1_lzma_swap" => BE_V3_1_LZMA_SWAP,
_ => return Err("not a valid kind".to_string()),
};
Ok(Kind { inner: Arc::new(kind) })
}
pub fn from_const(inner: InnerKind) -> Result<Kind, String> {
Ok(Kind { inner: Arc::new(inner) })
}
pub fn from_kind(kind: &Kind) -> Kind {
Self { inner: kind.inner.clone() }
}
pub fn with_magic(self, magic: Magic) -> Self {
let mut inner = (*self.inner).clone();
inner.magic = magic.magic();
Self { inner: Arc::new(inner) }
}
pub fn magic(&self) -> [u8; 4] {
self.inner.magic
}
pub fn version_major(&self) -> u16 {
self.inner.version_major
}
pub fn version_minor(&self) -> u16 {
self.inner.version_minor
}
pub fn with_type_endian(self, endian: Endian) -> Self {
let mut inner = (*self.inner).clone();
inner.type_endian = match endian {
Endian::Little => deku::ctx::Endian::Little,
Endian::Big => deku::ctx::Endian::Big,
};
Self { inner: Arc::new(inner) }
}
pub fn with_data_endian(self, endian: Endian) -> Self {
let mut inner = (*self.inner).clone();
inner.data_endian = match endian {
Endian::Little => deku::ctx::Endian::Little,
Endian::Big => deku::ctx::Endian::Big,
};
Self { inner: Arc::new(inner) }
}
pub fn with_all_endian(self, endian: Endian) -> Self {
let mut inner = (*self.inner).clone();
match endian {
Endian::Little => {
inner.type_endian = deku::ctx::Endian::Little;
inner.data_endian = deku::ctx::Endian::Little;
}
Endian::Big => {
inner.type_endian = deku::ctx::Endian::Big;
inner.data_endian = deku::ctx::Endian::Big;
}
}
Self { inner: Arc::new(inner) }
}
pub fn with_version(self, major: u16, minor: u16) -> Self {
let mut inner = (*self.inner).clone();
inner.version_major = major;
inner.version_minor = minor;
Self { inner: Arc::new(inner) }
}
}
pub const LE_V4_0: InnerKind = InnerKind {
magic: *b"hsqs",
type_endian: deku::ctx::Endian::Little,
data_endian: deku::ctx::Endian::Little,
version_major: 4,
version_minor: 0,
compressor: VersionedCompressor::V4(&V4DefaultCompressor),
bit_order: None,
};
pub const BE_V4_0: InnerKind = InnerKind {
magic: *b"sqsh",
type_endian: deku::ctx::Endian::Big,
data_endian: deku::ctx::Endian::Big,
version_major: 4,
version_minor: 0,
compressor: VersionedCompressor::V4(&V4DefaultCompressor),
bit_order: None,
};
pub const AVM_BE_V4_0: InnerKind = InnerKind {
magic: *b"sqsh",
type_endian: deku::ctx::Endian::Big,
data_endian: deku::ctx::Endian::Little,
version_major: 4,
version_minor: 0,
compressor: VersionedCompressor::V4(&V4DefaultCompressor),
bit_order: None,
};
#[cfg(feature = "v3")]
pub const LE_V3_0: InnerKind = InnerKind {
magic: *b"hsqs",
type_endian: deku::ctx::Endian::Little,
data_endian: deku::ctx::Endian::Little,
version_major: 3,
version_minor: 0,
compressor: VersionedCompressor::V3(&V3DefaultCompressor),
bit_order: Some(deku::ctx::Order::Lsb0),
};
#[cfg(feature = "v3")]
pub const BE_V3_0: InnerKind = InnerKind {
magic: *b"sqsh",
type_endian: deku::ctx::Endian::Big,
data_endian: deku::ctx::Endian::Big,
version_major: 3,
version_minor: 0,
compressor: VersionedCompressor::V3(&V3DefaultCompressor),
bit_order: Some(deku::ctx::Order::Msb0),
};
#[cfg(feature = "v3_lzma")]
pub const LE_V3_0_LZMA: InnerKind = InnerKind {
magic: *b"hsqs",
type_endian: deku::ctx::Endian::Little,
data_endian: deku::ctx::Endian::Little,
version_major: 3,
version_minor: 0,
compressor: VersionedCompressor::V3Lzma(&V3LzmaCompressor),
bit_order: Some(deku::ctx::Order::Lsb0),
};
#[cfg(feature = "v3_lzma")]
pub const BE_V3_0_LZMA: InnerKind = InnerKind {
magic: *b"sqsh",
type_endian: deku::ctx::Endian::Big,
data_endian: deku::ctx::Endian::Big,
version_major: 3,
version_minor: 0,
compressor: VersionedCompressor::V3Lzma(&V3LzmaCompressor),
bit_order: Some(deku::ctx::Order::Msb0),
};
#[cfg(feature = "v3_lzma")]
pub const NETGEAR_BE_V3_0_LZMA: InnerKind = InnerKind {
magic: *b"qshs",
type_endian: deku::ctx::Endian::Big,
data_endian: deku::ctx::Endian::Big,
version_major: 3,
version_minor: 0,
compressor: VersionedCompressor::V3Lzma(&V3LzmaCompressor),
bit_order: Some(deku::ctx::Order::Msb0),
};
#[cfg(feature = "v3_lzma")]
pub const NETGEAR_BE_V3_0_LZMA_STANDARD: InnerKind = InnerKind {
magic: *b"qshs",
type_endian: deku::ctx::Endian::Big,
data_endian: deku::ctx::Endian::Big,
version_major: 3,
version_minor: 0,
compressor: VersionedCompressor::V3LzmaStandard(&V3_LZMA_STANDARD_COMPRESSOR),
bit_order: Some(deku::ctx::Order::Msb0),
};
#[cfg(feature = "v3_lzma")]
pub const LE_V3_1_LZMA_SWAP: InnerKind = InnerKind {
magic: *b"shsq",
type_endian: deku::ctx::Endian::Little,
data_endian: deku::ctx::Endian::Little,
version_major: 3,
version_minor: 1,
compressor: VersionedCompressor::V3Lzma(&V3LzmaCompressor),
bit_order: Some(deku::ctx::Order::Lsb0),
};
#[cfg(feature = "v3_lzma")]
pub const BE_V3_1_LZMA_SWAP: InnerKind = InnerKind {
magic: *b"shsq",
type_endian: deku::ctx::Endian::Big,
data_endian: deku::ctx::Endian::Big,
version_major: 3,
version_minor: 1,
compressor: VersionedCompressor::V3Lzma(&V3LzmaCompressor),
bit_order: Some(deku::ctx::Order::Msb0),
};