Skip to content

+ add ShrinkIt NuLZW building block - #126

Merged
Hawkynt merged 1 commit into
mainfrom
feat/shrinkit-nulzw-building-block
Aug 30, 2026
Merged

+ add ShrinkIt NuLZW building block#126
Hawkynt merged 1 commit into
mainfrom
feat/shrinkit-nulzw-building-block

Conversation

@Hawkynt

@Hawkynt Hawkynt commented Aug 29, 2026

Copy link
Copy Markdown
Owner

What changed

Adds the Apple II NuFX/ShrinkIt RLE + LZW primitive to Compression.Core.Dictionary.Lzw.

NuLzwCodec implements both native ShrinkIt dialects:

  • LZW/1 — ProDOS ShrinkIt behavior, dictionary reset every 4096-byte chunk, embedded CRC-16/XMODEM over zero-padded expanded chunks
  • LZW/2 — GS/ShrinkIt behavior, dictionary persistence across useful LZW chunks, reset when compression falls back, thread-level integrity supplied by NuFX
  • 4096-byte chunking with final zero-fill and caller-supplied logical expanded length on decode
  • ShrinkIt delimiter RLE (0xDB by default), including delimiter escaping and 256-byte runs
  • 9→12-bit LSB-first codes with ShrinkIt's early-change width transition
  • 0x100 clear code and the rare dictionary-full-at-block-boundary deferred-clear case
  • raw/RLE/LZW per-chunk fallback decisions matching ShrinkIt economics
  • tolerance of the historical trailing pad byte
  • tolerance of the unreliable LZW/2 compressed-size recovery word emitted incorrectly by some Macintosh tools; actual bit consumption + requested expanded length remain authoritative, so true truncation is still rejected

A benchmarkable NuLzwBuildingBlock uses LZW/2 and prefixes only the expanded length required by the generic raw-building-block contract; NuLzwCodec itself emits/consumes the native bytes used inside NuFX.

Tests

Coverage includes CRC-16/XMODEM, canonical empty headers, partial/exact/multi-4K chunks, delimiter/run-heavy data, deterministic incompressible data, long persistent LZW/2 dictionaries across code-width changes, LZW/1 CRC corruption, trailing-pad tolerance, malformed Macintosh size hints, building-block roundtrip, and actual bitstream truncation rejection.

Behavior was cross-checked against Apple II File Type Note $e0/8002, NuFX final-revision documentation, and current CiderPress II compatibility behavior. The NuFX .shk/.sdk container remains separate in #128.

@Hawkynt
Hawkynt force-pushed the feat/shrinkit-nulzw-building-block branch 4 times, most recently from 799bf69 to e8f610b Compare August 30, 2026 01:13
NuLZW as ShrinkIt writes it: 12-bit codes, the clear that resets the table,
and the per-block framing the format wraps around them.

The encoder held its running prefix in a byte, so the first code past 255
would not go back into it.
@Hawkynt
Hawkynt force-pushed the feat/shrinkit-nulzw-building-block branch from e8f610b to 2e61a49 Compare August 30, 2026 01:24
@Hawkynt
Hawkynt merged commit 35fb50d into main Aug 30, 2026
3 checks passed
@Hawkynt
Hawkynt deleted the feat/shrinkit-nulzw-building-block branch August 30, 2026 03:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant