<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://moddingwiki.shikadi.net/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=QuirkyM</id>
	<title>ModdingWiki - User contributions [en-gb]</title>
	<link rel="self" type="application/atom+xml" href="https://moddingwiki.shikadi.net/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=QuirkyM"/>
	<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/wiki/Special:Contributions/QuirkyM"/>
	<updated>2026-05-14T05:48:31Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.11</generator>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Keen_4-6_Tileinfo_Format&amp;diff=11053</id>
		<title>Keen 4-6 Tileinfo Format</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Keen_4-6_Tileinfo_Format&amp;diff=11053"/>
		<updated>2023-05-27T18:01:03Z</updated>

		<summary type="html">&lt;p&gt;QuirkyM: Corrected order of foreground planes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is the tile info segment formats for Keen 4-6, Keen Dreams and a number of other ID Software and Apogee games.&lt;br /&gt;
&lt;br /&gt;
The tileinfo segment is stored in the executable and controls how everything interacts with tiles. In theory it is actually TWO segments, the unmasked and masked tileinfo. Each tileinfo is made up of a number of planes of data, with one byte per tile.&lt;br /&gt;
&lt;br /&gt;
Note [[TED5]] users, sprite &#039;icons&#039; are also counted as tiles, and can, with hacking, be placed into levels like normal tiles.&lt;br /&gt;
&lt;br /&gt;
=== Format ===&lt;br /&gt;
&lt;br /&gt;
 UNMASKED: ANIMATION PLANE&lt;br /&gt;
 UNMASKED: NEXT TILE PLANE&lt;br /&gt;
 MASKED: TOP PLANE&lt;br /&gt;
 MASKED: RIGHT PLANE&lt;br /&gt;
 MASKED: BOTTOM PLANE&lt;br /&gt;
 MASKED: LEFT PLANE&lt;br /&gt;
 MASKED: NEXT TILE PLANE&lt;br /&gt;
 MASKED: PROPERTIES PLANE&lt;br /&gt;
 MASKED: ANIMATION PLANE&lt;br /&gt;
&lt;br /&gt;
Thus as you can see there are two main parts to the tileinfo, a 2-plane unmasked segment and a 7 plane masked segment. The total tileinfo size is thus [2 * Unm] + [7 * Msk] bytes in size. For example, Keen 4 with 1296 and 2916 tiles respectively, we get 2592 + 20412 = 23004 bytes.&lt;br /&gt;
&lt;br /&gt;
Known tileinfo offsets are:&lt;br /&gt;
&lt;br /&gt;
 Keen 4:			$249C2	23004&lt;br /&gt;
 Keen 5:			$25B22	23688&lt;br /&gt;
 Keen 6:			$25212	23904&lt;br /&gt;
 Keen Dreams:		$1FC46	11322&lt;br /&gt;
&lt;br /&gt;
=== Planes (&#039;Flags&#039;): ===&lt;br /&gt;
&lt;br /&gt;
Each plane is simply a collection of each tile&#039;s value, each value taking up one byte of space. Thus in Keen 1, unmasked tile 0&#039;s animation and next tile values are stored at 0 and 1296 in the segment.&lt;br /&gt;
&lt;br /&gt;
==== Animation plane ====&lt;br /&gt;
&lt;br /&gt;
How long in game ticks before a tile animates. 0 is no animation. Maximum value is 255 ticks.&lt;br /&gt;
&lt;br /&gt;
==== Next tile plane ====&lt;br /&gt;
&lt;br /&gt;
Which tile, RELATIVE TO THIS TILE the tile will animate to. For non-animating tiles, zero. (Same tile!) For tiles like switches that animate when &#039;pressed&#039; this has a value, but no animation plane value. (I.e wait until pressed)&lt;br /&gt;
&lt;br /&gt;
This has values between +128 to -127 (A tile can animate to one less than it.) but should NOT animate to one not in the tileset!&lt;br /&gt;
&lt;br /&gt;
==== Left and right planes ====&lt;br /&gt;
&lt;br /&gt;
Whether Keen can walk into the tile from left or right (Actually pushes Keen out of the tile in that direction if set.) Values either 0 or 1 for &#039;off&#039; and &#039;on&#039;&lt;br /&gt;
&lt;br /&gt;
==== Top plane ====&lt;br /&gt;
&lt;br /&gt;
Top slope, stand-on or fall through. Values mainly between $00-$11:&lt;br /&gt;
&lt;br /&gt;
 0	Fall through		1	Flat&lt;br /&gt;
 2	Top -&amp;gt; Middle		3	Middle -&amp;gt; bottom&lt;br /&gt;
 4	Top -&amp;gt; bottom		5	Middle -&amp;gt; top&lt;br /&gt;
 6	Bottom -&amp;gt; middle	7	Bottom -&amp;gt; top&lt;br /&gt;
 8	Unused			9	Deadly, can&#039;t land on in God mode&lt;br /&gt;
&lt;br /&gt;
 SPECIAL VALUES:&lt;br /&gt;
 17	Flat with pole		33	Keen 6 giant switch on&lt;br /&gt;
 41	Keen 6 giant switch off	57	Keen 5 fuse&lt;br /&gt;
&lt;br /&gt;
==== Bottom plane ====&lt;br /&gt;
&lt;br /&gt;
Bottom slope, hit-head or fall through. Values mainly between 0-11:&lt;br /&gt;
&lt;br /&gt;
 0	Jump through		1	Flat bottom&lt;br /&gt;
 2	Bottom-&amp;gt; Middle		3	Middle -&amp;gt; top&lt;br /&gt;
 4	Bottom -&amp;gt; top		5	Middle -&amp;gt; bottom&lt;br /&gt;
 6	Top -&amp;gt; middle		7	Top -&amp;gt; bottom&lt;br /&gt;
&lt;br /&gt;
 SPECIAL VALUES:&lt;br /&gt;
 17	Pole going through	33	Keen 6 giant switch off&lt;br /&gt;
&lt;br /&gt;
==== Properties plane ====&lt;br /&gt;
&lt;br /&gt;
What the tile *does* to the player, kill, points, etc. Different for each game and can be complex.  Values are 0-255, with &#039;front&#039; tiles being +128 (That is a pole tile is 1, but a &#039;front&#039; pole is 129) Thus no game property can be above 127.&lt;br /&gt;
&lt;br /&gt;
 Value	Property		Games&lt;br /&gt;
 0	Nothing			All&lt;br /&gt;
 1	Pole			All&lt;br /&gt;
 2	Door			All (Also Miragia entrance in Keen 4)&lt;br /&gt;
 3	Kills			All&lt;br /&gt;
 4	100 for 1UP		Keen 4-6&lt;br /&gt;
 5	Goplat switch off	Keen 4, 5&lt;br /&gt;
 6	Goplat switch on	Keen 4, 5&lt;br /&gt;
 7	Red gem holder		Keen 4-6&lt;br /&gt;
 8	Yellow gem holder	Keen 4-6&lt;br /&gt;
 9	Blue gem holder		Keen 4-6&lt;br /&gt;
 10	Green gem holder	Keen 4-6&lt;br /&gt;
 11      Enter water from top	Keen 4&lt;br /&gt;
 12      Enter water from right	Keen 4&lt;br /&gt;
 13      Enter water from bottom Keen 4&lt;br /&gt;
 14      Enter water from left	Keen 4&lt;br /&gt;
 15	Bridge switch		Keen 4, 5&lt;br /&gt;
 16	Moon floor tile		Keen 4&lt;br /&gt;
 17	Sprite path arrow	Keen 5,6, Biomenace 1-3, Dave 3-4&lt;br /&gt;
 18	Bridge			Keen 5, 6&lt;br /&gt;
 19	Active zapper top	Keen 6&lt;br /&gt;
 20	Teleport entrance	Keen 5, 6&lt;br /&gt;
 21 	100			All&lt;br /&gt;
 22	200			All&lt;br /&gt;
 23	500			All&lt;br /&gt;
 24	1000			All&lt;br /&gt;
 25	2000			All&lt;br /&gt;
 26	5000			All&lt;br /&gt;
 27	1UP			All&lt;br /&gt;
 28	Stunner	, flowerpot	Keen 4-6, dreams&lt;br /&gt;
 29 	Unused			All&lt;br /&gt;
 30	Inactive zapper		Keen 6&lt;br /&gt;
 31	Ampton switch		Keen 5&lt;br /&gt;
 32	Keycard door		Keen 5&lt;br /&gt;
 33	Left map elevator	Keen 5&lt;br /&gt;
 34	Right map elevator	Keen 5 &lt;br /&gt;
&lt;br /&gt;
=== Utilities ===&lt;br /&gt;
&lt;br /&gt;
ck456tli can edit the tile properties of [[Commander Keen 4-6]] if graphics have been extracted. It also comes with extracted tileinfo files.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- All the games that use this file format --&amp;gt;&lt;br /&gt;
[[Category:Bio Menace]]&lt;br /&gt;
[[Category:Catacomb 3-D]]&lt;br /&gt;
[[Category:Commander Keen 4-6]]&lt;/div&gt;</summary>
		<author><name>QuirkyM</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=EGA_Palette&amp;diff=9889</id>
		<title>EGA Palette</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=EGA_Palette&amp;diff=9889"/>
		<updated>2021-07-06T21:35:23Z</updated>

		<summary type="html">&lt;p&gt;QuirkyM: Added an image showing the full 64-colour EGA gamut with corresponding hex values to make editing EGA palette files easier.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Palette Infobox&lt;br /&gt;
 | Hardware = EGA&lt;br /&gt;
 | Depth = 6-bit&lt;br /&gt;
 | Count = 16&lt;br /&gt;
&amp;lt;!-- Only list games that have 16-byte palette files --&amp;gt;&lt;br /&gt;
 | Games = &lt;br /&gt;
   {{Game|Monster Bash}}&lt;br /&gt;
   {{Game|Scubaventure}}&lt;br /&gt;
}}&lt;br /&gt;
While the EGA can only display up to 16 colours at a time, those 16 can be chosen from a selection of 64 possible colours.  Effectively this allows each of the red, green and blue channels to be independently set at four different levels (off, low, medium and high.)&lt;br /&gt;
&lt;br /&gt;
While it has always been possible to change the EGA palette in high resolution graphics mode, very few games ever did. Some notable exceptions include [[Corruption]], [[Fish]], [[SimAnt]], and [[SimFarm]]. [[Rambo III]] was able to change the palette in low resolution with a trick that requires a multi-scan monitor. [[Duke Nukem II]] is notable as it is an EGA game which changed the [[VGA Palette]] instead.&lt;br /&gt;
&lt;br /&gt;
== Default Palette ==&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;border-style: none; text-align:center; hspace=10px; float:right; margin: 1em;&amp;quot; border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
! colspan=&amp;quot;5&amp;quot; | Default EGA 16-Color Palette&amp;lt;br/&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Color !! Name !! RGB !! Binary !! Decimal&lt;br /&gt;
|- style=&amp;quot;color: white; background-color: #000000&amp;quot;&lt;br /&gt;
|| 0 || black || #000000 || 000000 || 0&lt;br /&gt;
|- style=&amp;quot;color: white; background-color: #0000AA&amp;quot;&lt;br /&gt;
|| 1 || blue || #0000AA || 000001 || 1&lt;br /&gt;
|- style=&amp;quot;color: white; background-color: #00AA00&amp;quot;&lt;br /&gt;
|| 2 || green || #00AA00 || 000010 || 2&lt;br /&gt;
|- style=&amp;quot;color: white; background-color: #00AAAA&amp;quot;&lt;br /&gt;
|| 3 || cyan || #00AAAA || 000011 || 3&lt;br /&gt;
|- style=&amp;quot;color: white; background-color: #AA0000&amp;quot;&lt;br /&gt;
|| 4 || red || #AA0000 || 000100 || 4&lt;br /&gt;
|- style=&amp;quot;color: white; background-color: #AA00AA&amp;quot;&lt;br /&gt;
|| 5 || magenta || #AA00AA || 000101 || 5&lt;br /&gt;
|- style=&amp;quot;color: white; background-color: #AA5500&amp;quot;&lt;br /&gt;
|| 6 || yellow / brown || #AA5500 || 010100 || 20&lt;br /&gt;
|- style=&amp;quot;color: black; background-color: #AAAAAA&amp;quot;&lt;br /&gt;
|| 7 || white / light gray || #AAAAAA || 000111 || 7&lt;br /&gt;
|- style=&amp;quot;color: white; background-color: #555555&amp;quot;&lt;br /&gt;
|| 8 || dark gray / bright black || (#555555 || 111000 || 56&lt;br /&gt;
|- style=&amp;quot;color: white; background-color: #5555FF&amp;quot;&lt;br /&gt;
|| 9 || bright blue || #5555FF || 111001 || 57&lt;br /&gt;
|- style=&amp;quot;color: black; background-color: #55FF55&amp;quot;&lt;br /&gt;
|| 10 || bright green || #55FF55 || 111010 || 58&lt;br /&gt;
|- style=&amp;quot;color: black; background-color: #55FFFF&amp;quot;&lt;br /&gt;
|| 11 || bright cyan || #55FFFF || 111011 || 59&lt;br /&gt;
|- style=&amp;quot;color: black; background-color: #FF5555&amp;quot;&lt;br /&gt;
|| 12 || bright red || #FF5555 || 111100 || 60&lt;br /&gt;
|- style=&amp;quot;color: black; background-color: #FF55FF&amp;quot;&lt;br /&gt;
|| 13 || bright magenta || #FF55FF || 111101 || 61&lt;br /&gt;
|- style=&amp;quot;color: black; background-color: #FFFF55&amp;quot;&lt;br /&gt;
|| 14 || bright yellow || #FFFF55 || 111110 || 62&lt;br /&gt;
|- style=&amp;quot;color: black; background-color: #FFFFFF&amp;quot;&lt;br /&gt;
|| 15 || bright white || #FFFFFF || 111111 || 63&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The default EGA palette found in most DOS games is shown on the right.  This is set up to be backwards-compatible with the 16 colours available in text mode on the original CGA.  Notice that colour entry #6 (brown) doesn&#039;t fit in sequence with the other entries.  This is because the CGA had additional circuitry to make this colour appear &amp;quot;more visually pleasing.&amp;quot;  The introduction of the EGA palette meant this adjustment no longer required additional hardware.  Setting palette entry #6 to the in-sequence value of 6 (&amp;lt;span style=&amp;quot;background-color: #AAAA00;&amp;quot;&amp;gt;#AAAA00&amp;lt;/span&amp;gt;) instead of 20 reveals the &amp;quot;dark yellow&amp;quot; colour found in cheaper clone CGA monitors lacking the additional circuitry.&lt;br /&gt;
&lt;br /&gt;
== The default format ==&lt;br /&gt;
&lt;br /&gt;
As there are 16 colours to change, it is easiest to write these values out as 16 bytes.  In this case, the palette file is only 16 bytes long.&lt;br /&gt;
&lt;br /&gt;
== Conversion ==&lt;br /&gt;
&lt;br /&gt;
To convert from an EGA palette to RGB values, each 2-bit EGA red, green or blue value should be multiplied by 85, to produce the values 0, 85, 170 and 255.&lt;br /&gt;
&lt;br /&gt;
To obtain the 2-bit value, the bits must be extracted as shown in the following table (where -H is the high bit and -L is the low bit, for each colour.)&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit&lt;br /&gt;
| 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0&lt;br /&gt;
|-&lt;br /&gt;
! Purpose&lt;br /&gt;
| Unused || Unused || Red-L || Green-L || Blue-L|| Red-H || Green-H || Blue-H&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Or as a formula:&lt;br /&gt;
&lt;br /&gt;
 red   = 85 * (((ega &amp;gt;&amp;gt; 1) &amp;amp; 2) | (ega &amp;gt;&amp;gt; 5) &amp;amp; 1)&lt;br /&gt;
 green = 85 * (( ega       &amp;amp; 2) | (ega &amp;gt;&amp;gt; 4) &amp;amp; 1)&lt;br /&gt;
 blue  = 85 * (((ega &amp;lt;&amp;lt; 1) &amp;amp; 2) | (ega &amp;gt;&amp;gt; 3) &amp;amp; 1)&lt;br /&gt;
&lt;br /&gt;
[[File:EGA_Table_Hex.svg|thumb|The full 64-colour EGA gamut.]]&lt;br /&gt;
&lt;br /&gt;
== Detection ==&lt;br /&gt;
&lt;br /&gt;
There are not many EGA palettes in existence on account of so few games bothering to change the palette, and any palette is so short detection is difficult.  Typically the first entry will be black (0x00) and the 16th white (0x3F) however even this is not guaranteed.  Any value larger than 0x3F is invalid and can be used to identify files that are definitely not palettes.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* [[wp:Enhanced Graphics Adapter|EGA article]] on Wikipedia&lt;br /&gt;
* [[CGA Palette]]&lt;br /&gt;
* [[VGA Palette]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Articles]]&lt;/div&gt;</summary>
		<author><name>QuirkyM</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=File:EGA_Table_Hex.svg&amp;diff=9888</id>
		<title>File:EGA Table Hex.svg</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=File:EGA_Table_Hex.svg&amp;diff=9888"/>
		<updated>2021-07-06T21:26:18Z</updated>

		<summary type="html">&lt;p&gt;QuirkyM: A list of the 64 possible EGA colours. Taken from https://commons.wikimedia.org/wiki/File:EGA_Table.svg but with the indices converted to hexadecimal.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
