Пример #1
0
        /* ---------------------------------------------------------------------------------------------------------------------------------- */
        public static int DecompressChapter(WdtFile wdtFile, Chapter chapter, Stream outStream)
        {
            int decompressedSize;

            var compressedBuffer = new byte[chapter.Size + 16];  // Additional safety bytes for LZSS

            using (var wdtFileStream = new FileStream(wdtFile.Path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                wdtFileStream.Seek(chapter.StartPosition, SeekOrigin.Begin);
                wdtFileStream.Read(compressedBuffer, 0, chapter.Size);
            }

            // TODO: Cleanup gotos; decompose the method
            var compressedPartStream = new MemoryStream(compressedBuffer);
            var compressedReader     = new BinaryReader(compressedPartStream);
            var decompressedWriter   = new BinaryWriter(outStream);

            {
                ushort shifter               = 0;
                uint   processedValue        = 0;
                int    bytesDecompressed     = 0;
                bool   carryFlag             = false;
                long   outStreamBasePosition = outStream.Position;

mainPart:
                while (bytesDecompressed < chapter.Size - 1)
                {
                    compressedPartStream.Seek(bytesDecompressed, SeekOrigin.Begin);

                    processedValue = BinaryUtils.SwapBytes(compressedReader.ReadUInt32());

                    processedValue = processedValue << (byte)shifter;
                    bool isShiftCarry = (processedValue & 0x80000000) > 0;
                    processedValue = processedValue << 1;

                    if (!isShiftCarry)
                    {
                        break;
                    }

                    if (shifter == 57351)
                    {
                        shifter  += 0x2001;
                        carryFlag = true;
                    }
                    else
                    {
                        shifter  += 0x2001;
                        carryFlag = false;
                    }

                    bytesDecompressed += carryFlag ? 2 : 1;

                    shifter = (ushort)(shifter & 0xFF07);

                    processedValue = BinaryUtils.SwapBytes(processedValue);
                    decompressedWriter.Write((byte)processedValue);

                    if ((outStream.Position - outStreamBasePosition) >= wdtFile.PageSize)
                    {
                        goto endOfFile;
                    }
                }

                if (shifter == 57351)
                {
                    shifter  += 0x2001;
                    carryFlag = true;
                }
                else
                {
                    shifter  += 0x2001;
                    carryFlag = false;
                }

                BinaryUtils.AddWithCarry(ref bytesDecompressed, 2, carryFlag);
                shifter = (ushort)(shifter & 0xFF07);

                uint helper = (processedValue >> 0x14);

                {
                    bool shrCarryFlag = false;
                    if ((helper & 0x80000) > 0)
                    {
                        shrCarryFlag = true;
                    }

                    if (shrCarryFlag)
                    {
                        processedValue &= 0xF0000;
                        processedValue  = processedValue >> 0x10;

                        decompressedWriter.Seek((int)(outStreamBasePosition + processedValue) + 2, SeekOrigin.Current);

                        if (bytesDecompressed < chapter.Size - 1)
                        {
                            goto endOfFile;
                        }
                        else
                        {
                            goto mainPart;
                        }
                    }
                }

                {
                    processedValue &= 0xF0000;

                    bool shrCarryFlag = false;
                    if ((processedValue & 0x10000) > 0)
                    {
                        shrCarryFlag = true;
                    }

                    processedValue = processedValue >> 0x11;

                    if (shrCarryFlag)
                    {
                        long outStreamPosition = outStream.Position;
                        outStream.Seek(outStreamPosition + helper - 0x1000, SeekOrigin.Begin);
                        byte someByte = (byte)outStream.ReadByte();
                        outStream.Seek(outStreamPosition, SeekOrigin.Begin);
                        decompressedWriter.Write(someByte);
                    }
                }

                processedValue++;

                while (processedValue > 0)
                {
                    long outStreamPosition = outStream.Position;
                    outStream.Seek(outStreamPosition + helper - 0x1000, SeekOrigin.Begin);
                    byte copiedByte = (byte)outStream.ReadByte();
                    outStream.Seek(outStreamPosition, SeekOrigin.Begin);
                    decompressedWriter.Write(copiedByte);

                    outStreamPosition = outStream.Position;
                    outStream.Seek(outStreamPosition + helper - 0x1000, SeekOrigin.Begin);
                    copiedByte = (byte)outStream.ReadByte();
                    outStream.Seek(outStreamPosition, SeekOrigin.Begin);
                    decompressedWriter.Write(copiedByte);

                    processedValue--;
                }

                if (bytesDecompressed < chapter.Size - 1)
                {
                    goto mainPart;
                }

endOfFile:
                decompressedSize = (int)(outStream.Position - outStreamBasePosition);
            }

            compressedPartStream.Dispose();

            return(decompressedSize);
        }