/* Compress */ public override MemoryStream Compress(ref Stream data, string filename) { try { uint DecompressedSize = (uint)data.Length; MemoryStream CompressedData = new MemoryStream(); byte[] DecompressedData = data.ToByteArray(); uint SourcePointer = 0x0; uint DestPointer = 0x10; // Test if the file is too large to be compressed if (data.Length > 0xFFFFFFFF) throw new Exception("Input file is too large to compress."); // Set up the Lz Compression Dictionary LzBufferDictionary LzDictionary = new LzBufferDictionary(); LzDictionary.SetBufferSize(0x1000); LzDictionary.SetBufferStart(0xFEE); LzDictionary.SetMaxMatchAmount(0xF + 3); // Start compression CompressedData.Write("LZ01"); CompressedData.Write((uint)0); // Will be filled in later CompressedData.Write(DecompressedSize); CompressedData.Seek(4, SeekOrigin.Current); // Advance 4 bytes while (SourcePointer < DecompressedSize) { byte Flag = 0x0; uint FlagPosition = DestPointer; CompressedData.WriteByte(Flag); // It will be filled in later DestPointer++; for (int i = 0; i < 8; i++) { int[] LzSearchMatch = LzDictionary.Search(DecompressedData, SourcePointer, DecompressedSize); if (LzSearchMatch[1] > 0) // There is a compression match { Flag |= (byte)(0 << i); CompressedData.WriteByte((byte)(LzSearchMatch[0] & 0xFF)); CompressedData.WriteByte((byte)(((LzSearchMatch[0] & 0xF00) >> 4) | ((LzSearchMatch[1] - 3) & 0xF))); LzDictionary.AddEntryRange(DecompressedData, (int)SourcePointer, LzSearchMatch[1]); SourcePointer += (uint)LzSearchMatch[1]; DestPointer += 2; } else // There wasn't a match { Flag |= (byte)(1 << i); CompressedData.WriteByte(DecompressedData[SourcePointer]); LzDictionary.AddEntry(DecompressedData, (int)SourcePointer); SourcePointer++; DestPointer++; } // Check for out of bounds if (SourcePointer >= DecompressedSize) break; } // Write the flag. // Note that the original position gets reset after writing. CompressedData.Seek(FlagPosition, SeekOrigin.Begin); CompressedData.WriteByte(Flag); CompressedData.Seek(DestPointer, SeekOrigin.Begin); } CompressedData.Seek(0x4, SeekOrigin.Begin); CompressedData.Write((uint)CompressedData.Length); CompressedData.Seek(0, SeekOrigin.End); return CompressedData; } catch { return null; // An error occured while compressing } }
/* Compress */ public override MemoryStream Compress(ref Stream data, string filename) { try { uint DecompressedSize = (uint)data.Length; MemoryStream CompressedData = new MemoryStream(); byte[] DecompressedData = data.ToByteArray(); uint SourcePointer = 0x0; uint DestPointer = 0x40; uint MagicValue = (uint)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds; // Test if the file is too large to be compressed if (data.Length > 0xFFFFFFFF) throw new Exception("Input file is too large to compress."); // Set up the Lz Compression Dictionary LzBufferDictionary LzDictionary = new LzBufferDictionary(); LzDictionary.SetBufferSize(0x1000); LzDictionary.SetBufferStart(0xFEE); LzDictionary.SetMaxMatchAmount(0xF + 3); // Start compression CompressedData.Write("LZ00"); CompressedData.Write(0u); // Will be filled in later CompressedData.Seek(8, SeekOrigin.Current); // Advance 8 bytes // If the file extension is MRZ or TEZ, we probably want to change it if (Path.GetExtension(filename).ToLower() == ".mrz") filename = Path.GetFileNameWithoutExtension(filename) + ".mrg"; else if (Path.GetExtension(filename).ToLower() == ".tez") filename = Path.GetFileNameWithoutExtension(filename) + ".tex"; CompressedData.Write(filename, 31, 32, Encoding.GetEncoding("Shift_JIS")); CompressedData.Write(DecompressedSize); CompressedData.Write(MagicValue); CompressedData.Seek(8, SeekOrigin.Current); // Advance 8 bytes while (SourcePointer < DecompressedSize) { MagicValue = GetNewMagicValue(MagicValue); byte Flag = 0x0; uint FlagPosition = DestPointer; uint FlagMagicValue = MagicValue; // Since it won't be filled in now CompressedData.WriteByte(Flag); // It will be filled in later DestPointer++; for (int i = 0; i < 8; i++) { int[] LzSearchMatch = LzDictionary.Search(DecompressedData, SourcePointer, DecompressedSize); if (LzSearchMatch[1] > 0) // There is a compression match { Flag |= (byte)(0 << i); MagicValue = GetNewMagicValue(MagicValue); CompressedData.WriteByte(EncryptByte((byte)(LzSearchMatch[0] & 0xFF), MagicValue)); MagicValue = GetNewMagicValue(MagicValue); CompressedData.WriteByte(EncryptByte((byte)(((LzSearchMatch[0] & 0xF00) >> 4) | ((LzSearchMatch[1] - 3) & 0xF)), MagicValue)); LzDictionary.AddEntryRange(DecompressedData, (int)SourcePointer, LzSearchMatch[1]); SourcePointer += (uint)LzSearchMatch[1]; DestPointer += 2; } else // There wasn't a match { Flag |= (byte)(1 << i); MagicValue = GetNewMagicValue(MagicValue); CompressedData.WriteByte(EncryptByte(DecompressedData[SourcePointer], MagicValue)); LzDictionary.AddEntry(DecompressedData, (int)SourcePointer); SourcePointer++; DestPointer++; } // Check for out of bounds if (SourcePointer >= DecompressedSize) break; } // Write the flag. // Note that the original position gets reset after writing. CompressedData.Seek(FlagPosition, SeekOrigin.Begin); CompressedData.WriteByte(EncryptByte(Flag, FlagMagicValue)); CompressedData.Seek(DestPointer, SeekOrigin.Begin); } CompressedData.Seek(0x4, SeekOrigin.Begin); CompressedData.Write((uint)CompressedData.Length); CompressedData.Seek(0, SeekOrigin.End); return CompressedData; } catch { return null; // An error occured while compressing } }