Compressed Macintosh resource data, Apple `'dcmp' (2)` format: Go parsing library

Compressed resource data in 'dcmp' (2) format, as stored in compressed resources with header type 9 and decompressor ID 2.

The 'dcmp' (2) decompressor resource is included in the System file of System 7.0 and later. This compression format is used for a few compressed resources in System 7.0's files (such as the System file). This decompressor is also included with and used by some other Apple applications, such as ResEdit. (Note: ResEdit includes the 'dcmp' (2) resource, but none of its resources actually use this decompressor.)

This compression format is based on simple dictionary coding, where each byte in the compressed data expands to two bytes, based on a lookup table (either included in the compressed data or provided by the decompressor). An alternative "tagged" compression format is also supported, which allows using two-byte literals in addition to single-byte table references, at the cost of requiring an extra "tag" byte every 16 output bytes, to differentiate literals and table references.

Application

Mac OS

KS implementation details

License: MIT
Minimal Kaitai Struct required: 0.8

This page hosts a formal specification of Compressed Macintosh resource data, Apple `'dcmp' (2)` format using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Go source code to parse Compressed Macintosh resource data, Apple `'dcmp' (2)` format

dcmp_2.go

// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.

import (
	"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
	"bytes"
	"io"
)


/**
 * Compressed resource data in `'dcmp' (2)` format,
 * as stored in compressed resources with header type `9` and decompressor ID `2`.
 * 
 * The `'dcmp' (2)` decompressor resource is included in the System file of System 7.0 and later.
 * This compression format is used for a few compressed resources in System 7.0's files
 * (such as the System file).
 * This decompressor is also included with and used by some other Apple applications,
 * such as ResEdit.
 * (Note: ResEdit includes the `'dcmp' (2)` resource,
 * but none of its resources actually use this decompressor.)
 * 
 * This compression format is based on simple dictionary coding,
 * where each byte in the compressed data expands to two bytes,
 * based on a lookup table
 * (either included in the compressed data or provided by the decompressor).
 * An alternative "tagged" compression format is also supported,
 * which allows using two-byte literals in addition to single-byte table references,
 * at the cost of requiring an extra "tag" byte every 16 output bytes,
 * to differentiate literals and table references.
 * @see <a href="https://github.com/dgelessus/python-rsrcfork/blob/f891a6e/src/rsrcfork/compress/dcmp2.py">Source</a>
 */
type Dcmp2 struct {
	CustomLookupTable [][]byte
	Data interface{}
	LastByte []byte
	LenDecompressed uint32
	HeaderParametersWithIo *BytesWithIo
	_io *kaitai.Stream
	_root *Dcmp2
	_parent interface{}
	_raw_Data []byte
	_f_headerParameters bool
	headerParameters *Dcmp2_HeaderParameters
	_f_isLenDecompressedOdd bool
	isLenDecompressedOdd bool
	_f_defaultLookupTable bool
	defaultLookupTable [][]byte
	_f_lookupTable bool
	lookupTable [][]byte
}
func NewDcmp2(lenDecompressed uint32, headerParametersWithIo *BytesWithIo) *Dcmp2 {
	return &Dcmp2{
		LenDecompressed: lenDecompressed,
		HeaderParametersWithIo: headerParametersWithIo,
	}
}