A list of the 64 possible EGA colours. Taken from https://commons.wikimedia.org/wiki/File:EGA_Table.svg but with the indices converted to hexadecimal.&lt;/div&gt;</summary>
		<author><name>QuirkyM</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Monster_Bash_Level_Format&amp;diff=9885</id>
		<title>Monster Bash Level Format</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Monster_Bash_Level_Format&amp;diff=9885"/>
		<updated>2021-07-03T19:54:13Z</updated>

		<summary type="html">&lt;p&gt;QuirkyM: Added more sprite dependencies, in particular for enemies from parts 2 and 3.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NeedMoreInfo}}&lt;br /&gt;
{{Map Infobox&lt;br /&gt;
 | Type = 2D tile-based&lt;br /&gt;
 | Layers = 3&lt;br /&gt;
 | Tile size = 16&amp;amp;times;16&lt;br /&gt;
 | Viewport = 320&amp;amp;times;200&lt;br /&gt;
 | Games = &lt;br /&gt;
   {{Game|Monster Bash}}&lt;br /&gt;
   {{Game|Scubaventure}}&lt;br /&gt;
}}&lt;br /&gt;
[[Monster Bash]] stores its levels across a number of different files inside &amp;lt;tt&amp;gt;[[DAT Format (Monster Bash)|BASHx.DAT]]&amp;lt;/tt&amp;gt;.  Annoyingly, many of the files have the same filename and only differ in the &#039;filetype code&#039; also stored in the .DAT file.&lt;br /&gt;
&lt;br /&gt;
== Map description file ==&lt;br /&gt;
&lt;br /&gt;
Each map contains a file (of .DAT filetype code #0) which contains the filenames of the other associated files for the level.  The file contains a number of fixed-length strings of 31 bytes each, corresponding to a filename in the main .DAT file.  Note that the DAT file will have multiple files matching the names used here, so the DAT filetype codes (or fake filename extensions) are used to differentiate between particular files.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data type !! Description !! DAT filetype code/extension&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] bgtiles[31] || Filename of the background tileset || 3 (.tbg)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] fgtiles[31] || Filename of the foreground tileset || 4 (.tfg)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] bonustiles[31] || Filename of the bonus tileset || 5 (.tbn)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] sprites[31] || Name of the sprite list || 6 (.sgl)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] palette[31] || Filename of the palette file(?) || 14 (.pal)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] sounds[31] || Filename of the PC speaker sound effects || 8 (.snd)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] unknown[31] || Unused slot? (contains &amp;quot;UNNAMED&amp;quot;) || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tilesets ==&lt;br /&gt;
&lt;br /&gt;
Each map file uses three tilesets - one for the background and two for the foreground (called &#039;&#039;bonus&#039;&#039; and &#039;&#039;fg&#039;&#039; below.)  See [[DAT Format (Monster Bash)]] for details on the file types and image format.  The animation frames for each sprite are stored in separate files (one file per sprite.)&lt;br /&gt;
&lt;br /&gt;
== Background layer ==&lt;br /&gt;
&lt;br /&gt;
The background layer is a list of 16-bit indices into the background tileset.  It is stored in a file of .DAT filetype code #1.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT8]] mapWidth || Width of map, in tiles&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT8]] mapHeight || Height of map, in tiles&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] mapWidthBytes || Width of map, in bytes (divide by two to get width in tiles)&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] pixelWidth || Width of map, in pixels (divide by 16 to get width in tiles)&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] pixelHeight || Height of map, in pixels (divide by 16 to get height in tiles)&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] tiles[mapWidth * mapHeight] || Tile codes, one per tile&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The lower nine bits of each tilecode are indices into the background tileset (so if &amp;lt;code&amp;gt;tilecode &amp;amp; 0x1FF&amp;lt;/code&amp;gt; was 2, the third tile from the background tileset would be drawn at that location.)&lt;br /&gt;
&lt;br /&gt;
The upper seven bits control the tile&#039;s behaviour:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Binary (Decimal) !! Mask !! Purpose when bit is 1&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0000001  (1) || 0x0200 || Can&#039;t walk right into tile&lt;br /&gt;
|-&lt;br /&gt;
| 2 || 0000010  (2) || 0x0400 || Can&#039;t walk left into tile&lt;br /&gt;
|-&lt;br /&gt;
| 3 || 0000100  (4) || 0x0800 || Can&#039;t fall down through tile (i.e. ground tiles you stand on)&lt;br /&gt;
|-&lt;br /&gt;
| 4 || 0001000  (8) || 0x1000 || Can&#039;t jump up through tile&lt;br /&gt;
|-&lt;br /&gt;
| 5 || 0010000 (16) || 0x2000 || Foreground tile contains an interactive item (point, spear, zombie spawning grave, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || 0100000 (32) || 0x4000 || Slanted tile (direction controlled by foreground tile)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || 1000000 (64) || 0x8000 || Climbable (ladder)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Foreground layer ==&lt;br /&gt;
&lt;br /&gt;
The foreground layer is a list of 8-bit indices into the two masked tilesets.  It is stored in a file of .DAT filetype code #2 (.mfg).&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] mapWidth || Width of map, in tiles&lt;br /&gt;
|-&lt;br /&gt;
| [[BYTE]] tiles[mapWidth * mapHeight] || Tile codes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The height of the layer is the same as for the background layer.  If the background layer is unavailable, it can be approximated by dividing the file&#039;s size by the map width, but as some files have an extra 0x00 byte at the end this method requires a little more effort to work correctly.&lt;br /&gt;
&lt;br /&gt;
Each byte represents an index to the tileset.  Values with the high bit unset (less than 128) are indices into the &#039;&#039;bonus&#039;&#039; tileset, and values with the high bit set (&amp;gt;= 128) are indices into the &#039;&#039;fg&#039;&#039; tileset (so a map code of 129 refers to the second tile in the &#039;&#039;fg&#039;&#039; tileset.)&lt;br /&gt;
&lt;br /&gt;
Foreground tiles are drawn at the very front (obscuring background tiles and sprites), while the bonus tiles are drawn behind sprites, only obscuring the background tiles.&lt;br /&gt;
&lt;br /&gt;
== Sprite layer ==&lt;br /&gt;
&lt;br /&gt;
The sprite layer is a list of sprite filenames and their coordinates.  It is stored in a file of .DAT filetype code #7 (.msp), while the sprites themselves are .DAT filetype code #64 (.spr).&lt;br /&gt;
&lt;br /&gt;
The sprite layer begins with an unknown [[UINT16LE]] value which always seems to be 0xFFFE, followed by the below structure repeated until EOF.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT32LE]] len || Length of this structure, including this field&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT32LE]] unknown || Always 0x00000000&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT32LE]] unknown || Unused? Changing seems to have no effect&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] unknown || Always 0x0000&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT32LE]] x || X-offset, in pixels&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT32LE]] y || Y-offset, in pixels&lt;br /&gt;
|-&lt;br /&gt;
| [[BYTE]] padding[22] || ?&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] filename[len-44] || Sprite filename, with two terminating nulls&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Sprite list (.sgl) ==&lt;br /&gt;
&lt;br /&gt;
When loading a level, the engine needs to preload all sprites that will be used in the level.  Each sprite must be explicitly listed (even if it&#039;s listed in the sprite layer) as well as other associated sprites, such as the knife sprite thrown by the knife-thrower.  The game will misbehave if it attempts to draw a sprite that has not been loaded.&lt;br /&gt;
&lt;br /&gt;
The names of these sprites are listed in the Sprite List (.sgl) file.  This file contains one ASCII filename (no extension) padded with 0x00 to 31 bytes long, one after the other until EOF.&lt;br /&gt;
&lt;br /&gt;
The official files store the sprite names in alphabetical order, however this is not required.&lt;br /&gt;
&lt;br /&gt;
This list will always include some names, like those belonging to the player sprite and the health gauge, however others only need to be included if related sprites exist in the level.  No need to load the zombie head sprites if there are no zombies in the level, for instance (doing so won&#039;t cause any harm, but may use up too much memory preventing the level from loading.)&lt;br /&gt;
&lt;br /&gt;
The following table lists the sprites that should appear in this list, based on the sprites appearing in the sprite layer.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Sprite name (.msp) !! Additional required sprites (.sgl)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;(Mandatory)&#039;&#039; || arrows blank border border2 cat chunk dog flag float100? guage heart leaf rock? {{TODO|Maybe only if rock powerup is used?}} score splat white&lt;br /&gt;
|-&lt;br /&gt;
| main_l&amp;lt;br/&amp;gt;main_r || break_screen crack crawl_left crawl_right dirt_l dirt_r main_die main_exit main_hat_l main_hat_r main_l main_meter main_r main_stars&lt;br /&gt;
|-&lt;br /&gt;
| axe || axe&lt;br /&gt;
|-&lt;br /&gt;
| bat || bat_blob&lt;br /&gt;
|-&lt;br /&gt;
| bazooka || bazooka_shot&lt;br /&gt;
|-&lt;br /&gt;
| beetle_rest || beetle&lt;br /&gt;
|-&lt;br /&gt;
| brain_l&amp;lt;br/&amp;gt;brain_r || brain_l brain_r brain_zap&lt;br /&gt;
|-&lt;br /&gt;
| cloud || lightn&lt;br /&gt;
|-&lt;br /&gt;
| cyclops_l&amp;lt;br/&amp;gt;cyclops_r || cyclops_l cyclops_r cyc_horn_l cyc_horn_r {{TODO|Confirm these last two are needed}}&lt;br /&gt;
|-&lt;br /&gt;
| devil_l&amp;lt;br/&amp;gt;devil_r || devil_l devil_r pfork_l pfork_r&lt;br /&gt;
|-&lt;br /&gt;
| eye_l&amp;lt;br/&amp;gt;eye_r || eye_l eye_r seye_l seye_r&lt;br /&gt;
|-&lt;br /&gt;
| fish_leap || fish_flounder&lt;br /&gt;
|-&lt;br /&gt;
| fly_l&amp;lt;br/&amp;gt;fly_r || fly_l fly_r fly_egg tsetse_l tsetse_r&lt;br /&gt;
|-&lt;br /&gt;
| gorgon_l&amp;lt;br/&amp;gt;gorgon_r || gorgon_l gorgon_r gorgon_zap main_stoned&lt;br /&gt;
|-&lt;br /&gt;
| guy_jump || guy_jump&lt;br /&gt;
|-&lt;br /&gt;
| hand_l&amp;lt;br/&amp;gt;hand_r || hand_l hand_r&lt;br /&gt;
|-&lt;br /&gt;
| hell_head || hell_head_pieces&lt;br /&gt;
|-&lt;br /&gt;
| horse || horse&lt;br /&gt;
|-&lt;br /&gt;
| iman_l&amp;lt;br/&amp;gt;iman_r || iman_l iman_r hat&lt;br /&gt;
|-&lt;br /&gt;
| knifee || knifee knife&lt;br /&gt;
|-&lt;br /&gt;
| knifee_ud || knifee_ud knife&lt;br /&gt;
|-&lt;br /&gt;
| mouse || mouse&lt;br /&gt;
|-&lt;br /&gt;
| nemesis || main_broom (plus all main_r dependent sprites)&lt;br /&gt;
|-&lt;br /&gt;
| phead_l&amp;lt;br/&amp;gt;phead_r || phead_l phead_r pumpkin&lt;br /&gt;
|-&lt;br /&gt;
| princess || bazooka bazooka_shot&lt;br /&gt;
|-&lt;br /&gt;
| score1up || score1up&lt;br /&gt;
|-&lt;br /&gt;
| skelet_l&amp;lt;br/&amp;gt;skelet_r || skelet_l sketet_r jaw_l jaw_r&lt;br /&gt;
|-&lt;br /&gt;
| snake || snake&lt;br /&gt;
|-&lt;br /&gt;
| swamp_l&amp;lt;br/&amp;gt;swamp_r&amp;lt;br/&amp;gt;swamp2_l&amp;lt;br/&amp;gt;swamp2_r || swamp_l swamp_r swamp2_l swamp2_r swamp_scum2_l swamp_scum2_r swamp_scum_l swamp_scum_r&lt;br /&gt;
|-&lt;br /&gt;
| teeth_l&amp;lt;br/&amp;gt;teeth_r || teeth_l teeth_r&lt;br /&gt;
|-&lt;br /&gt;
| tiger_l&amp;lt;br/&amp;gt;tiger_r || tiger_run_l tiger_run_r bomb explode&lt;br /&gt;
|-&lt;br /&gt;
| tman_bl&amp;lt;br/&amp;gt;tman_br || tman_bl tman_br pellet_h&lt;br /&gt;
|-&lt;br /&gt;
| tman_ld&amp;lt;br/&amp;gt;tman_lu || tman_ld tman_lu pellet_h&lt;br /&gt;
|-&lt;br /&gt;
| tman_rd&amp;lt;br/&amp;gt;tman_ru || tman_rd tman_ru pellet_h&lt;br /&gt;
|-&lt;br /&gt;
| tman_tl&amp;lt;br/&amp;gt;tman_tr || tman_tl tman_tr pellet_h&lt;br /&gt;
|-&lt;br /&gt;
| vulture || vulture vulture_l vulture_r&lt;br /&gt;
|-&lt;br /&gt;
| witch_l&amp;lt;br/&amp;gt;witch_r || witch_l witch_r witch_zap explode&lt;br /&gt;
|-&lt;br /&gt;
| witch_fly || witch_zap explode&lt;br /&gt;
|-&lt;br /&gt;
| zb_l&amp;lt;br/&amp;gt;zb_r || zb_l zb_r zbh_l zbh_r zhead zhead_r&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following table lists the sprites that should appear, based on tiles appearing in the foreground layer:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Map element !! Additional required sprites (.sgl)&lt;br /&gt;
|-&lt;br /&gt;
| collapsing walkway || plank plank_r&lt;br /&gt;
|-&lt;br /&gt;
| skull (point item) || skullw&lt;br /&gt;
|-&lt;br /&gt;
| dragon || drag_b drag_eye drag_fire drag_l smoke1&lt;br /&gt;
|-&lt;br /&gt;
| rocket (powerup) || msm explode&lt;br /&gt;
|-&lt;br /&gt;
| big rock (powerup) || grenade&lt;br /&gt;
|-&lt;br /&gt;
| fire shot (powerup) || grenade fire_bit?&lt;br /&gt;
|-&lt;br /&gt;
| lightbulb || glass&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
&lt;br /&gt;
This file format was reverse engineered by [[User:Malvineous|Malvineous]].  If you find this information helpful in a project you&#039;re working on, please give credit where credit is due.  (A link back to this wiki would be nice too!)&lt;/div&gt;</summary>
		<author><name>QuirkyM</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Monster_Bash_Level_Format&amp;diff=9884</id>
		<title>Monster Bash Level Format</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Monster_Bash_Level_Format&amp;diff=9884"/>
		<updated>2021-07-03T18:48:21Z</updated>

		<summary type="html">&lt;p&gt;QuirkyM: Added sprite requirements for certain tiles.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NeedMoreInfo}}&lt;br /&gt;
{{Map Infobox&lt;br /&gt;
 | Type = 2D tile-based&lt;br /&gt;
 | Layers = 3&lt;br /&gt;
 | Tile size = 16&amp;amp;times;16&lt;br /&gt;
 | Viewport = 320&amp;amp;times;200&lt;br /&gt;
 | Games = &lt;br /&gt;
   {{Game|Monster Bash}}&lt;br /&gt;
   {{Game|Scubaventure}}&lt;br /&gt;
}}&lt;br /&gt;
[[Monster Bash]] stores its levels across a number of different files inside &amp;lt;tt&amp;gt;[[DAT Format (Monster Bash)|BASHx.DAT]]&amp;lt;/tt&amp;gt;.  Annoyingly, many of the files have the same filename and only differ in the &#039;filetype code&#039; also stored in the .DAT file.&lt;br /&gt;
&lt;br /&gt;
== Map description file ==&lt;br /&gt;
&lt;br /&gt;
Each map contains a file (of .DAT filetype code #0) which contains the filenames of the other associated files for the level.  The file contains a number of fixed-length strings of 31 bytes each, corresponding to a filename in the main .DAT file.  Note that the DAT file will have multiple files matching the names used here, so the DAT filetype codes (or fake filename extensions) are used to differentiate between particular files.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data type !! Description !! DAT filetype code/extension&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] bgtiles[31] || Filename of the background tileset || 3 (.tbg)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] fgtiles[31] || Filename of the foreground tileset || 4 (.tfg)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] bonustiles[31] || Filename of the bonus tileset || 5 (.tbn)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] sprites[31] || Name of the sprite list || 6 (.sgl)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] palette[31] || Filename of the palette file(?) || 14 (.pal)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] sounds[31] || Filename of the PC speaker sound effects || 8 (.snd)&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] unknown[31] || Unused slot? (contains &amp;quot;UNNAMED&amp;quot;) || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tilesets ==&lt;br /&gt;
&lt;br /&gt;
Each map file uses three tilesets - one for the background and two for the foreground (called &#039;&#039;bonus&#039;&#039; and &#039;&#039;fg&#039;&#039; below.)  See [[DAT Format (Monster Bash)]] for details on the file types and image format.  The animation frames for each sprite are stored in separate files (one file per sprite.)&lt;br /&gt;
&lt;br /&gt;
== Background layer ==&lt;br /&gt;
&lt;br /&gt;
The background layer is a list of 16-bit indices into the background tileset.  It is stored in a file of .DAT filetype code #1.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT8]] mapWidth || Width of map, in tiles&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT8]] mapHeight || Height of map, in tiles&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] mapWidthBytes || Width of map, in bytes (divide by two to get width in tiles)&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] pixelWidth || Width of map, in pixels (divide by 16 to get width in tiles)&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] pixelHeight || Height of map, in pixels (divide by 16 to get height in tiles)&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] tiles[mapWidth * mapHeight] || Tile codes, one per tile&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The lower nine bits of each tilecode are indices into the background tileset (so if &amp;lt;code&amp;gt;tilecode &amp;amp; 0x1FF&amp;lt;/code&amp;gt; was 2, the third tile from the background tileset would be drawn at that location.)&lt;br /&gt;
&lt;br /&gt;
The upper seven bits control the tile&#039;s behaviour:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Binary (Decimal) !! Mask !! Purpose when bit is 1&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0000001  (1) || 0x0200 || Can&#039;t walk right into tile&lt;br /&gt;
|-&lt;br /&gt;
| 2 || 0000010  (2) || 0x0400 || Can&#039;t walk left into tile&lt;br /&gt;
|-&lt;br /&gt;
| 3 || 0000100  (4) || 0x0800 || Can&#039;t fall down through tile (i.e. ground tiles you stand on)&lt;br /&gt;
|-&lt;br /&gt;
| 4 || 0001000  (8) || 0x1000 || Can&#039;t jump up through tile&lt;br /&gt;
|-&lt;br /&gt;
| 5 || 0010000 (16) || 0x2000 || Foreground tile contains an interactive item (point, spear, zombie spawning grave, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || 0100000 (32) || 0x4000 || Slanted tile (direction controlled by foreground tile)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || 1000000 (64) || 0x8000 || Climbable (ladder)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Foreground layer ==&lt;br /&gt;
&lt;br /&gt;
The foreground layer is a list of 8-bit indices into the two masked tilesets.  It is stored in a file of .DAT filetype code #2 (.mfg).&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] mapWidth || Width of map, in tiles&lt;br /&gt;
|-&lt;br /&gt;
| [[BYTE]] tiles[mapWidth * mapHeight] || Tile codes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The height of the layer is the same as for the background layer.  If the background layer is unavailable, it can be approximated by dividing the file&#039;s size by the map width, but as some files have an extra 0x00 byte at the end this method requires a little more effort to work correctly.&lt;br /&gt;
&lt;br /&gt;
Each byte represents an index to the tileset.  Values with the high bit unset (less than 128) are indices into the &#039;&#039;bonus&#039;&#039; tileset, and values with the high bit set (&amp;gt;= 128) are indices into the &#039;&#039;fg&#039;&#039; tileset (so a map code of 129 refers to the second tile in the &#039;&#039;fg&#039;&#039; tileset.)&lt;br /&gt;
&lt;br /&gt;
Foreground tiles are drawn at the very front (obscuring background tiles and sprites), while the bonus tiles are drawn behind sprites, only obscuring the background tiles.&lt;br /&gt;
&lt;br /&gt;
== Sprite layer ==&lt;br /&gt;
&lt;br /&gt;
The sprite layer is a list of sprite filenames and their coordinates.  It is stored in a file of .DAT filetype code #7 (.msp), while the sprites themselves are .DAT filetype code #64 (.spr).&lt;br /&gt;
&lt;br /&gt;
The sprite layer begins with an unknown [[UINT16LE]] value which always seems to be 0xFFFE, followed by the below structure repeated until EOF.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT32LE]] len || Length of this structure, including this field&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT32LE]] unknown || Always 0x00000000&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT32LE]] unknown || Unused? Changing seems to have no effect&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT16LE]] unknown || Always 0x0000&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT32LE]] x || X-offset, in pixels&lt;br /&gt;
|-&lt;br /&gt;
| [[UINT32LE]] y || Y-offset, in pixels&lt;br /&gt;
|-&lt;br /&gt;
| [[BYTE]] padding[22] || ?&lt;br /&gt;
|-&lt;br /&gt;
| [[char]] filename[len-44] || Sprite filename, with two terminating nulls&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Sprite list (.sgl) ==&lt;br /&gt;
&lt;br /&gt;
When loading a level, the engine needs to preload all sprites that will be used in the level.  Each sprite must be explicitly listed (even if it&#039;s listed in the sprite layer) as well as other associated sprites, such as the knife sprite thrown by the knife-thrower.  The game will misbehave if it attempts to draw a sprite that has not been loaded.&lt;br /&gt;
&lt;br /&gt;
The names of these sprites are listed in the Sprite List (.sgl) file.  This file contains one ASCII filename (no extension) padded with 0x00 to 31 bytes long, one after the other until EOF.&lt;br /&gt;
&lt;br /&gt;
The official files store the sprite names in alphabetical order, however this is not required.&lt;br /&gt;
&lt;br /&gt;
This list will always include some names, like those belonging to the player sprite and the health gauge, however others only need to be included if related sprites exist in the level.  No need to load the zombie head sprites if there are no zombies in the level, for instance (doing so won&#039;t cause any harm, but may use up too much memory preventing the level from loading.)&lt;br /&gt;
&lt;br /&gt;
The following table lists the sprites that should appear in this list, based on the sprites appearing in the sprite layer.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Sprite name (.msp) !! Additional required sprites (.sgl)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;(Mandatory)&#039;&#039; || arrows blank border border2 cat chunk dog flag float100? guage heart leaf rock? {{TODO|Maybe only if rock powerup is used?}} score splat white&lt;br /&gt;
|-&lt;br /&gt;
| main_l&amp;lt;br/&amp;gt;main_r || break_screen crack crawl_left crawl_right dirt_l dirt_r main_die main_exit main_hat_l main_hat_r main_l main_meter main_r main_stars&lt;br /&gt;
|-&lt;br /&gt;
| axe || axe&lt;br /&gt;
|-&lt;br /&gt;
| cloud || lightn&lt;br /&gt;
|-&lt;br /&gt;
| cyclops_l&amp;lt;br/&amp;gt;cyclops_r || cyclops_l cyclops_r cyc_horn_l cyc_horn_r {{TODO|Confirm these last two are needed}}&lt;br /&gt;
|-&lt;br /&gt;
| devil_l&amp;lt;br/&amp;gt;devil_r || devil_l devil_r pfork_l pfork_r&lt;br /&gt;
|-&lt;br /&gt;
| guy_jump || guy_jump&lt;br /&gt;
|-&lt;br /&gt;
| hand_l&amp;lt;br/&amp;gt;hand_r || hand_l hand_r&lt;br /&gt;
|-&lt;br /&gt;
| horse || horse&lt;br /&gt;
|-&lt;br /&gt;
| iman_l&amp;lt;br/&amp;gt;iman_r || iman_l iman_r hat&lt;br /&gt;
|-&lt;br /&gt;
| knifee || knifee knife&lt;br /&gt;
|-&lt;br /&gt;
| knifee_ud || knifee_ud knife&lt;br /&gt;
|-&lt;br /&gt;
| mouse || mouse&lt;br /&gt;
|-&lt;br /&gt;
| nemesis || main_broom (plus all main_r dependent sprites)&lt;br /&gt;
|-&lt;br /&gt;
| score1up || score1up&lt;br /&gt;
|-&lt;br /&gt;
| skelet_l&amp;lt;br/&amp;gt;skelet_r || skelet_l sketet_r jaw_l jaw_r&lt;br /&gt;
|-&lt;br /&gt;
| snake || snake&lt;br /&gt;
|-&lt;br /&gt;
| swamp_l&amp;lt;br/&amp;gt;swamp_r&amp;lt;br/&amp;gt;swamp2_l&amp;lt;br/&amp;gt;swamp2_r || swamp_l swamp_r swamp2_l swamp2_r swamp_scum2_l swamp_scum2_r swamp_scum_l swamp_scum_r&lt;br /&gt;
|-&lt;br /&gt;
| teeth_l&amp;lt;br/&amp;gt;teeth_r || teeth_l teeth_r&lt;br /&gt;
|-&lt;br /&gt;
| tman_bl&amp;lt;br/&amp;gt;tman_br || tman_bl tman_br pellet_h&lt;br /&gt;
|-&lt;br /&gt;
| tman_ld&amp;lt;br/&amp;gt;tman_lu || tman_ld tman_lu pellet_h&lt;br /&gt;
|-&lt;br /&gt;
| tman_rd&amp;lt;br/&amp;gt;tman_ru || tman_rd tman_ru pellet_h&lt;br /&gt;
|-&lt;br /&gt;
| tman_tl&amp;lt;br/&amp;gt;tman_tr || tman_tl tman_tr pellet_h&lt;br /&gt;
|-&lt;br /&gt;
| vulture || vulture vulture_l vulture_r&lt;br /&gt;
|-&lt;br /&gt;
| zb_l&amp;lt;br/&amp;gt;zb_r || zb_l zb_r zbh_l zbh_r zhead zhead_r&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following table lists the sprites that should appear, based on tiles appearing in the foreground layer:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Map element !! Additional required sprites (.sgl)&lt;br /&gt;
|-&lt;br /&gt;
| collapsing walkway || plank plank_r&lt;br /&gt;
|-&lt;br /&gt;
| skull (point item) || skullw&lt;br /&gt;
|-&lt;br /&gt;
| dragon || drag_b drag_eye drag_fire drag_l smoke1&lt;br /&gt;
|-&lt;br /&gt;
| rocket (powerup) || msm explode&lt;br /&gt;
|-&lt;br /&gt;
| big rock (powerup) || grenade&lt;br /&gt;
|-&lt;br /&gt;
| fire shot (powerup) || grenade fire_bit?&lt;br /&gt;
|-&lt;br /&gt;
| lightbulb || glass&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
&lt;br /&gt;
This file format was reverse engineered by [[User:Malvineous|Malvineous]].  If you find this information helpful in a project you&#039;re working on, please give credit where credit is due.  (A link back to this wiki would be nice too!)&lt;/div&gt;</summary>
		<author><name>QuirkyM</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=8374</id>
		<title>Huffman Compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=8374"/>
		<updated>2019-03-01T17:04:50Z</updated>

		<summary type="html">&lt;p&gt;QuirkyM: Changed a couple lines in Haskell code to prevent a potential error.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Compression Infobox&lt;br /&gt;
 | Type = Stream&lt;br /&gt;
 | UnitSize = 1-byte in, 1-bit out&lt;br /&gt;
 | Games =&lt;br /&gt;
   {{Game|The Blues Brothers}}&lt;br /&gt;
   {{Game|Catacomb 3-D}}&lt;br /&gt;
   {{Game|Commander Keen Dreams}}&lt;br /&gt;
   {{Game|Dangerous Dave 2}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[Huffman Compression]] is a compression algorithm used in many classic games. It is about as efficient as LZW or RLE compression, with many games using the three formats simultaneously.&lt;br /&gt;
&lt;br /&gt;
Huffman compression involves changing how various characters are stored. Normally all characters in a given segment of data are equal and take an equal amount of space to store. However by making more common characters take up less space while allowing less commonly used characters to take up more the overall size of a segment of data can be reduced. Any Huffman compressed data will thus be associated with a dictionary file (internal or external) used to decompress it. This page will go through each aspect of Huffman compression in a stepwise manner before presenting some examples of usage and source code.&lt;br /&gt;
&lt;br /&gt;
==Frequency tables==&lt;br /&gt;
&lt;br /&gt;
To illustrate the various aspects of Huffman compression the example text &amp;quot;She sells seashells by the sea shore.&amp;quot; will be Huffman compressed and the processes and outputs shown in various sections on this page.&lt;br /&gt;
&lt;br /&gt;
In order to compress data using Huffman compression the compressor must first build a &#039;frequency table&#039; of all the elements it wishes to compress. In most cases this will be the 256 values a single byte can take, though it need not be limited to this. (Due to the binary nature of the compression method, sets of elements that match powers of 2 are both easiest and most efficient to compress.) The data is scanned and each occurrence of a given value. Taking the letters in our example sentence we can construct the following frequency table:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 Char   Freq&lt;br /&gt;
 &#039;s&#039;      7&lt;br /&gt;
 &#039;e&#039;      7&lt;br /&gt;
 &#039; &#039;      6&lt;br /&gt;
 &#039;h&#039;      4&lt;br /&gt;
 &#039;l&#039;      4&lt;br /&gt;
 &#039;a&#039;      2&lt;br /&gt;
 &#039;S&#039;      1&lt;br /&gt;
 &#039;b&#039;      1&lt;br /&gt;
 &#039;o&#039;      1&lt;br /&gt;
 &#039;r&#039;      1&lt;br /&gt;
 &#039;t&#039;      1&lt;br /&gt;
 &#039;y&#039;      1&lt;br /&gt;
 &#039;.&#039;      1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==The Binary Tree==&lt;br /&gt;
&lt;br /&gt;
The binary tree is core to how Huffman compression compresses data. This is done by constructing a &#039;binary tree&#039;, so named because of its branching structure. Each branching point or &#039;node&#039; has two options, &#039;left&#039; and &#039;right&#039; which lead either to another node or a character. The tree is constructed so that every character can be placed upon it and every path ends in a character. &lt;br /&gt;
&lt;br /&gt;
This is done by first building a point of origin, &#039;root node&#039; and the adding further nodes from there. Using our example we can build the following binary tree simply by listing the nodes alphabetically (and using &#039;_&#039; to stand in for the space for clarity):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
           [Root]&lt;br /&gt;
         ____|_______&lt;br /&gt;
       /             \&lt;br /&gt;
     __|__            |&lt;br /&gt;
    /      \        /   \&lt;br /&gt;
    |       |       |    .&lt;br /&gt;
  /   \   /   \   /   \&lt;br /&gt;
  |   |   |   |   |   |&lt;br /&gt;
 / \ / \ / \ / \ / \ / \&lt;br /&gt;
 _ S a b e h l o r s t y&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On this tree we can use &#039;L&#039; to specify a left path and &#039;R&#039; to specify a right. As such the letter &#039;a&#039; is represented by &#039;LLRL&#039; and &#039;y&#039; by &#039;RLRR&#039;. Note that since the number of different characters is not a power of two (E.g. 16) not all paths from the root to a character are the same length, one is considerably shorter. The &#039;.&#039; character is represented by simply &#039;RR&#039;&lt;br /&gt;
&lt;br /&gt;
Assuming that &#039;R&#039; and &#039;L&#039; are &#039;0&#039; and &#039;1&#039; each 8-bit character in the original text can be represented by just 4 bits on average, halving the message length. This is far from optimal however and there is a specific procedure used to construct an optimal tree for the shortest message length. To do this advantage is taken of the fact that paths can be different lengths. If one set of paths is made a bit shorter at the expense of making a smaller set of paths a bit longer then the overall message will be made shorter.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Constructing an optimal tree===&lt;br /&gt;
&lt;br /&gt;
The first step in creating an optimal tree again is to create a &#039;root node&#039;. To populate its two options the compressor repeatedly divides the frequency table. This is done by starting with the most common character and seeing if it contains more occurrences than the rest of the table combined. If not then the second most common character is added and so on.&lt;br /&gt;
&lt;br /&gt;
In our example there are a total of 37 characters. Three characters make up more than half of this, &#039;s&#039;, &#039;e&#039; and &#039; &#039;. Because of the binary structure of the tree however &#039;&#039;four&#039;&#039; options are needed here so &#039;h&#039; is also included. All of these characters are placed on the left option of the root node while the remaining characters are placed on the right.&lt;br /&gt;
&lt;br /&gt;
The next step creates a new node with left and right options and repeats the process. The two most common characters of the four, &#039;s&#039; and &#039;e&#039; go to the left branch of this new node. A third node is created and, now that there are only two options, each is given a branch. The tree now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [Root]&lt;br /&gt;
    / \&lt;br /&gt;
    |  l, a, etc&lt;br /&gt;
   / \&lt;br /&gt;
   | _, h&lt;br /&gt;
 /  \&lt;br /&gt;
 s  e&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now the character &#039;s&#039; can be represented as LLL and &#039;e&#039; as LLR.&lt;br /&gt;
&lt;br /&gt;
The compressor now moves &#039;up&#039; to the previous node which still has a branch with more than one option in it. Another node is created and, since there are only two options, one is assigned to each branch. Te compressor then returns to the root node to deal with the right half of the tree. When it has assigned very character to a node the following optimal tree is produced:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      ___[Root]____&lt;br /&gt;
     /             \&lt;br /&gt;
    _|_         ___|_______&lt;br /&gt;
   /   \       /           \&lt;br /&gt;
   |   |       |            |&lt;br /&gt;
 /  \ / \     / \          / \&lt;br /&gt;
 s  e _ h    l   |        |   |&lt;br /&gt;
                / \      / \ / \&lt;br /&gt;
               a  |      o r t |&lt;br /&gt;
                 / \          / \&lt;br /&gt;
                 S b         y  .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that 4 characters now have paths that are just 3 choices long while 4 have paths 4 choices long and 4 have paths 5 choices long. Overall the average path length is the same as our previous tree. However 24 occurrences are one choice shorter, 5 are identical,  3 are one choice longer and &#039;.&#039; is three choices longer. This gives us a compressed message that is  a total of 18 choices (or bits) shorter.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Labeling the tree===&lt;br /&gt;
&lt;br /&gt;
Now that a tree has been constructed it needs to be labelled in some form so that it can be stored as data either in the decompressor or to be sent with the compressed code. There are two major issues, what system to use when assigning numbers to the various nodes, and what bit value, 0 or 1, to assign to left or right options.&lt;br /&gt;
&lt;br /&gt;
The most common (but far from unique) system is to label nodes from the &#039;bottom&#039; of the tree to the top, going left-to-right across each &#039;layer&#039; of the tree. (In our example the node that leads to &#039;S&#039; and &#039;b&#039; would thus be the first numbered node.) Nodes are usually numbered starting with 0 and ending with the root node having the highest number. Our tree would be numbered as follows using this system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      ____[11]_____&lt;br /&gt;
     /             \&lt;br /&gt;
    [9]         __[10]_____&lt;br /&gt;
   /   \       /           \&lt;br /&gt;
  [5] [6]     [7]          [8]&lt;br /&gt;
 /  \ / \     / \          / \&lt;br /&gt;
 s  e _ h    l  [2]      [3] [4]&lt;br /&gt;
                / \      / \ / \&lt;br /&gt;
               a [0]     o r t[1]&lt;br /&gt;
                 / \          / \&lt;br /&gt;
                 S b         y  .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usually the left branch is given a bit value of 0 and the right branch a bit value of 1. Using this scheme &#039;s&#039; in our example resides on node 1 and is represented by the bit string &#039;000&#039; The complete compressed message in bit form is now &amp;lt;tt&amp;gt;10110 011 001 010 000 001 100 100 000 010 000 001 1010 000 011 001 100 100 000 010 10111 11110 010 1110 011 001 010 000 001 1010 010 000 011 1100 1101 001 11111&amp;lt;/tt&amp;gt; or in bytes &amp;lt;tt&amp;gt;$B3 $28 $19 $02 $06 $83 $32 $05 $7F $2E $65 $03 $48 $3C $D3 $F0&amp;lt;/tt&amp;gt; (The final byte is padded with nul bits.) This is a total of 16 bytes used for a 37 byte message.&lt;br /&gt;
&lt;br /&gt;
===Standard tree size===&lt;br /&gt;
&lt;br /&gt;
The most common implementation of Huffman compression is &#039;1 byte in, 1 bit out&#039;. This involves compressing one byte of data at a time and converting it into a bitstream. In this case the compressor expects to find 256 different possible values of data. This requires a tree with 255 nodes, including the root, and an average path length of 8 choices.&lt;br /&gt;
&lt;br /&gt;
This is not the only possibility however and Huffman can compress data in words or dwords or in more exotic manners. {{Game|Commander Keen Dreams}} for example combines Huffman with LZW compression, building a binary tree of a fixed size and filling it with the most recently encountered strings of bits.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==The dictionary==&lt;br /&gt;
&lt;br /&gt;
Often the binary tree must be stored in some form, usually called a &#039;&#039;dictionary&#039;&#039;. This will either be fixed and known by both the compressor and decompressor. (Which minimizes individual message sizes but can limit compression efficiency overall.) or tailored for each message and sent with said message.&lt;br /&gt;
&lt;br /&gt;
Dictionary format is quite standard. It is merely a numerical list of nodes (however they have been labelled.) starting with node 0 and ending with the root. Each node usually taking up four bytes, two bytes per branch. Each branch will have one byte dedicated to identifying if it leads to another node or a character and the other byte identifying the node or character. Usually &#039;0&#039; identifies the option asleading to a character and &#039;1&#039; to another node, but again this can be reversed.&lt;br /&gt;
&lt;br /&gt;
Using this system, our example tree could be stored as either of the two following:&lt;br /&gt;
&lt;br /&gt;
    0S0b 0y0. 0a10 0o0r 0t11 0s0e 0_0h 0l12 1314 1516 1718 19110&lt;br /&gt;
&lt;br /&gt;
    $00 $53 $00 $62 $00 $79 $00 $2E $00 $6F $00 $72 $00 $74 $01 $01 $00 $73 $00 $65 $00 $20 $00 $68...&lt;br /&gt;
     -   S   -   b   -   y   -   .   -   o   -   r   -   t   |  n1   -   s    -  e   -   _   -   h ...&lt;br /&gt;
         (node 0)         (node 1)       (node 3)        (node 4)        (node 5)      (node 6)    ...&lt;br /&gt;
    &lt;br /&gt;
The dictionary is thus usually 1020 bytes long, containing 255 nodes of 4 bytes each, though again this can vary depending on how readable the dictionary is to humans and whether or not the dictionary itself is compressed.&lt;br /&gt;
&lt;br /&gt;
==Huffman implementation in ID Software games==&lt;br /&gt;
&lt;br /&gt;
Games created by Id Software  have a shared but distinct implementation of Huffman compression.&lt;br /&gt;
&lt;br /&gt;
In older games such as {{Game|Dangerous Dave 2}} the dictionary and data are included together in one file. First is a four-byte header,, &#039;HUFF&#039; followed by four bytes that give the decompressed size of the data (for memory purposes.). Following that is the dictionary, 1020 bytes in length then the compressed data.&lt;br /&gt;
&lt;br /&gt;
In newer games (such as [[Commander Keen 4-6]] or [[Wolfenstein 3-D]]) the data is stored in an external file which consists of a number of concatenated &#039;chunks&#039;, each chunk beginning with a dword giving its decompressed size (again for memory purposes.). These chunks are addressed by an internal or external &#039;header&#039; file consisting of a series of three (or sometimes four) byte offsets to the start of various chunks in the data file. (The end of the header is easily found as the last entry is the length of the data file.) The dictionary is 1024 bytes long and stored in the executable.&lt;br /&gt;
&lt;br /&gt;
The dictionary consists of 255 nodes (in newr games plus four null bytes of padding) and there are two or three dictionaries stored in the executable depending on the game. The end of these dictionaries can be found by looking for node 255 (number 254!) which universally consists of the string &amp;lt;tt&amp;gt;$00 $00 $FD $01&amp;lt;/tt&amp;gt; due to the fact that the byte &amp;lt;tt&amp;gt;$00&amp;lt;/tt&amp;gt; is the single most common character in game data and thus always occupies the left branch of the root node while the other branch must go to the next lowest node, number 253.&lt;br /&gt;
&lt;br /&gt;
An important but subtle difference is how data is read. While bytes are read sequentially (1, 2, 3...) bits within each byte are read in reverse order (8, 7, 6...). (Technically each byte is little endian.)&lt;br /&gt;
&lt;br /&gt;
===Trivial ID dictionary===&lt;br /&gt;
&lt;br /&gt;
The following is a complete &#039;trivial&#039; dictionary. This dictionary is constructed such that data compressed with it is not altered in any way, the output and input are the same. When used to construct a binary tree all paths are of equal length, 8 choices or bits. And the nodes are arranged in a logical order with an easily seen pattern; the first half of the tree consists of terminal nodes, the second half of branch nodes. (Of the second half the first half of &#039;&#039;that&#039;&#039; consists of branch nodes that lead to terminal nodes while the second half consists of branch nodes to two branch nodes and so on.)&lt;br /&gt;
&lt;br /&gt;
 $00 $00 $80 $00 $40 $00 $C0 $00 $20 $00 $A0 $00 $60 $00 $E0 $00&lt;br /&gt;
 $10 $00 $90 $00 $50 $00 $D0 $00 $30 $00 $B0 $00 $70 $00 $F0 $00&lt;br /&gt;
 $08 $00 $88 $00 $48 $00 $C8 $00 $28 $00 $A8 $00 $68 $00 $E8 $00&lt;br /&gt;
 $18 $00 $98 $00 $58 $00 $D8 $00 $38 $00 $B8 $00 $78 $00 $F8 $00&lt;br /&gt;
 $04 $00 $84 $00 $44 $00 $C4 $00 $24 $00 $A4 $00 $64 $00 $E4 $00&lt;br /&gt;
 $14 $00 $94 $00 $54 $00 $D4 $00 $34 $00 $B4 $00 $74 $00 $F4 $00&lt;br /&gt;
 $0C $00 $8C $00 $4C $00 $CC $00 $2C $00 $AC $00 $6C $00 $EC $00&lt;br /&gt;
 $1C $00 $9C $00 $5C $00 $DC $00 $3C $00 $BC $00 $7C $00 $FC $00&lt;br /&gt;
 $02 $00 $82 $00 $42 $00 $C2 $00 $22 $00 $A2 $00 $62 $00 $E2 $00&lt;br /&gt;
 $12 $00 $92 $00 $52 $00 $D2 $00 $32 $00 $B2 $00 $72 $00 $F2 $00&lt;br /&gt;
 $0A $00 $8A $00 $4A $00 $CA $00 $2A $00 $AA $00 $6A $00 $EA $00&lt;br /&gt;
 $1A $00 $9A $00 $5A $00 $DA $00 $3A $00 $BA $00 $7A $00 $FA $00&lt;br /&gt;
 $06 $00 $86 $00 $46 $00 $C6 $00 $26 $00 $A6 $00 $66 $00 $E6 $00&lt;br /&gt;
 $16 $00 $96 $00 $56 $00 $D6 $00 $36 $00 $B6 $00 $76 $00 $F6 $00&lt;br /&gt;
 $0E $00 $8E $00 $4E $00 $CE $00 $2E $00 $AE $00 $6E $00 $EE $00&lt;br /&gt;
 $1E $00 $9E $00 $5E $00 $DE $00 $3E $00 $BE $00 $7E $00 $FE $00&lt;br /&gt;
 $01 $00 $81 $00 $41 $00 $C1 $00 $21 $00 $A1 $00 $61 $00 $E1 $00&lt;br /&gt;
 $11 $00 $91 $00 $51 $00 $D1 $00 $31 $00 $B1 $00 $71 $00 $F1 $00&lt;br /&gt;
 $09 $00 $89 $00 $49 $00 $C9 $00 $29 $00 $A9 $00 $69 $00 $E9 $00&lt;br /&gt;
 $19 $00 $99 $00 $59 $00 $D9 $00 $39 $00 $B9 $00 $79 $00 $F9 $00&lt;br /&gt;
 $05 $00 $85 $00 $45 $00 $C5 $00 $25 $00 $A5 $00 $65 $00 $E5 $00&lt;br /&gt;
 $15 $00 $95 $00 $55 $00 $D5 $00 $35 $00 $B5 $00 $75 $00 $F5 $00&lt;br /&gt;
 $0D $00 $8D $00 $4D $00 $CD $00 $2D $00 $AD $00 $6D $00 $ED $00&lt;br /&gt;
 $1D $00 $9D $00 $5D $00 $DD $00 $3D $00 $BD $00 $7D $00 $FD $00&lt;br /&gt;
 $03 $00 $83 $00 $43 $00 $C3 $00 $23 $00 $A3 $00 $63 $00 $E3 $00&lt;br /&gt;
 $13 $00 $93 $00 $53 $00 $D3 $00 $33 $00 $B3 $00 $73 $00 $F3 $00&lt;br /&gt;
 $0B $00 $8B $00 $4B $00 $CB $00 $2B $00 $AB $00 $6B $00 $EB $00&lt;br /&gt;
 $1B $00 $9B $00 $5B $00 $DB $00 $3B $00 $BB $00 $7B $00 $FB $00&lt;br /&gt;
 $07 $00 $87 $00 $47 $00 $C7 $00 $27 $00 $A7 $00 $67 $00 $E7 $00&lt;br /&gt;
 $17 $00 $97 $00 $57 $00 $D7 $00 $37 $00 $B7 $00 $77 $00 $F7 $00&lt;br /&gt;
 $0F $00 $8F $00 $4F $00 $CF $00 $2F $00 $AF $00 $6F $00 $EF $00&lt;br /&gt;
 $1F $00 $9F $00 $5F $00 $DF $00 $3F $00 $BF $00 $7F $00 $FF $00&lt;br /&gt;
 $00 $01 $01 $01 $02 $01 $03 $01 $04 $01 $05 $01 $06 $01 $07 $01&lt;br /&gt;
 $08 $01 $09 $01 $0A $01 $0B $01 $0C $01 $0D $01 $0E $01 $0F $01&lt;br /&gt;
 $10 $01 $11 $01 $12 $01 $13 $01 $14 $01 $15 $01 $16 $01 $17 $01&lt;br /&gt;
 $18 $01 $19 $01 $1A $01 $1B $01 $1C $01 $1D $01 $1E $01 $1F $01&lt;br /&gt;
 $20 $01 $21 $01 $22 $01 $23 $01 $24 $01 $25 $01 $26 $01 $27 $01&lt;br /&gt;
 $28 $01 $29 $01 $2A $01 $2B $01 $2C $01 $2D $01 $2E $01 $2F $01&lt;br /&gt;
 $30 $01 $31 $01 $32 $01 $33 $01 $34 $01 $35 $01 $36 $01 $37 $01&lt;br /&gt;
 $38 $01 $39 $01 $3A $01 $3B $01 $3C $01 $3D $01 $3E $01 $3F $01&lt;br /&gt;
 $40 $01 $41 $01 $42 $01 $43 $01 $44 $01 $45 $01 $46 $01 $47 $01&lt;br /&gt;
 $48 $01 $49 $01 $4A $01 $4B $01 $4C $01 $4D $01 $4E $01 $4F $01&lt;br /&gt;
 $50 $01 $51 $01 $52 $01 $53 $01 $54 $01 $55 $01 $56 $01 $57 $01&lt;br /&gt;
 $58 $01 $59 $01 $5A $01 $5B $01 $5C $01 $5D $01 $5E $01 $5F $01&lt;br /&gt;
 $60 $01 $61 $01 $62 $01 $63 $01 $64 $01 $65 $01 $66 $01 $67 $01&lt;br /&gt;
 $68 $01 $69 $01 $6A $01 $6B $01 $6C $01 $6D $01 $6E $01 $6F $01&lt;br /&gt;
 $70 $01 $71 $01 $72 $01 $73 $01 $74 $01 $75 $01 $76 $01 $77 $01&lt;br /&gt;
 $78 $01 $79 $01 $7A $01 $7B $01 $7C $01 $7D $01 $7E $01 $7F $01&lt;br /&gt;
 $80 $01 $81 $01 $82 $01 $83 $01 $84 $01 $85 $01 $86 $01 $87 $01&lt;br /&gt;
 $88 $01 $89 $01 $8A $01 $8B $01 $8C $01 $8D $01 $8E $01 $8F $01&lt;br /&gt;
 $90 $01 $91 $01 $92 $01 $93 $01 $94 $01 $95 $01 $96 $01 $97 $01&lt;br /&gt;
 $98 $01 $99 $01 $9A $01 $9B $01 $9C $01 $9D $01 $9E $01 $9F $01&lt;br /&gt;
 $A0 $01 $A1 $01 $A2 $01 $A3 $01 $A4 $01 $A5 $01 $A6 $01 $A7 $01&lt;br /&gt;
 $A8 $01 $A9 $01 $AA $01 $AB $01 $AC $01 $AD $01 $AE $01 $AF $01&lt;br /&gt;
 $B0 $01 $B1 $01 $B2 $01 $B3 $01 $B4 $01 $B5 $01 $B6 $01 $B7 $01&lt;br /&gt;
 $B8 $01 $B9 $01 $BA $01 $BB $01 $BC $01 $BD $01 $BE $01 $BF $01&lt;br /&gt;
 $C0 $01 $C1 $01 $C2 $01 $C3 $01 $C4 $01 $C5 $01 $C6 $01 $C7 $01&lt;br /&gt;
 $C8 $01 $C9 $01 $CA $01 $CB $01 $CC $01 $CD $01 $CE $01 $CF $01&lt;br /&gt;
 $D0 $01 $D1 $01 $D2 $01 $D3 $01 $D4 $01 $D5 $01 $D6 $01 $D7 $01&lt;br /&gt;
 $D8 $01 $D9 $01 $DA $01 $DB $01 $DC $01 $DD $01 $DE $01 $DF $01&lt;br /&gt;
 $E0 $01 $E1 $01 $E2 $01 $E3 $01 $E4 $01 $E5 $01 $E6 $01 $E7 $01&lt;br /&gt;
 $E8 $01 $E9 $01 $EA $01 $EB $01 $EC $01 $ED $01 $EE $01 $EF $01&lt;br /&gt;
 $F0 $01 $F1 $01 $F2 $01 $F3 $01 $F4 $01 $F5 $01 $F6 $01 $F7 $01&lt;br /&gt;
 $F8 $01 $F9 $01 $FA $01 $FB $01 $FC $01 $FD $01&lt;br /&gt;
&lt;br /&gt;
Using this example we can see the unusual manner in which ID games read bits within bytes. As an example consider the character $80; in binary this is &#039;10000000&#039; However, following this path using the dictionary given above will output the character $01 (00000001). Instead the bits must be read in reverse order. Doing so will lead to the following nodes starting at the root node: 254(root) -&amp;gt; 252 -&amp;gt; 248 -&amp;gt; 240 -&amp;gt; 224 -&amp;gt; 192 -&amp;gt; 128 -&amp;gt; 0(terminal node for characters $00 and $80)&lt;br /&gt;
&lt;br /&gt;
== Source code ==&lt;br /&gt;
&lt;br /&gt;
Some example code is available in various languages showing how to decompress (and in some cases compress) files using the Huffman algorithm.&lt;br /&gt;
&lt;br /&gt;
=== QuickBasic ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;qbasic&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&lt;br /&gt;
&#039; DANGEROUS DAVE 2 - IN THE HAUNTED MANSION - Huffman Decompressor&lt;br /&gt;
&#039;  - by Napalm with thanks to Adurdin&#039;s work on ModKeen&lt;br /&gt;
&#039;&lt;br /&gt;
&#039; This source is Public Domain, please credit me if you use it.&lt;br /&gt;
&#039;&lt;br /&gt;
&#039;&lt;br /&gt;
DECLARE SUB HUFFDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING)&lt;br /&gt;
&lt;br /&gt;
TYPE NODE&lt;br /&gt;
        BIT0 AS INTEGER&lt;br /&gt;
        BIT1 AS INTEGER&lt;br /&gt;
END TYPE&lt;br /&gt;
&lt;br /&gt;
&#039; Input filename, output filename&lt;br /&gt;
HUFFDECOMPRESS &amp;quot;TITLE1.DD2&amp;quot;, &amp;quot;TITLE1.PIC&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SUB HUFFDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING) &#039; by Napalm&lt;br /&gt;
	DIM INFILE AS INTEGER, OUTFILE AS INTEGER, I AS INTEGER&lt;br /&gt;
	DIM SIG AS LONG, OUTLEN AS LONG, BITMASK AS INTEGER&lt;br /&gt;
	DIM CURNODE AS INTEGER, NEXTNODE AS INTEGER&lt;br /&gt;
	DIM CHRIN AS STRING * 1, CHROUT AS STRING * 1&lt;br /&gt;
	DIM NODES(0 TO 254) AS NODE&lt;br /&gt;
