<?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=Fleexy</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=Fleexy"/>
	<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/wiki/Special:Contributions/Fleexy"/>
	<updated>2026-05-14T06:33:30Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.11</generator>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=GameMaps_Format&amp;diff=6209</id>
		<title>GameMaps Format</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=GameMaps_Format&amp;diff=6209"/>
		<updated>2015-08-09T17:23:35Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: /* Huffman compression */ filled in TODO&amp;#039;s (source: FleexCore2 code)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Map Infobox&lt;br /&gt;
 | Type = 2D tile-based&lt;br /&gt;
 | Layers = 3&lt;br /&gt;
 | Viewport = &#039;&#039;Varies by game&#039;&#039;&lt;br /&gt;
 | Game1 = Bio Menace&lt;br /&gt;
 | Game2 = Blake Stone&lt;br /&gt;
 | Game3 = Catacomb 3-D&lt;br /&gt;
 | Game4 = Catacomb Abyss&lt;br /&gt;
 | Game5 = Commander Keen&lt;br /&gt;
 | Game6 = Corridor 7 Alien Invasion&lt;br /&gt;
 | Game7 = Dangerous Dave 3&lt;br /&gt;
 | Game8 = Dangerous Dave 4&lt;br /&gt;
 | Game9 = Noah&#039;s Ark 3D&lt;br /&gt;
 | Game10 = Operation Body Count&lt;br /&gt;
 | Game11 = Spear of Destiny&lt;br /&gt;
 | Game12 = Wolfenstein 3-D&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;GameMaps Format&#039;&#039;&#039; stores levels in a number of [[:Category:id Software]] games. The filenames and compression varies somewhat across different games but all files stored in this format were produced by the [[TED5]] level editor.&lt;br /&gt;
