豫言 / 豫言操作系统压缩 @ 0.1.0

以宿主原生流解压 raw deflate 数据,并核对 ZIP 条目的 CRC-32 与大小。

源码浏览已生成;不能解析的文件以纯文本展示,不表示通过类型检查。

规范.汉语.md

# 压缩接口规范 0.1.0

本包在宿主的原生解压流上提供两种能力:限量的 raw deflate 解压,以及带 CRC-32 与大小校验的 ZIP 条目解压。它是云工专用能力,不使用绑定,也不需要资源许可。输入是字节串,结果是 `(整数 合 字节串)`:整数为状态码,字节串为解压结果(状态非 0 时为空字节串)。**可恢复的数据问题用状态码返回;参数违规、输入过大、最大输出越界抛出豫言异常**,应用可用「尝试运行」捕获。

## 状态码

| 状态 | 含义 | 适用函数 |
| --- | --- | --- |
| 0 | 成功;结果就是完整的解压输出 | 两个函数 |
| 1 | 输出超过上限;读取时累计超限即取消,不继续解压 | 两个函数 |
| 2 | 数据损坏或不完整(含尾随多余字节) | 两个函数 |
| 3 | 数据可以解压,但 CRC-32 或解压大小与预期不符 | 仅 `解压归档条目` |

状态 1 的判定不看预期:只要解压输出的累计字节数**大于**最大输出就立即取消解压流并返回 1;输出恰好等于最大输出算成功。

## 解压原始压缩

`解压原始压缩` 接收 raw deflate 字节串(无 zlib、无 gzip 头,即 ZIP 内部的压缩方法 8)和最大输出字节数,返回 `(状态 合 结果)`。

- 输入不得超过 16 MiB(宿主值桥的交换上限),最大输出须在 1 至 134217728(128 MiB)之间;越界抛出豫言异常。128 MiB 是接口允许的上限而不是推荐值:结果保存在 Wasm 内存里,应用应按自己的内存预算选择最大输出(Cloudflare Workers 的内存上限约为 128 MB)。
- 对合法的输入,结果与 Node 的 `zlib.inflateRawSync` 逐字节相同,包括空输出的合法流(如 `03 00`,得状态 0 与空字节串)、存储块、静态与动态哈夫曼块及跨多个输出块的大结果。
- 空输入、被截断的流、损坏的流为状态 2。**流结束后还有多余字节**(含两个流首尾相接)也是状态 2:这与浏览器、workerd 和 Node 的 `DecompressionStream` 一致,不同于 `zlib.inflateRawSync`(它忽略尾随字节)。
- 压缩炸弹(很小的输入、极大的输出)不会被整体解出:读取每个输出块时先核对累计长度,越限即取消。
- 既损坏又超限的数据,宿主流缓冲深度不同,可能先给出块(状态 1)也可能先报错(状态 2);应用应把非 0 的状态一律当作失败。

## 解压归档条目

`解压归档条目` 参数依次为:条目数据、方法、预期 CRC-32、预期解压大小、最大输出字节数。它服务于 ZIP 归档解析库:库按中央目录读到方法、CRC-32、大小,把本地文件头之后、长度恰为压缩大小的条目数据交给本函数。

- 方法:`0` 存储(数据即原文),`8` raw deflate;其他方法抛出豫言异常。
- 预期 CRC-32 须在 0 至 4294967295 之间;预期解压大小须在 0 至最大输出之间(预期大于最大输出是调用方的参数错误,抛出异常);最大输出须在 1 至 134217728 之间;数据不超过 16 MiB。违规均抛出豫言异常。
- 状态 0:数据完整、CRC-32 与解压大小都与预期相等,结果是校验过的解压输出。校验由宿主原生完成,不在豫言里逐字节计算。
- 状态 1:输出超过最大输出。因为预期大小来自不可信的归档目录,可以比实际小:“说谎”的条目照样受最大输出限制。
- 状态 2:deflate 流本身损坏、被截断或有尾随多余字节。存储方法的数据是任意字节,永远不会是状态 2。
- 状态 3:数据可以解压(流本身合法)而 CRC-32 或大小与预期不符;存储方法的数据长度不等于预期大小也是 3。
- 优先级:存储方法先比较长度——数据长度大于最大输出为 1,否则不等于预期大小为 3,否则进入校验;deflate 方法由宿主解压流校验,失败后再用 raw deflate 复解一遍来区分:复解超限为 1,复解失败为 2,复解成功则是 CRC-32 或大小不符,为 3。这样无论宿主流是先交出块还是先报错,状态都相同(既损坏又超限的数据除外,同上)。

