diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index 58cfa6a70..d5b5bfd0e 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -24,7 +24,14 @@ namespace ImageSharp.Formats
///
/// The dictionary of available color types.
///
- private static readonly Dictionary ColorTypes = new Dictionary();
+ private static readonly Dictionary ColorTypes = new Dictionary()
+ {
+ [PngColorType.Grayscale] = new byte[] { 1, 2, 4, 8 },
+ [PngColorType.Rgb] = new byte[] { 8 },
+ [PngColorType.Palette] = new byte[] { 1, 2, 4, 8 },
+ [PngColorType.GrayscaleWithAlpha] = new byte[] { 8 },
+ [PngColorType.RgbWithAlpha] = new byte[] { 8 },
+ };
///
/// The amount to increment when processing each column per scanline for each interlaced pass
@@ -122,20 +129,24 @@ namespace ImageSharp.Formats
private bool isEndChunkReached;
///
- /// Initializes static members of the class.
+ /// Previous scanline processed
///
- static PngDecoderCore()
- {
- ColorTypes.Add((int)PngColorType.Grayscale, new byte[] { 1, 2, 4, 8 });
-
- ColorTypes.Add((int)PngColorType.Rgb, new byte[] { 8 });
+ private byte[] previousScanline;
- ColorTypes.Add((int)PngColorType.Palette, new byte[] { 1, 2, 4, 8 });
+ ///
+ /// The current scanline that is being processed
+ ///
+ private byte[] scanline;
- ColorTypes.Add((int)PngColorType.GrayscaleWithAlpha, new byte[] { 8 });
+ ///
+ /// The index of the current scanline being processed
+ ///
+ private int currentRow = 0;
- ColorTypes.Add((int)PngColorType.RgbWithAlpha, new byte[] { 8 });
- }
+ ///
+ /// The current number of bytes read in the current scanline
+ ///
+ private int currentRowBytesRead = 0;
///
/// Initializes a new instance of the class.
@@ -171,65 +182,76 @@ namespace ImageSharp.Formats
ImageMetaData metadata = new ImageMetaData();
this.currentStream = stream;
this.currentStream.Skip(8);
-
- using (MemoryStream dataStream = new MemoryStream())
+ Image image = null;
+ PixelAccessor pixels = null;
+ try
{
- PngChunk currentChunk;
- while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null)
+ using (DeframeStream deframeStream = new DeframeStream(this.currentStream))
{
- try
+ PngChunk currentChunk;
+ while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null)
{
- switch (currentChunk.Type)
+ try
{
- case PngChunkTypes.Header:
- this.ReadHeaderChunk(currentChunk.Data);
- this.ValidateHeader();
- break;
- case PngChunkTypes.Physical:
- this.ReadPhysicalChunk(metadata, currentChunk.Data);
- break;
- case PngChunkTypes.Data:
- dataStream.Write(currentChunk.Data, 0, currentChunk.Length);
- break;
- case PngChunkTypes.Palette:
- byte[] pal = new byte[currentChunk.Length];
- Buffer.BlockCopy(currentChunk.Data, 0, pal, 0, currentChunk.Length);
- this.palette = pal;
- metadata.Quality = pal.Length / 3;
- break;
- case PngChunkTypes.PaletteAlpha:
- byte[] alpha = new byte[currentChunk.Length];
- Buffer.BlockCopy(currentChunk.Data, 0, alpha, 0, currentChunk.Length);
- this.paletteAlpha = alpha;
- break;
- case PngChunkTypes.Text:
- this.ReadTextChunk(metadata, currentChunk.Data, currentChunk.Length);
- break;
- case PngChunkTypes.End:
- this.isEndChunkReached = true;
- break;
+ switch (currentChunk.Type)
+ {
+ case PngChunkTypes.Header:
+ this.ReadHeaderChunk(currentChunk.Data);
+ this.ValidateHeader();
+ break;
+ case PngChunkTypes.Physical:
+ this.ReadPhysicalChunk(metadata, currentChunk.Data);
+ break;
+ case PngChunkTypes.Data:
+ if (image == null)
+ {
+ this.InitializeImage(metadata, out image, out pixels);
+ }
+
+ deframeStream.AllocateNewBytes(currentChunk.Length);
+ this.ReadScanlines(deframeStream.CompressedStream, pixels);
+ stream.Read(this.crcBuffer, 0, 4);
+ break;
+ case PngChunkTypes.Palette:
+ byte[] pal = new byte[currentChunk.Length];
+ Buffer.BlockCopy(currentChunk.Data, 0, pal, 0, currentChunk.Length);
+ this.palette = pal;
+ metadata.Quality = pal.Length / 3;
+ break;
+ case PngChunkTypes.PaletteAlpha:
+ byte[] alpha = new byte[currentChunk.Length];
+ Buffer.BlockCopy(currentChunk.Data, 0, alpha, 0, currentChunk.Length);
+ this.paletteAlpha = alpha;
+ break;
+ case PngChunkTypes.Text:
+ this.ReadTextChunk(metadata, currentChunk.Data, currentChunk.Length);
+ break;
+ case PngChunkTypes.End:
+ this.isEndChunkReached = true;
+ break;
+ }
+ }
+ finally
+ {
+ // Data is rented in ReadChunkData()
+ if (currentChunk.Data != null)
+ {
+ ArrayPool.Shared.Return(currentChunk.Data);
+ }
}
}
- finally
- {
- // Data is rented in ReadChunkData()
- ArrayPool.Shared.Return(currentChunk.Data);
- }
- }
-
- if (this.header.Width > Image.MaxWidth || this.header.Height > Image.MaxHeight)
- {
- throw new ArgumentOutOfRangeException($"The input png '{this.header.Width}x{this.header.Height}' is bigger than the max allowed size '{Image.MaxWidth}x{Image.MaxHeight}'");
}
- Image image = Image.Create(this.header.Width, this.header.Height, metadata, this.configuration);
-
- using (PixelAccessor pixels = image.Lock())
+ return image;
+ }
+ finally
+ {
+ pixels?.Dispose();
+ if (this.previousScanline != null)
{
- this.ReadScanlines(dataStream, pixels);
+ ArrayPool.Shared.Return(this.previousScanline);
+ ArrayPool.Shared.Return(this.scanline);
}
-
- return image;
}
}
@@ -293,6 +315,39 @@ namespace ImageSharp.Formats
metadata.VerticalResolution = BitConverter.ToInt32(data, 4) / 39.3700787d;
}
+ ///
+ /// Initializes the image and various buffers needed for processing
+ ///
+ /// The type the pixels will be
+ /// The metadata information for the image
+ /// The image that we will populate
+ /// The pixel accessor
+ private void InitializeImage(ImageMetaData metadata, out Image image, out PixelAccessor pixels)
+ where TPixel : struct, IPixel
+ {
+ if (this.header.Width > Image.MaxWidth || this.header.Height > Image.MaxHeight)
+ {
+ throw new ArgumentOutOfRangeException($"The input png '{this.header.Width}x{this.header.Height}' is bigger than the max allowed size '{Image.MaxWidth}x{Image.MaxHeight}'");
+ }
+
+ image = Image.Create(this.header.Width, this.header.Height, metadata, this.configuration);
+ pixels = image.Lock();
+ this.bytesPerPixel = this.CalculateBytesPerPixel();
+ this.bytesPerScanline = this.CalculateScanlineLength(this.header.Width) + 1;
+ this.bytesPerSample = 1;
+ if (this.header.BitDepth >= 8)
+ {
+ this.bytesPerSample = this.header.BitDepth / 8;
+ }
+
+ this.previousScanline = ArrayPool.Shared.Rent(this.bytesPerScanline);
+ this.scanline = ArrayPool.Shared.Rent(this.bytesPerScanline);
+
+ // Zero out the scanlines, because the bytes that are rented from the arraypool may not be zero.
+ Array.Clear(this.scanline, 0, this.bytesPerScanline);
+ Array.Clear(this.previousScanline, 0, this.bytesPerScanline);
+ }
+
///
/// Calculates the correct number of bytes per pixel for the given color type.
///
@@ -345,28 +400,16 @@ namespace ImageSharp.Formats
/// The pixel format.
/// The containing data.
/// The pixel data.
- private void ReadScanlines(MemoryStream dataStream, PixelAccessor pixels)
+ private void ReadScanlines(Stream dataStream, PixelAccessor pixels)
where TPixel : struct, IPixel
{
- this.bytesPerPixel = this.CalculateBytesPerPixel();
- this.bytesPerScanline = this.CalculateScanlineLength(this.header.Width) + 1;
- this.bytesPerSample = 1;
- if (this.header.BitDepth >= 8)
+ if (this.header.InterlaceMethod == PngInterlaceMode.Adam7)
{
- this.bytesPerSample = this.header.BitDepth / 8;
+ this.DecodeInterlacedPixelData(dataStream, pixels);
}
-
- dataStream.Position = 0;
- using (ZlibInflateStream compressedStream = new ZlibInflateStream(dataStream))
+ else
{
- if (this.header.InterlaceMethod == PngInterlaceMode.Adam7)
- {
- this.DecodeInterlacedPixelData(compressedStream, pixels);
- }
- else
- {
- this.DecodePixelData(compressedStream, pixels);
- }
+ this.DecodePixelData(dataStream, pixels);
}
}
@@ -379,66 +422,58 @@ namespace ImageSharp.Formats
private void DecodePixelData(Stream compressedStream, PixelAccessor pixels)
where TPixel : struct, IPixel
{
- byte[] previousScanline = ArrayPool.Shared.Rent(this.bytesPerScanline);
- byte[] scanline = ArrayPool.Shared.Rent(this.bytesPerScanline);
-
- // Zero out the scanlines, because the bytes that are rented from the arraypool may not be zero.
- Array.Clear(scanline, 0, this.bytesPerScanline);
- Array.Clear(previousScanline, 0, this.bytesPerScanline);
-
- try
+ while (this.currentRow < this.header.Height)
{
- for (int y = 0; y < this.header.Height; y++)
+ int bytesRead = compressedStream.Read(this.scanline, this.currentRowBytesRead, this.bytesPerScanline - this.currentRowBytesRead);
+ this.currentRowBytesRead += bytesRead;
+ if (this.currentRowBytesRead < this.bytesPerScanline)
{
- compressedStream.Read(scanline, 0, this.bytesPerScanline);
+ return;
+ }
- FilterType filterType = (FilterType)scanline[0];
+ this.currentRowBytesRead = 0;
+ FilterType filterType = (FilterType)this.scanline[0];
- switch (filterType)
- {
- case FilterType.None:
+ switch (filterType)
+ {
+ case FilterType.None:
- NoneFilter.Decode(scanline);
+ NoneFilter.Decode(this.scanline);
- break;
+ break;
- case FilterType.Sub:
+ case FilterType.Sub:
- SubFilter.Decode(scanline, this.bytesPerScanline, this.bytesPerPixel);
+ SubFilter.Decode(this.scanline, this.bytesPerScanline, this.bytesPerPixel);
- break;
+ break;
- case FilterType.Up:
+ case FilterType.Up:
- UpFilter.Decode(scanline, previousScanline, this.bytesPerScanline);
+ UpFilter.Decode(this.scanline, this.previousScanline, this.bytesPerScanline);
- break;
+ break;
- case FilterType.Average:
+ case FilterType.Average:
- AverageFilter.Decode(scanline, previousScanline, this.bytesPerScanline, this.bytesPerPixel);
+ AverageFilter.Decode(this.scanline, this.previousScanline, this.bytesPerScanline, this.bytesPerPixel);
- break;
+ break;
- case FilterType.Paeth:
+ case FilterType.Paeth:
- PaethFilter.Decode(scanline, previousScanline, this.bytesPerScanline, this.bytesPerPixel);
+ PaethFilter.Decode(this.scanline, this.previousScanline, this.bytesPerScanline, this.bytesPerPixel);
- break;
+ break;
- default:
- throw new ImageFormatException("Unknown filter type.");
- }
+ default:
+ throw new ImageFormatException("Unknown filter type.");
+ }
- this.ProcessDefilteredScanline(scanline, y, pixels);
+ this.ProcessDefilteredScanline(this.scanline, pixels);
- Swap(ref scanline, ref previousScanline);
- }
- }
- finally
- {
- ArrayPool.Shared.Return(previousScanline);
- ArrayPool.Shared.Return(scanline);
+ Swap(ref this.scanline, ref this.previousScanline);
+ this.currentRow++;
}
}
@@ -536,12 +571,13 @@ namespace ImageSharp.Formats
///
/// The pixel format.
/// The de-filtered scanline
- /// The current image row.
/// The image pixels
- private void ProcessDefilteredScanline(byte[] defilteredScanline, int row, PixelAccessor pixels)
+ private void ProcessDefilteredScanline(byte[] defilteredScanline, PixelAccessor pixels)
where TPixel : struct, IPixel
{
TPixel color = default(TPixel);
+ BufferSpan pixelBuffer = pixels.GetRowSpan(this.currentRow);
+ BufferSpan scanlineBuffer = new BufferSpan(defilteredScanline, 1);
switch (this.PngColorType)
{
case PngColorType.Grayscale:
@@ -551,7 +587,7 @@ namespace ImageSharp.Formats
{
byte intensity = (byte)(newScanline1[x] * factor);
color.PackFromBytes(intensity, intensity, intensity, 255);
- pixels[x, row] = color;
+ pixels[x, this.currentRow] = color;
}
break;
@@ -566,91 +602,84 @@ namespace ImageSharp.Formats
byte alpha = defilteredScanline[offset + this.bytesPerSample];
color.PackFromBytes(intensity, intensity, intensity, alpha);
- pixels[x, row] = color;
+ pixels[x, this.currentRow] = color;
}
break;
case PngColorType.Palette:
- byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth);
+ this.ProcessScanlineFromPalette(defilteredScanline, pixels);
- if (this.paletteAlpha != null && this.paletteAlpha.Length > 0)
- {
- // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha
- // channel and we should try to read it.
- for (int x = 0; x < this.header.Width; x++)
- {
- int index = newScanline[x + 1];
- int pixelOffset = index * 3;
+ break;
- byte a = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255;
+ case PngColorType.Rgb:
- if (a > 0)
- {
- byte r = this.palette[pixelOffset];
- byte g = this.palette[pixelOffset + 1];
- byte b = this.palette[pixelOffset + 2];
- color.PackFromBytes(r, g, b, a);
- }
- else
- {
- color.PackFromBytes(0, 0, 0, 0);
- }
+ BulkPixelOperations.Instance.PackFromXyzBytes(scanlineBuffer, pixelBuffer, this.header.Width);
- pixels[x, row] = color;
- }
- }
- else
- {
- for (int x = 0; x < this.header.Width; x++)
- {
- int index = newScanline[x + 1];
- int pixelOffset = index * 3;
+ break;
- byte r = this.palette[pixelOffset];
- byte g = this.palette[pixelOffset + 1];
- byte b = this.palette[pixelOffset + 2];
+ case PngColorType.RgbWithAlpha:
- color.PackFromBytes(r, g, b, 255);
- pixels[x, row] = color;
- }
- }
+ BulkPixelOperations.Instance.PackFromXyzwBytes(scanlineBuffer, pixelBuffer, this.header.Width);
break;
+ }
+ }
- case PngColorType.Rgb:
+ ///
+ /// Processes a scanline that uses a palette
+ ///
+ /// The type of pixel we are expanding to
+ /// The scanline
+ /// The output pixels
+ private void ProcessScanlineFromPalette(byte[] defilteredScanline, PixelAccessor pixels)
+ where TPixel : struct, IPixel
+ {
+ byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth);
+ byte[] palette = this.palette;
+ TPixel color = default(TPixel);
- for (int x = 0; x < this.header.Width; x++)
- {
- int offset = 1 + (x * this.bytesPerPixel);
+ if (this.paletteAlpha != null && this.paletteAlpha.Length > 0)
+ {
+ // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha
+ // channel and we should try to read it.
+ for (int x = 0; x < this.header.Width; x++)
+ {
+ int index = newScanline[x + 1];
+ int pixelOffset = index * 3;
- byte r = defilteredScanline[offset];
- byte g = defilteredScanline[offset + this.bytesPerSample];
- byte b = defilteredScanline[offset + (2 * this.bytesPerSample)];
+ byte a = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255;
- color.PackFromBytes(r, g, b, 255);
- pixels[x, row] = color;
+ if (a > 0)
+ {
+ byte r = palette[pixelOffset];
+ byte g = palette[pixelOffset + 1];
+ byte b = palette[pixelOffset + 2];
+ color.PackFromBytes(r, g, b, a);
}
-
- break;
-
- case PngColorType.RgbWithAlpha:
-
- for (int x = 0; x < this.header.Width; x++)
+ else
{
- int offset = 1 + (x * this.bytesPerPixel);
+ color.PackFromBytes(0, 0, 0, 0);
+ }
- byte r = defilteredScanline[offset];
- byte g = defilteredScanline[offset + this.bytesPerSample];
- byte b = defilteredScanline[offset + (2 * this.bytesPerSample)];
- byte a = defilteredScanline[offset + (3 * this.bytesPerSample)];
+ pixels[x, this.currentRow] = color;
+ }
+ }
+ else
+ {
+ for (int x = 0; x < this.header.Width; x++)
+ {
+ int index = newScanline[x + 1];
+ int pixelOffset = index * 3;
- color.PackFromBytes(r, g, b, a);
- pixels[x, row] = color;
- }
+ byte r = palette[pixelOffset];
+ byte g = palette[pixelOffset + 1];
+ byte b = palette[pixelOffset + 2];
- break;
+ color.PackFromBytes(r, g, b, 255);
+ pixels[x, this.currentRow] = color;
+ }
}
}
@@ -819,7 +848,7 @@ namespace ImageSharp.Formats
this.header.Height = BitConverter.ToInt32(data, 4);
this.header.BitDepth = data[8];
- this.header.ColorType = data[9];
+ this.header.ColorType = (PngColorType)data[9];
this.header.CompressionMethod = data[10];
this.header.FilterMethod = data[11];
this.header.InterlaceMethod = (PngInterlaceMode)data[12];
@@ -872,6 +901,11 @@ namespace ImageSharp.Formats
}
this.ReadChunkType(chunk);
+ if (chunk.Type == PngChunkTypes.Data)
+ {
+ return chunk;
+ }
+
this.ReadChunkData(chunk);
this.ReadChunkCrc(chunk);
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index e30f9791e..31e8cd90e 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -181,7 +181,7 @@ namespace ImageSharp.Formats
{
Width = image.Width,
Height = image.Height,
- ColorType = (byte)this.pngColorType,
+ ColorType = this.pngColorType,
BitDepth = this.bitDepth,
FilterMethod = 0, // None
CompressionMethod = 0,
@@ -462,7 +462,7 @@ namespace ImageSharp.Formats
WriteInteger(this.chunkDataBuffer, 4, header.Height);
this.chunkDataBuffer[8] = header.BitDepth;
- this.chunkDataBuffer[9] = header.ColorType;
+ this.chunkDataBuffer[9] = (byte)header.ColorType;
this.chunkDataBuffer[10] = header.CompressionMethod;
this.chunkDataBuffer[11] = header.FilterMethod;
this.chunkDataBuffer[12] = (byte)header.InterlaceMethod;
diff --git a/src/ImageSharp/Formats/Png/PngHeader.cs b/src/ImageSharp/Formats/Png/PngHeader.cs
index f1d332c04..50d6cc9ec 100644
--- a/src/ImageSharp/Formats/Png/PngHeader.cs
+++ b/src/ImageSharp/Formats/Png/PngHeader.cs
@@ -34,7 +34,7 @@ namespace ImageSharp.Formats
/// image data. Color type codes represent sums of the following values:
/// 1 (palette used), 2 (color used), and 4 (alpha channel used).
///
- public byte ColorType { get; set; }
+ public PngColorType ColorType { get; set; }
///
/// Gets or sets the compression method.
diff --git a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs
index 5f92cc9e0..e5101532c 100644
--- a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs
+++ b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs
@@ -132,18 +132,13 @@ namespace ImageSharp.Formats
throw new ArgumentOutOfRangeException(nameof(count), "cannot be negative");
}
- if (offset >= buffer.Length)
- {
- throw new ArgumentOutOfRangeException(nameof(offset), "not a valid index into buffer");
- }
-
if (offset + count > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(count), "exceeds buffer size");
}
// (By Per Bothner)
- uint s1 = this.checksum & 0xFFFF;
+ uint s1 = this.checksum;
uint s2 = this.checksum >> 16;
while (count > 0)
@@ -151,16 +146,12 @@ namespace ImageSharp.Formats
// We can defer the modulo operation:
// s1 maximally grows from 65521 to 65521 + 255 * 3800
// s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
- int n = 3800;
- if (n > count)
- {
- n = count;
- }
+ int n = Math.Min(3800, count);
count -= n;
- while (--n >= 0)
+ while (--n > -1)
{
- s1 = s1 + (uint)(buffer[offset++] & 0xff);
+ s1 = s1 + buffer[offset++];
s2 = s2 + s1;
}
diff --git a/src/ImageSharp/Formats/Png/Zlib/DeframeStream.cs b/src/ImageSharp/Formats/Png/Zlib/DeframeStream.cs
new file mode 100644
index 000000000..9b0a61b67
--- /dev/null
+++ b/src/ImageSharp/Formats/Png/Zlib/DeframeStream.cs
@@ -0,0 +1,121 @@
+namespace ImageSharp.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text;
+
+ ///
+ /// Provides methods and properties for deframing streams from PNGs.
+ ///
+ internal class DeframeStream : Stream
+ {
+ ///
+ /// The inner raw memory stream
+ ///
+ private readonly Stream innerStream;
+
+ ///
+ /// The compressed stream sitting over the top of the deframer
+ ///
+ private ZlibInflateStream compressedStream;
+
+ ///
+ /// The current data remaining to be read
+ ///
+ private int currentDataRemaining;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The inner raw stream
+ public DeframeStream(Stream innerStream)
+ {
+ this.innerStream = innerStream;
+ }
+
+ ///
+ public override bool CanRead => this.innerStream.CanRead;
+
+ ///
+ public override bool CanSeek => false;
+
+ ///
+ public override bool CanWrite => throw new NotSupportedException();
+
+ ///
+ public override long Length => throw new NotSupportedException();
+
+ ///
+ public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+
+ ///
+ /// Gets the compressed stream over the deframed inner stream
+ ///
+ public ZlibInflateStream CompressedStream => this.compressedStream;
+
+ ///
+ /// Adds new bytes from a frame found in the original stream
+ ///
+ /// blabla
+ public void AllocateNewBytes(int bytes)
+ {
+ this.currentDataRemaining = bytes;
+ if (this.compressedStream == null)
+ {
+ this.compressedStream = new ZlibInflateStream(this);
+ }
+ }
+
+ ///
+ public override void Flush()
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ public override int ReadByte()
+ {
+ this.currentDataRemaining--;
+ return this.innerStream.ReadByte();
+ }
+
+ ///
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (this.currentDataRemaining == 0)
+ {
+ return 0;
+ }
+
+ int bytesToRead = Math.Min(count, this.currentDataRemaining);
+ this.currentDataRemaining -= bytesToRead;
+ return this.innerStream.Read(buffer, offset, bytesToRead);
+ }
+
+ ///
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ this.compressedStream.Dispose();
+ base.Dispose(disposing);
+ }
+ }
+}