12 个不稳定版本 (5 个重大更改)
新 0.7.1 | 2024 年 8 月 21 日 |
---|---|
0.7.0 | 2024 年 5 月 30 日 |
0.6.0 | 2024 年 2 月 18 日 |
0.5.0 | 2023 年 10 月 25 日 |
0.2.1 | 2019 年 11 月 24 日 |
#19 in 压缩
558,560 每月下载量
在 169 个 crate (23 个直接使用) 中使用
275KB
6K SLoC
鲁兹标准库 (纯 Rust 的 zstd 解码器)
这是什么
这是一个功能完整的 zstd 压缩格式的解码器,它定义在:这份文档 中。
它不是一个压缩器。我也没有计划实现这一部分,至少在近期内不会。 (如果有人足够有动力,我当然会接受 pull-request!)
这个 crate 可能看起来不再活跃,这是因为已经没有太多可以做的事情了,除非发现错误或请求新的 API 功能。我当然会响应并调查这些问题!
当前状态
解码器方面功能完整。在速度上,它仍然落后于原始的 C 实现,该实现位于 这里。
正在积极维护,但没有计划添加新功能。如果您有建议,请打开一个问题,我会考虑。
速度
使用 'time' 工具测量原始 zstd 和我的解码器解码相同 enwik9.zst 文件(来自 aramfs),我的解码器大约慢 3.5 倍。Enwik9 非常可压缩,对于不太可压缩的数据(如 ubuntu 安装 .iso),我的解码器仅慢 1.4 倍。
可以做到
- 解析 /decodecorpus_files 中的所有文件。这些文件是由原始 zstd 开发者使用 decodecorpus 生成的
- 正确地将它们解码到输出缓冲区
- 解码我创建的所有本地 decode_corpus 文件(1000+)
- 计算校验和
- 可以作为
zstd -c -d
的插件替代品使用 - 可以编译在提供 alloc 的无-std 环境中
不能做到
这个解码器几乎功能完整。如果有新的 API 或错误报告的愿望,请提交问题,我会乐意查看!
路线图
- 更多的性能优化(目标是 sequence_decoding 和 reverse_bitreader::get_bits。这些占用了整个时间的约 50%)
测试
测试有两种形式。
- 使用格式良好的文件进行测试,这些文件必须正确解码并与其原始文件进行校验
- 使用模糊测试工具生成的畸形输入进行的测试。这些输入不需要解码(它们是垃圾),但解码器不能崩溃
模糊测试
使用 cargo fuzz 进行模糊测试。每次解码器崩溃时,我都会修复问题并将有问题的输入作为测试添加。它们已存入 repo 中的 fuzz/artifacts/fuzz_target_1 目录。这些在 fuzz_regressions.rs 测试中进行了测试。在撰写本文时,模糊测试器能够在随机输入上运行超过 12 小时而未找到新的崩溃。显然,这并不意味着没有漏洞,但常见的漏洞可能已经被修复。
模糊测试已经进行过
- 没有初始语料库的随机输入
- /fuzz_decodecorpus 中的 *.zst
你想帮助模糊测试吗?
使用 cargo +nightly fuzz run decode
运行模糊测试器。它使用由 decodecorpus 创建的文件进行初始化。
如果(当)模糊测试器找到崩溃,它将被模糊测试器保存到 artifacts 目录。运行 cargo test artifacts
以运行 artifacts 测试。这将告诉您解码器崩溃的确切位置。如果您能够修复问题,请随时提交拉取请求。如果不能,请仍然提交有问题的输入,我会看看如何自己修复它。
如何使用它?
除了描述和文档外,您还可以查看 zstd / zstd_streaming 二进制文件。它们展示了如何使用这个库。
简单
最简单的方法是将 io::Read 封装到 StreamingDecoder 中,它本身实现了 io::Read。它将按需解码块以满足读取请求
let mut f = File::open(path).unwrap();
let mut decoder = StreamingDecoder::new(&mut f).unwrap();
let mut result = Vec::new();
decoder.read_to_end(&mut result).unwrap();
如果您正在接受用户提供的数据,这可能会成为问题。解码后的帧可能非常大。如果是这种情况,您应该检查帧的实际大小或使用下面描述的内存高效方法。
内存高效
如果内存是问题,您可以部分解码帧。有两种方法可以这样做
流式解码器
使用 StreamingDecoder 并使用 while 循环填充您的缓冲区(请参阅 src/bin/zstd_stream.rs 以获取示例)。这是推荐的方法。
使用低级 FrameDecoder
请参阅 src/bin/zstd.rs 文件以获取示例。基本上,您可以解码帧,直到解码了给定数量的块或 decodebuffer 达到一定大小。然后您可以收集不再需要的字节从缓冲区中,并处理它们,丢弃它们,并循环解码帧,直到完全解码。
贡献
贡献将根据与本项目相同的 MIT 许可证发布。请在提交 PR 时在 Changelog.md 文件中添加条目。