/// <summary>Flushes current chunk.</summary> private void FlushCurrentChunk() { if (_bufferOffset <= 0) { return; } var compressed = new byte[_bufferOffset]; var compressedLength = _highCompression ? LZ4Codec.EncodeHC(_buffer, 0, _bufferOffset, compressed, 0, _bufferOffset) : LZ4Codec.Encode(_buffer, 0, _bufferOffset, compressed, 0, _bufferOffset); if (compressedLength <= 0 || compressedLength >= _bufferOffset) { // incompressible block compressed = _buffer; compressedLength = _bufferOffset; } var isCompressed = compressedLength < _bufferOffset; if (fileHeaderInfo == null) { fileHeaderInfo = new LZ4FileHeaderInfo(); fileHeaderInfo.FrameDescriptor_BD_BlockMaxSize = BlockMaximumSize.Block64K; fileHeaderInfo.FrameDescriptor_FLG_BChecksum = false; fileHeaderInfo.FrameDescriptor_FLG_BIndependence = true; fileHeaderInfo.FrameDescriptor_FLG_ContentChecksum = true; fileHeaderInfo.FrameDescriptor_FLG_ContentSize = false; fileHeaderInfo.FrameDescriptor_FLG_Version = 64; //U32 const xxh = XXH32(header, length, 0); //return (BYTE)(xxh >> 8); // *dstPtr = LZ4F_headerChecksum(headerStart, dstPtr - headerStart); LZ4FileHeaderInfo.WriteHeader(_innerStream, fileHeaderInfo); } LZ4HeaderChunkInfo chunkInfo = new LZ4HeaderChunkInfo(); chunkInfo.IsCompressed = true; chunkInfo.ChunkSize = compressedLength; LZ4HeaderChunkInfo.WriteHeader(_innerStream, chunkInfo); _innerStream.Write(compressed, 0, compressedLength); _bufferOffset = 0; }
/// <summary>Reads the next chunk from stream.</summary> /// <returns><c>true</c> if next has been read, or <c>false</c> if it is legitimate end of file. /// Throws <see cref="EndOfStreamException"/> if end of stream was unexpected.</returns> private bool AcquireNextChunk() { do { if (fileHeaderInfo == null) { fileHeaderInfo = _formatReader.ReadHeader(_innerStream); } if (blockInfo != null && blockInfo.ChunkSize <= 0) { return(false); } blockInfo = _formatReader.ReadChunkHeader(_innerStream); int compressedLength = blockInfo.ChunkSize; if (compressedLength <= 0 || compressedLength > GetBufferSize(fileHeaderInfo.FrameDescriptor_BD_BlockMaxSize)) { return(false); } bool isCompressed = blockInfo.IsCompressed; var compressed = new byte[compressedLength]; var chunk = ReadBlock(compressed, 0, compressedLength); if (chunk != compressedLength) { throw EndOfStream(); // corrupted } if (!isCompressed) { _buffer = compressed; // no compression on this chunk _bufferLength = compressedLength; } else { int bSize = GetBufferSize(fileHeaderInfo.FrameDescriptor_BD_BlockMaxSize); if (_buffer == null) { _buffer = new byte[bSize]; } _bufferLength = LZ4Codec.Decode(compressed, 0, compressedLength, _buffer, 0, bSize, false); } _bufferOffset = 0; } while (_bufferLength == 0); // skip empty block (shouldn't happen but...) return(true); }
///// <summary>Reads the variable length int. Work with assumption that value is in the stream ///// and throws exception if it isn't. If you want to check if value is in the stream ///// use <see cref="TryReadVarInt"/> instead.</summary> ///// <returns></returns> //ulong ReadVarInt(Stream stream) //{ // ulong result; // if (!TryReadVarInt(stream, out result)) throw new EndOfStreamException(); // return result; //} ///// <summary>Tries to read variable length int.</summary> ///// <param name="result">The result.</param> ///// <returns><c>true</c> if integer has been read, <c>false</c> if end of stream has been ///// encountered. If end of stream has been encountered in the middle of value ///// <see cref="EndOfStreamException"/> is thrown.</returns> //bool TryReadVarInt(Stream stream, out ulong result) //{ // var buffer = new byte[1]; // var count = 0; // result = 0; // while (true) // { // if (stream.Read(buffer, 0, 1) == 0) // { // if (count == 0) return false; // throw new EndOfStreamException(); // } // var b = buffer[0]; // result = result + ((ulong)(b & 0x7F) << count); // count += 7; // if ((b & 0x80) == 0 || count >= 64) break; // } // return true; //} public LZ4HeaderChunkInfo ReadChunkHeader(Stream stream) { var info = new LZ4HeaderChunkInfo(stream); return(info); }