feat: Add support for Brotli

Using https://crates.io/crates/brotli/7.0.0

#203
This commit is contained in:
Pascal Hertleif 2025-02-12 14:47:39 +01:00 committed by João Marcos
parent 58271ab77f
commit ecc05cdd60
11 changed files with 61 additions and 8 deletions

View File

@ -25,6 +25,7 @@ Categories Used:
- Add multithreading support for `zstd` compression [\#689](https://github.com/ouch-org/ouch/pull/689) ([nalabrie](https://github.com/nalabrie)) - Add multithreading support for `zstd` compression [\#689](https://github.com/ouch-org/ouch/pull/689) ([nalabrie](https://github.com/nalabrie))
- Add `bzip3` support [\#522](https://github.com/ouch-org/ouch/pull/522) ([freijon](https://github.com/freijon)) - Add `bzip3` support [\#522](https://github.com/ouch-org/ouch/pull/522) ([freijon](https://github.com/freijon))
- Add `--remove` flag for decompression subcommand to remove files after successful decompression [\#757](https://github.com/ouch-org/ouch/pull/757) ([ttys3](https://github.com/ttys3)) - Add `--remove` flag for decompression subcommand to remove files after successful decompression [\#757](https://github.com/ouch-org/ouch/pull/757) ([ttys3](https://github.com/ttys3))
- Add `br` (Brotli) support [\#765](https://github.com/ouch-org/ouch/pull/765) ([killercup](https://github.com/killercup))
### Bug Fixes ### Bug Fixes

37
Cargo.lock generated
View File

@ -28,6 +28,21 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "alloc-no-stdlib"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
[[package]]
name = "alloc-stdlib"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
dependencies = [
"alloc-no-stdlib",
]
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.18" version = "0.6.18"
@ -198,6 +213,27 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "brotli"
version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
"brotli-decompressor",
]
[[package]]
name = "brotli-decompressor"
version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
]
[[package]] [[package]]
name = "bstr" name = "bstr"
version = "1.11.0" version = "1.11.0"
@ -1032,6 +1068,7 @@ version = "0.5.1"
dependencies = [ dependencies = [
"assert_cmd", "assert_cmd",
"atty", "atty",
"brotli",
"bstr", "bstr",
"bytesize", "bytesize",
"bzip2", "bzip2",

View File

@ -15,6 +15,7 @@ description = "A command-line utility for easily compressing and decompressing f
[dependencies] [dependencies]
atty = "0.2.14" atty = "0.2.14"
brotli = "7.0.0"
bstr = { version = "1.10.0", default-features = false, features = ["std"] } bstr = { version = "1.10.0", default-features = false, features = ["std"] }
bytesize = "1.3.0" bytesize = "1.3.0"
bzip2 = "0.4.4" bzip2 = "0.4.4"

View File

@ -111,9 +111,9 @@ Output:
# Supported formats # Supported formats
| Format | `.tar` | `.zip` | `7z` | `.gz` | `.xz`, `.lzma` | `.bz`, `.bz2` | `.bz3` | `.lz4` | `.sz` (Snappy) | `.zst` | `.rar` | | Format | `.tar` | `.zip` | `7z` | `.gz` | `.xz`, `.lzma` | `.bz`, `.bz2` | `.bz3` | `.lz4` | `.sz` (Snappy) | `.zst` | `.rar` | `.br` |
|:---------:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| |:---------:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| Supported | ✓ | ✓¹ | ✓¹ | ✓² | ✓ | ✓ | ✓ | ✓ | ✓² | ✓² | ✓³ | | Supported | ✓ | ✓¹ | ✓¹ | ✓² | ✓ | ✓ | ✓ | ✓ | ✓² | ✓² | ✓³ | ✓ |
✓: Supports compression and decompression. ✓: Supports compression and decompression.

View File

@ -5,7 +5,7 @@ use clap::{Parser, ValueHint};
// Ouch command line options (docstrings below are part of --help) // Ouch command line options (docstrings below are part of --help)
/// A command-line utility for easily compressing and decompressing files and directories. /// A command-line utility for easily compressing and decompressing files and directories.
/// ///
/// Supported formats: tar, zip, gz, 7z, xz/lzma, bz/bz2, bz3, lz4, sz (Snappy), zst and rar. /// Supported formats: tar, zip, gz, 7z, xz/lzma, bz/bz2, bz3, lz4, sz (Snappy), zst, rar and br.
/// ///
/// Repository: https://github.com/ouch-org/ouch /// Repository: https://github.com/ouch-org/ouch
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]

View File

@ -83,6 +83,12 @@ pub fn compress_files(
zstd_encoder.multithread(num_cpus::get_physical() as u32)?; zstd_encoder.multithread(num_cpus::get_physical() as u32)?;
Box::new(zstd_encoder.auto_finish()) Box::new(zstd_encoder.auto_finish())
} }
Brotli => {
let default_level = 11; // Same as brotli CLI, default to highest compression
let level = level.unwrap_or(default_level).clamp(0, 11) as u32;
let win_size = 22; // default to 2^22 = 4 MiB window size
Box::new(brotli::CompressorWriter::new(encoder, BUFFER_CAPACITY, level, win_size))
}
Tar | Zip | Rar | SevenZip => unreachable!(), Tar | Zip | Rar | SevenZip => unreachable!(),
}; };
Ok(encoder) Ok(encoder)
@ -95,7 +101,7 @@ pub fn compress_files(
} }
match first_format { match first_format {
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd => { Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd | Brotli => {
writer = chain_writer_encoder(&first_format, writer)?; writer = chain_writer_encoder(&first_format, writer)?;
let mut reader = fs::File::open(&files[0])?; let mut reader = fs::File::open(&files[0])?;

View File

@ -119,6 +119,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
Lzma => Box::new(xz2::read::XzDecoder::new(decoder)), Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
Snappy => Box::new(snap::read::FrameDecoder::new(decoder)), Snappy => Box::new(snap::read::FrameDecoder::new(decoder)),
Zstd => Box::new(zstd::stream::Decoder::new(decoder)?), Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
Brotli => Box::new(brotli::Decompressor::new(decoder, BUFFER_CAPACITY)),
Tar | Zip | Rar | SevenZip => unreachable!(), Tar | Zip | Rar | SevenZip => unreachable!(),
}; };
Ok(decoder) Ok(decoder)
@ -131,7 +132,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
} }
let files_unpacked = match first_extension { let files_unpacked = match first_extension {
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd => { Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd | Brotli => {
reader = chain_reader_decoder(&first_extension, reader)?; reader = chain_reader_decoder(&first_extension, reader)?;
let mut writer = match utils::ask_to_create_file(&options.output_file_path, options.question_policy)? { let mut writer = match utils::ask_to_create_file(&options.output_file_path, options.question_policy)? {

View File

@ -55,6 +55,7 @@ pub fn list_archive_contents(
Lzma => Box::new(xz2::read::XzDecoder::new(decoder)), Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
Snappy => Box::new(snap::read::FrameDecoder::new(decoder)), Snappy => Box::new(snap::read::FrameDecoder::new(decoder)),
Zstd => Box::new(zstd::stream::Decoder::new(decoder)?), Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
Brotli => Box::new(brotli::Decompressor::new(decoder, BUFFER_CAPACITY)),
Tar | Zip | Rar | SevenZip => unreachable!(), Tar | Zip | Rar | SevenZip => unreachable!(),
}; };
Ok(decoder) Ok(decoder)
@ -112,7 +113,7 @@ pub fn list_archive_contents(
Box::new(sevenz::list_archive(archive_path, password)?) Box::new(sevenz::list_archive(archive_path, password)?)
} }
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd => { Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd | Brotli => {
panic!("Not an archive! This should never happen, if it does, something is wrong with `CompressionFormat::is_archive()`. Please report this error!"); panic!("Not an archive! This should never happen, if it does, something is wrong with `CompressionFormat::is_archive()`. Please report this error!");
} }
}; };

View File

@ -21,6 +21,7 @@ pub const SUPPORTED_EXTENSIONS: &[&str] = &[
#[cfg(feature = "unrar")] #[cfg(feature = "unrar")]
"rar", "rar",
"7z", "7z",
"br",
]; ];
pub const SUPPORTED_ALIASES: &[&str] = &["tgz", "tbz", "tlz4", "txz", "tzlma", "tsz", "tzst"]; pub const SUPPORTED_ALIASES: &[&str] = &["tgz", "tbz", "tlz4", "txz", "tzlma", "tsz", "tzst"];
@ -96,6 +97,8 @@ pub enum CompressionFormat {
Rar, Rar,
/// .7z /// .7z
SevenZip, SevenZip,
/// .br
Brotli,
} }
impl CompressionFormat { impl CompressionFormat {
@ -111,6 +114,7 @@ impl CompressionFormat {
Lzma => false, Lzma => false,
Snappy => false, Snappy => false,
Zstd => false, Zstd => false,
Brotli => false,
} }
} }
} }
@ -136,6 +140,7 @@ fn to_extension(ext: &[u8]) -> Option<Extension> {
b"zst" => &[Zstd], b"zst" => &[Zstd],
b"rar" => &[Rar], b"rar" => &[Rar],
b"7z" => &[SevenZip], b"7z" => &[SevenZip],
b"br" => &[Brotli],
_ => return None, _ => return None,
}, },
ext.to_str_lossy(), ext.to_str_lossy(),

View File

@ -44,6 +44,7 @@ enum FileExtension {
Sz, Sz,
Xz, Xz,
Zst, Zst,
Br,
} }
#[derive(Arbitrary, Debug, Display)] #[derive(Arbitrary, Debug, Display)]

View File

@ -5,7 +5,7 @@ snapshot_kind: text
--- ---
A command-line utility for easily compressing and decompressing files and directories. A command-line utility for easily compressing and decompressing files and directories.
Supported formats: tar, zip, gz, 7z, xz/lzma, bz/bz2, bz3, lz4, sz (Snappy), zst and rar. Supported formats: tar, zip, gz, 7z, xz/lzma, bz/bz2, bz3, lz4, sz (Snappy), zst, rar and br.
Repository: https://github.com/ouch-org/ouch Repository: https://github.com/ouch-org/ouch