Microsoft.Protocols.TestSuites.Common.Common.LZ77Compress C# (CSharp) Method

LZ77Compress() private static method

Compresses stream using LZ77 algorithm and encodes using Direct2 algorithm.
private static LZ77Compress ( byte inputStream ) : byte[]
inputStream byte The input stream needed to be compressed.
return byte[]
        private static byte[] LZ77Compress(byte[] inputStream)
        {
            if (inputStream == null)
            {
                throw new ArgumentNullException("inputStream");
            }

            #region Consts
            // The minimum match is 3 bytes. [MS-OXCRPC], section 3.1.4.11.1.2.1.4.
            const int SizeOfMinimumMatch = 3;

            // The maximum window size restricted by the metadata offset length (13 bytes). [MS-OXCRPC], section 3.1.4.11.1.2.2.3.
            const int MaximumWindowSize = 8193;

            // The size of bitmask. [MS-OXCRPC], section 3.1.4.11.1.2.2.1.
            const int SizeOfBitMask = sizeof(uint);

            // Indicates unused bits in bitmask are filled with 1.
            const uint DefaultBitMaskFilling = 0xFFFFFFFF;

            // Means the first 31 bytes are actual data. (1000 0000 0000 0000 0000 0000 0000 0000). Uses as the beginning of checking bitmask.
            const uint BitMaskOf31ActualData = 0x80000000;

            // The size of metadata. [MS-OXCRPC], section 3.1.4.11.1.2.2.3.
            const int SizeOfMetadata = sizeof(short);

            // The low-order three bits are the length. [MS-OXCRPC], section 3.1.4.11.1.2.2.4.
            const int MetadataLengthBitLength = 3;

            // The maximum value when all low-order three bits are "1". [MS-OXCRPC], section 3.1.4.11.1.2.2.4.
            const int MetadataLengthFullBitsValue = 7;

            // The shared byte with value 1111.
            const byte SharedByteSetLow4Bits = 0xF;

            // The next byte with value 11111111.
            const byte NextByteSetAllBits = 0xFF;

            // The size of final two bytes which is used to calculate the match length equal or greater than 280.
            const int SizeOfFinalTwoBytes = sizeof(short);

            // The increase of the length of output stream each time stream length is insufficient.
            const int OutStreamLengthIncrease = 128;

            // The maximum metadata length. It would be the first 2 bytes, 1 shared byte, 1 additional byte, and the final 2 bytes, section 3.1.4.11.1.2.2.4.
            const int MaximumMetadataLength = 6;
            #endregion

            #region Variables
            // The position of the byte in the input stream that is currently being coded (the beginning of the lookahead buffer).
            int codingPosition;

            // The starting position of the window in the input stream.
            int windowStartingPosition;

            // The position of the byte in the output stream where the data byte or metadata is being written.
            int outBytesPosition;

            // To distinguish data from metadata in the compressed byte stream. [MS-OXCRPC], section 3.1.4.11.1.2.2.1.
            uint bitMask;

            // Indicates the bit representing the next byte to be processed is "1".
            uint bitMaskPointer;

            // The position of the bitmask in the output stream.
            int outBitMaskPostion;

            // The position of the shared byte in the output stream. After the high-order nibble of the byte is used, this value is set to "-1" to indicate it needs to be set to a new position next time.
            int sharedBytePosition;
            #endregion

            int size = inputStream.Length;
            byte[] outStream = new byte[size];

            // Set the coding position to the beginning of the input stream.
            codingPosition = 0;
            windowStartingPosition = 0;
            outBytesPosition = 0;
            outBitMaskPostion = 0;
            bitMaskPointer = 0;
            sharedBytePosition = -1;
            while (codingPosition < size)
            {
                // Enlarge output stream length to ensure it's sufficient.
                if (outBytesPosition + MaximumMetadataLength + SizeOfBitMask > outStream.Length)
                {
                    Array.Resize<byte>(ref outStream, outStream.Length + OutStreamLengthIncrease);
                }

                // Move to the next bitmask if all bits in current bitmask are set.
                if (bitMaskPointer == 0)
                {
                    outBitMaskPostion = outBytesPosition;
                    Array.Copy(BitConverter.GetBytes(DefaultBitMaskFilling), 0, outStream, outBitMaskPostion, SizeOfBitMask);
                    outBytesPosition += SizeOfBitMask;
                    bitMaskPointer = BitMaskOf31ActualData;
                }

                // Find the longest match in the window for the lookahead buffer.
                int matchLength = 0;
                int matchOffset = 0;
                for (int matchOffsetPosition = windowStartingPosition; matchOffsetPosition < codingPosition - matchLength; matchOffsetPosition++)
                {
                    if (inputStream[codingPosition] == inputStream[matchOffsetPosition])
                    {
                        int currentMatchLength = 1;
                        while (currentMatchLength < size - codingPosition - 1)
                        {
                            if (inputStream[codingPosition + currentMatchLength] == inputStream[matchOffsetPosition + currentMatchLength])
                            {
                                currentMatchLength++;
                            }
                            else
                            {
                                break;
                            }
                        }

                        if (currentMatchLength >= matchLength)
                        {
                            matchLength = currentMatchLength;
                            matchOffset = codingPosition - matchOffsetPosition;
                        }
                    }
                }

                // Output the data byte or metadata with DIRECT2 encoding.
                if (matchLength < SizeOfMinimumMatch)
                {
                    // Next one is not metadata. Set bitmask bit to '0'.
                    bitMask = BitConverter.ToUInt32(outStream, outBitMaskPostion);
                    bitMask &= ~bitMaskPointer;
                    Array.Copy(BitConverter.GetBytes(bitMask), 0, outStream, outBitMaskPostion, sizeof(uint));
                    bitMaskPointer >>= 1;

                    // Fill data byte in output stream.
                    outStream[outBytesPosition] = inputStream[codingPosition];
                    outBytesPosition++;
                    codingPosition++;
                }
                else
                {
                    // Next one is metadata. Set bitmask bit to '1'.
                    bitMask = BitConverter.ToUInt32(outStream, outBitMaskPostion);
                    bitMask |= bitMaskPointer;
                    Array.Copy(BitConverter.GetBytes(bitMask), 0, outStream, outBitMaskPostion, sizeof(uint));
                    bitMaskPointer >>= 1;

                    // Fill metadata offset and length in output stream. 
                    // Use the high-order 13 bits in metadata bytes to store metadata offset.
                    matchOffset--;
                    int remainningMatchLength = matchLength - SizeOfMinimumMatch;
                    if (remainningMatchLength < MetadataLengthFullBitsValue)
                    {
                        // Use the low-order bits in metadata bytes to represent metadata length.
                        short metadata = (short)((matchOffset << MetadataLengthBitLength) + remainningMatchLength);
                        Array.Copy(BitConverter.GetBytes(metadata), 0, outStream, outBytesPosition, SizeOfMetadata);
                        outBytesPosition += SizeOfMetadata;
                    }
                    else
                    {
                        short metadata = (short)((matchOffset << MetadataLengthBitLength) + MetadataLengthFullBitsValue);
                        Array.Copy(BitConverter.GetBytes(metadata), 0, outStream, outBytesPosition, SizeOfMetadata);
                        outBytesPosition += SizeOfMetadata;
                        remainningMatchLength -= MetadataLengthFullBitsValue;
                        if (remainningMatchLength < (int)SharedByteSetLow4Bits)
                        {
                            // Additionally use the low-order or high-order nibble in shared byte to represent metadata length.
                            if (sharedBytePosition < 0)
                            {
                                sharedBytePosition = outBytesPosition++;
                                outStream[sharedBytePosition] = (byte)remainningMatchLength;
                            }
                            else
                            {
                                outStream[sharedBytePosition] += (byte)(remainningMatchLength << 4);
                                sharedBytePosition = -1;
                            }
                        }
                        else
                        {
                            if (sharedBytePosition < 0)
                            {
                                sharedBytePosition = outBytesPosition++;
                                outStream[sharedBytePosition] = SharedByteSetLow4Bits;
                            }
                            else
                            {
                                outStream[sharedBytePosition] += SharedByteSetLow4Bits << 4;
                                sharedBytePosition = -1;
                            }

                            remainningMatchLength -= (int)SharedByteSetLow4Bits;

                            if (remainningMatchLength < (int)NextByteSetAllBits)
                            {
                                // Additionally use another byte to represent metadata length.
                                outStream[outBytesPosition++] = (byte)remainningMatchLength;
                            }
                            else
                            {
                                outStream[outBytesPosition++] = NextByteSetAllBits;

                                // Use the final two bytes to represent metadata length.
                                Array.Copy(BitConverter.GetBytes((short)(matchLength - SizeOfMinimumMatch)), 0, outStream, outBytesPosition, SizeOfFinalTwoBytes);
                                outBytesPosition += SizeOfFinalTwoBytes;
                            }
                        }
                    }

                    // If the lookahead buffer is not empty, move the coding position (and the window) L bytes forward.
                    codingPosition += matchLength;
                    if (codingPosition - windowStartingPosition > MaximumWindowSize)
                    {
                        windowStartingPosition = codingPosition - MaximumWindowSize;
                    }
                }
            }

            // Move to the next bitmask if all bits in current bitmask are set because additional bit "1" is needed as EOF.
            if (bitMaskPointer == 0)
            {
                outBitMaskPostion = outBytesPosition;
                Array.Copy(BitConverter.GetBytes(DefaultBitMaskFilling), 0, outStream, outBitMaskPostion, SizeOfBitMask);
                outBytesPosition += SizeOfBitMask;
            }

            // Resize output stream
            Array.Resize<byte>(ref outStream, outBytesPosition);
            return outStream;
        }
Common