## 限额

| 项目 | 上限 | 违规时 |
| --- | --- | --- |
| 输入字节数 | 16 MiB | 豫言异常 |
| 最大输出字节数 | 1 至 134217728 | 豫言异常 |
| 预期解压大小 | 0 至最大输出 | 豫言异常 |
| 预期 CRC-32 | 0 至 4294967295 | 豫言异常 |

## 跨宿主一致性

任何宿主的实现须满足:状态码语义与上面相同;合法输入的结果字节与 zlib 的 raw inflate 相同;累计超限即停止解压;尾随多余字节为状态 2;CRC-32 与大小校验由原生解压库完成。云工适配用 `DecompressionStream('deflate-raw')` 解压,用 `DecompressionStream('gzip')` 借 gzip 尾部的 CRC-32 与 ISIZE 校验条目(把条目包成 gzip 容器,存储方法的数据先包成 deflate 存储块);其他宿主可以用原生 zlib 达到同样的可观察结果。

## 一致性样例

- `解压原始压缩` 对 `zlib.deflateRawSync("abc")` 与最大输出 10:`(0 合 "abc")`;最大输出 2:`(1 合 空)`;最大输出 3:`(0 合 "abc")`。
- `解压原始压缩` 对空输入:`(2 合 空)`;对 `03 00`:`(0 合 空)`;对合法流后接 1 个字节:`(2 合 空)`。
- `解压归档条目` 对 `"123456789"`:方法 0,CRC-32 `0xCBF43926`,大小 9:`(0 合 "123456789")`;CRC-32 改为 0:`(3 合 空)`;大小改为 8 或 10:`(3 合 空)`;最大输出 8(预期大小仍为 9):抛出异常。
- 存储条目长度 0、1、65534、65535、65536、65537、131070、131071 字节的校验都为 0(覆盖存储块边界);deflate 条目被改动一个字节:能解压则为 3,不能则为 2。

## 边界

本包只解压单个条目的数据,不解析 ZIP 目录、本地文件头、加密、Zip64 或数据描述符,也不提供压缩。CRC-32 不作为独立函数提供:纯豫言逐字节计算太慢,而平台的 Web Crypto 没有 CRC-32,所以校验只经由解压完成。结果字节串存放在 Wasm 内存里,超过宿主内存预算的输出属于应用选择最大输出时的责任。

规范.文言.md

# 压缩公约 0.1.0

此包依宿主原生解压之流,立二术:其一,限出量而解 raw deflate;其二,解 ZIP 之一条目而核其 CRC-32 与实数。此乃云工专用之能,不用绑定,亦无须资源之许。入者字节串,出者 `(整数 合 字节串)`:整数为状,字节串为所解之物,状不为零则空。**数据之可复者,以状返之;参数违规、入过大、出限越界,则抛豫言之异**,客可以「尝试运行」取之。

## 状

| 状 | 义 | 所适 |
| --- | --- | --- |
| 零 | 成;所返即全部所解 | 二术皆有 |
| 一 | 出逾限;读时累计逾限,即止其流,不复解 | 二术皆有 |
| 二 | 数据坏或缺(含末有余字节) | 二术皆有 |
| 三 | 数据可解,然 CRC-32 或实数与所期不合 | 惟解压归档条目 |

判状一,不问所期:解出累计之字节数**大于**出限,即止流而返一;恰等于出限者成。

## 解压原始压缩

`解压原始压缩` 受 raw deflate 字节串(无 zlib、无 gzip 首,即 ZIP 内之法八)与出限,返 `(状 合 果)`。

