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, (int)(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); } }
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; } }