&lt;br /&gt;
	&#039; Open input file&lt;br /&gt;
	INFILE = FREEFILE&lt;br /&gt;
	OPEN INNAME FOR BINARY ACCESS READ AS INFILE&lt;br /&gt;
       &lt;br /&gt;
	&#039; Check file signature&lt;br /&gt;
	GET INFILE, , SIG&lt;br /&gt;
	IF SIG &amp;lt;&amp;gt; &amp;amp;H46465548 THEN &#039; Hex for: HUFF in little endian&lt;br /&gt;
		PRINT &amp;quot;INVALID FILE!&amp;quot;&lt;br /&gt;
		EXIT SUB&lt;br /&gt;
	END IF&lt;br /&gt;
       &lt;br /&gt;
	&#039; Get output length&lt;br /&gt;
	OUTLEN = 0&lt;br /&gt;
	GET INFILE, , OUTLEN&lt;br /&gt;
       &lt;br /&gt;
	&#039; Read in the Huffman binary tree&lt;br /&gt;
	FOR I = 0 TO 254&lt;br /&gt;
		GET INFILE, , NODES(I).BIT0&lt;br /&gt;
		GET INFILE, , NODES(I).BIT1&lt;br /&gt;
	NEXT I&lt;br /&gt;
&lt;br /&gt;
	&#039; Open output file&lt;br /&gt;
	OUTFILE = FREEFILE&lt;br /&gt;
	OPEN OUTNAME FOR BINARY ACCESS WRITE AS OUTFILE&lt;br /&gt;
