Windows Help uses three kinds of compression. LZ77 squeezes |TOPIC blocks, phrase tables and pictures. Run-length coding is for pictures. Phrase compression replaces common words and phrases in the text with short codes.
LZ77
A flag byte is followed by eight items, one for each flag bit from the lowest up. A clear
bit is one literal byte. A set bit is a 16-bit little-endian word, copying
(word >> 12) + 3 bytes from
(word & 0xFFF) + 1 bytes back in what has already been produced. Copies may
overlap themselves. Each |TOPIC block is decompressed on its own, starting from
empty.
Run-length coding
Used for the pixels of pictures, alone or after LZ77. A control byte with its top bit set is followed by that many literal bytes (low seven bits). With its top bit clear, the next byte is repeated that many times.
The |Phrases table
Most compilers replace common words and phrases with codes. The table lists phrases as offsets into a block of text.
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 2 | u16 | NumPhrases | The number of phrases |
| 2 | 2 | u16 | OneHundred | Always 0x0100 |
| 4 | 4 | u32 | DecompressedSize | Minor above 16 only: the size of the phrase text once LZ77 is undone |
| 4 or 8 | 2 each | u16 | PhraseOffset | NumPhrases + 1 offsets of the phrases, the first equal to the table’s own size |
| … | … | bytes | phrase text | Plain for Minor 16 and below, LZ77-compressed above that |
Phrase n runs from PhraseOffset[n] to
PhraseOffset[n+1], counted from the start of the offsets. Phrases are not
NUL-terminated.
Decoding text
A byte above 15 or equal to 0 is itself. A byte from 1 to 15 starts a code with the next byte:
code = (byte − 1) × 256 + next byte
phrase number = code / 2
if code is odd, a space follows the phrase
Hall compression
The Windows 95 compiler usually replaces |Phrases with two files.
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 4 | u32 | Magic | Always 1 |
| 4 | 4 | u32 | NEntries | The number of phrases |
| 8 | 4 | u32 | CompressedSize | The size of the bit-coded lengths |
| 12 | 4 | u32 | PhrImageSize | The size of the phrase text |
| 16 | 4 | u32 | PhrImageCompressedSize | If this differs from PhrImageSize, |PhrImage is LZ77-compressed |
| 20 | 4 | u32 | Always0 | Always 0 |
| 24 | 2 | u16 | BitCount | The low four bits set the length coding |
| 26 | 2 | u16 | unknown | Usually 0x4A00 |
|PhrIndex holds the phrase lengths at offset 28, coded in bits read low-first
from 32-bit words. For each phrase, n starts at 1. While the next bit is 1, add
2BitCount. Then read BitCount more bits, each adding
1, 2, 4 and so on when set. |PhrImage is the phrases’ text in order.
Decoding text
| Byte | Meaning |
|---|---|
| Even | Phrase number byte / 2 |
Low bits 01 | Phrase number (byte + 1) × 64 + next byte |
Low bits 011 | The next byte / 8 + 1 bytes are literal |
Low bits 0111 | byte / 16 + 1 spaces |
Low bits 1111 | byte / 16 + 1 NUL bytes |