Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions Zstandard.Net/ZstandardStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ public override int Read(byte[] buffer, int offset, int count)
try
{
var length = 0;
var endOfBlockFound = false;

if (this.isInitialized == false)
{
Expand Down Expand Up @@ -262,14 +263,22 @@ public override int Read(byte[] buffer, int offset, int count)
this.outputBuffer.Position = UIntPtr.Zero;

// decompress inputBuffer to outputBuffer
Interop.ThrowIfError(Interop.ZSTD_decompressStream(this.zstream, this.outputBuffer, this.inputBuffer));
var nextSrcNeeded = Interop.ZSTD_decompressStream(this.zstream, this.outputBuffer, this.inputBuffer);
Interop.ThrowIfError(nextSrcNeeded);

//It is possible that nextSrcNeeded == 0 when at the end of a block but outputBufferPosition is not yet 0, and there are not any more bytes to be read on the incoming stream.
//If that happens the next time ZSTD_decompressStream() is called then nextSrcNeeded will be the next header size (i.e. 9) instead of 0, then when when outputBufferPosition does hit 0
//it will not "break" which will result in an additional stream read, which can hang.
//To avoid that we need to set a flag when nextSrcNeeded == 0, so when outputBufferPosition also reaches 0, it will hit the "break".
if (nextSrcNeeded.ToUInt64() == 0UL) endOfBlockFound = true;

// calculate progress in outputBuffer
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();

if (outputBufferPosition == 0)
{
// the internal buffer is depleted, we're either done
if (this.dataDepleted) break;
if (this.dataDepleted || endOfBlockFound) break;

// or we need more bytes
this.dataSkipRead = false;
Expand Down