namespace ImageProcessor.Formats { using System; using System.IO; //using ICSharpCode.SharpZipLib; //using ICSharpCode.SharpZipLib.Zip; //using ICSharpCode.SharpZipLib.Zip.Compression; /// /// This filter stream is used to decompress data compressed using the "deflate" /// format. The "deflate" format is described in RFC 1951. /// /// This stream may form the basis for other decompression filters, such /// as the GZipInputStream. /// /// Author of the original java version : John Leuner. /// public class InflaterInputStream : Stream { #region Constructors /// /// Create an InflaterInputStream with the default decompressor /// and a default buffer size of 4KB. /// /// /// The InputStream to read bytes from /// public InflaterInputStream(Stream baseInputStream) : this(baseInputStream, new Inflater(), 4096) { } /// /// Create an InflaterInputStream with the specified decompressor /// and a default buffer size of 4KB. /// /// /// The source of input data /// /// /// The decompressor used to decompress data read from baseInputStream /// public InflaterInputStream(Stream baseInputStream, Inflater inf) : this(baseInputStream, inf, 4096) { } /// /// Create an InflaterInputStream with the specified decompressor and the specified buffer size. /// /// /// The InputStream to read bytes from /// /// /// The decompressor to use /// /// /// Size of the buffer to use /// public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize) { if (baseInputStream == null) { throw new ArgumentNullException("baseInputStream"); } if (inflater == null) { throw new ArgumentNullException("inflater"); } if (bufferSize <= 0) { throw new ArgumentOutOfRangeException("bufferSize"); } this.baseInputStream = baseInputStream; this.inf = inflater; inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize); } #endregion /// /// Get/set flag indicating ownership of underlying stream. /// When the flag is true will close the underlying stream also. /// /// /// The default value is true. /// public bool IsStreamOwner { get { return isStreamOwner; } set { isStreamOwner = value; } } /// /// Skip specified number of bytes of uncompressed data /// /// /// Number of bytes to skip /// /// /// The number of bytes skipped, zero if the end of /// stream has been reached /// /// /// The number of bytes to skip is less than or equal to zero. /// public long Skip(long count) { if (count <= 0) { throw new ArgumentOutOfRangeException("count"); } // v0.80 Skip by seeking if underlying stream supports it... if (baseInputStream.CanSeek) { baseInputStream.Seek(count, SeekOrigin.Current); return count; } else { int length = 2048; if (count < length) { length = (int)count; } byte[] tmp = new byte[length]; int readCount = 1; long toSkip = count; while ((toSkip > 0) && (readCount > 0)) { if (toSkip < length) { length = (int)toSkip; } readCount = baseInputStream.Read(tmp, 0, length); toSkip -= readCount; } return count - toSkip; } } /// /// Clear any cryptographic state. /// protected void StopDecrypting() { #if !NETCF_1_0 && !NOCRYPTO inputBuffer.CryptoTransform = null; #endif } /// /// Returns 0 once the end of the stream (EOF) has been reached. /// Otherwise returns 1. /// public virtual int Available { get { return inf.IsFinished ? 0 : 1; } } /// /// Fills the buffer with more data to decompress. /// /// /// Stream ends early /// protected void Fill() { // Protect against redundant calls if (inputBuffer.Available <= 0) { inputBuffer.Fill(); if (inputBuffer.Available <= 0) { throw new ImageFormatException("Unexpected EOF"); } } inputBuffer.SetInflaterInput(inf); } #region Stream Overrides /// /// Gets a value indicating whether the current stream supports reading /// public override bool CanRead { get { return baseInputStream.CanRead; } } /// /// Gets a value of false indicating seeking is not supported for this stream. /// public override bool CanSeek { get { return false; } } /// /// Gets a value of false indicating that this stream is not writeable. /// public override bool CanWrite { get { return false; } } /// /// A value representing the length of the stream in bytes. /// public override long Length { get { return inputBuffer.RawLength; } } /// /// The current position within the stream. /// Throws a NotSupportedException when attempting to set the position /// /// Attempting to set the position public override long Position { get { return baseInputStream.Position; } set { throw new NotSupportedException("InflaterInputStream Position not supported"); } } /// /// Flushes the baseInputStream /// public override void Flush() { baseInputStream.Flush(); } /// /// Sets the position within the current stream /// Always throws a NotSupportedException /// /// The relative offset to seek to. /// The defining where to seek from. /// The new position in the stream. /// Any access public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException("Seek not supported"); } /// /// Set the length of the current stream /// Always throws a NotSupportedException /// /// The new length value for the stream. /// Any access public override void SetLength(long value) { throw new NotSupportedException("InflaterInputStream SetLength not supported"); } /// /// Writes a sequence of bytes to stream and advances the current position /// This method always throws a NotSupportedException /// /// Thew buffer containing data to write. /// The offset of the first byte to write. /// The number of bytes to write. /// Any access public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException("InflaterInputStream Write not supported"); } /// /// Writes one byte to the current stream and advances the current position /// Always throws a NotSupportedException /// /// The byte to write. /// Any access public override void WriteByte(byte value) { throw new NotSupportedException("InflaterInputStream WriteByte not supported"); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing && !isClosed) { isClosed = true; if (isStreamOwner) { baseInputStream.Dispose(); } } } /// /// Reads decompressed data into the provided buffer byte array /// /// /// The array to read and decompress data into /// /// /// The offset indicating where the data should be placed /// /// /// The number of bytes to decompress /// /// The number of bytes read. Zero signals the end of stream /// /// Inflater needs a dictionary /// public override int Read(byte[] buffer, int offset, int count) { if (inf.IsNeedingDictionary) { throw new ImageFormatException("Need a dictionary"); } int remainingBytes = count; while (true) { int bytesRead = inf.Inflate(buffer, offset, remainingBytes); offset += bytesRead; remainingBytes -= bytesRead; if (remainingBytes == 0 || inf.IsFinished) { break; } if (inf.IsNeedingInput) { Fill(); } else if (bytesRead == 0) { throw new ImageFormatException("Dont know what to do"); } } return count - remainingBytes; } #endregion #region Instance Fields /// /// Decompressor for this stream /// protected Inflater inf; /// /// Input buffer for this stream. /// protected InflaterInputBuffer inputBuffer; /// /// Base stream the inflater reads from. /// private Stream baseInputStream; /// /// The compressed size /// protected long csize; /// /// Flag indicating wether this instance has been closed or not. /// bool isClosed; /// /// Flag indicating wether this instance is designated the stream owner. /// When closing if this flag is true the underlying stream is closed. /// bool isStreamOwner = true; #endregion } }