func (this *Dcmp2) Read(io *kaitai.Stream, parent interface{}, root *Dcmp2) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp1, err := this.HeaderParameters()
	if err != nil {
		return err
	}
	if (tmp1.Flags.HasCustomLookupTable) {
		tmp2, err := this.HeaderParameters()
		if err != nil {
			return err
		}
		tmp3, err := tmp2.NumCustomLookupTableEntries()
		if err != nil {
			return err
		}
		for i := 0; i < int(tmp3); i++ {
			_ = i
			tmp4, err := this._io.ReadBytes(int(2))
			if err != nil {
				return err
			}
			tmp4 = tmp4
			this.CustomLookupTable = append(this.CustomLookupTable, tmp4)
		}
	}
	tmp5, err := this.HeaderParameters()
	if err != nil {
		return err
	}
	switch (tmp5.Flags.Tagged) {
	case true:
		tmp6, err := this._io.Size()
		if err != nil {
			return err
		}
		tmp7, err := this._io.Pos()
		if err != nil {
			return err
		}
		var tmp8 int8;
		tmp9, err := this.IsLenDecompressedOdd()
		if err != nil {
			return err
		}
		if (tmp9) {
			tmp8 = 1
		} else {
			tmp8 = 0
		}
		tmp10, err := this._io.ReadBytes(int(((tmp6 - tmp7) - tmp8)))
		if err != nil {
			return err
		}
		tmp10 = tmp10
		this._raw_Data = tmp10
		_io__raw_Data := kaitai.NewStream(bytes.NewReader(this._raw_Data))
		tmp11 := NewDcmp2_TaggedData()
		err = tmp11.Read(_io__raw_Data, this, this._root)
		if err != nil {
			return err
		}
		this.Data = tmp11
	default:
		tmp12, err := this._io.Size()
		if err != nil {
			return err
		}
		tmp13, err := this._io.Pos()
		if err != nil {
			return err
		}
		var tmp14 int8;
		tmp15, err := this.IsLenDecompressedOdd()
		if err != nil {
			return err
		}
		if (tmp15) {
			tmp14 = 1
		} else {
			tmp14 = 0
		}
		tmp16, err := this._io.ReadBytes(int(((tmp12 - tmp13) - tmp14)))
		if err != nil {
			return err
		}
		tmp16 = tmp16
		this._raw_Data = tmp16
		_io__raw_Data := kaitai.NewStream(bytes.NewReader(this._raw_Data))
		tmp17 := NewDcmp2_UntaggedData()
		err = tmp17.Read(_io__raw_Data, this, this._root)
		if err != nil {
			return err
		}
		this.Data = tmp17
	}
	tmp18, err := this.IsLenDecompressedOdd()
	if err != nil {
		return err
	}
	if (tmp18) {
		tmp19, err := this._io.ReadBytes(int(1))
		if err != nil {
			return err
		}
		tmp19 = tmp19
		this.LastByte = tmp19
	}
	return err
}

/**
 * The parsed decompressor-specific parameters from the compressed resource header.
 */
func (this *Dcmp2) HeaderParameters() (v *Dcmp2_HeaderParameters, err error) {
	if (this._f_headerParameters) {
		return this.headerParameters, nil
	}
	thisIo := this.HeaderParametersWithIo._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64(0), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp20 := NewDcmp2_HeaderParameters()
	err = tmp20.Read(thisIo, this, this._root)
	if err != nil {
		return nil, err
	}
	this.headerParameters = tmp20
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	this._f_headerParameters = true
	this._f_headerParameters = true
	return this.headerParameters, nil
}

/**
 * Whether the length of the decompressed data is odd.
 * This affects the meaning of the last byte of the compressed data.
 */
func (this *Dcmp2) IsLenDecompressedOdd() (v bool, err error) {
	if (this._f_isLenDecompressedOdd) {
		return this.isLenDecompressedOdd, nil
	}
	tmp21 := this.LenDecompressed % 2
	if tmp21 < 0 {
		tmp21 += 2
	}
	this.isLenDecompressedOdd = bool(tmp21 != 0)
	this._f_isLenDecompressedOdd = true
	return this.isLenDecompressedOdd, nil
}

/**
 * The default lookup table,
 * which is used if no custom lookup table is included with the compressed data.
 */
