From 10afe48585360016552f77cacd783899fdc594fa Mon Sep 17 00:00:00 2001 From: FineFindus Date: Mon, 13 Oct 2025 21:22:39 +0200 Subject: [PATCH 1/8] feat: add `DecodedSize` trait Adds a new trait that to retrieve the size of the data when uncompressed. The implementation of this trait on a format indicates that a format may support retrieving the uncompressed size, however it's not guaranteed. --- crates/compression-codecs/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/compression-codecs/src/lib.rs b/crates/compression-codecs/src/lib.rs index 00265074..2e8b6b8c 100644 --- a/crates/compression-codecs/src/lib.rs +++ b/crates/compression-codecs/src/lib.rs @@ -97,3 +97,8 @@ pub trait Decode { output: &mut PartialBuffer + AsMut<[u8]>>, ) -> Result; } + +pub trait DecodedSize { + /// Returns the size of the input when uncompressed. + fn decoded_size(input: &[u8]) -> Result; +} From 1621f2576d30f497ee7eacf7ab1a7a686a7c129b Mon Sep 17 00:00:00 2001 From: FineFindus Date: Mon, 13 Oct 2025 21:27:12 +0200 Subject: [PATCH 2/8] feat(xz2): implement `uncompressed_size` method --- crates/compression-codecs/src/xz2/decoder.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/crates/compression-codecs/src/xz2/decoder.rs b/crates/compression-codecs/src/xz2/decoder.rs index 8c7534d2..24099a35 100644 --- a/crates/compression-codecs/src/xz2/decoder.rs +++ b/crates/compression-codecs/src/xz2/decoder.rs @@ -1,7 +1,11 @@ -use crate::{lzma::params::LzmaDecoderParams, Decode}; +use crate::{lzma::params::LzmaDecoderParams, Decode, DecodedSize}; use compression_core::util::PartialBuffer; use liblzma::stream::{Action, Status, Stream}; -use std::{convert::TryFrom, fmt, io}; +use std::{ + convert::TryFrom, + fmt, + io::{self, Cursor}, +}; /// Xz2 decoding stream pub struct Xz2Decoder { @@ -108,6 +112,13 @@ impl Decode for Xz2Decoder { } } +impl DecodedSize for Xz2Decoder { + fn decoded_size(input: &[u8]) -> io::Result { + let cursor = Cursor::new(input); + liblzma::uncompressed_size(cursor).map(|size| size as usize) + } +} + #[cfg(test)] mod tests { use std::convert::TryFrom; From eaf199e68176c88d9af2196ffc3ab1666bf808bc Mon Sep 17 00:00:00 2001 From: FineFindus Date: Mon, 13 Oct 2025 21:29:34 +0200 Subject: [PATCH 3/8] feat(xz): support reading uncompressed size --- crates/compression-codecs/src/xz/decoder.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/compression-codecs/src/xz/decoder.rs b/crates/compression-codecs/src/xz/decoder.rs index 48b6de67..e1197f91 100644 --- a/crates/compression-codecs/src/xz/decoder.rs +++ b/crates/compression-codecs/src/xz/decoder.rs @@ -1,4 +1,4 @@ -use crate::{Decode, Xz2Decoder}; +use crate::{Decode, DecodedSize, Xz2Decoder}; use compression_core::util::PartialBuffer; use std::{ convert::TryInto, @@ -97,3 +97,9 @@ impl Decode for XzDecoder { self.inner.finish(output) } } + +impl DecodedSize for XzDecoder { + fn decoded_size(input: &[u8]) -> Result { + Xz2Decoder::decoded_size(input) + } +} From ae9573c9f6b81a7e60397a8e58e074c39e0f7ef7 Mon Sep 17 00:00:00 2001 From: FineFindus Date: Tue, 14 Oct 2025 10:30:21 +0200 Subject: [PATCH 4/8] feat(lzma): implement reading uncompressed size --- crates/compression-codecs/src/lzma/decoder.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/compression-codecs/src/lzma/decoder.rs b/crates/compression-codecs/src/lzma/decoder.rs index fd953f45..e53acf8e 100644 --- a/crates/compression-codecs/src/lzma/decoder.rs +++ b/crates/compression-codecs/src/lzma/decoder.rs @@ -1,4 +1,4 @@ -use crate::{Decode, Xz2Decoder}; +use crate::{Decode, DecodedSize, Xz2Decoder}; use compression_core::util::PartialBuffer; use std::{convert::TryInto, io::Result}; @@ -61,3 +61,9 @@ impl Decode for LzmaDecoder { self.inner.finish(output) } } + +impl DecodedSize for LzmaDecoder { + fn decoded_size(input: &[u8]) -> Result { + Xz2Decoder::decoded_size(input) + } +} From 07385614ae62270184328d0d4f239611b692a301 Mon Sep 17 00:00:00 2001 From: FineFindus Date: Mon, 13 Oct 2025 21:51:46 +0200 Subject: [PATCH 5/8] feat(zstd): support reading uncompressed size --- crates/compression-codecs/src/zstd/decoder.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/compression-codecs/src/zstd/decoder.rs b/crates/compression-codecs/src/zstd/decoder.rs index a35161be..d571b1f0 100644 --- a/crates/compression-codecs/src/zstd/decoder.rs +++ b/crates/compression-codecs/src/zstd/decoder.rs @@ -1,5 +1,5 @@ use crate::zstd::params::DParameter; -use crate::Decode; +use crate::{Decode, DecodedSize}; use compression_core::unshared::Unshared; use compression_core::util::PartialBuffer; use libzstd::stream::raw::{Decoder, Operation}; @@ -84,3 +84,10 @@ impl Decode for ZstdDecoder { Ok(bytes_left == 0) } } + +impl DecodedSize for ZstdDecoder { + fn decoded_size(input: &[u8]) -> Result { + zstd_safe::find_frame_compressed_size(input) + .map_err(|_err| io::Error::from(io::ErrorKind::Other)) + } +} From ac636daeb6bbc5b4e4b73d4e0c70decb1c60ffe3 Mon Sep 17 00:00:00 2001 From: FineFindus Date: Tue, 14 Oct 2025 16:18:08 +0200 Subject: [PATCH 6/8] refactor(zstd): return named error --- crates/compression-codecs/src/zstd/decoder.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/compression-codecs/src/zstd/decoder.rs b/crates/compression-codecs/src/zstd/decoder.rs index d571b1f0..6ce70f38 100644 --- a/crates/compression-codecs/src/zstd/decoder.rs +++ b/crates/compression-codecs/src/zstd/decoder.rs @@ -5,6 +5,7 @@ use compression_core::util::PartialBuffer; use libzstd::stream::raw::{Decoder, Operation}; use std::io; use std::io::Result; +use zstd_safe::get_error_name; #[derive(Debug)] pub struct ZstdDecoder { @@ -88,6 +89,6 @@ impl Decode for ZstdDecoder { impl DecodedSize for ZstdDecoder { fn decoded_size(input: &[u8]) -> Result { zstd_safe::find_frame_compressed_size(input) - .map_err(|_err| io::Error::from(io::ErrorKind::Other)) + .map_err(|error_code| io::Error::other(get_error_name(error_code))) } } From 6f282b1eb6a45f197fcbd06533af5a2f95db9917 Mon Sep 17 00:00:00 2001 From: FineFindus Date: Tue, 14 Oct 2025 17:28:55 +0200 Subject: [PATCH 7/8] feat: use explicit 64-bit unsigned int for decoded size --- crates/compression-codecs/src/lib.rs | 2 +- crates/compression-codecs/src/lzma/decoder.rs | 2 +- crates/compression-codecs/src/xz/decoder.rs | 2 +- crates/compression-codecs/src/xz2/decoder.rs | 4 ++-- crates/compression-codecs/src/zstd/decoder.rs | 7 ++++++- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/crates/compression-codecs/src/lib.rs b/crates/compression-codecs/src/lib.rs index 2e8b6b8c..1ad3ec17 100644 --- a/crates/compression-codecs/src/lib.rs +++ b/crates/compression-codecs/src/lib.rs @@ -100,5 +100,5 @@ pub trait Decode { pub trait DecodedSize { /// Returns the size of the input when uncompressed. - fn decoded_size(input: &[u8]) -> Result; + fn decoded_size(input: &[u8]) -> Result; } diff --git a/crates/compression-codecs/src/lzma/decoder.rs b/crates/compression-codecs/src/lzma/decoder.rs index e53acf8e..4291c455 100644 --- a/crates/compression-codecs/src/lzma/decoder.rs +++ b/crates/compression-codecs/src/lzma/decoder.rs @@ -63,7 +63,7 @@ impl Decode for LzmaDecoder { } impl DecodedSize for LzmaDecoder { - fn decoded_size(input: &[u8]) -> Result { + fn decoded_size(input: &[u8]) -> Result { Xz2Decoder::decoded_size(input) } } diff --git a/crates/compression-codecs/src/xz/decoder.rs b/crates/compression-codecs/src/xz/decoder.rs index e1197f91..4ff55b06 100644 --- a/crates/compression-codecs/src/xz/decoder.rs +++ b/crates/compression-codecs/src/xz/decoder.rs @@ -99,7 +99,7 @@ impl Decode for XzDecoder { } impl DecodedSize for XzDecoder { - fn decoded_size(input: &[u8]) -> Result { + fn decoded_size(input: &[u8]) -> Result { Xz2Decoder::decoded_size(input) } } diff --git a/crates/compression-codecs/src/xz2/decoder.rs b/crates/compression-codecs/src/xz2/decoder.rs index 24099a35..98d9ab88 100644 --- a/crates/compression-codecs/src/xz2/decoder.rs +++ b/crates/compression-codecs/src/xz2/decoder.rs @@ -113,9 +113,9 @@ impl Decode for Xz2Decoder { } impl DecodedSize for Xz2Decoder { - fn decoded_size(input: &[u8]) -> io::Result { + fn decoded_size(input: &[u8]) -> io::Result { let cursor = Cursor::new(input); - liblzma::uncompressed_size(cursor).map(|size| size as usize) + liblzma::uncompressed_size(cursor) } } diff --git a/crates/compression-codecs/src/zstd/decoder.rs b/crates/compression-codecs/src/zstd/decoder.rs index 6ce70f38..3011d589 100644 --- a/crates/compression-codecs/src/zstd/decoder.rs +++ b/crates/compression-codecs/src/zstd/decoder.rs @@ -3,6 +3,7 @@ use crate::{Decode, DecodedSize}; use compression_core::unshared::Unshared; use compression_core::util::PartialBuffer; use libzstd::stream::raw::{Decoder, Operation}; +use std::convert::TryInto; use std::io; use std::io::Result; use zstd_safe::get_error_name; @@ -87,8 +88,12 @@ impl Decode for ZstdDecoder { } impl DecodedSize for ZstdDecoder { - fn decoded_size(input: &[u8]) -> Result { + fn decoded_size(input: &[u8]) -> Result { zstd_safe::find_frame_compressed_size(input) .map_err(|error_code| io::Error::other(get_error_name(error_code))) + .and_then(|size| { + size.try_into() + .map_err(|_| io::Error::from(io::ErrorKind::InvalidData)) + }) } } From eb0efd1db08f9ec9205ebbcc9d76cd2a7b4403f4 Mon Sep 17 00:00:00 2001 From: FineFindus Date: Wed, 15 Oct 2025 15:25:40 +0200 Subject: [PATCH 8/8] refactor(zstd): use `FileTooLarge` when failing to convert usize to u64 --- crates/compression-codecs/src/zstd/decoder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/compression-codecs/src/zstd/decoder.rs b/crates/compression-codecs/src/zstd/decoder.rs index 3011d589..2eea1aa8 100644 --- a/crates/compression-codecs/src/zstd/decoder.rs +++ b/crates/compression-codecs/src/zstd/decoder.rs @@ -93,7 +93,7 @@ impl DecodedSize for ZstdDecoder { .map_err(|error_code| io::Error::other(get_error_name(error_code))) .and_then(|size| { size.try_into() - .map_err(|_| io::Error::from(io::ErrorKind::InvalidData)) + .map_err(|_| io::Error::from(io::ErrorKind::FileTooLarge)) }) } }