An LHA archive is a run of entries, each a header and the compressed data, ended by a
single 00 byte where the next header would start. Every header has the
method ID at offset 2 and the header level at offset 20; the level decides the rest.
This page follows the header notes of LHa for UNIX (header.doc) and the
parsers of the Lhasa library. Numbers are little-endian.
Header levels
| Offset | Level 0 | Level 1 | Level 2 | Level 3 |
|---|---|---|---|---|
0 | Header size, 1 byte | Header size, 1 byte | Total header size, 2 bytes | Word size, 2 bytes, always 4 |
1 | Header checksum, 1 byte | Header checksum, 1 byte | ||
2 | Method ID, 5 characters, such as -lh5- | |||
7 | Packed size, 4 | Skip size, 4: packed size plus all extended headers | Packed size, 4 | Packed size, 4 |
11 | Original size, 4 | |||
15 | MS-DOS time, 2, and date, 2 | MS-DOS time, 2, and date, 2 | Unix time, 4 | Unix time, 4 |
19 | MS-DOS attribute, 1 | Fixed 20, 1 | Reserved, 1 | Reserved, 1 |
20 | Level 00 | Level 01 | Level 02 | Level 03 |
21 | Name length, 1; name; file CRC-16, 2; optional extension area | Name length, 1; name; file CRC-16, 2; OS ID, 1; next extended header size, 2 | File CRC-16, 2 | File CRC-16, 2 |
23 | OS ID, 1 | OS ID, 1 | ||
24 | Next extended header size, 2 | Total header size, 4 | ||
26 / 28 | Extended headers (2-byte sizes) | Next extended header size, 4, then extended headers (4-byte sizes) | ||
- Level 0 is the LHarc and LArc layout. The header size counts the
bytes after the checksum byte; the name holds the whole path with
\separators. Anything between the CRC and the end of the header is an extension area (below). - Level 1 keeps the level 0 layout, so old programs can still extract the data, and adds extended headers after it. They are counted in the skip size, not in the header size, so the true packed size is the skip size minus their lengths. The base header’s name is usually the file name only, with the folder in an extended header.
- Level 2 has a 2-byte total size covering the base header and all extended headers, and no name in the base header: the name is always in extended headers. A level 2 header’s CRC is in the common extended header.
- Level 3, used by some later writers, is level 2 with 4-byte sizes: the word size at offset 0, a 4-byte total header size at 24, and 4-byte extended header sizes.
Header checksum and CRC
Levels 0 and 1: the checksum byte is the sum of the base header’s bytes from offset 2 to its end (the header size says where), keeping the low 8 bits. It does not cover the extended headers.
The file CRC, and the header CRC in a common extended header, is CRC-16 with
polynomial A001 (the reflected form of 8005, often called
CRC-16/ARC), starting from 0. For the header CRC, the two CRC bytes count as zero
while it is worked out.
Times
Levels 0 and 1 store an MS-DOS time word then date word, in local time: date bits 15 to 9 year − 1980, 8 to 5 month, 4 to 0 day; time bits 15 to 11 hour, 10 to 5 minute, 4 to 0 seconds ÷ 2. Levels 2 and 3 store Unix time, seconds since 1970 UTC.
Level 0 extension area
Some writers put more bytes after the CRC of a level 0 header. When the first byte
is the Unix OS ID (U), the area is at least 12 bytes: a byte that must be
00, a 4-byte Unix time, and in its last 6 bytes the permissions, user ID
and group ID, 2 bytes each. OS-9 writers use their own 22-byte layout with OS-9
permissions. These layouts are from Lhasa’s source.
Extended headers
In levels 1 to 3 each extended header is a type byte, its data, and the size of the next extended header (2 bytes, or 4 in level 3); a size of 0 ends the chain. A size counts the whole extended header: type, data and the next-size field.
| Type | Name | Data |
|---|---|---|
00 | Common | CRC-16 of the whole header, then optional information. |
01 | File name | The file name, without a path; no NUL. |
02 | Directory name | The folder path, with FF bytes between the folder names and normally after the last one. Lhasa adds a missing final FF because Amiga LHA 1.22 left it out. |
39 | Multi-disc | Defined for archives split across disks; no public layout found. |
3F | Comment | A comment. |
40 | MS-DOS attribute | The MS-DOS file attributes, 2 bytes. Not in LHa for UNIX’s notes or Lhasa; this layout is from other LHA writers’ notes and is unconfirmed. |
41 | Windows timestamps | 24 bytes: creation, modification and access times, each a 64-bit Windows FILETIME (100-nanosecond units since 1601). |
42 | File sizes | 16 bytes: the 64-bit packed size, then the 64-bit original size, for files over 4 GiB. |
50 | Unix permissions | 2 bytes: the Unix mode. |
51 | Unix group and user ID | 2-byte group ID, then 2-byte user ID. |
52 | Unix group name | Text. |
53 | Unix user name | Text. |
54 | Unix time | 4 bytes: modification time, seconds since 1970. LHa for UNIX writes it only in level 1 headers, which otherwise have an MS-DOS time. |
CC | OS-9 | OS-9 attributes; Lhasa reads the 2-byte permissions at offset 7 of the data and does not decode the rest. |
Types 00 to 3F are meant to be independent of the system,
40 to 7F and up for particular systems. Writers for the
Macintosh, Amiga and others defined further types (such as 7D,
7E, 7F and FF) whose layouts were never
published in a form we could confirm; readers skip them by their size.
Symbolic links are stored with the method -lhd- and the name
link|target, split at the |.
Method IDs
| ID | Window | Longest match | Coding |
|---|---|---|---|
-lh0- | – | – | Stored |
-lh1- | 4 KiB | 60 | LZSS with dynamic (adaptive) Huffman; fixed coding of positions. LHarc 1.x’s method. |
-lh2- | 8 KiB | 256 | Dynamic Huffman. Experimental, rarely seen. |
-lh3- | 8 KiB | 256 | Static Huffman. Experimental, rarely seen. |
-lh4- | 4 KiB | 256 | Static Huffman with better coding of positions and trees. |
-lh5- | 8 KiB | 256 | As -lh4-. LHA 2.x’s default and the most common method. |
-lh6- | 32 KiB | 256 | As -lh4-. |
-lh7- | 64 KiB | 256 | As -lh4-. |
-lhd- | – | – | Not a method: the entry is a folder (or a link), with no data. |
-lzs- | 2 KiB | 17 | LArc’s LZSS method. |
-lz4- | – | – | LArc: stored. |
-lz5- | 4 KiB | 17 | LArc’s LZSS method. |
-pm0-, -pm1-, -pm2- | PMarc, an archiver for MSX-DOS with the same headers: stored and two compression methods, not described here. | ||
LHARK, a DOS archiver, wrote -lh7- with a different method in level 1
archives; Lhasa tells them apart by context and calls that method
-lk7-.
OS IDs
| Character | System |
|---|---|
M | MS-DOS |
2 | OS/2 |
9 | OS-9 |
K | OS-9/68K |
3 | OS/386 |
H | Human68K |
U | Unix |
C | CP/M |
F | FLEX |
m | Macintosh |
R | Runser |
This is the list in LHa for UNIX’s header notes. Other ports use further letters, for example for the Amiga, Atari and Windows; no single public register lists them.