Skip to content

Commit f072ce5

Browse files
authored
feat: allow reading uncompressed size (#396)
* 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. * feat(xz2): implement `uncompressed_size` method * feat(xz): support reading uncompressed size * feat(lzma): implement reading uncompressed size * feat(zstd): support reading uncompressed size * refactor(zstd): return named error * feat: use explicit 64-bit unsigned int for decoded size * refactor(zstd): use `FileTooLarge` when failing to convert usize to u64
1 parent 1fa960f commit f072ce5

File tree

5 files changed

+46
-5
lines changed

5 files changed

+46
-5
lines changed

crates/compression-codecs/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,8 @@ pub trait Decode {
9797
output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
9898
) -> Result<bool>;
9999
}
100+
101+
pub trait DecodedSize {
102+
/// Returns the size of the input when uncompressed.
103+
fn decoded_size(input: &[u8]) -> Result<u64>;
104+
}

crates/compression-codecs/src/lzma/decoder.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{Decode, Xz2Decoder};
1+
use crate::{Decode, DecodedSize, Xz2Decoder};
22
use compression_core::util::PartialBuffer;
33
use std::{convert::TryInto, io::Result};
44

@@ -61,3 +61,9 @@ impl Decode for LzmaDecoder {
6161
self.inner.finish(output)
6262
}
6363
}
64+
65+
impl DecodedSize for LzmaDecoder {
66+
fn decoded_size(input: &[u8]) -> Result<u64> {
67+
Xz2Decoder::decoded_size(input)
68+
}
69+
}

crates/compression-codecs/src/xz/decoder.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{Decode, Xz2Decoder};
1+
use crate::{Decode, DecodedSize, Xz2Decoder};
22
use compression_core::util::PartialBuffer;
33
use std::{
44
convert::TryInto,
@@ -97,3 +97,9 @@ impl Decode for XzDecoder {
9797
self.inner.finish(output)
9898
}
9999
}
100+
101+
impl DecodedSize for XzDecoder {
102+
fn decoded_size(input: &[u8]) -> Result<u64> {
103+
Xz2Decoder::decoded_size(input)
104+
}
105+
}

crates/compression-codecs/src/xz2/decoder.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
use crate::{lzma::params::LzmaDecoderParams, Decode};
1+
use crate::{lzma::params::LzmaDecoderParams, Decode, DecodedSize};
22
use compression_core::util::PartialBuffer;
33
use liblzma::stream::{Action, Status, Stream};
4-
use std::{convert::TryFrom, fmt, io};
4+
use std::{
5+
convert::TryFrom,
6+
fmt,
7+
io::{self, Cursor},
8+
};
59

610
/// Xz2 decoding stream
711
pub struct Xz2Decoder {
@@ -108,6 +112,13 @@ impl Decode for Xz2Decoder {
108112
}
109113
}
110114

115+
impl DecodedSize for Xz2Decoder {
116+
fn decoded_size(input: &[u8]) -> io::Result<u64> {
117+
let cursor = Cursor::new(input);
118+
liblzma::uncompressed_size(cursor)
119+
}
120+
}
121+
111122
#[cfg(test)]
112123
mod tests {
113124
use std::convert::TryFrom;

crates/compression-codecs/src/zstd/decoder.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
use crate::zstd::params::DParameter;
2-
use crate::Decode;
2+
use crate::{Decode, DecodedSize};
33
use compression_core::unshared::Unshared;
44
use compression_core::util::PartialBuffer;
55
use libzstd::stream::raw::{Decoder, Operation};
6+
use std::convert::TryInto;
67
use std::io;
78
use std::io::Result;
9+
use zstd_safe::get_error_name;
810

911
#[derive(Debug)]
1012
pub struct ZstdDecoder {
@@ -84,3 +86,14 @@ impl Decode for ZstdDecoder {
8486
Ok(bytes_left == 0)
8587
}
8688
}
89+
90+
impl DecodedSize for ZstdDecoder {
91+
fn decoded_size(input: &[u8]) -> Result<u64> {
92+
zstd_safe::find_frame_compressed_size(input)
93+
.map_err(|error_code| io::Error::other(get_error_name(error_code)))
94+
.and_then(|size| {
95+
size.try_into()
96+
.map_err(|_| io::Error::from(io::ErrorKind::FileTooLarge))
97+
})
98+
}
99+
}

0 commit comments

Comments
 (0)