diff --git a/Cargo.lock b/Cargo.lock index 57e82bc..6c05aed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -255,6 +255,15 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +[[package]] +name = "lz4_flex" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177c079243f6867429aca5af5053747f57e329d44f0c58bebca078cd14873ec2" +dependencies = [ + "twox-hash", +] + [[package]] name = "lzma-sys" version = "0.1.17" @@ -310,6 +319,7 @@ dependencies = [ "infer", "libc", "linked-hash-map", + "lz4_flex", "once_cell", "rand", "tar", @@ -441,6 +451,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" @@ -521,6 +537,16 @@ dependencies = [ "syn", ] +[[package]] +name = "twox-hash" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f559b464de2e2bdabcac6a210d12e9b5a5973c251e102c44c585c71d51bd78e" +dependencies = [ + "cfg-if", + "static_assertions", +] + [[package]] name = "unicase" version = "2.6.0" diff --git a/Cargo.toml b/Cargo.toml index f2261a5..52b2774 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ walkdir = "2.3.2" bzip2 = "0.4.3" libc = "0.2.103" tar = "0.4.37" +lz4_flex = "0.9.0" xz2 = "0.1.6" zip = { version = "0.5.13", default-features = false, features = ["deflate-miniz"] } flate2 = { version = "1.0.22", default-features = false, features = ["zlib"] } diff --git a/README.md b/README.md index 4453fd5..15b0b46 100644 --- a/README.md +++ b/README.md @@ -82,11 +82,11 @@ For compiling, check the [wiki guide](https://github.com/ouch-org/ouch/wiki/Comp ## Supported formats -| Format | .tar | .zip | .bz, .bz2 | .gz | .xz, .lz, .lzma | .zst | -|:-------------:|:----:|:----:|:---------:| --- |:---------------:| --- | -| Supported | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Format | .tar | .zip | .bz, .bz2 | .gz | .lz4 | .xz, .lz, .lzma | .zst | +|:-------------:|:----:|:----:|:---------:|:---:|:----:|:---------------:|:----:| +| Supported | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -And the aliases: `tgz`, `tbz`, `tbz2`, `txz`, `tlz`, `tlzma`, `tzst`. +And the aliases: `tgz`, `tbz`, `tbz2`, `tlz4`, `txz`, `tlz`, `tlzma`, `tzst`. Formats can be chained (`ouch` keeps it _fast_): diff --git a/src/commands.rs b/src/commands.rs index c4318d9..867731a 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -270,6 +270,7 @@ fn compress_files(files: Vec, formats: Vec, output_file: fs: let encoder: Box = match format { Gzip => Box::new(flate2::write::GzEncoder::new(encoder, Default::default())), Bzip => Box::new(bzip2::write::BzEncoder::new(encoder, Default::default())), + Lz4 => Box::new(lz4_flex::frame::FrameEncoder::new(encoder)), Lzma => Box::new(xz2::write::XzEncoder::new(encoder, 6)), Zstd => { let zstd_encoder = zstd::stream::write::Encoder::new(encoder, Default::default()); @@ -288,7 +289,7 @@ fn compress_files(files: Vec, formats: Vec, output_file: fs: } match formats[0].compression_formats[0] { - Gzip | Bzip | Lzma | Zstd => { + Gzip | Bzip | Lz4 | Lzma | Zstd => { writer = chain_writer_encoder(&formats[0].compression_formats[0], writer); let mut reader = fs::File::open(&files[0]).unwrap(); io::copy(&mut reader, &mut writer)?; @@ -364,6 +365,7 @@ fn decompress_file( let decoder: Box = match format { Gzip => Box::new(flate2::read::GzDecoder::new(decoder)), Bzip => Box::new(bzip2::read::BzDecoder::new(decoder)), + Lz4 => Box::new(lz4_flex::frame::FrameDecoder::new(decoder)), Lzma => Box::new(xz2::read::XzDecoder::new(decoder)), Zstd => Box::new(zstd::stream::Decoder::new(decoder)?), _ => unreachable!(), @@ -380,7 +382,7 @@ fn decompress_file( let files_unpacked; match formats[0].compression_formats[0] { - Gzip | Bzip | Lzma | Zstd => { + Gzip | Bzip | Lz4 | Lzma | Zstd => { reader = chain_reader_decoder(&formats[0].compression_formats[0], reader)?; let writer = utils::create_or_ask_overwrite(&output_path, question_policy)?; @@ -451,6 +453,7 @@ fn list_archive_contents( let decoder: Box = match format { Gzip => Box::new(flate2::read::GzDecoder::new(decoder)), Bzip => Box::new(bzip2::read::BzDecoder::new(decoder)), + Lz4 => Box::new(lz4_flex::frame::FrameDecoder::new(decoder)), Lzma => Box::new(xz2::read::XzDecoder::new(decoder)), Zstd => Box::new(zstd::stream::Decoder::new(decoder)?), _ => unreachable!(), @@ -476,7 +479,7 @@ fn list_archive_contents( crate::archive::zip::list_archive(zip_archive)? } - Gzip | Bzip | Lzma | Zstd => { + Gzip | Bzip | Lz4 | Lzma | Zstd => { panic!("Not an archive! This should never happen, if it does, something is wrong with `CompressionFormat::is_archive()`. Please report this error!"); } }; diff --git a/src/extension.rs b/src/extension.rs index c9dc055..ba17209 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -47,9 +47,11 @@ pub enum CompressionFormat { Gzip, /// .bz .bz2 Bzip, + /// .lz4 + Lz4, /// .xz .lzma .lz Lzma, - /// tar, tgz, tbz, tbz2, txz, tlz, tlzma, tzst + /// tar, tgz, tbz, tbz2, txz, tlz, tlz4, tlzma, tzst Tar, /// .zst Zstd, @@ -65,6 +67,7 @@ impl CompressionFormat { Tar | Zip => true, Gzip => false, Bzip => false, + Lz4 => false, Lzma => false, Zstd => false, } @@ -80,6 +83,7 @@ impl fmt::Display for CompressionFormat { Gzip => ".gz", Bzip => ".bz", Zstd => ".zst", + Lz4 => ".lz4", Lzma => ".lz", Tar => ".tar", Zip => ".zip", @@ -110,11 +114,13 @@ pub fn separate_known_extensions_from_name(mut path: &Path) -> (&Path, Vec Extension::new([Tar], extension), "tgz" => Extension::new([Tar, Gzip], extension), "tbz" | "tbz2" => Extension::new([Tar, Bzip], extension), + "tlz4" => Extension::new([Tar, Lz4], extension), "txz" | "tlz" | "tlzma" => Extension::new([Tar, Lzma], extension), "tzst" => Extension::new([Tar, Zstd], ".tzst"), "zip" => Extension::new([Zip], extension), "bz" | "bz2" => Extension::new([Bzip], extension), "gz" => Extension::new([Gzip], extension), + "lz4" => Extension::new([Lz4], extension), "xz" | "lzma" | "lz" => Extension::new([Lzma], extension), "zst" => Extension::new([Zstd], extension), _ => break, diff --git a/tests/compress_and_decompress.rs b/tests/compress_and_decompress.rs index 9405ae0..3c866ad 100644 --- a/tests/compress_and_decompress.rs +++ b/tests/compress_and_decompress.rs @@ -76,12 +76,14 @@ fn test_each_format() { test_compressing_and_decompressing_archive("tar.bz2"); test_compressing_and_decompressing_archive("tar.xz"); test_compressing_and_decompressing_archive("tar.lz"); + test_compressing_and_decompressing_archive("tar.lz4"); test_compressing_and_decompressing_archive("tar.lzma"); test_compressing_and_decompressing_archive("tar.zst"); test_compressing_and_decompressing_archive("tgz"); test_compressing_and_decompressing_archive("tbz"); test_compressing_and_decompressing_archive("tbz2"); test_compressing_and_decompressing_archive("txz"); + test_compressing_and_decompressing_archive("tlz4"); test_compressing_and_decompressing_archive("tlz"); test_compressing_and_decompressing_archive("tlzma"); test_compressing_and_decompressing_archive("tzst");