Overview
A Squash file stores one compressed RISC OS file. It consists of a fixed 20-byte wrapper header followed by a compressed byte stream.
The wrapper header preserves the original file length and the original load and execution addresses. The compressed payload is a Unix compress-style LZW stream beginning with the standard 0x1F 0x9D marker bytes.
Compressed wrapper structure
All multi-byte fields in the wrapper header are stored as 32-bit little-endian integers.
Wrapper header
The file begins with the following fixed-size header:
| Offset | Size | Field | Contents |
|---|---|---|---|
| 0 | 4 | id | ASCII identification word SQSH. |
| 4 | 4 | length | Uncompressed length of the original file in bytes. |
| 8 | 4 | load | Original load address of the uncompressed file. |
| 12 | 4 | exec | Original execution address of the uncompressed file. |
| 16 | 4 | reserved | Reserved. This field should be zero. |
If the identification field is not SQSH, the file is not in Squash format.
The load and exec fields preserve the metadata of the original file before compression. In common RISC OS use these fields often carry the filetype and timestamp encoding rather than executable entry-point information.
Compressed payload
The payload begins immediately after the 20-byte wrapper header. It is a byte stream encoded in the same general format as Unix compress.
Payload header
The compressed stream begins with a 3-byte header:
| Offset | Size | Field | Contents |
|---|---|---|---|
| 0 | 1 | magic0 | Constant value 0x1F. |
| 1 | 1 | magic1 | Constant value 0x9D. |
| 2 | 1 | flags | Compression flags and maximum code width. |
The two magic bytes identify the payload as an LZW stream in the compress family.
Flags byte
The flags byte is interpreted as follows:
| Bit(s) | Name | Meaning | |
|---|---|---|---|
| 0-4 | Maximum code width | Maximum code width in bits. Valid values are 9 to 16, although a value of 9 is conventionally treated as meaning 10-bit growth. A conforming decoder should reject a stream declaring a width outside this range as invalid rather than guess at a width. | |
| 5-6 | Reserved, must be zero | ||
| 7 | Block-compress mode (clear-code support) | When set, code 256 is reserved as a clear code: emitting it resets the dictionary and the active code width returns to 9 bits. "Block-compress mode" and "clear-code support" are the same Unix-compress concept named two ways; this appendix uses both terms so that either is recognisable to a reader familiar with one or the other. | |
Code stream
Codes are packed least-significant-bit first. Decoding begins with 9-bit codes and the dictionary is extended as output strings are emitted. As the dictionary grows, the code width increases until it reaches the maximum width declared in the flags byte.
In block-compress mode, code 256 is a clear code. It does not emit data; instead it resets the dictionary state and returns the decoder to 9-bit codes.
The payload does not carry a separate uncompressed size field because the wrapper header already supplies the expected output length.
This format has no checksum or other integrity field anywhere in the header or code stream. The wrapper header's output-length field is the only sanity check available: a corrupted stream that happens to decode to the expected number of bytes will not be detected as wrong by the format itself.
Worked example
Wrapper layout
The following C structure matches the outer 20-byte file header:
typedef struct
{
char id[4];
unsigned int length;
unsigned int load;
unsigned int exec;
unsigned int reserved;
} squash_header;