mirror of https://github.com/SixLabors/ImageSharp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
3.7 KiB
119 lines
3.7 KiB
// 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()
|
|
{
|
|
if (this.currentDataRemaining is 0)
|
|
{
|
|
this.currentDataRemaining = this.getData();
|
|
if (this.currentDataRemaining is 0)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int value = this.innerStream.ReadByte();
|
|
if (value is not -1)
|
|
{
|
|
this.currentDataRemaining--;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
{
|
|
// Decrement currentDataRemaining only by bytes actually returned by
|
|
// innerStream.Read; a short read otherwise underflows the segment
|
|
// counter and triggers getData() before the segment is truly drained.
|
|
int totalBytesRead = 0;
|
|
while (totalBytesRead < count)
|
|
{
|
|
if (this.currentDataRemaining is 0)
|
|
{
|
|
this.currentDataRemaining = this.getData();
|
|
if (this.currentDataRemaining is 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
int bytesToRead = Math.Min(count - totalBytesRead, this.currentDataRemaining);
|
|
int bytesRead = this.innerStream.Read(buffer, offset + totalBytesRead, bytesToRead);
|
|
if (bytesRead is 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
this.currentDataRemaining -= bytesRead;
|
|
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();
|
|
}
|
|
|