func (this *Dcmp2) DefaultLookupTable() (v [][]byte, err error) {
	if (this._f_defaultLookupTable) {
		return this.defaultLookupTable, nil
	}
	this.defaultLookupTable = [][]byte([][]byte{[]uint8{0, 0}, []uint8{0, 8}, []uint8{78, 186}, []uint8{32, 110}, []uint8{78, 117}, []uint8{0, 12}, []uint8{0, 4}, []uint8{112, 0}, []uint8{0, 16}, []uint8{0, 2}, []uint8{72, 110}, []uint8{255, 252}, []uint8{96, 0}, []uint8{0, 1}, []uint8{72, 231}, []uint8{47, 46}, []uint8{78, 86}, []uint8{0, 6}, []uint8{78, 94}, []uint8{47, 0}, []uint8{97, 0}, []uint8{255, 248}, []uint8{47, 11}, []uint8{255, 255}, []uint8{0, 20}, []uint8{0, 10}, []uint8{0, 24}, []uint8{32, 95}, []uint8{0, 14}, []uint8{32, 80}, []uint8{63, 60}, []uint8{255, 244}, []uint8{76, 238}, []uint8{48, 46}, []uint8{103, 0}, []uint8{76, 223}, []uint8{38, 110}, []uint8{0, 18}, []uint8{0, 28}, []uint8{66, 103}, []uint8{255, 240}, []uint8{48, 60}, []uint8{47, 12}, []uint8{0, 3}, []uint8{78, 208}, []uint8{0, 32}, []uint8{112, 1}, []uint8{0, 22}, []uint8{45, 64}, []uint8{72, 192}, []uint8{32, 120}, []uint8{114, 0}, []uint8{88, 143}, []uint8{102, 0}, []uint8{79, 239}, []uint8{66, 167}, []uint8{103, 6}, []uint8{255, 250}, []uint8{85, 143}, []uint8{40, 110}, []uint8{63, 0}, []uint8{255, 254}, []uint8{47, 60}, []uint8{103, 4}, []uint8{89, 143}, []uint8{32, 107}, []uint8{0, 36}, []uint8{32, 31}, []uint8{65, 250}, []uint8{129, 225}, []uint8{102, 4}, []uint8{103, 8}, []uint8{0, 26}, []uint8{78, 185}, []uint8{80, 143}, []uint8{32, 46}, []uint8{0, 7}, []uint8{78, 176}, []uint8{255, 242}, []uint8{61, 64}, []uint8{0, 30}, []uint8{32, 104}, []uint8{102, 6}, []uint8{255, 246}, []uint8{78, 249}, []uint8{8, 0}, []uint8{12, 64}, []uint8{61, 124}, []uint8{255, 236}, []uint8{0, 5}, []uint8{32, 60}, []uint8{255, 232}, []uint8{222, 252}, []uint8{74, 46}, []uint8{0, 48}, []uint8{0, 40}, []uint8{47, 8}, []uint8{32, 11}, []uint8{96, 2}, []uint8{66, 110}, []uint8{45, 72}, []uint8{32, 83}, []uint8{32, 64}, []uint8{24, 0}, []uint8{96, 4}, []uint8{65, 238}, []uint8{47, 40}, []uint8{47, 1}, []uint8{103, 10}, []uint8{72, 64}, []uint8{32, 7}, []uint8{102, 8}, []uint8{1, 24}, []uint8{47, 7}, []uint8{48, 40}, []uint8{63, 46}, []uint8{48, 43}, []uint8{34, 110}, []uint8{47, 43}, []uint8{0, 44}, []uint8{103, 12}, []uint8{34, 95}, []uint8{96, 6}, []uint8{0, 255}, []uint8{48, 7}, []uint8{255, 238}, []uint8{83, 64}, []uint8{0, 64}, []uint8{255, 228}, []uint8{74, 64}, []uint8{102, 10}, []uint8{0, 15}, []uint8{78, 173}, []uint8{112, 255}, []uint8{34, 216}, []uint8{72, 107}, []uint8{0, 34}, []uint8{32, 75}, []uint8{103, 14}, []uint8{74, 174}, []uint8{78, 144}, []uint8{255, 224}, []uint8{255, 192}, []uint8{0, 42}, []uint8{39, 64}, []uint8{103, 2}, []uint8{81, 200}, []uint8{2, 182}, []uint8{72, 122}, []uint8{34, 120}, []uint8{176, 110}, []uint8{255, 230}, []uint8{0, 9}, []uint8{50, 46}, []uint8{62, 0}, []uint8{72, 65}, []uint8{255, 234}, []uint8{67, 238}, []uint8{78, 113}, []uint8{116, 0}, []uint8{47, 44}, []uint8{32, 108}, []uint8{0, 60}, []uint8{0, 38}, []uint8{0, 80}, []uint8{24, 128}, []uint8{48, 31}, []uint8{34, 0}, []uint8{102, 12}, []uint8{255, 218}, []uint8{0, 56}, []uint8{102, 2}, []uint8{48, 44}, []uint8{32, 12}, []uint8{45, 110}, []uint8{66, 64}, []uint8{255, 226}, []uint8{169, 240}, []uint8{255, 0}, []uint8{55, 124}, []uint8{229, 128}, []uint8{255, 220}, []uint8{72, 104}, []uint8{89, 79}, []uint8{0, 52}, []uint8{62, 31}, []uint8{96, 8}, []uint8{47, 6}, []uint8{255, 222}, []uint8{96, 10}, []uint8{112, 2}, []uint8{0, 50}, []uint8{255, 204}, []uint8{0, 128}, []uint8{34, 81}, []uint8{16, 31}, []uint8{49, 124}, []uint8{160, 41}, []uint8{255, 216}, []uint8{82, 64}, []uint8{1, 0}, []uint8{103, 16}, []uint8{160, 35}, []uint8{255, 206}, []uint8{255, 212}, []uint8{32, 6}, []uint8{72, 120}, []uint8{0, 46}, []uint8{80, 79}, []uint8{67, 250}, []uint8{103, 18}, []uint8{118, 0}, []uint8{65, 232}, []uint8{74, 110}, []uint8{32, 217}, []uint8{0, 90}, []uint8{127, 255}, []uint8{81, 202}, []uint8{0, 92}, []uint8{46, 0}, []uint8{2, 64}, []uint8{72, 199}, []uint8{103, 20}, []uint8{12, 128}, []uint8{46, 159}, []uint8{255, 214}, []uint8{128, 0}, []uint8{16, 0}, []uint8{72, 66}, []uint8{74, 107}, []uint8{255, 210}, []uint8{0, 72}, []uint8{74, 71}, []uint8{78, 209}, []uint8{32, 111}, []uint8{0, 65}, []uint8{96, 12}, []uint8{42, 120}, []uint8{66, 46}, []uint8{50, 0}, []uint8{101, 116}, []uint8{103, 22}, []uint8{0, 68}, []uint8{72, 109}, []uint8{32, 8}, []uint8{72, 108}, []uint8{11, 124}, []uint8{38, 64}, []uint8{4, 0}, []uint8{0, 104}, []uint8{32, 109}, []uint8{0, 13}, []uint8{42, 64}, []uint8{0, 11}, []uint8{0, 62}, []uint8{2, 32}})
	this._f_defaultLookupTable = true
	return this.defaultLookupTable, nil
}

