<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://alttp.run/hacking/index.php?action=history&amp;feed=atom&amp;title=Data_Compression</id>
		<title>Data Compression - Revision history</title>
		<link rel="self" type="application/atom+xml" href="http://alttp.run/hacking/index.php?action=history&amp;feed=atom&amp;title=Data_Compression"/>
		<link rel="alternate" type="text/html" href="http://alttp.run/hacking/index.php?title=Data_Compression&amp;action=history"/>
		<updated>2026-06-01T07:57:28Z</updated>
		<subtitle>Revision history for this page on the wiki</subtitle>
		<generator>MediaWiki 1.28.0</generator>

	<entry>
		<id>http://alttp.run/hacking/index.php?title=Data_Compression&amp;diff=430&amp;oldid=prev</id>
		<title>Jkazos: Created page with &quot;''See also: Standard Notation''  ALTTP (and some other SNES games) use a simple form of run-length compression to reduce the ROM consumption of data that often have repeat...&quot;</title>
		<link rel="alternate" type="text/html" href="http://alttp.run/hacking/index.php?title=Data_Compression&amp;diff=430&amp;oldid=prev"/>
				<updated>2016-11-19T14:41:09Z</updated>
		
		<summary type="html">&lt;p&gt;Created page with &amp;quot;&amp;#039;&amp;#039;See also: &lt;a href=&quot;/hacking/index.php?title=Standard_Notation&quot; title=&quot;Standard Notation&quot;&gt;Standard Notation&lt;/a&gt;&amp;#039;&amp;#039;  ALTTP (and some other SNES games) use a simple form of run-length compression to reduce the ROM consumption of data that often have repeat...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;''See also: [[Standard Notation]]''&lt;br /&gt;
