#build #original #version #archivelib #greenleaf #archive-lib #implementaton

bin+lib archivelib-sys

C++实现的Greenleaf ArchiveLib压缩/解压缩算法

3 个不稳定版本

0.2.0 2019年9月19日
0.1.1 2019年1月22日
0.1.0 2019年1月22日

#622 in 压缩

每月28次下载
archivelib 中使用

GPL-2.0-only

600KB
5.5K SLoC

C++ 5K SLoC // 0.7% comments Rust 269 SLoC // 0.0% comments

archivelib-rs

这是Greenleaf Software于1994年编写的'archivelib'压缩算法的Rust版本。代码基于1994年8月10日发布的1.0B版本,并从此存储库中的代码移植而来。

库目标

将代码从C移植到Rust的目标

  • 提供一个纯Rust实现。

    这将使用户能够在Rust可以构建的地方构建此代码,从WASM到嵌入式系统。并且它将允许代码被转换为其他语言(如Python)。

  • 提供一个'安全'的实现。

    该实现必须是内存安全的,且无崩溃,特别是在有限环境中使用时。

  • 必须完美地复制原始库,无论好坏

    端口行为必须与原始版本相同,对于明确定义代码路径(即快乐路径)非常重要。对于未定义的行为(如超出数组末尾读取)允许Rust库返回错误,而不是尝试复制未定义的行为。

  • 允许非算法偏差

    原始库的使用允许输出最多65,536字节的输出;超出该值时出错。默认情况下,Rust版本也有这个限制;但可以通过使用自定义的ArchivelibConfig输出更大的文件。

故事

这个故事始于我决定将EmbroiderModder移植到Rust,或者更具体地说,是读取和写入各种格式。为了处理两种常见的刺绣机格式husvip,我需要使用名为archivelib的压缩库。EmbroiderModder的git树中存在一个版本,在尝试移植代码几次后,我意识到我需要找到一个更接近原始版本的版本。

从C++到Rust

原始源代码可以在这个仓库找到,并被复制到archivelib-sys-orig/c-lib/。压缩算法本身是混淆的C++代码,可以在_rc.cpp_re.cpp中查看,以及其他一些作为它们被发现时(尽可能)包括的支持文件。除了修复一个或两个影响我有效模糊代码能力的错误(如这次更改以防止重复释放)外,对原始源代码进行了最小的修改。

从那里,大多数不必要的代码都被修剪,混淆的C++被格式化和拆分出来,理解、清理和整理代码的漫长过程开始了。

  • 变量名称从_266更改为更有用的名称,例如run_start226
  • 将C++类重构为更函数化的风格,传递结构体。
  • 尝试去除尽可能多的C/C++ '魔法'(如指针运算)。
  • 使用一些已知良好的数据为每个函数生成测试用例。

这使得代码可以转换为Rust,并继续重构和改进。

游戏开始

一旦实现了大多数工作的移植,测试移植是否正确变得很重要。我开始尝试简单地压缩给定输入,然后解压缩并断言它产生了相同的输出。这揭露了一些错误;但我确信还有更多。所以我最终陷入了一个兔子洞,试图模糊库的原始C++版本(该版本有很多内存安全问题)并确保我的Rust版本表现相同;只是没有恐慌。

为了有效地做到这一点,我最终不得不为原始库构建一个单独的C++ CLI,以便我可以使用所有内存保护选项(如no-stack-arrays以在堆栈数组访问上执行边界检查)。

今天的库

Rust库相对经过良好的测试,不会(读:不应该)在原始版本会崩溃的地方恐慌。API需要更多的文档,并需要更多考虑如何使用库。

进一步的工作

我在某处看到,这可能只是具有不同块大小的zlib。我想调查这个说法,只是为了让我放心。

无运行时依赖

~0–2MB
~37K SLoC