diff --git a/ANX.Framework/ANX.Framework.csproj b/ANX.Framework/ANX.Framework.csproj
index bb1717cf..876996a1 100644
--- a/ANX.Framework/ANX.Framework.csproj
+++ b/ANX.Framework/ANX.Framework.csproj
@@ -59,6 +59,7 @@
+
@@ -68,6 +69,7 @@
+
diff --git a/ANX.Framework/Content/ContentReader.cs b/ANX.Framework/Content/ContentReader.cs
index 72cc266d..8d9fc13c 100644
--- a/ANX.Framework/Content/ContentReader.cs
+++ b/ANX.Framework/Content/ContentReader.cs
@@ -179,8 +179,8 @@ namespace ANX.Framework.Content
if (isCompressed)
{
- uint decompressedSize = reader.ReadUInt32();
- throw new NotSupportedException("Compressed content is not supported yet.");
+ int decompressedSize = reader.ReadInt32();
+ return Decompressor.DecompressStream(reader, input, decompressedSize);
}
else
{
diff --git a/ANX.Framework/Content/Decompressor.cs b/ANX.Framework/Content/Decompressor.cs
new file mode 100644
index 00000000..b4b15e79
--- /dev/null
+++ b/ANX.Framework/Content/Decompressor.cs
@@ -0,0 +1,158 @@
+#region Using Statements
+using System;
+using System.IO;
+#endregion // Using Statements
+
+#region License AnxFramework
+//
+// This file is part of the ANX.Framework created by the "ANX.Framework developer group".
+//
+// This file is released under the Ms-PL license.
+//
+//
+//
+// Microsoft Public License (Ms-PL)
+//
+// This license governs use of the accompanying software. If you use the software, you accept this license.
+// If you do not accept the license, do not use the software.
+//
+// 1.Definitions
+// The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning
+// here as under U.S. copyright law.
+// A "contribution" is the original software, or any additions or changes to the software.
+// A "contributor" is any person that distributes its contribution under this license.
+// "Licensed patents" are a contributor's patent claims that read directly on its contribution.
+//
+// 2.Grant of Rights
+// (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations
+// in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to
+// reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution
+// or any derivative works that you create.
+// (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in
+// section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed
+// patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution
+// in the software or derivative works of the contribution in the software.
+//
+// 3.Conditions and Limitations
+// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
+// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your
+// patent license from such contributor to the software ends automatically.
+// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution
+// notices that are present in the software.
+// (D) If you distribute any portion of the software in source code form, you may do so only under this license by including
+// a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or
+// object code form, you may only do so under a license that complies with this license.
+// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees,
+// or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the
+// extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a
+// particular purpose and non-infringement.
+
+#endregion // License
+
+#region License MonoXna
+/*
+MIT License
+Copyright © 2011 The MonoXNA Team
+
+All rights reserved.
+
+Authors:
+ * Lars Magnusson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+#endregion License
+
+namespace ANX.Framework.Content
+{
+ internal static class Decompressor
+ {
+ public static Stream DecompressStream(BinaryReader reader, Stream input, int num)
+ {
+ // ... let's decompress it!
+ // get the decompressed size (num is our compressed size)
+ int decompressedSize = reader.ReadInt32();
+ // create a memory stream of that size
+ MemoryStream output = new MemoryStream(decompressedSize);
+
+ // save our initial position
+ long pos = input.Position;
+ // default window size for XNB encoded files is 64Kb (need 16 bits to represent it)
+ LzxDecoder decoder = new LzxDecoder(16);
+ // start our decode process
+ while (pos < num)
+ {
+ // the compressed stream is seperated into blocks that will decompress
+ // into 32Kb or some other size if specified.
+ // normal, 32Kb output blocks will have a short indicating the size
+ // of the block before the block starts
+ // blocks that have a defined output will be preceded by a byte of value
+ // 0xFF (255), then a short indicating the output size and another
+ // for the block size
+ // all shorts for these cases are encoded in big endian order
+ int hi, lo, block_size, frame_size;
+ // let's get the first byte
+ hi = reader.ReadByte();
+ // does this block define a frame size?
+ if (hi == 0xFF)
+ {
+ // get our bytes
+ hi = reader.ReadByte();
+ lo = reader.ReadByte();
+ // make a beautiful short baby together
+ frame_size = (hi << 8) | lo;
+ // let's read the block size
+ hi = reader.ReadByte();
+ lo = reader.ReadByte();
+ block_size = (hi << 8) | lo;
+ // add the read in bytes to the position
+ pos += 5;
+ }
+ else
+ {
+ // just block size, so let's read the rest
+ lo = reader.ReadByte();
+ block_size = (hi << 8) | lo;
+ // frame size is 32Kb by default
+ frame_size = 32768;
+ // add the read in bytes to the position
+ pos += 2;
+ }
+
+ // either says there is nothing to decode
+ if (block_size == 0 || frame_size == 0)
+ break;
+
+ // let's decompress the sucker
+ decoder.Decompress(input, block_size, output, frame_size);
+
+ // let's increment the input position by the block size
+ pos += block_size;
+ // reset the position of the input just incase the bit buffer
+ // read in some unused bytes
+ input.Seek(pos, SeekOrigin.Begin);
+ }
+
+ // finished decoding everything, let's set the decompressed buffer
+ // to the beginning and return that
+ output.Seek(0, SeekOrigin.Begin);
+ return output;
+ }
+ }
+}
diff --git a/ANX.Framework/Content/LzxDecoder.cs b/ANX.Framework/Content/LzxDecoder.cs
new file mode 100644
index 00000000..5bd47acb
--- /dev/null
+++ b/ANX.Framework/Content/LzxDecoder.cs
@@ -0,0 +1,784 @@
+#region HEADER
+/* This file was derived from libmspack
+ * (C) 2003-2004 Stuart Caie.
+ * (C) 2011 Ali Scissons.
+ *
+ * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
+ * by Microsoft Corporation.
+ *
+ * This source file is Dual licensed; meaning the end-user of this source file
+ * may redistribute/modify it under the LGPL 2.1 or MS-PL licenses.
+ */
+
+#region LGPL License
+/* GNU LESSER GENERAL PUBLIC LICENSE version 2.1
+ * LzxDecoder is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
+ */
+#endregion
+
+#region MS-PL License
+/*
+ * MICROSOFT PUBLIC LICENSE
+ * This source code is subject to the terms of the Microsoft Public License (Ms-PL).
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * is permitted provided that redistributions of the source code retain the above
+ * copyright notices and this file header.
+ *
+ * Additional copyright notices should be appended to the list above.
+ *
+ * For details, see .
+ */
+#endregion
+
+/*
+ * DETAILS
+ * This file is a pure C# port of the lzxd.c file from libmspack, with minor
+ * changes towards the decompression of XNB files. The original decompression
+ * software of LZX encoded data was written by Suart Caie in his
+ * libmspack/cabextract projects, which can be located at
+ * http://http://www.cabextract.org.uk/
+ */
+#endregion
+
+using System;
+namespace ANX.Framework.Content
+{
+ using System.IO;
+
+ internal class LzxDecoder
+ {
+ public static uint[] position_base = null;
+ public static byte[] extra_bits = null;
+
+ private LzxState m_state;
+
+ public LzxDecoder(int window)
+ {
+ uint wndsize = (uint)(1 << window);
+ int posn_slots;
+
+ // setup proper exception
+ if (window < 15 || window > 21) throw new UnsupportedWindowSizeRange();
+
+ // let's initialise our state
+ m_state = new LzxState();
+ m_state.actual_size = 0;
+ m_state.window = new byte[wndsize];
+ for (int i = 0; i < wndsize; i++) m_state.window[i] = 0xDC;
+ m_state.actual_size = wndsize;
+ m_state.window_size = wndsize;
+ m_state.window_posn = 0;
+
+ /* initialize static tables */
+ if (extra_bits == null)
+ {
+ extra_bits = new byte[52];
+ for (int i = 0, j = 0; i <= 50; i += 2)
+ {
+ extra_bits[i] = extra_bits[i + 1] = (byte)j;
+ if ((i != 0) && (j < 17)) j++;
+ }
+ }
+ if (position_base == null)
+ {
+ position_base = new uint[51];
+ for (int i = 0, j = 0; i <= 50; i++)
+ {
+ position_base[i] = (uint)j;
+ j += 1 << extra_bits[i];
+ }
+ }
+
+ /* calculate required position slots */
+ if (window == 20) posn_slots = 42;
+ else if (window == 21) posn_slots = 50;
+ else posn_slots = window << 1;
+
+ m_state.R0 = m_state.R1 = m_state.R2 = 1;
+ m_state.main_elements = (ushort)(LzxConstants.NUM_CHARS + (posn_slots << 3));
+ m_state.header_read = 0;
+ m_state.frames_read = 0;
+ m_state.block_remaining = 0;
+ m_state.block_type = LzxConstants.BLOCKTYPE.INVALID;
+ m_state.intel_curpos = 0;
+ m_state.intel_started = 0;
+
+ // yo dawg i herd u liek arrays so we put arrays in ur arrays so u can array while u array
+ m_state.PRETREE_table = new ushort[(1 << LzxConstants.PRETREE_TABLEBITS) + (LzxConstants.PRETREE_MAXSYMBOLS << 1)];
+ m_state.PRETREE_len = new byte[LzxConstants.PRETREE_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
+ m_state.MAINTREE_table = new ushort[(1 << LzxConstants.MAINTREE_TABLEBITS) + (LzxConstants.MAINTREE_MAXSYMBOLS << 1)];
+ m_state.MAINTREE_len = new byte[LzxConstants.MAINTREE_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
+ m_state.LENGTH_table = new ushort[(1 << LzxConstants.LENGTH_TABLEBITS) + (LzxConstants.LENGTH_MAXSYMBOLS << 1)];
+ m_state.LENGTH_len = new byte[LzxConstants.LENGTH_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
+ m_state.ALIGNED_table = new ushort[(1 << LzxConstants.ALIGNED_TABLEBITS) + (LzxConstants.ALIGNED_MAXSYMBOLS << 1)];
+ m_state.ALIGNED_len = new byte[LzxConstants.ALIGNED_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
+ /* initialise tables to 0 (because deltas will be applied to them) */
+ for (int i = 0; i < LzxConstants.MAINTREE_MAXSYMBOLS; i++) m_state.MAINTREE_len[i] = 0;
+ for (int i = 0; i < LzxConstants.LENGTH_MAXSYMBOLS; i++) m_state.LENGTH_len[i] = 0;
+ }
+
+ public int Decompress(Stream inData, int inLen, Stream outData, int outLen)
+ {
+ BitBuffer bitbuf = new BitBuffer(inData);
+ long startpos = inData.Position;
+ long endpos = inData.Position + inLen;
+
+ byte[] window = m_state.window;
+
+ uint window_posn = m_state.window_posn;
+ uint window_size = m_state.window_size;
+ uint R0 = m_state.R0;
+ uint R1 = m_state.R1;
+ uint R2 = m_state.R2;
+ uint i, j;
+
+ int togo = outLen, this_run, main_element, match_length, match_offset, length_footer, extra, verbatim_bits;
+ int rundest, runsrc, copy_length, aligned_bits;
+
+ bitbuf.InitBitStream();
+
+ /* read header if necessary */
+ if (m_state.header_read == 0)
+ {
+ uint intel = bitbuf.ReadBits(1);
+ if (intel != 0)
+ {
+ // read the filesize
+ i = bitbuf.ReadBits(16); j = bitbuf.ReadBits(16);
+ m_state.intel_filesize = (int)((i << 16) | j);
+ }
+ m_state.header_read = 1;
+ }
+
+ /* main decoding loop */
+ while (togo > 0)
+ {
+ /* last block finished, new block expected */
+ if (m_state.block_remaining == 0)
+ {
+ // TODO may screw something up here
+ if (m_state.block_type == LzxConstants.BLOCKTYPE.UNCOMPRESSED)
+ {
+ if ((m_state.block_length & 1) == 1) inData.ReadByte(); /* realign bitstream to word */
+ bitbuf.InitBitStream();
+ }
+
+ m_state.block_type = (LzxConstants.BLOCKTYPE)bitbuf.ReadBits(3); ;
+ i = bitbuf.ReadBits(16);
+ j = bitbuf.ReadBits(8);
+ m_state.block_remaining = m_state.block_length = (uint)((i << 8) | j);
+
+ switch (m_state.block_type)
+ {
+ case LzxConstants.BLOCKTYPE.ALIGNED:
+ for (i = 0, j = 0; i < 8; i++) { j = bitbuf.ReadBits(3); m_state.ALIGNED_len[i] = (byte)j; }
+ MakeDecodeTable(LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
+ m_state.ALIGNED_len, m_state.ALIGNED_table);
+ /* rest of aligned header is same as verbatim */
+ goto case LzxConstants.BLOCKTYPE.VERBATIM;
+
+ case LzxConstants.BLOCKTYPE.VERBATIM:
+ ReadLengths(m_state.MAINTREE_len, 0, 256, bitbuf);
+ ReadLengths(m_state.MAINTREE_len, 256, m_state.main_elements, bitbuf);
+ MakeDecodeTable(LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
+ m_state.MAINTREE_len, m_state.MAINTREE_table);
+ if (m_state.MAINTREE_len[0xE8] != 0) m_state.intel_started = 1;
+
+ ReadLengths(m_state.LENGTH_len, 0, LzxConstants.NUM_SECONDARY_LENGTHS, bitbuf);
+ MakeDecodeTable(LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
+ m_state.LENGTH_len, m_state.LENGTH_table);
+ break;
+
+ case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
+ m_state.intel_started = 1; /* because we can't assume otherwise */
+ bitbuf.EnsureBits(16); /* get up to 16 pad bits into the buffer */
+ if (bitbuf.GetBitsLeft() > 16) inData.Seek(-2, SeekOrigin.Current); /* and align the bitstream! */
+ byte hi, mh, ml, lo;
+ lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
+ R0 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
+ lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
+ R1 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
+ lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
+ R2 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
+ break;
+
+ default:
+ return -1; // TODO throw proper exception
+ }
+ }
+
+ /* buffer exhaustion check */
+ if (inData.Position > (startpos + inLen))
+ {
+ /* it's possible to have a file where the next run is less than
+ * 16 bits in size. In this case, the READ_HUFFSYM() macro used
+ * in building the tables will exhaust the buffer, so we should
+ * allow for this, but not allow those accidentally read bits to
+ * be used (so we check that there are at least 16 bits
+ * remaining - in this boundary case they aren't really part of
+ * the compressed data)
+ */
+ Console.WriteLine("WTF");
+ if (inData.Position > (startpos + inLen + 2) || bitbuf.GetBitsLeft() < 16) return -1; //TODO throw proper exception
+ }
+
+ while ((this_run = (int)m_state.block_remaining) > 0 && togo > 0)
+ {
+ if (this_run > togo) this_run = togo;
+ togo -= this_run;
+ m_state.block_remaining -= (uint)this_run;
+
+ /* apply 2^x-1 mask */
+ window_posn &= window_size - 1;
+ /* runs can't straddle the window wraparound */
+ if ((window_posn + this_run) > window_size)
+ return -1; //TODO throw proper exception
+
+ switch (m_state.block_type)
+ {
+ case LzxConstants.BLOCKTYPE.VERBATIM:
+ while (this_run > 0)
+ {
+ main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
+ LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
+ bitbuf);
+ if (main_element < LzxConstants.NUM_CHARS)
+ {
+ /* literal: 0 to NUM_CHARS-1 */
+ window[window_posn++] = (byte)main_element;
+ this_run--;
+ }
+ else
+ {
+ /* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
+ main_element -= LzxConstants.NUM_CHARS;
+
+ match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
+ if (match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
+ {
+ length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
+ LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
+ bitbuf);
+ match_length += length_footer;
+ }
+ match_length += LzxConstants.MIN_MATCH;
+
+ match_offset = main_element >> 3;
+
+ if (match_offset > 2)
+ {
+ /* not repeated offset */
+ if (match_offset != 3)
+ {
+ extra = extra_bits[match_offset];
+ verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
+ match_offset = (int)position_base[match_offset] - 2 + verbatim_bits;
+ }
+ else
+ {
+ match_offset = 1;
+ }
+
+ /* update repeated offset LRU queue */
+ R2 = R1; R1 = R0; R0 = (uint)match_offset;
+ }
+ else if (match_offset == 0)
+ {
+ match_offset = (int)R0;
+ }
+ else if (match_offset == 1)
+ {
+ match_offset = (int)R1;
+ R1 = R0; R0 = (uint)match_offset;
+ }
+ else /* match_offset == 2 */
+ {
+ match_offset = (int)R2;
+ R2 = R0; R0 = (uint)match_offset;
+ }
+
+ rundest = (int)window_posn;
+ this_run -= match_length;
+
+ /* copy any wrapped around source data */
+ if (window_posn >= match_offset)
+ {
+ /* no wrap */
+ runsrc = rundest - match_offset;
+ }
+ else
+ {
+ runsrc = rundest + ((int)window_size - match_offset);
+ copy_length = match_offset - (int)window_posn;
+ if (copy_length < match_length)
+ {
+ match_length -= copy_length;
+ window_posn += (uint)copy_length;
+ while (copy_length-- > 0) window[rundest++] = window[runsrc++];
+ runsrc = 0;
+ }
+ }
+ window_posn += (uint)match_length;
+
+ /* copy match data - no worries about destination wraps */
+ while (match_length-- > 0) window[rundest++] = window[runsrc++];
+ }
+ }
+ break;
+
+ case LzxConstants.BLOCKTYPE.ALIGNED:
+ while (this_run > 0)
+ {
+ main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
+ LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
+ bitbuf);
+
+ if (main_element < LzxConstants.NUM_CHARS)
+ {
+ /* literal 0 to NUM_CHARS-1 */
+ window[window_posn++] = (byte)main_element;
+ this_run--;
+ }
+ else
+ {
+ /* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
+ main_element -= LzxConstants.NUM_CHARS;
+
+ match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
+ if (match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
+ {
+ length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
+ LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
+ bitbuf);
+ match_length += length_footer;
+ }
+ match_length += LzxConstants.MIN_MATCH;
+
+ match_offset = main_element >> 3;
+
+ if (match_offset > 2)
+ {
+ /* not repeated offset */
+ extra = extra_bits[match_offset];
+ match_offset = (int)position_base[match_offset] - 2;
+ if (extra > 3)
+ {
+ /* verbatim and aligned bits */
+ extra -= 3;
+ verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
+ match_offset += (verbatim_bits << 3);
+ aligned_bits = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
+ LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
+ bitbuf);
+ match_offset += aligned_bits;
+ }
+ else if (extra == 3)
+ {
+ /* aligned bits only */
+ aligned_bits = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
+ LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
+ bitbuf);
+ match_offset += aligned_bits;
+ }
+ else if (extra > 0) /* extra==1, extra==2 */
+ {
+ /* verbatim bits only */
+ verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
+ match_offset += verbatim_bits;
+ }
+ else /* extra == 0 */
+ {
+ /* ??? */
+ match_offset = 1;
+ }
+
+ /* update repeated offset LRU queue */
+ R2 = R1; R1 = R0; R0 = (uint)match_offset;
+ }
+ else if (match_offset == 0)
+ {
+ match_offset = (int)R0;
+ }
+ else if (match_offset == 1)
+ {
+ match_offset = (int)R1;
+ R1 = R0; R0 = (uint)match_offset;
+ }
+ else /* match_offset == 2 */
+ {
+ match_offset = (int)R2;
+ R2 = R0; R0 = (uint)match_offset;
+ }
+
+ rundest = (int)window_posn;
+ this_run -= match_length;
+
+ /* copy any wrapped around source data */
+ if (window_posn >= match_offset)
+ {
+ /* no wrap */
+ runsrc = rundest - match_offset;
+ }
+ else
+ {
+ runsrc = rundest + ((int)window_size - match_offset);
+ copy_length = match_offset - (int)window_posn;
+ if (copy_length < match_length)
+ {
+ match_length -= copy_length;
+ window_posn += (uint)copy_length;
+ while (copy_length-- > 0) window[rundest++] = window[runsrc++];
+ runsrc = 0;
+ }
+ }
+ window_posn += (uint)match_length;
+
+ /* copy match data - no worries about destination wraps */
+ while (match_length-- > 0) window[rundest++] = window[runsrc++];
+ }
+ }
+ break;
+
+ case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
+ if ((inData.Position + this_run) > endpos) return -1; //TODO throw proper exception
+ byte[] temp_buffer = new byte[this_run];
+ inData.Read(temp_buffer, 0, this_run);
+ temp_buffer.CopyTo(window, window_posn);
+ window_posn += (uint)this_run;
+ break;
+
+ default:
+ return -1; //TODO throw proper exception
+ }
+ }
+ }
+
+ if (togo != 0) return -1; //TODO throw proper exception
+ int start_window_pos = (int)window_posn;
+ if (start_window_pos == 0) start_window_pos = (int)window_size;
+ start_window_pos -= outLen;
+ outData.Write(window, start_window_pos, outLen);
+
+ m_state.window_posn = window_posn;
+ m_state.R0 = R0;
+ m_state.R1 = R1;
+ m_state.R2 = R2;
+
+ // TODO finish intel E8 decoding
+ /* intel E8 decoding */
+ if ((m_state.frames_read++ < 32768) && m_state.intel_filesize != 0)
+ {
+ if (outLen <= 6 || m_state.intel_started == 0)
+ {
+ m_state.intel_curpos += outLen;
+ }
+ else
+ {
+ int dataend = outLen - 10;
+ uint curpos = (uint)m_state.intel_curpos;
+ uint filesize = (uint)m_state.intel_filesize;
+ uint abs_off, rel_off;
+
+ m_state.intel_curpos = (int)curpos + outLen;
+
+ while (outData.Position < dataend)
+ {
+ if (outData.ReadByte() != 0xE8) { curpos++; continue; }
+ //abs_off =
+ }
+ }
+ return -1;
+ }
+ return 0;
+ }
+
+ // READ_LENGTHS(table, first, last)
+ // if(lzx_read_lens(LENTABLE(table), first, last, bitsleft))
+ // return ERROR (ILLEGAL_DATA)
+ //
+
+ // TODO make returns throw exceptions
+ private int MakeDecodeTable(uint nsyms, uint nbits, byte[] length, ushort[] table)
+ {
+ ushort sym;
+ uint leaf;
+ byte bit_num = 1;
+ uint fill;
+ uint pos = 0; /* the current position in the decode table */
+ uint table_mask = (uint)(1 << (int)nbits);
+ uint bit_mask = table_mask >> 1; /* don't do 0 length codes */
+ uint next_symbol = bit_mask; /* base of allocation for long codes */
+
+ /* fill entries for codes short enough for a direct mapping */
+ while (bit_num <= nbits)
+ {
+ for (sym = 0; sym < nsyms; sym++)
+ {
+ if (length[sym] == bit_num)
+ {
+ leaf = pos;
+
+ if ((pos += bit_mask) > table_mask) return 1; /* table overrun */
+
+ /* fill all possible lookups of this symbol with the symbol itself */
+ fill = bit_mask;
+ while (fill-- > 0) table[leaf++] = sym;
+ }
+ }
+ bit_mask >>= 1;
+ bit_num++;
+ }
+
+ /* if there are any codes longer than nbits */
+ if (pos != table_mask)
+ {
+ /* clear the remainder of the table */
+ for (sym = (ushort)pos; sym < table_mask; sym++) table[sym] = 0;
+
+ /* give ourselves room for codes to grow by up to 16 more bits */
+ pos <<= 16;
+ table_mask <<= 16;
+ bit_mask = 1 << 15;
+
+ while (bit_num <= 16)
+ {
+ for (sym = 0; sym < nsyms; sym++)
+ {
+ if (length[sym] == bit_num)
+ {
+ leaf = pos >> 16;
+ for (fill = 0; fill < bit_num - nbits; fill++)
+ {
+ /* if this path hasn't been taken yet, 'allocate' two entries */
+ if (table[leaf] == 0)
+ {
+ table[(next_symbol << 1)] = 0;
+ table[(next_symbol << 1) + 1] = 0;
+ table[leaf] = (ushort)(next_symbol++);
+ }
+ /* follow the path and select either left or right for next bit */
+ leaf = (uint)(table[leaf] << 1);
+ if (((pos >> (int)(15 - fill)) & 1) == 1) leaf++;
+ }
+ table[leaf] = sym;
+
+ if ((pos += bit_mask) > table_mask) return 1;
+ }
+ }
+ bit_mask >>= 1;
+ bit_num++;
+ }
+ }
+
+ /* full talbe? */
+ if (pos == table_mask) return 0;
+
+ /* either erroneous table, or all elements are 0 - let's find out. */
+ for (sym = 0; sym < nsyms; sym++) if (length[sym] != 0) return 1;
+ return 0;
+ }
+
+ // TODO throw exceptions instead of returns
+ private void ReadLengths(byte[] lens, uint first, uint last, BitBuffer bitbuf)
+ {
+ uint x, y;
+ int z;
+
+ // hufftbl pointer here?
+
+ for (x = 0; x < 20; x++)
+ {
+ y = bitbuf.ReadBits(4);
+ m_state.PRETREE_len[x] = (byte)y;
+ }
+ MakeDecodeTable(LzxConstants.PRETREE_MAXSYMBOLS, LzxConstants.PRETREE_TABLEBITS,
+ m_state.PRETREE_len, m_state.PRETREE_table);
+
+ for (x = first; x < last; )
+ {
+ z = (int)ReadHuffSym(m_state.PRETREE_table, m_state.PRETREE_len,
+ LzxConstants.PRETREE_MAXSYMBOLS, LzxConstants.PRETREE_TABLEBITS, bitbuf);
+ if (z == 17)
+ {
+ y = bitbuf.ReadBits(4); y += 4;
+ while (y-- != 0) lens[x++] = 0;
+ }
+ else if (z == 18)
+ {
+ y = bitbuf.ReadBits(5); y += 20;
+ while (y-- != 0) lens[x++] = 0;
+ }
+ else if (z == 19)
+ {
+ y = bitbuf.ReadBits(1); y += 4;
+ z = (int)ReadHuffSym(m_state.PRETREE_table, m_state.PRETREE_len,
+ LzxConstants.PRETREE_MAXSYMBOLS, LzxConstants.PRETREE_TABLEBITS, bitbuf);
+ z = lens[x] - z; if (z < 0) z += 17;
+ while (y-- != 0) lens[x++] = (byte)z;
+ }
+ else
+ {
+ z = lens[x] - z; if (z < 0) z += 17;
+ lens[x++] = (byte)z;
+ }
+ }
+ }
+
+ private uint ReadHuffSym(ushort[] table, byte[] lengths, uint nsyms, uint nbits, BitBuffer bitbuf)
+ {
+ uint i, j;
+ bitbuf.EnsureBits(16);
+ if ((i = table[bitbuf.PeekBits((byte)nbits)]) >= nsyms)
+ {
+ j = (uint)(1 << (int)((sizeof(uint) * 8) - nbits));
+ do
+ {
+ j >>= 1; i <<= 1; i |= (bitbuf.GetBuffer() & j) != 0 ? (uint)1 : 0;
+ if (j == 0) return 0; // TODO throw proper exception
+ } while ((i = table[i]) >= nsyms);
+ }
+ j = lengths[i];
+ bitbuf.RemoveBits((byte)j);
+
+ return i;
+ }
+
+ #region Our BitBuffer Class
+ private class BitBuffer
+ {
+ uint buffer;
+ byte bitsleft;
+ Stream byteStream;
+
+ public BitBuffer(Stream stream)
+ {
+ byteStream = stream;
+ InitBitStream();
+ }
+
+ public void InitBitStream()
+ {
+ buffer = 0;
+ bitsleft = 0;
+ }
+
+ public void EnsureBits(byte bits)
+ {
+ while (bitsleft < bits)
+ {
+ int lo = (byte)byteStream.ReadByte();
+ int hi = (byte)byteStream.ReadByte();
+ int amount2shift = sizeof(uint) * 8 - 16 - bitsleft;
+ buffer |= (uint)(((hi << 8) | lo) << (sizeof(uint) * 8 - 16 - bitsleft));
+ bitsleft += 16;
+ }
+ }
+
+ public uint PeekBits(byte bits)
+ {
+ return (buffer >> ((sizeof(uint) * 8) - bits));
+ }
+
+ public void RemoveBits(byte bits)
+ {
+ buffer <<= bits;
+ bitsleft -= bits;
+ }
+
+ public uint ReadBits(byte bits)
+ {
+ uint ret = 0;
+
+ if (bits > 0)
+ {
+ EnsureBits(bits);
+ ret = PeekBits(bits);
+ RemoveBits(bits);
+ }
+
+ return ret;
+ }
+
+ public uint GetBuffer()
+ {
+ return buffer;
+ }
+
+ public byte GetBitsLeft()
+ {
+ return bitsleft;
+ }
+ }
+ #endregion
+
+ struct LzxState
+ {
+ public uint R0, R1, R2; /* for the LRU offset system */
+ public ushort main_elements; /* number of main tree elements */
+ public int header_read; /* have we started decoding at all yet? */
+ public LzxConstants.BLOCKTYPE block_type; /* type of this block */
+ public uint block_length; /* uncompressed length of this block */
+ public uint block_remaining; /* uncompressed bytes still left to decode */
+ public uint frames_read; /* the number of CFDATA blocks processed */
+ public int intel_filesize; /* magic header value used for transform */
+ public int intel_curpos; /* current offset in transform space */
+ public int intel_started; /* have we seen any translateable data yet? */
+
+ public ushort[] PRETREE_table;
+ public byte[] PRETREE_len;
+ public ushort[] MAINTREE_table;
+ public byte[] MAINTREE_len;
+ public ushort[] LENGTH_table;
+ public byte[] LENGTH_len;
+ public ushort[] ALIGNED_table;
+ public byte[] ALIGNED_len;
+
+ // NEEDED MEMBERS
+ // CAB actualsize
+ // CAB window
+ // CAB window_size
+ // CAB window_posn
+ public uint actual_size;
+ public byte[] window;
+ public uint window_size;
+ public uint window_posn;
+ }
+ }
+
+ /* CONSTANTS */
+ internal struct LzxConstants
+ {
+ public const ushort MIN_MATCH = 2;
+ public const ushort MAX_MATCH = 257;
+ public const ushort NUM_CHARS = 256;
+ public enum BLOCKTYPE
+ {
+ INVALID = 0,
+ VERBATIM = 1,
+ ALIGNED = 2,
+ UNCOMPRESSED = 3
+ }
+ public const ushort PRETREE_NUM_ELEMENTS = 20;
+ public const ushort ALIGNED_NUM_ELEMENTS = 8;
+ public const ushort NUM_PRIMARY_LENGTHS = 7;
+ public const ushort NUM_SECONDARY_LENGTHS = 249;
+
+ public const ushort PRETREE_MAXSYMBOLS = PRETREE_NUM_ELEMENTS;
+ public const ushort PRETREE_TABLEBITS = 6;
+ public const ushort MAINTREE_MAXSYMBOLS = NUM_CHARS + 50 * 8;
+ public const ushort MAINTREE_TABLEBITS = 12;
+ public const ushort LENGTH_MAXSYMBOLS = NUM_SECONDARY_LENGTHS + 1;
+ public const ushort LENGTH_TABLEBITS = 12;
+ public const ushort ALIGNED_MAXSYMBOLS = ALIGNED_NUM_ELEMENTS;
+ public const ushort ALIGNED_TABLEBITS = 7;
+
+ public const ushort LENTABLE_SAFETY = 64;
+ }
+
+ /* EXCEPTIONS */
+ public class UnsupportedWindowSizeRange : Exception
+ {
+ }
+}
\ No newline at end of file