&lt;br /&gt;
ALTTP (and some other SNES games) use a simple form of run-length compression to reduce the ROM consumption of data that often have repeated sequences within them (such as a row of pixels all the same color, or a row of tiles all the same type). Decompressing data that are compressed in this way takes more time than simply copying them from ROM bytewise, so compression should be used only when necessary.&lt;br /&gt;
&lt;br /&gt;
== Compressed Format ==&lt;br /&gt;
&lt;br /&gt;
A compressed datum is a sequence of single-byte command headers with optional arguments. The compressed sequence is terminated by the $FF header with no arguments.&lt;br /&gt;
&lt;br /&gt;
;Header byte -- bits 7..5&lt;br /&gt;
: command&lt;br /&gt;
&lt;br /&gt;
;Header byte -- bits 4..0&lt;br /&gt;
: length parameter&lt;br /&gt;
&lt;br /&gt;
If the command within the header byte is %111, then the byte after the header byte is a header extension byte and the extended header is as follows.&lt;br /&gt;
&lt;br /&gt;
;Header byte -- bits 4..2&lt;br /&gt;
: command&lt;br /&gt;
&lt;br /&gt;
;Header byte -- bits 1..0&lt;br /&gt;
: bits 9..8 of length parameter&lt;br /&gt;
&lt;br /&gt;
;Header extension byte&lt;br /&gt;
: bits 7..0 of length parameter&lt;br /&gt;
&lt;br /&gt;
NOTE: The length parameter is implied to be one more than actually stored in the header, because you would never want a command to generate 0 bytes, so once the length has been calculated, increment it by 1.&lt;br /&gt;
&lt;br /&gt;
Commands 0-4 are valid. Commands 5-7 are unused and invalid.&lt;br /&gt;
&lt;br /&gt;
;Command 0&lt;br /&gt;
: the next (length parameter + 1) bytes of the input are copied to the output bytewise&lt;br /&gt;
&lt;br /&gt;
;Command 1&lt;br /&gt;
: the next byte of the input is copied to the output (length parameter + 1) times&lt;br /&gt;
&lt;br /&gt;
;Command 2&lt;br /&gt;
: let the next byte of the input be A&lt;br /&gt;
: let the byte of the input after A be B&lt;br /&gt;
: A and B are copied (alternating, as in ABABABAB...) to the output until (length parameter + 1) bytes have been copied to the output&lt;br /&gt;
&lt;br /&gt;
;Command 3&lt;br /&gt;
: let the next byte of the input be A&lt;br /&gt;
: A is copied and incremented (as in A,A+1,A+2,A+3...) to the output until (length parameter + 1) bytes have been copied to the output&lt;br /&gt;
&lt;br /&gt;
;Command 4&lt;br /&gt;
: let the next byte of the input be A&lt;br /&gt;
: let the byte of the input after A be B&lt;br /&gt;
: A and B form an offset into the current output buffer (the bytes that have already been decompressed and copied to the output)&lt;br /&gt;
: let this offset be X&lt;br /&gt;
: &amp;lt;tt&amp;gt;X = A | ( B &amp;lt;&amp;lt; 8 )&amp;lt;/tt&amp;gt;&lt;br /&gt;
: (length parameter + 1) bytes are copied from within the current output buffer and appended to the end of the current output buffer&lt;br /&gt;
&lt;br /&gt;
== Sample C# Code ==&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' This code assumes the compressed input is well-formed. If the input is garbage, corrupted, or the wrong format, the code may hang, raise an exception, or generate garbage output.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;public static class AlttpDataCompression&lt;br /&gt;
{&lt;br /&gt;
	static System . Collections . Generic . List &amp;lt; byte &amp;gt; Output = new System . Collections . Generic . List &amp;lt; byte &amp;gt; ( ) ;&lt;br /&gt;
&lt;br /&gt;
	public static byte [ ] Decompress ( byte [ ] Input , int InputOffset )&lt;br /&gt;
	{&lt;br /&gt;
		Output . Clear ( ) ;&lt;br /&gt;
&lt;br /&gt;
		while ( true )&lt;br /&gt;
		{&lt;br /&gt;
			int Header = Input [ InputOffset ] ;&lt;br /&gt;
&lt;br /&gt;
			InputOffset ++ ;&lt;br /&gt;
&lt;br /&gt;
			if ( Header == 0xFF )&lt;br /&gt;
			{&lt;br /&gt;
				return ( Output . ToArray ( ) ) ;&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			int Command = Header &amp;gt;&amp;gt; 5 ;&lt;br /&gt;
&lt;br /&gt;
			int Length = Header &amp;amp; 0x1F ;&lt;br /&gt;
&lt;br /&gt;
			if ( Command == 0x7 )&lt;br /&gt;
			{&lt;br /&gt;
				Command = ( Header &amp;gt;&amp;gt; 2 ) &amp;amp; 0x7 ;&lt;br /&gt;
&lt;br /&gt;
				Length = ( Header &amp;amp; 0x3 ) &amp;lt;&amp;lt; 8 ;&lt;br /&gt;
&lt;br /&gt;
				Length |= Input [ InputOffset ] ;&lt;br /&gt;
&lt;br /&gt;
				InputOffset ++ ;&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			Length ++ ;&lt;br /&gt;
&lt;br /&gt;
			if ( Command == 0 )&lt;br /&gt;
			{&lt;br /&gt;
				for ( int Index = 0 ; Index &amp;lt; Length ; Index ++ )&lt;br /&gt;
				{&lt;br /&gt;
					Output . Add ( Input [ InputOffset + Index ] ) ;&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				InputOffset += Length ;&lt;br /&gt;
			}&lt;br /&gt;
			else if ( Command == 1 )&lt;br /&gt;
			{&lt;br /&gt;
				for ( int Index = 0 ; Index &amp;lt; Length ; Index ++ )&lt;br /&gt;
				{&lt;br /&gt;
					Output . Add ( Input [ InputOffset ] ) ;&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				InputOffset ++ ;&lt;br /&gt;
			}&lt;br /&gt;
			else if ( Command == 2 )&lt;br /&gt;
			{&lt;br /&gt;
				int AlternatingOffset = 0 ;&lt;br /&gt;
&lt;br /&gt;
				for ( int Index = 0 ; Index &amp;lt; Length ; Index ++ )&lt;br /&gt;
				{&lt;br /&gt;
					Output . Add ( Input [ InputOffset + AlternatingOffset ] ) ;&lt;br /&gt;
&lt;br /&gt;
					AlternatingOffset = ( AlternatingOffset + 1 ) % 2 ;&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				InputOffset += 2 ;&lt;br /&gt;
			}&lt;br /&gt;
			else if ( Command == 3 )&lt;br /&gt;
			{&lt;br /&gt;
				int IncrementingValue = Input [ InputOffset ] ;&lt;br /&gt;
&lt;br /&gt;
				InputOffset ++ ;&lt;br /&gt;
&lt;br /&gt;
				for ( int Index = 0 ; Index &amp;lt; Length ; Index ++ )&lt;br /&gt;
				{&lt;br /&gt;
					Output . Add ( ( byte ) ( IncrementingValue &amp;amp; 0xFF ) ) ;&lt;br /&gt;
&lt;br /&gt;
					IncrementingValue ++ ;&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
			else if ( Command == 4 )&lt;br /&gt;
			{&lt;br /&gt;
				int CopyOffset = Input [ InputOffset ] | ( Input [ InputOffset + 1 ] &amp;lt;&amp;lt; 8 ) ;&lt;br /&gt;
&lt;br /&gt;
				InputOffset += 2 ;&lt;br /&gt;
&lt;br /&gt;
				for ( int Index = 0 ; Index &amp;lt; Length ; Index ++ )&lt;br /&gt;
				{&lt;br /&gt;
					Output . Add ( Output [ CopyOffset + Index ] ) ;&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jkazos</name></author>	</entry>

	</feed>