#zstd #解压缩 #zstandard

no-std bin+lib ruzstd

zstd 压缩格式的解码器

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 压缩

Download history 107349/week @ 2024-05-03 113057/week @ 2024-05-10 112112/week @ 2024-05-17 137983/week @ 2024-05-24 142236/week @ 2024-05-31 136053/week @ 2024-06-07 120793/week @ 2024-06-14 132786/week @ 2024-06-21 117580/week @ 2024-06-28 139944/week @ 2024-07-05 144957/week @ 2024-07-12 154775/week @ 2024-07-19 152285/week @ 2024-07-26 123584/week @ 2024-08-02 134095/week @ 2024-08-09 118854/week @ 2024-08-16

558,560 每月下载量
169 个 crate (23 个直接使用) 中使用

MIT 许可协议

275KB
6K SLoC

鲁兹标准库 (纯 Rust 的 zstd 解码器)

Released API docs CI

这是什么

这是一个功能完整的 zstd 压缩格式的解码器,它定义在:这份文档 中。

它不是一个压缩器。我也没有计划实现这一部分,至少在近期内不会。 (如果有人足够有动力,我当然会接受 pull-request!)

这个 crate 可能看起来不再活跃,这是因为已经没有太多可以做的事情了,除非发现错误或请求新的 API 功能。我当然会响应并调查这些问题!

当前状态

解码器方面功能完整。在速度上,它仍然落后于原始的 C 实现,该实现位于 这里

正在积极维护,但没有计划添加新功能。如果您有建议,请打开一个问题,我会考虑。

速度

使用 'time' 工具测量原始 zstd 和我的解码器解码相同 enwik9.zst 文件(来自 aramfs),我的解码器大约慢 3.5 倍。Enwik9 非常可压缩,对于不太可压缩的数据(如 ubuntu 安装 .iso),我的解码器仅慢 1.4 倍。

可以做到

  1. 解析 /decodecorpus_files 中的所有文件。这些文件是由原始 zstd 开发者使用 decodecorpus 生成的
  2. 正确地将它们解码到输出缓冲区
  3. 解码我创建的所有本地 decode_corpus 文件(1000+)
  4. 计算校验和
  5. 可以作为 zstd -c -d 的插件替代品使用
  6. 可以编译在提供 alloc 的无-std 环境中

不能做到

这个解码器几乎功能完整。如果有新的 API 或错误报告的愿望,请提交问题,我会乐意查看!

路线图

  1. 更多的性能优化(目标是 sequence_decoding 和 reverse_bitreader::get_bits。这些占用了整个时间的约 50%)

测试

测试有两种形式。

  1. 使用格式良好的文件进行测试,这些文件必须正确解码并与其原始文件进行校验
  2. 使用模糊测试工具生成的畸形输入进行的测试。这些输入不需要解码(它们是垃圾),但解码器不能崩溃

模糊测试

使用 cargo fuzz 进行模糊测试。每次解码器崩溃时,我都会修复问题并将有问题的输入作为测试添加。它们已存入 repo 中的 fuzz/artifacts/fuzz_target_1 目录。这些在 fuzz_regressions.rs 测试中进行了测试。在撰写本文时,模糊测试器能够在随机输入上运行超过 12 小时而未找到新的崩溃。显然,这并不意味着没有漏洞,但常见的漏洞可能已经被修复。

模糊测试已经进行过

  1. 没有初始语料库的随机输入
  2. /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 文件中添加条目。

依赖项