Documentation
¶
Overview ¶
Package adc decodes Apple Data Compression (ADC), the byte-oriented LZ77 variant Apple uses for the "UDCO" flavour of UDIF disk images and, before that, for resources in classic Mac OS.
The format has no header, no checksum and no stored output length: a stream is a bare sequence of three opcodes, and it ends when its bytes run out. A caller that knows how long the output should be must check that itself.
out, err := adc.Decompress(src)
CGO is not used, so this builds for every target Go builds for.
The opcodes ¶
The first byte of each opcode says which one it is, and the format was read off streams written by Apple's own hdiutil rather than from any implementation of it:
1xxxxxxx literal run, (x+1) bytes follow, 1..128 01xxxxxx hhhhhhhh llllllll match, length (x+4) 4..67, offset (hl+1) 1..65536 00xxxxyy yyyyyyyy match, length (x+3) 3..18, offset (y+1) 1..1024
An offset counts backwards from the end of the output produced so far, so 1 is the byte just written. A match may be longer than its offset, in which case it repeats what it has already copied; that is the usual way a run of one byte is coded, and it is why the copy repeats the offset's period instead of moving a slice.
Untrusted input ¶
The stream carries no length, so the only thing that says how much a decode produces is the decode itself, and one opcode byte can ask for far more output than it costs: a three-byte long match yields up to 67 bytes (22.3 per input byte), a two-byte short match up to 18. Decompress therefore walks the opcodes once without copying, checks every operand and the running output size, and allocates exactly once, only after the size is known to be within the ceiling. The ceiling is DefaultMaxOutput for Decompress and the caller's choice for DecompressLimit; a caller that knows the real size (a UDIF chunk says how many sectors it holds) should pass it.
Index ¶
Constants ¶
const DefaultMaxOutput = 1 << 30
DefaultMaxOutput is the ceiling Decompress applies: 1 GiB. ADC amplifies by up to 22.3x, so a stream of 48 MB can ask for it.
Variables ¶
var ErrOffset = errors.New("adc: match offset reaches before the start of the output")
ErrOffset is returned when a match points further back than the output written so far, which no stream produced by a correct encoder ever does.
var ErrTooLarge = errors.New("adc: output exceeds the size limit")
ErrTooLarge is returned when the stream would produce more output than the ceiling allows. It is returned before any output is allocated.
var ErrTruncated = errors.New("adc: truncated stream")
ErrTruncated is returned when an opcode's operands, or a literal run's bytes, reach past the end of the input.
Functions ¶
func Decompress ¶
Decompress returns the bytes the stream encodes, refusing a stream that would produce more than DefaultMaxOutput bytes with ErrTooLarge. An empty input gives an empty output and no error: the format ends by exhaustion, so a stream of no opcodes is a stream of no bytes.
func DecompressLimit ¶ added in v0.3.0
DecompressLimit is Decompress with a caller-chosen ceiling: a stream whose output would exceed max bytes gives ErrTooLarge and allocates nothing proportional to what it declared. A max below zero is taken as zero.
Types ¶
This section is empty.