&lt;br /&gt;
	&#039; Decompress input data using binary tree&lt;br /&gt;
	CURNODE = 254&lt;br /&gt;
	DO&lt;br /&gt;
		BITMASK = 0&lt;br /&gt;
		GET INFILE, , CHRIN&lt;br /&gt;
		DO&lt;br /&gt;
			&#039; Decide which node to travel down depending on&lt;br /&gt;
			&#039;   input bits from CHRIN.&lt;br /&gt;
			IF ASC(CHRIN) AND 2 ^ BITMASK THEN&lt;br /&gt;
				NEXTNODE = NODES(CURNODE).BIT1&lt;br /&gt;
			ELSE&lt;br /&gt;
				NEXTNODE = NODES(CURNODE).BIT0&lt;br /&gt;
			END IF&lt;br /&gt;
		       &lt;br /&gt;
			&#039; Is this next node another part of the tree or&lt;br /&gt;
			&#039;   is it a end node? Less than 256 mean end node.&lt;br /&gt;
			IF NEXTNODE &amp;lt; 256 THEN&lt;br /&gt;
			       &lt;br /&gt;
				&#039; Get output char from end node and save.&lt;br /&gt;
				CHROUT = CHR$(NEXTNODE AND &amp;amp;HFF)&lt;br /&gt;
				PUT OUTFILE, , CHROUT&lt;br /&gt;
			       &lt;br /&gt;
				&#039; Amend output length and start from top of&lt;br /&gt;
				&#039;   binary tree.&lt;br /&gt;
				OUTLEN = OUTLEN - 1&lt;br /&gt;
				CURNODE = 254&lt;br /&gt;
