Exemplo n.º 1
0
        public static int FindLengthOfMIO0Block(byte[] data, int offsetOfMIO0)
        {
            //Load the header info
            MIO0Header header = new MIO0Header(data, offsetOfMIO0);

            //Count all the uncompressed bytes
            int uncompressedCount = 0;
            for (int i = 0x10; i < header.CompLoc; i++)
            {
                for (int j = 7; j >= 0; j--)
                {
                    //Check for one
                    if ((data[i + offsetOfMIO0] & (byte)(1 << j)) != 0)
                    {
                        uncompressedCount++;
                    }
                }
            }

            //Make it line up to 4-byte address
            int length = uncompressedCount + (int)header.RawLoc;
            if (length % 4 != 0)
                length += 4 - (length % 4);

            return length;
        }
Exemplo n.º 2
0
        public static byte[] Encode(byte[] rawData, byte padToAddress = 4)
        {
            //To do: describe this algorithm
            // for now, just see here: http://wiki.origami64.net/sm64:mio0
            int minByteClump = 3;
            int maxByteClump = 18;
            int maxReadBack = 4096;

            ClumpInfo currentBestClump;

            List<ClumpInfo> clumpInfo = new List<ClumpInfo>();

            for (int offset = 1; offset < rawData.Length; )
            {
                currentBestClump = FindBestClump(rawData, offset, maxReadBack, maxByteClump, minByteClump);

                if (currentBestClump.Length >= minByteClump)
                {
                    //Set the clump, set back x bytes
                    clumpInfo.Add(currentBestClump);
                    offset += currentBestClump.Length;
                }
                else
                {
                    //Uncompressed, move on one byte
                    offset++;
                }
            }

            if (clumpInfo.Count == 0)
            {
                //Call the other one, huge waste of time
                return EncodeAsRaw(rawData);
            }

            //Optimization code
            for (int i = 0; i < clumpInfo.Count; i++)
            {
                if(FindBestAlternativeClumps(rawData, maxReadBack, maxByteClump, minByteClump,
                    clumpInfo, i))
                {
                    //to try to further optimize?
                }

            }

            ClumpInfo nextCompressedSection = clumpInfo[0];
            clumpInfo.RemoveAt(0);
            List<byte> UncompressedInfo = new List<byte>();
            List<byte> CompressedInfo = new List<byte>();
            List<byte> LayoutInfo = new List<byte>();
            byte layoutByte = 0;
            int layoutByteIndex = 7;

            for (int offset = 0; offset < rawData.Length; )
            {
                //If it's the offset from the next compressed section, do the compression. Else add an uncompressed.
                if (nextCompressedSection != null && offset == nextCompressedSection.Offset)
                {
                    //Write the compressed data
                    short compressedValues = (short)((((nextCompressedSection.Length - 3) & 0xF) << 12) | ((nextCompressedSection.CopyOffset - 1) & 0xFFF));
                    CompressedInfo.Add((byte)(compressedValues >> 8));
                    CompressedInfo.Add((byte)compressedValues);

                    //No writing to the byte, since it's a 0

                    offset += nextCompressedSection.Length;
                    if (clumpInfo.Count == 0)
                        nextCompressedSection = null;
                    else
                    {
                        nextCompressedSection = clumpInfo[0];
                        clumpInfo.RemoveAt(0);
                    }
                }
                else
                {
                    UncompressedInfo.Add(rawData[offset]);
                    layoutByte |= (byte)(1 << layoutByteIndex);
                    offset++;
                }

                layoutByteIndex--;
                if (layoutByteIndex < 0)
                {
                    LayoutInfo.Add(layoutByte);
                    layoutByte = 0;
                    layoutByteIndex = 7;
                }
            }

            //Add the proper end buffers to the lists, put together the header, throw it all to the user here
            if (layoutByteIndex != 7)
                LayoutInfo.Add(layoutByte);

            while (LayoutInfo.Count % 4 != 0)
                LayoutInfo.Add(0);

            MIO0Header header = new MIO0Header();
            header.ID = MIO0.MIO0_AS_UINT;
            header.OutputSize = (uint)rawData.Length;
            header.CompLoc = 0x10 + (uint)LayoutInfo.Count;
            header.RawLoc = header.CompLoc + (uint)CompressedInfo.Count;
            uint fullLength = header.RawLoc + (uint)UncompressedInfo.Count;

            //Pad if needed to hit a certain address value
            if (padToAddress != 0 && fullLength % padToAddress != 0)
                fullLength += padToAddress - (fullLength % padToAddress);

            byte[] finalData = new byte[fullLength];
            header.WriteToBytes(finalData, 0);
            Array.Copy(LayoutInfo.ToArray(), 0, finalData, 0x10, LayoutInfo.Count);
            Array.Copy(CompressedInfo.ToArray(), 0, finalData, header.CompLoc, CompressedInfo.Count);
            Array.Copy(UncompressedInfo.ToArray(), 0, finalData, header.RawLoc, UncompressedInfo.Count);

            return finalData;
        }