public static void Decompress(CompressionHeader header, MemoryMappedViewAccessor original, MemoryMappedViewAccessor uncompressed) { switch (header.Compression) { case CompressionType.LZ77: case CompressionType.ExtendedLZ77: LZ77.Expand(header, original, uncompressed); break; default: throw new ArgumentException($"{header.Compression} is not properly supported."); } }
/// <summary> /// Uncompresses a valid LZ77 file. /// </summary> /// <param name="header">The compression header of the original file.</param> /// <param name="original">The original file accessor.</param> /// <param name="uncompressed">The uncompressed file accessor to write to.</param> public static void Expand(CompressionHeader header, MemoryMappedViewAccessor original, MemoryMappedViewAccessor uncompressed) { var extended = header.Compression == CompressionType.ExtendedLZ77; var uncompLen = uncompressed.Capacity; long origPos = header.HeaderSize; long uncompPos = 0; while (uncompPos < uncompLen) { byte bit = 8; var control = original.ReadByte(origPos++); while (bit-- != 0 && uncompPos < uncompLen) { if ((control & (1 << bit)) == 0) { uncompressed.Write(uncompPos++, original.ReadByte(origPos++)); } else { var temp = original.ReadByte(origPos) >> 4; var num = !extended ? temp + 3 : temp == 1 ? (((original.ReadByte(origPos++) & 0x0F) << 12) | (original.ReadByte(origPos++) << 4) | (original.ReadByte(origPos) >> 4)) + 0xFF + 0xF + 3 : temp == 0 ? (((original.ReadByte(origPos++) & 0x0F) << 4) | (original.ReadByte(origPos) >> 4)) + 0xF + 2 : temp + 1; var offset = (((original.ReadByte(origPos++) & 0xF) << 8) | original.ReadByte(origPos++)) + 2; while (uncompPos != uncompLen && num-- > 0) { uncompressed.Write(uncompPos++, uncompressed.ReadByte(uncompPos - offset)); } } } } }