mirror of https://github.com/SixLabors/ImageSharp
3 changed files with 167 additions and 203 deletions
@ -0,0 +1,125 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using SixLabors.ImageSharp.IO; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Compression.Zlib; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A read-only stream over a sequence of length-delimited segments. Bytes are
|
||||
|
/// pulled from the inner stream up to the current segment's remaining length;
|
||||
|
/// when the segment is exhausted the supplied delegate is invoked to advance
|
||||
|
/// to the next segment and return its length. The inner stream is not owned
|
||||
|
/// and is not disposed.
|
||||
|
/// </summary>
|
||||
|
internal sealed class ChunkedReadStream : Stream |
||||
|
{ |
||||
|
private static readonly Func<int> GetDataNoOp = () => 0; |
||||
|
|
||||
|
private readonly BufferedReadStream innerStream; |
||||
|
private readonly Func<int> getData; |
||||
|
private int currentDataRemaining; |
||||
|
|
||||
|
public ChunkedReadStream(BufferedReadStream innerStream) |
||||
|
: this(innerStream, GetDataNoOp) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public ChunkedReadStream(BufferedReadStream innerStream, Func<int> getData) |
||||
|
{ |
||||
|
this.innerStream = innerStream; |
||||
|
this.getData = getData; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override bool CanRead => this.innerStream.CanRead; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override bool CanSeek => false; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override bool CanWrite => throw new NotSupportedException(); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override long Length => throw new NotSupportedException(); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the number of bytes available to read from the current segment.
|
||||
|
/// Must be called before reading each segment.
|
||||
|
/// </summary>
|
||||
|
public void SetCurrentSegmentLength(int bytes) => this.currentDataRemaining = bytes; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override void Flush() => throw new NotSupportedException(); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override int ReadByte() |
||||
|
{ |
||||
|
this.currentDataRemaining--; |
||||
|
return this.innerStream.ReadByte(); |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override int Read(byte[] buffer, int offset, int count) |
||||
|
{ |
||||
|
if (this.currentDataRemaining is 0) |
||||
|
{ |
||||
|
// Current segment is exhausted; ask the caller for the next one.
|
||||
|
this.currentDataRemaining = this.getData(); |
||||
|
|
||||
|
if (this.currentDataRemaining is 0) |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int bytesToRead = Math.Min(count, this.currentDataRemaining); |
||||
|
this.currentDataRemaining -= bytesToRead; |
||||
|
int totalBytesRead = this.innerStream.Read(buffer, offset, bytesToRead); |
||||
|
long innerStreamLength = this.innerStream.Length; |
||||
|
|
||||
|
// Keep reading data until we've reached the end of the stream or filled the buffer.
|
||||
|
int bytesRead = 0; |
||||
|
offset += totalBytesRead; |
||||
|
while (this.currentDataRemaining is 0 && totalBytesRead < count) |
||||
|
{ |
||||
|
this.currentDataRemaining = this.getData(); |
||||
|
|
||||
|
if (this.currentDataRemaining is 0) |
||||
|
{ |
||||
|
return totalBytesRead; |
||||
|
} |
||||
|
|
||||
|
offset += bytesRead; |
||||
|
|
||||
|
if (offset >= innerStreamLength || offset >= count) |
||||
|
{ |
||||
|
return totalBytesRead; |
||||
|
} |
||||
|
|
||||
|
bytesToRead = Math.Min(count - totalBytesRead, this.currentDataRemaining); |
||||
|
this.currentDataRemaining -= bytesToRead; |
||||
|
bytesRead = this.innerStream.Read(buffer, offset, bytesToRead); |
||||
|
if (bytesRead == 0) |
||||
|
{ |
||||
|
return totalBytesRead; |
||||
|
} |
||||
|
|
||||
|
totalBytesRead += bytesRead; |
||||
|
} |
||||
|
|
||||
|
return totalBytesRead; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override void SetLength(long value) => throw new NotSupportedException(); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); |
||||
|
} |
||||
Loading…
Reference in new issue