&lt;br /&gt;
There are three main varieties of the file format: uncompressed, [[Carmack compression|carmackized]], and [[Huffman Compression|Huffman compressed]]. Each variation has its own file naming scheme and pattern of external/internal files.&lt;br /&gt;
&lt;br /&gt;
There are two main components to the format.  The game maps proper, which contain the actual level data, and the map headers, which contain both the location of each level&#039;s data within the game maps file, and the tile info for the game.&lt;br /&gt;
&lt;br /&gt;
== Structure of uncompressed data ==&lt;br /&gt;
&lt;br /&gt;
The uncompressed format is used by several games including [[Bio Menace]] and [[Wolfenstein 3-D]].  In this format map data is stored in &amp;lt;tt&amp;gt;MAPTEMP.xxx&amp;lt;/tt&amp;gt; and map headers in &amp;lt;tt&amp;gt;MAPTHEAD.xxx&amp;lt;/tt&amp;gt;.  This is the working format saved by [[TED5]] when maps are being edited and can be directly accessed and edited by this utility, allowing changes to be made to the game.&lt;br /&gt;
&lt;br /&gt;
Note that filenames differ and that Wolfenstein 3-D uses &amp;lt;tt&amp;gt;GAMEMAPS.WLx&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;MAPHEAD.WLx&amp;lt;/tt&amp;gt; files to store data (except for v1.0, which uses &amp;lt;tt&amp;gt;MAPTEMP.WLx&amp;lt;/tt&amp;gt; in place of &amp;lt;tt&amp;gt;GAMEMAPS.WLx&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The main indicator of this format being used is that in the unaltered game the map header file is external.&lt;br /&gt;
&lt;br /&gt;
Only the latest Id Software games lacked compression, when file size was no longer an issue.&lt;br /&gt;
&lt;br /&gt;
=== Map headers (MAPHEAD) ===&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Offset !! Type !! Name !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 || [[UINT16LE]] || magic || Magic word signalling [[RLEW compression]]&lt;br /&gt;
|-&lt;br /&gt;
| 2 || [[UINT32LE]][400] || ptr || 100 pointers to start of level 0-99 data in the game maps file&lt;br /&gt;
|-&lt;br /&gt;
| 402 || {{TODO|Unknown}} || tileinfo || Tileinfo data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The map header file (MAPHEAD) is of varying length and contains three main types of data. The first is the magic word or flag used for RLEW compression, which is always $ABCD.  The second is 100 level pointers which give the location of the start of level data in the GAMEMAPS file, relative to the start of that file.  A value greater than 0 indicates no level (generally 0, but occasionally -1 (xFFFFFFFF) is used).  The third is the tileinfo data, which contains tile properties for each tile used in level creation. (These are masked and unmasked and either 8x8, 16x16 or 32x32.)&lt;br /&gt;
&lt;br /&gt;
Many programs treat the tileinfo as a separate file from the MAPHEAD and it is possible to modify a game in this manner.  Indeed, some games such as Wolfenstein 3-D do not have any tileinfo data at all in the map header file (giving a total file length of 402 bytes.) However TED5 works with any tileinfo data in the MAPHEAD.&lt;br /&gt;
&lt;br /&gt;
=== Map data (GAMEMAPS) ===&lt;br /&gt;
&lt;br /&gt;
The GAMEMAPS file consists of the string &amp;quot;TED5v1.0&amp;quot; and a number of RLEW compressed chunks of varying length.  Each level in the file will have from two to four chunks (usually four) depending on the game, with all levels in a given game having the same number of chunks.  These are the level header and 1-3 planes (foreground, background and sprite/info.)  The chunks are in no particular order and it is possible to read through the entire file decompressing chunks as they&#039;re found.&lt;br /&gt;
&lt;br /&gt;
Chunks are ordered by the MAPHEAD file, which will point to the GAMEMAPS level header chunks which in turn contain pointers to the other GAMEMAPS chunks used by that level.&lt;br /&gt;
&lt;br /&gt;
All level data is in the form of [[UINT16LE]] values (or in the case of pointers, [[UINT32LE]].)&lt;br /&gt;
&lt;br /&gt;
==== Level headers ====&lt;br /&gt;
&lt;br /&gt;
The header for each level inside the GAMEMAPS file (which is pointed to by MAPHEAD) is 42 bytes long and RLEW compressed, though this is difficult to see since the data is so short and non-repetitive.  For the offsets to level planes, a value of 0 indicates the plane does not exist.&lt;br /&gt;
&lt;br /&gt;
Plane 0 is background using unmasked tiles, plane 1 is foreground and uses masked tiles, and plane 2 is sprite/info.  Levels must contain a background plane and usually an infoplane.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Offset !! Type !! Name !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 || UINT32LE || offPlane0 || Offset in GAMEMAPS to beginning of compressed plane 0 data (or 0 if plane is not present)&lt;br /&gt;
|-&lt;br /&gt;
| 4 || UINT32LE || offPlane1 || Offset in GAMEMAPS to beginning of compressed plane 1 data (or 0 if plane is not present)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || UINT32LE || offPlane2 || Offset in GAMEMAPS to beginning of compressed plane 2 data (or 0 if plane is not present)&lt;br /&gt;
|-&lt;br /&gt;
| 12 || UINT16LE || lenPlane0 || Length of compressed plane 0 data (in bytes)&lt;br /&gt;
|-&lt;br /&gt;
| 14 || UINT16LE || lenPlane1 || Length of compressed plane 1 data (in bytes)&lt;br /&gt;
|-&lt;br /&gt;
| 16 || UINT16LE || lenPlane2 || Length of compressed plane 2 data (in bytes)&lt;br /&gt;
|-&lt;br /&gt;
| 18 || UINT16LE || width || Width of level (in tiles)&lt;br /&gt;
|-&lt;br /&gt;
| 20 || UINT16LE || height || Height of level (in tiles)&lt;br /&gt;
|-&lt;br /&gt;
| 22 || char[16] || name || Internal name for level (used only by editor, not displayed in-game. null-terminated)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that for Wolfenstein 3D, a 4-byte signature string (&amp;quot;!ID!&amp;quot;) will normally be present directly after the level name. The signature does not appear to be used anywhere, but is useful for distinguishing between v1.0 files (the signature string is missing), and files for v1.1 and later (includes the signature string).&lt;br /&gt;
&lt;br /&gt;
== Carmack compression ==&lt;br /&gt;
&lt;br /&gt;
[[Carmack compression]] is the method used to compress later &#039;&#039;id Software&#039;&#039; games, when file size was still a concern.  It is the most efficient and complex compression method and was created specifically to work with the 16-bit word structure of the GameMaps file.  The compression is detailed on its [[Carmack compression|own page.]]&lt;br /&gt;
&lt;br /&gt;
Carmackized game maps files are external &amp;lt;tt&amp;gt;GAMEMAPS.xxx&amp;lt;/tt&amp;gt; files and the map header is stored internally in the executable.  The map header must be extracted and the game maps decompressed before TED5 can access them.  TED5 itself can produce carmackized files and external &amp;lt;tt&amp;gt;MAPHEAD.xxx&amp;lt;/tt&amp;gt; files. Carmackization does not replace the RLEW compression used in uncompressed data, but compresses this data, that is, the data is doubly compressed.&lt;br /&gt;
&lt;br /&gt;
Note that for Wolfenstein 3D v1.0, map files are not carmackized, only RLEW compression is applied.&lt;br /&gt;
&lt;br /&gt;
== Huffman compression ==&lt;br /&gt;
&lt;br /&gt;
[[Huffman Compression]] was probably used by earlier versions of TED5 (but possibly not TED5 at all) before carmackization was introduced.  It uses the same method to compress its data as is used by &#039;&#039;id Software&#039;&#039; games to compress their graphics and sounds.  Again this compression method works with RLEW compressed data and has its [[Huffman Compression|own page.]]&lt;br /&gt;
&lt;br /&gt;
Huffman compression is easily detected since it works on the bit level and thus disrupts the word structure of the game data.  This is easily seen in a hex editor.  Compressed data will not contain the string $00 $00 or indeed even $00 very often. (In contrast, even carmackized data contains both strings hundreds of times.)&lt;br /&gt;
&lt;br /&gt;
There will be two internal files for this format: the map header and the Huffman dictionary (which is always the first dictionary in the executable.)  The map header format is also slightly different, being 502 bytes long, the extra 100 bytes being the length of the compressed level headers in the game maps data, which occur immediately after the normal level header offsets and before the tileinfo. Each entry is one octet indicating the decompressed header length in bytes or zero if the level does not exist. (These can be ignored when decompressing since Huffman data can be read until the decompressed level header&#039;s fixed size is reached, but if they are omitted when writing the MAPHEAD, the game may experience a buffer overflow when reading the maps.)&lt;br /&gt;
&lt;br /&gt;
== Location of internal files ==&lt;br /&gt;
&lt;br /&gt;
The GAMEMAPS file itself is always external, but in the case of compression, the MAPHEAD is stored internally in the main .exe file.  Executables are themselves compressed with either with LZEXE or PKLite.  Once the .exe has been decompressed it is a trivial task to find the MAPHEAD as it will start with the UINT16LE value $ABCD (i.e. the byte $CD followed by the byte $AB.)  For level editing purposes only the first 402 (or 502) bytes of the file need to be extracted, though it is possible to read the MAPHEAD file to calculate its length.&lt;br /&gt;
&lt;br /&gt;
The following table lists the offsets of the MAPHEAD file for various games, relative to the start of the decompressed game .exe file.&lt;br /&gt;
&lt;br /&gt;
{{TODO|TODO: Add all known versions of all games}}&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Game !! Version !! Location !! Filename !! Offset !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| [[Bio Menace]] || Freeware || External || &amp;lt;tt&amp;gt;MAPHEAD.BM[123]&amp;lt;/tt&amp;gt; || - ||&lt;br /&gt;
|-&lt;br /&gt;
| [[Blake Stone]]: Aliens of Gold || Shareware || External || &amp;lt;tt&amp;gt;MAPHEAD.BS1&amp;lt;/tt&amp;gt; || - ||&lt;br /&gt;
|-&lt;br /&gt;
| [[Blake Stone]] 2: Planet Strike || All || External || ? || - ||&lt;br /&gt;
|-&lt;br /&gt;
| [[Catacomb 3-D]] (3) || 1.00 || Internal || &amp;lt;tt&amp;gt;CAT3D.EXE&amp;lt;/tt&amp;gt; || $1C570 || After UNLZEXE&lt;br /&gt;
|-&lt;br /&gt;
| [[Catacomb Abyss]] (4) || 1.13 || Internal || &amp;lt;tt&amp;gt;CATABYSS.EXE&amp;lt;/tt&amp;gt; || $1C510 || After UNLZEXE&lt;br /&gt;
|-&lt;br /&gt;
| [[Catacomb Armageddon]] (5) || 1.01a || Internal || &amp;lt;tt&amp;gt;CATARMA.EXE&amp;lt;/tt&amp;gt; || $1D900 || After UNLZEXE&lt;br /&gt;
|-&lt;br /&gt;
| [[Catacomb Apocalypse]] (6) || 1.00b || Internal || &amp;lt;tt&amp;gt;CATAPOC.EXE&amp;lt;/tt&amp;gt; || $1DD50 || After UNLZEXE&lt;br /&gt;
|-&lt;br /&gt;
|rowspan=3| [[Corridor 7 Alien Invasion]] || Demo || External || ? || - ||&lt;br /&gt;
|-&lt;br /&gt;
|| CD || Internal || &amp;lt;tt&amp;gt;CORR7CD.EXE&amp;lt;/tt&amp;gt; || $30D50 || File is not compressed&lt;br /&gt;
|-&lt;br /&gt;
| Floppy || Internal || &amp;lt;tt&amp;gt;C7.EXE&amp;lt;/tt&amp;gt; || $24BF0 || File is not compressed&lt;br /&gt;
|-&lt;br /&gt;
|rowspan=2| [[Commander Keen 4-6|Keen 4]] || Special Demo || ? || ? || ? || File is PKLite compressed&lt;br /&gt;
|-&lt;br /&gt;
| 1.4 EGA || Internal || &amp;lt;tt&amp;gt;KEEN4E.EXE&amp;lt;/tt&amp;gt; || $24830 || After UNLZEXE&lt;br /&gt;
|-&lt;br /&gt;
| [[Commander Keen 4-6|Keen 5]] || 1.4 EGA || Internal || &amp;lt;tt&amp;gt;KEEN5E.EXE&amp;lt;/tt&amp;gt; || $25990 || After UNLZEXE&lt;br /&gt;
|-&lt;br /&gt;
| [[Commander Keen 4-6|Keen 6]] || 1.4 EGA || Internal || &amp;lt;tt&amp;gt;KEEN6.EXE&amp;lt;/tt&amp;gt; || $25080 || After UNLZEXE&lt;br /&gt;
|-&lt;br /&gt;
| [[Commander Keen Dreams]] || 1.13 || Internal || ? || $1FA50 || After UNLZEXE&lt;br /&gt;
|-&lt;br /&gt;
| [[Noah&#039;s Ark 3D]] || All || External || ? || - ||&lt;br /&gt;
|-&lt;br /&gt;
| [[Operation Body Count]] || All || External || ? || - ||&lt;br /&gt;
|-&lt;br /&gt;
| [[Spear of Destiny]] || All || External || ? || - ||&lt;br /&gt;
|-&lt;br /&gt;
|rowspan=2| [[Wolfenstein 3-D]] || Shareware || External || &amp;lt;tt&amp;gt;MAPHEAD.WL1&amp;lt;/tt&amp;gt; || - ||&lt;br /&gt;
|-&lt;br /&gt;
| Registered || External || &amp;lt;tt&amp;gt;MAPHEAD.WL6&amp;lt;/tt&amp;gt; || - ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Utilities ==&lt;br /&gt;
&lt;br /&gt;
* [[TED5]] can edit the &amp;lt;tt&amp;gt;GAMEMAPS&amp;lt;/tt&amp;gt; format of any games that use it.  It is the original editor used to create these files.&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
&lt;br /&gt;
This file format was reverse engineered by Andrew Durdin (adurdin).  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>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Talk:Keen_4-6_Tileinfo_Format&amp;diff=6191</id>
		<title>Talk:Keen 4-6 Tileinfo Format</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Talk:Keen_4-6_Tileinfo_Format&amp;diff=6191"/>
		<updated>2015-06-28T17:14:54Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: answered own question&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;What does the &amp;quot;sprite path arrow&amp;quot; special property actually do? I can&#039;t find any tiles that use it in Keen 5 or 6. [[User:Fleexy|Fleexy]] ([[User talk:Fleexy|talk]]) 17:06, 28 June 2015 (UTC)&lt;br /&gt;
: Oh wait, apparently the &#039;&#039;&#039;foreground tiles&#039;&#039;&#039; that hold the icons for the platform path arrows get that property. That&#039;s kind of strange, because those icons never actually appear as foreground tiles in levels. Does anybody know if the property is actually used/checked? [[User:Fleexy|Fleexy]] ([[User talk:Fleexy|talk]]) 17:14, 28 June 2015 (UTC)&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Talk:Keen_4-6_Tileinfo_Format&amp;diff=6190</id>
		<title>Talk:Keen 4-6 Tileinfo Format</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Talk:Keen_4-6_Tileinfo_Format&amp;diff=6190"/>
		<updated>2015-06-28T17:06:28Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: asked about prop. 17&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;What does the &amp;quot;sprite path arrow&amp;quot; special property actually do? I can&#039;t find any tiles that use it in Keen 5 or 6. [[User:Fleexy|Fleexy]] ([[User talk:Fleexy|talk]]) 17:06, 28 June 2015 (UTC)&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Talk:EGAGraph_Format&amp;diff=6186</id>
		<title>Talk:EGAGraph Format</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Talk:EGAGraph_Format&amp;diff=6186"/>
		<updated>2015-06-20T19:34:08Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: /* CGAGraph format */ new section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== xSPRITES.TXT ==&lt;br /&gt;
&lt;br /&gt;
What is the actual content of the sprite table?  The following is from the modkeen document, which does not agree with what is posted on the main page of this artice.  It would suggest that the &amp;quot;shifts&amp;quot; are stored in here as well?  Are they stored somewhere else?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Episodes 4, 5, and 6 only: This file contains extra information about each sprite. Each line in the file has the sprite number, followed by the four clipping rectangle co-ordinates in square brackets [top, left, bottom, right], followed by the sprite origin in square brackets [top, left], followed by the number of shifts the sprite uses. The origin of the sprite image is the point from which its location is calculated. For example, the hand sprite in Keen 5 (5SPR0291.BMP) has several images. The origin for each of these images is in the centre of the &amp;quot;eye&amp;quot;, so that as the hand rotates, the different sprite images all appear to rotate about the eye. The origin coordinates are given in pixels from the top-left corner of the sprite image. The shifts is the number of different copies of the sprite image that are stored in memory, and can be 1, 2, or 4. As a general rule, the more shifts a sprite has, the smoother it moves, but the more memory it takes up. If you are making a very large sprite, you can reduce the number of shifts to save memory. But if you have a small sprite and want it to move more smoothly, increase the number of shifts.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Also from modkeen source:&lt;br /&gt;
&lt;br /&gt;
typedef struct&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
	unsigned short Width;&lt;br /&gt;
&lt;br /&gt;
	unsigned short Height;&lt;br /&gt;
&lt;br /&gt;
	signed short OrgX;&lt;br /&gt;
&lt;br /&gt;
	signed short OrgY;&lt;br /&gt;
&lt;br /&gt;
	signed short Rx1, Ry1;&lt;br /&gt;
&lt;br /&gt;
	signed short Rx2, Ry2;&lt;br /&gt;
&lt;br /&gt;
	unsigned short Shifts;&lt;br /&gt;
&lt;br /&gt;
} SpriteHeadStruct;&lt;br /&gt;
&lt;br /&gt;
Which would make a 9-word structure.&lt;br /&gt;
&lt;br /&gt;
20:16, 3 September 2010 (GMT)&lt;br /&gt;
&lt;br /&gt;
: Well from studying Keen 1-3 type games, my guess would be two words of height / 8 and width, four words giving hitbox co-ords and two words giving h\v offsets. However Keen 4-6 is more complex so I&#039;ll have to investigate this later on when I work with those files --[[User:Levellass|Endian? What are you on about?]] 04:40, 16 September 2010 (GMT)&lt;br /&gt;
&lt;br /&gt;
:: I can confirm that each entry is 9 words (or 18 bytes) long and matches the above structure. And the last value (shifts) is actually the same value that you can see at the end of each line in the &amp;lt;tt&amp;gt;xSPRITES.TXT&amp;lt;/tt&amp;gt; file. --[[User:K1n9 Duk3|K1n9 Duk3]] 00:30, 7 February 2011 (GMT)&lt;br /&gt;
&lt;br /&gt;
== CGAGraph format ==&lt;br /&gt;
&lt;br /&gt;
Almost everything in this article seems to apply to the CGA graphics resources as well. There are two main differences: the fonts are stored in version 1 of the [[EGA Font format]], and dividing by 8 for EGA dimensions is equivalent to dividing by 4 in CGA. (Generalization: divide by [bpp * 2].) Keep in mind that both CGA and EGA always store the mask before the actual image. --[[User:Fleexy|Fleexy]] ([[User talk:Fleexy|talk]]) 19:34, 20 June 2015 (UTC)&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Commander_Keen_4-6&amp;diff=5888</id>
		<title>Commander Keen 4-6</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Commander_Keen_4-6&amp;diff=5888"/>
		<updated>2014-12-21T21:33:42Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Updated Abiathar capabilities for the v2.2 release&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Game Infobox&lt;br /&gt;
 | Title = Commander Keen 4.png&lt;br /&gt;
 | Levels = Edit&lt;br /&gt;
 | Tiles = Edit&lt;br /&gt;
 | Sprites = Edit&lt;br /&gt;
 | Fullscreen = Edit&lt;br /&gt;
 | Sound = Edit&lt;br /&gt;
 | Music = Edit&lt;br /&gt;
 | Text = Edit&lt;br /&gt;
 | Story = Edit&lt;br /&gt;
 | Interface = Edit&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;Commander Keen: Goodbye Galaxy&#039;&#039;&#039; is a very popular platform scroller, which set the benchmark for this style of game on a PC.&lt;br /&gt;
&lt;br /&gt;
There is a large amount of modding info in the [[keenwiki:Galaxy Tools|modding section of the KeenWiki]] and there is an extensive [[keenwiki:Category:Patches|patch library]] allowing the game to be extended and changed considerably.&lt;br /&gt;
&lt;br /&gt;
== Tools ==&lt;br /&gt;
&lt;br /&gt;
{{BeginFileFormatTools|Type=game}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[keenwiki:Abiathar|Abiathar]]&lt;br /&gt;
| Platform = Windows&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = Edit&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = Replace&lt;br /&gt;
| sfx = Edit&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[CKPatch]]&lt;br /&gt;
| Platform = DOS&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = No&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = Yes&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[keenwiki:IMF Creator|IMF Creator]]&lt;br /&gt;
| Platform = Windows&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = No&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = Create&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = Yes&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[keenwiki:Keen: Next (level editor)|Keen: Next]]&lt;br /&gt;
| Platform = Windows&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = Edit&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[keenwiki:Keengraph|Keengraph]]&lt;br /&gt;
| Platform = DOS/Win/Linux&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = No&lt;br /&gt;
| gfx = Edit&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[keenwiki:KeenWave|KeenWave]]&lt;br /&gt;
| Platform = DOS/Win/Linux&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = No&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = Replace&lt;br /&gt;
| sfx = Edit&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = EModKeen/LModKeen&lt;br /&gt;
| Platform = Win/Linux&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = No&lt;br /&gt;
| gfx = Edit&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[keenwiki:ModKeen|ModKeen]]&lt;br /&gt;
| Platform = DOS&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = No&lt;br /&gt;
| gfx = Edit&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[keenwiki:The Omegamatic|The Omegamatic]]&lt;br /&gt;
| Platform = Windows&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = Edit&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[keenwiki:The Photachyon Transceiver|The Photachyon Transceiver]]&lt;br /&gt;
| Platform = Windows&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = Edit&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[keenwiki:Startext|Startext]]&lt;br /&gt;
| Platform = DOS&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = No&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = Edit&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[TED5]]&lt;br /&gt;
| Platform = DOS&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = Edit&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{EndFileFormatTools}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
{{BeginGameFileList}}&lt;br /&gt;
{{GameFile&lt;br /&gt;
 | Name = audio.ck[456]&lt;br /&gt;
 | Format = [[AudioT Format]], [[IMF Format]]&lt;br /&gt;
 | KnownFormat = Yes&lt;br /&gt;
 | Desc = Sound and music&lt;br /&gt;
}}&lt;br /&gt;
{{GameFile&lt;br /&gt;
 | Name = config.ck[456]&lt;br /&gt;
 | Format = [[Keen 4-6 Configuration File]]&lt;br /&gt;
 | KnownFormat = No&lt;br /&gt;
 | Desc = Settings and high scores&lt;br /&gt;
}}&lt;br /&gt;
{{GameFile&lt;br /&gt;
 | Name = egagraph.ck[456]&lt;br /&gt;
 | Format = [[EGAGraph Format]]&lt;br /&gt;
 | KnownFormat = Yes&lt;br /&gt;
 | Desc = Graphics, text and miscellaneous data&lt;br /&gt;
}}&lt;br /&gt;
{{GameFile&lt;br /&gt;
 | Name = gamemaps.ck[456]&lt;br /&gt;
 | Format = [[GameMaps Format]]&lt;br /&gt;
 | KnownFormat = Yes&lt;br /&gt;
 | Desc = Level maps&lt;br /&gt;
}}&lt;br /&gt;
{{GameFile&lt;br /&gt;
 | Name = keen[456]e.exe&lt;br /&gt;
 | Format = [[B800 Text]], [[Keen 4-6 Action Format]]&lt;br /&gt;
 | KnownFormat = Yes&lt;br /&gt;
 | Desc = There are a couple of text screens in the main .EXE file (including the text displayed on the screen when you quit)&lt;br /&gt;
}}&lt;br /&gt;
{{GameFile&lt;br /&gt;
 | Name = keen[456]e.exe&lt;br /&gt;
 | Format = [[Keen 4-6 Action Format]]&lt;br /&gt;
 | KnownFormat = Yes&lt;br /&gt;
 | Desc = Sprite behaviours are governed by this&lt;br /&gt;
}}&lt;br /&gt;
{{GameFile&lt;br /&gt;
 | Name = keen[456]e.exe&lt;br /&gt;
 | Format = [[Keen 4-6 Tileinfo Format]]&lt;br /&gt;
 | KnownFormat = Yes&lt;br /&gt;
 | Desc = Tile information are governed by this&lt;br /&gt;
}}&lt;br /&gt;
{{EndGameFileList}}&lt;br /&gt;
&lt;br /&gt;
=== AudioT Format Details ===&lt;br /&gt;
&lt;br /&gt;
Keen 4, 5 and 6 use the compressed version of the [[AudioT Format]] to store music and sound. The main audio file for each game, the AUDIOT.xxx file, is called AUDIO.CKx, where x is the number of the Keen game (4, 5 or 6). For example, the file for Keen 4 is AUDIO.CK4.&lt;br /&gt;
&lt;br /&gt;
The two secondary files needed for this format, the AUDIOHED.xxx and AUDIODCT.xxx, are embedded inside the main .exe file of each game (KEEN4E.EXE, KEEN5E.EXE and KEEN6.EXE for the EGA versions of the game).&lt;br /&gt;
&lt;br /&gt;
== Related Links ==&lt;br /&gt;
&lt;br /&gt;
* [[Commander Keen 1-3]]&lt;br /&gt;
* [[Commander Keen Dreams]]&lt;br /&gt;
* The [[KeenWiki:Main Page|Commander Keen Wiki]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Apogee]]&lt;br /&gt;
[[Category:id Software]]&lt;br /&gt;
[[Category:Sidescroller]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Bio_Menace&amp;diff=5690</id>
		<title>Bio Menace</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Bio_Menace&amp;diff=5690"/>
		<updated>2014-11-11T20:18:05Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Added notes to entries, fixed Abiathar link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
{{Game Infobox&lt;br /&gt;
 | Levels = Edit&lt;br /&gt;
 | Tiles = No&lt;br /&gt;
 | Sprites = No&lt;br /&gt;
 | Fullscreen = No&lt;br /&gt;
 | Sound = Some&lt;br /&gt;
 | Music = Some&lt;br /&gt;
 | Text = No&lt;br /&gt;
 | Story = No&lt;br /&gt;
 | Interface = No&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;Bio Menace&#039;&#039;&#039; is a series of three games known simply as Bio Menace 1, 2 and 3. They use a slightly altered version of the [[Commander Keen 4-6]] engine, so the file formats used are almost identical.&lt;br /&gt;
&lt;br /&gt;
The game follows the adventures of Snake Logan, a top secret operative at the CIA, who takes on missions others would see as suicidal, as he battles hordes of strange mutant monsters that have suddenly appeared and are taking over cities. The goals of the game vary, from rescuing trapped prisoners to destroying an evil computer. Notably, in the second game, if you do not get the portable nuclear device in one of the levels, the game becomes unwinnable and you are treated to the story of Snake&#039;s eventual death.&lt;br /&gt;
&lt;br /&gt;
{{BeginFileFormatTools|Type=game}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [http://www.shikadi.net/keenwiki/Abiathar Abiathar]&lt;br /&gt;
| Platform = Windows&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = Edit&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
| notes = Offers templates for Bio Menace projects&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[TED5]]&lt;br /&gt;
| Platform = DOS GUI&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = Edit&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
| notes = Must be [http://people.inf.elte.hu/szgrahi/bmenace_mod.zip configured to work with Bio Menace]&lt;br /&gt;
}}&lt;br /&gt;
{{EndFileFormatTools}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
== File formats ==&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File name !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;audiohed.bm*&amp;lt;br/&amp;gt;audiot.bm*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| style=&amp;quot;background: #CCFFCC;&amp;quot; | Sound effects and music in [[AudioT Format]] (and within that, music in [[IMF Format]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;bmenace[123].exe&amp;lt;/tt&amp;gt;&lt;br /&gt;
| style=&amp;quot;background: #FFFFCC;&amp;quot; | Exit text screens in [[B800 Text]] format&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;egadict.bm*&amp;lt;br/&amp;gt;egahead.bm*&amp;lt;br/&amp;gt;egagraph.bm*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| style=&amp;quot;background: #CCFFCC;&amp;quot; | Graphics, text and miscellaneous data in [[EGAGraph Format]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;gamemaps.bm*&amp;lt;br/&amp;gt;maphead.bm*&amp;lt;br/&amp;gt;maptemp.bm*&amp;lt;br/&amp;gt;mapthead.bm*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| style=&amp;quot;background: #CCFFCC;&amp;quot; | Levels in [[GameMaps Format]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* Sprite behaviours are governed by data structures in the .exe, arranged in [[Keen 4-6 Action Format]]&lt;br /&gt;
&lt;br /&gt;
== Music ==&lt;br /&gt;
&lt;br /&gt;
=== AudioT Format Details ===&lt;br /&gt;
Biomenace uses the uncompressed version of the [[AudioT Format]] to store music and sound. The main audio file for each game, the AUDIOT.xxx file, is called AUDIOT.BMx, where x is the number of the game (1, 2 or 3). For example, the file for Keen 2 is AUDIO.BM2. The secondary files needed for this format, the AUDIOHED.BMx are external.&lt;br /&gt;
&lt;br /&gt;
=== Levels Songs Assignment ===&lt;br /&gt;
There is a place inside the executables too, where each level in the game is assigned a song from the AUDIOT.BMx file. From that addresses, the following bytes indicate the song for each level. Every 2 bytes is a value corresponding to a level. The first 2 bytes correspond to level 0; the next 2 bytes correspond to level 1; and so on. Each 2-byte value is an integer corresponding to the song number used in that level, starting from $00 $00, and going up to $00 $01, and so on. This numbers refer to the order the songs are in the AUDIO.BMx file; $00 $00 is the first one, $00 $01 is the second one, and so on.&lt;br /&gt;
&lt;br /&gt;
It is notable that Biomenace has many more songs in it than the Keen 4-6 games upon which it was based.&lt;br /&gt;
&lt;br /&gt;
== Obtaining the game ==&lt;br /&gt;
&lt;br /&gt;
The full version of this game [http://www.3drealms.com/news/2005/12/bio_menace_released_as_freewar.html has been released as freeware].&lt;br /&gt;
&lt;br /&gt;
* Three different versions are available from [http://www.classicdosgames.com/apogee.html Classic DOS Games]&lt;br /&gt;
&lt;br /&gt;
[[Category:Apogee]]&lt;br /&gt;
[[Category:Sidescroller]]&lt;br /&gt;
[[Category:Freeware]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Bio_Menace&amp;diff=5689</id>
		<title>Bio Menace</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Bio_Menace&amp;diff=5689"/>
		<updated>2014-11-11T20:11:09Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Added Abiathar to editing program list&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
{{Game Infobox&lt;br /&gt;
 | Levels = Edit&lt;br /&gt;
 | Tiles = No&lt;br /&gt;
 | Sprites = No&lt;br /&gt;
 | Fullscreen = No&lt;br /&gt;
 | Sound = Some&lt;br /&gt;
 | Music = Some&lt;br /&gt;
 | Text = No&lt;br /&gt;
 | Story = No&lt;br /&gt;
 | Interface = No&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;Bio Menace&#039;&#039;&#039; is a series of three games known simply as Bio Menace 1, 2 and 3. They use a slightly altered version of the [[Commander Keen 4-6]] engine, so the file formats used are almost identical.&lt;br /&gt;
&lt;br /&gt;
The game follows the adventures of Snake Logan, a top secret operative at the CIA, who takes on missions others would see as suicidal, as he battles hordes of strange mutant monsters that have suddenly appeared and are taking over cities. The goals of the game vary, from rescuing trapped prisoners to destroying an evil computer. Notably, in the second game, if you do not get the portable nuclear device in one of the levels, the game becomes unwinnable and you are treated to the story of Snake&#039;s eventual death.&lt;br /&gt;
&lt;br /&gt;
{{BeginFileFormatTools|Type=game}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[TED5]]&lt;br /&gt;
| Platform = DOS GUI&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = Edit&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{FileFormatTool&lt;br /&gt;
| Name = [[Abiathar]]&lt;br /&gt;
| Platform = Windows&lt;br /&gt;
| grp = N/A&lt;br /&gt;
| map = Edit&lt;br /&gt;
| gfx = No&lt;br /&gt;
| mus = No&lt;br /&gt;
| sfx = No&lt;br /&gt;
| txt = No&lt;br /&gt;
| sav = No&lt;br /&gt;
| exe = No&lt;br /&gt;
}}&lt;br /&gt;
{{EndFileFormatTools}}&lt;br /&gt;
&lt;br /&gt;
* TED5 must be [http://people.inf.elte.hu/szgrahi/bmenace_mod.zip configured to work with Bio Menace]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
== File formats ==&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File name !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;audiohed.bm*&amp;lt;br/&amp;gt;audiot.bm*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| style=&amp;quot;background: #CCFFCC;&amp;quot; | Sound effects and music in [[AudioT Format]] (and within that, music in [[IMF Format]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;bmenace[123].exe&amp;lt;/tt&amp;gt;&lt;br /&gt;
| style=&amp;quot;background: #FFFFCC;&amp;quot; | Exit text screens in [[B800 Text]] format&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;egadict.bm*&amp;lt;br/&amp;gt;egahead.bm*&amp;lt;br/&amp;gt;egagraph.bm*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| style=&amp;quot;background: #CCFFCC;&amp;quot; | Graphics, text and miscellaneous data in [[EGAGraph Format]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;gamemaps.bm*&amp;lt;br/&amp;gt;maphead.bm*&amp;lt;br/&amp;gt;maptemp.bm*&amp;lt;br/&amp;gt;mapthead.bm*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| style=&amp;quot;background: #CCFFCC;&amp;quot; | Levels in [[GameMaps Format]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* Sprite behaviours are governed by data structures in the .exe, arranged in [[Keen 4-6 Action Format]]&lt;br /&gt;
&lt;br /&gt;
== Music ==&lt;br /&gt;
&lt;br /&gt;
=== AudioT Format Details ===&lt;br /&gt;
Biomenace uses the uncompressed version of the [[AudioT Format]] to store music and sound. The main audio file for each game, the AUDIOT.xxx file, is called AUDIOT.BMx, where x is the number of the game (1, 2 or 3). For example, the file for Keen 2 is AUDIO.BM2. The secondary files needed for this format, the AUDIOHED.BMx are external.&lt;br /&gt;
&lt;br /&gt;
=== Levels Songs Assignment ===&lt;br /&gt;
There is a place inside the executables too, where each level in the game is assigned a song from the AUDIOT.BMx file. From that addresses, the following bytes indicate the song for each level. Every 2 bytes is a value corresponding to a level. The first 2 bytes correspond to level 0; the next 2 bytes correspond to level 1; and so on. Each 2-byte value is an integer corresponding to the song number used in that level, starting from $00 $00, and going up to $00 $01, and so on. This numbers refer to the order the songs are in the AUDIO.BMx file; $00 $00 is the first one, $00 $01 is the second one, and so on.&lt;br /&gt;
&lt;br /&gt;
It is notable that Biomenace has many more songs in it than the Keen 4-6 games upon which it was based.&lt;br /&gt;
&lt;br /&gt;
== Obtaining the game ==&lt;br /&gt;
&lt;br /&gt;
The full version of this game [http://www.3drealms.com/news/2005/12/bio_menace_released_as_freewar.html has been released as freeware].&lt;br /&gt;
&lt;br /&gt;
* Three different versions are available from [http://www.classicdosgames.com/apogee.html Classic DOS Games]&lt;br /&gt;
&lt;br /&gt;
[[Category:Apogee]]&lt;br /&gt;
[[Category:Sidescroller]]&lt;br /&gt;
[[Category:Freeware]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Commander_Keen_Dreams&amp;diff=5402</id>
		<title>Commander Keen Dreams</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Commander_Keen_Dreams&amp;diff=5402"/>
		<updated>2014-08-12T19:59:18Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Noted the possibility of modding levels and graphics&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
{{Game Infobox&lt;br /&gt;
 | Levels = Edit&lt;br /&gt;
 | Tiles = Edit&lt;br /&gt;
 | Sprites = Edit&lt;br /&gt;
 | Fullscreen = No&lt;br /&gt;
 | Sound = No&lt;br /&gt;
 | Music = No&lt;br /&gt;
 | Text = No&lt;br /&gt;
 | Story = No&lt;br /&gt;
 | Interface = No&lt;br /&gt;
}}&lt;br /&gt;
== File formats ==&lt;br /&gt;
&lt;br /&gt;
* [[AudioT Format]] - used for storing sound and music data&lt;br /&gt;
* [[B800 Text]] - there are a couple of text screens in the main .EXE file (including the text displayed on the screen when you quit)&lt;br /&gt;
* [[EGAGraph Format]] - used for storing graphics, text and miscellaneous data&lt;br /&gt;
* [[Keen Dreams level Format]] - used for storing level maps&lt;br /&gt;
* [[Keen 4-6 Action Format]] Sprite&#039;s behaviors are governed by this&lt;br /&gt;
* [[Keen 4-6 Tileinfo Format]] Tile information are governed by this&lt;br /&gt;
* [[SHL data]] - The start menu is in this format&lt;br /&gt;
* [[SLIB compression]] The title screen is compressed with this&lt;br /&gt;
&lt;br /&gt;
Compression used in KeenDreams is complex; most of the &#039;registered&#039; (Non shareware) executables are compressed using [[PKLite compression]] and demo versions have additional files or filenames.  Uniquely, the game maps are compressed using [[Huffman Compression]] instead of [[Carmack compression]], as they were made with an earlier version of [[TED5]] (TED3).&lt;br /&gt;
&lt;br /&gt;
== Versions ==&lt;br /&gt;
&lt;br /&gt;
There are no less than six versions of Keen Dreams available; these differ very little in actual gameplay, but markedly in file structure. Most of these are listed at [[http://www.shikadi.net/keenwiki/Keen_Dreams_Versions the Commander Keen Wiki]] (They omit version 1.0 and the Id Anthology)&lt;br /&gt;
&lt;br /&gt;
The main moddable version is version 1.13, which is not the latest version of the game. Notably it has less in-game help and text, requires the player to run a program from Gamer&#039;s Edge before playing and names its files differently from the later Keen 4-6 manner. It also uses a seperate file for its start screen, which is unusual.&lt;br /&gt;
&lt;br /&gt;
== Related Links ==&lt;br /&gt;
* [[Commander Keen 1-3]]&lt;br /&gt;
* [[Commander Keen 4-6]]&lt;br /&gt;
* The [[KeenWiki:Main Page|Commander Keen Wiki]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Softdisk]]&lt;br /&gt;
[[Category:id Software]]&lt;br /&gt;
[[Category:Sidescroller]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=TED5&amp;diff=5229</id>
		<title>TED5</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=TED5&amp;diff=5229"/>
		<updated>2014-06-15T13:36:14Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: /* GFXINFOE.xxx */ Filled in fields. Source: https://github.com/Fleex255/TED5/blob/master/TED5.H&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Tool Infobox&lt;br /&gt;
 | Image = TED5-Keen4.png&lt;br /&gt;
 | Platform = DOS&lt;br /&gt;
 | Edit1 = Map&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Tile Editor v5.0 (TED5) is a level editor written by [[:Category:id Software|id Software]] that has been used to create the levels for many of their games. It edits the [[GameMaps Format]] seen in many older id Software games and is also apparently able to edit the [[Commander Keen 1-3 Level format]], though how is not known.&lt;br /&gt;
&lt;br /&gt;
== Files used by TED5 ==&lt;br /&gt;
&lt;br /&gt;
TED5 is compatible with any ID game that has a &amp;lt;tt&amp;gt;GAMEMAPS.xxx&amp;lt;/tt&amp;gt; file. However the actual &amp;lt;tt&amp;gt;GAMEMAPS.xxx&amp;lt;/tt&amp;gt; file is the final product, many other supporting files are required for TED5 to function.&lt;br /&gt;
&lt;br /&gt;
If the game is &#039;compressed&#039;, it will not have most of these files. [[Commander Keen 4-6]] is one such game. In contrast &#039;uncompressed&#039; games such as [[Bio Menace]] will have the full complement of files. Sadly, most games are compressed, as this is most efficient.&lt;br /&gt;
&lt;br /&gt;
=== EGAGRAPH.xxx, EGAHEAD.xxx and EGADCT.xxx ===&lt;br /&gt;
&lt;br /&gt;
These are explained fully under [[EGAGraph Format]]; they are respectively the game graphics, the graphics header and the [[Huffman Compression]] dictionary for decompressing graphics. Compressed games will just have the &amp;lt;tt&amp;gt;EGAGRAPH&amp;lt;/tt&amp;gt;; with the HEAD and DCT files stored internally in the executable. Uncompressed games will have an external &amp;lt;tt&amp;gt;EGAHEAD&amp;lt;/tt&amp;gt; and no need for an &amp;lt;tt&amp;gt;EGADCT&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
Like all Huffman dictionaries, the &amp;lt;tt&amp;gt;EGADCT&amp;lt;/tt&amp;gt; file can be located in the executable by looking for the string &amp;lt;tt&amp;gt;$FD $01 $00 $00 $00 $00&amp;lt;/tt&amp;gt; which is found at the file&#039;s end. (The file will be 1024 bytes long.) The &amp;lt;tt&amp;gt;EGAHEAD&amp;lt;/tt&amp;gt; file can be located by looking for a 4 (Or 3) byte string which is the &amp;lt;tt&amp;gt;EGAGRAPH&amp;lt;/tt&amp;gt; file size, this is always the last entry. (If you then proceed to move backwards until you reach a zero value entry, you will have the start of the file.)&lt;br /&gt;
&lt;br /&gt;
You will receive an error if these files are absent. If the DCT is missing then TED5 will assume graphics are uncompressed.&lt;br /&gt;
&amp;lt;!-- TODO: A list of the locations of the head and dct for supported games --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Gamemaps ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;GAMEMAPS&amp;lt;/tt&amp;gt; file is not used, but is produced by TED5. It contains the compressed game maps and is produced from the &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt; file when the user selects &#039;Carmackize maps&#039; in TED5. Carmackization is complex and takes a long time to do. Because of this it is recommended that modders use Instant Carma! (See below)&lt;br /&gt;
&lt;br /&gt;
=== GFXINFOE.xxx ===&lt;br /&gt;
&lt;br /&gt;
This is a 46 byte file that contains data allowing TED5 to extract the graphics used in levels.It consists of a number of numbers and locations of various tile types.&lt;br /&gt;
&lt;br /&gt;
Levels can be made of 8x8, 16x16 or 32x32 tiles (Always 16 color EGA.) Levels have a foreground plane, and may also have a background and info (Sprite) plane.The structure of the &amp;lt;tt&amp;gt;GFXINFOE&amp;lt;/tt&amp;gt; file is as follows:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset!!Type!!Description&lt;br /&gt;
|-&lt;br /&gt;
|0||[[UINT16LE]]||Number of 8x8 background tiles&lt;br /&gt;
|-&lt;br /&gt;
|2||[[UINT16LE]]||Number of 8x8 foreground tiles&lt;br /&gt;
|-&lt;br /&gt;
|4||[[UINT16LE]]||Number of 16x16 background tiles&lt;br /&gt;
|-&lt;br /&gt;
|6||[[UINT16LE]]||Number of 16x16 foreground tiles&lt;br /&gt;
|-&lt;br /&gt;
|8||[[UINT16LE]]||Number of 32x32 background tiles&lt;br /&gt;
|-&lt;br /&gt;
|10||[[UINT16LE]]||Number of 32x32 foreground tiles&lt;br /&gt;
|-&lt;br /&gt;
|12||[[UINT16LE]]||8x8 back tile start&lt;br /&gt;
|-&lt;br /&gt;
|14||[[UINT16LE]]||8x8 fore tile start&lt;br /&gt;
|-&lt;br /&gt;
|16||[[UINT16LE]]||16x16 back start&lt;br /&gt;
|-&lt;br /&gt;
|18||[[UINT16LE]]||16x16 fore start&lt;br /&gt;
|-&lt;br /&gt;
|20||[[UINT16LE]]||32x32 back start&lt;br /&gt;
|-&lt;br /&gt;
|22||[[UINT16LE]]||32x32 fore start &lt;br /&gt;
|-&lt;br /&gt;
|24||[[UINT16LE]]||Number of pictures&lt;br /&gt;
|-&lt;br /&gt;
|26||[[UINT16LE]]||Number of masked pictures&lt;br /&gt;
|-&lt;br /&gt;
|28||[[UINT16LE]]||Number of sprites&lt;br /&gt;
|-&lt;br /&gt;
|30||[[UINT16LE]]||Picture start&lt;br /&gt;
|-&lt;br /&gt;
|32||[[UINT16LE]]||Mask picture start&lt;br /&gt;
|-&lt;br /&gt;
|34||[[UINT16LE]]||Sprite start&lt;br /&gt;
|-&lt;br /&gt;
|36||[[UINT16LE]]||&amp;quot;offpicstr&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|38||[[UINT16LE]]||&amp;quot;offpicmstr&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|40||[[UINT16LE]]||&amp;quot;offstrstr&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|42||[[UINT16LE]]||Number of extra EGA resources&lt;br /&gt;
|-&lt;br /&gt;
|44||[[UINT16LE]]||Extra EGA resource start&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The location (Start) given for tiles is the entry in the &amp;lt;tt&amp;gt;EGAHEAD.xxx&amp;lt;/tt&amp;gt; file, most &amp;lt;tt&amp;gt;EGAHEAD.xxx&amp;lt;/tt&amp;gt; files consist of 3 byte entries so the actual location, in bytes, in the file is three times this, though older games (Such as [[Commander Keen Dreams]]) have 4 byte entries. (It is not known if or how TED5 tells the difference between these.) Each tile has its own entry in the header.&lt;br /&gt;
&lt;br /&gt;
The icons used by TED5 (For sprites, etc) are calculated as follows; icons follow directly after background tiles, then foreground tiles. There will thus be some &#039;extra&#039; slots between the back and fore tiles. These are used as the number of icons.&lt;br /&gt;
&lt;br /&gt;
This file is found with uncompressed games, but has to be created for compressed games. It is not currently known if it can be extracted somehow from the executable or if it is hard coded for each game.&lt;br /&gt;
&lt;br /&gt;
=== Maptemp and Mapthead ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt; file contains the uncarmackized level maps. Carmackization is a form of compression related to [[Keen 1-3 LZW compression]] in that it employs a sliding window. &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt; is however [[RLE Compression]] compressed to avoid excess size. This is easy for TED5 to edit though. This file is changed each time levels are saved in TED5 and is not used by the game. To make usable levels you must select the item &#039;Carmackize maps&#039; in the file menu, which will produce the &amp;lt;tt&amp;gt;GAMEMAPS&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;MAPTHEAD&amp;lt;/tt&amp;gt; is the header for the &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt; file. When maps are carmackized it is used to create the &amp;lt;tt&amp;gt;MAPHEAD&amp;lt;/tt&amp;gt; file. &amp;lt;tt&amp;gt;MAPTHEAD&amp;lt;/tt&amp;gt; contains several variables used by TED5 and some older games. Notably it has information for IDs tileinfo program to work with. Its structure is as follows:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset!!Type!!Description&lt;br /&gt;
|-&lt;br /&gt;
|0||[[UINT16LE]]||Bit field for level planes (+1 unmasked, +2 masked, +4 infoplane)&lt;br /&gt;
|-&lt;br /&gt;
|2||[[UINT16LE]]||Type of tile (8x8 = 1, 16x16 = 2, 32x32 = 3)&lt;br /&gt;
|-&lt;br /&gt;
|4||[[UINT16LE]]|||Number of unmasked tileinfo (TILEINFO) planes in file. Most games 2, speed and offset. Max 10&lt;br /&gt;
|-&lt;br /&gt;
|6||[[UINT16LE]]||Number of unmasked tiles&lt;br /&gt;
|-&lt;br /&gt;
|8||[[UINT32LE]][10]||Pointers to tileinfo planes in &amp;lt;tt&amp;gt;MAPTHEAD&amp;lt;/tt&amp;gt; file&lt;br /&gt;
|-&lt;br /&gt;
|48||[[UINT16LE]][10]||Size of TILFINFO planes data.&lt;br /&gt;
|-&lt;br /&gt;
|68||[[char]][10][8]||TILEINFO plane names&lt;br /&gt;
|-&lt;br /&gt;
|148||[[UINT16LE]]||Number of masked tileinfo (TILEINFOM) planes in file. Usually 7. Max 10&lt;br /&gt;
|-&lt;br /&gt;
|150||[[UINT16LE]]||Number of masked tiles&lt;br /&gt;
|-&lt;br /&gt;
|152||[[UINT16LE]][10]||Pointers to TILEINFOM planes in file&lt;br /&gt;
|-&lt;br /&gt;
|192||[[UINT16LE]][10]||Size of TILFINFOM planes data.&lt;br /&gt;
|-&lt;br /&gt;
|212||[[char]][10][8]||TILFINFOM plane names&lt;br /&gt;
|-&lt;br /&gt;
|292||[[UINT16LE]]||RLEW flag, default $ABCD&lt;br /&gt;
|-&lt;br /&gt;
|294||[[UINT32LE]][100]||Pointers to level headers in &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt;. 100 pointers, null values are -1 ($FFFFFFFF)&lt;br /&gt;
|-&lt;br /&gt;
|694||[[UINT32LE]][100]||Level header sizes &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt;. Older games Huffman Compressed headers and used this. Older games have $26 here, the (uncompressed) header size and don&#039;t use it&lt;br /&gt;
|-&lt;br /&gt;
|1094||[[UINT16LE]]||Number of ICON rows TED5 sets aside from masked tiles to display icons. For most games this is 5&lt;br /&gt;
|-&lt;br /&gt;
|1096||[[char]][x]||Optional TILEINFOM and TILEINFO data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Tedinfo ===&lt;br /&gt;
&lt;br /&gt;
This file is used by TED5 to store various details of the level format. Important here is the number of planes in each level, and the number of icons. Icons (used for sprites) are taken from the foreground tiles. The known values are:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset!!Type!!Description&lt;br /&gt;
|-&lt;br /&gt;
|0||[[UINT16LE]]||Level TED opens in (last edited)&lt;br /&gt;
|-&lt;br /&gt;
|2||[[UINT16LE]]||Screen view, close (1) or distant (2)&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|...&lt;br /&gt;
|-&lt;br /&gt;
|8||[[UINT16LE]]||Number of tile planes in levels (usually 2, fore and back)&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|...&lt;br /&gt;
|-&lt;br /&gt;
|35||[[BYTE]]||Planes editable/visible in TED; +1 view icon, +2 view fore, +4 view back, +16 edit icon, +32 edit fore, +64 edit back&lt;br /&gt;
|-&lt;br /&gt;
|36||[[UINT16LE]]||h loc in level&lt;br /&gt;
|-&lt;br /&gt;
|38||[[UINT16LE]]||v loc in level&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|...&lt;br /&gt;
|-&lt;br /&gt;
|119||[[char]][64]||Import map path&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Backup files ==&lt;br /&gt;
&lt;br /&gt;
TED5 backs up all its files when levels are saved or carmackized or TED5 is exited. The old files are saved as &amp;lt;tt&amp;gt;*.BAK&amp;lt;/tt&amp;gt; files and a simple renaming will suffice to undo the latest change. Only one backup is made so it is wise to save these files occasionally.&lt;br /&gt;
&lt;br /&gt;
== Setting up TED5 ==&lt;br /&gt;
&lt;br /&gt;
For uncompressed games, such as [[Bio Menace]], all that is required is to copy the file &amp;lt;tt&amp;gt;TED5.EXE&amp;lt;/tt&amp;gt; into the games directory. For compressed games the situation is slightly more complex.&lt;br /&gt;
&lt;br /&gt;
Some games, such as [[Commander Keen 4-6]] have a Ted setup utility to either extract or create the necessary files. If this is the case then a two step process is required. The first involves copying TED5 and the setup utility and running the setup to obtain the required files. The second step involves using a patching utility (Such as [[CKPatch]]) to patch the modified files back into the executable.&lt;br /&gt;
&lt;br /&gt;
Finally, some games, such as [[Catacomb 3D]], have no utilities at present. While it is not impossible to modify the levels in these games, it takes a bit more work, since the required files must be extracted manually and the executables illegally modified. It has already been mentioned how the graphics files can be located in an executable, but other files will need to be hard coded until somebody automates the procedure.&lt;br /&gt;
&lt;br /&gt;
== Modifying levels ==&lt;br /&gt;
&lt;br /&gt;
If TED5 is setup correctly then it should run (Dosbox may be required for this.) and go to the first level in the game, usually a world map. There are a number of commands and actions that can be used, which will not be covered here. After the desired changes have been made the user must select &#039;Carmackize maps&#039; from the file menu to produce a modified &amp;lt;tt&amp;gt;GAMEMAPS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;MAPHEAD&amp;lt;/tt&amp;gt; file. For compressed games such as Keen this file will then need to be patched into the executable.&lt;br /&gt;
&lt;br /&gt;
A level can be completely replaced with one from another GAMEMAPS file by using the &#039;Import levels&#039; command under the file menu. (You will need to specify a patch to a valid GAMEMAPS file.) This allows a person to copy levels between backups, etc.&lt;br /&gt;
&lt;br /&gt;
The program Instant Carma! skips Carmack compression by doing the very minimal amount of work. It takes a fraction of the time of TED5 and can be used while TED5 is running and is thus very useful. Sadly it is only available for Commander Keen 4-6.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- TODO: Perhaps write in full how to use TED5? Or just a link to the plumbing the depths of keen article? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other utilities ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;CKPatch:&amp;lt;/b&amp;gt; A set of utilities that allow Keen 4-6 executables to be modified temporarily and legally by patching a copy of the executable into memory and modifying that. This is vital for using new levels in Keen 4-6 There are several versions available, with the latest having the most features. http://www.bipship.com/CKPatch &lt;br /&gt;
* &amp;lt;b&amp;gt;Fixmhead:&amp;lt;/b&amp;gt; This converts the &amp;lt;tt&amp;gt;MAPTHEAD&amp;lt;/tt&amp;gt; file to &amp;lt;tt&amp;gt;MAPHEAD&amp;lt;/tt&amp;gt;. It is not really required for anything, but is included with a lot of TED5 packs.&lt;br /&gt;
* &amp;lt;b&amp;gt;Galaxymk:&amp;lt;/b&amp;gt; This pack contains everything needed to set Commander Keen 4-6 games up for editing with TED5, including the setups and patchers. http://keenmodding.org/search.php?search_author=The_Fosti&amp;amp;sid=92cde18022face91063ec52109b6c2ec&lt;br /&gt;
* &amp;lt;b&amp;gt;Instant Carma!:&amp;lt;/b&amp;gt; by CK Guy externalizes the carmackization of Keen 4-6 maps, saving time and improving efficiency. http://www.keenmodding.org/viewtopic.php?t=997&lt;br /&gt;
* &amp;lt;b&amp;gt;Tedsetup:&amp;lt;/b&amp;gt; A program that sets up certain games to be editable by TED5, automatically extracting or creating required files, Often comes with TED5&lt;br /&gt;
&lt;br /&gt;
== Supported Games ==&lt;br /&gt;
&lt;br /&gt;
This is a list of games that have been successfully edited with TED5: (though many of them have dedicated editors that are more user friendly)&lt;br /&gt;
&lt;br /&gt;
* [[Bio Menace]]&lt;br /&gt;
* [[Catacomb 3D]]&lt;br /&gt;
* [[Commander Keen 4-6]]&lt;br /&gt;
* [[Commander Keen Dreams]]&lt;br /&gt;
* [[Dangerous Dave 3]]&lt;br /&gt;
* [[Dangerous Dave 4]] (Dave Goes Nutz)&lt;br /&gt;
* [[Rise of the Triad]]&lt;br /&gt;
* [[Wolfenstein 3-D]]&lt;br /&gt;
&lt;br /&gt;
== Download ==&lt;br /&gt;
&lt;br /&gt;
TED5 has been released as open source freeware. TED5 and its source code can be downloaded from [http://www.3drealms.com/downloads.html#rott 3D Realms]. It can be used to edit the levels of Bio Menace and to create new levels for Rise of the Triad. It is also possible to edit the levels of Commander Keen 4-6, but this is a bit harder to [http://www.keenmodding.org/viewtopic.php?t=899 set up].&lt;br /&gt;
&lt;br /&gt;
[[Category:id Software]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- List of games that this editor works with --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Bio Menace]]&lt;br /&gt;
[[Category:Catacomb 3D]]&lt;br /&gt;
[[Category:Commander Keen 4-6]]&lt;br /&gt;
[[Category:Commander Keen Dreams]]&lt;br /&gt;
[[Category:Dangerous Dave 3]]&lt;br /&gt;
[[Category:Dangerous Dave 4]]&lt;br /&gt;
[[Category:Rise of the Triad]]&lt;br /&gt;
[[Category:Wolfenstein 3-D]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Talk:TED5&amp;diff=5225</id>
		<title>Talk:TED5</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Talk:TED5&amp;diff=5225"/>
		<updated>2014-06-14T19:26:30Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Gave links to TED5 source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;We need more details on how Dave 3&amp;amp;4 have been edited with TED, since these use a different level format to that of other games.~!Levellass;20-9-2009&lt;br /&gt;
:Different even to Keen Dreams?  Maybe we should have a bunch of instructions explaining how to configure TED5 for each game. -- [[User:Malvineous|Malvineous]] 22:32, 20 September 2009 (GMT)&lt;br /&gt;
&lt;br /&gt;
I&#039;m working on filling in the format specs, you can check out the TED5 source code at https://github.com/Fleex255/TED5/ or look at [https://github.com/Fleex255/TED5/blob/a602282af71d9c085c1270211889313131e4d24c/TED5.H the TED5.H file that contains most of the typedefs]. [[User:Fleexy|Fleexy]] ([[User talk:Fleexy|talk]]) 19:26, 14 June 2014 (GMT)&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=TED5&amp;diff=5224</id>
		<title>TED5</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=TED5&amp;diff=5224"/>
		<updated>2014-06-14T19:23:20Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: /* Maptemp and Mapthead */ Corrected and filled in the MAPTHEAD format. Source: https://github.com/Fleex255/TED5/blob/a602282af71d9c085c1270211889313131e4d24c/TED5.H&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Tool Infobox&lt;br /&gt;
 | Image = TED5-Keen4.png&lt;br /&gt;
 | Platform = DOS&lt;br /&gt;
 | Edit1 = Map&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Tile Editor v5.0 (TED5) is a level editor written by [[:Category:id Software|id Software]] that has been used to create the levels for many of their games. It edits the [[GameMaps Format]] seen in many older id Software games and is also apparently able to edit the [[Commander Keen 1-3 Level format]], though how is not known.&lt;br /&gt;
&lt;br /&gt;
== Files used by TED5 ==&lt;br /&gt;
&lt;br /&gt;
TED5 is compatible with any ID game that has a &amp;lt;tt&amp;gt;GAMEMAPS.xxx&amp;lt;/tt&amp;gt; file. However the actual &amp;lt;tt&amp;gt;GAMEMAPS.xxx&amp;lt;/tt&amp;gt; file is the final product, many other supporting files are required for TED5 to function.&lt;br /&gt;
&lt;br /&gt;
If the game is &#039;compressed&#039;, it will not have most of these files. [[Commander Keen 4-6]] is one such game. In contrast &#039;uncompressed&#039; games such as [[Bio Menace]] will have the full complement of files. Sadly, most games are compressed, as this is most efficient.&lt;br /&gt;
&lt;br /&gt;
=== EGAGRAPH.xxx, EGAHEAD.xxx and EGADCT.xxx ===&lt;br /&gt;
&lt;br /&gt;
These are explained fully under [[EGAGraph Format]]; they are respectively the game graphics, the graphics header and the [[Huffman Compression]] dictionary for decompressing graphics. Compressed games will just have the &amp;lt;tt&amp;gt;EGAGRAPH&amp;lt;/tt&amp;gt;; with the HEAD and DCT files stored internally in the executable. Uncompressed games will have an external &amp;lt;tt&amp;gt;EGAHEAD&amp;lt;/tt&amp;gt; and no need for an &amp;lt;tt&amp;gt;EGADCT&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
Like all Huffman dictionaries, the &amp;lt;tt&amp;gt;EGADCT&amp;lt;/tt&amp;gt; file can be located in the executable by looking for the string &amp;lt;tt&amp;gt;$FD $01 $00 $00 $00 $00&amp;lt;/tt&amp;gt; which is found at the file&#039;s end. (The file will be 1024 bytes long.) The &amp;lt;tt&amp;gt;EGAHEAD&amp;lt;/tt&amp;gt; file can be located by looking for a 4 (Or 3) byte string which is the &amp;lt;tt&amp;gt;EGAGRAPH&amp;lt;/tt&amp;gt; file size, this is always the last entry. (If you then proceed to move backwards until you reach a zero value entry, you will have the start of the file.)&lt;br /&gt;
&lt;br /&gt;
You will receive an error if these files are absent. If the DCT is missing then TED5 will assume graphics are uncompressed.&lt;br /&gt;
&amp;lt;!-- TODO: A list of the locations of the head and dct for supported games --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Gamemaps ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;GAMEMAPS&amp;lt;/tt&amp;gt; file is not used, but is produced by TED5. It contains the compressed game maps and is produced from the &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt; file when the user selects &#039;Carmackize maps&#039; in TED5. Carmackization is complex and takes a long time to do. Because of this it is recommended that modders use Instant Carma! (See below)&lt;br /&gt;
&lt;br /&gt;
=== GFXINFOE.xxx ===&lt;br /&gt;
&lt;br /&gt;
This is a 46 byte file that contains data allowing TED5 to extract the graphics used in levels.It consists of a number of numbers and locations of various tile types.&lt;br /&gt;
&lt;br /&gt;
Levels can be made of 8x8, 16x16 or 32x32 tiles (Always 16 color EGA.) Levels have a foreground plane, and may also have a background and info (Sprite) plane.The structure of the &amp;lt;tt&amp;gt;GFXINFOE&amp;lt;/tt&amp;gt; file is as follows:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset!!Type!!Description&lt;br /&gt;
|-&lt;br /&gt;
|0||[[UINT16LE]]||Number of 8x8 background tiles&lt;br /&gt;
|-&lt;br /&gt;
|2||[[UINT16LE]]||Number of 8x8 foreground tile&lt;br /&gt;
|-&lt;br /&gt;
|4||[[UINT16LE]]||Number of 16x16 background tiles&lt;br /&gt;
|-&lt;br /&gt;
|6||[[UINT16LE]]||Number of 16x16 foreground tiles&lt;br /&gt;
|-&lt;br /&gt;
|8||[[UINT16LE]]||Number of 32x32 background tiles&lt;br /&gt;
|-&lt;br /&gt;
|10||[[UINT16LE]]||Number of 32x32 foreground tiles&lt;br /&gt;
|-&lt;br /&gt;
|12||[[UINT16LE]]||8x8 back tile start&lt;br /&gt;
|-&lt;br /&gt;
|14||[[UINT16LE]]||8x8 fore tile start&lt;br /&gt;
|-&lt;br /&gt;
|16||[[UINT16LE]]||16x16 back start&lt;br /&gt;
|-&lt;br /&gt;
|18||[[UINT16LE]]||16x16 fore start&lt;br /&gt;
|-&lt;br /&gt;
|20||[[UINT16LE]]||32x32 back start&lt;br /&gt;
|-&lt;br /&gt;
|22||[[UINT16LE]]||32x32 back start &lt;br /&gt;
|-&lt;br /&gt;
|26||[[char]][20]||??? Usually blank, probably has some function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The location (Start) given for tiles is the entry in the &amp;lt;tt&amp;gt;EGAHEAD.xxx&amp;lt;/tt&amp;gt; file, most &amp;lt;tt&amp;gt;EGAHEAD.xxx&amp;lt;/tt&amp;gt; files consist of 3 byte entries so the actual location, in bytes, in the file is three times this, though older games (Such as [[Commander Keen Dreams]]) have 4 byte entries. (It is not known if or how TED5 tells the difference between these.) Each tile has its own entry in the header.&lt;br /&gt;
&lt;br /&gt;
The icons used by TED5 (For sprites, etc) are calculated as follows; icons follow directly after background tiles, then foreground tiles. There will thus be some &#039;extra&#039; slots between the back and fore tiles. These are used as the number of icons.&lt;br /&gt;
&lt;br /&gt;
This file is found with uncompressed games, but has to be created for compressed games. It is not currently known if it can be extracted somehow from the executable or if it is hard coded for each game.&lt;br /&gt;
&lt;br /&gt;
=== Maptemp and Mapthead ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt; file contains the uncarmackized level maps. Carmackization is a form of compression related to [[Keen 1-3 LZW compression]] in that it employs a sliding window. &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt; is however [[RLE Compression]] compressed to avoid excess size. This is easy for TED5 to edit though. This file is changed each time levels are saved in TED5 and is not used by the game. To make usable levels you must select the item &#039;Carmackize maps&#039; in the file menu, which will produce the &amp;lt;tt&amp;gt;GAMEMAPS&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;MAPTHEAD&amp;lt;/tt&amp;gt; is the header for the &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt; file. When maps are carmackized it is used to create the &amp;lt;tt&amp;gt;MAPHEAD&amp;lt;/tt&amp;gt; file. &amp;lt;tt&amp;gt;MAPTHEAD&amp;lt;/tt&amp;gt; contains several variables used by TED5 and some older games. Notably it has information for IDs tileinfo program to work with. Its structure is as follows:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset!!Type!!Description&lt;br /&gt;
|-&lt;br /&gt;
|0||[[UINT16LE]]||Bit field for level planes (+1 unmasked, +2 masked, +4 infoplane)&lt;br /&gt;
|-&lt;br /&gt;
|2||[[UINT16LE]]||Type of tile (8x8 = 1, 16x16 = 2, 32x32 = 3)&lt;br /&gt;
|-&lt;br /&gt;
|4||[[UINT16LE]]|||Number of unmasked tileinfo (TILEINFO) planes in file. Most games 2, speed and offset. Max 10&lt;br /&gt;
|-&lt;br /&gt;
|6||[[UINT16LE]]||Number of unmasked tiles&lt;br /&gt;
|-&lt;br /&gt;
|8||[[UINT32LE]][10]||Pointers to tileinfo planes in &amp;lt;tt&amp;gt;MAPTHEAD&amp;lt;/tt&amp;gt; file&lt;br /&gt;
|-&lt;br /&gt;
|48||[[UINT16LE]][10]||Size of TILFINFO planes data.&lt;br /&gt;
|-&lt;br /&gt;
|68||[[char]][10][8]||TILEINFO plane names&lt;br /&gt;
|-&lt;br /&gt;
|148||[[UINT16LE]]||Number of masked tileinfo (TILEINFOM) planes in file. Usually 7. Max 10&lt;br /&gt;
|-&lt;br /&gt;
|150||[[UINT16LE]]||Number of masked tiles&lt;br /&gt;
|-&lt;br /&gt;
|152||[[UINT16LE]][10]||Pointers to TILEINFOM planes in file&lt;br /&gt;
|-&lt;br /&gt;
|192||[[UINT16LE]][10]||Size of TILFINFOM planes data.&lt;br /&gt;
|-&lt;br /&gt;
|212||[[char]][10][8]||TILFINFOM plane names&lt;br /&gt;
|-&lt;br /&gt;
|292||[[UINT16LE]]||RLEW flag, default $ABCD&lt;br /&gt;
|-&lt;br /&gt;
|294||[[UINT32LE]][100]||Pointers to level headers in &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt;. 100 pointers, null values are -1 ($FFFFFFFF)&lt;br /&gt;
|-&lt;br /&gt;
|694||[[UINT32LE]][100]||Level header sizes &amp;lt;tt&amp;gt;MAPTEMP&amp;lt;/tt&amp;gt;. Older games Huffman Compressed headers and used this. Older games have $26 here, the (uncompressed) header size and don&#039;t use it&lt;br /&gt;
|-&lt;br /&gt;
|1094||[[UINT16LE]]||Number of ICON rows TED5 sets aside from masked tiles to display icons. For most games this is 5&lt;br /&gt;
|-&lt;br /&gt;
|1096||[[char]][x]||Optional TILEINFOM and TILEINFO data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Tedinfo ===&lt;br /&gt;
&lt;br /&gt;
This file is used by TED5 to store various details of the level format. Important here is the number of planes in each level, and the number of icons. Icons (used for sprites) are taken from the foreground tiles. The known values are:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset!!Type!!Description&lt;br /&gt;
|-&lt;br /&gt;
|0||[[UINT16LE]]||Level TED opens in (last edited)&lt;br /&gt;
|-&lt;br /&gt;
|2||[[UINT16LE]]||Screen view, close (1) or distant (2)&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|...&lt;br /&gt;
|-&lt;br /&gt;
|8||[[UINT16LE]]||Number of tile planes in levels (usually 2, fore and back)&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|...&lt;br /&gt;
|-&lt;br /&gt;
|35||[[BYTE]]||Planes editable/visible in TED; +1 view icon, +2 view fore, +4 view back, +16 edit icon, +32 edit fore, +64 edit back&lt;br /&gt;
|-&lt;br /&gt;
|36||[[UINT16LE]]||h loc in level&lt;br /&gt;
|-&lt;br /&gt;
|38||[[UINT16LE]]||v loc in level&lt;br /&gt;
|-&lt;br /&gt;
|colspan=3|...&lt;br /&gt;
|-&lt;br /&gt;
|119||[[char]][64]||Import map path&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Backup files ==&lt;br /&gt;
&lt;br /&gt;
TED5 backs up all its files when levels are saved or carmackized or TED5 is exited. The old files are saved as &amp;lt;tt&amp;gt;*.BAK&amp;lt;/tt&amp;gt; files and a simple renaming will suffice to undo the latest change. Only one backup is made so it is wise to save these files occasionally.&lt;br /&gt;
&lt;br /&gt;
== Setting up TED5 ==&lt;br /&gt;
&lt;br /&gt;
For uncompressed games, such as [[Bio Menace]], all that is required is to copy the file &amp;lt;tt&amp;gt;TED5.EXE&amp;lt;/tt&amp;gt; into the games directory. For compressed games the situation is slightly more complex.&lt;br /&gt;
&lt;br /&gt;
Some games, such as [[Commander Keen 4-6]] have a Ted setup utility to either extract or create the necessary files. If this is the case then a two step process is required. The first involves copying TED5 and the setup utility and running the setup to obtain the required files. The second step involves using a patching utility (Such as [[CKPatch]]) to patch the modified files back into the executable.&lt;br /&gt;
&lt;br /&gt;
Finally, some games, such as [[Catacomb 3D]], have no utilities at present. While it is not impossible to modify the levels in these games, it takes a bit more work, since the required files must be extracted manually and the executables illegally modified. It has already been mentioned how the graphics files can be located in an executable, but other files will need to be hard coded until somebody automates the procedure.&lt;br /&gt;
&lt;br /&gt;
== Modifying levels ==&lt;br /&gt;
&lt;br /&gt;
If TED5 is setup correctly then it should run (Dosbox may be required for this.) and go to the first level in the game, usually a world map. There are a number of commands and actions that can be used, which will not be covered here. After the desired changes have been made the user must select &#039;Carmackize maps&#039; from the file menu to produce a modified &amp;lt;tt&amp;gt;GAMEMAPS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;MAPHEAD&amp;lt;/tt&amp;gt; file. For compressed games such as Keen this file will then need to be patched into the executable.&lt;br /&gt;
&lt;br /&gt;
A level can be completely replaced with one from another GAMEMAPS file by using the &#039;Import levels&#039; command under the file menu. (You will need to specify a patch to a valid GAMEMAPS file.) This allows a person to copy levels between backups, etc.&lt;br /&gt;
&lt;br /&gt;
The program Instant Carma! skips Carmack compression by doing the very minimal amount of work. It takes a fraction of the time of TED5 and can be used while TED5 is running and is thus very useful. Sadly it is only available for Commander Keen 4-6.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- TODO: Perhaps write in full how to use TED5? Or just a link to the plumbing the depths of keen article? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other utilities ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;CKPatch:&amp;lt;/b&amp;gt; A set of utilities that allow Keen 4-6 executables to be modified temporarily and legally by patching a copy of the executable into memory and modifying that. This is vital for using new levels in Keen 4-6 There are several versions available, with the latest having the most features. http://www.bipship.com/CKPatch &lt;br /&gt;
* &amp;lt;b&amp;gt;Fixmhead:&amp;lt;/b&amp;gt; This converts the &amp;lt;tt&amp;gt;MAPTHEAD&amp;lt;/tt&amp;gt; file to &amp;lt;tt&amp;gt;MAPHEAD&amp;lt;/tt&amp;gt;. It is not really required for anything, but is included with a lot of TED5 packs.&lt;br /&gt;
* &amp;lt;b&amp;gt;Galaxymk:&amp;lt;/b&amp;gt; This pack contains everything needed to set Commander Keen 4-6 games up for editing with TED5, including the setups and patchers. http://keenmodding.org/search.php?search_author=The_Fosti&amp;amp;sid=92cde18022face91063ec52109b6c2ec&lt;br /&gt;
* &amp;lt;b&amp;gt;Instant Carma!:&amp;lt;/b&amp;gt; by CK Guy externalizes the carmackization of Keen 4-6 maps, saving time and improving efficiency. http://www.keenmodding.org/viewtopic.php?t=997&lt;br /&gt;
* &amp;lt;b&amp;gt;Tedsetup:&amp;lt;/b&amp;gt; A program that sets up certain games to be editable by TED5, automatically extracting or creating required files, Often comes with TED5&lt;br /&gt;
&lt;br /&gt;
== Supported Games ==&lt;br /&gt;
&lt;br /&gt;
This is a list of games that have been successfully edited with TED5: (though many of them have dedicated editors that are more user friendly)&lt;br /&gt;
&lt;br /&gt;
* [[Bio Menace]]&lt;br /&gt;
* [[Catacomb 3D]]&lt;br /&gt;
* [[Commander Keen 4-6]]&lt;br /&gt;
* [[Commander Keen Dreams]]&lt;br /&gt;
* [[Dangerous Dave 3]]&lt;br /&gt;
* [[Dangerous Dave 4]] (Dave Goes Nutz)&lt;br /&gt;
* [[Rise of the Triad]]&lt;br /&gt;
* [[Wolfenstein 3-D]]&lt;br /&gt;
&lt;br /&gt;
== Download ==&lt;br /&gt;
&lt;br /&gt;
TED5 has been released as open source freeware. TED5 and its source code can be downloaded from [http://www.3drealms.com/downloads.html#rott 3D Realms]. It can be used to edit the levels of Bio Menace and to create new levels for Rise of the Triad. It is also possible to edit the levels of Commander Keen 4-6, but this is a bit harder to [http://www.keenmodding.org/viewtopic.php?t=899 set up].&lt;br /&gt;
&lt;br /&gt;
[[Category:id Software]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- List of games that this editor works with --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Bio Menace]]&lt;br /&gt;
[[Category:Catacomb 3D]]&lt;br /&gt;
[[Category:Commander Keen 4-6]]&lt;br /&gt;
[[Category:Commander Keen Dreams]]&lt;br /&gt;
[[Category:Dangerous Dave 3]]&lt;br /&gt;
[[Category:Dangerous Dave 4]]&lt;br /&gt;
[[Category:Rise of the Triad]]&lt;br /&gt;
[[Category:Wolfenstein 3-D]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=File_format_data_types&amp;diff=5098</id>
		<title>File format data types</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=File_format_data_types&amp;diff=5098"/>
		<updated>2014-01-03T20:26:32Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Changed source language parameter on VB .NET stuff to be dot-netty&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a list of all the data types used in the file format descriptions on the wiki.  They are loosely based on common C/C++ data types, and should be used throughout the wiki for consistency.&lt;br /&gt;
&lt;br /&gt;
== Type list ==&lt;br /&gt;
&lt;br /&gt;
==== Numeric values ====&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||Unsigned 8-bit integer&lt;br /&gt;
|-&lt;br /&gt;
|UINT16LE||Unsigned 16-bit integer in little-endian format&lt;br /&gt;
|-&lt;br /&gt;
|UINT16BE||Unsigned 16-bit integer in big-endian format&lt;br /&gt;
|-&lt;br /&gt;
|UINT32LE||Unsigned 32-bit integer in little-endian format&lt;br /&gt;
|-&lt;br /&gt;
|UINT32BE||Unsigned 32-bit integer in big-endian format&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Signed equivalents are the same without the leading U, i.e. &amp;lt;tt&amp;gt;INT8&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;INT16LE&amp;lt;/tt&amp;gt;, etc.  Unless otherwise stated, the format is in [[wikipedia:Two&#039;s complement|two&#039;s complement]] (where a UINT8 value of 255 is -1 as an INT8, for example.)&lt;br /&gt;
&lt;br /&gt;
==== Character strings ====&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Data type!!Description&lt;br /&gt;
|-&lt;br /&gt;
|char[x]||String &#039;&#039;x&#039;&#039; characters long&lt;br /&gt;
|-&lt;br /&gt;
|char||Single 8-bit character&lt;br /&gt;
|-&lt;br /&gt;
|ASCIIZ||A C-style string (variable-length, terminated with a single NULL/0x00 value)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Misc data types ====&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Data type!!Description&lt;br /&gt;
|-&lt;br /&gt;
|BYTE||Same as UINT8 but conceptually for generic data rather than numeric values (e.g. UINT8 would be used for a number, while a BYTE would be used for a bitfield)&lt;br /&gt;
|-&lt;br /&gt;
|BYTE[x]||Block of data &#039;&#039;x&#039;&#039; bytes long&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Big endian vs little endian ==&lt;br /&gt;
&lt;br /&gt;
For numeric values larger than a single byte, the endianness specifies how the values are split over multiple bytes.  For example a hex value of 0x1234AABB when written to a file will take up two bytes, as follows:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Endian!!Bytes in file&lt;br /&gt;
|-&lt;br /&gt;
|Big||&amp;lt;code&amp;gt;12 34 AA BB&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Little||&amp;lt;code&amp;gt;BB AA 34 12&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For those languages that allow direct memory access such as C/C++, converting an integer value to a byte array will reveal the value stored in-memory in the same order as the table above.&lt;br /&gt;
&lt;br /&gt;
Normally when reading or writing a variable to a file a programmer will simply pass the memory address of the variable, resulting in the file mirroring the byte order in memory.  This is no problem when reading the variable back in on the same system, as the byte order will match.  However when reading data from a different system (for example using an Intel PC to read files from a PowerPC Mac) the byte order will be opposite to what the system expects and the programmer must convert the values manually.&lt;br /&gt;
&lt;br /&gt;
=== Conversion examples ===&lt;br /&gt;
&lt;br /&gt;
If a value is being read on the same system (little to little or big to big) then no action is required.  If the systems are different, then the values must be swapped.  The following sections list examples for different programming languages.&lt;br /&gt;
&lt;br /&gt;
==== C/C++ ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// 16-bit&lt;br /&gt;
int in = 0x1234;&lt;br /&gt;
int out = ((in &amp;amp; 0xFF) &amp;lt;&amp;lt; 8) | (in &amp;gt;&amp;gt; 8);&lt;br /&gt;
// out should now be 0x3412&lt;br /&gt;
&lt;br /&gt;
// 32-bit&lt;br /&gt;
int in = 0x1234AABB;&lt;br /&gt;
int out =&lt;br /&gt;
  ((in &amp;amp; 0xFF) &amp;lt;&amp;lt; 24) |&lt;br /&gt;
  ((in &amp;amp; 0xFF00) &amp;lt;&amp;lt; 8) |&lt;br /&gt;
  ((in &amp;amp; 0xFF0000) &amp;gt;&amp;gt; 8) |&lt;br /&gt;
  (in &amp;gt;&amp;gt; 24);&lt;br /&gt;
// out should now be 0xBBAA3412&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Visual Basic .NET ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vbnet&amp;quot;&amp;gt;&lt;br /&gt;
Function ByteSwap16(ByVal InValue as Int16) as Int16&lt;br /&gt;
  Return ((InValue And 255) &amp;lt;&amp;lt; 8) Or (InValue &amp;gt;&amp;gt; 8)&lt;br /&gt;
End Function&lt;br /&gt;
&lt;br /&gt;
Function ByteSwap32(ByVal InValue as Int32) as Int32&lt;br /&gt;
  Return ((InValue And &amp;amp;HFF) &amp;lt;&amp;lt; 24) Or _&lt;br /&gt;
         ((InValue And &amp;amp;HFF00) &amp;lt;&amp;lt; 8) Or _&lt;br /&gt;
         ((InValue And &amp;amp;HFF0000) &amp;gt;&amp;gt; 8) Or _&lt;br /&gt;
         (InValue &amp;gt;&amp;gt; 24)&lt;br /&gt;
End Function&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:File Formats]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=User_talk:Levellass&amp;diff=5097</id>
		<title>User talk:Levellass</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=User_talk:Levellass&amp;diff=5097"/>
		<updated>2014-01-03T17:32:51Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Asked question about EGADICT&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Hi Levellass - not sure if you&#039;ve seen the question on [[Talk:Softdisk Library Format]] but since you wrote it you&#039;re probably best placed to answer! -- [[User:Malvineous|Malvineous]] 02:26, 6 January 2012 (GMT)&lt;br /&gt;
&lt;br /&gt;
Hi Levellass - I reverted your change to [[IMF Format]] (removing [[:Category:File Formats]]) because I am trying to remove all the pages from that category, instead putting them into more specific ones.  So in this case [[IMF Format]] will appear in [[:Category:All file formats]] as well as [[:Category:All music formats]].  And these categories should apply automatically when an infobox is added to the article page, so hopefully there will be no need to add categories manually!  So if you spot any pages missing categories, please add infoboxes to them instead of just the bare categories.  Thanks! -- [[User:Malvineous|Malvineous]] 09:03, 8 March 2013 (GMT)&lt;br /&gt;
: Nifty, that should certainly simplify things. -[[User:Levellass|Endian? What are you on about?]]&lt;br /&gt;
&lt;br /&gt;
Hey, LL! Your new example/explanation of Huffman helped a lot in writing a decompressor, but I&#039;m having an issue using it on EGAGRAPH. I verified that it is identical to the EGADICT created by KG and that I am reading it correctly. I get a tree full of reversed bit sequences, just like you said. However, the EGAGRAPH does not appear to use reversed bit sequences; it is completely uncompressed. (It does still have the UInt32LE at the front of the appropriate chunks specifying decompressed length.) Keen can read it and KeenGraph can read it, but using the provided dictionary, I can&#039;t. Can you help me? [[User:Fleexy|Fleexy]] ([[User talk:Fleexy|talk]]) 17:32, 3 January 2014 (GMT)&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=5096</id>
		<title>Huffman Compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=5096"/>
		<updated>2014-01-02T16:24:31Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Added HasValue property to BinaryTreeNode&amp;lt;T&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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 making/reading a &#039;&#039;dictionary&#039;&#039; of 256 entries, one for each possible 1-byte character.  This is organised in the form of a &#039;&#039;binary tree&#039;&#039; which is basically formed by taking the two lowest frequency characters and combining them into a new entry with their added frequencies and repeating until all entries are reduced to one &#039;&#039;root node&#039;&#039;.  After the dictionary is created, every character of data is replaced with the corresponding bit representation from the tree.&lt;br /&gt;
&lt;br /&gt;
Any Huffman compressed data will thus be associated with a dictionary file (internal or external) used to decompress it.&lt;br /&gt;
&lt;br /&gt;
==Nodes==&lt;br /&gt;
&lt;br /&gt;
The binary tree must be stored in some form, usually called a &#039;&#039;dictionary&#039;&#039;. The format varies from game to game, but is usually broadly along these lines. The tree will have 254 nodes (for all the one byte characters in game data) stored as two &#039;branches&#039; of that node, usually taking up 4 bytes each, but sometimes 3. The second part is either 0 or 1, and says whether that branch goes to a character (0) or another node (1).  The first part is the value of either that character or that node. (For the usual 4-byte implementation each part is a byte.)&lt;br /&gt;
&lt;br /&gt;
In the Huffman table then we can expect to see each possible character TWICE, once as a character, once as a node reference. Note that the nodes are numbered from 0-253, NOT 1-254. The order of the nodes doesn&#039;t matter, only how they are connected.&lt;br /&gt;
&lt;br /&gt;
The root node is ALWAYS node 254 (number 253!) and should always be something like $xx $yy $00 $00 (Since 0 is the most common character it is closest to the root.) It will also tend to be at the end of the dictionary, since most programs find it easier to write their dictionaries from bottom to top. This can often be used to find Huffman dictionaries in files, if you know what you are looking for.&lt;br /&gt;
&lt;br /&gt;
==Example 1==&lt;br /&gt;
&lt;br /&gt;
Compress the word &amp;quot;HUFFMAN&amp;quot;.  For simplicity, we will not use the usual 256 character tree, but rather something a bit smaller. (Huffman trees can be any size, the concept is the same.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Frequencies are:&amp;lt;br/&amp;gt;1: H,U,M,A,N&amp;lt;br/&amp;gt;2: F&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Make a binary tree: (here left = 0 and right = 1)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &#039;Root node&#039;&lt;br /&gt;
       * &lt;br /&gt;
      / \&lt;br /&gt;
     /   * &lt;br /&gt;
    /   / \&lt;br /&gt;
   *   *   *&lt;br /&gt;
  / \ / \ / \&lt;br /&gt;
  F N M A H U&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The first letter is &#039;H&#039;; this on the tree is &amp;lt;tt&amp;gt;110&amp;lt;/tt&amp;gt; The next letter is &#039;U&#039; which is &amp;lt;tt&amp;gt;111&amp;lt;/tt&amp;gt;.  The third letter is &#039;F&#039; which is &amp;lt;tt&amp;gt;00&amp;lt;/tt&amp;gt; and so on (notice common letters have shorter strings?)  The final output in bits is &amp;lt;tt&amp;gt;110111000010010101&amp;lt;/tt&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not of course the optimum Huffman tree, but that doesn&#039;t matter, ANY tree will do. As bytes the output is thus: &amp;lt;tt&amp;gt;11011100 00100101 01000000&amp;lt;/tt&amp;gt; (the end bit is padded with nulls) or &amp;lt;tt&amp;gt;$DC $25 $40&amp;lt;/tt&amp;gt;.  We have a reduction in size from 7 bytes to 3, over 50%!  Sadly, we then need to include the Huffman table (the &#039;&#039;dictionary&#039;&#039;) in some form.&lt;br /&gt;
&lt;br /&gt;
A possibility for storing the dictionary might be: &amp;lt;tt&amp;gt;$00 $46 $00 $4E $00 $4D $00 $41 $00 $48 $00 $55 $01 $02 $01 $03 $01 $01 $01 $00&amp;lt;/tt&amp;gt;.  Here we have numbered the nodes starting at the root as 254 and labelled every other node from 0-4 going left to right and top to bottom. (If this is hard to see, try drawing things out on a piece of paper, the first 12 bytes are the bottom 3 nodes, all pointing to characters, and the last 8 bytes are the top two nodes, all pointing to other nodes.) This is the format used in Keen 4-6 executables.&lt;br /&gt;
&lt;br /&gt;
To decompress the data we use the tree again starting at the root node and reading the data bit by bit. So the first three bits are &amp;lt;tt&amp;gt;100&amp;lt;/tt&amp;gt; which leads us down the tree to character &#039;H&#039;, then &amp;lt;tt&amp;gt;000&amp;lt;/tt&amp;gt; which leads us to &#039;U&#039; and so on.&lt;br /&gt;
&lt;br /&gt;
==Example 2==&lt;br /&gt;
&lt;br /&gt;
The following 1020 bytes constitute the complete &#039;trivial&#039; Huffman dictionary, that is, one that does not compress the data at all:&lt;br /&gt;
&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;
This is a useful example to use since it has a number of unique features. Firstly the paths to any given terminal node are all the same length, 8 bits. Secondly the path to each terminal node is the &#039;&#039;reverse&#039;&#039; of the character it represents. And finally 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;
As an example the character $80 (128 or 10000000) can be expected to be represented by the path &#039;00000001&#039; and as such be the second node in the tree. Starting at the root node and following the leftmost path until the last step takes us to the following nodes: 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; Test Function&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;
[[Category:File Formats]]&lt;br /&gt;
[[Category:Compressed Files]]&lt;br /&gt;
[[Category:Huffman Compression]]&lt;br /&gt;
[[Category:Compression Algorithms]]&lt;br /&gt;
[[Category:Code examples]]&lt;br /&gt;
[[Category:Dangerous Dave 2]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=5095</id>
		<title>Huffman Compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=5095"/>
		<updated>2014-01-02T15:26:56Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Corrected BinaryTreeNode&amp;lt;T&amp;gt;.ChildSide enumeration values&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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 making/reading a &#039;&#039;dictionary&#039;&#039; of 256 entries, one for each possible 1-byte character.  This is organised in the form of a &#039;&#039;binary tree&#039;&#039; which is basically formed by taking the two lowest frequency characters and combining them into a new entry with their added frequencies and repeating until all entries are reduced to one &#039;&#039;root node&#039;&#039;.  After the dictionary is created, every character of data is replaced with the corresponding bit representation from the tree.&lt;br /&gt;
&lt;br /&gt;
Any Huffman compressed data will thus be associated with a dictionary file (internal or external) used to decompress it.&lt;br /&gt;
&lt;br /&gt;
==Nodes==&lt;br /&gt;
&lt;br /&gt;
The binary tree must be stored in some form, usually called a &#039;&#039;dictionary&#039;&#039;. The format varies from game to game, but is usually broadly along these lines. The tree will have 254 nodes (for all the one byte characters in game data) stored as two &#039;branches&#039; of that node, usually taking up 4 bytes each, but sometimes 3. The second part is either 0 or 1, and says whether that branch goes to a character (0) or another node (1).  The first part is the value of either that character or that node. (For the usual 4-byte implementation each part is a byte.)&lt;br /&gt;
&lt;br /&gt;
In the Huffman table then we can expect to see each possible character TWICE, once as a character, once as a node reference. Note that the nodes are numbered from 0-253, NOT 1-254. The order of the nodes doesn&#039;t matter, only how they are connected.&lt;br /&gt;
&lt;br /&gt;
The root node is ALWAYS node 254 (number 253!) and should always be something like $xx $yy $00 $00 (Since 0 is the most common character it is closest to the root.) It will also tend to be at the end of the dictionary, since most programs find it easier to write their dictionaries from bottom to top. This can often be used to find Huffman dictionaries in files, if you know what you are looking for.&lt;br /&gt;
&lt;br /&gt;
==Example 1==&lt;br /&gt;
&lt;br /&gt;
Compress the word &amp;quot;HUFFMAN&amp;quot;.  For simplicity, we will not use the usual 256 character tree, but rather something a bit smaller. (Huffman trees can be any size, the concept is the same.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Frequencies are:&amp;lt;br/&amp;gt;1: H,U,M,A,N&amp;lt;br/&amp;gt;2: F&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Make a binary tree: (here left = 0 and right = 1)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &#039;Root node&#039;&lt;br /&gt;
       * &lt;br /&gt;
      / \&lt;br /&gt;
     /   * &lt;br /&gt;
    /   / \&lt;br /&gt;
   *   *   *&lt;br /&gt;
  / \ / \ / \&lt;br /&gt;
  F N M A H U&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The first letter is &#039;H&#039;; this on the tree is &amp;lt;tt&amp;gt;110&amp;lt;/tt&amp;gt; The next letter is &#039;U&#039; which is &amp;lt;tt&amp;gt;111&amp;lt;/tt&amp;gt;.  The third letter is &#039;F&#039; which is &amp;lt;tt&amp;gt;00&amp;lt;/tt&amp;gt; and so on (notice common letters have shorter strings?)  The final output in bits is &amp;lt;tt&amp;gt;110111000010010101&amp;lt;/tt&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not of course the optimum Huffman tree, but that doesn&#039;t matter, ANY tree will do. As bytes the output is thus: &amp;lt;tt&amp;gt;11011100 00100101 01000000&amp;lt;/tt&amp;gt; (the end bit is padded with nulls) or &amp;lt;tt&amp;gt;$DC $25 $40&amp;lt;/tt&amp;gt;.  We have a reduction in size from 7 bytes to 3, over 50%!  Sadly, we then need to include the Huffman table (the &#039;&#039;dictionary&#039;&#039;) in some form.&lt;br /&gt;
&lt;br /&gt;
A possibility for storing the dictionary might be: &amp;lt;tt&amp;gt;$00 $46 $00 $4E $00 $4D $00 $41 $00 $48 $00 $55 $01 $02 $01 $03 $01 $01 $01 $00&amp;lt;/tt&amp;gt;.  Here we have numbered the nodes starting at the root as 254 and labelled every other node from 0-4 going left to right and top to bottom. (If this is hard to see, try drawing things out on a piece of paper, the first 12 bytes are the bottom 3 nodes, all pointing to characters, and the last 8 bytes are the top two nodes, all pointing to other nodes.) This is the format used in Keen 4-6 executables.&lt;br /&gt;
&lt;br /&gt;
To decompress the data we use the tree again starting at the root node and reading the data bit by bit. So the first three bits are &amp;lt;tt&amp;gt;100&amp;lt;/tt&amp;gt; which leads us down the tree to character &#039;H&#039;, then &amp;lt;tt&amp;gt;000&amp;lt;/tt&amp;gt; which leads us to &#039;U&#039; and so on.&lt;br /&gt;
&lt;br /&gt;
==Example 2==&lt;br /&gt;
&lt;br /&gt;
The following 1020 bytes constitute the complete &#039;trivial&#039; Huffman dictionary, that is, one that does not compress the data at all:&lt;br /&gt;
&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;
This is a useful example to use since it has a number of unique features. Firstly the paths to any given terminal node are all the same length, 8 bits. Secondly the path to each terminal node is the &#039;&#039;reverse&#039;&#039; of the character it represents. And finally 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;
As an example the character $80 (128 or 10000000) can be expected to be represented by the path &#039;00000001&#039; and as such be the second node in the tree. Starting at the root node and following the leftmost path until the last step takes us to the following nodes: 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; Test Function&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 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;
[[Category:File Formats]]&lt;br /&gt;
[[Category:Compressed Files]]&lt;br /&gt;
[[Category:Huffman Compression]]&lt;br /&gt;
[[Category:Compression Algorithms]]&lt;br /&gt;
[[Category:Code examples]]&lt;br /&gt;
[[Category:Dangerous Dave 2]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=5093</id>
		<title>Huffman Compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=5093"/>
		<updated>2014-01-02T01:24:03Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Fixed variable type mismatch in the newly added VB.NET code&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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 making/reading a &#039;&#039;dictionary&#039;&#039; of 256 entries, one for each possible 1-byte character.  This is organised in the form of a &#039;&#039;binary tree&#039;&#039; which is basically formed by taking the two lowest frequency characters and combining them into a new entry with their added frequencies and repeating until all entries are reduced to one &#039;&#039;root node&#039;&#039;.  After the dictionary is created, every character of data is replaced with the corresponding bit representation from the tree.&lt;br /&gt;
&lt;br /&gt;
Any Huffman compressed data will thus be associated with a dictionary file (internal or external) used to decompress it.&lt;br /&gt;
&lt;br /&gt;
==Nodes==&lt;br /&gt;
&lt;br /&gt;
The binary tree must be stored in some form, usually called a &#039;&#039;dictionary&#039;&#039;. The format varies from game to game, but is usually broadly along these lines. The tree will have 254 nodes (for all the one byte characters in game data) stored as two &#039;branches&#039; of that node, usually taking up 4 bytes each, but sometimes 3. The second part is either 0 or 1, and says whether that branch goes to a character (0) or another node (1).  The first part is the value of either that character or that node. (For the usual 4-byte implementation each part is a byte.)&lt;br /&gt;
&lt;br /&gt;
In the Huffman table then we can expect to see each possible character TWICE, once as a character, once as a node reference. Note that the nodes are numbered from 0-253, NOT 1-254. The order of the nodes doesn&#039;t matter, only how they are connected.&lt;br /&gt;
&lt;br /&gt;
The root node is ALWAYS node 254 (number 253!) and should always be something like $xx $yy $00 $00 (Since 0 is the most common character it is closest to the root.) It will also tend to be at the end of the dictionary, since most programs find it easier to write their dictionaries from bottom to top. This can often be used to find Huffman dictionaries in files, if you know what you are looking for.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&lt;br /&gt;
Compress the word &amp;quot;HUFFMAN&amp;quot;.  For simplicity, we will not use the usual 256 character tree, but rather something a bit smaller. (Huffman trees can be any size, the concept is the same.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Frequencies are:&amp;lt;br/&amp;gt;1: H,U,M,A,N&amp;lt;br/&amp;gt;2: F&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Make a binary tree: (here left = 0 and right = 1)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &#039;Root node&#039;&lt;br /&gt;
       * &lt;br /&gt;
      / \&lt;br /&gt;
     /   * &lt;br /&gt;
    /   / \&lt;br /&gt;
   *   *   *&lt;br /&gt;
  / \ / \ / \&lt;br /&gt;
  F N M A H U&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The first letter is &#039;H&#039;; this on the tree is &amp;lt;tt&amp;gt;110&amp;lt;/tt&amp;gt; The next letter is &#039;U&#039; which is &amp;lt;tt&amp;gt;111&amp;lt;/tt&amp;gt;.  The third letter is &#039;F&#039; which is &amp;lt;tt&amp;gt;00&amp;lt;/tt&amp;gt; and so on (notice common letters have shorter strings?)  The final output in bits is &amp;lt;tt&amp;gt;110111000010010101&amp;lt;/tt&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not of course the optimum Huffman tree, but that doesn&#039;t matter, ANY tree will do. As bytes the output is thus: &amp;lt;tt&amp;gt;11011100 00100101 01000000&amp;lt;/tt&amp;gt; (the end bit is padded with nulls) or &amp;lt;tt&amp;gt;$DC $25 $40&amp;lt;/tt&amp;gt;.  We have a reduction in size from 7 bytes to 3, over 50%!  Sadly, we then need to include the Huffman table (the &#039;&#039;dictionary&#039;&#039;) in some form.&lt;br /&gt;
&lt;br /&gt;
A possibility for storing the dictionary might be: &amp;lt;tt&amp;gt;$00 $46 $00 $4E $00 $4D $00 $41 $00 $48 $00 $55 $01 $02 $01 $03 $01 $01 $01 $00&amp;lt;/tt&amp;gt;.  Here we have numbered the nodes starting at the root as 254 and labelled every other node from 0-4 going left to right and top to bottom. (If this is hard to see, try drawing things out on a piece of paper, the first 12 bytes are the bottom 3 nodes, all pointing to characters, and the last 8 bytes are the top two nodes, all pointing to other nodes.) This is the format used in Keen 4-6 executables.&lt;br /&gt;
&lt;br /&gt;
To decompress the data we use the tree again starting at the root node and reading the data bit by bit. So the first three bits are &amp;lt;tt&amp;gt;100&amp;lt;/tt&amp;gt; which leads us down the tree to character &#039;H&#039;, then &amp;lt;tt&amp;gt;000&amp;lt;/tt&amp;gt; which leads us to &#039;U&#039; and so on.&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; Test Function&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 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 = 0&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;
[[Category:File Formats]]&lt;br /&gt;
[[Category:Compressed Files]]&lt;br /&gt;
[[Category:Huffman Compression]]&lt;br /&gt;
[[Category:Compression Algorithms]]&lt;br /&gt;
[[Category:Code examples]]&lt;br /&gt;
[[Category:Dangerous Dave 2]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=5092</id>
		<title>Huffman Compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Huffman_Compression&amp;diff=5092"/>
		<updated>2014-01-02T01:22:29Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Made the encoding example&amp;#039;s bits correct, added VB.NET code&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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 making/reading a &#039;&#039;dictionary&#039;&#039; of 256 entries, one for each possible 1-byte character.  This is organised in the form of a &#039;&#039;binary tree&#039;&#039; which is basically formed by taking the two lowest frequency characters and combining them into a new entry with their added frequencies and repeating until all entries are reduced to one &#039;&#039;root node&#039;&#039;.  After the dictionary is created, every character of data is replaced with the corresponding bit representation from the tree.&lt;br /&gt;
&lt;br /&gt;
Any Huffman compressed data will thus be associated with a dictionary file (internal or external) used to decompress it.&lt;br /&gt;
&lt;br /&gt;
==Nodes==&lt;br /&gt;
&lt;br /&gt;
The binary tree must be stored in some form, usually called a &#039;&#039;dictionary&#039;&#039;. The format varies from game to game, but is usually broadly along these lines. The tree will have 254 nodes (for all the one byte characters in game data) stored as two &#039;branches&#039; of that node, usually taking up 4 bytes each, but sometimes 3. The second part is either 0 or 1, and says whether that branch goes to a character (0) or another node (1).  The first part is the value of either that character or that node. (For the usual 4-byte implementation each part is a byte.)&lt;br /&gt;
&lt;br /&gt;
In the Huffman table then we can expect to see each possible character TWICE, once as a character, once as a node reference. Note that the nodes are numbered from 0-253, NOT 1-254. The order of the nodes doesn&#039;t matter, only how they are connected.&lt;br /&gt;
&lt;br /&gt;
The root node is ALWAYS node 254 (number 253!) and should always be something like $xx $yy $00 $00 (Since 0 is the most common character it is closest to the root.) It will also tend to be at the end of the dictionary, since most programs find it easier to write their dictionaries from bottom to top. This can often be used to find Huffman dictionaries in files, if you know what you are looking for.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&lt;br /&gt;
Compress the word &amp;quot;HUFFMAN&amp;quot;.  For simplicity, we will not use the usual 256 character tree, but rather something a bit smaller. (Huffman trees can be any size, the concept is the same.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Frequencies are:&amp;lt;br/&amp;gt;1: H,U,M,A,N&amp;lt;br/&amp;gt;2: F&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Make a binary tree: (here left = 0 and right = 1)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &#039;Root node&#039;&lt;br /&gt;
       * &lt;br /&gt;
      / \&lt;br /&gt;
     /   * &lt;br /&gt;
    /   / \&lt;br /&gt;
   *   *   *&lt;br /&gt;
  / \ / \ / \&lt;br /&gt;
  F N M A H U&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The first letter is &#039;H&#039;; this on the tree is &amp;lt;tt&amp;gt;110&amp;lt;/tt&amp;gt; The next letter is &#039;U&#039; which is &amp;lt;tt&amp;gt;111&amp;lt;/tt&amp;gt;.  The third letter is &#039;F&#039; which is &amp;lt;tt&amp;gt;00&amp;lt;/tt&amp;gt; and so on (notice common letters have shorter strings?)  The final output in bits is &amp;lt;tt&amp;gt;110111000010010101&amp;lt;/tt&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not of course the optimum Huffman tree, but that doesn&#039;t matter, ANY tree will do. As bytes the output is thus: &amp;lt;tt&amp;gt;11011100 00100101 01000000&amp;lt;/tt&amp;gt; (the end bit is padded with nulls) or &amp;lt;tt&amp;gt;$DC $25 $40&amp;lt;/tt&amp;gt;.  We have a reduction in size from 7 bytes to 3, over 50%!  Sadly, we then need to include the Huffman table (the &#039;&#039;dictionary&#039;&#039;) in some form.&lt;br /&gt;
&lt;br /&gt;
A possibility for storing the dictionary might be: &amp;lt;tt&amp;gt;$00 $46 $00 $4E $00 $4D $00 $41 $00 $48 $00 $55 $01 $02 $01 $03 $01 $01 $01 $00&amp;lt;/tt&amp;gt;.  Here we have numbered the nodes starting at the root as 254 and labelled every other node from 0-4 going left to right and top to bottom. (If this is hard to see, try drawing things out on a piece of paper, the first 12 bytes are the bottom 3 nodes, all pointing to characters, and the last 8 bytes are the top two nodes, all pointing to other nodes.) This is the format used in Keen 4-6 executables.&lt;br /&gt;
&lt;br /&gt;
To decompress the data we use the tree again starting at the root node and reading the data bit by bit. So the first three bits are &amp;lt;tt&amp;gt;100&amp;lt;/tt&amp;gt; which leads us down the tree to character &#039;H&#039;, then &amp;lt;tt&amp;gt;000&amp;lt;/tt&amp;gt; which leads us to &#039;U&#039; and so on.&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; Test Function&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 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 = 0&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 UInteger) 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;
[[Category:File Formats]]&lt;br /&gt;
[[Category:Compressed Files]]&lt;br /&gt;
[[Category:Huffman Compression]]&lt;br /&gt;
[[Category:Compression Algorithms]]&lt;br /&gt;
[[Category:Code examples]]&lt;br /&gt;
[[Category:Dangerous Dave 2]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Commander_Keen_EGA_Header&amp;diff=5091</id>
		<title>Commander Keen EGA Header</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Commander_Keen_EGA_Header&amp;diff=5091"/>
		<updated>2013-12-31T23:18:40Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Fixed compression entry in the EGAHEAD, cleared stuff up&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Many early (1989-1993( [[ID Software]]\[[Softdish]] games use an &amp;lt;tt&amp;gt;EGAHEAD.*&amp;lt;/tt&amp;gt; file to read their graphics files. While the number and function of various graphics files vary substantially across various games, the header format itself is rather constant, with only a few minor variations. (Indeed it is possible to see a progressive development of the format over the years by tracing changes across several games.) In [[Commander Keen 1-3]] itself two [[Raw EGA data]] files contain all the tiles, sprites and in-game images. In other games more files are usually required.&lt;br /&gt;
&lt;br /&gt;
There are &#039;types&#039; of graphics, 8x8 fonts, 16x16 tiles, unmasked images and masked sprites. Sprites are almost always stored separately because they usually require 5 planes of EGA data, not 4.&lt;br /&gt;
&lt;br /&gt;
The EGAHEAD file may be external or internal and is divided into three parts, the first section deals with the number and location of fonts, tiles, images and sprites. The second section is a list of the names of unmasked images (Each 16 bytes long.) and the third (And usually largest.) section deals with a list of the names of sprites. (Each 128 bytes long.)&lt;br /&gt;
&lt;br /&gt;
Note that the addresses of graphics are offsets from where an EGA plane starts. So with a plane size of 100, the address 40 would have us looking for data at 40, 140, 240... in the graphics file. If graphics are stored separately, then this address is usually blank (Since it will start at the file start.)&lt;br /&gt;
&lt;br /&gt;
== Commander Keen format ==&lt;br /&gt;
&lt;br /&gt;
 Section 1:&lt;br /&gt;
 0   4    Latplansiz  Size of 4-plane EGA plane; should be one quarter of the size of the UNCOMPRESSED EGA&lt;br /&gt;
                      file size. In Keen this is for the EGALATCH file.&lt;br /&gt;
 4   4    Sprplansiz  Size of 5-plane EGA plane; should be one fifth of the size of the UNCOMPRESSED EGA&lt;br /&gt;
                      file size. In Keen this is EGASPRIT. This may be blank in games that store their&lt;br /&gt;
                      sprites in multiple files.&lt;br /&gt;
 8   4    Imgdatstart Where in the EGAHEAD the entries for unmasked graphics (Excluding font and tiles.)  &lt;br /&gt;
                      start. If there are none, this is blank.&lt;br /&gt;
 12  4    Sprdatstart Where in the EGAHEAD the entries for masked graphics (Sprites) start; by default&lt;br /&gt;
                      this is right after the unmasked graphics.&lt;br /&gt;
 16  2    Fontnum     Number of 8x8 font entries are in the font; note that many games have this for&lt;br /&gt;
                      drawing windows, with the actual black and white font stored in the executable.&lt;br /&gt;
 18  4    Fontloc     Offset in memory where font data is placed. Should be zero since font is&lt;br /&gt;
                      first. In Keen 1-3 also the location in LATCH file where font data starts.      &lt;br /&gt;
 22  2    Unknum      Used for the ending screen until this was removed. Number of screen graphics.       &lt;br /&gt;
 24  4    Unkloc      Used for screen graphics until removal. Offset in memory where screen data placed.   &lt;br /&gt;
 28  2    Tilenum     Number of 16x16 tiles                                &lt;br /&gt;
 30  4    Tileloc     Offset in memory\LATCH where tile data placed\starts.     &lt;br /&gt;
                      &lt;br /&gt;
 34  2    Bmpnum      Number of unmasked bitmaps                           &lt;br /&gt;
 36  4    Bmploc      Offset in memory\plane where unmasked bitmap data starts\placed.   &lt;br /&gt;
 40  2    Spritenum   Number of sprite images                              &lt;br /&gt;
 42  4    Spriteloc   Offset in EGASPRIT plane of start of sprite data. Is, of course, zero. Also relates&lt;br /&gt;
                      to memory&lt;br /&gt;
 46  2    Compression Add 2 to this byte if EGALATCH is compressed, add 1 to it if EGASPRIT is compressed.&lt;br /&gt;
                      Thus uncompressed graphics have this set at 0 and fully compressed at 3. The only&lt;br /&gt;
                      game that compresses its graphics like this is Commander Keen 1. Attempting to set&lt;br /&gt;
                      any compression for the other games will result in garbage graphics.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Section 2:&lt;br /&gt;
     2    Size h      The width of the graphic divided by 8 &lt;br /&gt;
 2   2    Size v      The height of the graphic in pixels; if this cannot be&lt;br /&gt;
                      divided into neat 16 byte pieces, the extra data,     &lt;br /&gt;
                      usually 8 bytes, is added to the size.                &lt;br /&gt;
 4   4     Loc        When added to the graphic offset in the header, gives &lt;br /&gt;
                      the location of the start of the graphic data in the  &lt;br /&gt;
                      plane. For the first graphic this is thus zero.       &lt;br /&gt;
 8   8     Name       Name of the graphic, padded with nulls. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Section 3:&lt;br /&gt;
 0   2     Width      The width of the graphic divided by 8 &lt;br /&gt;
 2   2     Height     The height of the graphic in pixels;  the same rule &lt;br /&gt;
                      applies as for unmasked graphics except now we have:&lt;br /&gt;
 4   2     Loc offset Usually 8, this is the number of bytes &#039;extra&#039; that &lt;br /&gt;
                      must be added to the location to reach the start of &lt;br /&gt;
                      the sprite data. This appears when a sprite is so   &lt;br /&gt;
                      small, usually 8x8 pixels, that it doesn&#039;t fill a   &lt;br /&gt;
                      multiple of 16 bytes. This will affect ALL sprites  &lt;br /&gt;
                      after the aberration until another one occurs to fix&lt;br /&gt;
                      the shortfall.                                      &lt;br /&gt;
 6   2     Location   Multiplying this by 16 bytes gives the location of  &lt;br /&gt;
                      the start of the sprite data in the EGA plane.      &lt;br /&gt;
 8   4     Hitbox ul  Location of the upper-left corner of the sprite&#039;s   &lt;br /&gt;
                      hitbox or collision rectangle, in pixels, starting   &lt;br /&gt;
                      from 0,0. First two bytes are the h location and the&lt;br /&gt;
                      next two are the v location. In the EGAHEAD, both&lt;br /&gt;
                      values are multiplied by 256.               &lt;br /&gt;
 12  4     Hitbox br  Same as above, for the bottom left corner.          &lt;br /&gt;
 16  12    Name       The sprite name, usually includes a number and is   &lt;br /&gt;
                      usually only 10 bytes long. May spill into the next&lt;br /&gt;
                      field in games that do not use that.                        &lt;br /&gt;
 28  4     h/v off    The horizontal and vertical offset of the sprite frame from the sprite&lt;br /&gt;
                      event. In early games this is blank, but in later ones such as&lt;br /&gt;
                      [[Shadow Knights]] it is utilized. This can be used to &#039;line up&#039;&lt;br /&gt;
                      frames of different heights and so on.&lt;br /&gt;
 32  3*32  Copies     Games use these entries for smooth movement; each 32 byte entry is&lt;br /&gt;
                      a copy of the initial sprite shifted 2 pixels left. The game will&lt;br /&gt;
                      automatically generate the graphics, but the preceding information&lt;br /&gt;
                      must be duplicated. In the copies, 1 is added to the width field.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Other games ==&lt;br /&gt;
&lt;br /&gt;
There are several differences between other games and Commander Keen. The most notable is usually the presence of more than two graphics files. Sprites are often split into various &amp;lt;tt&amp;gt;S_*&amp;lt;/tt&amp;gt; files, each of which is compressed, containing, as its first word, the decompressed file size (Including the word itself and any header the raw data may have.) It is usually not hard to calculate a plane size from this.&lt;br /&gt;
&lt;br /&gt;
Addresses in the header will point to the right location in whatever file is being used at the time. Thus is sprites have been split up into several files, it is possible to see when files are &#039;switched&#039; whenever the pointer for a sprite is less (usually 0) than the pointer to the previous sprite. (A new file is being opened and data read from the start of it, instead of the end of the old file.) Note however that the order sprite files are opened and how many sprites they contain is usually hard-coded.&lt;br /&gt;
&lt;br /&gt;
Another effect of this is that pointers in the EGA are used for memory, NOT files. In Keen they are the same, since the EGALATCH is copied directly into memory in segments, essentially the whole file is copied as-is. In other games with more files the game is hard-coded to calculate where to read from the number of graphics entries, their size or whether or not a file has been opened so they header pointers are not a reliable guide.&lt;br /&gt;
&lt;br /&gt;
Aside fro Commander Keen, no other games are [[Keen 1-3 LZW Compression|LZW compressed]] and so don&#039;t use that feature in the header. Other forms of compression are used which may or may not be indicated in the header somehow.&lt;br /&gt;
&lt;br /&gt;
As games progressed an additional modification was added to the header format; the last four bytes of a sprite&#039;s name were set aside to be h and v offsets of the sprite image (as used in [[Commander Keen 4-6]] games.) This left a sprite with a maximum name length of 11 bytes. Since the last four bytes are seldom used (are zero), it can often be assumed that all games use this with few problems.&lt;br /&gt;
&lt;br /&gt;
Finally is the issue of &#039;sprite blitting&#039; The header&#039;s sprite entries are 128 bytes long, being essentially four copies of a 32 byte entry. In earlier games each was in fact a separate entry, there were in effect four times the number of sprites, each one used for when a sprite was moving 0, 2, 4, and 6 pixels left or right. Later games automated the creation of these sprites, shrinking file size. For simplicity the header format was left as-is.&lt;br /&gt;
&lt;br /&gt;
=== [[Dangerous Dave in Copyright Infringement]] ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== [[Dangerous Dave 2]] ===&lt;br /&gt;
&lt;br /&gt;
Dangerous Dave 2 stores the header and &amp;lt;tt&amp;gt;LATCH&amp;lt;/tt&amp;gt; internally in the executable at 74896 and 101096 respectively (in the [[UNLZEXE]]&#039;d executable.) Because the &amp;lt;tt&amp;gt;EGALATCH.DD2&amp;lt;/tt&amp;gt; file is stored internally there is an interesting situation with 8x8 tiles and unmasked bitmaps; the &amp;lt;tt&amp;gt;EGAHEAD&amp;lt;/tt&amp;gt; points to 32 8x8 tiles, but the last tile is overwritten by the start of the unmasked bitmap data. This means that 8 bytes from each EGA plane are copied into memory twice, once as the end of 8x8 tiles and again as the first unmasked bitmap. It also means that the &#039;location&#039; of the bitmaps (e.g. $100) is 8 bytes larger than the location of the EGA data in the internal file.&lt;br /&gt;
&lt;br /&gt;
Otherwise the format is nearly identical. Number of unmasked bitmaps and their location are at 40\42 in the header instead of 34\36. There is no sprite plane size at 4 since the sprites are stored in several compressed files (each containing its own planesize.) Tiles are stored in a separate file &amp;lt;tt&amp;gt;EGATILES.DD2&amp;lt;/tt&amp;gt;. Since each tile may or may not be loaded in a level depending on whether it&#039;s needed, the tile file is composed of 858 128-byte entries, each containing 4-EGA planes for the tile. There is a &#039;copy&#039; of the EGA planesize at byte 40 and bytes 22-34 and 52-64 are blank or contain nonsense data.&lt;br /&gt;
&lt;br /&gt;
=== [[Rescue Rover]] ===&lt;br /&gt;
&lt;br /&gt;
Rescue Rover has two sprite files, &amp;lt;tt&amp;gt;S_PLAY.ROV&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;S_DEMO.ROV&amp;lt;/tt&amp;gt; used in that order. Bitmaps and 8x8 font are stored in &amp;lt;tt&amp;gt;EGAPLANE.ROV&amp;lt;/tt&amp;gt;, tiles are 32x32 and stored in &amp;lt;tt&amp;gt;EGABTILE.ROV&amp;lt;/tt&amp;gt; (TED 16x16 tiles are stored in a file not used by the game, &amp;lt;tt&amp;gt;EGATILES.ROV&amp;lt;/tt&amp;gt;. Finally a monochrome font is stored in &amp;lt;tt&amp;gt;EGAFONT0.ROV&amp;lt;/tt&amp;gt; There are also several compressed screen images, &amp;lt;tt&amp;gt;*PIC.ROV&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The number\location-in-file of the sprites are stored at slightly different places, at bytes 47 and 49 instead of 41 and 43. In practice the location of tile and sprite data is 0, since they do not share files with any other EGA graphics.&lt;br /&gt;
&lt;br /&gt;
=== [[Shadow Knights]] ===&lt;br /&gt;
&lt;br /&gt;
Shadow knights uses the same (subtly different) EGA header as Rescue Rover, this document http://levellord.rewound.net/Index/File%20Formats/Shadow%20Knights/Shadow%20EGA.txt describes how the compression used for the sprites and the slightly odd layout of the tile data works.&lt;br /&gt;
&lt;br /&gt;
=== [[Slordax]] ===&lt;br /&gt;
&lt;br /&gt;
Slordax uses a format exactly identical to Commander Keen.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
&lt;br /&gt;
This format has been reverse engineered several times, mostly by the Commander Keen community.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: File Formats]]&lt;br /&gt;
[[Category: Graphics Files]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Carmack_compression&amp;diff=5090</id>
		<title>Carmack compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Carmack_compression&amp;diff=5090"/>
		<updated>2013-12-31T23:12:36Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Made it even clearer that the xA8 address is in words&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Carmack compression]] is used in the [[GameMaps Format|GAMEMAPS file]] in [[Commander Keen 4-6]], [[Catacomb 3D]], [[Wolfenstein 3D]], and [[Noah&#039;s Ark 3D]] to further shrink the levels down beyond what [[RLEW compression]] can achieve. Its basic idea is somewhat like LZ (Lempel-Ziv) compression in that it contains pointers back to previous data.&lt;br /&gt;
&lt;br /&gt;
As in RLEW compression, the first word in the Carmack compressed data is the number of bytes (not words) in the decompressed data. This is typically the number of bytes in the compressed RLEW data, as Carmack compression is performed after RLEW compression.&lt;br /&gt;
&lt;br /&gt;
Carmack compression contains two types of references to previous data: near pointers and far pointers.&lt;br /&gt;
&lt;br /&gt;
= Near Pointers =&lt;br /&gt;
&lt;br /&gt;
Near pointers occupy three bytes in the compressed data. The first is the number of words in the referenced sequence, the second is the signal byte of xA7, and the third is the number of words to the start of the reference (counting backwards from the current location). As a concrete example, the three bytes x05 xA7 x0A mean &#039;repeat the 5 words starting 10 words ago&#039;.&lt;br /&gt;
&lt;br /&gt;
Notice that near pointers only let one refer to the last 255 words. To refer to sequences further back, one must use far pointers.&lt;br /&gt;
&lt;br /&gt;
= Far Pointers =&lt;br /&gt;
&lt;br /&gt;
Far pointers occupy four bytes in the compressed data. The first is, again, the number of words in the referenced sequence, the second is xA8, and the third and fourth are interpreted as a word - a 0-based pointer to the start of the reference &#039;&#039;&#039;in words&#039;&#039;&#039;, so the address must be multiplied by two to reach the correct byte location. As a concrete example, the four bytes x10 xA8 x01 x20 mean &#039;repeat the 16 words starting at word number 513&#039;.&lt;br /&gt;
&lt;br /&gt;
= Words with a high byte of $A7 or $A8 =&lt;br /&gt;
&lt;br /&gt;
Words whose high (second) byte is xA7 or xA8 would appear to be issue, as they would be confused with near or far pointers. These are handled by representing them as the three bytes: $00, $Ax $xx, this is recognized as an exception (Repeating zero words would make no sense.)&lt;br /&gt;
&lt;br /&gt;
[[Category:File Formats]]&lt;br /&gt;
[[Category:Compressed Files]]&lt;br /&gt;
[[Category:Compression Algorithms]]&lt;br /&gt;
[[Category:Commander Keen 4-6]]&lt;br /&gt;
[[Category:Catacomb 3D]]&lt;br /&gt;
[[Category:Wolfenstein 3D]]&lt;br /&gt;
[[Category:Noah&#039;s Ark 3D]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=Talk:LZW_Compression&amp;diff=5089</id>
		<title>Talk:LZW Compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=Talk:LZW_Compression&amp;diff=5089"/>
		<updated>2013-12-31T23:10:19Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Responded to Malv&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The article states that some games are limited to 12-bit codes to save space, but it doesn&#039;t say what happens when this limit is reached (which I am having trouble trying to reverse engineer.)  I can&#039;t figure out whether it resets the dictionary or just keeps adjusting the last entry.  Any ideas? -- [[User:Malvineous|Malvineous]] 07:24, 19 September 2010 (GMT)&lt;br /&gt;
&lt;br /&gt;
When a 12-bit dictionary is filled, it simply stops adding codes. Therefore, the compressor just continues using the longest string in the dictionary for output, but doesn&#039;t add any new codes. See my VB.NET implementation for details. [[User:Fleexy|Fleexy]] ([[User talk:Fleexy|talk]]) 23:10, 31 December 2013 (GMT)&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=LZW_Compression&amp;diff=5088</id>
		<title>LZW Compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=LZW_Compression&amp;diff=5088"/>
		<updated>2013-12-31T23:05:09Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Made the separate dictionary general algorithm billions of times clearer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;LZW compression is a common form of compression used in some early games to compress data and by most early games to compress their executables. It is notable in being one of the first compression methods to not compress on the byte level (Along with [[Huffman Compression]]) and for its efficiency.&lt;br /&gt;
&lt;br /&gt;
The basic concept for LZW is universal, though the implementations differ. In essence it involves replacing data strings that have been encountered before with references to already decompressed data. (Known as a &#039;dictionary&#039;) This can be done in a number of ways, the two main approaches differing on whether the dictionary is separate or integrated&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Separate Dictionary Approach =&lt;br /&gt;
&lt;br /&gt;
In this approach the dictionary is separate from the data being decompressed, that is it is stored in a separate location in memory. In this it behaves more like one would expect a dictionary to work; when a codeword is found in the data, it is looked up in the dictionary and the corresponding string copied to output. (As an example dictionary entry 42 could represent the string &#039;life&#039;, thus whenever the code &#039;42&#039; is encountered the string &#039;life&#039; is added to the decompressed data.)&lt;br /&gt;
&lt;br /&gt;
The advantage of this method is that the efficiency of compression increases as the amount of data to compress increases. The following points differ between implementations:&lt;br /&gt;
&lt;br /&gt;
* The initial dictionary. Just how large the initial dictionary is varies. Some implementations start with no dictioanry at all, others set a number of entries, usually 255, covering all possible 1-byte values.&lt;br /&gt;
&lt;br /&gt;
* The maximum size of the dictionary. Many older implementations with less resources were forced to cap the dictionary at a certain size, usually a power of two entries long. (512, 1024...) Unlimited implementations are rare as modern methods (e.g. the DEFLATE algorithm.)  usually rely on several compression methods at once. Sometimes the dictionary is &#039;reset&#039; when it reaches too large a size.&lt;br /&gt;
&lt;br /&gt;
* Whether the codestream is made partly or entirely of codewords. Often the compressed data is made entirely of codewords, even non-repeating strings, which means that initially compression can sometimes be rather poor. Other implementations use codeowords only for repeating strings. Differences in how codewords vs literal are indicated and how dictionaries are built up may occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Decoding ==&lt;br /&gt;
&lt;br /&gt;
This is a general decoding algorithm for separate dictionary LZW. It will need to be altered slightly when dealing with different implementations. Notably it assumes that the codestream is composed entirely of codewords and that the dictionary can keep growing indefinitely.&lt;br /&gt;
&lt;br /&gt;
    Add all roots to the dictionary. Code 0 corresponds to $00, code 1 is $01, etc to $FF;&lt;br /&gt;
    Add error, clear, and end-mark flags to the dictionary as appropriate;&lt;br /&gt;
    FirstCode [as unknown length binary number] = the first code in the codestream;&lt;br /&gt;
    CurMatch [as byte array] = the dictionary entry for FirstCode;&lt;br /&gt;
    Output CurMatch;&lt;br /&gt;
    Loop until end of codestream {&lt;br /&gt;
        CurCode [as unknown length binary number] = next code in the codestream;&lt;br /&gt;
        TempMatch [as byte array] allocate;&lt;br /&gt;
        If there is an entry for CurCode in the dictionary {&lt;br /&gt;
            TempMatch = the dictionary entry for CurCode;&lt;br /&gt;
        } If not {&lt;br /&gt;
            TempMatch = CurMatch;&lt;br /&gt;
            Concatenate the first byte of CurMatch to the end of TempMatch;&lt;br /&gt;
        }&lt;br /&gt;
        Output TempMatch;&lt;br /&gt;
        NewDictEntry [as byte array] = CurMatch;&lt;br /&gt;
        Concatenate the first byte of TempMatch to the end of NewDictEntry;&lt;br /&gt;
        Try to add NewDictEntry to the dictionary for the first empty key;&lt;br /&gt;
        CurMatch = TempMatch;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== [[Commander Keen 1-3|Commander Keen 1-3 LZW]] ==&lt;br /&gt;
&lt;br /&gt;
In [[Commander Keen 1-3]] LZW is used to compress the &amp;lt;tt&amp;gt;EGALATCH&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;EGASPRIT&amp;lt;/tt&amp;gt; files in episode 1 (It can also be used in episodes 2 and 3, but isn&#039;t.) The game uses two error-checking methods in this implementation, firstly it reserves two dictionary values, $100 to indicate an error (This is written by the compression program and will make the executable abort.) and $101 to indicate the end of data. (If the program reaches the end of the data without encountering this it will also abort.) The compressed data is also prefixed with a dword giving the decompressed data size, so this can be compared with the output.&lt;br /&gt;
&lt;br /&gt;
This method is a typical separate dictionary approach. It starts with a dictionary of 256 9-bit codewords representing the 8-bit strings $00-$FF (Plus some special cases.) The dictionary is allowed to grow to 4096 entries. The following is the initial dictionary:&lt;br /&gt;
&lt;br /&gt;
        0000 - 00 (character)&lt;br /&gt;
        0001 - 01 (character)&lt;br /&gt;
            ...&lt;br /&gt;
        00FE - FE (character)&lt;br /&gt;
        00FF - FF (character)&lt;br /&gt;
        0100 - Reserved for errors...&lt;br /&gt;
        0101 - Reserved for end of compressed data...&lt;br /&gt;
        0102 - (not set)&lt;br /&gt;
        0103 - (not set)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It will be immediately noticed that 4096 entries cannot be represented by 9-bit codes but at the least by 12-bit codes. To further conserve space the length of the codewords is increased every time the dictionary grows too large. Thus when it reaches $01FF entries codewords become 10 bits long, at $03FF they are 11 bits and finally at $07FF 12 bits. At $0FFF entries the dictionary stops growing.&lt;br /&gt;
&lt;br /&gt;
The following data is taken from the EGALATCH file from Keen 1. Notice that the first six bytes are ignored. (The first four give the decompressed data size, the next two are the maximum number of bits the LZW decoder will use.) The first few steps of decompression follows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    0000  80 D3 01 00  0C 00 00 40 - A0 70 31 E9  F8 F8 78 38&lt;br /&gt;
    0010  08 08 00 07  FC 39 FF 04 - 5E 41 E1 30  B3 C4 5A 2F&lt;br /&gt;
&lt;br /&gt;
The first code word encountered is 000000000 (First 9 bits) and thus outputs the string $00 - the first dictionary entry. This has set us up to step 4 and now things work slightly differently.&lt;br /&gt;
&lt;br /&gt;
The second code word is the next 9 bits, 100000010, which would point to entry $102. Since this entry is NOT found in the dictionary yet, we will create this entry then output it. Entry $102 is created by taking the previous codeword&#039;s string adding to it the first byte of that string. In this case the previous code word&#039;s (0) string is $00. $00 + $00 is $00 $00. Entry $102 thus represents the string $00 $00&lt;br /&gt;
&lt;br /&gt;
The next code word is 100000011, which is entry $103, which again doesn&#039;t exist. Entry $103 is created just like with $102, except now since the previous codeword is $00 $00, entry $103 is $00 $00 $00.&lt;br /&gt;
&lt;br /&gt;
The next code word is again $103, this IS found in the dictionary and is outputted ($00 $00 $00) however we now create dictionary entry $104 just like $103. (It is $00 $00 $00 $00.) Note that the previous codeword is still $103.&lt;br /&gt;
&lt;br /&gt;
The next code word is $3B. It is outputted and entry $105 created ($00 $00 $00 $3B) Now, the previous codeword is $3B. This pattern continues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Integrated Dictionary Approach =&lt;br /&gt;
&lt;br /&gt;
In this approach the dictionary is the decompressed data itself. The codewords do not represent an entry in the dictionary structure, but rather directions in the decompressed code as to where a repeated string is located. That is a repeat string may well be represented by a codeword that states &#039;copy seven bytes from byte 132 in the decompressed data&#039;&lt;br /&gt;
&lt;br /&gt;
The advantage of this approach is that it doesn&#039;t require a separate construct for the dictionary and can just use the already decompressed data. The downside is that it will always need some method to distinguish literals and codewords, and, since codewords are nearly always of a fixed length there is an inherent limit both to how long the copied string can be and where it can be read from. this means that eventually the compression efficiency will level off and stop improving.&lt;br /&gt;
&lt;br /&gt;
There This is often called the &#039;sliding window&#039; and it represents the data that can be &#039;reached&#039; by the codewords. It is named as such because it is of a fixed length and &#039;slides&#039; along the output stream as it gets longer. The following features differ between implementations:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Differentiating codewords from literals. There must be a way to tell codewords apart from data that is just to be read and outputted. Sometimes this is integrated into the codewords themselves, but more often the &#039;flag&#039; precedes a codeword. The flag may indicate only codewords or both codewords and literals. (&#039;Following data is made of two codewords and six literals&#039;, etc.)&lt;br /&gt;
&lt;br /&gt;
* Codeword format. Most implementations use codewords of a fixed format that must encode both the length of data to copy and the location to copy it from. Codewords are usually two or four bytes long.&lt;br /&gt;
&lt;br /&gt;
* Zero point location. Different implementations use different places in the output as zero. If the start of the code is used as zero only the first x bytes of the output can be used as a reference. Most implementations use a more complex, but seldom less effective &#039;sliding window&#039;; the zero point is the start of the data until the data becomes too long at which point it moves forward so that the most recent x bytes of output can be used. It is also possible for zero to be the most recent byte with all locations being &#039;x bytes from the end&#039;, which also produces a sliding window. Finally it may be possible to have both negative and positive locations.&lt;br /&gt;
&lt;br /&gt;
* Sliding window. The nature of this is dictated by the format of the codewords. Common sizes are 1KB, 2KB or 4KB. The window will always be present, but it may not &#039;slide&#039; if the implementation uses a fixed location as the zero point.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== LZEXE ==&lt;br /&gt;
&lt;br /&gt;
Many vintage executables are compressed with the program LZEXE, interesting in that the compressed file contains its own decompressor, meaning that it is in essence a self-extracting archive. However the unique feature of LZEXE executables is that they extract the compressed data to memory and run it. To the user this is indistinguishable from the decompressed executable, though it takes slightly longer to start up and takes up much less space.&lt;br /&gt;
&lt;br /&gt;
[[UNLZEXE]] can be used to extract the decompressed executables from this which will run perfectly with other game files. It can be obtained here: http://www.dosclassics.com/download/198 It is currently unknown specifically how the LZW compression is implemented in this case, but with the source code for decompression is available.&lt;br /&gt;
&lt;br /&gt;
The LZEXE compression is similar to the SoftDisk Library Approach described below, but it uses UINT16LE values instead of byte values to store the flag bits and the sliding window has a size of 8192 (0x2000) bytes. Also, the flag bits have different meanings (you could argue that they are in fact Huffman codes):&lt;br /&gt;
&lt;br /&gt;
    1 -&amp;gt; copy 1 literal byte&lt;br /&gt;
   10 -&amp;gt; next two bytes contain length and distance&lt;br /&gt;
 0000 -&amp;gt; length is 2, next byte contains distance &lt;br /&gt;
 1000 -&amp;gt; length is 3, next byte contains distance &lt;br /&gt;
 0100 -&amp;gt; length is 4, next byte contains distance &lt;br /&gt;
 1100 -&amp;gt; length is 5, next byte contains distance &lt;br /&gt;
&lt;br /&gt;
The real distance value is always a signed 16 bit integer (you can use unsigned but then you have to bitwise-and the resulting index value with 0xFFFF). If the length is given by the flag bits/Huffman code, the real distance is &amp;lt;tt&amp;gt;b | 0xFF00&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;b - 256&amp;lt;/tt&amp;gt; where &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt; is the byte value read from the file. If the length value is not given, read the byte values &amp;lt;tt&amp;gt;b0&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;b1&amp;lt;/tt&amp;gt; and calculate length and distance like this:&lt;br /&gt;
&lt;br /&gt;
 length = (b1 mod 8)+2&lt;br /&gt;
 distance = b0 + (b1/8)*256 - 8192&lt;br /&gt;
or&lt;br /&gt;
 length = (b1 &amp;amp; 0x07)+2&lt;br /&gt;
 distance = b0 | ((b1 &amp;amp; 0xF8)&amp;lt;&amp;lt;5) | 0xE000&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt; value calculated from &amp;lt;tt&amp;gt;b1&amp;lt;/tt&amp;gt; is 2, this indicates that another byte value &amp;lt;tt&amp;gt;b2&amp;lt;/tt&amp;gt; must be read. Depending in the value of b2, one of three things can happen:&lt;br /&gt;
 b2 = 0:&lt;br /&gt;
    end of compressed data - stop decompressing&lt;br /&gt;
 b2 = 1:&lt;br /&gt;
    end of segment&lt;br /&gt;
    (decompressor may write contents of buffer to output)&lt;br /&gt;
    set length to 0 or jump to the part where the decompressor reads the next flag bits/Huffman code&lt;br /&gt;
 otherwise:&lt;br /&gt;
    set length to b2+1&lt;br /&gt;
&lt;br /&gt;
Now the decompressor must only add &amp;lt;tt&amp;gt;distance&amp;lt;/tt&amp;gt; to the current buffer index (since &amp;lt;tt&amp;gt;distance&amp;lt;/tt&amp;gt; is negative, the index goes backwards) and copy &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt; bytes from there to the current index:&lt;br /&gt;
&lt;br /&gt;
 WHILE length &amp;gt; 0&lt;br /&gt;
    buffer[index] = buffer[index+distance]&lt;br /&gt;
    index = index + 1&lt;br /&gt;
    length = length - 1&lt;br /&gt;
 END WHILE&lt;br /&gt;
&lt;br /&gt;
Please refer to the UNLZEXE source code for further information.&lt;br /&gt;
&lt;br /&gt;
== SoftDisk Library Approach ==&lt;br /&gt;
&lt;br /&gt;
This is used as the first form of compression in the [[Softdisk Library Format]]. Flags are 1-byte long and divide the datastream into segments of eight &#039;values&#039; which can be either literals or codewords. Codewords are 2 bytes long, literals 1 byte. (Therefore there will be a flag byte every 8 to 16 bytes of data.) The value of each bit (In little endian) indicates whether a value will be a literal (1) or codeword (0) Thus a value of 199 (11000111 in binary) indicates three codewords, three literals and two codewords in that order. (Total of 13 bytes.)&lt;br /&gt;
&lt;br /&gt;
Literals are sequences that have never been seen in the datastream before, they cannot be compressed and are thus the same in the compressed and decompressed datastreams. (If the data is text they become quite obvious.) Any string less than 3 bytes long that has not been read before or cannot be pointed to (See below) will be stored as literals.&lt;br /&gt;
&lt;br /&gt;
Codewords are reference to data that has already been read. They are two bytes long, with the first 12 bits giving the location to read data from and the last 4 bits giving the length of data to read.&lt;br /&gt;
&lt;br /&gt;
The lower nybble (4 bits) of the second codeword byte holds the length of repeat data to read minus three. (This makes sense, the shortest sequence it makes sense to code is three bytes which can be given the value 0.) It will be immediately apparent that the maximum length of repeated data that can be stored as a codeword is 18 bytes.&lt;br /&gt;
&lt;br /&gt;
The high nybble of the second byte is multiplied by 16 then added to the first byte to give the location of the data to read in the &#039;sliding window&#039; minus 19. (This is due to the way the decompression is set up in memory.)&lt;br /&gt;
&lt;br /&gt;
It will be immediately obvious that the codewords can encode values between +-2048, or about 2KB. If the decompressed data is less than 2KB in size then zero is the start of the data, if it is larger than it is 2048 bytes from the data end.&lt;br /&gt;
&lt;br /&gt;
It will be noted that it is probable that the compressed datastream will not be perfectly divisible by flag bytes. In this case the unused bits are set to 0. The decompressor stops when the decompressed data size is equal to the value given in the chunk header. (If it runs out of data it will abort.)&lt;br /&gt;
&lt;br /&gt;
As a simple example the sentence &#039;I am Sam. Sam I am!&#039; will be compressed to:&lt;br /&gt;
&lt;br /&gt;
 FF				Flag byte, 8 literals follow&lt;br /&gt;
 49 20 61 6D 20 53 61 6D	&#039;I am Sam&#039; as literals&lt;br /&gt;
 2B				Flag byte, 2L, P, L, P, L 2Blanks ($2B = 43 = 00101011)&lt;br /&gt;
 2E 20				&#039; .&#039; as literals&lt;br /&gt;
 F2 F0				codeword, read 0 + 3 = 3 bytes from $FF2, or -14 + 19 = 5 in the data. This is &#039;Sam&#039;&lt;br /&gt;
 20				&#039; &#039; as literal&lt;br /&gt;
 ED F1				codeword, read 1 + 3 = 4 bytes from $FED or -19 + 19 = 1 in the data. This is &#039;I am&#039;&lt;br /&gt;
 21				&#039;!&#039; as literal&lt;br /&gt;
&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 Keen&#039;s LZW algorithm in its various implementations.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Keen 1-3 Implementation ==&lt;br /&gt;
&lt;br /&gt;
These segments f code work with the Keen 1-3 implementation only and will not for example decompress LZEXE compressed executables.&lt;br /&gt;
&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;
DECLARE FUNCTION READBITS% (FILE AS INTEGER, NUMBITS AS INTEGER)&lt;br /&gt;
DECLARE SUB LZWDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING)&lt;br /&gt;
DECLARE SUB LZWOUTPUT (FILE AS INTEGER, DIC AS INTEGER, CHAR AS INTEGER)&lt;br /&gt;
&#039;&lt;br /&gt;
&#039; KEEN1 Compatible LZW Decompressor (Lempel-Ziv-Welch)&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&lt;br /&gt;
&#039;&lt;br /&gt;
&#039;&lt;br /&gt;
&lt;br /&gt;
&#039; Allocate dictionary&lt;br /&gt;
DIM LZDIC(0 TO 4095) AS INTEGER&lt;br /&gt;
DIM LZCHR(0 TO 4095) AS INTEGER&lt;br /&gt;
&lt;br /&gt;
&#039; Test Function&lt;br /&gt;
LZWDECOMPRESS &amp;quot;EGALATCH.CK1&amp;quot;, &amp;quot;EGALATCH.DAT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SUB LZWDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING)&lt;br /&gt;
        SHARED LZDIC() AS INTEGER, LZCHR() AS INTEGER&lt;br /&gt;
        DIM INFILE AS INTEGER, OUTFILE AS INTEGER, I AS INTEGER&lt;br /&gt;
        DIM BITLEN AS INTEGER, CURPOS AS INTEGER&lt;br /&gt;
        DIM CW AS INTEGER, PW AS INTEGER, C AS INTEGER, P AS INTEGER&lt;br /&gt;
        DIM CHECK AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        &#039; Open files for input and output&lt;br /&gt;
        INFILE = FREEFILE&lt;br /&gt;
        OPEN INNAME FOR BINARY ACCESS READ AS INFILE&lt;br /&gt;
        OUTFILE = FREEFILE&lt;br /&gt;
        OPEN OUTNAME FOR BINARY ACCESS WRITE AS OUTFILE&lt;br /&gt;
        SEEK INFILE, 7&lt;br /&gt;
&lt;br /&gt;
       &lt;br /&gt;
        &#039; Fill dictionary with starting values&lt;br /&gt;
        FOR I = 0 TO 4095&lt;br /&gt;
                LZDIC(I) = -1&lt;br /&gt;
                IF I &amp;lt; 256 THEN&lt;br /&gt;
                        LZCHR(I) = I&lt;br /&gt;
                ELSE&lt;br /&gt;
                        LZCHR(I) = -1&lt;br /&gt;
                END IF&lt;br /&gt;
        NEXT I&lt;br /&gt;
&lt;br /&gt;
        &#039; Decompress input stream to output stream&lt;br /&gt;
        BITLEN = 9&lt;br /&gt;
        CURPOS = 258&lt;br /&gt;
        CW = READBITS(INFILE, BITLEN)&lt;br /&gt;
        LZWOUTPUT OUTFILE, LZDIC(CW), LZCHR(CW)&lt;br /&gt;
       &lt;br /&gt;
        WHILE CW &amp;lt;&amp;gt; &amp;amp;H100 AND CW &amp;lt;&amp;gt; &amp;amp;H101&lt;br /&gt;
                PW = CW&lt;br /&gt;
                CW = READBITS(INFILE, BITLEN)&lt;br /&gt;
                IF CW &amp;lt;&amp;gt; &amp;amp;H100 AND CW &amp;lt;&amp;gt; &amp;amp;H101 THEN&lt;br /&gt;
                        P = PW&lt;br /&gt;
                        CHECK = (LZCHR(CW) &amp;lt;&amp;gt; -1)&lt;br /&gt;
                       &lt;br /&gt;
                        IF CHECK THEN&lt;br /&gt;
                                TMP = CW&lt;br /&gt;
                        ELSE&lt;br /&gt;
                                TMP = PW&lt;br /&gt;
                        END IF&lt;br /&gt;
                        WHILE LZDIC(TMP) &amp;lt;&amp;gt; -1&lt;br /&gt;
                                TMP = LZDIC(TMP)&lt;br /&gt;
                        WEND&lt;br /&gt;
                        C = LZCHR(TMP)&lt;br /&gt;
                       &lt;br /&gt;
                        IF CHECK THEN&lt;br /&gt;
                                LZWOUTPUT OUTFILE, LZDIC(CW), LZCHR(CW)&lt;br /&gt;
                        ELSE&lt;br /&gt;
                                LZWOUTPUT OUTFILE, P, C&lt;br /&gt;
                        END IF&lt;br /&gt;
                       &lt;br /&gt;
                        IF CURPOS &amp;lt; 4096 THEN&lt;br /&gt;
                                LZDIC(CURPOS) = P&lt;br /&gt;
                                LZCHR(CURPOS) = C&lt;br /&gt;
                                CURPOS = CURPOS + 1&lt;br /&gt;
                                IF CURPOS = (2 ^ BITLEN - 1) AND BITLEN &amp;lt; 12 THEN&lt;br /&gt;
                                        BITLEN = BITLEN + 1&lt;br /&gt;
                                END IF&lt;br /&gt;
                        END IF&lt;br /&gt;
&lt;br /&gt;
                END IF&lt;br /&gt;
        WEND&lt;br /&gt;
       &lt;br /&gt;
        &#039; Close files&lt;br /&gt;
        CLOSE OUTFILE&lt;br /&gt;
        CLOSE INFILE&lt;br /&gt;
END SUB&lt;br /&gt;
&lt;br /&gt;
SUB LZWOUTPUT (FILE AS INTEGER, DIC AS INTEGER, CHAR AS INTEGER)&lt;br /&gt;
        SHARED LZDIC() AS INTEGER, LZCHR() AS INTEGER&lt;br /&gt;
        DIM LZSTK(0 TO 127) AS STRING * 1&lt;br /&gt;
        DIM X AS INTEGER, SP AS INTEGER&lt;br /&gt;
        DIM LDIC AS INTEGER, LCHAR AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        LCHAR = CHAR&lt;br /&gt;
        LDIC = DIC&lt;br /&gt;
        SP = 0&lt;br /&gt;
        X = 1&lt;br /&gt;
&lt;br /&gt;
        DO&lt;br /&gt;
                IF SP &amp;gt;= 128 THEN&lt;br /&gt;
                        PRINT &amp;quot;LZW: Stack Overflow!&amp;quot;&lt;br /&gt;
                        END&lt;br /&gt;
                END IF&lt;br /&gt;
                LZSTK(SP) = CHR$(LCHAR)&lt;br /&gt;
                SP = SP + 1&lt;br /&gt;
                IF LDIC &amp;lt;&amp;gt; -1 THEN&lt;br /&gt;
                        LCHAR = LZCHR(LDIC)&lt;br /&gt;
                        LDIC = LZDIC(LDIC)&lt;br /&gt;
                ELSE&lt;br /&gt;
                        X = 0&lt;br /&gt;
                END IF&lt;br /&gt;
        LOOP WHILE X&lt;br /&gt;
       &lt;br /&gt;
        WHILE SP &amp;lt;&amp;gt; 0&lt;br /&gt;
                SP = SP - 1&lt;br /&gt;
                PUT FILE, , LZSTK(SP)&lt;br /&gt;
        WEND&lt;br /&gt;
END SUB&lt;br /&gt;
&lt;br /&gt;
FUNCTION READBITS% (FILE AS INTEGER, NUMBITS AS INTEGER)&lt;br /&gt;
        STATIC BITDAT AS STRING * 1, BITPOS AS INTEGER&lt;br /&gt;
        DIM BITVAL AS INTEGER, BIT AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        BITVAL = 0&lt;br /&gt;
        FOR BIT = (NUMBITS - 1) TO 0 STEP -1&lt;br /&gt;
                IF BITPOS = 0 THEN&lt;br /&gt;
                        GET FILE, , BITDAT&lt;br /&gt;
                        BITPOS = 7&lt;br /&gt;
                ELSE&lt;br /&gt;
                        BITPOS = BITPOS - 1&lt;br /&gt;
                END IF&lt;br /&gt;
                IF ASC(BITDAT) AND 2 ^ BITPOS THEN&lt;br /&gt;
                        BITVAL = BITVAL OR 2 ^ BIT&lt;br /&gt;
                END IF&lt;br /&gt;
        NEXT BIT&lt;br /&gt;
&lt;br /&gt;
        READBITS% = BITVAL&lt;br /&gt;
END FUNCTION&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== FreeBasic ===&lt;br /&gt;
&lt;br /&gt;
This code does not suffer from the 64K memory limit imposed by QuickBasic and so is less efficient, but runs faster. It can be compiled with FreeBasic compiler using the -lang=qb switch. Aside from memory concerns, all code here is compatible with QuickBasic.&lt;br /&gt;
&lt;br /&gt;
The code before the subroutine is used to make a string containing the bit expansion of all values from 0 to 255. The subroutine takes a filename, reads the entire file into memory then expands each bit of data to a byte using the aforesaid string as Basic cannot deal with bits directly. cw$ is codeword, pw$ is the previous codeword, lun is the lowest dictionary entry that is empty, p is the location in the compressed data stream and bl is the length of codes in bits (Starting at nine bits increasing to 12)&lt;br /&gt;
&lt;br /&gt;
The dictionary is set before decompression. The first 258 are the starting dictionary, the remainder are cleared. (It is vital to reset the dictionary for each file) An error occurs if entry 256 is found in the data, &#039;distrupt&#039; is printed when the newest dictionary entry is not the lowest possible entry (This shouldn&#039;t happen but is possible.) Decompression ends at encountering entry 257, or when there is no more data to read.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;qbasic&amp;quot;&amp;gt;&lt;br /&gt;
DECLARE SUB LZWDEC (lfn AS STRING)&lt;br /&gt;
&lt;br /&gt;
x$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 0 TO 255&lt;br /&gt;
 IF (l AND 128) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 64) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 32) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 16) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 8) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 4) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 2) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 1) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
NEXT l&lt;br /&gt;
LZEDEC &amp;quot;EGALATCH.CK1&amp;quot;&lt;br /&gt;
END&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;_________________________________________________&lt;br /&gt;
SUB LZWDEC (lfn AS STRING) &#039; Decompress LZW data&lt;br /&gt;
&#039;_________________________________________________&lt;br /&gt;
DIM lzw(0 TO 4095) AS STRING&lt;br /&gt;
PRINT lfn; &amp;quot; is LZW compressed, decompressing...&amp;quot;;&lt;br /&gt;
OPEN folder + lfn FOR BINARY AS #9&lt;br /&gt;
y$ = SPACE$(LOF(9))&lt;br /&gt;
GET #9, 1, y$&lt;br /&gt;
CLOSE #9&lt;br /&gt;
z$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 7 TO LEN(y$)&lt;br /&gt;
 z$ = z$ + MID$(x$, (ASC(MID$(y$, l, 1)) * 8) + 1, 8)&lt;br /&gt;
NEXT l&lt;br /&gt;
&lt;br /&gt;
bl = 9&lt;br /&gt;
lun = 258&lt;br /&gt;
p = 1&lt;br /&gt;
cw$ = &amp;quot;&amp;quot;&lt;br /&gt;
y$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 0 TO 4095&lt;br /&gt;
 IF l &amp;lt; 256 THEN lzw(l) = CHR$(l) ELSE lzw(l) = &amp;quot;&amp;quot;&lt;br /&gt;
NEXT l&lt;br /&gt;
DO&lt;br /&gt;
 IF lun = 511 THEN bl = 10&lt;br /&gt;
 IF lun = 1023 THEN bl = 11&lt;br /&gt;
 IF lun = 2047 THEN bl = 12&lt;br /&gt;
 pw$ = cw$&lt;br /&gt;
 u$ = MID$(z$, p, bl)&lt;br /&gt;
 p = p + bl&lt;br /&gt;
 y = 0&lt;br /&gt;
 FOR l = 1 TO bl&lt;br /&gt;
  IF MID$(u$, bl - l + 1, 1) = &amp;quot;1&amp;quot; THEN y = y + (2 ^ (l - 1))&lt;br /&gt;
 NEXT l&lt;br /&gt;
 IF y = 256 THEN&lt;br /&gt;
  PRINT &amp;quot;LZW error in Keen data!&amp;quot;&lt;br /&gt;
  OPEN &amp;quot;ERROR.DAT&amp;quot; FOR OUTPUT AS #9&lt;br /&gt;
  PRINT #9, y$;&lt;br /&gt;
  CLOSE&lt;br /&gt;
  END&lt;br /&gt;
 END IF&lt;br /&gt;
 IF y = 257 THEN EXIT DO&lt;br /&gt;
 IF cw$ = &amp;quot;&amp;quot; THEN&lt;br /&gt;
  cw$ = lzw(y)&lt;br /&gt;
  y$ = y$ + cw$&lt;br /&gt;
 ELSE&lt;br /&gt;
  IF lun &amp;lt; 4096 THEN&lt;br /&gt;
   IF lzw(y) = &amp;quot;&amp;quot; THEN&lt;br /&gt;
    cw$ = pw$ + LEFT$(pw$, 1)&lt;br /&gt;
    lzw(y) = cw$&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
    IF y &amp;lt;&amp;gt; lun THEN PRINT &amp;quot;Disrupt!&amp;quot;&lt;br /&gt;
    lun = y + 1&lt;br /&gt;
   ELSE&lt;br /&gt;
    cw$ = lzw(y)&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
    lzw(lun) = pw$ + LEFT$(cw$, 1)&lt;br /&gt;
    lun = lun + 1&lt;br /&gt;
   END IF&lt;br /&gt;
  ELSE&lt;br /&gt;
   IF lzw(y) = &amp;quot;&amp;quot; THEN&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
   ELSE&lt;br /&gt;
    cw$ = lzw(y)&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
   END IF&lt;br /&gt;
  END IF&lt;br /&gt;
 END IF&lt;br /&gt;
LOOP WHILE p &amp;lt; LEN(z$)&lt;br /&gt;
IF y = 257 THEN PRINT &amp;quot;done&amp;quot; ELSE PRINT &amp;quot;out of data.&amp;quot;&lt;br /&gt;
OPEN folder + LEFT$(lfn, 4) + extq FOR OUTPUT AS #9&lt;br /&gt;
PRINT #9, y$;&lt;br /&gt;
CLOSE #9&lt;br /&gt;
END SUB&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Visual Basic .NET ===&lt;br /&gt;
&lt;br /&gt;
This implementation uses high-level elements such as lambdas, anonymous arrays, and strict types. It must be compiled for the Microsoft .NET Framework v4.5 in Visual Studio 2012. It has the advantages of running in non-DosBox Windows and using .NET streams for simple reusability. It can also be used for higher-bit LZW.&lt;br /&gt;
&lt;br /&gt;
==== Decompression ====&lt;br /&gt;
&lt;br /&gt;
Decompressing is very fast.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vbnet&amp;quot;&amp;gt;    Sub DecompressLZW(Data As IO.Stream, MaxBits As Byte, Output As IO.Stream)&lt;br /&gt;
        &#039; This source is by Fleexy and is in the public domain. If used, please note it as such.&lt;br /&gt;
        Dim dict As New List(Of Byte())&lt;br /&gt;
        For x = 0 To 255&lt;br /&gt;
            dict.Add({x})&lt;br /&gt;
        Next&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        dict.Add(Nothing)&lt;br /&gt;
        Dim usebits As Byte = 9&lt;br /&gt;
        Dim bpos As Long&lt;br /&gt;
        Dim bits As New List(Of Byte)&lt;br /&gt;
        Do Until Data.Position = Data.Length&lt;br /&gt;
            Dim b, ub As Byte&lt;br /&gt;
            b = Data.ReadByte&lt;br /&gt;
            ub = b&lt;br /&gt;
            For x = 7 To 0 Step -1&lt;br /&gt;
                If ub - (2 ^ x) &amp;gt;= 0 Then&lt;br /&gt;
                    ub -= (2 ^ x)&lt;br /&gt;
                    bits.Add(1)&lt;br /&gt;
                Else&lt;br /&gt;
                    bits.Add(0)&lt;br /&gt;
                End If&lt;br /&gt;
            Next&lt;br /&gt;
        Loop&lt;br /&gt;
        Dim GetCode = Function() As UInteger&lt;br /&gt;
                          Dim u As UInteger&lt;br /&gt;
                          For x = usebits To 1 Step -1&lt;br /&gt;
                              If bits(bpos) = 1 Then u += (2 ^ (x - 1))&lt;br /&gt;
                              bpos += 1&lt;br /&gt;
                          Next&lt;br /&gt;
                          Return u&lt;br /&gt;
                      End Function&lt;br /&gt;
        Dim OutputCode = Sub(DecompData As Byte())&lt;br /&gt;
                             Dim n As UInteger = DecompData.Length&lt;br /&gt;
                             Output.Write(DecompData, 0, n)&lt;br /&gt;
                         End Sub&lt;br /&gt;
        Dim AddToDict = Sub(Entry As Byte())&lt;br /&gt;
                            If dict.Count &amp;lt; (2 ^ MaxBits) Then&lt;br /&gt;
                                dict.Add(Entry)&lt;br /&gt;
                                If dict.Count = (2 ^ usebits) - 1 Then usebits = Math.Min(usebits + 1, MaxBits)&lt;br /&gt;
                            End If&lt;br /&gt;
                        End Sub&lt;br /&gt;
        Dim fcode As UInteger = GetCode()&lt;br /&gt;
        Dim match As Byte() = dict(fcode)&lt;br /&gt;
        OutputCode(match)&lt;br /&gt;
        Do&lt;br /&gt;
            Dim ncode As UInteger = GetCode()&lt;br /&gt;
            If ncode = 257 Then Exit Do&lt;br /&gt;
            If ncode = 256 Then Throw New Exception&lt;br /&gt;
            Dim nmatch As Byte()&lt;br /&gt;
            If ncode &amp;lt; dict.Count Then&lt;br /&gt;
                nmatch = dict(ncode)&lt;br /&gt;
            Else&lt;br /&gt;
                nmatch = match.Concat({match(0)}).ToArray&lt;br /&gt;
            End If&lt;br /&gt;
            OutputCode(nmatch)&lt;br /&gt;
            AddToDict(match.Concat({nmatch(0)}).ToArray)&lt;br /&gt;
            match = nmatch&lt;br /&gt;
        Loop&lt;br /&gt;
    End Sub&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Compression ====&lt;br /&gt;
&lt;br /&gt;
Compression is more difficult; consulting the dictionary for a byte array takes more time. The speed of this algorithm may be unacceptable.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vbnet&amp;quot;&amp;gt;    Sub CompressLZW(Data As IO.Stream, MaxBits As Byte, Output As IO.Stream)&lt;br /&gt;
        &#039; This source is by Fleexy and is in the public domain.&lt;br /&gt;
        Dim bits As New List(Of Byte)&lt;br /&gt;
        Dim dict As New List(Of Byte())&lt;br /&gt;
        For x = 0 To 255&lt;br /&gt;
            dict.Add({x})&lt;br /&gt;
        Next&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        Dim usebits As Byte = 9&lt;br /&gt;
        Dim PutCode = Sub(Code As UInteger)&lt;br /&gt;
                          For x = usebits To 1 Step -1&lt;br /&gt;
                              If Code - (2 ^ (x - 1)) &amp;gt;= 0 Then&lt;br /&gt;
                                  Code -= (2 ^ (x - 1))&lt;br /&gt;
                                  bits.Add(1)&lt;br /&gt;
                              Else&lt;br /&gt;
                                  bits.Add(0)&lt;br /&gt;
                              End If&lt;br /&gt;
                          Next&lt;br /&gt;
                      End Sub&lt;br /&gt;
        Dim AddToDict = Function(Entry As Byte()) As Boolean&lt;br /&gt;
                            If dict.Count &amp;lt; 2 ^ MaxBits Then&lt;br /&gt;
                                dict.Add(Entry)&lt;br /&gt;
                                If dict.Count = 2 ^ usebits Then usebits = Math.Min(usebits + 1, MaxBits)&lt;br /&gt;
                                Return True&lt;br /&gt;
                            Else&lt;br /&gt;
                                Return False&lt;br /&gt;
                            End If&lt;br /&gt;
                        End Function&lt;br /&gt;
        Dim FindCode = Function(Bytes As Byte()) As UInteger&lt;br /&gt;
                           For x = 1 To dict.Count&lt;br /&gt;
                               If dict(x - 1).Count = Bytes.Count Then&lt;br /&gt;
                                   If dict(x - 1).SequenceEqual(Bytes) Then Return x - 1&lt;br /&gt;
                               End If&lt;br /&gt;
                           Next&lt;br /&gt;
                           Throw New NotFiniteNumberException&lt;br /&gt;
                       End Function&lt;br /&gt;
        Dim DictContains = Function(Bytes As Byte()) As Boolean&lt;br /&gt;
                               For x = 1 To dict.Count&lt;br /&gt;
                                   If dict(x - 1).Length = Bytes.Length Then&lt;br /&gt;
                                       If dict(x - 1).SequenceEqual(Bytes) Then Return True&lt;br /&gt;
                                   End If&lt;br /&gt;
                               Next&lt;br /&gt;
                               Return False&lt;br /&gt;
                           End Function&lt;br /&gt;
        Dim match As Byte() = {}&lt;br /&gt;
        Do Until Data.Position = Data.Length&lt;br /&gt;
            Dim nbyte As Byte = Data.ReadByte&lt;br /&gt;
            Dim nmatch As Byte() = match.Concat({nbyte}).ToArray&lt;br /&gt;
            If DictContains(nmatch) Then&lt;br /&gt;
                match = nmatch&lt;br /&gt;
            Else&lt;br /&gt;
                PutCode(FindCode(match))&lt;br /&gt;
                AddToDict(nmatch)&lt;br /&gt;
                match = {nbyte}&lt;br /&gt;
            End If&lt;br /&gt;
        Loop&lt;br /&gt;
        PutCode(FindCode(match))&lt;br /&gt;
        PutCode(257)&lt;br /&gt;
        Do Until bits.LongCount Mod 8L = 0L&lt;br /&gt;
            bits.Add(0)&lt;br /&gt;
        Loop&lt;br /&gt;
        For x = 1 To CInt(bits.LongCount / 8L)&lt;br /&gt;
            Dim b As Byte = 0&lt;br /&gt;
            For y = 0 To 7&lt;br /&gt;
                b += bits((x - 1) * 8 + y) * (2 ^ (7 - y))&lt;br /&gt;
            Next&lt;br /&gt;
            Output.WriteByte(b)&lt;br /&gt;
        Next&lt;br /&gt;
    End Sub&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander Keen 1-3]]&lt;br /&gt;
[[Category:File Formats]]&lt;br /&gt;
[[Category:Compressed Files]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=LZW_Compression&amp;diff=5087</id>
		<title>LZW Compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=LZW_Compression&amp;diff=5087"/>
		<updated>2013-12-31T22:42:52Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Forgot &amp;lt;/source&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;LZW compression is a common form of compression used in some early games to compress data and by most early games to compress their executables. It is notable in being one of the first compression methods to not compress on the byte level (Along with [[Huffman Compression]]) and for its efficiency.&lt;br /&gt;
&lt;br /&gt;
The basic concept for LZW is universal, though the implementations differ. In essence it involves replacing data strings that have been encountered before with references to already decompressed data. (Known as a &#039;dictionary&#039;) This can be done in a number of ways, the two main approaches differing on whether the dictionary is separate or integrated&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Separate Dictionary Approach =&lt;br /&gt;
&lt;br /&gt;
In this approach the dictionary is separate from the data being decompressed, that is it is stored in a separate location in memory. In this it behaves more like one would expect a dictionary to work; when a codeword is found in the data, it is looked up in the dictionary and the corresponding string copied to output. (As an example dictionary entry 42 could represent the string &#039;life&#039;, thus whenever the code &#039;42&#039; is encountered the string &#039;life&#039; is added to the decompressed data.)&lt;br /&gt;
&lt;br /&gt;
The advantage of this method is that the efficiency of compression increases as the amount of data to compress increases. The following points differ between implementations:&lt;br /&gt;
&lt;br /&gt;
* The initial dictionary. Just how large the initial dictionary is varies. Some implementations start with no dictioanry at all, others set a number of entries, usually 255, covering all possible 1-byte values.&lt;br /&gt;
&lt;br /&gt;
* The maximum size of the dictionary. Many older implementations with less resources were forced to cap the dictionary at a certain size, usually a power of two entries long. (512, 1024...) Unlimited implementations are rare as modern methods (e.g. the DEFLATE algorithm.)  usually rely on several compression methods at once. Sometimes the dictionary is &#039;reset&#039; when it reaches too large a size.&lt;br /&gt;
&lt;br /&gt;
* Whether the codestream is made partly or entirely of codewords. Often the compressed data is made entirely of codewords, even non-repeating strings, which means that initially compression can sometimes be rather poor. Other implementations use codeowords only for repeating strings. Differences in how codewords vs literal are indicated and how dictionaries are built up may occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Decoding ==&lt;br /&gt;
&lt;br /&gt;
This is a general decoding algorithm for separate dictionary LZW. It will need to be altered slightly when dealing with different implementations. Notably it assumes that the codestream is composed entirely of codewords and that the dictionary can keep growing indefinitely.&lt;br /&gt;
&lt;br /&gt;
    1   At the start the dictionary contains all possible roots;&lt;br /&gt;
    2   cW := the first code word in the codestream (it denotes a root);&lt;br /&gt;
    3   output the string.cW to the charstream;&lt;br /&gt;
    4   pW := cW;&lt;br /&gt;
    5   cW := next code word in the codestream;&lt;br /&gt;
    6   Is the string.cW present in the dictionary?&lt;br /&gt;
            a   if it is,&lt;br /&gt;
                    i   output the string.cW to the charstream;&lt;br /&gt;
                    ii  P := string.pW;&lt;br /&gt;
                    iii C := the first character of the string.cW;&lt;br /&gt;
                    iv  add the string P+C to the dictionary;&lt;br /&gt;
            b   if not,&lt;br /&gt;
                    i   P := string.pW;&lt;br /&gt;
                    ii  C := the first character of the string.pW;&lt;br /&gt;
                    iii output the string P+C to the charstream&lt;br /&gt;
                    iv  add the string P+C to the dictionary (now it corresponds to the cW);&lt;br /&gt;
    7   Are there more code words in the codestream?&lt;br /&gt;
            a   if yes, go back to step 4;&lt;br /&gt;
            b   if not, END.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== [[Commander Keen 1-3|Commander Keen 1-3 LZW]] ==&lt;br /&gt;
&lt;br /&gt;
In [[Commander Keen 1-3]] LZW is used to compress the &amp;lt;tt&amp;gt;EGALATCH&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;EGASPRIT&amp;lt;/tt&amp;gt; files in episode 1 (It can also be used in episodes 2 and 3, but isn&#039;t.) The game uses two error-checking methods in this implementation, firstly it reserves two dictionary values, $100 to indicate an error (This is written by the compression program and will make the executable abort.) and $101 to indicate the end of data. (If the program reaches the end of the data without encountering this it will also abort.) The compressed data is also prefixed with a dword giving the decompressed data size, so this can be compared with the output.&lt;br /&gt;
&lt;br /&gt;
This method is a typical separate dictionary approach. It starts with a dictionary of 256 9-bit codewords representing the 8-bit strings $00-$FF (Plus some special cases.) The dictionary is allowed to grow to 4096 entries. The following is the initial dictionary:&lt;br /&gt;
&lt;br /&gt;
        0000 - 00 (character)&lt;br /&gt;
        0001 - 01 (character)&lt;br /&gt;
            ...&lt;br /&gt;
        00FE - FE (character)&lt;br /&gt;
        00FF - FF (character)&lt;br /&gt;
        0100 - Reserved for errors...&lt;br /&gt;
        0101 - Reserved for end of compressed data...&lt;br /&gt;
        0102 - (not set)&lt;br /&gt;
        0103 - (not set)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It will be immediately noticed that 4096 entries cannot be represented by 9-bit codes but at the least by 12-bit codes. To further conserve space the length of the codewords is increased every time the dictionary grows too large. Thus when it reaches $01FF entries codewords become 10 bits long, at $03FF they are 11 bits and finally at $07FF 12 bits. At $0FFF entries the dictionary stops growing.&lt;br /&gt;
&lt;br /&gt;
The following data is taken from the EGALATCH file from Keen 1. Notice that the first six bytes are ignored. (The first four give the decompressed data size, the next two are an executable variable of unknown use.) The first few steps of decompression follows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    0000  80 D3 01 00  0C 00 00 40 - A0 70 31 E9  F8 F8 78 38&lt;br /&gt;
    0010  08 08 00 07  FC 39 FF 04 - 5E 41 E1 30  B3 C4 5A 2F&lt;br /&gt;
&lt;br /&gt;
The first code word encountered is 000000000 (First 9 bits) and thus outputs the string $00 (First dictionary entry.) This has set us up to step 4 and now things work slightly differently.&lt;br /&gt;
&lt;br /&gt;
The second code word is 100000010 (Next 9 bits) which is entry $102. Since this entry is NOT found in the dictionary yet, we will create this entry then output it. Entry $102 is created by taking the previous codeword&#039;s string adding to it the first byte of that string. In this case the previous codewrode&#039;s (0) string is $00. $00 + $00 is $00 $00 Entry $102 thus represents the string $00 $00&lt;br /&gt;
&lt;br /&gt;
The next code word is 100000011 which is entry $103, which again doesn&#039;t exist. Entry $103 is created just like with $102, except now since the previous codeword is $00 $00, entry $103 is $00 $00 $00&lt;br /&gt;
&lt;br /&gt;
The next code word is again $103, this IS found in the dictionary and is outputted ($00 $00 $00) however we now create dictionary entry $104 just like $103. (It is $00 $00 $00 $00)&lt;br /&gt;
&lt;br /&gt;
The next code word is $3B. It is outputted and entry $105 created ($00 $00 $00 $00 $3B) Note that now the previous codeword is $3B. This pattern continues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Integrated Dictionary Approach =&lt;br /&gt;
&lt;br /&gt;
In this approach the dictionary is the decompressed data itself. The codewords do not represent an entry in the dictionary structure, but rather directions in the decompressed code as to where a repeated string is located. That is a repeat string may well be represented by a codeword that states &#039;copy seven bytes from byte 132 in the decompressed data&#039;&lt;br /&gt;
&lt;br /&gt;
The advantage of this approach is that it doesn&#039;t require a separate construct for the dictionary and can just use the already decompressed data. The downside is that it will always need some method to distinguish literals and codewords, and, since codewords are nearly always of a fixed length there is an inherent limit both to how long the copied string can be and where it can be read from. this means that eventually the compression efficiency will level off and stop improving.&lt;br /&gt;
&lt;br /&gt;
There This is often called the &#039;sliding window&#039; and it represents the data that can be &#039;reached&#039; by the codewords. It is named as such because it is of a fixed length and &#039;slides&#039; along the output stream as it gets longer. The following features differ between implementations:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Differentiating codewords from literals. There must be a way to tell codewords apart from data that is just to be read and outputted. Sometimes this is integrated into the codewords themselves, but more often the &#039;flag&#039; precedes a codeword. The flag may indicate only codewords or both codewords and literals. (&#039;Following data is made of two codewords and six literals&#039;, etc.)&lt;br /&gt;
&lt;br /&gt;
* Codeword format. Most implementations use codewords of a fixed format that must encode both the length of data to copy and the location to copy it from. Codewords are usually two or four bytes long.&lt;br /&gt;
&lt;br /&gt;
* Zero point location. Different implementations use different places in the output as zero. If the start of the code is used as zero only the first x bytes of the output can be used as a reference. Most implementations use a more complex, but seldom less effective &#039;sliding window&#039;; the zero point is the start of the data until the data becomes too long at which point it moves forward so that the most recent x bytes of output can be used. It is also possible for zero to be the most recent byte with all locations being &#039;x bytes from the end&#039;, which also produces a sliding window. Finally it may be possible to have both negative and positive locations.&lt;br /&gt;
&lt;br /&gt;
* Sliding window. The nature of this is dictated by the format of the codewords. Common sizes are 1KB, 2KB or 4KB. The window will always be present, but it may not &#039;slide&#039; if the implementation uses a fixed location as the zero point.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== LZEXE ==&lt;br /&gt;
&lt;br /&gt;
Many vintage executables are compressed with the program LZEXE, interesting in that the compressed file contains its own decompressor, meaning that it is in essence a self-extracting archive. However the unique feature of LZEXE executables is that they extract the compressed data to memory and run it. To the user this is indistinguishable from the decompressed executable, though it takes slightly longer to start up and takes up much less space.&lt;br /&gt;
&lt;br /&gt;
[[UNLZEXE]] can be used to extract the decompressed executables from this which will run perfectly with other game files. It can be obtained here: http://www.dosclassics.com/download/198 It is currently unknown specifically how the LZW compression is implemented in this case, but with the source code for decompression is available.&lt;br /&gt;
&lt;br /&gt;
The LZEXE compression is similar to the SoftDisk Library Approach described below, but it uses UINT16LE values instead of byte values to store the flag bits and the sliding window has a size of 8192 (0x2000) bytes. Also, the flag bits have different meanings (you could argue that they are in fact Huffman codes):&lt;br /&gt;
&lt;br /&gt;
    1 -&amp;gt; copy 1 literal byte&lt;br /&gt;
   10 -&amp;gt; next two bytes contain length and distance&lt;br /&gt;
 0000 -&amp;gt; length is 2, next byte contains distance &lt;br /&gt;
 1000 -&amp;gt; length is 3, next byte contains distance &lt;br /&gt;
 0100 -&amp;gt; length is 4, next byte contains distance &lt;br /&gt;
 1100 -&amp;gt; length is 5, next byte contains distance &lt;br /&gt;
&lt;br /&gt;
The real distance value is always a signed 16 bit integer (you can use unsigned but then you have to bitwise-and the resulting index value with 0xFFFF). If the length is given by the flag bits/Huffman code, the real distance is &amp;lt;tt&amp;gt;b | 0xFF00&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;b - 256&amp;lt;/tt&amp;gt; where &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt; is the byte value read from the file. If the length value is not given, read the byte values &amp;lt;tt&amp;gt;b0&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;b1&amp;lt;/tt&amp;gt; and calculate length and distance like this:&lt;br /&gt;
&lt;br /&gt;
 length = (b1 mod 8)+2&lt;br /&gt;
 distance = b0 + (b1/8)*256 - 8192&lt;br /&gt;
or&lt;br /&gt;
 length = (b1 &amp;amp; 0x07)+2&lt;br /&gt;
 distance = b0 | ((b1 &amp;amp; 0xF8)&amp;lt;&amp;lt;5) | 0xE000&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt; value calculated from &amp;lt;tt&amp;gt;b1&amp;lt;/tt&amp;gt; is 2, this indicates that another byte value &amp;lt;tt&amp;gt;b2&amp;lt;/tt&amp;gt; must be read. Depending in the value of b2, one of three things can happen:&lt;br /&gt;
 b2 = 0:&lt;br /&gt;
    end of compressed data - stop decompressing&lt;br /&gt;
 b2 = 1:&lt;br /&gt;
    end of segment&lt;br /&gt;
    (decompressor may write contents of buffer to output)&lt;br /&gt;
    set length to 0 or jump to the part where the decompressor reads the next flag bits/Huffman code&lt;br /&gt;
 otherwise:&lt;br /&gt;
    set length to b2+1&lt;br /&gt;
&lt;br /&gt;
Now the decompressor must only add &amp;lt;tt&amp;gt;distance&amp;lt;/tt&amp;gt; to the current buffer index (since &amp;lt;tt&amp;gt;distance&amp;lt;/tt&amp;gt; is negative, the index goes backwards) and copy &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt; bytes from there to the current index:&lt;br /&gt;
&lt;br /&gt;
 WHILE length &amp;gt; 0&lt;br /&gt;
    buffer[index] = buffer[index+distance]&lt;br /&gt;
    index = index + 1&lt;br /&gt;
    length = length - 1&lt;br /&gt;
 END WHILE&lt;br /&gt;
&lt;br /&gt;
Please refer to the ULZEXE source code for further information.&lt;br /&gt;
&lt;br /&gt;
== SoftDisk Library Approach ==&lt;br /&gt;
&lt;br /&gt;
This is used as the first form of compression in the [[Softdisk Library Format]]. Flags are 1-byte long and divide the datastream into segments of eight &#039;values&#039; which can be either literals or codewords. Codewords are 2 bytes long, literals 1 byte. (Therefore there will be a flag byte every 8 to 16 bytes of data.) The value of each bit (In little endian) indicates whether a value will be a literal (1) or codeword (0) Thus a value of 199 (11000111 in binary) indicates three codewords, three literals and two codewords in that order. (Total of 13 bytes.)&lt;br /&gt;
&lt;br /&gt;
Literals are sequences that have never been seen in the datastream before, they cannot be compressed and are thus the same in the compressed and decompressed datastreams. (If the data is text they become quite obvious.) Any string less than 3 bytes long that has not been read before or cannot be pointed to (See below) will be stored as literals.&lt;br /&gt;
&lt;br /&gt;
Codewords are reference to data that has already been read. They are two bytes long, with the first 12 bits giving the location to read data from and the last 4 bits giving the length of data to read.&lt;br /&gt;
&lt;br /&gt;
The lower nybble (4 bits) of the second codeword byte holds the length of repeat data to read minus three. (This makes sense, the shortest sequence it makes sense to code is three bytes which can be given the value 0.) It will be immediately apparent that the maximum length of repeated data that can be stored as a codeword is 18 bytes.&lt;br /&gt;
&lt;br /&gt;
The high nybble of the second byte is multiplied by 16 then added to the first byte to give the location of the data to read in the &#039;sliding window&#039; minus 19. (This is due to the way the decompression is set up in memory.)&lt;br /&gt;
&lt;br /&gt;
It will be immediately obvious that the codewords can encode values between +-2048, or about 2KB. If the decompressed data is less than 2KB in size then zero is the start of the data, if it is larger than it is 2048 bytes from the data end.&lt;br /&gt;
&lt;br /&gt;
It will be noted that it is probable that the compressed datastream will not be perfectly divisible by flag bytes. In this case the unused bits are set to 0. The decompressor stops when the decompressed data size is equal to the value given in the chunk header. (If it runs out of data it will abort.)&lt;br /&gt;
&lt;br /&gt;
As a simple example the sentence &#039;I am Sam. Sam I am!&#039; will be compressed to:&lt;br /&gt;
&lt;br /&gt;
 FF				Flag byte, 8 literals follow&lt;br /&gt;
 49 20 61 6D 20 53 61 6D	&#039;I am Sam&#039; as literals&lt;br /&gt;
 2B				Flag byte, 2L, P, L, P, L 2Blanks ($2B = 43 = 00101011)&lt;br /&gt;
 2E 20				&#039; .&#039; as literals&lt;br /&gt;
 F2 F0				codeword, read 0 + 3 = 3 bytes from $FF2, or -14 + 19 = 5 in the data. This is &#039;Sam&#039;&lt;br /&gt;
 20				&#039; &#039; as literal&lt;br /&gt;
 ED F1				codeword, read 1 + 3 = 4 bytes from $FED or -19 + 19 = 1 in the data. This is &#039;I am&#039;&lt;br /&gt;
 21				&#039;!&#039; as literal&lt;br /&gt;
&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 Keen&#039;s LZW algorithm in its various implementations.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Keen 1-3 Implementation ==&lt;br /&gt;
&lt;br /&gt;
These segments f code work with the Keen 1-3 implementation only and will not for example decompress LZEXE compressed executables.&lt;br /&gt;
&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;
DECLARE FUNCTION READBITS% (FILE AS INTEGER, NUMBITS AS INTEGER)&lt;br /&gt;
DECLARE SUB LZWDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING)&lt;br /&gt;
DECLARE SUB LZWOUTPUT (FILE AS INTEGER, DIC AS INTEGER, CHAR AS INTEGER)&lt;br /&gt;
&#039;&lt;br /&gt;
&#039; KEEN1 Compatible LZW Decompressor (Lempel-Ziv-Welch)&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&lt;br /&gt;
&#039;&lt;br /&gt;
&#039;&lt;br /&gt;
&lt;br /&gt;
&#039; Allocate dictionary&lt;br /&gt;
DIM LZDIC(0 TO 4095) AS INTEGER&lt;br /&gt;
DIM LZCHR(0 TO 4095) AS INTEGER&lt;br /&gt;
&lt;br /&gt;
&#039; Test Function&lt;br /&gt;
LZWDECOMPRESS &amp;quot;EGALATCH.CK1&amp;quot;, &amp;quot;EGALATCH.DAT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SUB LZWDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING)&lt;br /&gt;
        SHARED LZDIC() AS INTEGER, LZCHR() AS INTEGER&lt;br /&gt;
        DIM INFILE AS INTEGER, OUTFILE AS INTEGER, I AS INTEGER&lt;br /&gt;
        DIM BITLEN AS INTEGER, CURPOS AS INTEGER&lt;br /&gt;
        DIM CW AS INTEGER, PW AS INTEGER, C AS INTEGER, P AS INTEGER&lt;br /&gt;
        DIM CHECK AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        &#039; Open files for input and output&lt;br /&gt;
        INFILE = FREEFILE&lt;br /&gt;
        OPEN INNAME FOR BINARY ACCESS READ AS INFILE&lt;br /&gt;
        OUTFILE = FREEFILE&lt;br /&gt;
        OPEN OUTNAME FOR BINARY ACCESS WRITE AS OUTFILE&lt;br /&gt;
        SEEK INFILE, 7&lt;br /&gt;
&lt;br /&gt;
       &lt;br /&gt;
        &#039; Fill dictionary with starting values&lt;br /&gt;
        FOR I = 0 TO 4095&lt;br /&gt;
                LZDIC(I) = -1&lt;br /&gt;
                IF I &amp;lt; 256 THEN&lt;br /&gt;
                        LZCHR(I) = I&lt;br /&gt;
                ELSE&lt;br /&gt;
                        LZCHR(I) = -1&lt;br /&gt;
                END IF&lt;br /&gt;
        NEXT I&lt;br /&gt;
&lt;br /&gt;
        &#039; Decompress input stream to output stream&lt;br /&gt;
        BITLEN = 9&lt;br /&gt;
        CURPOS = 258&lt;br /&gt;
        CW = READBITS(INFILE, BITLEN)&lt;br /&gt;
        LZWOUTPUT OUTFILE, LZDIC(CW), LZCHR(CW)&lt;br /&gt;
       &lt;br /&gt;
        WHILE CW &amp;lt;&amp;gt; &amp;amp;H100 AND CW &amp;lt;&amp;gt; &amp;amp;H101&lt;br /&gt;
                PW = CW&lt;br /&gt;
                CW = READBITS(INFILE, BITLEN)&lt;br /&gt;
                IF CW &amp;lt;&amp;gt; &amp;amp;H100 AND CW &amp;lt;&amp;gt; &amp;amp;H101 THEN&lt;br /&gt;
                        P = PW&lt;br /&gt;
                        CHECK = (LZCHR(CW) &amp;lt;&amp;gt; -1)&lt;br /&gt;
                       &lt;br /&gt;
                        IF CHECK THEN&lt;br /&gt;
                                TMP = CW&lt;br /&gt;
                        ELSE&lt;br /&gt;
                                TMP = PW&lt;br /&gt;
                        END IF&lt;br /&gt;
                        WHILE LZDIC(TMP) &amp;lt;&amp;gt; -1&lt;br /&gt;
                                TMP = LZDIC(TMP)&lt;br /&gt;
                        WEND&lt;br /&gt;
                        C = LZCHR(TMP)&lt;br /&gt;
                       &lt;br /&gt;
                        IF CHECK THEN&lt;br /&gt;
                                LZWOUTPUT OUTFILE, LZDIC(CW), LZCHR(CW)&lt;br /&gt;
                        ELSE&lt;br /&gt;
                                LZWOUTPUT OUTFILE, P, C&lt;br /&gt;
                        END IF&lt;br /&gt;
                       &lt;br /&gt;
                        IF CURPOS &amp;lt; 4096 THEN&lt;br /&gt;
                                LZDIC(CURPOS) = P&lt;br /&gt;
                                LZCHR(CURPOS) = C&lt;br /&gt;
                                CURPOS = CURPOS + 1&lt;br /&gt;
                                IF CURPOS = (2 ^ BITLEN - 1) AND BITLEN &amp;lt; 12 THEN&lt;br /&gt;
                                        BITLEN = BITLEN + 1&lt;br /&gt;
                                END IF&lt;br /&gt;
                        END IF&lt;br /&gt;
&lt;br /&gt;
                END IF&lt;br /&gt;
        WEND&lt;br /&gt;
       &lt;br /&gt;
        &#039; Close files&lt;br /&gt;
        CLOSE OUTFILE&lt;br /&gt;
        CLOSE INFILE&lt;br /&gt;
END SUB&lt;br /&gt;
&lt;br /&gt;
SUB LZWOUTPUT (FILE AS INTEGER, DIC AS INTEGER, CHAR AS INTEGER)&lt;br /&gt;
        SHARED LZDIC() AS INTEGER, LZCHR() AS INTEGER&lt;br /&gt;
        DIM LZSTK(0 TO 127) AS STRING * 1&lt;br /&gt;
        DIM X AS INTEGER, SP AS INTEGER&lt;br /&gt;
        DIM LDIC AS INTEGER, LCHAR AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        LCHAR = CHAR&lt;br /&gt;
        LDIC = DIC&lt;br /&gt;
        SP = 0&lt;br /&gt;
        X = 1&lt;br /&gt;
&lt;br /&gt;
        DO&lt;br /&gt;
                IF SP &amp;gt;= 128 THEN&lt;br /&gt;
                        PRINT &amp;quot;LZW: Stack Overflow!&amp;quot;&lt;br /&gt;
                        END&lt;br /&gt;
                END IF&lt;br /&gt;
                LZSTK(SP) = CHR$(LCHAR)&lt;br /&gt;
                SP = SP + 1&lt;br /&gt;
                IF LDIC &amp;lt;&amp;gt; -1 THEN&lt;br /&gt;
                        LCHAR = LZCHR(LDIC)&lt;br /&gt;
                        LDIC = LZDIC(LDIC)&lt;br /&gt;
                ELSE&lt;br /&gt;
                        X = 0&lt;br /&gt;
                END IF&lt;br /&gt;
        LOOP WHILE X&lt;br /&gt;
       &lt;br /&gt;
        WHILE SP &amp;lt;&amp;gt; 0&lt;br /&gt;
                SP = SP - 1&lt;br /&gt;
                PUT FILE, , LZSTK(SP)&lt;br /&gt;
        WEND&lt;br /&gt;
END SUB&lt;br /&gt;
&lt;br /&gt;
FUNCTION READBITS% (FILE AS INTEGER, NUMBITS AS INTEGER)&lt;br /&gt;
        STATIC BITDAT AS STRING * 1, BITPOS AS INTEGER&lt;br /&gt;
        DIM BITVAL AS INTEGER, BIT AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        BITVAL = 0&lt;br /&gt;
        FOR BIT = (NUMBITS - 1) TO 0 STEP -1&lt;br /&gt;
                IF BITPOS = 0 THEN&lt;br /&gt;
                        GET FILE, , BITDAT&lt;br /&gt;
                        BITPOS = 7&lt;br /&gt;
                ELSE&lt;br /&gt;
                        BITPOS = BITPOS - 1&lt;br /&gt;
                END IF&lt;br /&gt;
                IF ASC(BITDAT) AND 2 ^ BITPOS THEN&lt;br /&gt;
                        BITVAL = BITVAL OR 2 ^ BIT&lt;br /&gt;
                END IF&lt;br /&gt;
        NEXT BIT&lt;br /&gt;
&lt;br /&gt;
        READBITS% = BITVAL&lt;br /&gt;
END FUNCTION&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== FreeBasic ===&lt;br /&gt;
&lt;br /&gt;
This code does not suffer from the 64K memory limit imposed by QuickBasic and so is less efficient, but runs faster. It can be compiled with FreeBasic compiler using the -lang=qb switch. Aside from memory concerns, all code here is compatible with QuickBasic.&lt;br /&gt;
&lt;br /&gt;
The code before the subroutine is used to make a string containing the bit expansion of all values from 0 to 255. The subroutine takes a filename, reads the entire file into memory then expands each bit of data to a byte using the aforesaid string as Basic cannot deal with bits directly. cw$ is codeword, pw$ is the previous codeword, lun is the lowest dictionary entry that is empty, p is the location in the compressed data stream and bl is the length of codes in bits (Starting at nine bits increasing to 12)&lt;br /&gt;
&lt;br /&gt;
The dictionary is set before decompression. The first 258 are the starting dictionary, the remainder are cleared. (It is vital to reset the dictionary for each file) An error occurs if entry 256 is found in the data, &#039;distrupt&#039; is printed when the newest dictionary entry is not the lowest possible entry (This shouldn&#039;t happen but is possible.) Decompression ends at encountering entry 257, or when there is no more data to read.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;qbasic&amp;quot;&amp;gt;&lt;br /&gt;
DECLARE SUB LZWDEC (lfn AS STRING)&lt;br /&gt;
&lt;br /&gt;
x$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 0 TO 255&lt;br /&gt;
 IF (l AND 128) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 64) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 32) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 16) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 8) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 4) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 2) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 1) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
NEXT l&lt;br /&gt;
LZEDEC &amp;quot;EGALATCH.CK1&amp;quot;&lt;br /&gt;
END&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;_________________________________________________&lt;br /&gt;
SUB LZWDEC (lfn AS STRING) &#039; Decompress LZW data&lt;br /&gt;
&#039;_________________________________________________&lt;br /&gt;
DIM lzw(0 TO 4095) AS STRING&lt;br /&gt;
PRINT lfn; &amp;quot; is LZW compressed, decompressing...&amp;quot;;&lt;br /&gt;
OPEN folder + lfn FOR BINARY AS #9&lt;br /&gt;
y$ = SPACE$(LOF(9))&lt;br /&gt;
GET #9, 1, y$&lt;br /&gt;
CLOSE #9&lt;br /&gt;
z$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 7 TO LEN(y$)&lt;br /&gt;
 z$ = z$ + MID$(x$, (ASC(MID$(y$, l, 1)) * 8) + 1, 8)&lt;br /&gt;
NEXT l&lt;br /&gt;
&lt;br /&gt;
bl = 9&lt;br /&gt;
lun = 258&lt;br /&gt;
p = 1&lt;br /&gt;
cw$ = &amp;quot;&amp;quot;&lt;br /&gt;
y$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 0 TO 4095&lt;br /&gt;
 IF l &amp;lt; 256 THEN lzw(l) = CHR$(l) ELSE lzw(l) = &amp;quot;&amp;quot;&lt;br /&gt;
NEXT l&lt;br /&gt;
DO&lt;br /&gt;
 IF lun = 511 THEN bl = 10&lt;br /&gt;
 IF lun = 1023 THEN bl = 11&lt;br /&gt;
 IF lun = 2047 THEN bl = 12&lt;br /&gt;
 pw$ = cw$&lt;br /&gt;
 u$ = MID$(z$, p, bl)&lt;br /&gt;
 p = p + bl&lt;br /&gt;
 y = 0&lt;br /&gt;
 FOR l = 1 TO bl&lt;br /&gt;
  IF MID$(u$, bl - l + 1, 1) = &amp;quot;1&amp;quot; THEN y = y + (2 ^ (l - 1))&lt;br /&gt;
 NEXT l&lt;br /&gt;
 IF y = 256 THEN&lt;br /&gt;
  PRINT &amp;quot;LZW error in Keen data!&amp;quot;&lt;br /&gt;
  OPEN &amp;quot;ERROR.DAT&amp;quot; FOR OUTPUT AS #9&lt;br /&gt;
  PRINT #9, y$;&lt;br /&gt;
  CLOSE&lt;br /&gt;
  END&lt;br /&gt;
 END IF&lt;br /&gt;
 IF y = 257 THEN EXIT DO&lt;br /&gt;
 IF cw$ = &amp;quot;&amp;quot; THEN&lt;br /&gt;
  cw$ = lzw(y)&lt;br /&gt;
  y$ = y$ + cw$&lt;br /&gt;
 ELSE&lt;br /&gt;
  IF lun &amp;lt; 4096 THEN&lt;br /&gt;
   IF lzw(y) = &amp;quot;&amp;quot; THEN&lt;br /&gt;
    cw$ = pw$ + LEFT$(pw$, 1)&lt;br /&gt;
    lzw(y) = cw$&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
    IF y &amp;lt;&amp;gt; lun THEN PRINT &amp;quot;Disrupt!&amp;quot;&lt;br /&gt;
    lun = y + 1&lt;br /&gt;
   ELSE&lt;br /&gt;
    cw$ = lzw(y)&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
    lzw(lun) = pw$ + LEFT$(cw$, 1)&lt;br /&gt;
    lun = lun + 1&lt;br /&gt;
   END IF&lt;br /&gt;
  ELSE&lt;br /&gt;
   IF lzw(y) = &amp;quot;&amp;quot; THEN&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
   ELSE&lt;br /&gt;
    cw$ = lzw(y)&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
   END IF&lt;br /&gt;
  END IF&lt;br /&gt;
 END IF&lt;br /&gt;
LOOP WHILE p &amp;lt; LEN(z$)&lt;br /&gt;
IF y = 257 THEN PRINT &amp;quot;done&amp;quot; ELSE PRINT &amp;quot;out of data.&amp;quot;&lt;br /&gt;
OPEN folder + LEFT$(lfn, 4) + extq FOR OUTPUT AS #9&lt;br /&gt;
PRINT #9, y$;&lt;br /&gt;
CLOSE #9&lt;br /&gt;
END SUB&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Visual Basic .NET ===&lt;br /&gt;
&lt;br /&gt;
This implementation uses high-level elements such as lambdas, anonymous arrays, and strict types. It must be compiled for the Microsoft .NET Framework v4.5 in Visual Studio 2012. It has the advantages of running in non-DosBox Windows and using .NET streams for simple reusability. It can also be used for higher-bit LZW.&lt;br /&gt;
&lt;br /&gt;
==== Decompression ====&lt;br /&gt;
&lt;br /&gt;
Decompressing is very fast.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vbnet&amp;quot;&amp;gt;    Sub DecompressLZW(Data As IO.Stream, MaxBits As Byte, Output As IO.Stream)&lt;br /&gt;
        &#039; This source is by Fleexy and is in the public domain. If used, please note it as such.&lt;br /&gt;
        Dim dict As New List(Of Byte())&lt;br /&gt;
        For x = 0 To 255&lt;br /&gt;
            dict.Add({x})&lt;br /&gt;
        Next&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        dict.Add(Nothing)&lt;br /&gt;
        Dim usebits As Byte = 9&lt;br /&gt;
        Dim bpos As Long&lt;br /&gt;
        Dim bits As New List(Of Byte)&lt;br /&gt;
        Do Until Data.Position = Data.Length&lt;br /&gt;
            Dim b, ub As Byte&lt;br /&gt;
            b = Data.ReadByte&lt;br /&gt;
            ub = b&lt;br /&gt;
            For x = 7 To 0 Step -1&lt;br /&gt;
                If ub - (2 ^ x) &amp;gt;= 0 Then&lt;br /&gt;
                    ub -= (2 ^ x)&lt;br /&gt;
                    bits.Add(1)&lt;br /&gt;
                Else&lt;br /&gt;
                    bits.Add(0)&lt;br /&gt;
                End If&lt;br /&gt;
            Next&lt;br /&gt;
        Loop&lt;br /&gt;
        Dim GetCode = Function() As UInteger&lt;br /&gt;
                          Dim u As UInteger&lt;br /&gt;
                          For x = usebits To 1 Step -1&lt;br /&gt;
                              If bits(bpos) = 1 Then u += (2 ^ (x - 1))&lt;br /&gt;
                              bpos += 1&lt;br /&gt;
                          Next&lt;br /&gt;
                          Return u&lt;br /&gt;
                      End Function&lt;br /&gt;
        Dim OutputCode = Sub(DecompData As Byte())&lt;br /&gt;
                             Dim n As UInteger = DecompData.Length&lt;br /&gt;
                             Output.Write(DecompData, 0, n)&lt;br /&gt;
                         End Sub&lt;br /&gt;
        Dim AddToDict = Sub(Entry As Byte())&lt;br /&gt;
                            If dict.Count &amp;lt; (2 ^ MaxBits) Then&lt;br /&gt;
                                dict.Add(Entry)&lt;br /&gt;
                                If dict.Count = (2 ^ usebits) - 1 Then usebits = Math.Min(usebits + 1, MaxBits)&lt;br /&gt;
                            End If&lt;br /&gt;
                        End Sub&lt;br /&gt;
        Dim fcode As UInteger = GetCode()&lt;br /&gt;
        Dim match As Byte() = dict(fcode)&lt;br /&gt;
        OutputCode(match)&lt;br /&gt;
        Do&lt;br /&gt;
            Dim ncode As UInteger = GetCode()&lt;br /&gt;
            If ncode = 257 Then Exit Do&lt;br /&gt;
            If ncode = 256 Then Throw New Exception&lt;br /&gt;
            Dim nmatch As Byte()&lt;br /&gt;
            If ncode &amp;lt; dict.Count Then&lt;br /&gt;
                nmatch = dict(ncode)&lt;br /&gt;
            Else&lt;br /&gt;
                nmatch = match.Concat({match(0)}).ToArray&lt;br /&gt;
            End If&lt;br /&gt;
            OutputCode(nmatch)&lt;br /&gt;
            AddToDict(match.Concat({nmatch(0)}).ToArray)&lt;br /&gt;
            match = nmatch&lt;br /&gt;
        Loop&lt;br /&gt;
    End Sub&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Compression ====&lt;br /&gt;
&lt;br /&gt;
Compression is more difficult; consulting the dictionary for a byte array takes more time. The speed of this algorithm may be unacceptable.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vbnet&amp;quot;&amp;gt;    Sub CompressLZW(Data As IO.Stream, MaxBits As Byte, Output As IO.Stream)&lt;br /&gt;
        &#039; This source is by Fleexy and is in the public domain.&lt;br /&gt;
        Dim bits As New List(Of Byte)&lt;br /&gt;
        Dim dict As New List(Of Byte())&lt;br /&gt;
        For x = 0 To 255&lt;br /&gt;
            dict.Add({x})&lt;br /&gt;
        Next&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        Dim usebits As Byte = 9&lt;br /&gt;
        Dim PutCode = Sub(Code As UInteger)&lt;br /&gt;
                          For x = usebits To 1 Step -1&lt;br /&gt;
                              If Code - (2 ^ (x - 1)) &amp;gt;= 0 Then&lt;br /&gt;
                                  Code -= (2 ^ (x - 1))&lt;br /&gt;
                                  bits.Add(1)&lt;br /&gt;
                              Else&lt;br /&gt;
                                  bits.Add(0)&lt;br /&gt;
                              End If&lt;br /&gt;
                          Next&lt;br /&gt;
                      End Sub&lt;br /&gt;
        Dim AddToDict = Function(Entry As Byte()) As Boolean&lt;br /&gt;
                            If dict.Count &amp;lt; 2 ^ MaxBits Then&lt;br /&gt;
                                dict.Add(Entry)&lt;br /&gt;
                                If dict.Count = 2 ^ usebits Then usebits = Math.Min(usebits + 1, MaxBits)&lt;br /&gt;
                                Return True&lt;br /&gt;
                            Else&lt;br /&gt;
                                Return False&lt;br /&gt;
                            End If&lt;br /&gt;
                        End Function&lt;br /&gt;
        Dim FindCode = Function(Bytes As Byte()) As UInteger&lt;br /&gt;
                           For x = 1 To dict.Count&lt;br /&gt;
                               If dict(x - 1).Count = Bytes.Count Then&lt;br /&gt;
                                   If dict(x - 1).SequenceEqual(Bytes) Then Return x - 1&lt;br /&gt;
                               End If&lt;br /&gt;
                           Next&lt;br /&gt;
                           Throw New NotFiniteNumberException&lt;br /&gt;
                       End Function&lt;br /&gt;
        Dim DictContains = Function(Bytes As Byte()) As Boolean&lt;br /&gt;
                               For x = 1 To dict.Count&lt;br /&gt;
                                   If dict(x - 1).Length = Bytes.Length Then&lt;br /&gt;
                                       If dict(x - 1).SequenceEqual(Bytes) Then Return True&lt;br /&gt;
                                   End If&lt;br /&gt;
                               Next&lt;br /&gt;
                               Return False&lt;br /&gt;
                           End Function&lt;br /&gt;
        Dim match As Byte() = {}&lt;br /&gt;
        Do Until Data.Position = Data.Length&lt;br /&gt;
            Dim nbyte As Byte = Data.ReadByte&lt;br /&gt;
            Dim nmatch As Byte() = match.Concat({nbyte}).ToArray&lt;br /&gt;
            If DictContains(nmatch) Then&lt;br /&gt;
                match = nmatch&lt;br /&gt;
            Else&lt;br /&gt;
                PutCode(FindCode(match))&lt;br /&gt;
                AddToDict(nmatch)&lt;br /&gt;
                match = {nbyte}&lt;br /&gt;
            End If&lt;br /&gt;
        Loop&lt;br /&gt;
        PutCode(FindCode(match))&lt;br /&gt;
        PutCode(257)&lt;br /&gt;
        Do Until bits.LongCount Mod 8L = 0L&lt;br /&gt;
            bits.Add(0)&lt;br /&gt;
        Loop&lt;br /&gt;
        For x = 1 To CInt(bits.LongCount / 8L)&lt;br /&gt;
            Dim b As Byte = 0&lt;br /&gt;
            For y = 0 To 7&lt;br /&gt;
                b += bits((x - 1) * 8 + y) * (2 ^ (7 - y))&lt;br /&gt;
            Next&lt;br /&gt;
            Output.WriteByte(b)&lt;br /&gt;
        Next&lt;br /&gt;
    End Sub&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander Keen 1-3]]&lt;br /&gt;
[[Category:File Formats]]&lt;br /&gt;
[[Category:Compressed Files]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=LZW_Compression&amp;diff=5086</id>
		<title>LZW Compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=LZW_Compression&amp;diff=5086"/>
		<updated>2013-12-31T22:41:57Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Fixed source language; I expected it to not be displayed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;LZW compression is a common form of compression used in some early games to compress data and by most early games to compress their executables. It is notable in being one of the first compression methods to not compress on the byte level (Along with [[Huffman Compression]]) and for its efficiency.&lt;br /&gt;
&lt;br /&gt;
The basic concept for LZW is universal, though the implementations differ. In essence it involves replacing data strings that have been encountered before with references to already decompressed data. (Known as a &#039;dictionary&#039;) This can be done in a number of ways, the two main approaches differing on whether the dictionary is separate or integrated&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Separate Dictionary Approach =&lt;br /&gt;
&lt;br /&gt;
In this approach the dictionary is separate from the data being decompressed, that is it is stored in a separate location in memory. In this it behaves more like one would expect a dictionary to work; when a codeword is found in the data, it is looked up in the dictionary and the corresponding string copied to output. (As an example dictionary entry 42 could represent the string &#039;life&#039;, thus whenever the code &#039;42&#039; is encountered the string &#039;life&#039; is added to the decompressed data.)&lt;br /&gt;
&lt;br /&gt;
The advantage of this method is that the efficiency of compression increases as the amount of data to compress increases. The following points differ between implementations:&lt;br /&gt;
&lt;br /&gt;
* The initial dictionary. Just how large the initial dictionary is varies. Some implementations start with no dictioanry at all, others set a number of entries, usually 255, covering all possible 1-byte values.&lt;br /&gt;
&lt;br /&gt;
* The maximum size of the dictionary. Many older implementations with less resources were forced to cap the dictionary at a certain size, usually a power of two entries long. (512, 1024...) Unlimited implementations are rare as modern methods (e.g. the DEFLATE algorithm.)  usually rely on several compression methods at once. Sometimes the dictionary is &#039;reset&#039; when it reaches too large a size.&lt;br /&gt;
&lt;br /&gt;
* Whether the codestream is made partly or entirely of codewords. Often the compressed data is made entirely of codewords, even non-repeating strings, which means that initially compression can sometimes be rather poor. Other implementations use codeowords only for repeating strings. Differences in how codewords vs literal are indicated and how dictionaries are built up may occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Decoding ==&lt;br /&gt;
&lt;br /&gt;
This is a general decoding algorithm for separate dictionary LZW. It will need to be altered slightly when dealing with different implementations. Notably it assumes that the codestream is composed entirely of codewords and that the dictionary can keep growing indefinitely.&lt;br /&gt;
&lt;br /&gt;
    1   At the start the dictionary contains all possible roots;&lt;br /&gt;
    2   cW := the first code word in the codestream (it denotes a root);&lt;br /&gt;
    3   output the string.cW to the charstream;&lt;br /&gt;
    4   pW := cW;&lt;br /&gt;
    5   cW := next code word in the codestream;&lt;br /&gt;
    6   Is the string.cW present in the dictionary?&lt;br /&gt;
            a   if it is,&lt;br /&gt;
                    i   output the string.cW to the charstream;&lt;br /&gt;
                    ii  P := string.pW;&lt;br /&gt;
                    iii C := the first character of the string.cW;&lt;br /&gt;
                    iv  add the string P+C to the dictionary;&lt;br /&gt;
            b   if not,&lt;br /&gt;
                    i   P := string.pW;&lt;br /&gt;
                    ii  C := the first character of the string.pW;&lt;br /&gt;
                    iii output the string P+C to the charstream&lt;br /&gt;
                    iv  add the string P+C to the dictionary (now it corresponds to the cW);&lt;br /&gt;
    7   Are there more code words in the codestream?&lt;br /&gt;
            a   if yes, go back to step 4;&lt;br /&gt;
            b   if not, END.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== [[Commander Keen 1-3|Commander Keen 1-3 LZW]] ==&lt;br /&gt;
&lt;br /&gt;
In [[Commander Keen 1-3]] LZW is used to compress the &amp;lt;tt&amp;gt;EGALATCH&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;EGASPRIT&amp;lt;/tt&amp;gt; files in episode 1 (It can also be used in episodes 2 and 3, but isn&#039;t.) The game uses two error-checking methods in this implementation, firstly it reserves two dictionary values, $100 to indicate an error (This is written by the compression program and will make the executable abort.) and $101 to indicate the end of data. (If the program reaches the end of the data without encountering this it will also abort.) The compressed data is also prefixed with a dword giving the decompressed data size, so this can be compared with the output.&lt;br /&gt;
&lt;br /&gt;
This method is a typical separate dictionary approach. It starts with a dictionary of 256 9-bit codewords representing the 8-bit strings $00-$FF (Plus some special cases.) The dictionary is allowed to grow to 4096 entries. The following is the initial dictionary:&lt;br /&gt;
&lt;br /&gt;
        0000 - 00 (character)&lt;br /&gt;
        0001 - 01 (character)&lt;br /&gt;
            ...&lt;br /&gt;
        00FE - FE (character)&lt;br /&gt;
        00FF - FF (character)&lt;br /&gt;
        0100 - Reserved for errors...&lt;br /&gt;
        0101 - Reserved for end of compressed data...&lt;br /&gt;
        0102 - (not set)&lt;br /&gt;
        0103 - (not set)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It will be immediately noticed that 4096 entries cannot be represented by 9-bit codes but at the least by 12-bit codes. To further conserve space the length of the codewords is increased every time the dictionary grows too large. Thus when it reaches $01FF entries codewords become 10 bits long, at $03FF they are 11 bits and finally at $07FF 12 bits. At $0FFF entries the dictionary stops growing.&lt;br /&gt;
&lt;br /&gt;
The following data is taken from the EGALATCH file from Keen 1. Notice that the first six bytes are ignored. (The first four give the decompressed data size, the next two are an executable variable of unknown use.) The first few steps of decompression follows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    0000  80 D3 01 00  0C 00 00 40 - A0 70 31 E9  F8 F8 78 38&lt;br /&gt;
    0010  08 08 00 07  FC 39 FF 04 - 5E 41 E1 30  B3 C4 5A 2F&lt;br /&gt;
&lt;br /&gt;
The first code word encountered is 000000000 (First 9 bits) and thus outputs the string $00 (First dictionary entry.) This has set us up to step 4 and now things work slightly differently.&lt;br /&gt;
&lt;br /&gt;
The second code word is 100000010 (Next 9 bits) which is entry $102. Since this entry is NOT found in the dictionary yet, we will create this entry then output it. Entry $102 is created by taking the previous codeword&#039;s string adding to it the first byte of that string. In this case the previous codewrode&#039;s (0) string is $00. $00 + $00 is $00 $00 Entry $102 thus represents the string $00 $00&lt;br /&gt;
&lt;br /&gt;
The next code word is 100000011 which is entry $103, which again doesn&#039;t exist. Entry $103 is created just like with $102, except now since the previous codeword is $00 $00, entry $103 is $00 $00 $00&lt;br /&gt;
&lt;br /&gt;
The next code word is again $103, this IS found in the dictionary and is outputted ($00 $00 $00) however we now create dictionary entry $104 just like $103. (It is $00 $00 $00 $00)&lt;br /&gt;
&lt;br /&gt;
The next code word is $3B. It is outputted and entry $105 created ($00 $00 $00 $00 $3B) Note that now the previous codeword is $3B. This pattern continues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Integrated Dictionary Approach =&lt;br /&gt;
&lt;br /&gt;
In this approach the dictionary is the decompressed data itself. The codewords do not represent an entry in the dictionary structure, but rather directions in the decompressed code as to where a repeated string is located. That is a repeat string may well be represented by a codeword that states &#039;copy seven bytes from byte 132 in the decompressed data&#039;&lt;br /&gt;
&lt;br /&gt;
The advantage of this approach is that it doesn&#039;t require a separate construct for the dictionary and can just use the already decompressed data. The downside is that it will always need some method to distinguish literals and codewords, and, since codewords are nearly always of a fixed length there is an inherent limit both to how long the copied string can be and where it can be read from. this means that eventually the compression efficiency will level off and stop improving.&lt;br /&gt;
&lt;br /&gt;
There This is often called the &#039;sliding window&#039; and it represents the data that can be &#039;reached&#039; by the codewords. It is named as such because it is of a fixed length and &#039;slides&#039; along the output stream as it gets longer. The following features differ between implementations:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Differentiating codewords from literals. There must be a way to tell codewords apart from data that is just to be read and outputted. Sometimes this is integrated into the codewords themselves, but more often the &#039;flag&#039; precedes a codeword. The flag may indicate only codewords or both codewords and literals. (&#039;Following data is made of two codewords and six literals&#039;, etc.)&lt;br /&gt;
&lt;br /&gt;
* Codeword format. Most implementations use codewords of a fixed format that must encode both the length of data to copy and the location to copy it from. Codewords are usually two or four bytes long.&lt;br /&gt;
&lt;br /&gt;
* Zero point location. Different implementations use different places in the output as zero. If the start of the code is used as zero only the first x bytes of the output can be used as a reference. Most implementations use a more complex, but seldom less effective &#039;sliding window&#039;; the zero point is the start of the data until the data becomes too long at which point it moves forward so that the most recent x bytes of output can be used. It is also possible for zero to be the most recent byte with all locations being &#039;x bytes from the end&#039;, which also produces a sliding window. Finally it may be possible to have both negative and positive locations.&lt;br /&gt;
&lt;br /&gt;
* Sliding window. The nature of this is dictated by the format of the codewords. Common sizes are 1KB, 2KB or 4KB. The window will always be present, but it may not &#039;slide&#039; if the implementation uses a fixed location as the zero point.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== LZEXE ==&lt;br /&gt;
&lt;br /&gt;
Many vintage executables are compressed with the program LZEXE, interesting in that the compressed file contains its own decompressor, meaning that it is in essence a self-extracting archive. However the unique feature of LZEXE executables is that they extract the compressed data to memory and run it. To the user this is indistinguishable from the decompressed executable, though it takes slightly longer to start up and takes up much less space.&lt;br /&gt;
&lt;br /&gt;
[[UNLZEXE]] can be used to extract the decompressed executables from this which will run perfectly with other game files. It can be obtained here: http://www.dosclassics.com/download/198 It is currently unknown specifically how the LZW compression is implemented in this case, but with the source code for decompression is available.&lt;br /&gt;
&lt;br /&gt;
The LZEXE compression is similar to the SoftDisk Library Approach described below, but it uses UINT16LE values instead of byte values to store the flag bits and the sliding window has a size of 8192 (0x2000) bytes. Also, the flag bits have different meanings (you could argue that they are in fact Huffman codes):&lt;br /&gt;
&lt;br /&gt;
    1 -&amp;gt; copy 1 literal byte&lt;br /&gt;
   10 -&amp;gt; next two bytes contain length and distance&lt;br /&gt;
 0000 -&amp;gt; length is 2, next byte contains distance &lt;br /&gt;
 1000 -&amp;gt; length is 3, next byte contains distance &lt;br /&gt;
 0100 -&amp;gt; length is 4, next byte contains distance &lt;br /&gt;
 1100 -&amp;gt; length is 5, next byte contains distance &lt;br /&gt;
&lt;br /&gt;
The real distance value is always a signed 16 bit integer (you can use unsigned but then you have to bitwise-and the resulting index value with 0xFFFF). If the length is given by the flag bits/Huffman code, the real distance is &amp;lt;tt&amp;gt;b | 0xFF00&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;b - 256&amp;lt;/tt&amp;gt; where &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt; is the byte value read from the file. If the length value is not given, read the byte values &amp;lt;tt&amp;gt;b0&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;b1&amp;lt;/tt&amp;gt; and calculate length and distance like this:&lt;br /&gt;
&lt;br /&gt;
 length = (b1 mod 8)+2&lt;br /&gt;
 distance = b0 + (b1/8)*256 - 8192&lt;br /&gt;
or&lt;br /&gt;
 length = (b1 &amp;amp; 0x07)+2&lt;br /&gt;
 distance = b0 | ((b1 &amp;amp; 0xF8)&amp;lt;&amp;lt;5) | 0xE000&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt; value calculated from &amp;lt;tt&amp;gt;b1&amp;lt;/tt&amp;gt; is 2, this indicates that another byte value &amp;lt;tt&amp;gt;b2&amp;lt;/tt&amp;gt; must be read. Depending in the value of b2, one of three things can happen:&lt;br /&gt;
 b2 = 0:&lt;br /&gt;
    end of compressed data - stop decompressing&lt;br /&gt;
 b2 = 1:&lt;br /&gt;
    end of segment&lt;br /&gt;
    (decompressor may write contents of buffer to output)&lt;br /&gt;
    set length to 0 or jump to the part where the decompressor reads the next flag bits/Huffman code&lt;br /&gt;
 otherwise:&lt;br /&gt;
    set length to b2+1&lt;br /&gt;
&lt;br /&gt;
Now the decompressor must only add &amp;lt;tt&amp;gt;distance&amp;lt;/tt&amp;gt; to the current buffer index (since &amp;lt;tt&amp;gt;distance&amp;lt;/tt&amp;gt; is negative, the index goes backwards) and copy &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt; bytes from there to the current index:&lt;br /&gt;
&lt;br /&gt;
 WHILE length &amp;gt; 0&lt;br /&gt;
    buffer[index] = buffer[index+distance]&lt;br /&gt;
    index = index + 1&lt;br /&gt;
    length = length - 1&lt;br /&gt;
 END WHILE&lt;br /&gt;
&lt;br /&gt;
Please refer to the ULZEXE source code for further information.&lt;br /&gt;
&lt;br /&gt;
== SoftDisk Library Approach ==&lt;br /&gt;
&lt;br /&gt;
This is used as the first form of compression in the [[Softdisk Library Format]]. Flags are 1-byte long and divide the datastream into segments of eight &#039;values&#039; which can be either literals or codewords. Codewords are 2 bytes long, literals 1 byte. (Therefore there will be a flag byte every 8 to 16 bytes of data.) The value of each bit (In little endian) indicates whether a value will be a literal (1) or codeword (0) Thus a value of 199 (11000111 in binary) indicates three codewords, three literals and two codewords in that order. (Total of 13 bytes.)&lt;br /&gt;
&lt;br /&gt;
Literals are sequences that have never been seen in the datastream before, they cannot be compressed and are thus the same in the compressed and decompressed datastreams. (If the data is text they become quite obvious.) Any string less than 3 bytes long that has not been read before or cannot be pointed to (See below) will be stored as literals.&lt;br /&gt;
&lt;br /&gt;
Codewords are reference to data that has already been read. They are two bytes long, with the first 12 bits giving the location to read data from and the last 4 bits giving the length of data to read.&lt;br /&gt;
&lt;br /&gt;
The lower nybble (4 bits) of the second codeword byte holds the length of repeat data to read minus three. (This makes sense, the shortest sequence it makes sense to code is three bytes which can be given the value 0.) It will be immediately apparent that the maximum length of repeated data that can be stored as a codeword is 18 bytes.&lt;br /&gt;
&lt;br /&gt;
The high nybble of the second byte is multiplied by 16 then added to the first byte to give the location of the data to read in the &#039;sliding window&#039; minus 19. (This is due to the way the decompression is set up in memory.)&lt;br /&gt;
&lt;br /&gt;
It will be immediately obvious that the codewords can encode values between +-2048, or about 2KB. If the decompressed data is less than 2KB in size then zero is the start of the data, if it is larger than it is 2048 bytes from the data end.&lt;br /&gt;
&lt;br /&gt;
It will be noted that it is probable that the compressed datastream will not be perfectly divisible by flag bytes. In this case the unused bits are set to 0. The decompressor stops when the decompressed data size is equal to the value given in the chunk header. (If it runs out of data it will abort.)&lt;br /&gt;
&lt;br /&gt;
As a simple example the sentence &#039;I am Sam. Sam I am!&#039; will be compressed to:&lt;br /&gt;
&lt;br /&gt;
 FF				Flag byte, 8 literals follow&lt;br /&gt;
 49 20 61 6D 20 53 61 6D	&#039;I am Sam&#039; as literals&lt;br /&gt;
 2B				Flag byte, 2L, P, L, P, L 2Blanks ($2B = 43 = 00101011)&lt;br /&gt;
 2E 20				&#039; .&#039; as literals&lt;br /&gt;
 F2 F0				codeword, read 0 + 3 = 3 bytes from $FF2, or -14 + 19 = 5 in the data. This is &#039;Sam&#039;&lt;br /&gt;
 20				&#039; &#039; as literal&lt;br /&gt;
 ED F1				codeword, read 1 + 3 = 4 bytes from $FED or -19 + 19 = 1 in the data. This is &#039;I am&#039;&lt;br /&gt;
 21				&#039;!&#039; as literal&lt;br /&gt;
&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 Keen&#039;s LZW algorithm in its various implementations.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Keen 1-3 Implementation ==&lt;br /&gt;
&lt;br /&gt;
These segments f code work with the Keen 1-3 implementation only and will not for example decompress LZEXE compressed executables.&lt;br /&gt;
&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;
DECLARE FUNCTION READBITS% (FILE AS INTEGER, NUMBITS AS INTEGER)&lt;br /&gt;
DECLARE SUB LZWDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING)&lt;br /&gt;
DECLARE SUB LZWOUTPUT (FILE AS INTEGER, DIC AS INTEGER, CHAR AS INTEGER)&lt;br /&gt;
&#039;&lt;br /&gt;
&#039; KEEN1 Compatible LZW Decompressor (Lempel-Ziv-Welch)&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&lt;br /&gt;
&#039;&lt;br /&gt;
&#039;&lt;br /&gt;
&lt;br /&gt;
&#039; Allocate dictionary&lt;br /&gt;
DIM LZDIC(0 TO 4095) AS INTEGER&lt;br /&gt;
DIM LZCHR(0 TO 4095) AS INTEGER&lt;br /&gt;
&lt;br /&gt;
&#039; Test Function&lt;br /&gt;
LZWDECOMPRESS &amp;quot;EGALATCH.CK1&amp;quot;, &amp;quot;EGALATCH.DAT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SUB LZWDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING)&lt;br /&gt;
        SHARED LZDIC() AS INTEGER, LZCHR() AS INTEGER&lt;br /&gt;
        DIM INFILE AS INTEGER, OUTFILE AS INTEGER, I AS INTEGER&lt;br /&gt;
        DIM BITLEN AS INTEGER, CURPOS AS INTEGER&lt;br /&gt;
        DIM CW AS INTEGER, PW AS INTEGER, C AS INTEGER, P AS INTEGER&lt;br /&gt;
        DIM CHECK AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        &#039; Open files for input and output&lt;br /&gt;
        INFILE = FREEFILE&lt;br /&gt;
        OPEN INNAME FOR BINARY ACCESS READ AS INFILE&lt;br /&gt;
        OUTFILE = FREEFILE&lt;br /&gt;
        OPEN OUTNAME FOR BINARY ACCESS WRITE AS OUTFILE&lt;br /&gt;
        SEEK INFILE, 7&lt;br /&gt;
&lt;br /&gt;
       &lt;br /&gt;
        &#039; Fill dictionary with starting values&lt;br /&gt;
        FOR I = 0 TO 4095&lt;br /&gt;
                LZDIC(I) = -1&lt;br /&gt;
                IF I &amp;lt; 256 THEN&lt;br /&gt;
                        LZCHR(I) = I&lt;br /&gt;
                ELSE&lt;br /&gt;
                        LZCHR(I) = -1&lt;br /&gt;
                END IF&lt;br /&gt;
        NEXT I&lt;br /&gt;
&lt;br /&gt;
        &#039; Decompress input stream to output stream&lt;br /&gt;
        BITLEN = 9&lt;br /&gt;
        CURPOS = 258&lt;br /&gt;
        CW = READBITS(INFILE, BITLEN)&lt;br /&gt;
        LZWOUTPUT OUTFILE, LZDIC(CW), LZCHR(CW)&lt;br /&gt;
       &lt;br /&gt;
        WHILE CW &amp;lt;&amp;gt; &amp;amp;H100 AND CW &amp;lt;&amp;gt; &amp;amp;H101&lt;br /&gt;
                PW = CW&lt;br /&gt;
                CW = READBITS(INFILE, BITLEN)&lt;br /&gt;
                IF CW &amp;lt;&amp;gt; &amp;amp;H100 AND CW &amp;lt;&amp;gt; &amp;amp;H101 THEN&lt;br /&gt;
                        P = PW&lt;br /&gt;
                        CHECK = (LZCHR(CW) &amp;lt;&amp;gt; -1)&lt;br /&gt;
                       &lt;br /&gt;
                        IF CHECK THEN&lt;br /&gt;
                                TMP = CW&lt;br /&gt;
                        ELSE&lt;br /&gt;
                                TMP = PW&lt;br /&gt;
                        END IF&lt;br /&gt;
                        WHILE LZDIC(TMP) &amp;lt;&amp;gt; -1&lt;br /&gt;
                                TMP = LZDIC(TMP)&lt;br /&gt;
                        WEND&lt;br /&gt;
                        C = LZCHR(TMP)&lt;br /&gt;
                       &lt;br /&gt;
                        IF CHECK THEN&lt;br /&gt;
                                LZWOUTPUT OUTFILE, LZDIC(CW), LZCHR(CW)&lt;br /&gt;
                        ELSE&lt;br /&gt;
                                LZWOUTPUT OUTFILE, P, C&lt;br /&gt;
                        END IF&lt;br /&gt;
                       &lt;br /&gt;
                        IF CURPOS &amp;lt; 4096 THEN&lt;br /&gt;
                                LZDIC(CURPOS) = P&lt;br /&gt;
                                LZCHR(CURPOS) = C&lt;br /&gt;
                                CURPOS = CURPOS + 1&lt;br /&gt;
                                IF CURPOS = (2 ^ BITLEN - 1) AND BITLEN &amp;lt; 12 THEN&lt;br /&gt;
                                        BITLEN = BITLEN + 1&lt;br /&gt;
                                END IF&lt;br /&gt;
                        END IF&lt;br /&gt;
&lt;br /&gt;
                END IF&lt;br /&gt;
        WEND&lt;br /&gt;
       &lt;br /&gt;
        &#039; Close files&lt;br /&gt;
        CLOSE OUTFILE&lt;br /&gt;
        CLOSE INFILE&lt;br /&gt;
END SUB&lt;br /&gt;
&lt;br /&gt;
SUB LZWOUTPUT (FILE AS INTEGER, DIC AS INTEGER, CHAR AS INTEGER)&lt;br /&gt;
        SHARED LZDIC() AS INTEGER, LZCHR() AS INTEGER&lt;br /&gt;
        DIM LZSTK(0 TO 127) AS STRING * 1&lt;br /&gt;
        DIM X AS INTEGER, SP AS INTEGER&lt;br /&gt;
        DIM LDIC AS INTEGER, LCHAR AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        LCHAR = CHAR&lt;br /&gt;
        LDIC = DIC&lt;br /&gt;
        SP = 0&lt;br /&gt;
        X = 1&lt;br /&gt;
&lt;br /&gt;
        DO&lt;br /&gt;
                IF SP &amp;gt;= 128 THEN&lt;br /&gt;
                        PRINT &amp;quot;LZW: Stack Overflow!&amp;quot;&lt;br /&gt;
                        END&lt;br /&gt;
                END IF&lt;br /&gt;
                LZSTK(SP) = CHR$(LCHAR)&lt;br /&gt;
                SP = SP + 1&lt;br /&gt;
                IF LDIC &amp;lt;&amp;gt; -1 THEN&lt;br /&gt;
                        LCHAR = LZCHR(LDIC)&lt;br /&gt;
                        LDIC = LZDIC(LDIC)&lt;br /&gt;
                ELSE&lt;br /&gt;
                        X = 0&lt;br /&gt;
                END IF&lt;br /&gt;
        LOOP WHILE X&lt;br /&gt;
       &lt;br /&gt;
        WHILE SP &amp;lt;&amp;gt; 0&lt;br /&gt;
                SP = SP - 1&lt;br /&gt;
                PUT FILE, , LZSTK(SP)&lt;br /&gt;
        WEND&lt;br /&gt;
END SUB&lt;br /&gt;
&lt;br /&gt;
FUNCTION READBITS% (FILE AS INTEGER, NUMBITS AS INTEGER)&lt;br /&gt;
        STATIC BITDAT AS STRING * 1, BITPOS AS INTEGER&lt;br /&gt;
        DIM BITVAL AS INTEGER, BIT AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        BITVAL = 0&lt;br /&gt;
        FOR BIT = (NUMBITS - 1) TO 0 STEP -1&lt;br /&gt;
                IF BITPOS = 0 THEN&lt;br /&gt;
                        GET FILE, , BITDAT&lt;br /&gt;
                        BITPOS = 7&lt;br /&gt;
                ELSE&lt;br /&gt;
                        BITPOS = BITPOS - 1&lt;br /&gt;
                END IF&lt;br /&gt;
                IF ASC(BITDAT) AND 2 ^ BITPOS THEN&lt;br /&gt;
                        BITVAL = BITVAL OR 2 ^ BIT&lt;br /&gt;
                END IF&lt;br /&gt;
        NEXT BIT&lt;br /&gt;
&lt;br /&gt;
        READBITS% = BITVAL&lt;br /&gt;
END FUNCTION&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== FreeBasic ===&lt;br /&gt;
&lt;br /&gt;
This code does not suffer from the 64K memory limit imposed by QuickBasic and so is less efficient, but runs faster. It can be compiled with FreeBasic compiler using the -lang=qb switch. Aside from memory concerns, all code here is compatible with QuickBasic.&lt;br /&gt;
&lt;br /&gt;
The code before the subroutine is used to make a string containing the bit expansion of all values from 0 to 255. The subroutine takes a filename, reads the entire file into memory then expands each bit of data to a byte using the aforesaid string as Basic cannot deal with bits directly. cw$ is codeword, pw$ is the previous codeword, lun is the lowest dictionary entry that is empty, p is the location in the compressed data stream and bl is the length of codes in bits (Starting at nine bits increasing to 12)&lt;br /&gt;
&lt;br /&gt;
The dictionary is set before decompression. The first 258 are the starting dictionary, the remainder are cleared. (It is vital to reset the dictionary for each file) An error occurs if entry 256 is found in the data, &#039;distrupt&#039; is printed when the newest dictionary entry is not the lowest possible entry (This shouldn&#039;t happen but is possible.) Decompression ends at encountering entry 257, or when there is no more data to read.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;qbasic&amp;quot;&amp;gt;&lt;br /&gt;
DECLARE SUB LZWDEC (lfn AS STRING)&lt;br /&gt;
&lt;br /&gt;
x$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 0 TO 255&lt;br /&gt;
 IF (l AND 128) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 64) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 32) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 16) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 8) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 4) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 2) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 1) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
NEXT l&lt;br /&gt;
LZEDEC &amp;quot;EGALATCH.CK1&amp;quot;&lt;br /&gt;
END&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;_________________________________________________&lt;br /&gt;
SUB LZWDEC (lfn AS STRING) &#039; Decompress LZW data&lt;br /&gt;
&#039;_________________________________________________&lt;br /&gt;
DIM lzw(0 TO 4095) AS STRING&lt;br /&gt;
PRINT lfn; &amp;quot; is LZW compressed, decompressing...&amp;quot;;&lt;br /&gt;
OPEN folder + lfn FOR BINARY AS #9&lt;br /&gt;
y$ = SPACE$(LOF(9))&lt;br /&gt;
GET #9, 1, y$&lt;br /&gt;
CLOSE #9&lt;br /&gt;
z$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 7 TO LEN(y$)&lt;br /&gt;
 z$ = z$ + MID$(x$, (ASC(MID$(y$, l, 1)) * 8) + 1, 8)&lt;br /&gt;
NEXT l&lt;br /&gt;
&lt;br /&gt;
bl = 9&lt;br /&gt;
lun = 258&lt;br /&gt;
p = 1&lt;br /&gt;
cw$ = &amp;quot;&amp;quot;&lt;br /&gt;
y$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 0 TO 4095&lt;br /&gt;
 IF l &amp;lt; 256 THEN lzw(l) = CHR$(l) ELSE lzw(l) = &amp;quot;&amp;quot;&lt;br /&gt;
NEXT l&lt;br /&gt;
DO&lt;br /&gt;
 IF lun = 511 THEN bl = 10&lt;br /&gt;
 IF lun = 1023 THEN bl = 11&lt;br /&gt;
 IF lun = 2047 THEN bl = 12&lt;br /&gt;
 pw$ = cw$&lt;br /&gt;
 u$ = MID$(z$, p, bl)&lt;br /&gt;
 p = p + bl&lt;br /&gt;
 y = 0&lt;br /&gt;
 FOR l = 1 TO bl&lt;br /&gt;
  IF MID$(u$, bl - l + 1, 1) = &amp;quot;1&amp;quot; THEN y = y + (2 ^ (l - 1))&lt;br /&gt;
 NEXT l&lt;br /&gt;
 IF y = 256 THEN&lt;br /&gt;
  PRINT &amp;quot;LZW error in Keen data!&amp;quot;&lt;br /&gt;
  OPEN &amp;quot;ERROR.DAT&amp;quot; FOR OUTPUT AS #9&lt;br /&gt;
  PRINT #9, y$;&lt;br /&gt;
  CLOSE&lt;br /&gt;
  END&lt;br /&gt;
 END IF&lt;br /&gt;
 IF y = 257 THEN EXIT DO&lt;br /&gt;
 IF cw$ = &amp;quot;&amp;quot; THEN&lt;br /&gt;
  cw$ = lzw(y)&lt;br /&gt;
  y$ = y$ + cw$&lt;br /&gt;
 ELSE&lt;br /&gt;
  IF lun &amp;lt; 4096 THEN&lt;br /&gt;
   IF lzw(y) = &amp;quot;&amp;quot; THEN&lt;br /&gt;
    cw$ = pw$ + LEFT$(pw$, 1)&lt;br /&gt;
    lzw(y) = cw$&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
    IF y &amp;lt;&amp;gt; lun THEN PRINT &amp;quot;Disrupt!&amp;quot;&lt;br /&gt;
    lun = y + 1&lt;br /&gt;
   ELSE&lt;br /&gt;
    cw$ = lzw(y)&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
    lzw(lun) = pw$ + LEFT$(cw$, 1)&lt;br /&gt;
    lun = lun + 1&lt;br /&gt;
   END IF&lt;br /&gt;
  ELSE&lt;br /&gt;
   IF lzw(y) = &amp;quot;&amp;quot; THEN&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
   ELSE&lt;br /&gt;
    cw$ = lzw(y)&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
   END IF&lt;br /&gt;
  END IF&lt;br /&gt;
 END IF&lt;br /&gt;
LOOP WHILE p &amp;lt; LEN(z$)&lt;br /&gt;
IF y = 257 THEN PRINT &amp;quot;done&amp;quot; ELSE PRINT &amp;quot;out of data.&amp;quot;&lt;br /&gt;
OPEN folder + LEFT$(lfn, 4) + extq FOR OUTPUT AS #9&lt;br /&gt;
PRINT #9, y$;&lt;br /&gt;
CLOSE #9&lt;br /&gt;
END SUB&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Visual Basic .NET ===&lt;br /&gt;
&lt;br /&gt;
This implementation uses high-level elements such as lambdas, anonymous arrays, and strict types. It must be compiled for the Microsoft .NET Framework v4.5 in Visual Studio 2012. It has the advantages of running in non-DosBox Windows and using .NET streams for simple reusability. It can also be used for higher-bit LZW.&lt;br /&gt;
&lt;br /&gt;
==== Decompression ====&lt;br /&gt;
&lt;br /&gt;
Decompressing is very fast.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vbnet&amp;quot;&amp;gt;    Sub DecompressLZW(Data As IO.Stream, MaxBits As Byte, Output As IO.Stream)&lt;br /&gt;
        &#039; This source is by Fleexy and is in the public domain. If used, please note it as such.&lt;br /&gt;
        Dim dict As New List(Of Byte())&lt;br /&gt;
        For x = 0 To 255&lt;br /&gt;
            dict.Add({x})&lt;br /&gt;
        Next&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        dict.Add(Nothing)&lt;br /&gt;
        Dim usebits As Byte = 9&lt;br /&gt;
        Dim bpos As Long&lt;br /&gt;
        Dim bits As New List(Of Byte)&lt;br /&gt;
        Do Until Data.Position = Data.Length&lt;br /&gt;
            Dim b, ub As Byte&lt;br /&gt;
            b = Data.ReadByte&lt;br /&gt;
            ub = b&lt;br /&gt;
            For x = 7 To 0 Step -1&lt;br /&gt;
                If ub - (2 ^ x) &amp;gt;= 0 Then&lt;br /&gt;
                    ub -= (2 ^ x)&lt;br /&gt;
                    bits.Add(1)&lt;br /&gt;
                Else&lt;br /&gt;
                    bits.Add(0)&lt;br /&gt;
                End If&lt;br /&gt;
            Next&lt;br /&gt;
        Loop&lt;br /&gt;
        Dim GetCode = Function() As UInteger&lt;br /&gt;
                          Dim u As UInteger&lt;br /&gt;
                          For x = usebits To 1 Step -1&lt;br /&gt;
                              If bits(bpos) = 1 Then u += (2 ^ (x - 1))&lt;br /&gt;
                              bpos += 1&lt;br /&gt;
                          Next&lt;br /&gt;
                          Return u&lt;br /&gt;
                      End Function&lt;br /&gt;
        Dim OutputCode = Sub(DecompData As Byte())&lt;br /&gt;
                             Dim n As UInteger = DecompData.Length&lt;br /&gt;
                             Output.Write(DecompData, 0, n)&lt;br /&gt;
                         End Sub&lt;br /&gt;
        Dim AddToDict = Sub(Entry As Byte())&lt;br /&gt;
                            If dict.Count &amp;lt; (2 ^ MaxBits) Then&lt;br /&gt;
                                dict.Add(Entry)&lt;br /&gt;
                                If dict.Count = (2 ^ usebits) - 1 Then usebits = Math.Min(usebits + 1, MaxBits)&lt;br /&gt;
                            End If&lt;br /&gt;
                        End Sub&lt;br /&gt;
        Dim fcode As UInteger = GetCode()&lt;br /&gt;
        Dim match As Byte() = dict(fcode)&lt;br /&gt;
        OutputCode(match)&lt;br /&gt;
        Do&lt;br /&gt;
            Dim ncode As UInteger = GetCode()&lt;br /&gt;
            If ncode = 257 Then Exit Do&lt;br /&gt;
            If ncode = 256 Then Throw New Exception&lt;br /&gt;
            Dim nmatch As Byte()&lt;br /&gt;
            If ncode &amp;lt; dict.Count Then&lt;br /&gt;
                nmatch = dict(ncode)&lt;br /&gt;
            Else&lt;br /&gt;
                nmatch = match.Concat({match(0)}).ToArray&lt;br /&gt;
            End If&lt;br /&gt;
            OutputCode(nmatch)&lt;br /&gt;
            AddToDict(match.Concat({nmatch(0)}).ToArray)&lt;br /&gt;
            match = nmatch&lt;br /&gt;
        Loop&lt;br /&gt;
    End Sub&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Compression ====&lt;br /&gt;
&lt;br /&gt;
Compression is more difficult; consulting the dictionary for a byte array takes more time. The speed of this algorithm may be unacceptable.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vbnet&amp;quot;&amp;gt;    Sub CompressLZW(Data As IO.Stream, MaxBits As Byte, Output As IO.Stream)&lt;br /&gt;
        &#039; This source is by Fleexy and is in the public domain.&lt;br /&gt;
        Dim bits As New List(Of Byte)&lt;br /&gt;
        Dim dict As New List(Of Byte())&lt;br /&gt;
        For x = 0 To 255&lt;br /&gt;
            dict.Add({x})&lt;br /&gt;
        Next&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        Dim usebits As Byte = 9&lt;br /&gt;
        Dim PutCode = Sub(Code As UInteger)&lt;br /&gt;
                          For x = usebits To 1 Step -1&lt;br /&gt;
                              If Code - (2 ^ (x - 1)) &amp;gt;= 0 Then&lt;br /&gt;
                                  Code -= (2 ^ (x - 1))&lt;br /&gt;
                                  bits.Add(1)&lt;br /&gt;
                              Else&lt;br /&gt;
                                  bits.Add(0)&lt;br /&gt;
                              End If&lt;br /&gt;
                          Next&lt;br /&gt;
                      End Sub&lt;br /&gt;
        Dim AddToDict = Function(Entry As Byte()) As Boolean&lt;br /&gt;
                            If dict.Count &amp;lt; 2 ^ MaxBits Then&lt;br /&gt;
                                dict.Add(Entry)&lt;br /&gt;
                                If dict.Count = 2 ^ usebits Then usebits = Math.Min(usebits + 1, MaxBits)&lt;br /&gt;
                                Return True&lt;br /&gt;
                            Else&lt;br /&gt;
                                Return False&lt;br /&gt;
                            End If&lt;br /&gt;
                        End Function&lt;br /&gt;
        Dim FindCode = Function(Bytes As Byte()) As UInteger&lt;br /&gt;
                           For x = 1 To dict.Count&lt;br /&gt;
                               If dict(x - 1).Count = Bytes.Count Then&lt;br /&gt;
                                   If dict(x - 1).SequenceEqual(Bytes) Then Return x - 1&lt;br /&gt;
                               End If&lt;br /&gt;
                           Next&lt;br /&gt;
                           Throw New NotFiniteNumberException&lt;br /&gt;
                       End Function&lt;br /&gt;
        Dim DictContains = Function(Bytes As Byte()) As Boolean&lt;br /&gt;
                               For x = 1 To dict.Count&lt;br /&gt;
                                   If dict(x - 1).Length = Bytes.Length Then&lt;br /&gt;
                                       If dict(x - 1).SequenceEqual(Bytes) Then Return True&lt;br /&gt;
                                   End If&lt;br /&gt;
                               Next&lt;br /&gt;
                               Return False&lt;br /&gt;
                           End Function&lt;br /&gt;
        Dim match As Byte() = {}&lt;br /&gt;
        Do Until Data.Position = Data.Length&lt;br /&gt;
            Dim nbyte As Byte = Data.ReadByte&lt;br /&gt;
            Dim nmatch As Byte() = match.Concat({nbyte}).ToArray&lt;br /&gt;
            If DictContains(nmatch) Then&lt;br /&gt;
                match = nmatch&lt;br /&gt;
            Else&lt;br /&gt;
                PutCode(FindCode(match))&lt;br /&gt;
                AddToDict(nmatch)&lt;br /&gt;
                match = {nbyte}&lt;br /&gt;
            End If&lt;br /&gt;
        Loop&lt;br /&gt;
        PutCode(FindCode(match))&lt;br /&gt;
        PutCode(257)&lt;br /&gt;
        Do Until bits.LongCount Mod 8L = 0L&lt;br /&gt;
            bits.Add(0)&lt;br /&gt;
        Loop&lt;br /&gt;
        For x = 1 To CInt(bits.LongCount / 8L)&lt;br /&gt;
            Dim b As Byte = 0&lt;br /&gt;
            For y = 0 To 7&lt;br /&gt;
                b += bits((x - 1) * 8 + y) * (2 ^ (7 - y))&lt;br /&gt;
            Next&lt;br /&gt;
            Output.WriteByte(b)&lt;br /&gt;
        Next&lt;br /&gt;
    End Sub&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander Keen 1-3]]&lt;br /&gt;
[[Category:File Formats]]&lt;br /&gt;
[[Category:Compressed Files]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
	<entry>
		<id>https://moddingwiki.shikadi.net/w/index.php?title=LZW_Compression&amp;diff=5085</id>
		<title>LZW Compression</title>
		<link rel="alternate" type="text/html" href="https://moddingwiki.shikadi.net/w/index.php?title=LZW_Compression&amp;diff=5085"/>
		<updated>2013-12-31T22:40:31Z</updated>

		<summary type="html">&lt;p&gt;Fleexy: Added Keen LZW implementation in VB.NET&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;LZW compression is a common form of compression used in some early games to compress data and by most early games to compress their executables. It is notable in being one of the first compression methods to not compress on the byte level (Along with [[Huffman Compression]]) and for its efficiency.&lt;br /&gt;
&lt;br /&gt;
The basic concept for LZW is universal, though the implementations differ. In essence it involves replacing data strings that have been encountered before with references to already decompressed data. (Known as a &#039;dictionary&#039;) This can be done in a number of ways, the two main approaches differing on whether the dictionary is separate or integrated&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Separate Dictionary Approach =&lt;br /&gt;
&lt;br /&gt;
In this approach the dictionary is separate from the data being decompressed, that is it is stored in a separate location in memory. In this it behaves more like one would expect a dictionary to work; when a codeword is found in the data, it is looked up in the dictionary and the corresponding string copied to output. (As an example dictionary entry 42 could represent the string &#039;life&#039;, thus whenever the code &#039;42&#039; is encountered the string &#039;life&#039; is added to the decompressed data.)&lt;br /&gt;
&lt;br /&gt;
The advantage of this method is that the efficiency of compression increases as the amount of data to compress increases. The following points differ between implementations:&lt;br /&gt;
&lt;br /&gt;
* The initial dictionary. Just how large the initial dictionary is varies. Some implementations start with no dictioanry at all, others set a number of entries, usually 255, covering all possible 1-byte values.&lt;br /&gt;
&lt;br /&gt;
* The maximum size of the dictionary. Many older implementations with less resources were forced to cap the dictionary at a certain size, usually a power of two entries long. (512, 1024...) Unlimited implementations are rare as modern methods (e.g. the DEFLATE algorithm.)  usually rely on several compression methods at once. Sometimes the dictionary is &#039;reset&#039; when it reaches too large a size.&lt;br /&gt;
&lt;br /&gt;
* Whether the codestream is made partly or entirely of codewords. Often the compressed data is made entirely of codewords, even non-repeating strings, which means that initially compression can sometimes be rather poor. Other implementations use codeowords only for repeating strings. Differences in how codewords vs literal are indicated and how dictionaries are built up may occur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Decoding ==&lt;br /&gt;
&lt;br /&gt;
This is a general decoding algorithm for separate dictionary LZW. It will need to be altered slightly when dealing with different implementations. Notably it assumes that the codestream is composed entirely of codewords and that the dictionary can keep growing indefinitely.&lt;br /&gt;
&lt;br /&gt;
    1   At the start the dictionary contains all possible roots;&lt;br /&gt;
    2   cW := the first code word in the codestream (it denotes a root);&lt;br /&gt;
    3   output the string.cW to the charstream;&lt;br /&gt;
    4   pW := cW;&lt;br /&gt;
    5   cW := next code word in the codestream;&lt;br /&gt;
    6   Is the string.cW present in the dictionary?&lt;br /&gt;
            a   if it is,&lt;br /&gt;
                    i   output the string.cW to the charstream;&lt;br /&gt;
                    ii  P := string.pW;&lt;br /&gt;
                    iii C := the first character of the string.cW;&lt;br /&gt;
                    iv  add the string P+C to the dictionary;&lt;br /&gt;
            b   if not,&lt;br /&gt;
                    i   P := string.pW;&lt;br /&gt;
                    ii  C := the first character of the string.pW;&lt;br /&gt;
                    iii output the string P+C to the charstream&lt;br /&gt;
                    iv  add the string P+C to the dictionary (now it corresponds to the cW);&lt;br /&gt;
    7   Are there more code words in the codestream?&lt;br /&gt;
            a   if yes, go back to step 4;&lt;br /&gt;
            b   if not, END.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== [[Commander Keen 1-3|Commander Keen 1-3 LZW]] ==&lt;br /&gt;
&lt;br /&gt;
In [[Commander Keen 1-3]] LZW is used to compress the &amp;lt;tt&amp;gt;EGALATCH&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;EGASPRIT&amp;lt;/tt&amp;gt; files in episode 1 (It can also be used in episodes 2 and 3, but isn&#039;t.) The game uses two error-checking methods in this implementation, firstly it reserves two dictionary values, $100 to indicate an error (This is written by the compression program and will make the executable abort.) and $101 to indicate the end of data. (If the program reaches the end of the data without encountering this it will also abort.) The compressed data is also prefixed with a dword giving the decompressed data size, so this can be compared with the output.&lt;br /&gt;
&lt;br /&gt;
This method is a typical separate dictionary approach. It starts with a dictionary of 256 9-bit codewords representing the 8-bit strings $00-$FF (Plus some special cases.) The dictionary is allowed to grow to 4096 entries. The following is the initial dictionary:&lt;br /&gt;
&lt;br /&gt;
        0000 - 00 (character)&lt;br /&gt;
        0001 - 01 (character)&lt;br /&gt;
            ...&lt;br /&gt;
        00FE - FE (character)&lt;br /&gt;
        00FF - FF (character)&lt;br /&gt;
        0100 - Reserved for errors...&lt;br /&gt;
        0101 - Reserved for end of compressed data...&lt;br /&gt;
        0102 - (not set)&lt;br /&gt;
        0103 - (not set)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It will be immediately noticed that 4096 entries cannot be represented by 9-bit codes but at the least by 12-bit codes. To further conserve space the length of the codewords is increased every time the dictionary grows too large. Thus when it reaches $01FF entries codewords become 10 bits long, at $03FF they are 11 bits and finally at $07FF 12 bits. At $0FFF entries the dictionary stops growing.&lt;br /&gt;
&lt;br /&gt;
The following data is taken from the EGALATCH file from Keen 1. Notice that the first six bytes are ignored. (The first four give the decompressed data size, the next two are an executable variable of unknown use.) The first few steps of decompression follows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    0000  80 D3 01 00  0C 00 00 40 - A0 70 31 E9  F8 F8 78 38&lt;br /&gt;
    0010  08 08 00 07  FC 39 FF 04 - 5E 41 E1 30  B3 C4 5A 2F&lt;br /&gt;
&lt;br /&gt;
The first code word encountered is 000000000 (First 9 bits) and thus outputs the string $00 (First dictionary entry.) This has set us up to step 4 and now things work slightly differently.&lt;br /&gt;
&lt;br /&gt;
The second code word is 100000010 (Next 9 bits) which is entry $102. Since this entry is NOT found in the dictionary yet, we will create this entry then output it. Entry $102 is created by taking the previous codeword&#039;s string adding to it the first byte of that string. In this case the previous codewrode&#039;s (0) string is $00. $00 + $00 is $00 $00 Entry $102 thus represents the string $00 $00&lt;br /&gt;
&lt;br /&gt;
The next code word is 100000011 which is entry $103, which again doesn&#039;t exist. Entry $103 is created just like with $102, except now since the previous codeword is $00 $00, entry $103 is $00 $00 $00&lt;br /&gt;
&lt;br /&gt;
The next code word is again $103, this IS found in the dictionary and is outputted ($00 $00 $00) however we now create dictionary entry $104 just like $103. (It is $00 $00 $00 $00)&lt;br /&gt;
&lt;br /&gt;
The next code word is $3B. It is outputted and entry $105 created ($00 $00 $00 $00 $3B) Note that now the previous codeword is $3B. This pattern continues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Integrated Dictionary Approach =&lt;br /&gt;
&lt;br /&gt;
In this approach the dictionary is the decompressed data itself. The codewords do not represent an entry in the dictionary structure, but rather directions in the decompressed code as to where a repeated string is located. That is a repeat string may well be represented by a codeword that states &#039;copy seven bytes from byte 132 in the decompressed data&#039;&lt;br /&gt;
&lt;br /&gt;
The advantage of this approach is that it doesn&#039;t require a separate construct for the dictionary and can just use the already decompressed data. The downside is that it will always need some method to distinguish literals and codewords, and, since codewords are nearly always of a fixed length there is an inherent limit both to how long the copied string can be and where it can be read from. this means that eventually the compression efficiency will level off and stop improving.&lt;br /&gt;
&lt;br /&gt;
There This is often called the &#039;sliding window&#039; and it represents the data that can be &#039;reached&#039; by the codewords. It is named as such because it is of a fixed length and &#039;slides&#039; along the output stream as it gets longer. The following features differ between implementations:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Differentiating codewords from literals. There must be a way to tell codewords apart from data that is just to be read and outputted. Sometimes this is integrated into the codewords themselves, but more often the &#039;flag&#039; precedes a codeword. The flag may indicate only codewords or both codewords and literals. (&#039;Following data is made of two codewords and six literals&#039;, etc.)&lt;br /&gt;
&lt;br /&gt;
* Codeword format. Most implementations use codewords of a fixed format that must encode both the length of data to copy and the location to copy it from. Codewords are usually two or four bytes long.&lt;br /&gt;
&lt;br /&gt;
* Zero point location. Different implementations use different places in the output as zero. If the start of the code is used as zero only the first x bytes of the output can be used as a reference. Most implementations use a more complex, but seldom less effective &#039;sliding window&#039;; the zero point is the start of the data until the data becomes too long at which point it moves forward so that the most recent x bytes of output can be used. It is also possible for zero to be the most recent byte with all locations being &#039;x bytes from the end&#039;, which also produces a sliding window. Finally it may be possible to have both negative and positive locations.&lt;br /&gt;
&lt;br /&gt;
* Sliding window. The nature of this is dictated by the format of the codewords. Common sizes are 1KB, 2KB or 4KB. The window will always be present, but it may not &#039;slide&#039; if the implementation uses a fixed location as the zero point.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== LZEXE ==&lt;br /&gt;
&lt;br /&gt;
Many vintage executables are compressed with the program LZEXE, interesting in that the compressed file contains its own decompressor, meaning that it is in essence a self-extracting archive. However the unique feature of LZEXE executables is that they extract the compressed data to memory and run it. To the user this is indistinguishable from the decompressed executable, though it takes slightly longer to start up and takes up much less space.&lt;br /&gt;
&lt;br /&gt;
[[UNLZEXE]] can be used to extract the decompressed executables from this which will run perfectly with other game files. It can be obtained here: http://www.dosclassics.com/download/198 It is currently unknown specifically how the LZW compression is implemented in this case, but with the source code for decompression is available.&lt;br /&gt;
&lt;br /&gt;
The LZEXE compression is similar to the SoftDisk Library Approach described below, but it uses UINT16LE values instead of byte values to store the flag bits and the sliding window has a size of 8192 (0x2000) bytes. Also, the flag bits have different meanings (you could argue that they are in fact Huffman codes):&lt;br /&gt;
&lt;br /&gt;
    1 -&amp;gt; copy 1 literal byte&lt;br /&gt;
   10 -&amp;gt; next two bytes contain length and distance&lt;br /&gt;
 0000 -&amp;gt; length is 2, next byte contains distance &lt;br /&gt;
 1000 -&amp;gt; length is 3, next byte contains distance &lt;br /&gt;
 0100 -&amp;gt; length is 4, next byte contains distance &lt;br /&gt;
 1100 -&amp;gt; length is 5, next byte contains distance &lt;br /&gt;
&lt;br /&gt;
The real distance value is always a signed 16 bit integer (you can use unsigned but then you have to bitwise-and the resulting index value with 0xFFFF). If the length is given by the flag bits/Huffman code, the real distance is &amp;lt;tt&amp;gt;b | 0xFF00&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;b - 256&amp;lt;/tt&amp;gt; where &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt; is the byte value read from the file. If the length value is not given, read the byte values &amp;lt;tt&amp;gt;b0&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;b1&amp;lt;/tt&amp;gt; and calculate length and distance like this:&lt;br /&gt;
&lt;br /&gt;
 length = (b1 mod 8)+2&lt;br /&gt;
 distance = b0 + (b1/8)*256 - 8192&lt;br /&gt;
or&lt;br /&gt;
 length = (b1 &amp;amp; 0x07)+2&lt;br /&gt;
 distance = b0 | ((b1 &amp;amp; 0xF8)&amp;lt;&amp;lt;5) | 0xE000&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt; value calculated from &amp;lt;tt&amp;gt;b1&amp;lt;/tt&amp;gt; is 2, this indicates that another byte value &amp;lt;tt&amp;gt;b2&amp;lt;/tt&amp;gt; must be read. Depending in the value of b2, one of three things can happen:&lt;br /&gt;
 b2 = 0:&lt;br /&gt;
    end of compressed data - stop decompressing&lt;br /&gt;
 b2 = 1:&lt;br /&gt;
    end of segment&lt;br /&gt;
    (decompressor may write contents of buffer to output)&lt;br /&gt;
    set length to 0 or jump to the part where the decompressor reads the next flag bits/Huffman code&lt;br /&gt;
 otherwise:&lt;br /&gt;
    set length to b2+1&lt;br /&gt;
&lt;br /&gt;
Now the decompressor must only add &amp;lt;tt&amp;gt;distance&amp;lt;/tt&amp;gt; to the current buffer index (since &amp;lt;tt&amp;gt;distance&amp;lt;/tt&amp;gt; is negative, the index goes backwards) and copy &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt; bytes from there to the current index:&lt;br /&gt;
&lt;br /&gt;
 WHILE length &amp;gt; 0&lt;br /&gt;
    buffer[index] = buffer[index+distance]&lt;br /&gt;
    index = index + 1&lt;br /&gt;
    length = length - 1&lt;br /&gt;
 END WHILE&lt;br /&gt;
&lt;br /&gt;
Please refer to the ULZEXE source code for further information.&lt;br /&gt;
&lt;br /&gt;
== SoftDisk Library Approach ==&lt;br /&gt;
&lt;br /&gt;
This is used as the first form of compression in the [[Softdisk Library Format]]. Flags are 1-byte long and divide the datastream into segments of eight &#039;values&#039; which can be either literals or codewords. Codewords are 2 bytes long, literals 1 byte. (Therefore there will be a flag byte every 8 to 16 bytes of data.) The value of each bit (In little endian) indicates whether a value will be a literal (1) or codeword (0) Thus a value of 199 (11000111 in binary) indicates three codewords, three literals and two codewords in that order. (Total of 13 bytes.)&lt;br /&gt;
&lt;br /&gt;
Literals are sequences that have never been seen in the datastream before, they cannot be compressed and are thus the same in the compressed and decompressed datastreams. (If the data is text they become quite obvious.) Any string less than 3 bytes long that has not been read before or cannot be pointed to (See below) will be stored as literals.&lt;br /&gt;
&lt;br /&gt;
Codewords are reference to data that has already been read. They are two bytes long, with the first 12 bits giving the location to read data from and the last 4 bits giving the length of data to read.&lt;br /&gt;
&lt;br /&gt;
The lower nybble (4 bits) of the second codeword byte holds the length of repeat data to read minus three. (This makes sense, the shortest sequence it makes sense to code is three bytes which can be given the value 0.) It will be immediately apparent that the maximum length of repeated data that can be stored as a codeword is 18 bytes.&lt;br /&gt;
&lt;br /&gt;
The high nybble of the second byte is multiplied by 16 then added to the first byte to give the location of the data to read in the &#039;sliding window&#039; minus 19. (This is due to the way the decompression is set up in memory.)&lt;br /&gt;
&lt;br /&gt;
It will be immediately obvious that the codewords can encode values between +-2048, or about 2KB. If the decompressed data is less than 2KB in size then zero is the start of the data, if it is larger than it is 2048 bytes from the data end.&lt;br /&gt;
&lt;br /&gt;
It will be noted that it is probable that the compressed datastream will not be perfectly divisible by flag bytes. In this case the unused bits are set to 0. The decompressor stops when the decompressed data size is equal to the value given in the chunk header. (If it runs out of data it will abort.)&lt;br /&gt;
&lt;br /&gt;
As a simple example the sentence &#039;I am Sam. Sam I am!&#039; will be compressed to:&lt;br /&gt;
&lt;br /&gt;
 FF				Flag byte, 8 literals follow&lt;br /&gt;
 49 20 61 6D 20 53 61 6D	&#039;I am Sam&#039; as literals&lt;br /&gt;
 2B				Flag byte, 2L, P, L, P, L 2Blanks ($2B = 43 = 00101011)&lt;br /&gt;
 2E 20				&#039; .&#039; as literals&lt;br /&gt;
 F2 F0				codeword, read 0 + 3 = 3 bytes from $FF2, or -14 + 19 = 5 in the data. This is &#039;Sam&#039;&lt;br /&gt;
 20				&#039; &#039; as literal&lt;br /&gt;
 ED F1				codeword, read 1 + 3 = 4 bytes from $FED or -19 + 19 = 1 in the data. This is &#039;I am&#039;&lt;br /&gt;
 21				&#039;!&#039; as literal&lt;br /&gt;
&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 Keen&#039;s LZW algorithm in its various implementations.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Keen 1-3 Implementation ==&lt;br /&gt;
&lt;br /&gt;
These segments f code work with the Keen 1-3 implementation only and will not for example decompress LZEXE compressed executables.&lt;br /&gt;
&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;
DECLARE FUNCTION READBITS% (FILE AS INTEGER, NUMBITS AS INTEGER)&lt;br /&gt;
DECLARE SUB LZWDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING)&lt;br /&gt;
DECLARE SUB LZWOUTPUT (FILE AS INTEGER, DIC AS INTEGER, CHAR AS INTEGER)&lt;br /&gt;
&#039;&lt;br /&gt;
&#039; KEEN1 Compatible LZW Decompressor (Lempel-Ziv-Welch)&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&lt;br /&gt;
&#039;&lt;br /&gt;
&#039;&lt;br /&gt;
&lt;br /&gt;
&#039; Allocate dictionary&lt;br /&gt;
DIM LZDIC(0 TO 4095) AS INTEGER&lt;br /&gt;
DIM LZCHR(0 TO 4095) AS INTEGER&lt;br /&gt;
&lt;br /&gt;
&#039; Test Function&lt;br /&gt;
LZWDECOMPRESS &amp;quot;EGALATCH.CK1&amp;quot;, &amp;quot;EGALATCH.DAT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SUB LZWDECOMPRESS (INNAME AS STRING, OUTNAME AS STRING)&lt;br /&gt;
        SHARED LZDIC() AS INTEGER, LZCHR() AS INTEGER&lt;br /&gt;
        DIM INFILE AS INTEGER, OUTFILE AS INTEGER, I AS INTEGER&lt;br /&gt;
        DIM BITLEN AS INTEGER, CURPOS AS INTEGER&lt;br /&gt;
        DIM CW AS INTEGER, PW AS INTEGER, C AS INTEGER, P AS INTEGER&lt;br /&gt;
        DIM CHECK AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        &#039; Open files for input and output&lt;br /&gt;
        INFILE = FREEFILE&lt;br /&gt;
        OPEN INNAME FOR BINARY ACCESS READ AS INFILE&lt;br /&gt;
        OUTFILE = FREEFILE&lt;br /&gt;
        OPEN OUTNAME FOR BINARY ACCESS WRITE AS OUTFILE&lt;br /&gt;
        SEEK INFILE, 7&lt;br /&gt;
&lt;br /&gt;
       &lt;br /&gt;
        &#039; Fill dictionary with starting values&lt;br /&gt;
        FOR I = 0 TO 4095&lt;br /&gt;
                LZDIC(I) = -1&lt;br /&gt;
                IF I &amp;lt; 256 THEN&lt;br /&gt;
                        LZCHR(I) = I&lt;br /&gt;
                ELSE&lt;br /&gt;
                        LZCHR(I) = -1&lt;br /&gt;
                END IF&lt;br /&gt;
        NEXT I&lt;br /&gt;
&lt;br /&gt;
        &#039; Decompress input stream to output stream&lt;br /&gt;
        BITLEN = 9&lt;br /&gt;
        CURPOS = 258&lt;br /&gt;
        CW = READBITS(INFILE, BITLEN)&lt;br /&gt;
        LZWOUTPUT OUTFILE, LZDIC(CW), LZCHR(CW)&lt;br /&gt;
       &lt;br /&gt;
        WHILE CW &amp;lt;&amp;gt; &amp;amp;H100 AND CW &amp;lt;&amp;gt; &amp;amp;H101&lt;br /&gt;
                PW = CW&lt;br /&gt;
                CW = READBITS(INFILE, BITLEN)&lt;br /&gt;
                IF CW &amp;lt;&amp;gt; &amp;amp;H100 AND CW &amp;lt;&amp;gt; &amp;amp;H101 THEN&lt;br /&gt;
                        P = PW&lt;br /&gt;
                        CHECK = (LZCHR(CW) &amp;lt;&amp;gt; -1)&lt;br /&gt;
                       &lt;br /&gt;
                        IF CHECK THEN&lt;br /&gt;
                                TMP = CW&lt;br /&gt;
                        ELSE&lt;br /&gt;
                                TMP = PW&lt;br /&gt;
                        END IF&lt;br /&gt;
                        WHILE LZDIC(TMP) &amp;lt;&amp;gt; -1&lt;br /&gt;
                                TMP = LZDIC(TMP)&lt;br /&gt;
                        WEND&lt;br /&gt;
                        C = LZCHR(TMP)&lt;br /&gt;
                       &lt;br /&gt;
                        IF CHECK THEN&lt;br /&gt;
                                LZWOUTPUT OUTFILE, LZDIC(CW), LZCHR(CW)&lt;br /&gt;
                        ELSE&lt;br /&gt;
                                LZWOUTPUT OUTFILE, P, C&lt;br /&gt;
                        END IF&lt;br /&gt;
                       &lt;br /&gt;
                        IF CURPOS &amp;lt; 4096 THEN&lt;br /&gt;
                                LZDIC(CURPOS) = P&lt;br /&gt;
                                LZCHR(CURPOS) = C&lt;br /&gt;
                                CURPOS = CURPOS + 1&lt;br /&gt;
                                IF CURPOS = (2 ^ BITLEN - 1) AND BITLEN &amp;lt; 12 THEN&lt;br /&gt;
                                        BITLEN = BITLEN + 1&lt;br /&gt;
                                END IF&lt;br /&gt;
                        END IF&lt;br /&gt;
&lt;br /&gt;
                END IF&lt;br /&gt;
        WEND&lt;br /&gt;
       &lt;br /&gt;
        &#039; Close files&lt;br /&gt;
        CLOSE OUTFILE&lt;br /&gt;
        CLOSE INFILE&lt;br /&gt;
END SUB&lt;br /&gt;
&lt;br /&gt;
SUB LZWOUTPUT (FILE AS INTEGER, DIC AS INTEGER, CHAR AS INTEGER)&lt;br /&gt;
        SHARED LZDIC() AS INTEGER, LZCHR() AS INTEGER&lt;br /&gt;
        DIM LZSTK(0 TO 127) AS STRING * 1&lt;br /&gt;
        DIM X AS INTEGER, SP AS INTEGER&lt;br /&gt;
        DIM LDIC AS INTEGER, LCHAR AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        LCHAR = CHAR&lt;br /&gt;
        LDIC = DIC&lt;br /&gt;
        SP = 0&lt;br /&gt;
        X = 1&lt;br /&gt;
&lt;br /&gt;
        DO&lt;br /&gt;
                IF SP &amp;gt;= 128 THEN&lt;br /&gt;
                        PRINT &amp;quot;LZW: Stack Overflow!&amp;quot;&lt;br /&gt;
                        END&lt;br /&gt;
                END IF&lt;br /&gt;
                LZSTK(SP) = CHR$(LCHAR)&lt;br /&gt;
                SP = SP + 1&lt;br /&gt;
                IF LDIC &amp;lt;&amp;gt; -1 THEN&lt;br /&gt;
                        LCHAR = LZCHR(LDIC)&lt;br /&gt;
                        LDIC = LZDIC(LDIC)&lt;br /&gt;
                ELSE&lt;br /&gt;
                        X = 0&lt;br /&gt;
                END IF&lt;br /&gt;
        LOOP WHILE X&lt;br /&gt;
       &lt;br /&gt;
        WHILE SP &amp;lt;&amp;gt; 0&lt;br /&gt;
                SP = SP - 1&lt;br /&gt;
                PUT FILE, , LZSTK(SP)&lt;br /&gt;
        WEND&lt;br /&gt;
END SUB&lt;br /&gt;
&lt;br /&gt;
FUNCTION READBITS% (FILE AS INTEGER, NUMBITS AS INTEGER)&lt;br /&gt;
        STATIC BITDAT AS STRING * 1, BITPOS AS INTEGER&lt;br /&gt;
        DIM BITVAL AS INTEGER, BIT AS INTEGER&lt;br /&gt;
&lt;br /&gt;
        BITVAL = 0&lt;br /&gt;
        FOR BIT = (NUMBITS - 1) TO 0 STEP -1&lt;br /&gt;
                IF BITPOS = 0 THEN&lt;br /&gt;
                        GET FILE, , BITDAT&lt;br /&gt;
                        BITPOS = 7&lt;br /&gt;
                ELSE&lt;br /&gt;
                        BITPOS = BITPOS - 1&lt;br /&gt;
                END IF&lt;br /&gt;
                IF ASC(BITDAT) AND 2 ^ BITPOS THEN&lt;br /&gt;
                        BITVAL = BITVAL OR 2 ^ BIT&lt;br /&gt;
                END IF&lt;br /&gt;
        NEXT BIT&lt;br /&gt;
&lt;br /&gt;
        READBITS% = BITVAL&lt;br /&gt;
END FUNCTION&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== FreeBasic ===&lt;br /&gt;
&lt;br /&gt;
This code does not suffer from the 64K memory limit imposed by QuickBasic and so is less efficient, but runs faster. It can be compiled with FreeBasic compiler using the -lang=qb switch. Aside from memory concerns, all code here is compatible with QuickBasic.&lt;br /&gt;
&lt;br /&gt;
The code before the subroutine is used to make a string containing the bit expansion of all values from 0 to 255. The subroutine takes a filename, reads the entire file into memory then expands each bit of data to a byte using the aforesaid string as Basic cannot deal with bits directly. cw$ is codeword, pw$ is the previous codeword, lun is the lowest dictionary entry that is empty, p is the location in the compressed data stream and bl is the length of codes in bits (Starting at nine bits increasing to 12)&lt;br /&gt;
&lt;br /&gt;
The dictionary is set before decompression. The first 258 are the starting dictionary, the remainder are cleared. (It is vital to reset the dictionary for each file) An error occurs if entry 256 is found in the data, &#039;distrupt&#039; is printed when the newest dictionary entry is not the lowest possible entry (This shouldn&#039;t happen but is possible.) Decompression ends at encountering entry 257, or when there is no more data to read.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;qbasic&amp;quot;&amp;gt;&lt;br /&gt;
DECLARE SUB LZWDEC (lfn AS STRING)&lt;br /&gt;
&lt;br /&gt;
x$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 0 TO 255&lt;br /&gt;
 IF (l AND 128) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 64) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 32) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 16) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 8) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 4) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 2) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
 IF (l AND 1) &amp;gt; 0 THEN x$ = x$ + &amp;quot;1&amp;quot; ELSE x$ = x$ + &amp;quot;0&amp;quot;&lt;br /&gt;
NEXT l&lt;br /&gt;
LZEDEC &amp;quot;EGALATCH.CK1&amp;quot;&lt;br /&gt;
END&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;_________________________________________________&lt;br /&gt;
SUB LZWDEC (lfn AS STRING) &#039; Decompress LZW data&lt;br /&gt;
&#039;_________________________________________________&lt;br /&gt;
DIM lzw(0 TO 4095) AS STRING&lt;br /&gt;
PRINT lfn; &amp;quot; is LZW compressed, decompressing...&amp;quot;;&lt;br /&gt;
OPEN folder + lfn FOR BINARY AS #9&lt;br /&gt;
y$ = SPACE$(LOF(9))&lt;br /&gt;
GET #9, 1, y$&lt;br /&gt;
CLOSE #9&lt;br /&gt;
z$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 7 TO LEN(y$)&lt;br /&gt;
 z$ = z$ + MID$(x$, (ASC(MID$(y$, l, 1)) * 8) + 1, 8)&lt;br /&gt;
NEXT l&lt;br /&gt;
&lt;br /&gt;
bl = 9&lt;br /&gt;
lun = 258&lt;br /&gt;
p = 1&lt;br /&gt;
cw$ = &amp;quot;&amp;quot;&lt;br /&gt;
y$ = &amp;quot;&amp;quot;&lt;br /&gt;
FOR l = 0 TO 4095&lt;br /&gt;
 IF l &amp;lt; 256 THEN lzw(l) = CHR$(l) ELSE lzw(l) = &amp;quot;&amp;quot;&lt;br /&gt;
NEXT l&lt;br /&gt;
DO&lt;br /&gt;
 IF lun = 511 THEN bl = 10&lt;br /&gt;
 IF lun = 1023 THEN bl = 11&lt;br /&gt;
 IF lun = 2047 THEN bl = 12&lt;br /&gt;
 pw$ = cw$&lt;br /&gt;
 u$ = MID$(z$, p, bl)&lt;br /&gt;
 p = p + bl&lt;br /&gt;
 y = 0&lt;br /&gt;
 FOR l = 1 TO bl&lt;br /&gt;
  IF MID$(u$, bl - l + 1, 1) = &amp;quot;1&amp;quot; THEN y = y + (2 ^ (l - 1))&lt;br /&gt;
 NEXT l&lt;br /&gt;
 IF y = 256 THEN&lt;br /&gt;
  PRINT &amp;quot;LZW error in Keen data!&amp;quot;&lt;br /&gt;
  OPEN &amp;quot;ERROR.DAT&amp;quot; FOR OUTPUT AS #9&lt;br /&gt;
  PRINT #9, y$;&lt;br /&gt;
  CLOSE&lt;br /&gt;
  END&lt;br /&gt;
 END IF&lt;br /&gt;
 IF y = 257 THEN EXIT DO&lt;br /&gt;
 IF cw$ = &amp;quot;&amp;quot; THEN&lt;br /&gt;
  cw$ = lzw(y)&lt;br /&gt;
  y$ = y$ + cw$&lt;br /&gt;
 ELSE&lt;br /&gt;
  IF lun &amp;lt; 4096 THEN&lt;br /&gt;
   IF lzw(y) = &amp;quot;&amp;quot; THEN&lt;br /&gt;
    cw$ = pw$ + LEFT$(pw$, 1)&lt;br /&gt;
    lzw(y) = cw$&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
    IF y &amp;lt;&amp;gt; lun THEN PRINT &amp;quot;Disrupt!&amp;quot;&lt;br /&gt;
    lun = y + 1&lt;br /&gt;
   ELSE&lt;br /&gt;
    cw$ = lzw(y)&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
    lzw(lun) = pw$ + LEFT$(cw$, 1)&lt;br /&gt;
    lun = lun + 1&lt;br /&gt;
   END IF&lt;br /&gt;
  ELSE&lt;br /&gt;
   IF lzw(y) = &amp;quot;&amp;quot; THEN&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
   ELSE&lt;br /&gt;
    cw$ = lzw(y)&lt;br /&gt;
    y$ = y$ + cw$&lt;br /&gt;
   END IF&lt;br /&gt;
  END IF&lt;br /&gt;
 END IF&lt;br /&gt;
LOOP WHILE p &amp;lt; LEN(z$)&lt;br /&gt;
IF y = 257 THEN PRINT &amp;quot;done&amp;quot; ELSE PRINT &amp;quot;out of data.&amp;quot;&lt;br /&gt;
OPEN folder + LEFT$(lfn, 4) + extq FOR OUTPUT AS #9&lt;br /&gt;
PRINT #9, y$;&lt;br /&gt;
CLOSE #9&lt;br /&gt;
END SUB&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Visual Basic .NET ===&lt;br /&gt;
&lt;br /&gt;
This implementation uses high-level elements such as lambdas, anonymous arrays, and strict types. It must be compiled for the Microsoft .NET Framework v4.5 in Visual Studio 2012. It has the advantages of running in non-DosBox Windows and using .NET streams for simple reusability. It can also be used for higher-bit LZW.&lt;br /&gt;
&lt;br /&gt;
==== Decompression ====&lt;br /&gt;
&lt;br /&gt;
Decompressing is very fast.&lt;br /&gt;
&amp;lt;source&amp;gt;    Sub DecompressLZW(Data As IO.Stream, MaxBits As Byte, Output As IO.Stream)&lt;br /&gt;
        &#039; This source is by Fleexy and is in the public domain. If used, please note it as such.&lt;br /&gt;
        Dim dict As New List(Of Byte())&lt;br /&gt;
        For x = 0 To 255&lt;br /&gt;
            dict.Add({x})&lt;br /&gt;
        Next&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        dict.Add(Nothing)&lt;br /&gt;
        Dim usebits As Byte = 9&lt;br /&gt;
        Dim bpos As Long&lt;br /&gt;
        Dim bits As New List(Of Byte)&lt;br /&gt;
        Do Until Data.Position = Data.Length&lt;br /&gt;
            Dim b, ub As Byte&lt;br /&gt;
            b = Data.ReadByte&lt;br /&gt;
            ub = b&lt;br /&gt;
            For x = 7 To 0 Step -1&lt;br /&gt;
                If ub - (2 ^ x) &amp;gt;= 0 Then&lt;br /&gt;
                    ub -= (2 ^ x)&lt;br /&gt;
                    bits.Add(1)&lt;br /&gt;
                Else&lt;br /&gt;
                    bits.Add(0)&lt;br /&gt;
                End If&lt;br /&gt;
            Next&lt;br /&gt;
        Loop&lt;br /&gt;
        Dim GetCode = Function() As UInteger&lt;br /&gt;
                          Dim u As UInteger&lt;br /&gt;
                          For x = usebits To 1 Step -1&lt;br /&gt;
                              If bits(bpos) = 1 Then u += (2 ^ (x - 1))&lt;br /&gt;
                              bpos += 1&lt;br /&gt;
                          Next&lt;br /&gt;
                          Return u&lt;br /&gt;
                      End Function&lt;br /&gt;
        Dim OutputCode = Sub(DecompData As Byte())&lt;br /&gt;
                             Dim n As UInteger = DecompData.Length&lt;br /&gt;
                             Output.Write(DecompData, 0, n)&lt;br /&gt;
                         End Sub&lt;br /&gt;
        Dim AddToDict = Sub(Entry As Byte())&lt;br /&gt;
                            If dict.Count &amp;lt; (2 ^ MaxBits) Then&lt;br /&gt;
                                dict.Add(Entry)&lt;br /&gt;
                                If dict.Count = (2 ^ usebits) - 1 Then usebits = Math.Min(usebits + 1, MaxBits)&lt;br /&gt;
                            End If&lt;br /&gt;
                        End Sub&lt;br /&gt;
        Dim fcode As UInteger = GetCode()&lt;br /&gt;
        Dim match As Byte() = dict(fcode)&lt;br /&gt;
        OutputCode(match)&lt;br /&gt;
        Do&lt;br /&gt;
            Dim ncode As UInteger = GetCode()&lt;br /&gt;
            If ncode = 257 Then Exit Do&lt;br /&gt;
            If ncode = 256 Then Throw New Exception&lt;br /&gt;
            Dim nmatch As Byte()&lt;br /&gt;
            If ncode &amp;lt; dict.Count Then&lt;br /&gt;
                nmatch = dict(ncode)&lt;br /&gt;
            Else&lt;br /&gt;
                nmatch = match.Concat({match(0)}).ToArray&lt;br /&gt;
            End If&lt;br /&gt;
            OutputCode(nmatch)&lt;br /&gt;
            AddToDict(match.Concat({nmatch(0)}).ToArray)&lt;br /&gt;
            match = nmatch&lt;br /&gt;
        Loop&lt;br /&gt;
    End Sub&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Compression ====&lt;br /&gt;
&lt;br /&gt;
Compression is more difficult; consulting the dictionary for a byte array takes more time. The speed of this algorithm may be unacceptable.&lt;br /&gt;
&amp;lt;source&amp;gt;    Sub CompressLZW(Data As IO.Stream, MaxBits As Byte, Output As IO.Stream)&lt;br /&gt;
        &#039; This source is by Fleexy and is in the public domain.&lt;br /&gt;
        Dim bits As New List(Of Byte)&lt;br /&gt;
        Dim dict As New List(Of Byte())&lt;br /&gt;
        For x = 0 To 255&lt;br /&gt;
            dict.Add({x})&lt;br /&gt;
        Next&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        dict.Add({})&lt;br /&gt;
        Dim usebits As Byte = 9&lt;br /&gt;
        Dim PutCode = Sub(Code As UInteger)&lt;br /&gt;
                          For x = usebits To 1 Step -1&lt;br /&gt;
                              If Code - (2 ^ (x - 1)) &amp;gt;= 0 Then&lt;br /&gt;
                                  Code -= (2 ^ (x - 1))&lt;br /&gt;
                                  bits.Add(1)&lt;br /&gt;
                              Else&lt;br /&gt;
                                  bits.Add(0)&lt;br /&gt;
                              End If&lt;br /&gt;
                          Next&lt;br /&gt;
                      End Sub&lt;br /&gt;
        Dim AddToDict = Function(Entry As Byte()) As Boolean&lt;br /&gt;
                            If dict.Count &amp;lt; 2 ^ MaxBits Then&lt;br /&gt;
                                dict.Add(Entry)&lt;br /&gt;
                                If dict.Count = 2 ^ usebits Then usebits = Math.Min(usebits + 1, MaxBits)&lt;br /&gt;
                                Return True&lt;br /&gt;
                            Else&lt;br /&gt;
                                Return False&lt;br /&gt;
                            End If&lt;br /&gt;
                        End Function&lt;br /&gt;
        Dim FindCode = Function(Bytes As Byte()) As UInteger&lt;br /&gt;
                           For x = 1 To dict.Count&lt;br /&gt;
                               If dict(x - 1).Count = Bytes.Count Then&lt;br /&gt;
                                   If dict(x - 1).SequenceEqual(Bytes) Then Return x - 1&lt;br /&gt;
                               End If&lt;br /&gt;
                           Next&lt;br /&gt;
                           Throw New NotFiniteNumberException&lt;br /&gt;
                       End Function&lt;br /&gt;
        Dim DictContains = Function(Bytes As Byte()) As Boolean&lt;br /&gt;
                               For x = 1 To dict.Count&lt;br /&gt;
                                   If dict(x - 1).Length = Bytes.Length Then&lt;br /&gt;
                                       If dict(x - 1).SequenceEqual(Bytes) Then Return True&lt;br /&gt;
                                   End If&lt;br /&gt;
                               Next&lt;br /&gt;
                               Return False&lt;br /&gt;
                           End Function&lt;br /&gt;
        Dim match As Byte() = {}&lt;br /&gt;
        Do Until Data.Position = Data.Length&lt;br /&gt;
            Dim nbyte As Byte = Data.ReadByte&lt;br /&gt;
            Dim nmatch As Byte() = match.Concat({nbyte}).ToArray&lt;br /&gt;
            If DictContains(nmatch) Then&lt;br /&gt;
                match = nmatch&lt;br /&gt;
            Else&lt;br /&gt;
                PutCode(FindCode(match))&lt;br /&gt;
                AddToDict(nmatch)&lt;br /&gt;
                match = {nbyte}&lt;br /&gt;
            End If&lt;br /&gt;
        Loop&lt;br /&gt;
        PutCode(FindCode(match))&lt;br /&gt;
        PutCode(257)&lt;br /&gt;
        Do Until bits.LongCount Mod 8L = 0L&lt;br /&gt;
            bits.Add(0)&lt;br /&gt;
        Loop&lt;br /&gt;
        For x = 1 To CInt(bits.LongCount / 8L)&lt;br /&gt;
            Dim b As Byte = 0&lt;br /&gt;
            For y = 0 To 7&lt;br /&gt;
                b += bits((x - 1) * 8 + y) * (2 ^ (7 - y))&lt;br /&gt;
            Next&lt;br /&gt;
            Output.WriteByte(b)&lt;br /&gt;
        Next&lt;br /&gt;
    End Sub&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander Keen 1-3]]&lt;br /&gt;
[[Category:File Formats]]&lt;br /&gt;
[[Category:Compressed Files]]&lt;/div&gt;</summary>
		<author><name>Fleexy</name></author>
	</entry>
</feed>