- 入不得逾一千六百七十七万七千二百一十六字节(宿主值桥之限),出限当在一至一亿三千四百二十一万七千七百二十八之间;越界则抛豫言之异。一亿三千余万乃接口所许之上,非所荐:果存于 Wasm 内存,客当依己之内存预算择出限(Cloudflare Workers 内存约百二十八兆)。
- 合法之入,其果与 Node 之 `zlib.inflateRawSync` 逐字节相同,含出为空之合法流(如 `03 00`,得状零与空串)、存储块、静动哈夫曼块及跨多出块之大果。
- 入空、流截、流坏,皆状二。**流终而末有余字节**(含二流首尾相接)亦状二:此与浏览器、workerd 及 Node 之 `DecompressionStream` 同,不同于 `zlib.inflateRawSync`(其略末余)。
- 压缩之炸(入甚小而出极巨)不整解:每读一出块,先核累计之长,逾则止。
- 既坏且逾者,宿主流之缓冲深浅不同,或先出块(状一),或先报错(状二);客当以非零之状一律为败。

## 解压归档条目

`解压归档条目` 参数依次为:条目数据、法、所期 CRC-32、所期解压实数、出限。此为 ZIP 归档析库而设:库循中央目录得法、CRC-32 与实数,以本地文件首之后、长恰为压缩实数之条目数据授此术。

- 法:`零` 为存(数据即原文),`八` 为 raw deflate;余法抛豫言之异。
- 所期 CRC-32 当在零至四十二亿九千四百九十六万七千二百九十五之间;所期实数当在零至出限之间(所期大于出限乃客之参数误,抛异);出限当在一至一亿三千四百二十一万七千七百二十八之间;数据不逾十六兆。违者皆抛豫言之异。
- 状零:数据全、CRC-32 与实数俱合所期,果乃已验之所解。验由宿主原生为之,不在豫言逐字节算。
- 状一:出逾出限。所期实数出于不可信之归档目录,或小于实出:“诳”之条目亦受出限所制。
- 状二:deflate 流自身坏、截,或末有余字节。存之法,数据为任意字节,永不为状二。
- 状三:数据可解(流自身合法)而 CRC-32 或实数与所期不合;存之法,数据之长不等于所期实数,亦为三。
- 先后:存之法先较其长——数据之长大于出限则一,否则不等所期实数则三,否则入验;deflate 之法由宿主解压流验之,败则复以 raw deflate 解一过以别之:复解逾限则一,复解败则二,复解成则为 CRC-32 或实数不合而三。如此,宿主流无论先出块或先报错,其状皆同(既坏且逾者除外,如上)。

## 限

| 项 | 上限 | 违者 |
| --- | --- | --- |
| 入字节数 | 十六兆 | 豫言之异 |
| 出限 | 一至一亿三千四百二十一万七千七百二十八 | 豫言之异 |
| 所期实数 | 零至出限 | 豫言之异 |
| 所期 CRC-32 | 零至四十二亿九千四百九十六万七千二百九十五 | 豫言之异 |

## 诸宿主同一

任一宿主之实现,须使:状之义如上;合法入之果字节与 zlib 之 raw inflate 同;累计逾限即止解;末有余字节为状二;CRC-32 与实数之验由原生解压库为之。云工之适配以 `DecompressionStream('deflate-raw')` 解之,以 `DecompressionStream('gzip')` 借 gzip 尾之 CRC-32 与 ISIZE 验条目(包条目为 gzip 容器,存之法之数据先包为 deflate 存储块);他宿主可用原生 zlib 得同一可观之果。

## 同一之例

- `解压原始压缩` 于 `zlib.deflateRawSync("abc")`,出限十:`(零 合 "abc")`;出限二:`(一 合 空)`;出限三:`(零 合 "abc")`。
- `解压原始压缩` 于空入:`(二 合 空)`;于 `03 00`:`(零 合 空)`;于合法流后随一字节:`(二 合 空)`。
- `解压归档条目` 于 `"123456789"`:法零,CRC-32 `0xCBF43926`,实数九:`(零 合 "123456789")`;CRC-32 改为零:`(三 合 空)`;实数改为八或十:`(三 合 空)`;出限八(所期实数仍九):抛异。
- 存之条目长零、一、六万五千五百三十四、六万五千五百三十五、六万五千五百三十六、六万五千五百三十七、十三万零七十、十三万零七十一字节,验皆为零(覆存储块之边);deflate 条目改一字节:可解则三,不可解则二。

## 界

此包但解单条目之数据,不析 ZIP 目录、本地文件首、加密、Zip64 与数据描述符,亦不供压缩。CRC-32 不别立为术:纯豫言逐字节算之则太慢,而平台之 Web Crypto 无 CRC-32,故惟由解压而验。果字节串存于 Wasm 内存,出逾宿主内存预算者,乃客择出限时之责。