Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
                }
            }
        }
Пример #6
0
        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);
        }
Пример #7
0
        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);
        }
Пример #8
0
        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);
                }
            }
        }
Пример #9
0
        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);
        }
Пример #10
0
        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);
                    }
                }
            }
        }
Пример #11
0
        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);
        }
Пример #12
0
        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);
        }
Пример #13
0
        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);
        }
Пример #14
0
        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);
        }
Пример #15
0
        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);
                }
            }
        }
Пример #16
0
        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);
        }
Пример #17
0
        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);
                }
            }
        }
Пример #18
0
        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);
        }
Пример #19
0
        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);
        }
Пример #20
0
        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);
            }
        }
Пример #21
0
        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);
                }
            }
        }
Пример #22
0
        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);
        }
Пример #23
0
        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);
            }
        }
Пример #24
0
        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}.");
                }
            }
        }
Пример #25
0
        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);
                }
            }
        }
Пример #26
0
        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);
                }
            }
        }
Пример #27
0
        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);
                        }
                    }
                }
            }
        }
Пример #28
0
 private void ReadDisplacedData(Stream output, int displacement, int length)
 {
     _circularBuffer.Copy(output, displacement, length);
 }
Пример #29
0
        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);
                }
            }
        }