&lt;br /&gt;
			ELSE&lt;br /&gt;
				&#039; Travel to next node&lt;br /&gt;
				CURNODE = (NEXTNODE AND &amp;amp;HFF)&lt;br /&gt;
&lt;br /&gt;
			END IF&lt;br /&gt;
&lt;br /&gt;
			&#039; Move to next input bit&lt;br /&gt;
			BITMASK = BITMASK + 1&lt;br /&gt;
		LOOP WHILE BITMASK &amp;lt; 8 AND OUTLEN &amp;gt; 0&lt;br /&gt;
		&#039; Loop while we still need to output data&lt;br /&gt;
	LOOP WHILE OUTLEN &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
	&#039; Clean up&lt;br /&gt;
	CLOSE OUTFILE&lt;br /&gt;
	CLOSE INFILE&lt;br /&gt;
&lt;br /&gt;
END SUB&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;qbasic&amp;quot;&amp;gt;&lt;br /&gt;
SUB MAKHUF &#039;Mak a degenerate huffman tree, store as string huffq&lt;br /&gt;
	OPEN &amp;quot;HUFF.DD2&amp;quot; FOR BINARY AS #8&lt;br /&gt;
	aq = &amp;quot;HUFF&amp;quot;&lt;br /&gt;
	PUT #8, 1, aq&lt;br /&gt;
	x = 9&lt;br /&gt;
	FOR t = 0 TO 255&lt;br /&gt;
		b = t&lt;br /&gt;
		va = 0&lt;br /&gt;
		vb = 0&lt;br /&gt;
		vc = 0&lt;br /&gt;
		vd = 0&lt;br /&gt;
		ve = 0&lt;br /&gt;
		vf = 0&lt;br /&gt;
		vg = 0&lt;br /&gt;
		vh = 0&lt;br /&gt;
		IF b &amp;gt; 127 THEN LET va = va + 1&lt;br /&gt;
		b = b MOD 128&lt;br /&gt;
		IF b &amp;gt; 63 THEN LET vb = vb + 1&lt;br /&gt;
		b = b MOD 64&lt;br /&gt;
		IF b &amp;gt; 31 THEN LET vc = vc + 1&lt;br /&gt;
		b = b MOD 32&lt;br /&gt;
		IF b &amp;gt; 15 THEN LET vd = vd + 1&lt;br /&gt;
		b = b MOD 16&lt;br /&gt;
		IF b &amp;gt; 7 THEN LET ve = ve + 1&lt;br /&gt;
		b = b MOD 8&lt;br /&gt;
		IF b &amp;gt; 3 THEN LET vf = vf + 1&lt;br /&gt;
		b = b MOD 4&lt;br /&gt;
		IF b &amp;gt; 1 THEN LET vg = vg + 1&lt;br /&gt;
		b = b MOD 2&lt;br /&gt;
		IF b = 1 THEN LET vh = vh + 1&lt;br /&gt;
		b = (vh * 128) + (vg * 64) + (vf * 32) + (16 * ve) + (8 * vd) + (4 * vc) + (2 * vb) + va&lt;br /&gt;
		aq = MKI$(b)&lt;br /&gt;
		PUT #8, x, aq&lt;br /&gt;
		x = x + 2&lt;br /&gt;
	NEXT t&lt;br /&gt;
	FOR t = 0 TO 253&lt;br /&gt;
		aq = MKI$(t + 256)&lt;br /&gt;
		PUT #8, x, aq&lt;br /&gt;
		x = x + 2&lt;br /&gt;
	NEXT t&lt;br /&gt;
	GET #8, 1, huffq&lt;br /&gt;
	CLOSE #8&lt;br /&gt;
	KILL &amp;quot;HUFF.DD2&amp;quot;&lt;br /&gt;
END SUB&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Visual Basic .NET ===&lt;br /&gt;
&lt;br /&gt;
==== Huffman tree representation ====&lt;br /&gt;
&lt;br /&gt;
This class, BinaryTreeNode, represents a binary tree whose branch nodes carry no value, like a Huffman dictionary tree.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vbnet&amp;quot;&amp;gt;Public Class BinaryTreeNode(Of T)&lt;br /&gt;
    &#039; By Fleexy, public domain, credit where credit is due&lt;br /&gt;
    Private Branch As Boolean&lt;br /&gt;
    Private Children As BinaryTreeNode(Of T)()&lt;br /&gt;
    Private HoldValue As T&lt;br /&gt;
    Public Sub New(LeafValue As T)&lt;br /&gt;
        Branch = False&lt;br /&gt;
        HoldValue = LeafValue&lt;br /&gt;
    End Sub&lt;br /&gt;
    Public Sub New(LeftChild As BinaryTreeNode(Of T), RightChild As BinaryTreeNode(Of T))&lt;br /&gt;
        Branch = True&lt;br /&gt;
        Children = {LeftChild, RightChild}&lt;br /&gt;
    End Sub&lt;br /&gt;
    Public ReadOnly Property HasValue As Boolean&lt;br /&gt;
        Get&lt;br /&gt;
            Return Not Branch&lt;br /&gt;
        End Get&lt;br /&gt;
    End Property&lt;br /&gt;
    Public Property Value As T&lt;br /&gt;
        Get&lt;br /&gt;
            If Branch Then Throw New InvalidOperationException&lt;br /&gt;
            Return HoldValue&lt;br /&gt;
        End Get&lt;br /&gt;
        Set(value As T)&lt;br /&gt;
            If Branch Then Throw New InvalidOperationException&lt;br /&gt;
            HoldValue = value&lt;br /&gt;
        End Set&lt;br /&gt;
    End Property&lt;br /&gt;
    Public Property Child(Side As ChildSide) As BinaryTreeNode(Of T)&lt;br /&gt;
        Get&lt;br /&gt;
            If Not Branch Then Throw New InvalidOperationException&lt;br /&gt;
            Return Children(Side)&lt;br /&gt;
        End Get&lt;br /&gt;
        Set(value As BinaryTreeNode(Of T))&lt;br /&gt;
            If Not Branch Then Throw New InvalidOperationException&lt;br /&gt;
            Children(Side) = value&lt;br /&gt;
        End Set&lt;br /&gt;
    End Property&lt;br /&gt;
    Public Enum ChildSide As Byte&lt;br /&gt;
        Left = 0&lt;br /&gt;
        Right = 1&lt;br /&gt;
    End Enum&lt;br /&gt;
    Public ReadOnly Property Count As Integer&lt;br /&gt;
        Get&lt;br /&gt;
            If Not Branch Then Return 1&lt;br /&gt;
            Return Children(0).Count + Children(1).Count&lt;br /&gt;
        End Get&lt;br /&gt;
    End Property&lt;br /&gt;
    Public ReadOnly Property Depth As Integer&lt;br /&gt;
        Get&lt;br /&gt;
            If Not Branch Then Return 1&lt;br /&gt;
            Return Math.Max(Children(0).Depth, Children(1).Depth) + 1&lt;br /&gt;
        End Get&lt;br /&gt;
    End Property&lt;br /&gt;
    Public Overrides Function ToString() As String&lt;br /&gt;
        Return &amp;quot;{Count = &amp;quot; &amp;amp; Count &amp;amp; &amp;quot;, Depth = &amp;quot; &amp;amp; Depth &amp;amp; &amp;quot;}&amp;quot;&lt;br /&gt;
    End Function&lt;br /&gt;
End Class&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Huffman tree reading ====&lt;br /&gt;
&lt;br /&gt;
This piece of code will read in a stored Huffman dictionary in the format described at the top of this article and store it in a BinaryTreeNode(Of Byte) as shown above.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vbnet&amp;quot;&amp;gt;        &#039; By Fleexy, public domain, credit where credit is due&lt;br /&gt;
        Dim fDict As New IO.FileStream(DictionaryFile, IO.FileMode.Open)&lt;br /&gt;
        Dim raw(254) As Tuple(Of UShort, UShort)&lt;br /&gt;
        For x = 0 To 254&lt;br /&gt;
            raw(x) = Tuple.Create(ReadUShort(fDict), ReadUShort(fDict))&lt;br /&gt;
        Next&lt;br /&gt;
        fDict.Close()&lt;br /&gt;
        Dim GenerateTree As Func(Of UShort, BinaryTreeNode(Of Byte))&lt;br /&gt;
        GenerateTree = Function(NextNode As UShort) As BinaryTreeNode(Of Byte)&lt;br /&gt;
                           Dim n As Tuple(Of UShort, UShort) = raw(NextNode)&lt;br /&gt;
                           Dim a, b As BinaryTreeNode(Of Byte)&lt;br /&gt;
                           If n.Item1 &amp;lt; 256 Then&lt;br /&gt;
                               a = New BinaryTreeNode(Of Byte)(n.Item1)&lt;br /&gt;
                           Else&lt;br /&gt;
                               a = GenerateTree(n.Item1 - 256)&lt;br /&gt;
                           End If&lt;br /&gt;
                           If n.Item2 &amp;lt; 256 Then&lt;br /&gt;
                               b = New BinaryTreeNode(Of Byte)(n.Item2)&lt;br /&gt;
                           Else&lt;br /&gt;
                               b = GenerateTree(n.Item2 - 256)&lt;br /&gt;
                           End If&lt;br /&gt;
                           Return New BinaryTreeNode(Of Byte)(a, b)&lt;br /&gt;
                       End Function&lt;br /&gt;
        Dim dict As BinaryTreeNode(Of Byte) = GenerateTree(254)&lt;br /&gt;
        fDict.Close()&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Haskell ===&lt;br /&gt;
