/// <summary>Creates decompression stream on top of inner stream.</summary> /// <param name="stream">Inner stream.</param> /// <param name="settings">Decompression settings.</param> /// <param name="leaveOpen">Leave inner stream open after disposing.</param> /// <returns>Decompression stream.</returns> public static LZ4DecoderStream Decode( Stream stream, LZ4DecoderSettings settings = null, bool leaveOpen = false) { settings = settings ?? LZ4DecoderSettings.Default; var extraMemory = settings.ExtraMemory; return(new LZ4DecoderStream( stream, i => LZ4Decoder.Create( i.Chaining, i.BlockSize, ExtraBlocks(i.BlockSize, extraMemory)), leaveOpen)); }
private static byte[] Decode(byte[] input, int blockSize, int extraBlocks) { using (var outputStream = new MemoryStream()) using (var inputStream = new MemoryStream(input)) { using (var inputReader = new BinaryReader(inputStream, Encoding.UTF8, false)) using (var outputWriter = new BinaryWriter(outputStream, Encoding.UTF8, true)) using (var decoder = new LZ4Decoder(blockSize, extraBlocks)) { var maximumInputBlock = LZ4Codec.MaximumOutputSize(blockSize); var inputBuffer = new byte[maximumInputBlock]; var outputBuffer = new byte[blockSize]; while (true) { var length = inputReader.ReadInt32(); if (length < 0) { break; } Assert.True(length <= inputBuffer.Length); inputReader.Read(inputBuffer, 0, length); decoder.DecodeAndDrain( inputBuffer, 0, length, outputBuffer, 0, outputBuffer.Length, out var decoded); outputWriter.Write(outputBuffer, 0, decoded); } } return(outputStream.ToArray()); } }
public static unsafe byte[] DecodeChunks(List <ABNDChunk> chunks, uint blockSize, int decLength) { var result = new byte[decLength]; var decoder = LZ4Decoder.Create(true, (int)blockSize, chunks.Count - 1); int offset = 0; foreach (var chunk in chunks) { fixed(byte *chunkP = chunk.Data) { int chunkLen = decoder.Decode(chunkP, (int)chunk.Length); Debug.Assert(chunkLen > 0 || chunk.Length == 1); offset -= chunkLen; } } fixed(byte *resultP = result) { decoder.Drain(resultP, offset, decLength); } return(result); }
public void UnCompressData() { uncompressedData = null; MemoryStream rawStream; if ((header.sectionFlags & SectionFlags.LZ4Compressed) == SectionFlags.LZ4Compressed) { rawStream = new MemoryStream(); int outBuffLen = LZ4Decoder.LZ4_COMPRESSBOUND(LZ4_BLOCK_SIZE); var outBuffer0 = new byte[outBuffLen]; var outBuffer1 = new byte[outBuffLen]; fixed(void *pDiskBase = diskData) fixed(void *pOutBuff0 = outBuffer0) fixed(void *pOutBuff1 = outBuffer1) { byte *pDiskData = (byte *)pDiskBase; byte *pOutBuffer = (byte *)pOutBuff0; using (LZ4Decoder decoder = new LZ4Decoder()) { int loopNo = 0; while (true) { if ((pDiskData - (byte *)pDiskBase) >= diskData.Length) { break; } /* * LZ4 continue 解压会使用上一次解压出的数据的作为下一次解压的字典并且保存数据指针,因此需要不停交换缓冲区 */ bool useBuff0 = loopNo % 2 == 0; pOutBuffer = (byte *)(useBuff0 ? pOutBuff0 : pOutBuff1); // rdc 文件中的压缩数据按page存储,每个page前4个字节存储长度, 由于对齐原因此长度有可能大于 decodedSize int dataSize = *(int *)pDiskData; pDiskData += 4; Debug.Assert(dataSize > 0 && dataSize < outBuffLen); int decodedSize = decoder.LZ4_decompress_safe_continue(pDiskData, pOutBuffer, dataSize, LZ4_BLOCK_SIZE); Debug.Assert(decodedSize > 0 && decodedSize <= outBuffLen); pDiskData += dataSize; rawStream.Write(useBuff0 ? outBuffer0 : outBuffer1, 0, decodedSize); loopNo++; } } } uncompressedData = rawStream.ToArray(); Debug.Assert(uncompressedData.Length == (int)header.sectionUncompressedLength); } else if ((header.sectionFlags & SectionFlags.ZstdCompressed) == SectionFlags.ZstdCompressed) { using (var decoder = new Decompressor()) { uncompressedData = decoder.Unwrap(diskData); } } else // raw data { uncompressedData = diskData; } }