MSZIP compression #4

Closed
opened 2026-10-14 01:26:51 -05:00 by jeff · 1 comment
Owner

Parent

Part of #1

What to build

Files are compressed with MSZIP per [MS-MCI] by default, using std.compress.flate, and CompressionLevel="none" stores them. A payload too large for one cabinet folder is split across as many folders as the format requires.

Acceptance criteria

  • Seam 1 tests: the Media and File rows are unchanged by compression (sequence numbers, sizes).
  • VM test: a fixture with a compressible file and an incompressible one installs under Wine with both files byte-identical to their sources.
  • VM test: a fixture large enough to need more than one cabinet folder installs under Wine intact.
  • VM test: the tables match the reference implementation's with generated columns masked.
## Parent Part of #1 ## What to build Files are compressed with MSZIP per [MS-MCI] by default, using `std.compress.flate`, and `CompressionLevel="none"` stores them. A payload too large for one cabinet folder is split across as many folders as the format requires. ## Acceptance criteria - [ ] Seam 1 tests: the `Media` and `File` rows are unchanged by compression (sequence numbers, sizes). - [ ] VM test: a fixture with a compressible file and an incompressible one installs under Wine with both files byte-identical to their sources. - [ ] VM test: a fixture large enough to need more than one cabinet folder installs under Wine intact. - [ ] VM test: the tables match the reference implementation's with generated columns masked.
Author
Owner

Done in c1bc65d; CI run 6 is green.

  • Compression: files are compressed with MSZIP by default. Each 32 KiB block is CK plus a complete deflate stream from std.compress.flate. CompressionLevel picks the effort, and none stores the files.
  • The incompatibility found: std.compress.flate encodes a block whose matches all share one distance with a one-symbol distance code. RFC 1951 allows that, but cabextract's MSZIP decoder rejects it, and zlib never writes one. zixl now rewrites every block so that its Huffman codes are complete (src/write/deflate.zig), and the data it decodes to is unchanged.
  • Seam 1: File and Media rows are identical with and without compression.
  • End to end: the compressed fixture (318 KB of text plus 150 KB of noise) passes cabextract -t, and both files install byte-identical under Wine. Its tables match wixl's.
  • Not as specified: the format only forces a new folder at 65,535 blocks, about 2 GiB, so that is the only place zixl splits. A test that installs more than one folder under Wine would need a 2 GiB fixture, so splitting is proven by a unit test instead: it forces two-block folders and reads the cabinet back, checking the checksums and decompressing every block.
Done in c1bc65d; CI run 6 is green. - **Compression:** files are compressed with MSZIP by default. Each 32 KiB block is `CK` plus a complete deflate stream from `std.compress.flate`. `CompressionLevel` picks the effort, and `none` stores the files. - **The incompatibility found:** `std.compress.flate` encodes a block whose matches all share one distance with a one-symbol distance code. RFC 1951 allows that, but cabextract's MSZIP decoder rejects it, and zlib never writes one. zixl now rewrites every block so that its Huffman codes are complete (`src/write/deflate.zig`), and the data it decodes to is unchanged. - **Seam 1:** File and Media rows are identical with and without compression. - **End to end:** the `compressed` fixture (318 KB of text plus 150 KB of noise) passes `cabextract -t`, and both files install byte-identical under Wine. Its tables match wixl's. - **Not as specified:** the format only forces a new folder at 65,535 blocks, about 2 GiB, so that is the only place zixl splits. A test that installs more than one folder under Wine would need a 2 GiB fixture, so splitting is proven by a unit test instead: it forces two-block folders and reads the cabinet back, checking the checksums and decompressing every block.
jeff closed this issue 2026-10-14 03:54:01 -05:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
jeff/zixl#4
No description provided.