Beispiel #1
0
        public override CompressionResult Compress(byte[] source, int sourceOffset, int sourceLength, byte[] compressed, int compressedOffset, ref int compressedLength)
        {
            uint sourcePointer = 0;
            uint sourceCurrentBlock = 0;
            uint destPointer = 0;

            // Set up the Lz Compression Dictionary 
            LzWindowDictionary lzDictionary = new LzWindowDictionary();
            bool nonZeroDataFound = false;

            for (int subBlock = 0; subBlock < sourceLength; subBlock += BlockSize)
            {
                lzDictionary.MinMatchAmount = 3;
                sourceCurrentBlock = sourcePointer;

                uint decompressedSize = (uint)Math.Min(sourceLength - subBlock, BlockSize);
                uint compressedSize = 0;

                // Start compression 
                uint headerPosition = destPointer;
                compressed[compressedOffset + destPointer] = compressed[compressedOffset + destPointer + 1] = 0;
                destPointer += 2;

                while (sourcePointer - subBlock < decompressedSize)
                {
                    if (destPointer + 1 >= compressedLength)
                    {
                        return CompressionResult.Incompressible;
                    }

                    byte bitFlag = 0x0;
                    uint flagPosition = destPointer;

                    compressed[compressedOffset + destPointer] = bitFlag; // It will be filled in later 
                    compressedSize++;
                    destPointer++;

                    for (int i = 0; i < 8; i++)
                    {
                        int lengthBits = 16 - s_compressionBits[sourcePointer - subBlock];
                        ushort lengthMask = (ushort)((1 << s_compressionBits[sourcePointer - subBlock]) - 1);

                        lzDictionary.MaxMatchAmount = Math.Min(1 << lengthBits, BlockSize - 1);

                        int[] lzSearchMatch = lzDictionary.Search(source, sourceOffset + subBlock, (uint)(sourcePointer - subBlock), decompressedSize);
                        if (lzSearchMatch[1] > 0)
                        {
                            // There is a compression match
                            if (destPointer + 2 >= compressedLength)
                            {
                                return CompressionResult.Incompressible;
                            }

                            bitFlag |= (byte)(1 << i);

                            int rawOffset = lzSearchMatch[0];
                            int rawLength = lzSearchMatch[1];

                            int convertedOffset = (rawOffset - 1) << lengthBits;
                            int convertedSize = (rawLength - 3) & ((1 << lengthMask) - 1);

                            ushort convertedData = (ushort)(convertedOffset | convertedSize);
                            Utilities.WriteBytesLittleEndian(convertedData, compressed, compressedOffset + (int)destPointer);

                            lzDictionary.AddEntryRange(source, sourceOffset + subBlock, (int)(sourcePointer - subBlock), lzSearchMatch[1]);
                            sourcePointer += (uint)lzSearchMatch[1];
                            destPointer += 2;
                            compressedSize += 2;
                        }
                        else
                        {
                            // There wasn't a match
                            if (destPointer + 1 >= compressedLength)
                            {
                                return CompressionResult.Incompressible;
                            }

                            bitFlag |= (byte)(0 << i);

                            if (source[sourceOffset + sourcePointer] != 0)
                            {
                                nonZeroDataFound = true;
                            }

                            compressed[compressedOffset + destPointer] = source[sourceOffset + sourcePointer];
                            lzDictionary.AddEntry(source, sourceOffset + subBlock, (int)(sourcePointer - subBlock));

                            sourcePointer++;
                            destPointer++;
                            compressedSize++;
                        }

                        // Check for out of bounds 
                        if (sourcePointer - subBlock >= decompressedSize)
                        {
                            break;
                        }
                    }

                    // Write the real flag. 
                    compressed[compressedOffset + flagPosition] = bitFlag;
                }

                // If compressed size >= block size just store block
                if (compressedSize >= BlockSize)
                {
                    // Set the header to indicate non-compressed block
                    Utilities.WriteBytesLittleEndian((ushort)(0x3000 | (BlockSize - 1)), compressed, compressedOffset + (int)headerPosition);

                    Array.Copy(source, (int)sourceOffset + sourceCurrentBlock, compressed, compressedOffset + headerPosition + 2, BlockSize);
                    destPointer = (uint)(headerPosition + 2 + BlockSize);

                    // Make sure decompression stops by setting the next two bytes to null, prevents us from having to 
                    // clear the rest of the array.
                    compressed[destPointer] = 0;
                    compressed[destPointer + 1] = 0;
                }
                else
                {
                    // Set the header to indicate compressed and the right length
                    Utilities.WriteBytesLittleEndian((ushort)(0xb000 | (compressedSize - 1)), compressed, compressedOffset + (int)headerPosition);
                }

                lzDictionary.Reset();
            }

            if (destPointer >= sourceLength)
            {
                compressedLength = 0;
                return CompressionResult.Incompressible;
            }
            else if (nonZeroDataFound)
            {
                compressedLength = (int)destPointer;
                return CompressionResult.Compressed;
            }
            else
            {
                compressedLength = 0;
                return CompressionResult.AllZeros;
            }
        }