&lt;br /&gt;
Currently, you have to manually extract chunks using the offsets in AUDIOHED.***.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;haskell&amp;quot;&amp;gt;&lt;br /&gt;
-- Reading in a Huffman Tree, and using&lt;br /&gt;
-- it to decompress individual chunks.&lt;br /&gt;
-- Code by QuirkyM, format information&lt;br /&gt;
-- taken from http://www.shikadi.net/moddingwiki/Huffman_Compression&lt;br /&gt;
&lt;br /&gt;
-- This code is public domain, but please credit me&lt;br /&gt;
-- if you use it.&lt;br /&gt;
&lt;br /&gt;
import Data.Maybe&lt;br /&gt;
import Data.Word  -- Fixed-size unsigned integers&lt;br /&gt;
import Data.Bits&lt;br /&gt;
import Data.List&lt;br /&gt;
import Data.Int   -- Fixed-size signed integers&lt;br /&gt;
&lt;br /&gt;
import qualified Data.ByteString as BS&lt;br /&gt;
&lt;br /&gt;
import Data.ByteString (ByteString)&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
-- Huffman Tree data structure and related functions&lt;br /&gt;
&lt;br /&gt;
data HuffTree a = HuffNode (HuffTree a) (HuffTree a) | HuffLeaf a deriving (Show,Eq)&lt;br /&gt;
&lt;br /&gt;
-- This just counts the number of output symbols.&lt;br /&gt;
huffSize2 :: (HuffTree a) -&amp;gt; Int&lt;br /&gt;
huffSize2 (HuffNode l r) = (huffSize2 l) + (huffSize2 r)&lt;br /&gt;
huffSize2 (HuffLeaf _)   = 1&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
-- Helper Functions&lt;br /&gt;
&lt;br /&gt;
-- Find the first element that satisfies a&lt;br /&gt;
-- predicate after mapping.&lt;br /&gt;
findFirst :: (a -&amp;gt; b) -&amp;gt; (b -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; Maybe b&lt;br /&gt;
findFirst f p (x:xs)&lt;br /&gt;
    | (p $ f x) = Just $ f x&lt;br /&gt;
    | otherwise = findFirst f p xs&lt;br /&gt;
findFirst f p [] = Nothing&lt;br /&gt;
&lt;br /&gt;
-- Find the first element that satisfies a&lt;br /&gt;
-- predicate after mapping, throwing an error&lt;br /&gt;
-- if no such element is found.&lt;br /&gt;
findFirst&#039; :: String -&amp;gt; (a -&amp;gt; b) -&amp;gt; (b -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; b&lt;br /&gt;
findFirst&#039; err f p xs = fromMaybe (error err) (findFirst f p xs)&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
-- Reading Huffman Dictionary&lt;br /&gt;
&lt;br /&gt;
-- Read in a Huffman Tree&lt;br /&gt;
-- (If node 254 is not the root, try creating all&lt;br /&gt;
--  the trees until you find one with all 256 bytes)&lt;br /&gt;
readHuffTree :: ByteString -&amp;gt; HuffTree Word8&lt;br /&gt;
readHuffTree bs&lt;br /&gt;
    | (huffSize2 hf1 == 256) = hf1&lt;br /&gt;
    | otherwise              = findFirst&#039; (&amp;quot;readHuffTree: No Full Huffman Tree found.&amp;quot;) (readHuffTree&#039; bs) (\hf -&amp;gt; 256 == huffSize2 hf) [0..253]&lt;br /&gt;
    where hf1 = readHuffTree&#039; bs 254&lt;br /&gt;
&lt;br /&gt;
-- Read a Huffman Tree starting from a specific node.&lt;br /&gt;
readHuffTree&#039; :: ByteString -&amp;gt; Int -&amp;gt; HuffTree Word8&lt;br /&gt;
readHuffTree&#039; bs ind&lt;br /&gt;
    | x1 &amp;lt;- BS.index bs (4 * ind)&lt;br /&gt;
    , x2 &amp;lt;- BS.index bs (1 + (4 * ind))&lt;br /&gt;
    , y1 &amp;lt;- BS.index bs (2 + (4 * ind))&lt;br /&gt;
    , y2 &amp;lt;- BS.index bs (3 + (4 * ind))&lt;br /&gt;
    = HuffNode (huffChoice x1 x2 bs) (huffChoice y1 y2 bs)&lt;br /&gt;
&lt;br /&gt;
-- Pattern match on one side of a node&lt;br /&gt;
huffChoice :: Word8 -&amp;gt; Word8 -&amp;gt; ByteString -&amp;gt; HuffTree Word8&lt;br /&gt;
huffChoice x 0x01 bs = readHuffTree&#039; bs (fromIntegral x)&lt;br /&gt;
huffChoice c 0x00 bs = HuffLeaf c&lt;br /&gt;
huffChoice _ _    _  = error &amp;quot;readHuffTree: Encountered a non-00/01 option.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----------------------------------------------------------&lt;br /&gt;
-- Reading Huffman-Compressed Data&lt;br /&gt;
&lt;br /&gt;
-- Take four bytes, and convert them into an&lt;br /&gt;
-- unsigned 32-bit integer.&lt;br /&gt;
word32le :: (Word8,Word8,Word8,Word8) -&amp;gt; Word32&lt;br /&gt;
word32le (x1,x2,x3,x4) = (fi x1) .|. (fi x2 `shiftL` 8) .|. (fi x3 `shiftL` 16) .|. (fi x4 `shiftL` 24)&lt;br /&gt;
    where fi = fromIntegral :: Word8 -&amp;gt; Word32&lt;br /&gt;
&lt;br /&gt;
-- Lazy construction/interpretation of Bool List.&lt;br /&gt;
-- (Big-endian bits)&lt;br /&gt;
readBitsBE :: Word8 -&amp;gt; [Bool] -&amp;gt; [Bool]&lt;br /&gt;
readBitsBE x xs = ((rd 7):(rd 6):(rd 5):(rd 4):(rd 3):(rd 2):(rd 1):(rd 0):xs)&lt;br /&gt;
    where rd i = testBit x i&lt;br /&gt;
&lt;br /&gt;
-- Lazy construction/interpretation of Bool List.&lt;br /&gt;
-- (Little-endian bits)&lt;br /&gt;
readBitsLE :: Word8 -&amp;gt; [Bool] -&amp;gt; [Bool]&lt;br /&gt;
readBitsLE x xs = ((rd 0):(rd 1):(rd 2):(rd 3):(rd 4):(rd 5):(rd 6):(rd 7):xs)&lt;br /&gt;
    where rd i = testBit x i&lt;br /&gt;
&lt;br /&gt;
-- This is probably a bad idea...&lt;br /&gt;
-- ...unless the laziness saves some memory...&lt;br /&gt;
convertBitsLE :: ByteString -&amp;gt; [Bool]&lt;br /&gt;
convertBitsLE bs&lt;br /&gt;
    | (Just (x,xs)) &amp;lt;- BS.uncons bs&lt;br /&gt;
    = readBitsLE x (convertBitsLE xs)&lt;br /&gt;
    | otherwise = []&lt;br /&gt;
&lt;br /&gt;
-- The actual function to read the data&lt;br /&gt;
huffRead :: (HuffTree a) -&amp;gt; BS.ByteString -&amp;gt; [a]&lt;br /&gt;
huffRead hf bs &lt;br /&gt;
    | (Just (x1,bs1)) &amp;lt;- BS.uncons bs&lt;br /&gt;
    , (Just (x2,bs2)) &amp;lt;- BS.uncons bs1&lt;br /&gt;
    , (Just (x3,bs3)) &amp;lt;- BS.uncons bs2&lt;br /&gt;
    , (Just (x4,bs4)) &amp;lt;- BS.uncons bs3&lt;br /&gt;
    = huffRead&#039; 0 (word32le (x1,x2,x3,x4)) hf hf (convertBitsLE bs4)&lt;br /&gt;
    | otherwise = error &amp;quot;huffRead: Less than 4 bytes in chunk.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
-- Usage:&lt;br /&gt;
-- huffRead&#039; &amp;lt;# of bytes output&amp;gt; &amp;lt;total # of bytes&amp;gt; &amp;lt;current position in HuffTree&amp;gt; &amp;lt;full HuffTree&amp;gt; &amp;lt;input bit stream&amp;gt;&lt;br /&gt;
-- More Details:&lt;br /&gt;
-- &amp;lt;# of bytes output&amp;gt;            : The number of bytes output from reading the input stream.&lt;br /&gt;
--                                  When this reaches the total # of bytes, the original data&lt;br /&gt;
--                                  has all been extracted&lt;br /&gt;
-- &amp;lt;total # of bytes&amp;gt;             : The total number of bytes&lt;br /&gt;
-- &amp;lt;current position in HuffTree&amp;gt; : A sub-Huffman Tree, representing the current position&lt;br /&gt;
--                                  e.g. If you start with the full tree, and then read a 1,&lt;br /&gt;
--                                  you&#039;ll get the right subtree.&lt;br /&gt;
-- &amp;lt;full HuffTree&amp;gt;                : The full Huffman Tree.&lt;br /&gt;
-- &amp;lt;input bit stream&amp;gt;             : A list of Bools, converted from a bytestring.&lt;br /&gt;
huffRead&#039; :: Word32 -&amp;gt; Word32 -&amp;gt; (HuffTree a) -&amp;gt; (HuffTree a) -&amp;gt; [Bool] -&amp;gt; [a]&lt;br /&gt;
huffRead&#039; cntr mx           _   _ []&lt;br /&gt;
    | (cntr == mx) = []&lt;br /&gt;
    | otherwise    = error &amp;quot;huffRead: Ran out of bits to read.&amp;quot;&lt;br /&gt;
huffRead&#039; cntr mx (HuffLeaf x) hf bls = (x:(huffRead&#039; (cntr+1) mx hf hf bls))&lt;br /&gt;
huffRead&#039; cntr mx (HuffNode l r) hf (bl:bls)&lt;br /&gt;
    | (cntr  == mx) = [] -- end if the number of output bytes has been reached.&lt;br /&gt;
    | (bl ==  True) = huffRead&#039; cntr mx r hf bls&lt;br /&gt;
    | (bl == False) = huffRead&#039; cntr mx l hf bls&lt;br /&gt;
    | otherwise     = error &amp;quot;huffRead: Apparently the law of the excluded middle doesn&#039;t hold.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
-- Example IO Operation&lt;br /&gt;
&lt;br /&gt;
-- Take a compressed chunk, and decode it.&lt;br /&gt;
huffDecode :: FilePath -&amp;gt; FilePath -&amp;gt; FilePath -&amp;gt; IO ()&lt;br /&gt;
huffDecode dct inf outf = do&lt;br /&gt;
    { hf &amp;lt;- readHuffTree &amp;lt;$&amp;gt; BS.readFile dct&lt;br /&gt;
    ; bs &amp;lt;- BS.readFile inf&lt;br /&gt;
    ; op &amp;lt;- return $ BS.pack $ huffRead hf bs&lt;br /&gt;
    ; BS.writeFile outf op&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
-- Take a list of compressed chunks, and decode it.&lt;br /&gt;
huffDecodes :: FilePath -&amp;gt; [(FilePath,FilePath)] -&amp;gt; IO ()&lt;br /&gt;
huffDecodes dct fps = do&lt;br /&gt;
    { hf &amp;lt;- readHuffTree &amp;lt;$&amp;gt; BS.readFile dct&lt;br /&gt;
    ; mapM_ (\(inf,outf) -&amp;gt; do {op &amp;lt;- BS.pack &amp;lt;$&amp;gt; huffRead hf &amp;lt;$&amp;gt; BS.readFile inf ; BS.writeFile outf op}) fps&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
-- Example Usage:&lt;br /&gt;
-- huffDecodes &amp;quot;AUDIODCT.CK5&amp;quot; [(&amp;quot;song_0001.imf&amp;quot;,&amp;quot;extr_song_0001.imf&amp;quot;),(&amp;quot;song_0002.imf&amp;quot;,&amp;quot;extr_song_0002.imf&amp;quot;),(&amp;quot;song_0003.imf&amp;quot;,&amp;quot;extr_song_0003.imf&amp;quot;)]&lt;br /&gt;
-- where song_0001.imf etc... are compressed chunks extracted from &amp;quot;AUDIO.CK5&amp;quot; using the offsets in &amp;quot;AUDIOHED.CK5&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Code examples]]&lt;/div&gt;</summary>
		<author><name>QuirkyM</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=8373</id>
		<title>Huffman Compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=8373"/>
		<updated>2019-03-01T16:53:09Z</updated>

		<summary type="html">&lt;p&gt;QuirkyM: Added Example Code in Haskell&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Compression Infobox&lt;br /&gt;
 | Type = Stream&lt;br /&gt;
 | UnitSize = 1-byte in, 1-bit out&lt;br /&gt;
 | Games =&lt;br /&gt;
   {{Game|The Blues Brothers}}&lt;br /&gt;
   {{Game|Catacomb 3-D}}&lt;br /&gt;
   {{Game|Commander Keen Dreams}}&lt;br /&gt;
   {{Game|Dangerous Dave 2}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[Huffman Compression]] is a compression algorithm used in many classic games. It is about as efficient as LZW or RLE compression, with many games using the three formats simultaneously.&lt;br /&gt;
&lt;br /&gt;
Huffman compression involves changing how various characters are stored. Normally all characters in a given segment of data are equal and take an equal amount of space to store. However by making more common characters take up less space while allowing less commonly used characters to take up more the overall size of a segment of data can be reduced. Any Huffman compressed data will thus be associated with a dictionary file (internal or external) used to decompress it. This page will go through each aspect of Huffman compression in a stepwise manner before presenting some examples of usage and source code.&lt;br /&gt;
&lt;br /&gt;
==Frequency tables==&lt;br /&gt;
&lt;br /&gt;
To illustrate the various aspects of Huffman compression the example text &amp;quot;She sells seashells by the sea shore.&amp;quot; will be Huffman compressed and the processes and outputs shown in various sections on this page.&lt;br /&gt;
&lt;br /&gt;
In order to compress data using Huffman compression the compressor must first build a &#039;frequency table&#039; of all the elements it wishes to compress. In most cases this will be the 256 values a single byte can take, though it need not be limited to this. (Due to the binary nature of the compression method, sets of elements that match powers of 2 are both easiest and most efficient to compress.) The data is scanned and each occurrence of a given value. Taking the letters in our example sentence we can construct the following frequency table:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 Char   Freq&lt;br /&gt;
 &#039;s&#039;      7&lt;br /&gt;
 &#039;e&#039;      7&lt;br /&gt;
 &#039; &#039;      6&lt;br /&gt;
 &#039;h&#039;      4&lt;br /&gt;
 &#039;l&#039;      4&lt;br /&gt;
 &#039;a&#039;      2&lt;br /&gt;
 &#039;S&#039;      1&lt;br /&gt;
 &#039;b&#039;      1&lt;br /&gt;
 &#039;o&#039;      1&lt;br /&gt;
 &#039;r&#039;      1&lt;br /&gt;
 &#039;t&#039;      1&lt;br /&gt;
 &#039;y&#039;      1&lt;br /&gt;
 &#039;.&#039;      1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==The Binary Tree==&lt;br /&gt;
&lt;br /&gt;
The binary tree is core to how Huffman compression compresses data. This is done by constructing a &#039;binary tree&#039;, so named because of its branching structure. Each branching point or &#039;node&#039; has two options, &#039;left&#039; and &#039;right&#039; which lead either to another node or a character. The tree is constructed so that every character can be placed upon it and every path ends in a character. &lt;br /&gt;
&lt;br /&gt;
This is done by first building a point of origin, &#039;root node&#039; and the adding further nodes from there. Using our example we can build the following binary tree simply by listing the nodes alphabetically (and using &#039;_&#039; to stand in for the space for clarity):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
           [Root]&lt;br /&gt;
         ____|_______&lt;br /&gt;
       /             \&lt;br /&gt;
     __|__            |&lt;br /&gt;
    /      \        /   \&lt;br /&gt;
    |       |       |    .&lt;br /&gt;
  /   \   /   \   /   \&lt;br /&gt;
  |   |   |   |   |   |&lt;br /&gt;
 / \ / \ / \ / \ / \ / \&lt;br /&gt;
 _ S a b e h l o r s t y&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On this tree we can use &#039;L&#039; to specify a left path and &#039;R&#039; to specify a right. As such the letter &#039;a&#039; is represented by &#039;LLRL&#039; and &#039;y&#039; by &#039;RLRR&#039;. Note that since the number of different characters is not a power of two (E.g. 16) not all paths from the root to a character are the same length, one is considerably shorter. The &#039;.&#039; character is represented by simply &#039;RR&#039;&lt;br /&gt;
&lt;br /&gt;
Assuming that &#039;R&#039; and &#039;L&#039; are &#039;0&#039; and &#039;1&#039; each 8-bit character in the original text can be represented by just 4 bits on average, halving the message length. This is far from optimal however and there is a specific procedure used to construct an optimal tree for the shortest message length. To do this advantage is taken of the fact that paths can be different lengths. If one set of paths is made a bit shorter at the expense of making a smaller set of paths a bit longer then the overall message will be made shorter.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Constructing an optimal tree===&lt;br /&gt;
&lt;br /&gt;
The first step in creating an optimal tree again is to create a &#039;root node&#039;. To populate its two options the compressor repeatedly divides the frequency table. This is done by starting with the most common character and seeing if it contains more occurrences than the rest of the table combined. If not then the second most common character is added and so on.&lt;br /&gt;
&lt;br /&gt;
In our example there are a total of 37 characters. Three characters make up more than half of this, &#039;s&#039;, &#039;e&#039; and &#039; &#039;. Because of the binary structure of the tree however &#039;&#039;four&#039;&#039; options are needed here so &#039;h&#039; is also included. All of these characters are placed on the left option of the root node while the remaining characters are placed on the right.&lt;br /&gt;
&lt;br /&gt;
The next step creates a new node with left and right options and repeats the process. The two most common characters of the four, &#039;s&#039; and &#039;e&#039; go to the left branch of this new node. A third node is created and, now that there are only two options, each is given a branch. The tree now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [Root]&lt;br /&gt;
    / \&lt;br /&gt;
    |  l, a, etc&lt;br /&gt;
   / \&lt;br /&gt;
   | _, h&lt;br /&gt;
 /  \&lt;br /&gt;
 s  e&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now the character &#039;s&#039; can be represented as LLL and &#039;e&#039; as LLR.&lt;br /&gt;
&lt;br /&gt;
The compressor now moves &#039;up&#039; to the previous node which still has a branch with more than one option in it. Another node is created and, since there are only two options, one is assigned to each branch. Te compressor then returns to the root node to deal with the right half of the tree. When it has assigned very character to a node the following optimal tree is produced:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      ___[Root]____&lt;br /&gt;
     /             \&lt;br /&gt;
    _|_         ___|_______&lt;br /&gt;
   /   \       /           \&lt;br /&gt;
   |   |       |            |&lt;br /&gt;
 /  \ / \     / \          / \&lt;br /&gt;
 s  e _ h    l   |        |   |&lt;br /&gt;
                / \      / \ / \&lt;br /&gt;
               a  |      o r t |&lt;br /&gt;
                 / \          / \&lt;br /&gt;
                 S b         y  .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that 4 characters now have paths that are just 3 choices long while 4 have paths 4 choices long and 4 have paths 5 choices long. Overall the average path length is the same as our previous tree. However 24 occurrences are one choice shorter, 5 are identical,  3 are one choice longer and &#039;.&#039; is three choices longer. This gives us a compressed message that is  a total of 18 choices (or bits) shorter.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Labeling the tree===&lt;br /&gt;
&lt;br /&gt;
Now that a tree has been constructed it needs to be labelled in some form so that it can be stored as data either in the decompressor or to be sent with the compressed code. There are two major issues, what system to use when assigning numbers to the various nodes, and what bit value, 0 or 1, to assign to left or right options.&lt;br /&gt;
&lt;br /&gt;
The most common (but far from unique) system is to label nodes from the &#039;bottom&#039; of the tree to the top, going left-to-right across each &#039;layer&#039; of the tree. (In our example the node that leads to &#039;S&#039; and &#039;b&#039; would thus be the first numbered node.) Nodes are usually numbered starting with 0 and ending with the root node having the highest number. Our tree would be numbered as follows using this system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      ____[11]_____&lt;br /&gt;
     /             \&lt;br /&gt;
    [9]         __[10]_____&lt;br /&gt;
   /   \       /           \&lt;br /&gt;
  [5] [6]     [7]          [8]&lt;br /&gt;
 /  \ / \     / \          / \&lt;br /&gt;
 s  e _ h    l  [2]      [3] [4]&lt;br /&gt;
                / \      / \ / \&lt;br /&gt;
               a [0]     o r t[1]&lt;br /&gt;
                 / \          / \&lt;br /&gt;
                 S b         y  .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usually the left branch is given a bit value of 0 and the right branch a bit value of 1. Using this scheme &#039;s&#039; in our example resides on node 1 and is represented by the bit string &#039;000&#039; The complete compressed message in bit form is now &amp;lt;tt&amp;gt;10110 011 001 010 000 001 100 100 000 010 000 001 1010 000 011 001 100 100 000 010 10111 11110 010 1110 011 001 010 000 001 1010 010 000 011 1100 1101 001 11111&amp;lt;/tt&amp;gt; or in bytes &amp;lt;tt&amp;gt;$B3 $28 $19 $02 $06 $83 $32 $05 $7F $2E $65 $03 $48 $3C $D3 $F0&amp;lt;/tt&amp;gt; (The final byte is padded with nul bits.) This is a total of 16 bytes used for a 37 byte message.&lt;br /&gt;
&lt;br /&gt;
===Standard tree size===&lt;br /&gt;
&lt;br /&gt;
The most common implementation of Huffman compression is &#039;1 byte in, 1 bit out&#039;. This involves compressing one byte of data at a time and converting it into a bitstream. In this case the compressor expects to find 256 different possible values of data. This requires a tree with 255 nodes, including the root, and an average path length of 8 choices.&lt;br /&gt;
&lt;br /&gt;
This is not the only possibility however and Huffman can compress data in words or dwords or in more exotic manners. {{Game|Commander Keen Dreams}} for example combines Huffman with LZW compression, building a binary tree of a fixed size and filling it with the most recently encountered strings of bits.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==The dictionary==&lt;br /&gt;
&lt;br /&gt;
Often the binary tree must be stored in some form, usually called a &#039;&#039;dictionary&#039;&#039;. This will either be fixed and known by both the compressor and decompressor. (Which minimizes individual message sizes but can limit compression efficiency overall.) or tailored for each message and sent with said message.&lt;br /&gt;
&lt;br /&gt;
Dictionary format is quite standard. It is merely a numerical list of nodes (however they have been labelled.) starting with node 0 and ending with the root. Each node usually taking up four bytes, two bytes per branch. Each branch will have one byte dedicated to identifying if it leads to another node or a character and the other byte identifying the node or character. Usually &#039;0&#039; identifies the option asleading to a character and &#039;1&#039; to another node, but again this can be reversed.&lt;br /&gt;
&lt;br /&gt;
Using this system, our example tree could be stored as either of the two following:&lt;br /&gt;
&lt;br /&gt;
    0S0b 0y0. 0a10 0o0r 0t11 0s0e 0_0h 0l12 1314 1516 1718 19110&lt;br /&gt;
&lt;br /&gt;
    $00 $53 $00 $62 $00 $79 $00 $2E $00 $6F $00 $72 $00 $74 $01 $01 $00 $73 $00 $65 $00 $20 $00 $68...&lt;br /&gt;
     -   S   -   b   -   y   -   .   -   o   -   r   -   t   |  n1   -   s    -  e   -   _   -   h ...&lt;br /&gt;
         (node 0)         (node 1)       (node 3)        (node 4)        (node 5)      (node 6)    ...&lt;br /&gt;
    &lt;br /&gt;
The dictionary is thus usually 1020 bytes long, containing 255 nodes of 4 bytes each, though again this can vary depending on how readable the dictionary is to humans and whether or not the dictionary itself is compressed.&lt;br /&gt;
&lt;br /&gt;
==Huffman implementation in ID Software games==&lt;br /&gt;
&lt;br /&gt;
Games created by Id Software  have a shared but distinct implementation of Huffman compression.&lt;br /&gt;
&lt;br /&gt;
In older games such as {{Game|Dangerous Dave 2}} the dictionary and data are included together in one file. First is a four-byte header,, &#039;HUFF&#039; followed by four bytes that give the decompressed size of the data (for memory purposes.). Following that is the dictionary, 1020 bytes in length then the compressed data.&lt;br /&gt;
&lt;br /&gt;
In newer games (such as [[Commander Keen 4-6]] or [[Wolfenstein 3-D]]) the data is stored in an external file which consists of a number of concatenated &#039;chunks&#039;, each chunk beginning with a dword giving its decompressed size (again for memory purposes.). These chunks are addressed by an internal or external &#039;header&#039; file consisting of a series of three (or sometimes four) byte offsets to the start of various chunks in the data file. (The end of the header is easily found as the last entry is the length of the data file.) The dictionary is 1024 bytes long and stored in the executable.&lt;br /&gt;
&lt;br /&gt;
The dictionary consists of 255 nodes (in newr games plus four null bytes of padding) and there are two or three dictionaries stored in the executable depending on the game. The end of these dictionaries can be found by looking for node 255 (number 254!) which universally consists of the string &amp;lt;tt&amp;gt;$00 $00 $FD $01&amp;lt;/tt&amp;gt; due to the fact that the byte &amp;lt;tt&amp;gt;$00&amp;lt;/tt&amp;gt; is the single most common character in game data and thus always occupies the left branch of the root node while the other branch must go to the next lowest node, number 253.&lt;br /&gt;
&lt;br /&gt;
An important but subtle difference is how data is read. While bytes are read sequentially (1, 2, 3...) bits within each byte are read in reverse order (8, 7, 6...). (Technically each byte is little endian.)&lt;br /&gt;
&lt;br /&gt;
===Trivial ID dictionary===&lt;br /&gt;
&lt;br /&gt;
The following is a complete &#039;trivial&#039; dictionary. This dictionary is constructed such that data compressed with it is not altered in any way, the output and input are the same. When used to construct a binary tree all paths are of equal length, 8 choices or bits. And the nodes are arranged in a logical order with an easily seen pattern; the first half of the tree consists of terminal nodes, the second half of branch nodes. (Of the second half the first half of &#039;&#039;that&#039;&#039; consists of branch nodes that lead to terminal nodes while the second half consists of branch nodes to two branch nodes and so on.)&lt;br /&gt;
&lt;br /&gt;
 $00 $00 $80 $00 $40 $00 $C0 $00 $20 $00 $A0 $00 $60 $00 $E0 $00&lt;br /&gt;
 $10 $00 $90 $00 $50 $00 $D0 $00 $30 $00 $B0 $00 $70 $00 $F0 $00&lt;br /&gt;
 $08 $00 $88 $00 $48 $00 $C8 $00 $28 $00 $A8 $00 $68 $00 $E8 $00&lt;br /&gt;
 $18 $00 $98 $00 $58 $00 $D8 $00 $38 $00 $B8 $00 $78 $00 $F8 $00&lt;br /&gt;
 $04 $00 $84 $00 $44 $00 $C4 $00 $24 $00 $A4 $00 $64 $00 $E4 $00&lt;br /&gt;
 $14 $00 $94 $00 $54 $00 $D4 $00 $34 $00 $B4 $00 $74 $00 $F4 $00&lt;br /&gt;
 $0C $00 $8C $00 $4C $00 $CC $00 $2C $00 $AC $00 $6C $00 $EC $00&lt;br /&gt;
 $1C $00 $9C $00 $5C $00 $DC $00 $3C $00 $BC $00 $7C $00 $FC $00&lt;br /&gt;
 $02 $00 $82 $00 $42 $00 $C2 $00 $22 $00 $A2 $00 $62 $00 $E2 $00&lt;br /&gt;
 $12 $00 $92 $00 $52 $00 $D2 $00 $32 $00 $B2 $00 $72 $00 $F2 $00&lt;br /&gt;
 $0A $00 $8A $00 $4A $00 $CA $00 $2A $00 $AA $00 $6A $00 $EA $00&lt;br /&gt;
 $1A $00 $9A $00 $5A $00 $DA $00 $3A $00 $BA $00 $7A $00 $FA $00&lt;br /&gt;
 $06 $00 $86 $00 $46 $00 $C6 $00 $26 $00 $A6 $00 $66 $00 $E6 $00&lt;br /&gt;
 $16 $00 $96 $00 $56 $00 $D6 $00 $36 $00 $B6 $00 $76 $00 $F6 $00&lt;br /&gt;
 $0E $00 $8E $00 $4E $00 $CE $00 $2E $00 $AE $00 $6E $00 $EE $00&lt;br /&gt;
 $1E $00 $9E $00 $5E $00 $DE $00 $3E $00 $BE $00 $7E $00 $FE $00&lt;br /&gt;
 $01 $00 $81 $00 $41 $00 $C1 $00 $21 $00 $A1 $00 $61 $00 $E1 $00&lt;br /&gt;
 $11 $00 $91 $00 $51 $00 $D1 $00 $31 $00 $B1 $00 $71 $00 $F1 $00&lt;br /&gt;
 $09 $00 $89 $00 $49 $00 $C9 $00 $29 $00 $A9 $00 $69 $00 $E9 $00&lt;br /&gt;
 $19 $00 $99 $00 $59 $00 $D9 $00 $39 $00 $B9 $00 $79 $00 $F9 $00&lt;br /&gt;
 $05 $00 $85 $00 $45 $00 $C5 $00 $25 $00 $A5 $00 $65 $00 $E5 $00&lt;br /&gt;
 $15 $00 $95 $00 $55 $00 $D5 $00 $35 $00 $B5 $00 $75 $00 $F5 $00&lt;br /&gt;
 $0D $00 $8D $00 $4D $00 $CD $00 $2D $00 $AD $00 $6D $00 $ED $00&lt;br /&gt;
 $1D $00 $9D $00 $5D $00 $DD $00 $3D $00 $BD $00 $7D $00 $FD $00&lt;br /&gt;
 $03 $00 $83 $00 $43 $00 $C3 $00 $23 $00 $A3 $00 $63 $00 $E3 $00&lt;br /&gt;
 $13 $00 $93 $00 $53 $00 $D3 $00 $33 $00 $B3 $00 $73 $00 $F3 $00&lt;br /&gt;
 $0B $00 $8B $00 $4B $00 $CB $00 $2B $00 $AB $00 $6B $00 $EB $00&lt;br /&gt;
 $1B $00 $9B $00 $5B $00 $DB $00 $3B $00 $BB $00 $7B $00 $FB $00&lt;br /&gt;
 $07 $00 $87 $00 $47 $00 $C7 $00 $27 $00 $A7 $00 $67 $00 $E7 $00&lt;br /&gt;
 $17 $00 $97 $00 $57 $00 $D7 $00 $37 $00 $B7 $00 $77 $00 $F7 $00&lt;br /&gt;
 $0F $00 $8F $00 $4F $00 $CF $00 $2F $00 $AF $00 $6F $00 $EF $00&lt;br /&gt;
 $1F $00 $9F $00 $5F $00 $DF $00 $3F $00 $BF $00 $7F $00 $FF $00&lt;br /&gt;
 $00 $01 $01 $01 $02 $01 $03 $01 $04 $01 $05 $01 $06 $01 $07 $01&lt;br /&gt;
 $08 $01 $09 $01 $0A $01 $0B $01 $0C $01 $0D $01 $0E $01 $0F $01&lt;br /&gt;
 $10 $01 $11 $01 $12 $01 $13 $01 $14 $01 $15 $01 $16 $01 $17 $01&lt;br /&gt;
 $18 $01 $19 $01 $1A $01 $1B $01 $1C $01 $1D $01 $1E $01 $1F $01&lt;br /&gt;
 $20 $01 $21 $01 $22 $01 $23 $01 $24 $01 $25 $01 $26 $01 $27 $01&lt;br /&gt;
 $28 $01 $29 $01 $2A $01 $2B $01 $2C $01 $2D $01 $2E $01 $2F $01&lt;br /&gt;
 $30 $01 $31 $01 $32 $01 $33 $01 $34 $01 $35 $01 $36 $01 $37 $01&lt;br /&gt;
 $38 $01 $39 $01 $3A $01 $3B $01 $3C $01 $3D $01 $3E $01 $3F $01&lt;br /&gt;
 $40 $01 $41 $01 $42 $01 $43 $01 $44 $01 $45 $01 $46 $01 $47 $01&lt;br /&gt;
 $48 $01 $49 $01 $4A $01 $4B $01 $4C $01 $4D $01 $4E $01 $4F $01&lt;br /&gt;
 $50 $01 $51 $01 $52 $01 $53 $01 $54 $01 $55 $01 $56 $01 $57 $01&lt;br /&gt;
 $58 $01 $59 $01 $5A $01 $5B $01 $5C $01 $5D $01 $5E $01 $5F $01&lt;br /&gt;
 $60 $01 $61 $01 $62 $01 $63 $01 $64 $01 $65 $01 $66 $01 $67 $01&lt;br /&gt;
 $68 $01 $69 $01 $6A $01 $6B $01 $6C $01 $6D $01 $6E $01 $6F $01&lt;br /&gt;
 $70 $01 $71 $01 $72 $01 $73 $01 $74 $01 $75 $01 $76 $01 $77 $01&lt;br /&gt;
 $78 $01 $79 $01 $7A $01 $7B $01 $7C $01 $7D $01 $7E $01 $7F $01&lt;br /&gt;
 $80 $01 $81 $01 $82 $01 $83 $01 $84 $01 $85 $01 $86 $01 $87 $01&lt;br /&gt;
 $88 $01 $89 $01 $8A $01 $8B $01 $8C $01 $8D $01 $8E $01 $8F $01&lt;br /&gt;
 $90 $01 $91 $01 $92 $01 $93 $01 $94 $01 $95 $01 $96 $01 $97 $01&lt;br /&gt;
 $98 $01 $99 $01 $9A $01 $9B $01 $9C $01 $9D $01 $9E $01 $9F $01&lt;br /&gt;
 $A0 $01 $A1 $01 $A2 $01 $A3 $01 $A4 $01 $A5 $01 $A6 $01 $A7 $01&lt;br /&gt;
 $A8 $01 $A9 $01 $AA $01 $AB $01 $AC $01 $AD $01 $AE $01 $AF $01&lt;br /&gt;
 $B0 $01 $B1 $01 $B2 $01 $B3 $01 $B4 $01 $B5 $01 $B6 $01 $B7 $01&lt;br /&gt;
 $B8 $01 $B9 $01 $BA $01 $BB $01 $BC $01 $BD $01 $BE $01 $BF $01&lt;br /&gt;
 $C0 $01 $C1 $01 $C2 $01 $C3 $01 $C4 $01 $C5 $01 $C6 $01 $C7 $01&lt;br /&gt;
 $C8 $01 $C9 $01 $CA $01 $CB $01 $CC $01 $CD $01 $CE $01 $CF $01&lt;br /&gt;
 $D0 $01 $D1 $01 $D2 $01 $D3 $01 $D4 $01 $D5 $01 $D6 $01 $D7 $01&lt;br /&gt;
 $D8 $01 $D9 $01 $DA $01 $DB $01 $DC $01 $DD $01 $DE $01 $DF $01&lt;br /&gt;
 $E0 $01 $E1 $01 $E2 $01 $E3 $01 $E4 $01 $E5 $01 $E6 $01 $E7 $01&lt;br /&gt;
 $E8 $01 $E9 $01 $EA $01 $EB $01 $EC $01 $ED $01 $EE $01 $EF $01&lt;br /&gt;
 $F0 $01 $F1 $01 $F2 $01 $F3 $01 $F4 $01 $F5 $01 $F6 $01 $F7 $01&lt;br /&gt;
 $F8 $01 $F9 $01 $FA $01 $FB $01 $FC $01 $FD $01&lt;br /&gt;
&lt;br /&gt;
Using this example we can see the unusual manner in which ID games read bits within bytes. As an example consider the character $80; in binary this is &#039;10000000&#039; However, following this path using the dictionary given above will output the character $01 (00000001). Instead the bits must be read in reverse order. Doing so will lead to the following nodes starting at the root node: 254(root) -&amp;gt; 252 -&amp;gt; 248 -&amp;gt; 240 -&amp;gt; 224 -&amp;gt; 192 -&amp;gt; 128 -&amp;gt; 0(terminal node for characters $00 and $80)&lt;br /&gt;
&lt;br /&gt;
== Source code ==&lt;br /&gt;
&lt;br /&gt;
Some example code is available in various languages showing how to decompress (and in some cases compress) files using the Huffman algorithm.&lt;br /&gt;
&lt;br /&gt;
=== QuickBasic ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;qbasic&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&lt;br /&gt;
&#039; DANGEROUS DAVE 2 - IN THE HAUNTED MANSION - Huffman Decompressor&lt;br /&gt;
&#039;  - by Napalm with thanks to Adurdin&#039;s work on ModKeen&lt;br /&gt;
&#039;&lt;br /&gt;
&#039; This source is Public Domain, please credit me if you use it.&lt;br /&gt;
&#039;&lt;br /&gt;
&#039;&lt;br /&gt;
DECLARE SUB HUFFDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING)&lt;br /&gt;
&lt;br /&gt;
TYPE NODE&lt;br /&gt;
        BIT0 AS INTEGER&lt;br /&gt;
        BIT1 AS INTEGER&lt;br /&gt;
