private void HandleZeroCompressedBlock(Stream input, Stream output) { var byte1 = input.ReadByte(); var byte2 = input.ReadByte(); var length = (byte2 >> 4) + 3; var displacement = (((byte2 & 0x0F) << 8) | byte1) + 5; _circularBuffer.Copy(output, displacement, length); }
private void ReadMatchStart(Stream input, Stream output, byte flag) { // Min length: 4, Max length: 7 // Min disp: 0, Max disp: 0x1FFF var length = ((flag >> 5) & 0x3) + 4; _displacement = (flag & 0x1F) << 8; _displacement |= input.ReadByte(); _circularBuffer.Copy(output, _displacement, length); }
private void ReadCompressedData(BitReader br, Stream output, CircularBuffer circularBuffer, TaikoLz81Tree dispIndexMapping, int index) { // Max displacement 0x8000; Min displacement 2 // Max length 0x102; Min length 1 var length = _counters[index]; if (_counterBitReads[index] != 0) { length += br.ReadBits <int>(_counterBitReads[index]); } var dispIndex = dispIndexMapping.ReadValue(br); var displacement = _dispRanges[dispIndex]; if (_dispBitReads[dispIndex] != 0) { displacement += br.ReadBits <int>(_dispBitReads[dispIndex]); } if (length == 0) { return; } circularBuffer.Copy(output, displacement, length); }
private void HandleCompressedBlock(Stream input, Stream output) { // A compressed block starts with 2 bytes; if there are there < 2 bytes left, throw error if (input.Length - input.Position < 2) { throw new StreamTooShortException(); } var byte1 = (byte)input.ReadByte(); var byte2 = (byte)input.ReadByte(); int length, displacement; if (byte1 >> 4 == 0) // 0000 { (length, displacement) = HandleZeroCompressedBlock(byte1, byte2, input, output); } else if (byte1 >> 4 == 1) // 0001 { (length, displacement) = HandleOneCompressedBlock(byte1, byte2, input, output); } else // >= 0010 { (length, displacement) = HandleRemainingCompressedBlock(byte1, byte2, input, output); } _circularBuffer.Copy(output, displacement, length); }
public void Decode(Stream input, Stream output) { var buffer = new byte[4]; input.Read(buffer, 0, 4); if (!buffer.SequenceEqual(new byte[] { 0x59, 0x61, 0x7a, 0x30 })) { throw new InvalidCompressionException("Yaz0" + (_byteOrder == ByteOrder.LittleEndian ? "LE" : "BE")); } input.Read(buffer, 0, 4); var uncompressedLength = _byteOrder == ByteOrder.LittleEndian ? buffer.GetInt32LittleEndian(0) : buffer.GetInt32BigEndian(0); input.Position += 0x8; var circularBuffer = new CircularBuffer(0x1000); var codeBlock = input.ReadByte(); var codeBlockPosition = 8; while (output.Length < uncompressedLength) { if (codeBlockPosition == 0) { codeBlockPosition = 8; codeBlock = input.ReadByte(); } var flag = (codeBlock >> --codeBlockPosition) & 0x1; if (flag == 1) { // Flag for uncompressed byte var value = (byte)input.ReadByte(); output.WriteByte(value); circularBuffer.WriteByte(value); } else { var firstByte = input.ReadByte(); var secondByte = input.ReadByte(); var length = firstByte >> 4; if (length > 0) { length += 2; } else { // Yes, we do read the length from the uncompressed data stream length = input.ReadByte() + 0x12; } var displacement = (((firstByte & 0xF) << 8) | secondByte) + 1; circularBuffer.Copy(output, displacement, length); } } }
private void HandleCompressedBlock(Stream input, Stream output, CircularBuffer circularBuffer) { // A compressed block starts with 2 bytes; if there are there < 2 bytes left, throw error if (input.Length - input.Position < 2) { throw new StreamTooShortException(); } var byte1 = (byte)input.ReadByte(); var byte2 = (byte)input.ReadByte(); int displacement = (byte2 << 4) | (byte1 >> 4); // max 0xFFF if (displacement > output.Length) { throw new DisplacementException(displacement, output.Length, input.Position - 2); } int length; if ((byte1 & 0xF) == 0) // 0000 { length = HandleZeroCompressedBlock(input); } else if ((byte1 & 0xF) == 1) // 0001 { length = HandleOneCompressedBlock(input); } else // >= 0010 { length = byte1 & 0xF; } circularBuffer.Copy(output, displacement, length); }
private void ReadMatchContinue(Stream output, CircularBuffer circularBuffer, byte flag, int previousDisplacement) { // Min length: 0, Max length: 0x1F var length = flag & 0x1F; circularBuffer.Copy(output, previousDisplacement, length); }
public void Decode(Stream input, Stream output) { var buffer = new byte[4]; input.Read(buffer, 0, 4); if (Encoding.ASCII.GetString(buffer) != "Wp16") { throw new InvalidOperationException("Not Wp16 compressed."); } input.Read(buffer, 0, 4); var decompressedSize = buffer.GetInt32LittleEndian(0); var circularBuffer = new CircularBuffer(0xFFE) { Position = PreBufferSize_ }; long flags = 0; var flagPosition = 32; while (output.Length < decompressedSize) { if (flagPosition == 32) { input.Read(buffer, 0, 4); flags = buffer.GetInt32LittleEndian(0); flagPosition = 0; } if (((flags >> flagPosition++) & 0x1) == 1) { // Copy 2 bytes from input var value = (byte)input.ReadByte(); output.WriteByte(value); circularBuffer.WriteByte(value); value = (byte)input.ReadByte(); output.WriteByte(value); circularBuffer.WriteByte(value); } else { // Read the Lz match // min displacement 2, max displacement 0xFFE // min length 2, max length 0x42 var byte1 = input.ReadByte(); var byte2 = input.ReadByte(); var displacement = (byte2 << 3) | (byte1 >> 5); var length = (byte1 & 0x1F) + 2; circularBuffer.Copy(output, displacement * 2, length * 2); } } }
private void HandleOneCompressedBlock(Stream input, Stream output, CircularBuffer circularBuffer) { var byte1 = input.ReadByte(); var length = (byte1 >> 2) + 2; var displacement = (byte1 & 0x3) + 1; circularBuffer.Copy(output, displacement, length); }
public void Decode(Stream input, Stream output) { var inputStartPosition = input.Position; var buffer = new byte[4]; input.Read(buffer, 0, 4); if (!buffer.SequenceEqual(new byte[] { 0x4d, 0x49, 0x4f, 0x30 })) { throw new InvalidCompressionException("MIO0" + (_byteOrder == ByteOrder.LittleEndian ? "LE" : "BE")); } input.Read(buffer, 0, 4); var uncompressedLength = _byteOrder == ByteOrder.LittleEndian ? buffer.GetInt32LittleEndian(0) : buffer.GetInt32BigEndian(0); input.Read(buffer, 0, 4); var compressedTableOffset = _byteOrder == ByteOrder.LittleEndian ? buffer.GetInt32LittleEndian(0) : buffer.GetInt32BigEndian(0); input.Read(buffer, 0, 4); var uncompressedTableOffset = _byteOrder == ByteOrder.LittleEndian ? buffer.GetInt32LittleEndian(0) : buffer.GetInt32BigEndian(0); _circularBuffer = new CircularBuffer(0x1000); var compressedTablePosition = 0; var uncompressedTablePosition = 0; var bitLayout = new byte[compressedTableOffset - 0x10]; input.Read(bitLayout, 0, bitLayout.Length); using (var bitReader = new BitReader(new MemoryStream(bitLayout), BitOrder.MsbFirst, 1, ByteOrder.BigEndian)) { while (output.Length < uncompressedLength) { if (bitReader.ReadBit() == 1) { // Flag for uncompressed byte input.Position = inputStartPosition + uncompressedTableOffset + uncompressedTablePosition++; var value = (byte)input.ReadByte(); output.WriteByte(value); _circularBuffer.WriteByte(value); } else { // Flag for compressed data input.Position = inputStartPosition + compressedTableOffset + compressedTablePosition; var firstByte = input.ReadByte(); var secondByte = input.ReadByte(); compressedTablePosition += 2; var length = (firstByte >> 4) + 3; var displacement = (((firstByte & 0xF) << 8) | secondByte) + 1; _circularBuffer.Copy(output, displacement, length); } } } }
private void ReadOneCompressedData(Stream output, CircularBuffer circularBuffer, int code) { // 8 bits // 11 11 1111 var length = ((code >> 4) & 0x3) + 2; var displacement = (code & 0xF) + 1; circularBuffer.Copy(output, displacement, length); }
private void HandleCompressedBlock(Stream input, Stream output, CircularBuffer circularBuffer) { var byte1 = input.ReadByte(); var byte2 = input.ReadByte(); var length = (byte1 >> 4) + 3; var displacement = (((byte1 & 0xF) << 8) | byte2) + 3; circularBuffer.Copy(output, displacement, length); }
private void ReadTwoCompressedData(Stream input, Stream output, CircularBuffer circularBuffer, int code) { // 16 bits // 11 1111 1111111111 var byte1 = input.ReadByte(); var length = ((code >> 2) & 0xF) + 3; var displacement = (((code & 0x3) << 8) | byte1) + 1; circularBuffer.Copy(output, displacement, length); }
private void ReadThreeCompressedData(Stream input, Stream output, CircularBuffer circularBuffer, int code) { // 24 bits // 11 1111111 111111111111111 var byte1 = input.ReadByte(); var byte2 = input.ReadByte(); var length = (((code & 0x3F) << 1) | (byte1 >> 7)) + 4; var displacement = (((byte1 & 0x7F) << 8) | byte2) + 1; circularBuffer.Copy(output, displacement, length); }
public void Decode(Stream input, Stream output) { int decompSize = 0; while (input.Position < input.Length && !IsLastBlock(decompSize)) { var blockPosition = input.Position; var circularBuffer = new CircularBuffer(0xFFFF); // Read block sizes var compSize = ReadBlockSizes(input, out decompSize); while (input.Position < blockPosition + 8 + compSize) { var token = input.ReadByte(); var literalLength = token >> 4; var matchLength = token & 0xF; // Expand literal length token = literalLength == 0xF ? 0xFF : 0; while (token == 0xFF) { token = input.ReadByte(); literalLength += token; } // Read literals var literalBuffer = new byte[literalLength]; input.Read(literalBuffer, 0, literalLength); output.Write(literalBuffer, 0, literalLength); circularBuffer.Write(literalBuffer, 0, literalLength); if (input.Position >= blockPosition + 8 + compSize) continue; // Read displacement var byte1 = input.ReadByte(); var displacement = (input.ReadByte() << 8) | byte1; // Expand match length token = matchLength == 0xF ? 0xFF : 0; while (token == 0xFF) { token = input.ReadByte(); matchLength += token; } // Read match copy circularBuffer.Copy(output, displacement, matchLength + 4); } } }
private int ReadMatchStart(Stream input, Stream output, CircularBuffer circularBuffer, byte flag) { // Min length: 4, Max length: 7 // Min disp: 0, Max disp: 0x1FFF var length = ((flag >> 5) & 0x3) + 4; var displacement = (flag & 0x1F) << 8; displacement |= input.ReadByte(); circularBuffer.Copy(output, displacement, length); return(displacement); }
public void Decode(Stream input, Stream output, int decompressedSize) { var circularBuffer = new CircularBuffer(0x1000) { Position = PreBufferSize_ }; var flags = 0; var flagPosition = 8; while (output.Length < decompressedSize) { if (flagPosition == 8) { flagPosition = 0; flags = input.ReadByte(); } if (((flags >> flagPosition++) & 0x1) == 1) { // raw data var value = (byte)input.ReadByte(); output.WriteByte(value); circularBuffer.WriteByte(value); } else { // compressed data var byte1 = input.ReadByte(); var byte2 = input.ReadByte(); var length = (byte2 & 0xF) + 3; var bufferPosition = byte1 | ((byte2 & 0xF0) << 4); // Convert buffer position to displacement var displacement = (circularBuffer.Position - bufferPosition) % circularBuffer.Length; displacement = (displacement + circularBuffer.Length) % circularBuffer.Length; if (displacement == 0) { displacement = 0x1000; } circularBuffer.Copy(output, displacement, length); } } }
private bool ReadSubLoopMatch(Stream input, Stream output, CircularBuffer circularBuffer, out byte codeByte) { // Read LZ match codeByte = (byte)input.ReadByte(); if (codeByte > 0xF) { input.Position--; return(true); } var codeByte2 = (byte)input.ReadByte(); var displacement = ((codeByte2 << 2) | (codeByte >> 2)) + 0x801; circularBuffer.Copy(output, displacement, 3); return(false); }
private void HandleCompressedBlock(BitReader br, Stream output, CircularBuffer circularBuffer) { var displacement = br.ReadByte(); var length = br.ReadByte(); var nextByte = (byte)br.ReadByte(); circularBuffer.Copy(output, displacement, length); // If an occurrence goes until the end of the file, 'next' still exists // In this case, 'next' shouldn't be written to the file // but there is no indicator if this symbol has to be written or not // According to Kuriimu, I once implemented a 0x24 static symbol for some reason // Maybe 'next' is 0x24 if an occurrence goes directly until the end of a file? // TODO: Fix overflowing symbol // HINT: Look at Kuriimu issue 517 and see if the used compression is this one output.WriteByte(nextByte); circularBuffer.WriteByte(nextByte); }
public void Decode(Stream input, Stream output) { using var br = new BinaryReaderX(input, true); var header = br.ReadType <CrilaylaHeader>(); if (header.magic != "CRILAYLA" || header.magic == "\0\0\0\0\0\0\0\0") { throw new InvalidCompressionException("Crilayla"); } // Copy raw part input.Position = input.Length - RawSize_; output.Write(br.ReadBytes(RawSize_), 0, RawSize_); // Decompress var compStream = new SubStream(input, 0x10, input.Length - RawSize_ - 0x10); var reverseCompStream = new ReverseStream(compStream, compStream.Length); var reverseOutputStream = new ReverseStream(output, header.decompSize + RawSize_); var circularBuffer = new CircularBuffer(0x2002); using var reverseBr = new BinaryReaderX(reverseCompStream, ByteOrder.LittleEndian, BitOrder.MostSignificantBitFirst, 1); while (reverseOutputStream.Position < reverseOutputStream.Length - RawSize_) { if (!reverseBr.ReadBit()) { var value = reverseBr.ReadBits <byte>(8); reverseOutputStream.WriteByte(value); circularBuffer.WriteByte(value); continue; } var displacement = reverseBr.ReadBits <short>(13) + 3; var length = ReadLength(reverseBr) + 3; circularBuffer.Copy(reverseOutputStream, displacement, length); } }
public void Decode(Stream input, Stream output) { var circularBuffer = new CircularBuffer(0x400) { Position = PreBufferSize_ }; var flagPosition = 0; var flag = 0; while (input.Position < input.Length) { if (flagPosition == 0) { flag = input.ReadByte(); flagPosition = 8; } if ((flag >> --flagPosition & 1) == 1) { // Read raw value var value = (byte)input.ReadByte(); circularBuffer.WriteByte(value); output.WriteByte(value); } else { // Read match var value = input.ReadByte() | (input.ReadByte() << 8); var length = (value >> 10) + 2; var displacement = 0x400 - (value & 0x3FF); circularBuffer.Copy(output, displacement, length); } } }
private void HandleCompressedBlock(Stream input, Stream output, CircularBuffer circularBuffer) { // A compressed block starts with 2 bytes; if there are there < 2 bytes left, throw error if (input.Length - input.Position < 2) { throw new StreamTooShortException(); } var byte1 = input.ReadByte(); var byte2 = input.ReadByte(); // The number of bytes to copy var length = (byte2 >> 4) + 2; // From where the bytes should be copied (relatively) var displacement = (((byte2 & 0x0F) << 8) | byte1) + 1; if (displacement > output.Length) { throw new DisplacementException(displacement, output.Length, input.Position - 2); } circularBuffer.Copy(output, displacement, length); }
private void MainLoop(Stream input, Stream output) { while (true) { _codeByte = (byte)input.ReadByte(); if (_codeByte >= 0x40) { var byte2 = (byte)input.ReadByte(); // 11 bit displacement // Min disp: 0x1; Max disp: 0x800 // Min length: 3; Max length: 8 var displacement = ((_codeByte >> 2) & 0x7) + (byte2 << 3) + 1; var length = (_codeByte >> 5) + 1; _circularBuffer.Copy(output, displacement, length); } else if (_codeByte >= 0x20) { // 14 bit displacement // Min disp: 1; Max disp: 0x4000 // Min length: 2; Max length: virtually infinite var length = _codeByte & 0x1F; if (length == 0) { length += ReadVariableLength(input, 5); } length += 2; _codeByte = (byte)input.ReadByte(); var byte2 = (byte)input.ReadByte(); var displacement = (_codeByte >> 2) + (byte2 << 6) + 1; _circularBuffer.Copy(output, displacement, length); } else if (_codeByte >= 0x10) { // 14 bit displacement // Min disp: 0x4001; Max disp: 0xBFFF // Min length: 2; Max length: virtually infinite var length = _codeByte & 0x7; if (length == 0) { length += ReadVariableLength(input, 3); } length += 2; var sign = _codeByte & 0x8; _codeByte = (byte)input.ReadByte(); var byte2 = (byte)input.ReadByte(); if (sign == 0 && _codeByte >> 2 == 0 && byte2 == 0) { // End of decompression break; } var displacement = (_codeByte >> 2) + (byte2 << 6) + (sign > 0 ? 0x4000 : 0) + 0x4000; _circularBuffer.Copy(output, displacement, length); } else { // 10 bit displacement // Min disp: 1; Max disp: 0x400 // Min length: 2; Max length: 2 var byte2 = (byte)input.ReadByte(); var displacement = ((byte2 << 2) | (_codeByte >> 2)) + 1; _circularBuffer.Copy(output, displacement, 2); } SubLoop(input, output); } }
public void Decode(Stream input, Stream output) { _circularBuffer = new CircularBuffer(0xFFFF); int mode; while ((mode = input.ReadByte()) != 0xFF) { var length = mode & 0x1F; if (length == 0) { length = ReadInt16Le(input); } var buffer = new byte[length]; switch (mode >> 5) { // Raw bytes case 0: input.Read(buffer, 0, length); output.Write(buffer, 0, length); _circularBuffer.Write(buffer, 0, length); break; // 0-only RLE case 1: output.Write(buffer, 0, length); _circularBuffer.Write(buffer, 0, length); break; // Variable value RLE case 2: var value = (byte)input.ReadByte(); for (var i = 0; i < length; i++) { buffer[i] = value; } output.Write(buffer, 0, length); _circularBuffer.Write(buffer, 0, length); break; // 1-byte displacement LZ case 3: var offset = input.ReadByte(); _circularBuffer.Copy(output, offset, length); break; // 2-byte displacement LZ case 4: var offset1 = ReadInt16Le(input); _circularBuffer.Copy(output, offset1, length); break; // 2-byte RLE 0-discarding case 5: buffer = new byte[length * 2]; for (var i = 0; i < length; i++) { buffer[i * 2] = (byte)input.ReadByte(); } output.Write(buffer, 0, buffer.Length); _circularBuffer.Write(buffer, 0, buffer.Length); break; default: throw new InvalidOperationException($"Unknown mode {mode >> 5} in PsLz at position 0x{input.Position:X8}."); } } }
public void Decode(Stream input, Stream output) { if (input.ReadByte() != 0x01) { throw new InvalidOperationException("This is not a tales of compression with version 1."); } var buffer = new byte[4]; input.Read(buffer, 0, 4); var compressedDataSize = GetLittleEndian(buffer); input.Read(buffer, 0, 4); var decompressedSize = GetLittleEndian(buffer); _circularBuffer = new CircularBuffer(0x1000) { Position = _preBufferSize }; var flags = 0; var flagPosition = 8; while (output.Length < decompressedSize) { if (flagPosition == 8) { flagPosition = 0; flags = input.ReadByte(); } if (((flags >> flagPosition++) & 0x1) == 1) { // raw data var value = (byte)input.ReadByte(); output.WriteByte(value); _circularBuffer.WriteByte(value); } else { // compressed data var byte1 = input.ReadByte(); var byte2 = input.ReadByte(); var length = (byte2 & 0xF) + 3; var bufferPosition = byte1 | ((byte2 & 0xF0) << 4); if (input.Position > 0x5f40) { Debugger.Break(); } // Convert buffer position to displacement var displacement = (_circularBuffer.Position - bufferPosition) % _circularBuffer.Length; displacement = (displacement + _circularBuffer.Length) % _circularBuffer.Length; if (displacement == 0) { displacement = 0x1000; } _circularBuffer.Copy(output, displacement, length); } } }
public void Decode(Stream input, Stream output) { var buffer = new byte[4]; // Read header information input.Read(buffer, 0, 4); var magic = BinaryPrimitives.ReadUInt32BigEndian(buffer); if (magic != 0x4C5A3737) // LZ77 { throw new InvalidCompressionException(nameof(StingLzDecoder)); } input.Read(buffer, 0, 4); var decompressedSize = BinaryPrimitives.ReadInt32LittleEndian(buffer); input.Read(buffer, 0, 4); var tokenCount = BinaryPrimitives.ReadInt32LittleEndian(buffer); input.Read(buffer, 0, 4); var dataOffset = BinaryPrimitives.ReadInt32LittleEndian(buffer); // Read compressed data var flagOffset = 0x10; var flags = 0; var flagPosition = 0; var circularBuffer = new CircularBuffer(0xFF); while (tokenCount-- > 0) { if (flagPosition == 0) { input.Position = flagOffset++; flags = input.ReadByte(); flagPosition = 8; } if (((flags >> --flagPosition) & 1) == 0) { // Literal input.Position = dataOffset++; var value = (byte)input.ReadByte(); output.WriteByte(value); circularBuffer.WriteByte(value); } else { // Match input.Position = dataOffset; dataOffset += 2; var displacement = input.ReadByte(); var length = input.ReadByte() + 3; circularBuffer.Copy(output, displacement, length); } } }
public void Decode(Stream input, Stream output) { if (input.ReadByte() != 0x03) { throw new InvalidOperationException("This is not a tales of compression with version 3."); } var buffer = new byte[4]; input.Read(buffer, 0, 4); var compressedDataSize = buffer.GetInt32LittleEndian(0); input.Read(buffer, 0, 4); var decompressedSize = buffer.GetInt32LittleEndian(0); var circularBuffer = new CircularBuffer(0x1000) { Position = PreBufferSize_ }; var flags = 0; var flagPosition = 8; while (output.Length < decompressedSize) { if (flagPosition == 8) { flagPosition = 0; flags = input.ReadByte(); } if (((flags >> flagPosition++) & 0x1) == 1) { // raw data var value = (byte)input.ReadByte(); output.WriteByte(value); circularBuffer.WriteByte(value); } else { // compressed data var byte1 = input.ReadByte(); var byte2 = input.ReadByte(); if ((byte2 & 0xF) != 0xF) { // LZ compressed data var length = (byte2 & 0xF) + 3; var bufferPosition = byte1 | ((byte2 & 0xF0) << 4); // Convert buffer position to displacement var displacement = (circularBuffer.Position - bufferPosition) % circularBuffer.Length; displacement = (displacement + circularBuffer.Length) % circularBuffer.Length; if (displacement == 0) { displacement = 0x1000; } circularBuffer.Copy(output, displacement, length); } else { // RLE compressed data byte repValue; var length = (byte2 & 0xF0) >> 4; if (length == 0) { repValue = (byte)input.ReadByte(); length = byte1 + 0x13; } else { repValue = (byte)byte1; length += 3; } for (var i = 0; i < length; i++) { output.WriteByte(repValue); circularBuffer.WriteByte(repValue); } } } } }
private void ReadDisplacedData(Stream output, int displacement, int length) { _circularBuffer.Copy(output, displacement, length); }
public void Decode(Stream input, Stream output) { var buffer = new byte[4]; input.Read(buffer, 0, 3); if (!buffer.SequenceEqual(new byte[] { 0x45, 0x43, 0x44, 0x00 })) { throw new InvalidCompressionException("LZ ECD"); } if (input.ReadByte() == 0) { input.Position = 0x10; input.CopyTo(output); return; } input.Read(buffer, 0, 4); var skipData = buffer.GetInt32BigEndian(0); input.Read(buffer, 0, 4); var compressedLength = buffer.GetInt32BigEndian(0); input.Read(buffer, 0, 4); var uncompressedLength = buffer.GetInt32BigEndian(0); _circularBuffer = new CircularBuffer(0x400) { Position = _preBufferLength }; // Read initial data for (var i = 0; i < skipData; i++) { var value = (byte)input.ReadByte(); output.WriteByte(value); } var codeBlock = input.ReadByte(); var codeBlockPosition = 0; while (output.Length < uncompressedLength) { if (codeBlockPosition == 8) { codeBlockPosition = 0; codeBlock = input.ReadByte(); } var flag = (codeBlock >> codeBlockPosition++) & 0x1; if (flag == 1) { var value = (byte)input.ReadByte(); output.WriteByte(value); _circularBuffer.WriteByte(value); } else { var byte1 = input.ReadByte(); var byte2 = input.ReadByte(); var length = (byte2 & 0x3F) + 3; var bufferPosition = ((byte2 & 0xC0) << 2) | byte1; // Convert buffer position to displacement var displacement = (_circularBuffer.Position - bufferPosition) % _circularBuffer.Length; displacement = (displacement + _circularBuffer.Length) % _circularBuffer.Length; if (displacement == 0) { displacement = 0x400; } _circularBuffer.Copy(output, displacement, length); } } }