Beispiel #2
0
        public override CompressionResult Compress(byte[] source, int sourceOffset, int sourceLength, byte[] compressed, int compressedOffset, ref int compressedLength)
        {
            uint sourcePointer      = 0;
            uint sourceCurrentBlock = 0;
            uint destPointer        = 0;

            // Set up the Lz Compression Dictionary
            LzWindowDictionary lzDictionary = new LzWindowDictionary();
            bool nonZeroDataFound           = false;

            for (int subBlock = 0; subBlock < sourceLength; subBlock += BlockSize)
            {
                lzDictionary.MinMatchAmount = 3;
                sourceCurrentBlock          = sourcePointer;

                uint decompressedSize = (uint)Math.Min(sourceLength - subBlock, BlockSize);
                uint compressedSize   = 0;

                // Start compression
                uint headerPosition = destPointer;
                compressed[compressedOffset + destPointer] = compressed[compressedOffset + destPointer + 1] = 0;
                destPointer += 2;

                while (sourcePointer - subBlock < decompressedSize)
                {
                    if (destPointer + 1 >= compressedLength)
                    {
                        return(CompressionResult.Incompressible);
                    }

                    byte bitFlag      = 0x0;
                    uint flagPosition = destPointer;

                    compressed[compressedOffset + destPointer] = bitFlag; // It will be filled in later
                    compressedSize++;
                    destPointer++;

                    for (int i = 0; i < 8; i++)
                    {
                        int    lengthBits = 16 - s_compressionBits[sourcePointer - subBlock];
                        ushort lengthMask = (ushort)((1 << s_compressionBits[sourcePointer - subBlock]) - 1);

                        lzDictionary.MaxMatchAmount = Math.Min(1 << lengthBits, BlockSize - 1);

                        int[] lzSearchMatch = lzDictionary.Search(source, sourceOffset + subBlock, (uint)(sourcePointer - subBlock), decompressedSize);
                        if (lzSearchMatch[1] > 0)
                        {
                            // There is a compression match
                            if (destPointer + 2 >= compressedLength)
                            {
                                return(CompressionResult.Incompressible);
                            }

                            bitFlag |= (byte)(1 << i);

                            int rawOffset = lzSearchMatch[0];
                            int rawLength = lzSearchMatch[1];

                            int convertedOffset = (rawOffset - 1) << lengthBits;
                            int convertedSize   = (rawLength - 3) & ((1 << lengthMask) - 1);

                            ushort convertedData = (ushort)(convertedOffset | convertedSize);
                            Utilities.WriteBytesLittleEndian(convertedData, compressed, compressedOffset + (int)destPointer);

                            lzDictionary.AddEntryRange(source, sourceOffset + subBlock, (int)(sourcePointer - subBlock), lzSearchMatch[1]);
                            sourcePointer  += (uint)lzSearchMatch[1];
                            destPointer    += 2;
                            compressedSize += 2;
                        }
                        else
                        {
                            // There wasn't a match
                            if (destPointer + 1 >= compressedLength)
                            {
                                return(CompressionResult.Incompressible);
                            }

                            bitFlag |= (byte)(0 << i);

                            if (source[sourceOffset + sourcePointer] != 0)
                            {
                                nonZeroDataFound = true;
                            }

                            compressed[compressedOffset + destPointer] = source[sourceOffset + sourcePointer];
                            lzDictionary.AddEntry(source, sourceOffset + subBlock, (int)(sourcePointer - subBlock));

                            sourcePointer++;
                            destPointer++;
                            compressedSize++;
                        }

                        // Check for out of bounds
                        if (sourcePointer - subBlock >= decompressedSize)
                        {
                            break;
                        }
                    }

                    // Write the real flag.
                    compressed[compressedOffset + flagPosition] = bitFlag;
                }

                // If compressed size >= block size just store block
                if (compressedSize >= BlockSize)
                {
                    // Set the header to indicate non-compressed block
                    Utilities.WriteBytesLittleEndian((ushort)(0x3000 | (BlockSize - 1)), compressed, compressedOffset + (int)headerPosition);

                    Array.Copy(source, (int)sourceOffset + sourceCurrentBlock, compressed, compressedOffset + headerPosition + 2, BlockSize);
                    destPointer = (uint)(headerPosition + 2 + BlockSize);

                    // Make sure decompression stops by setting the next two bytes to null, prevents us from having to
                    // clear the rest of the array.
                    compressed[destPointer]     = 0;
                    compressed[destPointer + 1] = 0;
                }
                else
                {
                    // Set the header to indicate compressed and the right length
                    Utilities.WriteBytesLittleEndian((ushort)(0xb000 | (compressedSize - 1)), compressed, compressedOffset + (int)headerPosition);
                }

                lzDictionary.Reset();
            }

            if (destPointer >= sourceLength)
            {
                compressedLength = 0;
                return(CompressionResult.Incompressible);
            }
            else if (nonZeroDataFound)
            {
                compressedLength = (int)destPointer;
                return(CompressionResult.Compressed);
            }
            else
            {
                compressedLength = 0;
                return(CompressionResult.AllZeros);
            }
        }