/Utilities/Compression/Streams/InflaterInputStream.cs
C# | 475 lines | 267 code | 44 blank | 164 comment | 17 complexity | 37fbe9e5568a848c9799bf0fdb75b244 MD5 | raw file
Possible License(s): Apache-2.0
- // Based on Mike Krueger's SharpZipLib, Copyright (C) 2001 (GNU license).
- // Authors of the original java version: Jochen Hoenicke, John Leuner
- // See http://www.ISeeSharpCode.com for more information.
-
- using System;
- using System.IO;
- using Delta.Utilities.Compression.Inflaters;
-
- namespace Delta.Utilities.Compression.Streams
- {
- /// <summary>
- /// 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.
- /// Author of the original java version: John Leuner.
- /// </summary>
- public class InflaterInputStream : Stream
- {
- #region IsStreamOwner (Public)
- /// <summary>
- /// Get/set flag indicating ownership of underlying stream.
- /// When the flag is true <see cref="Close"/> will close the underlying
- /// stream also.
- /// </summary>
- /// <remarks>
- /// The default value is true.
- /// </remarks>
- public bool IsStreamOwner
- {
- get
- {
- return isStreamOwner;
- } // get
- set
- {
- isStreamOwner = value;
- } // set
- }
- #endregion
-
- #region CanRead (Public)
- /// <summary>
- /// Gets a value indicating whether the current stream supports reading
- /// </summary>
- public override bool CanRead
- {
- get
- {
- return baseInputStream.CanRead;
- } // get
- }
- #endregion
-
- #region CanSeek (Public)
- /// <summary>
- /// Gets a value of false indicating seeking is not supported for this
- /// stream.
- /// </summary>
- public override bool CanSeek
- {
- get
- {
- return false;
- } // get
- }
- #endregion
-
- #region CanWrite (Public)
- /// <summary>
- /// Gets a value of false indicating that this stream is not writeable.
- /// </summary>
- public override bool CanWrite
- {
- get
- {
- return false;
- } // get
- }
- #endregion
-
- #region Length (Public)
- /// <summary>
- /// A value representing the length of the stream in bytes.
- /// </summary>
- public override long Length
- {
- get
- {
- return inputBuffer.RawLength;
- } // get
- }
- #endregion
-
- #region Position (Public)
- /// <summary>
- /// The current position within the stream.
- /// Throws a NotSupportedException when attempting to set the position
- /// </summary>
- /// <exception cref="NotSupportedException">Attempting to set the position
- /// </exception>
- public override long Position
- {
- get
- {
- return baseInputStream.Position;
- } // get
- set
- {
- throw new NotSupportedException(
- "InflaterInputStream Position not supported");
- } // set
- }
- #endregion
-
- #region IsEntryAvailable (Public)
- /// <summary>
- /// Returns 0 once the end of the stream (EOF) has been reached.
- /// Otherwise returns 1.
- /// </summary>
- public virtual int IsEntryAvailable
- {
- get
- {
- return inf.IsFinished
- ? 0
- : 1;
- } // get
- }
- #endregion
-
- #region Protected
-
- #region inf (Protected)
- /// <summary>
- /// Decompressor for this stream
- /// </summary>
- protected Inflater inf;
- #endregion
-
- #region inputBuffer (Protected)
- /// <summary>
- /// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.
- /// </summary>
- protected InflaterInputBuffer inputBuffer;
- #endregion
-
- #region baseInputStream (Protected)
- /// <summary>
- /// Base stream the inflater reads from.
- /// </summary>
- protected Stream baseInputStream;
- #endregion
-
- #region csize (Protected)
- /// <summary>
- /// The compressed size
- /// </summary>
- protected long csize;
- #endregion
-
- #endregion
-
- #region Private
-
- #region isClosed (Private)
- /// <summary>
- /// Is closed
- /// </summary>
- /// <returns>False</returns>
- private bool isClosed;
- #endregion
-
- #region isStreamOwner (Private)
- /// <summary>
- /// Is stream owner
- /// </summary>
- /// <returns>True</returns>
- private bool isStreamOwner = true;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Create an InflaterInputStream with the default decompressor
- /// and a default buffer size of 4KB.
- /// </summary>
- /// <param name = "baseInputStream">
- /// The InputStream to read bytes from
- /// </param>
- public InflaterInputStream(Stream baseInputStream)
- : this(baseInputStream, new Inflater(), 4096)
- {
- }
-
- // InflaterInputStream(baseInputStream)
-
- /// <summary>
- /// Create an InflaterInputStream with the specified decompressor
- /// and a default buffer size of 4KB.
- /// </summary>
- /// <param name = "baseInputStream">
- /// The source of input data
- /// </param>
- /// <param name = "inf">
- /// The decompressor used to decompress data read from baseInputStream
- /// </param>
- public InflaterInputStream(Stream baseInputStream, Inflater inf)
- : this(baseInputStream, inf, 4096)
- {
- }
-
- // InflaterInputStream(baseInputStream, inf)
-
- /// <summary>
- /// Create an InflaterInputStream with the specified decompressor
- /// and the specified buffer size.
- /// </summary>
- /// <param name = "baseInputStream">
- /// The InputStream to read bytes from
- /// </param>
- /// <param name = "inflater">
- /// The decompressor to use
- /// </param>
- /// <param name = "bufferSize">
- /// Size of the buffer to use
- /// </param>
- public InflaterInputStream(Stream baseInputStream, Inflater inflater,
- int bufferSize)
- {
- if (baseInputStream == null)
- {
- throw new ArgumentNullException(
- "InflaterInputStream baseInputStream is null");
- } // if (baseInputStream)
-
- if (inflater == null)
- {
- throw new ArgumentNullException(
- "InflaterInputStream Inflater is null");
- } // if (inflater)
-
- if (bufferSize <= 0)
- {
- throw new ArgumentOutOfRangeException("bufferSize");
- } // if (bufferSize)
-
- this.baseInputStream = baseInputStream;
- inf = inflater;
-
- inputBuffer = new InflaterInputBuffer(baseInputStream);
- }
- #endregion
-
- #region Flush (Public)
- /// <summary>
- /// Flushes the baseInputStream
- /// </summary>
- public override void Flush()
- {
- baseInputStream.Flush();
- }
- #endregion
-
- #region Seek (Public)
- /// <summary>
- /// Sets the position within the current stream
- /// Always throws a NotSupportedException
- /// </summary>
- /// <exception cref="NotSupportedException">Any access</exception>
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotSupportedException("Seek not supported");
- }
- #endregion
-
- #region SetLength (Public)
- /// <summary>
- /// Set the length of the current stream
- /// Always throws a NotSupportedException
- /// </summary>
- /// <exception cref="NotSupportedException">Any access</exception>
- public override void SetLength(long value)
- {
- throw new NotSupportedException(
- "InflaterInputStream SetLength not supported");
- }
- #endregion
-
- #region Write (Public)
- /// <summary>
- /// Writes a sequence of bytes to stream and advances the current position
- /// This method always throws a NotSupportedException
- /// </summary>
- /// <exception cref="NotSupportedException">Any access</exception>
- public override void Write(byte[] buffer, int offset, int count)
- {
- throw new NotSupportedException(
- "InflaterInputStream Write not supported");
- }
- #endregion
-
- #region WriteByte (Public)
- /// <summary>
- /// Writes one byte to the current stream and advances the current position
- /// Always throws a NotSupportedException
- /// </summary>
- /// <exception cref="NotSupportedException">Any access</exception>
- public override void WriteByte(byte value)
- {
- throw new NotSupportedException(
- "InflaterInputStream WriteByte not supported");
- }
- #endregion
-
- #region BeginWrite (Public)
- /// <summary>
- /// Entry point to begin an asynchronous write.
- /// Always throws a NotSupportedException.
- /// </summary>
- /// <param name="buffer">The buffer to write data from</param>
- /// <param name="offset">Offset of first byte to write</param>
- /// <param name="count">The maximum number of bytes to write</param>
- /// <param name="callback">The method to be called when the asynchronous
- /// write operation is completed</param>
- /// <param name="state">A user-provided object that distinguishes this
- /// particular asynchronous write request from other requests</param>
- /// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that
- /// references the asynchronous write</returns>
- /// <exception cref="NotSupportedException">Any access</exception>
- public override IAsyncResult BeginWrite(
- byte[] buffer, int offset, int count,
- AsyncCallback callback, object state)
- {
- throw new NotSupportedException(
- "InflaterInputStream BeginWrite not supported");
- }
- #endregion
-
- #region Close (Public)
- /// <summary>
- /// Closes the input stream. When <see cref="IsStreamOwner"></see>
- /// is true the underlying stream is also closed.
- /// </summary>
- public override void Close()
- {
- if (!isClosed)
- {
- isClosed = true;
- if (isStreamOwner)
- {
- baseInputStream.Close();
- } // if (isStreamOwner)
- } // if ()
- }
- #endregion
-
- #region Read (Public)
- /// <summary>
- /// Decompresses data into the byte array
- /// </summary>
- /// <param name="buffer">The array to read and decompress data into</param>
- /// <param name="offset">The offset indicating where the data should be
- /// placed</param>
- /// <param name="count">The number of bytes to decompress</param>
- /// <returns>The number of bytes read. Zero signals the end of stream
- /// </returns>
- /// <exception cref="CompressionException">Inflater needs a dictionary
- /// </exception>
- public override int Read(byte[] buffer, int offset, int count)
- {
- for (;;)
- {
- int length;
- try
- {
- length = inf.Inflate(buffer, offset, count);
- } // try
- catch (Exception e)
- {
- throw new CompressionException(e.ToString());
- } // catch
-
- if (length > 0)
- {
- return length;
- } // if (length)
-
- if (inf.IsNeedingDictionary)
- {
- throw new CompressionException("Need a dictionary");
- } // if (inf.IsNeedingDictionary)
- else if (inf.IsFinished)
- {
- return 0;
- } // else if
- else if (inf.IsNeedingInput)
- {
- Fill();
- } // else if
- else
- {
- throw new InvalidOperationException("Don't know what to do");
- } // else
- } // for
- }
- #endregion
-
- #region Skip (Public)
- /// <summary>
- /// Skip specified number of bytes of uncompressed data
- /// </summary>
- /// <param name="numberOfBytesToSkip">Number of bytes to skip</param>
- /// <returns>The number of bytes skipped, zero if the end of stream has
- /// been reached.</returns>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Number of bytes to skip is zero or less
- /// </exception>
- public long Skip(long numberOfBytesToSkip)
- {
- if (numberOfBytesToSkip <= 0)
- {
- throw new ArgumentOutOfRangeException("numberOfBytesToSkip");
- } // if (numberOfBytesToSkip)
-
- // v0.80 Skip by seeking if underlying stream supports it...
- if (baseInputStream.CanSeek)
- {
- baseInputStream.Seek(numberOfBytesToSkip, SeekOrigin.Current);
- return numberOfBytesToSkip;
- } // if (baseInputStream.CanSeek)
- else
- {
- int len = 2048;
- if (numberOfBytesToSkip < len)
- {
- len = (int)numberOfBytesToSkip;
- } // if (numberOfBytesToSkip)
- byte[] tmp = new byte[len];
- return baseInputStream.Read(tmp, 0, tmp.Length);
- } // else
- }
- #endregion
-
- #region Methods (Private)
-
- #region Fill
- /// <summary>
- /// Fills the buffer with more data to decompress.
- /// </summary>
- /// <exception cref="CompressionException">
- /// Stream ends early
- /// </exception>
- protected void Fill()
- {
- inputBuffer.Fill();
- inputBuffer.SetInflaterInput(inf);
- }
- #endregion
-
- // Skip(numberOfBytesToSkip)
-
- #region StopDecrypting
- /// <summary>
- /// Clear any cryptographic state.
- /// </summary>
- protected void StopDecrypting()
- {
- inputBuffer.CryptoTransform = null;
- }
- #endregion
-
- #endregion
- }
- }