Example #1
0
        public static MemoryStream Decompress(Stream data)
        {
            try
            {
                data.Position = 0;
                byte[] aklzBuffer = new byte[4];
                data.Read(aklzBuffer, 0, 4);
                if (aklzBuffer[0] != 0x41 ||
                    aklzBuffer[1] != 0x4B ||
                    aklzBuffer[2] != 0x4C ||
                    aklzBuffer[3] != 0x5A)
                {
                    return(new MemoryStream(StreamReaderExtensions.ToByteArray(data)));
                }
                const uint START_INDEX = 0x1000;
                // Compressed & Decompressed Data Information
                uint compressedSize   = (uint)data.Length;
                uint decompressedSize = EndianUtil.SwapEndian(StreamReaderExtensions.ReadUInt(data, 0xC));

                uint sourcePointer = 0x10;
                uint destPointer   = 0x0;

                byte[] compressedData   = StreamReaderExtensions.ToByteArray(data);
                byte[] decompressedData = new byte[decompressedSize];

                // Start Decompression
                while (sourcePointer < compressedSize && destPointer < decompressedSize)
                {
                    byte instruction = compressedData[sourcePointer]; // Compression Flag
                    sourcePointer++;

                    for (int i = 0; i < 8; ++i)
                    {
                        bool copySingleByte = (instruction & 0x01) != 0;
                        instruction >>= 1;
                        if (copySingleByte) // Data is not compressed
                        {
                            decompressedData[destPointer] = compressedData[sourcePointer];
                            sourcePointer++;
                            destPointer++;
                        }
                        else // Data is compressed
                        {
                            int copyFromAddress = (compressedData[sourcePointer] | ((compressedData[sourcePointer + 1] & 0xF0) << 4)) + 0x12;
                            int Amount          = (compressedData[sourcePointer + 1] & 0x0F) + 3;
                            sourcePointer += 2;

                            int  memCopyAddress = copyFromAddress;
                            uint wrapCount      = destPointer / START_INDEX;
                            for (int wrap = 1; wrap <= wrapCount; ++wrap)
                            {
                                if (copyFromAddress + wrap * START_INDEX < destPointer)
                                {
                                    memCopyAddress += (int)START_INDEX;
                                }
                            }

                            if (memCopyAddress > destPointer)
                            {
                                memCopyAddress -= (int)START_INDEX;
                            }

                            // Copy copySize bytes from decompressedData
                            for (int copyIndex = 0; copyIndex < Amount; ++copyIndex, ++memCopyAddress)
                            {
                                if (memCopyAddress < 0)
                                {
                                    // This means 0
                                    decompressedData[destPointer] = 0;
                                }
                                else
                                {
                                    decompressedData[destPointer] = decompressedData[memCopyAddress];
                                }
                                ++destPointer;
                                if (destPointer >= decompressedData.Length)
                                {
                                    return(new MemoryStream(decompressedData));
                                }
                            }
                        }

                        // Check for out of range
                        if (sourcePointer >= compressedSize || destPointer >= decompressedSize)
                        {
                            break;
                        }
                    }
                }

                return(new MemoryStream(decompressedData));
            }
            catch
            {
                return(null); // An error occured while decompressing
            }
        }
Example #2
0
        public static MemoryStream Compress(Stream data)
        {
            try
            {
                uint DecompressedSize = (uint)data.Length;

                MemoryStream CompressedData   = new MemoryStream();
                byte[]       DecompressedData = StreamReaderExtensions.ToByteArray(data);

                uint SourcePointer = 0x0;
                uint DestPointer   = 0x10;

                // Set up the Lz Compression Dictionary
                LzWindowDictionary LzDictionary = new LzWindowDictionary();
                LzDictionary.SetWindowSize(0x1000);
                LzDictionary.SetMaxMatchAmount(0xF + 3);

                // Start compression
                StreamWriterExtensions.Write(CompressedData, "AKLZ");
                byte[] header = new byte[] { 0x7e, 0x3f, 0x51, 0x64, 0x3d, 0xcc, 0xcc, 0xcd };
                StreamWriterExtensions.Write(CompressedData, header);
                StreamWriterExtensions.Write(CompressedData, EndianUtil.SwapEndian(DecompressedSize));
                while (SourcePointer < DecompressedSize)
                {
                    byte Flag         = 0x0;
                    uint FlagPosition = DestPointer;
                    CompressedData.WriteByte(Flag); // It will be filled in later
                    DestPointer++;

                    for (int i = 0; i < 8; ++i)
                    {
                        int[] LzSearchMatch = LzDictionary.Search(DecompressedData, SourcePointer, DecompressedSize);
                        if (LzSearchMatch[1] > 0) // There is a compression match
                        {
                            Flag |= (byte)(0 << i);

                            int  copySize   = LzSearchMatch[1] - 3;
                            int  address    = LzSearchMatch[0] - 0x12;
                            byte firstByte  = (byte)(address & 0x0FF);
                            byte secondByte = (byte)(copySize | ((address & 0xF00) >> 4));
                            CompressedData.WriteByte(firstByte);
                            CompressedData.WriteByte(secondByte);

                            LzDictionary.AddEntryRange(DecompressedData, (int)SourcePointer, LzSearchMatch[1]);
                            LzDictionary.SlideWindow(LzSearchMatch[1]);

                            SourcePointer += (uint)LzSearchMatch[1];
                            DestPointer   += 2;
                        }
                        else // There wasn't a match
                        {
                            Flag |= (byte)(1 << i);

                            CompressedData.WriteByte(DecompressedData[SourcePointer]);

                            LzDictionary.AddEntry(DecompressedData, (int)SourcePointer);
                            LzDictionary.SlideWindow(1);

                            SourcePointer++;
                            DestPointer++;
                        }

                        // Check for out of bounds
                        if (SourcePointer >= DecompressedSize)
                        {
                            break;
                        }
                    }

                    // Write the flag.
                    // Note that the original position gets reset after writing.
                    CompressedData.Seek(FlagPosition, SeekOrigin.Begin);
                    CompressedData.WriteByte(Flag);
                    CompressedData.Seek(DestPointer, SeekOrigin.Begin);
                }

                return(CompressedData);
            }
            catch
            {
                return(null); // An error occured while compressing
            }
        }