private static void DecodeNibbleRun(UInt8InputBitStream inputBits, UInt8OutputBitStream outputBits, byte count, byte nibble, ref int bitsWritten) { bitsWritten += count * 4; // Write single nibble, if needed if ((count & 1) != 0) { outputBits.Write(nibble, 4); } // Write pairs of nibbles count >>= 1; nibble |= (byte)(nibble << 4); while (count-- != 0) { outputBits.Write(nibble, 8); } }
private static void Decode(Stream input, Stream output, long size) { long end = input.Position + size; UInt8InputBitStream bitStream = new UInt8InputBitStream(input); List <byte> outputBuffer = new List <byte>(); while (input.Position < end) { if (bitStream.Unshift()) { if (input.Position >= end) { break; } outputBuffer.Add(NeutralEndian.Read1(input)); } else { if (input.Position >= end) { break; } ushort offset = NeutralEndian.Read1(input); if (input.Position >= end) { break; } byte count = NeutralEndian.Read1(input); // We've just read 2 bytes: %llllllll %hhhhcccc // offset = %hhhhllllllll + 0x12, count = %cccc + 3 offset |= (ushort)((count & 0xF0) << 4); offset += 0x12; offset |= (ushort)(outputBuffer.Count & 0xF000); count &= 0xf; count += 3; if (offset >= outputBuffer.Count) { offset -= 0x1000; } outputBuffer.AddRange(new byte[count]); if (offset < outputBuffer.Count) { for (int sourceIndex = offset, destinationIndex = outputBuffer.Count - count; destinationIndex < outputBuffer.Count; sourceIndex++, destinationIndex++) { outputBuffer[destinationIndex] = outputBuffer[sourceIndex]; } } } } byte[] bytes = outputBuffer.ToArray(); output.Write(bytes, 0, bytes.Length); }
private static void DecodeInternal(Stream input, Stream output, DecodingCodeTreeNode codeTree, ushort numberOfTiles, bool xorOutput) { UInt8InputBitStream inputBits = new UInt8InputBitStream(input); UInt8OutputBitStream outputBits; XorStream xorStream = null; try { if (xorOutput) { xorStream = new XorStream(output); outputBits = new UInt8OutputBitStream(xorStream); } else { outputBits = new UInt8OutputBitStream(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(); } } }