END TYPE&lt;br /&gt;
&lt;br /&gt;
&#039; Input filename, output filename&lt;br /&gt;
HUFFDECOMPRESS &amp;quot;TITLE1.DD2&amp;quot;, &amp;quot;TITLE1.PIC&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SUB HUFFDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING) &#039; by Napalm&lt;br /&gt;
	DIM INFILE AS INTEGER, OUTFILE AS INTEGER, I AS INTEGER&lt;br /&gt;
	DIM SIG AS LONG, OUTLEN AS LONG, BITMASK AS INTEGER&lt;br /&gt;
	DIM CURNODE AS INTEGER, NEXTNODE AS INTEGER&lt;br /&gt;
	DIM CHRIN AS STRING * 1, CHROUT AS STRING * 1&lt;br /&gt;
	DIM NODES(0 TO 254) AS NODE&lt;br /&gt;
&lt;br /&gt;
	&#039; Open input file&lt;br /&gt;
	INFILE = FREEFILE&lt;br /&gt;
	OPEN INNAME FOR BINARY ACCESS READ AS INFILE&lt;br /&gt;
       &lt;br /&gt;
	&#039; Check file signature&lt;br /&gt;
	GET INFILE, , SIG&lt;br /&gt;
	IF SIG &amp;lt;&amp;gt; &amp;amp;H46465548 THEN &#039; Hex for: HUFF in little endian&lt;br /&gt;
		PRINT &amp;quot;INVALID FILE!&amp;quot;&lt;br /&gt;
		EXIT SUB&lt;br /&gt;
	END IF&lt;br /&gt;
       &lt;br /&gt;
	&#039; Get output length&lt;br /&gt;
	OUTLEN = 0&lt;br /&gt;
	GET INFILE, , OUTLEN&lt;br /&gt;
       &lt;br /&gt;
	&#039; Read in the Huffman binary tree&lt;br /&gt;
	FOR I = 0 TO 254&lt;br /&gt;
		GET INFILE, , NODES(I).BIT0&lt;br /&gt;
		GET INFILE, , NODES(I).BIT1&lt;br /&gt;
	NEXT I&lt;br /&gt;
&lt;br /&gt;
	&#039; Open output file&lt;br /&gt;
	OUTFILE = FREEFILE&lt;br /&gt;
	OPEN OUTNAME FOR BINARY ACCESS WRITE AS OUTFILE&lt;br /&gt;
&lt;br /&gt;
	&#039; Decompress input data using binary tree&lt;br /&gt;
	CURNODE = 254&lt;br /&gt;
	DO&lt;br /&gt;
		BITMASK = 0&lt;br /&gt;
		GET INFILE, , CHRIN&lt;br /&gt;
		DO&lt;br /&gt;
			&#039; Decide which node to travel down depending on&lt;br /&gt;
			&#039;   input bits from CHRIN.&lt;br /&gt;
			IF ASC(CHRIN) AND 2 ^ BITMASK THEN&lt;br /&gt;
				NEXTNODE = NODES(CURNODE).BIT1&lt;br /&gt;
			ELSE&lt;br /&gt;
				NEXTNODE = NODES(CURNODE).BIT0&lt;br /&gt;
			END IF&lt;br /&gt;
		       &lt;br /&gt;
			&#039; Is this next node another part of the tree or&lt;br /&gt;
			&#039;   is it a end node? Less than 256 mean end node.&lt;br /&gt;
			IF NEXTNODE &amp;lt; 256 THEN&lt;br /&gt;
			       &lt;br /&gt;
				&#039; Get output char from end node and save.&lt;br /&gt;
				CHROUT = CHR$(NEXTNODE AND &amp;amp;HFF)&lt;br /&gt;
				PUT OUTFILE, , CHROUT&lt;br /&gt;
			       &lt;br /&gt;
				&#039; Amend output length and start from top of&lt;br /&gt;
				&#039;   binary tree.&lt;br /&gt;
				OUTLEN = OUTLEN - 1&lt;br /&gt;
				CURNODE = 254&lt;br /&gt;
&lt;br /&gt;
			ELSE&lt;br /&gt;
				&#039; Travel to next node&lt;br /&gt;
				CURNODE = (NEXTNODE AND &amp;amp;HFF)&lt;br /&gt;
&lt;br /&gt;
			END IF&lt;br /&gt;
&lt;br /&gt;
			&#039; Move to next input bit&lt;br /&gt;
			BITMASK = BITMASK + 1&lt;br /&gt;
		LOOP WHILE BITMASK &amp;lt; 8 AND OUTLEN &amp;gt; 0&lt;br /&gt;
		&#039; Loop while we still need to output data&lt;br /&gt;
	LOOP WHILE OUTLEN &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
	&#039; Clean up&lt;br /&gt;
	CLOSE OUTFILE&lt;br /&gt;
	CLOSE INFILE&lt;br /&gt;
&lt;br /&gt;
END SUB&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;qbasic&amp;quot;&amp;gt;&lt;br /&gt;
SUB MAKHUF &#039;Mak a degenerate huffman tree, store as string huffq&lt;br /&gt;
	OPEN &amp;quot;HUFF.DD2&amp;quot; FOR BINARY AS #8&lt;br /&gt;
	aq = &amp;quot;HUFF&amp;quot;&lt;br /&gt;
	PUT #8, 1, aq&lt;br /&gt;
	x = 9&lt;br /&gt;
	FOR t = 0 TO 255&lt;br /&gt;
		b = t&lt;br /&gt;
		va = 0&lt;br /&gt;
		vb = 0&lt;br /&gt;
		vc = 0&lt;br /&gt;
		vd = 0&lt;br /&gt;
		ve = 0&lt;br /&gt;
		vf = 0&lt;br /&gt;
		vg = 0&lt;br /&gt;
		vh = 0&lt;br /&gt;
		IF b &amp;gt; 127 THEN LET va = va + 1&lt;br /&gt;
		b = b MOD 128&lt;br /&gt;
		IF b &amp;gt; 63 THEN LET vb = vb + 1&lt;br /&gt;
		b = b MOD 64&lt;br /&gt;
		IF b &amp;gt; 31 THEN LET vc = vc + 1&lt;br /&gt;
		b = b MOD 32&lt;br /&gt;
		IF b &amp;gt; 15 THEN LET vd = vd + 1&lt;br /&gt;
		b = b MOD 16&lt;br /&gt;
		IF b &amp;gt; 7 THEN LET ve = ve + 1&lt;br /&gt;
		b = b MOD 8&lt;br /&gt;
		IF b &amp;gt; 3 THEN LET vf = vf + 1&lt;br /&gt;
		b = b MOD 4&lt;br /&gt;
		IF b &amp;gt; 1 THEN LET vg = vg + 1&lt;br /&gt;
		b = b MOD 2&lt;br /&gt;
		IF b = 1 THEN LET vh = vh + 1&lt;br /&gt;
		b = (vh * 128) + (vg * 64) + (vf * 32) + (16 * ve) + (8 * vd) + (4 * vc) + (2 * vb) + va&lt;br /&gt;
		aq = MKI$(b)&lt;br /&gt;
		PUT #8, x, aq&lt;br /&gt;
		x = x + 2&lt;br /&gt;
	NEXT t&lt;br /&gt;
	FOR t = 0 TO 253&lt;br /&gt;
		aq = MKI$(t + 256)&lt;br /&gt;
		PUT #8, x, aq&lt;br /&gt;
		x = x + 2&lt;br /&gt;
	NEXT t&lt;br /&gt;
	GET #8, 1, huffq&lt;br /&gt;
	CLOSE #8&lt;br /&gt;
	KILL &amp;quot;HUFF.DD2&amp;quot;&lt;br /&gt;
