/* Compress */ public static MemoryStream Compress(ref Stream data, string filename) { try { var decompressedSize = (uint)data.Length; var compressedData = new MemoryStream(); byte[] decompressedData = data.ToByteArray(); uint sourcePointer = 0x0; uint destPointer = 0x4; // Test if the file is too large to be compressed if (data.Length > 0xFFFFFF) throw new Exception("Input file is too large to compress."); // Set up the Lz Compression Dictionary var lzDictionary = new LzWindowDictionary(); lzDictionary.SetWindowSize(0x1000); lzDictionary.SetMaxMatchAmount(0xF + 3); // Start compression compressedData.Write('\x10' | (decompressedSize << 8)); while (sourcePointer < decompressedSize) { byte flag = 0x0; var flagPosition = destPointer; compressedData.WriteByte(flag); // It will be filled in later destPointer++; for (var i = 7; i >= 0; i--) { var lzSearchMatch = lzDictionary.Search(decompressedData, sourcePointer, decompressedSize); if (lzSearchMatch[1] > 0) // There is a compression match { flag |= (byte)(1 << i); compressedData.WriteByte((byte)((((lzSearchMatch[1] - 3) & 0xF) << 4) | (((lzSearchMatch[0] - 1) & 0xFFF) >> 8))); compressedData.WriteByte((byte)((lzSearchMatch[0] - 1) & 0xFF)); lzDictionary.AddEntryRange(decompressedData, (int)sourcePointer, lzSearchMatch[1]); lzDictionary.SlideWindow(lzSearchMatch[1]); sourcePointer += (uint)lzSearchMatch[1]; destPointer += 2; } else // There wasn't a match { flag |= (byte)(0 << i); compressedData.WriteByte(decompressedData[sourcePointer]); lzDictionary.AddEntry(decompressedData, (int)sourcePointer); lzDictionary.SlideWindow(1); sourcePointer++; destPointer++; } // Check for out of bounds if (sourcePointer >= decompressedSize) break; } // Write the flag. // The original position gets reset after writing. compressedData.Seek(flagPosition, SeekOrigin.Begin); compressedData.WriteByte(flag); compressedData.Seek(destPointer, SeekOrigin.Begin); } return compressedData; } catch { return null; // An error occured while compressing } }
/* Compress */ public static MemoryStream Compress(ref Stream data, string filename) { try { var decompressedSize = (uint)data.Length; var compressedData = new MemoryStream(); byte[] decompressedData = data.ToByteArray(); uint sourcePointer = 0x0; uint destPointer = 0x4; // Test if the file is too large to be compressed if (data.Length > 0xFFFFFF) { throw new Exception("Input file is too large to compress."); } // Set up the Lz Compression Dictionary var lzDictionary = new LzWindowDictionary(); lzDictionary.SetWindowSize(0x1000); lzDictionary.SetMaxMatchAmount(0xF + 3); // Start compression compressedData.Write('\x10' | (decompressedSize << 8)); while (sourcePointer < decompressedSize) { byte flag = 0x0; var flagPosition = destPointer; compressedData.WriteByte(flag); // It will be filled in later destPointer++; for (var i = 7; i >= 0; i--) { var lzSearchMatch = lzDictionary.Search(decompressedData, sourcePointer, decompressedSize); if (lzSearchMatch[1] > 0) // There is a compression match { flag |= (byte)(1 << i); compressedData.WriteByte((byte)((((lzSearchMatch[1] - 3) & 0xF) << 4) | (((lzSearchMatch[0] - 1) & 0xFFF) >> 8))); compressedData.WriteByte((byte)((lzSearchMatch[0] - 1) & 0xFF)); lzDictionary.AddEntryRange(decompressedData, (int)sourcePointer, lzSearchMatch[1]); lzDictionary.SlideWindow(lzSearchMatch[1]); sourcePointer += (uint)lzSearchMatch[1]; destPointer += 2; } else // There wasn't a match { flag |= (byte)(0 << i); compressedData.WriteByte(decompressedData[sourcePointer]); lzDictionary.AddEntry(decompressedData, (int)sourcePointer); lzDictionary.SlideWindow(1); sourcePointer++; destPointer++; } // Check for out of bounds if (sourcePointer >= decompressedSize) { break; } } // Write the flag. // The original position gets reset after writing. compressedData.Seek(flagPosition, SeekOrigin.Begin); compressedData.WriteByte(flag); compressedData.Seek(destPointer, SeekOrigin.Begin); } return(compressedData); } catch { return(null); // An error occured while compressing } }