예제 #1
0
        public static MemoryStream Decode(EndianBinaryReader reader)
        {
            if (reader.ReadUInt32() != 0x59617930) // "Yay0" Magic
            {
                throw new InvalidDataException("Invalid Magic, not a Yay0 File");
            }

            int uncompressedSize = reader.ReadInt32();
            int linkTableOffset = reader.ReadInt32();
            int byteChunkAndCountModifiersOffset = reader.ReadInt32();

            int maskBitCounter = 0;
            int currentOffsetInDestBuffer = 0;
            int currentMask = 0;

            byte[] uncompressedData = new byte[uncompressedSize];

            do
            {
                // If we're out of bits, get the next mask.
                if (maskBitCounter == 0)
                {
                    currentMask = reader.ReadInt32();
                    maskBitCounter = 32;
                }

                // If the next bit is set, the chunk is non-linked and just copy it from the non-link table.
                if (((uint)currentMask & (uint)0x80000000) == 0x80000000)
                {
                    uncompressedData[currentOffsetInDestBuffer] = reader.ReadByteAt(byteChunkAndCountModifiersOffset);
                    currentOffsetInDestBuffer++;
                    byteChunkAndCountModifiersOffset++;
                }
                // Do a copy otherwise.
                else
                {
                    // Read 16-bit from the link table
                    ushort link = reader.ReadUInt16At(linkTableOffset);
                    linkTableOffset += 2;

                    // Calculate the offset
                    int offset = currentOffsetInDestBuffer - (link & 0xfff);

                    // Calculate the count
                    int count = link >> 12;

                    if (count == 0)
                    {
                        byte countModifier;
                        countModifier = reader.ReadByteAt(byteChunkAndCountModifiersOffset);
                        byteChunkAndCountModifiersOffset++;
                        count = countModifier + 18;
                    }
                    else
                    {
                        count += 2;
                    }

                    // Copy the block
                    int blockCopy = offset;

                    for (int i = 0; i < count; i++)
                    {
                        uncompressedData[currentOffsetInDestBuffer] = uncompressedData[blockCopy - 1];
                        currentOffsetInDestBuffer++;
                        blockCopy++;
                    }
                }

                // Get the next bit in the mask.
                currentMask <<= 1;
                maskBitCounter--;

            } while (currentOffsetInDestBuffer < uncompressedSize);

            return new MemoryStream(uncompressedData);
        }