private static void DecodeHeader(Stream input, Stream output, DecodingCodeTreeNode codeTree) { byte outputValue = 0; byte inputValue; // Loop until a byte with value 0xFF is encountered while ((inputValue = NeutralEndian.Read1(input)) != 0xFF) { if ((inputValue & 0x80) != 0) { outputValue = (byte)(inputValue & 0xF); inputValue = NeutralEndian.Read1(input); } codeTree.SetCode( NeutralEndian.Read1(input), inputValue & 0xF, new NibbleRun(outputValue, (byte)(((inputValue & 0x70) >> 4) + 1))); } // Store a special nibble run for inline RLE sequences (code = 0b111111, length = 6) // Length = 0xFF in the nibble run is just a marker value that will be handled specially in DecodeInternal codeTree.SetCode(0x3F, 6, new NibbleRun(0, 0xFF)); }
private static void DecodeInternal(Stream input, Stream output, DecodingCodeTreeNode codeTree, ushort numberOfTiles, bool xorOutput) { UInt8_E_L_InputBitStream inputBits = new UInt8_E_L_InputBitStream(input); UInt8_E_L_OutputBitStream outputBits; XorStream xorStream = null; try { if (xorOutput) { xorStream = new XorStream(output); outputBits = new UInt8_E_L_OutputBitStream(xorStream); } else { outputBits = new UInt8_E_L_OutputBitStream(output); } // The output is: number of tiles * 0x20 (1 << 5) bytes per tile * 8 (1 << 3) bits per byte int outputSize = numberOfTiles << 8; // in bits int bitsWritten = 0; DecodingCodeTreeNode currentNode = codeTree; while (bitsWritten < outputSize) { NibbleRun nibbleRun = currentNode.NibbleRun; if (nibbleRun.Count == 0xFF) { // Bit pattern 0b111111; inline RLE. // First 3 bits are repetition count, followed by the inlined nibble. byte count = (byte)(inputBits.Read(3) + 1); byte nibble = inputBits.Read(4); DecodeNibbleRun(inputBits, outputBits, count, nibble, ref bitsWritten); currentNode = codeTree; } else if (nibbleRun.Count != 0) { // Output the encoded nibble run DecodeNibbleRun(inputBits, outputBits, nibbleRun.Count, nibbleRun.Nibble, ref bitsWritten); currentNode = codeTree; } else { // Read the next bit and go down one level in the tree currentNode = currentNode[inputBits.Get()]; if (currentNode == null) { throw new CompressionException(Properties.Resources.InvalidCode); } } } outputBits.Flush(false); } finally { if (xorStream != null) { xorStream.Dispose(); } } }