/**
 * The lookup table to be used for this compressed data.
 */
func (this *Dcmp2) LookupTable() (v [][]byte, err error) {
	if (this._f_lookupTable) {
		return this.lookupTable, nil
	}
	var tmp22 [][]byte;
	tmp23, err := this.HeaderParameters()
	if err != nil {
		return nil, err
	}
	if (tmp23.Flags.HasCustomLookupTable) {
		tmp22 = this.CustomLookupTable
	} else {
		tmp24, err := this.DefaultLookupTable()
		if err != nil {
			return nil, err
		}
		tmp22 = tmp24
	}
	this.lookupTable = [][]byte(tmp22)
	this._f_lookupTable = true
	return this.lookupTable, nil
}

/**
 * The custom lookup table to be used instead of the default lookup table.
 */

/**
 * The compressed data.
 * The structure of the data varies depending on whether the "tagged" or "untagged" variant of the compression format is used.
 */

/**
 * The last byte of the decompressed data,
 * stored literally.
 * Only present if the decompressed data has an odd length.
 * 
 * This special case is necessary because the compressed data is otherwise always stored in two-byte groups,
 * either literally or as table references,
 * so otherwise there would be no way to compress odd-length resources using this format.
 */

/**
 * Decompressor-specific parameters for this compression format,
 * as stored in the compressed resource header.
 */
