Ejemplo n.º 1
0
        public byte[] Compress(byte[] buffer)
        {
            ByteDictionary byteDictionary = new ByteDictionary(buffer);

            byte[] compBuffer = new byte[Codec.BufferSize];

            int i = 0; // Iterator for buffer
            int j = 0; // Iterator for compBuffer

            while (i < buffer.Length)
            {
                int k = i + 1;   // Forward iterator for buffer
                int command;     // The compression command we consider the most efficient
                int commandCost; // How costly we consider this command

                if (k < buffer.Length &&
                    buffer[i] == buffer[k])
                {
                    // Command 1: the same byte is repeated
                    command     = 1;
                    commandCost = 0;

                    do
                    {
                        k++;
                    }while (k < buffer.Length &&
                            buffer[i] == buffer[k]);
                }
                else if ((k + 1) < buffer.Length &&
                         buffer[i] == buffer[i + 2])
                {
                    // Command 2: a sequence of 2 bytes is repeated
                    command     = 2;
                    commandCost = 2;

                    k += 2;
                    while (k < buffer.Length &&
                           buffer[k - 2] == buffer[k])
                    {
                        k++;
                    }
                }
                else if (k < buffer.Length &&
                         ((buffer[i] + 1) & 0xFF) == buffer[k])
                {
                    // Command 3: a value keeps getting incremented by 1
                    command     = 3;
                    commandCost = 0;

                    do
                    {
                        k++;
                    }while (k < buffer.Length &&
                            ((buffer[k - 1] + 1) & 0xFF) == buffer[k]);
                }
                else
                {
                    // Command 0: simply stores a sequence of bytes as is
                    command     = 0;
                    commandCost = 0;
                }

                Range range        = FastCompressor.GetRange(i, k);
                Range maxBackRange = byteDictionary.GetMaxBackRange(i);
                int   distance     = i - maxBackRange.Start;

                if (distance > 0xFF)
                {
                    // If distance > 0xFF, then command 4 should be used, otherwise command 6 is more efficient.
                    // We need to know this to optimize compression, because using command 4 is more expensive
                    // (the address is encoded on one more byte, because it's absolute rather than relative).
                    commandCost--; // Decreases the odds of using a back command (4 or 6)
                }

                if (maxBackRange.Length + commandCost > range.Length)
                {
                    // Command 4 or 6: repeats a previous data sequence
                    // Command 4: from an absolute address (on two bytes)
                    // Command 6: from a relative address (on one byte)
                    command = 4; // Actually 4 or 6
                }

                switch (command)
                {
                case 0:
                    FastCompressor.CallCommand0(buffer, compBuffer, ref i, ref j, k, byteDictionary);
                    break;

                case 1:
                    FastCompressor.CallCommand1(buffer, compBuffer, ref i, ref j, range.Length);
                    break;

                case 2:
                    FastCompressor.CallCommand2(buffer, compBuffer, ref i, ref j, range.Length);
                    break;

                case 3:
                    FastCompressor.CallCommand3(buffer, compBuffer, ref i, ref j, range.Length);
                    break;

                case 4:
                    FastCompressor.CallCommand4Or6(compBuffer, ref i, ref j, maxBackRange);
                    break;
                }
            }

            compBuffer[j++] = 0xFF;

            return(Utilities.ReadBlock(compBuffer, 0, j));
        }
Ejemplo n.º 2
0
        private static void CallCommand0(byte[] buffer, byte[] compBuffer, ref int i, ref int j, int k, ByteDictionary byteDictionary)
        {
            while (k < buffer.Length)
            {
                if
                (
                    (
                        // Matches command 3
                        (k + 2) < buffer.Length &&
                        (buffer[k] == ((buffer[k + 1] - 1) & 0xFF) &&
                         buffer[k + 2] == ((buffer[k + 1] + 1) & 0xFF))
                    )
                    ||
                    (
                        // Matches command 1
                        (k + 2) < buffer.Length &&
                        (buffer[k] == buffer[k + 1] &&
                         buffer[k] == buffer[k + 2])
                    )
                    ||
                    (
                        // Matches command 2
                        (k + 3) < buffer.Length &&
                        (buffer[k] == buffer[k + 2] &&
                         buffer[k + 1] == buffer[k + 3])
                    )
                )
                {
                    break;
                }

                Range backRange = byteDictionary.GetMaxBackRange(k);
                int   distance  = k - backRange.Start;
                // Matches command 4 or 6
                if ((distance > 0xFF && backRange.Length > 4) ||
                    (distance <= 0xFF && backRange.Length > 3))
                {
                    break;
                }

                k++;
            }

            Range range = FastCompressor.GetRange(i, k);

            int byteCount = range.Length;

            if (byteCount <= Codec.NormalCommandMax)
            {
                compBuffer[j++] = (byte)(byteCount - 1);
            }
            else
            {
                compBuffer[j++] = (byte)(0xE0 + ((byteCount - 1 & 0x300) >> 8));
                compBuffer[j++] = (byte)(byteCount - 1 & 0xFF);
            }

            Buffer.BlockCopy(buffer, i, compBuffer, j, byteCount);
            j += byteCount;
            i += byteCount;
        }