License: CC0 1.0.
All multi-byte integers are little-endian unless stated otherwise.
- Archive Layout
- Signatures
- ALZ File Header
- Local File Header
- Compression Methods
- Encryption
- DOS Date/Time Format
- Comment Section
- File Tail
- Central Directory Structure
- End of Central Directory
- Multi-Volume Archives
- CRC32
- Filename Encoding
An ALZ archive consists of a sequence of tagged records identified by 4-byte signatures:
[ALZ File Header] 8 bytes
[Local File Header 0] variable
[Compressed data]
[Local File Header 1 ...]
[Comment Section] optional
[Central Directory] optional, not used for extraction
[End of Central Directory]
The archive is parsed sequentially. The last 16 bytes of the file contain a tail structure (section 9) that is read first to determine the comment section size.
| Signature (LE) | Description |
|---|---|
0x015a4c41 |
ALZ file header |
0x015a4c42 |
Local file header |
0x015a4c43 |
Central directory structure |
0x025a4c43 |
End of central directory |
0x015a4c45 |
Comment section |
0x035a4c43 |
Split marker |
| Offset | Size | Description |
|---|---|---|
| +0 | 4 | Signature 0x015a4c41 |
| +4 | 2 | Version |
| +6 | 2 | ID |
| Offset | Size | Field | Description |
|---|---|---|---|
| +0 | 2 | fileNameLength | Length of filename in bytes |
| +2 | 1 | fileAttribute | See 4.2 |
| +3 | 4 | fileTimeDate | DOS date/time, see 7 |
| +7 | 1 | fileDescriptor | See 4.3 |
| +8 | 1 | unknown |
| Bit | Mask | Meaning |
|---|---|---|
| 0 | 0x01 |
Read-only |
| 1 | 0x02 |
Hidden |
| 2 | 0x04 |
System |
| 4 | 0x10 |
Directory |
| 5 | 0x20 |
Archive |
This byte is the low 8 bits of the Windows FILE_ATTRIBUTE_* value, stored
unchanged.
| Bits | Mask | Meaning |
|---|---|---|
| 0 | 0x01 |
Encrypted |
| 3 | 0x08 |
Data descriptor present |
| 4-7 | 0xF0 |
Size field byte width |
The high nibble (fileDescriptor >> 4) gives the byte width N of the compressed/uncompressed size fields:
| Value | N |
|---|---|
0x00 |
0 (no variable part; directory entry) |
0x10 |
1 |
0x20 |
2 |
0x40 |
4 |
0x80 |
8 |
Only these values are valid. Any other value (e.g., 0x30, 0x50) is an error.
| Offset | Size | Field | Description |
|---|---|---|---|
| +0 | 1 | compressionMethod | See 5 |
| +1 | 1 | unknown | |
| +2 | 4 | fileCRC | CRC32 of uncompressed data |
| +6 | N | compressedSize | LE integer, zero-padded to 64-bit |
| +6+N | N | uncompressedSize | LE integer, zero-padded to 64-bit |
| Size | Field |
|---|---|
| fileNameLength | Filename (CP949 or UTF-8) |
| 12 (if encrypted) | Encryption header, see 6 |
| compressedSize | File data |
| Value | Method |
|---|---|
| 0 | Store (uncompressed) |
| 1 | ALZ-modified bzip2, see 5.1 |
| 2 | Raw DEFLATE (RFC 1951, no wrapper) |
Values 3+ are undefined. Unknown methods are a fatal error.
Standard bzip2 with the following changes:
| Standard bzip2 | ALZ | |
|---|---|---|
| Stream header | BZh[1-9] (4 bytes) |
Absent |
| Block size | From header | Hardcoded 9 (900K) |
| Block magic | 0x314159265359 (6 bytes) |
DLZ\x01 (4 bytes) |
| End magic | 0x177245385090 (6 bytes) |
DLZ\x02 (4 bytes) |
| Block CRC | 4 bytes | Absent |
| Randomization bit | 1 bit | Absent |
| Combined CRC | 4 bytes at end | Absent |
| origPtr | 24-bit big-endian | Unchanged |
| Huffman/MTF/BWT/RLE | Standard | Unchanged |
Block parsing:
Read 4 bytes: expect 'D' 'L' 'Z' [type]
type == 0x01: data block
Read origPtr (3 bytes, big-endian)
Decode standard bzip2 block data (Huffman, MTF, BWT, RLE)
type == 0x02: end of stream
PKware ZIP traditional encryption (identical to ZIP 2.0).
Three 32-bit keys, initialized:
key[0] = 0x12345678
key[1] = 0x23456789
key[2] = 0x34567890
Each password byte is processed through UpdateKeys (6.2).
key[0] = CRC32_TABLE[(key[0] ^ c) & 0xFF] ^ (key[0] >> 8)
key[1] = (key[1] + (key[0] & 0xFF)) * 134775813 + 1
key[2] = CRC32_TABLE[(key[2] ^ (key[1] >> 24)) & 0xFF] ^ (key[2] >> 8)
The constant 134775813 is 0x08088405 in hexadecimal. CRC32 polynomial:
0xEDB88320.
temp = (key[2] | 2) as u16
return (temp * (temp ^ 1)) >> 8
For each ciphertext byte:
plain = cipher ^ DecryptByte()
UpdateKeys(plain)
The 12-byte encryption header (after filename) is decrypted. The last decrypted byte must equal:
(fileCRC >> 24) & 0xFFnormally(fileTimeDate >> 8) & 0xFFif data descriptor flag (bit 3) is set
On match, re-initialize keys with the password and re-process the 12-byte header to establish the correct key state for data decryption.
Bits 0-4: seconds / 2
Bits 5-10: minutes
Bits 11-15: hours
Bits 16-20: day
Bits 21-24: month
Bits 25-31: year - 1980
Signature: 0x015a4c45
The comment section total size (including the 4-byte signature) is stored in
endInfos[1] of the file tail (section 9). After the signature, the
remaining size is endInfos[1] - 4 bytes.
The section contains a sequence of comment entries:
| Offset | Size | Field | Description |
|---|---|---|---|
| +0 | 4 | fileIndex | File index (0xFFFFFFFF = archive-level comment) |
| +4 | 2 | commentSize | Comment data size |
| +6 | N | comment | Comment text (local codepage encoding) |
Entries repeat until the section size is consumed. Each entry is 6 + commentSize bytes.
The last 16 bytes of an ALZ file contain four UInt32 values:
| Offset | Size | Field | Description |
|---|---|---|---|
| +0 | 4 | endInfos[0] | Unknown |
| +4 | 4 | endInfos[1] | Comment section total size (including signature) |
| +8 | 4 | endInfos[2] | Unknown |
| +12 | 4 | endInfos[3] | Unknown |
Read these 16 bytes first (seek to EOF-16), then seek back to the beginning
to parse sequentially. If endInfos[1] <= 4, there is no comment data.
| Offset | Size | Description |
|---|---|---|
| +0 | 4 | Signature 0x015a4c43 |
| +4 | 4 | Unknown |
| +8 | 4 | Unknown |
| +12 | 4 | Unknown |
Not used for extraction. The archive is parsed sequentially.
| Offset | Size | Description |
|---|---|---|
| +0 | 4 | Signature 0x025a4c43 |
No additional fields.
| Volume | Extension |
|---|---|
| 0 | .alz |
| 1 | .a00 |
| 2 | .a01 |
| ... | |
| 100 | .a99 |
| 101 | .b00 |
| ... |
For volume index i > 0: letter = 'a' + (i-1)/100, number = (i-1) % 100, extension = {letter}{number:02}. Maximum 1000 volumes.
First volume (.alz):
[data...]
[16-byte tail]
Middle volumes:
[8-byte header]
[data...]
[16-byte tail]
Last volume:
[8-byte header] (unless it is also the first)
[data...]
The last volume has no 16-byte tail. For a single-volume archive (first = last), there is no header and no tail subtracted from the data region.
The header and tail are opaque metadata skipped during I/O. Usable data per
volume = file_size - header_size - tail_size.
| Name | Value |
|---|---|
| Header size | 8 bytes |
| Tail size | 16 bytes |
| Max volumes | 1000 |
Standard CRC32 with polynomial 0xEDB88320. Computed over decompressed (and decrypted) file data. Verified against fileCRC from the local file header.
Filenames are typically CP949 (a superset of EUC-KR). If the bytes are valid UTF-8, they should be interpreted as UTF-8. Otherwise, decode as CP949.
Path separators may be / or \; normalize to the platform convention.