type Dcmp2_HeaderParameters struct {
	Unknown uint16
	NumCustomLookupTableEntriesM1 uint8
	Flags *Dcmp2_HeaderParameters_Flags
	_io *kaitai.Stream
	_root *Dcmp2
	_parent *Dcmp2
	_f_numCustomLookupTableEntries bool
	numCustomLookupTableEntries int
}
func NewDcmp2_HeaderParameters() *Dcmp2_HeaderParameters {
	return &Dcmp2_HeaderParameters{
	}
}

func (this *Dcmp2_HeaderParameters) Read(io *kaitai.Stream, parent *Dcmp2, root *Dcmp2) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp25, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Unknown = uint16(tmp25)
	tmp26, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.NumCustomLookupTableEntriesM1 = tmp26
	tmp27 := NewDcmp2_HeaderParameters_Flags()
	err = tmp27.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Flags = tmp27
	return err
}

/**
 * The number of entries in the custom lookup table.
 * Only used if a custom lookup table is present.
 */
func (this *Dcmp2_HeaderParameters) NumCustomLookupTableEntries() (v int, err error) {
	if (this._f_numCustomLookupTableEntries) {
		return this.numCustomLookupTableEntries, nil
	}
	if (this.Flags.HasCustomLookupTable) {
		this.numCustomLookupTableEntries = int((this.NumCustomLookupTableEntriesM1 + 1))
	}
	this._f_numCustomLookupTableEntries = true
	return this.numCustomLookupTableEntries, nil
}

/**
 * The meaning of this field is unknown.
 * It does not appear to have any effect on the format of the compressed data or the decompression process.
 * 
 * The value of this field is usually zero and otherwise a small integer (< 10).
 * For `'lpch'` resources,
 * the value is always nonzero,
 * and sometimes larger than usual.
 */

/**
 * The number of entries in the custom lookup table,
 * minus one.
 * 
 * If the default lookup table is used rather than a custom one,
 * this value is zero.
 */

/**
 * Various flags that affect the format of the compressed data and the decompression process.
 */

/**
 * Flags for the decompressor,
 * as stored in the decompressor-specific parameters.
 */
type Dcmp2_HeaderParameters_Flags struct {
	Reserved uint64
	Tagged bool
	HasCustomLookupTable bool
	_io *kaitai.Stream
	_root *Dcmp2
	_parent *Dcmp2_HeaderParameters
	_f_asInt bool
	asInt uint8
}
func NewDcmp2_HeaderParameters_Flags() *Dcmp2_HeaderParameters_Flags {
	return &Dcmp2_HeaderParameters_Flags{
	}
}

func (this *Dcmp2_HeaderParameters_Flags) Read(io *kaitai.Stream, parent *Dcmp2_HeaderParameters, root *Dcmp2) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp28, err := this._io.ReadBitsIntBe(6)
	if err != nil {
		return err
	}
	this.Reserved = tmp28
	tmp29, err := this._io.ReadBitsIntBe(1)
	if err != nil {
		return err
	}
	this.Tagged = tmp29 != 0
	tmp30, err := this._io.ReadBitsIntBe(1)
	if err != nil {
		return err
	}
	this.HasCustomLookupTable = tmp30 != 0
	return err
}

/**
 * The flags as a packed integer,
 * as they are stored in the data.
 */
func (this *Dcmp2_HeaderParameters_Flags) AsInt() (v uint8, err error) {
	if (this._f_asInt) {
		return this.asInt, nil
	}
	_pos, err := this._io.Pos()
	if err != nil {
		return 0, err
	}
	_, err = this._io.Seek(int64(0), io.SeekStart)
	if err != nil {
		return 0, err
	}
	tmp31, err := this._io.ReadU1()
	if err != nil {
		return 0, err
	}
	this.asInt = tmp31
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return 0, err
	}
	this._f_asInt = true
	this._f_asInt = true
	return this.asInt, nil
}

/**
 * These flags have no known usage or meaning and should always be zero.
 */

/**
 * Whether the "tagged" variant of this compression format should be used,
 * rather than the default "untagged" variant.
 */

