#huffman #decompression #embedded-devices #lz77

无 std 程序+库 brotli

一个避免使用 Rust stdlib 接口的 brotli 压缩和解压缩工具。这使得它适合嵌入式设备和内核。它采用可插拔的分配器设计,以便可以使用标准库的分配器。默认构建还包括一个 stdlib 分配器和流接口。使用 --features=no-stdlib 禁用此功能。所有包含的代码都是安全的。

46 个稳定版本 (6 个主要版本)

使用旧的 Rust 2015

6.0.0 2024 年 5 月 4 日
5.0.0 2024 年 4 月 12 日
4.0.0 2024 年 4 月 3 日
3.5.0 2024 年 3 月 17 日
0.1.0 2015 年 11 月 30 日

#8 in 压缩

Download history 514248/week @ 2024-05-03 561118/week @ 2024-05-10 564596/week @ 2024-05-17 581158/week @ 2024-05-24 661294/week @ 2024-05-31 678449/week @ 2024-06-07 623058/week @ 2024-06-14 676255/week @ 2024-06-21 653021/week @ 2024-06-28 630778/week @ 2024-07-05 625128/week @ 2024-07-12 640038/week @ 2024-07-19 663093/week @ 2024-07-26 691350/week @ 2024-08-02 701936/week @ 2024-08-09 577629/week @ 2024-08-16

2,758,869 每月下载量
1,681 个crate(直接使用 161 个) 中使用

BSD-3-Clause OR MIT

4.5MB
235K SLoC

rust-brotli

crates.io Build Status

5.0.0 版本的新功能

  • 默认情况下,FFI 不再活跃,以避免在多个依赖项中包含多个 brotli 版本时出现 ODR 问题。

4.0.0 版本的新功能

锁定到可以禁用 ffi 的 rust-brotli-decompressor,使用 ffi-api 标志。这可以帮助避免与其他 brotli 库的符号冲突。

3.5 版本的新功能

更新 SIMD 支持。更好的 CI 集成。清理了一些 clippy 警告。

3.4 版本的新功能

Brotli 解压缩器的读取器和写入器在处理末尾有额外位的 brotli 流时具有更好的行为。现在已测试或禁用可选功能,如 stdsimd。

3.2 版本的新功能

  • Reader 和 Writer 类的 into_inner 转换

3.0 版本的新功能

  • 完全兼容的 FFI,与 https://github.com/google/brotli 二进制文件兼容
    • 完全支持自定义分配器
  • 多线程压缩,以便多个线程可以同时处理单个文件
  • 可拼接模式,以添加在 https://github.com/google/brotli/issues/628 中请求的功能
    • 二进制工具 catbrotli 可以完成此功能,如果第一个文件使用 -apendable 指定,第二个文件使用 -catable 指定
  • 验证模式,其中文件被双重检查以确保可以使用相同的设置进行解压缩;对于基准测试或模糊测试很有用
  • 魔数:brotli 文件可以具有包含一些魔数字节、可拼接信息和最终输出大小的有用头,以便预先分配内存

2.5 版本的新功能

  • 在 2.5 版本中,回调还传递一个分配器来创建新的 StaticCommands 和 PDF,以及 256 位浮点向量。
  • 在2.4节中,带有压缩中间表示的回调现在一次传递一个完整的元块。另外,如果需要进一步优化,这些项是可变的。

2.3版本的新特性

  • 现在flush会生成输出,而不是在流上调用finish。这允许您使用writer抽象来获取即时输出,而无需求助于CompressStream内部抽象。

项目需求

将C brotli压缩器的直接无stdlib端口移植到Rust

不依赖于Rust stdlib:这个库非常适合在Rust内核中进行解压缩等。

这有助于在相同的算法、数据结构和优化下进行C和Rust的直观比较。

压缩使用

Rust brotli目前支持压缩等级0-11,它们应该与压缩等级0-9的brotli C压缩引擎在位上相同。推荐的lg_window_size在20到22之间。

使用io::Read抽象

let mut input = brotli::CompressorReader::new(&mut io::stdin(), 4096 /* buffer size */,
                                              quality as u32, lg_window_size as u32);

然后您只需像读取其他io::Read类一样读取输入即可。

使用io::Write抽象

let mut writer = brotli::Compressor::new(&mut io::stdout(), 4096 /* buffer size */,
                                         quality as u32, lg_window_size as u32);

还有使用with_params静态函数构建Compressor Readers或Writers的方法。