END SUB&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Visual Basic .NET ===&lt;br /&gt;
&lt;br /&gt;
==== Huffman tree representation ====&lt;br /&gt;
&lt;br /&gt;
This class, BinaryTreeNode, represents a binary tree whose branch nodes carry no value, like a Huffman dictionary tree.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vbnet&amp;quot;&amp;gt;Public Class BinaryTreeNode(Of T)&lt;br /&gt;
    &#039; By Fleexy, public domain, credit where credit is due&lt;br /&gt;
    Private Branch As Boolean&lt;br /&gt;
    Private Children As BinaryTreeNode(Of T)()&lt;br /&gt;
    Private HoldValue As T&lt;br /&gt;
    Public Sub New(LeafValue As T)&lt;br /&gt;
        Branch = False&lt;br /&gt;
        HoldValue = LeafValue&lt;br /&gt;
    End Sub&lt;br /&gt;
    Public Sub New(LeftChild As BinaryTreeNode(Of T), RightChild As BinaryTreeNode(Of T))&lt;br /&gt;
        Branch = True&lt;br /&gt;
        Children = {LeftChild, RightChild}&lt;br /&gt;
    End Sub&lt;br /&gt;
    Public ReadOnly Property HasValue As Boolean&lt;br /&gt;
        Get&lt;br /&gt;
            Return Not Branch&lt;br /&gt;
        End Get&lt;br /&gt;
    End Property&lt;br /&gt;
    Public Property Value As T&lt;br /&gt;
        Get&lt;br /&gt;
            If Branch Then Throw New InvalidOperationException&lt;br /&gt;
            Return HoldValue&lt;br /&gt;
        End Get&lt;br /&gt;
        Set(value As T)&lt;br /&gt;
            If Branch Then Throw New InvalidOperationException&lt;br /&gt;
            HoldValue = value&lt;br /&gt;
        End Set&lt;br /&gt;
    End Property&lt;br /&gt;
    Public Property Child(Side As ChildSide) As BinaryTreeNode(Of T)&lt;br /&gt;
        Get&lt;br /&gt;
            If Not Branch Then Throw New InvalidOperationException&lt;br /&gt;
            Return Children(Side)&lt;br /&gt;
        End Get&lt;br /&gt;
        Set(value As BinaryTreeNode(Of T))&lt;br /&gt;
            If Not Branch Then Throw New InvalidOperationException&lt;br /&gt;
            Children(Side) = value&lt;br /&gt;
        End Set&lt;br /&gt;
    End Property&lt;br /&gt;
    Public Enum ChildSide As Byte&lt;br /&gt;
        Left = 0&lt;br /&gt;
        Right = 1&lt;br /&gt;
    End Enum&lt;br /&gt;
    Public ReadOnly Property Count As Integer&lt;br /&gt;
        Get&lt;br /&gt;
            If Not Branch Then Return 1&lt;br /&gt;
            Return Children(0).Count + Children(1).Count&lt;br /&gt;
        End Get&lt;br /&gt;
    End Property&lt;br /&gt;
    Public ReadOnly Property Depth As Integer&lt;br /&gt;
        Get&lt;br /&gt;
            If Not Branch Then Return 1&lt;br /&gt;
            Return Math.Max(Children(0).Depth, Children(1).Depth) + 1&lt;br /&gt;
        End Get&lt;br /&gt;
    End Property&lt;br /&gt;
    Public Overrides Function ToString() As String&lt;br /&gt;
        Return &amp;quot;{Count = &amp;quot; &amp;amp; Count &amp;amp; &amp;quot;, Depth = &amp;quot; &amp;amp; Depth &amp;amp; &amp;quot;}&amp;quot;&lt;br /&gt;
    End Function&lt;br /&gt;
End Class&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Huffman tree reading ====&lt;br /&gt;
&lt;br /&gt;
This piece of code will read in a stored Huffman dictionary in the format described at the top of this article and store it in a BinaryTreeNode(Of Byte) as shown above.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vbnet&amp;quot;&amp;gt;        &#039; By Fleexy, public domain, credit where credit is due&lt;br /&gt;
        Dim fDict As New IO.FileStream(DictionaryFile, IO.FileMode.Open)&lt;br /&gt;
        Dim raw(254) As Tuple(Of UShort, UShort)&lt;br /&gt;
        For x = 0 To 254&lt;br /&gt;
            raw(x) = Tuple.Create(ReadUShort(fDict), ReadUShort(fDict))&lt;br /&gt;
        Next&lt;br /&gt;
        fDict.Close()&lt;br /&gt;
        Dim GenerateTree As Func(Of UShort, BinaryTreeNode(Of Byte))&lt;br /&gt;
        GenerateTree = Function(NextNode As UShort) As BinaryTreeNode(Of Byte)&lt;br /&gt;
                           Dim n As Tuple(Of UShort, UShort) = raw(NextNode)&lt;br /&gt;
                           Dim a, b As BinaryTreeNode(Of Byte)&lt;br /&gt;
                           If n.Item1 &amp;lt; 256 Then&lt;br /&gt;
                               a = New BinaryTreeNode(Of Byte)(n.Item1)&lt;br /&gt;
                           Else&lt;br /&gt;
                               a = GenerateTree(n.Item1 - 256)&lt;br /&gt;
                           End If&lt;br /&gt;
                           If n.Item2 &amp;lt; 256 Then&lt;br /&gt;
                               b = New BinaryTreeNode(Of Byte)(n.Item2)&lt;br /&gt;
                           Else&lt;br /&gt;
                               b = GenerateTree(n.Item2 - 256)&lt;br /&gt;
                           End If&lt;br /&gt;
                           Return New BinaryTreeNode(Of Byte)(a, b)&lt;br /&gt;
                       End Function&lt;br /&gt;
        Dim dict As BinaryTreeNode(Of Byte) = GenerateTree(254)&lt;br /&gt;
        fDict.Close()&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Haskell ===&lt;br /&gt;
&lt;br /&gt;
Currently, you have to manually extract chunks using the offsets in AUDIOHED.***.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;haskell&amp;quot;&amp;gt;&lt;br /&gt;
-- Reading in a Huffman Tree, and using&lt;br /&gt;
-- it to decompress individual chunks.&lt;br /&gt;
-- Code by QuirkyM, format information&lt;br /&gt;
-- taken from http://www.shikadi.net/moddingwiki/Huffman_Compression&lt;br /&gt;
&lt;br /&gt;
-- This code is public domain, but please credit me&lt;br /&gt;
-- if you use it.&lt;br /&gt;
&lt;br /&gt;
import Data.Maybe&lt;br /&gt;
import Data.Word  -- Fixed-size unsigned integers&lt;br /&gt;
import Data.Bits&lt;br /&gt;
import Data.List&lt;br /&gt;
import Data.Int   -- Fixed-size signed integers&lt;br /&gt;
&lt;br /&gt;
import qualified Data.ByteString as BS&lt;br /&gt;
&lt;br /&gt;
import Data.ByteString (ByteString)&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
-- Huffman Tree data structure and related functions&lt;br /&gt;
&lt;br /&gt;
data HuffTree a = HuffNode (HuffTree a) (HuffTree a) | HuffLeaf a deriving (Show,Eq)&lt;br /&gt;
&lt;br /&gt;
-- This just counts the number of output symbols.&lt;br /&gt;
huffSize2 :: (HuffTree a) -&amp;gt; Int&lt;br /&gt;
huffSize2 (HuffNode l r) = (huffSize2 l) + (huffSize2 r)&lt;br /&gt;
huffSize2 (HuffLeaf _)   = 1&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
-- Helper Functions&lt;br /&gt;
&lt;br /&gt;
-- Find the first element that satisfies a&lt;br /&gt;
-- predicate after mapping.&lt;br /&gt;
findFirst :: (a -&amp;gt; b) -&amp;gt; (b -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; Maybe b&lt;br /&gt;
findFirst f p (x:xs)&lt;br /&gt;
    | (p $ f x) = Just $ f x&lt;br /&gt;
    | otherwise = findFirst f p xs&lt;br /&gt;
findFirst f p [] = Nothing&lt;br /&gt;
&lt;br /&gt;
-- Find the first element that satisfies a&lt;br /&gt;
-- predicate after mapping, throwing an error&lt;br /&gt;
-- if no such element is found.&lt;br /&gt;
findFirst&#039; :: String -&amp;gt; (a -&amp;gt; b) -&amp;gt; (b -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; b&lt;br /&gt;
findFirst&#039; err f p xs = fromMaybe (error err) (findFirst f p xs)&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
-- Reading Huffman Dictionary&lt;br /&gt;
&lt;br /&gt;
-- Read in a Huffman Tree&lt;br /&gt;
-- (If node 254 is not the root, try creating all&lt;br /&gt;
--  the trees until you find one with all 256 bytes)&lt;br /&gt;
readHuffTree :: ByteString -&amp;gt; HuffTree Word8&lt;br /&gt;
readHuffTree bs&lt;br /&gt;
    | (huffSize2 hf1 == 256) = hf1&lt;br /&gt;
    | otherwise              = findFirst&#039; (&amp;quot;readHuffTree: No Full Huffman Tree found.&amp;quot;) (readHuffTree&#039; bs) (\hf -&amp;gt; 256 == huffSize2 hf) [0..253]&lt;br /&gt;
    where hf1 = readHuffTree&#039; bs 254&lt;br /&gt;
&lt;br /&gt;
-- Read a Huffman Tree starting from a specific node.&lt;br /&gt;
readHuffTree&#039; :: ByteString -&amp;gt; Int -&amp;gt; HuffTree Word8&lt;br /&gt;
readHuffTree&#039; bs ind&lt;br /&gt;
    | x1 &amp;lt;- BS.index bs (4 * ind)&lt;br /&gt;
    , x2 &amp;lt;- BS.index bs (1 + (4 * ind))&lt;br /&gt;
    , y1 &amp;lt;- BS.index bs (2 + (4 * ind))&lt;br /&gt;
    , y2 &amp;lt;- BS.index bs (3 + (4 * ind))&lt;br /&gt;
    = HuffNode (huffChoice x1 x2 bs) (huffChoice y1 y2 bs)&lt;br /&gt;
&lt;br /&gt;
-- Pattern match on one side of a node&lt;br /&gt;
huffChoice :: Word8 -&amp;gt; Word8 -&amp;gt; ByteString -&amp;gt; HuffTree Word8&lt;br /&gt;
huffChoice x 0x01 bs = readHuffTree&#039; bs (fromIntegral x)&lt;br /&gt;
huffChoice c 0x00 bs = HuffLeaf c&lt;br /&gt;
huffChoice _ _    _  = error &amp;quot;readHuffTree: Encountered a non-00/01 option.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----------------------------------------------------------&lt;br /&gt;
-- Reading Huffman-Compressed Data&lt;br /&gt;
&lt;br /&gt;
-- Take four bytes, and convert them into an&lt;br /&gt;
-- unsigned 32-bit integer.&lt;br /&gt;
word32le :: (Word8,Word8,Word8,Word8) -&amp;gt; Word32&lt;br /&gt;
word32le (x1,x2,x3,x4) = (fi x1) .|. (fi x2 `shiftL` 8) .|. (fi x3 `shiftL` 16) .|. (fi x4 `shiftL` 24)&lt;br /&gt;
    where fi = fromIntegral :: Word8 -&amp;gt; Word32&lt;br /&gt;
&lt;br /&gt;
-- Lazy construction/interpretation of Bool List.&lt;br /&gt;
-- (Big-endian bits)&lt;br /&gt;
readBitsBE :: Word8 -&amp;gt; [Bool] -&amp;gt; [Bool]&lt;br /&gt;
readBitsBE x xs = ((rd 7):(rd 6):(rd 5):(rd 4):(rd 3):(rd 2):(rd 1):(rd 0):xs)&lt;br /&gt;
    where rd i = testBit x i&lt;br /&gt;
&lt;br /&gt;
-- Lazy construction/interpretation of Bool List.&lt;br /&gt;
-- (Little-endian bits)&lt;br /&gt;
readBitsLE :: Word8 -&amp;gt; [Bool] -&amp;gt; [Bool]&lt;br /&gt;
readBitsLE x xs = ((rd 0):(rd 1):(rd 2):(rd 3):(rd 4):(rd 5):(rd 6):(rd 7):xs)&lt;br /&gt;
    where rd i = testBit x i&lt;br /&gt;
&lt;br /&gt;
-- This is probably a bad idea...&lt;br /&gt;
-- ...unless the laziness saves some memory...&lt;br /&gt;
convertBitsLE :: ByteString -&amp;gt; [Bool]&lt;br /&gt;
convertBitsLE bs&lt;br /&gt;
    | (Just (x,xs)) &amp;lt;- BS.uncons bs&lt;br /&gt;
    = readBitsLE x (convertBitsLE xs)&lt;br /&gt;
    | otherwise = []&lt;br /&gt;
&lt;br /&gt;
-- The actual function to read the data&lt;br /&gt;
huffRead :: (HuffTree a) -&amp;gt; BS.ByteString -&amp;gt; [a]&lt;br /&gt;
huffRead hf bs &lt;br /&gt;
    | (Just (x1,bs1)) &amp;lt;- BS.uncons bs&lt;br /&gt;
    , (Just (x2,bs2)) &amp;lt;- BS.uncons bs1&lt;br /&gt;
    , (Just (x3,bs3)) &amp;lt;- BS.uncons bs2&lt;br /&gt;
    , (Just (x4,bs4)) &amp;lt;- BS.uncons bs3&lt;br /&gt;
    = huffRead&#039; 0 (word32le (x1,x2,x3,x4)) hf hf (convertBitsLE bs4)&lt;br /&gt;
    | otherwise = error &amp;quot;huffRead: Less than 4 bytes in chunk.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
-- Usage:&lt;br /&gt;
-- huffRead&#039; &amp;lt;# of bytes output&amp;gt; &amp;lt;total # of bytes&amp;gt; &amp;lt;current position in HuffTree&amp;gt; &amp;lt;full HuffTree&amp;gt; &amp;lt;input bit stream&amp;gt;&lt;br /&gt;
-- More Details:&lt;br /&gt;
-- &amp;lt;# of bytes output&amp;gt;            : The number of bytes output from reading the input stream.&lt;br /&gt;
--                                  When this reaches the total # of bytes, the original data&lt;br /&gt;
--                                  has all been extracted&lt;br /&gt;
-- &amp;lt;total # of bytes&amp;gt;             : The total number of bytes&lt;br /&gt;
-- &amp;lt;current position in HuffTree&amp;gt; : A sub-Huffman Tree, representing the current position&lt;br /&gt;
--                                  e.g. If you start with the full tree, and then read a 1,&lt;br /&gt;
--                                  you&#039;ll get the right subtree.&lt;br /&gt;
-- &amp;lt;full HuffTree&amp;gt;                : The full Huffman Tree.&lt;br /&gt;
-- &amp;lt;input bit stream&amp;gt;             : A list of Bools, converted from a bytestring.&lt;br /&gt;
huffRead&#039; :: Word32 -&amp;gt; Word32 -&amp;gt; (HuffTree a) -&amp;gt; (HuffTree a) -&amp;gt; [Bool] -&amp;gt; [a]&lt;br /&gt;
huffRead&#039;    _  _           _   _ []  = error &amp;quot;huffRead: Ran out of bits to read.&amp;quot;&lt;br /&gt;
huffRead&#039; cntr mx (HuffLeaf x) hf bls = (x:(huffRead&#039; (cntr+1) mx hf hf bls))&lt;br /&gt;
huffRead&#039; cntr mx (HuffNode l r) hf (bl:bls)&lt;br /&gt;
    | (cntr  == mx) = [] -- end if the number of output bytes has been reached.&lt;br /&gt;
    | (bl ==  True) = huffRead&#039; cntr mx r hf bls&lt;br /&gt;
    | (bl == False) = huffRead&#039; cntr mx l hf bls&lt;br /&gt;
    | otherwise     = error &amp;quot;huffRead: Apparently the law of the excluded middle doesn&#039;t hold.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
-- Example IO Operation&lt;br /&gt;
&lt;br /&gt;
-- Take a compressed chunk, and decode it.&lt;br /&gt;
huffDecode :: FilePath -&amp;gt; FilePath -&amp;gt; FilePath -&amp;gt; IO ()&lt;br /&gt;
huffDecode dct inf outf = do&lt;br /&gt;
    { hf &amp;lt;- readHuffTree &amp;lt;$&amp;gt; BS.readFile dct&lt;br /&gt;
    ; bs &amp;lt;- BS.readFile inf&lt;br /&gt;
    ; op &amp;lt;- return $ BS.pack $ huffRead hf bs&lt;br /&gt;
    ; BS.writeFile outf op&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
-- Take a list of compressed chunks, and decode it.&lt;br /&gt;
huffDecodes :: FilePath -&amp;gt; [(FilePath,FilePath)] -&amp;gt; IO ()&lt;br /&gt;
huffDecodes dct fps = do&lt;br /&gt;
    { hf &amp;lt;- readHuffTree &amp;lt;$&amp;gt; BS.readFile dct&lt;br /&gt;
    ; mapM_ (\(inf,outf) -&amp;gt; do {op &amp;lt;- BS.pack &amp;lt;$&amp;gt; huffRead hf &amp;lt;$&amp;gt; BS.readFile inf ; BS.writeFile outf op}) fps&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
-- Example Usage:&lt;br /&gt;
-- huffDecodes &amp;quot;AUDIODCT.CK5&amp;quot; [(&amp;quot;song_0001.imf&amp;quot;,&amp;quot;extr_song_0001.imf&amp;quot;),(&amp;quot;song_0002.imf&amp;quot;,&amp;quot;extr_song_0002.imf&amp;quot;),(&amp;quot;song_0003.imf&amp;quot;,&amp;quot;extr_song_0003.imf&amp;quot;)]&lt;br /&gt;
-- where song_0001.imf etc... are compressed chunks extracted from &amp;quot;AUDIO.CK5&amp;quot; using the offsets in &amp;quot;AUDIOHED.CK5&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Code examples]]&lt;/div&gt;</summary>
		<author><name>QuirkyM</name></author>
	</entry>
</feed>