/**
 * Whether a custom lookup table is included before the compressed data,
 * which should be used instead of the default hardcoded lookup table.
 */

/**
 * Compressed data in the "untagged" variant of the format.
 */
type Dcmp2_UntaggedData struct {
	TableReferences []uint8
	_io *kaitai.Stream
	_root *Dcmp2
	_parent *Dcmp2
}
func NewDcmp2_UntaggedData() *Dcmp2_UntaggedData {
	return &Dcmp2_UntaggedData{
	}
}

func (this *Dcmp2_UntaggedData) Read(io *kaitai.Stream, parent *Dcmp2, root *Dcmp2) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 1;; i++ {
		tmp32, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp32 {
			break
		}
		tmp33, err := this._io.ReadU1()
		if err != nil {
			return err
		}
		this.TableReferences = append(this.TableReferences, tmp33)
	}
	return err
}

/**
 * References into the lookup table.
 * Each reference is an integer that is expanded to two bytes by looking it up in the table.
 */

/**
 * Compressed data in the "tagged" variant of the format.
 */
type Dcmp2_TaggedData struct {
	Chunks []*Dcmp2_TaggedData_Chunk
	_io *kaitai.Stream
	_root *Dcmp2
	_parent *Dcmp2
}
func NewDcmp2_TaggedData() *Dcmp2_TaggedData {
	return &Dcmp2_TaggedData{
	}
}

func (this *Dcmp2_TaggedData) Read(io *kaitai.Stream, parent *Dcmp2, root *Dcmp2) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 1;; i++ {
		tmp34, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp34 {
			break
		}
		tmp35 := NewDcmp2_TaggedData_Chunk()
		err = tmp35.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Chunks = append(this.Chunks, tmp35)
	}
	return err
}

/**
 * The tagged chunks that make up the compressed data.
 */

/**
 * A single tagged chunk of compressed data.
 * 
 * Each chunk expands to 16 bytes of decompressed data.
 * In compressed form,
 * the chunks have a variable length
 * (between 9 and 17 bytes)
 * depending on the value of the tag byte.
 */
type Dcmp2_TaggedData_Chunk struct {
	Tag []bool
	Units []interface{}
	_io *kaitai.Stream
	_root *Dcmp2
	_parent *Dcmp2_TaggedData
}
func NewDcmp2_TaggedData_Chunk() *Dcmp2_TaggedData_Chunk {
	return &Dcmp2_TaggedData_Chunk{
	}
}

func (this *Dcmp2_TaggedData_Chunk) Read(io *kaitai.Stream, parent *Dcmp2_TaggedData, root *Dcmp2) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 0; i < int(8); i++ {
		_ = i
		tmp36, err := this._io.ReadBitsIntBe(1)
		if err != nil {
			return err
		}
		this.Tag = append(this.Tag, tmp36 != 0)
	}
	this._io.AlignToByte()
	for i := 1;; i++ {
		switch (this.Tag[i]) {
		case true:
			tmp37, err := this._io.ReadU1()
			if err != nil {
				return err
			}
			_it := tmp37
			this.Units = append(this.Units, _it)
		default:
			var tmp38 int8;
			if (this.Tag[i]) {
				tmp38 = 1
			} else {
				tmp38 = 2
			}
			tmp39, err := this._io.ReadBytes(int(tmp38))
			if err != nil {
				return err
			}
			tmp39 = tmp39
			_it := tmp39
			this._raw_Units = append(this._raw_Units, _it)
		}
		tmp40, err := this._io.EOF()
		if err != nil {
			return err
		}
		if  ((i >= 7) || (tmp40))  {
			break
		}
	}
	return err
}

/**
 * The bits of the tag byte control the format and meaning of the 8 compressed data units that follow the tag byte.
 */

/**
 * The compressed data units in this chunk.
 * 
 * The format and meaning of each unit is controlled by the bit in the tag byte with the same index.
 * If the bit is 0 (false),
 * the unit is a pair of bytes,
 * which are literally copied to the decompressed data.
 * If the bit is 1 (true),
 * the unit is a reference into the lookup table,
 * an integer which is expanded to two bytes by looking it up in the table.
 */