例如:

let params = BrotliEncoderParams::default();
// modify params to fit the application needs
let mut writer = brotli::Compressor::with_params(&mut io::stdout(), 4096 /* buffer size */,
                                         params);

或者对于读者:

let params = BrotliEncoderParams::default();
// modify params to fit the application needs
let mut writer = brotli::CompressorReader::with_params(&mut io::stdin(), 4096 /* buffer size */,
                                                       params);

使用Stream Copy抽象

match brotli::BrotliCompress(&mut io::stdin(), &mut io::stdout(), &brotli_encoder_params) {
    Ok(_) => {},
    Err(e) => panic!("Error {:?}", e),
}

解压缩使用

使用io::Read抽象

let mut input = brotli::Decompressor::new(&mut io::stdin(), 4096 /* buffer size */);

然后您只需像读取其他io::Read类一样读取输入即可。

使用io::Write抽象

let mut writer = brotli::DecompressorWriter::new(&mut io::stdout(), 4096 /* buffer size */);

使用Stream Copy抽象

match brotli::BrotliDecompress(&mut io::stdin(), &mut io::stdout()) {
    Ok(_) => {},
    Err(e) => panic!("Error {:?}", e),
}

使用手动内存管理

使用无stdlib的brotli有3个步骤

  1. 设置内存管理器
  2. 设置BrotliState
  3. 在一个循环中,调用BrotliDecompressStream

详细说明

// at global scope declare a MemPool type -- in this case we'll choose the heap to
// avoid unsafe code, and avoid restrictions of the stack size

declare_stack_allocator_struct!(MemPool, heap);

// at local scope, make a heap allocated buffers to hold uint8's uint32's and huffman codes
let mut u8_buffer = define_allocator_memory_pool!(4096, u8, [0; 32 * 1024 * 1024], heap);
let mut u32_buffer = define_allocator_memory_pool!(4096, u32, [0; 1024 * 1024], heap);
let mut hc_buffer = define_allocator_memory_pool!(4096, HuffmanCode, [0; 4 * 1024 * 1024], heap);
let heap_u8_allocator = HeapPrealloc::<u8>::new_allocator(4096, &mut u8_buffer, bzero);
let heap_u32_allocator = HeapPrealloc::<u32>::new_allocator(4096, &mut u32_buffer, bzero);
let heap_hc_allocator = HeapPrealloc::<HuffmanCode>::new_allocator(4096, &mut hc_buffer, bzero);

// At this point no more syscalls are going to be needed since everything can come from the allocators.

// Feel free to activate SECCOMP jailing or other mechanisms to secure your application if you wish.

// Now it's possible to setup the decompressor state
let mut brotli_state = BrotliState::new(heap_u8_allocator, heap_u32_allocator, heap_hc_allocator);

// at this point the decompressor simply needs an input and output buffer and the ability to track
// the available data left in each buffer
loop {
    result = BrotliDecompressStream(&mut available_in, &mut input_offset, &input.slice(),
                                    &mut available_out, &mut output_offset, &mut output.slice_mut(),
                                    &mut written, &mut brotli_state);

    // just end the decompression if result is BrotliResult::ResultSuccess or BrotliResult::ResultFailure
}

此接口与C brotli解压缩器使用的接口相同

也可以自由使用直接调用Box的定制分配器。以下示例说明了一种在初始分配之后避免后续系统调用的机制。

使用C接口

rust-brotli是官方https://github.com/google/brotli C实现的直接替换。这意味着您可以从支持该库的任何位置使用它。以这种方式构建rust-brotli,请进入c子目录并运行make。

cd c && make

这应该会构建c/target/release/libbrotli.so,并构建C的纯命令行工具,用于压缩和解压缩任何brotli文件。

c/target/release中的libbrotli.so应该能够替换任何其他libbrotli.so文件,但具有使用安全Rust(除了在FFI绑定中)的所有优点。

代码还允许更广泛的选择,包括强制预测模式(例如UTF8与有符号的、MSB与LSB)以及将字面成本权重从540更改为其他值。

此外,CATABLE和APPENDABLE选项已公开,允许以这种方式创建的文件连接。

具体来说,CATABLE文件可以使用catbrotli工具以任何顺序连接,APPENDABLE文件可以是一个序列中的第一个catable文件...例如,您可以组合appendable.br、catable1.br、catable2.br、catable3.br。

或者简单地catable0.br、catable1.br、catable2.br、catable3.br。

依赖项