PageRenderTime 85ms CodeModel.GetById 30ms app.highlight 13ms RepoModel.GetById 37ms app.codeStats 1ms

/Utilities/Compression/Streams/InflaterInputStream.cs

#
C# | 475 lines | 267 code | 44 blank | 164 comment | 17 complexity | 37fbe9e5568a848c9799bf0fdb75b244 MD5 | raw file
  1// Based on Mike Krueger's SharpZipLib, Copyright (C) 2001 (GNU license).
  2// Authors of the original java version: Jochen Hoenicke, John Leuner
  3// See http://www.ISeeSharpCode.com for more information.
  4
  5using System;
  6using System.IO;
  7using Delta.Utilities.Compression.Inflaters;
  8
  9namespace Delta.Utilities.Compression.Streams
 10{
 11	/// <summary>
 12	/// This filter stream is used to decompress data compressed using the
 13	/// "deflate" format. The "deflate" format is described in RFC 1951.
 14	/// This stream may form the basis for other decompression filters.
 15	/// Author of the original java version: John Leuner.
 16	/// </summary>
 17	public class InflaterInputStream : Stream
 18	{
 19		#region IsStreamOwner (Public)
 20		/// <summary>
 21		/// Get/set flag indicating ownership of underlying stream.
 22		/// When the flag is true <see cref="Close"/> will close the underlying
 23		/// stream also.
 24		/// </summary>
 25		/// <remarks>
 26		/// The default value is true.
 27		/// </remarks>
 28		public bool IsStreamOwner
 29		{
 30			get
 31			{
 32				return isStreamOwner;
 33			} // get
 34			set
 35			{
 36				isStreamOwner = value;
 37			} // set
 38		}
 39		#endregion
 40
 41		#region CanRead (Public)
 42		/// <summary>
 43		/// Gets a value indicating whether the current stream supports reading
 44		/// </summary>
 45		public override bool CanRead
 46		{
 47			get
 48			{
 49				return baseInputStream.CanRead;
 50			} // get
 51		}
 52		#endregion
 53
 54		#region CanSeek (Public)
 55		/// <summary>
 56		/// Gets a value of false indicating seeking is not supported for this
 57		/// stream.
 58		/// </summary>
 59		public override bool CanSeek
 60		{
 61			get
 62			{
 63				return false;
 64			} // get
 65		}
 66		#endregion
 67
 68		#region CanWrite (Public)
 69		/// <summary>
 70		/// Gets a value of false indicating that this stream is not writeable.
 71		/// </summary>
 72		public override bool CanWrite
 73		{
 74			get
 75			{
 76				return false;
 77			} // get
 78		}
 79		#endregion
 80
 81		#region Length (Public)
 82		/// <summary>
 83		/// A value representing the length of the stream in bytes.
 84		/// </summary>
 85		public override long Length
 86		{
 87			get
 88			{
 89				return inputBuffer.RawLength;
 90			} // get
 91		}
 92		#endregion
 93
 94		#region Position (Public)
 95		/// <summary>
 96		/// The current position within the stream.
 97		/// Throws a NotSupportedException when attempting to set the position
 98		/// </summary>
 99		/// <exception cref="NotSupportedException">Attempting to set the position
100		/// </exception>
101		public override long Position
102		{
103			get
104			{
105				return baseInputStream.Position;
106			} // get
107			set
108			{
109				throw new NotSupportedException(
110					"InflaterInputStream Position not supported");
111			} // set
112		}
113		#endregion
114
115		#region IsEntryAvailable (Public)
116		/// <summary>
117		/// Returns 0 once the end of the stream (EOF) has been reached.
118		/// Otherwise returns 1.
119		/// </summary>
120		public virtual int IsEntryAvailable
121		{
122			get
123			{
124				return inf.IsFinished
125				       	? 0
126				       	: 1;
127			} // get
128		}
129		#endregion
130
131		#region Protected
132
133		#region inf (Protected)
134		/// <summary>
135		/// Decompressor for this stream
136		/// </summary>
137		protected Inflater inf;
138		#endregion
139
140		#region inputBuffer (Protected)
141		/// <summary>
142		/// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.
143		/// </summary>
144		protected InflaterInputBuffer inputBuffer;
145		#endregion
146
147		#region baseInputStream (Protected)
148		/// <summary>
149		/// Base stream the inflater reads from.
150		/// </summary>
151		protected Stream baseInputStream;
152		#endregion
153
154		#region csize (Protected)
155		/// <summary>
156		/// The compressed size
157		/// </summary>
158		protected long csize;
159		#endregion
160
161		#endregion
162
163		#region Private
164
165		#region isClosed (Private)
166		/// <summary>
167		/// Is closed
168		/// </summary>
169		/// <returns>False</returns>
170		private bool isClosed;
171		#endregion
172
173		#region isStreamOwner (Private)
174		/// <summary>
175		/// Is stream owner
176		/// </summary>
177		/// <returns>True</returns>
178		private bool isStreamOwner = true;
179		#endregion
180
181		#endregion
182
183		#region Constructors
184		/// <summary>
185		/// Create an InflaterInputStream with the default decompressor
186		/// and a default buffer size of 4KB.
187		/// </summary>
188		/// <param name = "baseInputStream">
189		/// The InputStream to read bytes from
190		/// </param>
191		public InflaterInputStream(Stream baseInputStream)
192			: this(baseInputStream, new Inflater(), 4096)
193		{
194		}
195
196		// InflaterInputStream(baseInputStream)
197
198		/// <summary>
199		/// Create an InflaterInputStream with the specified decompressor
200		/// and a default buffer size of 4KB.
201		/// </summary>
202		/// <param name = "baseInputStream">
203		/// The source of input data
204		/// </param>
205		/// <param name = "inf">
206		/// The decompressor used to decompress data read from baseInputStream
207		/// </param>
208		public InflaterInputStream(Stream baseInputStream, Inflater inf)
209			: this(baseInputStream, inf, 4096)
210		{
211		}
212
213		// InflaterInputStream(baseInputStream, inf)
214
215		/// <summary>
216		/// Create an InflaterInputStream with the specified decompressor
217		/// and the specified buffer size.
218		/// </summary>
219		/// <param name = "baseInputStream">
220		/// The InputStream to read bytes from
221		/// </param>
222		/// <param name = "inflater">
223		/// The decompressor to use
224		/// </param>
225		/// <param name = "bufferSize">
226		/// Size of the buffer to use
227		/// </param>
228		public InflaterInputStream(Stream baseInputStream, Inflater inflater,
229			int bufferSize)
230		{
231			if (baseInputStream == null)
232			{
233				throw new ArgumentNullException(
234					"InflaterInputStream baseInputStream is null");
235			} // if (baseInputStream)
236
237			if (inflater == null)
238			{
239				throw new ArgumentNullException(
240					"InflaterInputStream Inflater is null");
241			} // if (inflater)
242
243			if (bufferSize <= 0)
244			{
245				throw new ArgumentOutOfRangeException("bufferSize");
246			} // if (bufferSize)
247
248			this.baseInputStream = baseInputStream;
249			inf = inflater;
250
251			inputBuffer = new InflaterInputBuffer(baseInputStream);
252		}
253		#endregion
254
255		#region Flush (Public)
256		/// <summary>
257		/// Flushes the baseInputStream
258		/// </summary>
259		public override void Flush()
260		{
261			baseInputStream.Flush();
262		}
263		#endregion
264
265		#region Seek (Public)
266		/// <summary>
267		/// Sets the position within the current stream
268		/// Always throws a NotSupportedException
269		/// </summary>
270		/// <exception cref="NotSupportedException">Any access</exception>
271		public override long Seek(long offset, SeekOrigin origin)
272		{
273			throw new NotSupportedException("Seek not supported");
274		}
275		#endregion
276
277		#region SetLength (Public)
278		/// <summary>
279		/// Set the length of the current stream
280		/// Always throws a NotSupportedException
281		/// </summary>
282		/// <exception cref="NotSupportedException">Any access</exception>
283		public override void SetLength(long value)
284		{
285			throw new NotSupportedException(
286				"InflaterInputStream SetLength not supported");
287		}
288		#endregion
289
290		#region Write (Public)
291		/// <summary>
292		/// Writes a sequence of bytes to stream and advances the current position
293		/// This method always throws a NotSupportedException
294		/// </summary>
295		/// <exception cref="NotSupportedException">Any access</exception>
296		public override void Write(byte[] buffer, int offset, int count)
297		{
298			throw new NotSupportedException(
299				"InflaterInputStream Write not supported");
300		}
301		#endregion
302
303		#region WriteByte (Public)
304		/// <summary>
305		/// Writes one byte to the current stream and advances the current position
306		/// Always throws a NotSupportedException
307		/// </summary>
308		/// <exception cref="NotSupportedException">Any access</exception>
309		public override void WriteByte(byte value)
310		{
311			throw new NotSupportedException(
312				"InflaterInputStream WriteByte not supported");
313		}
314		#endregion
315
316		#region BeginWrite (Public)
317		/// <summary>
318		/// Entry point to begin an asynchronous write.
319		/// Always throws a NotSupportedException.
320		/// </summary>
321		/// <param name="buffer">The buffer to write data from</param>
322		/// <param name="offset">Offset of first byte to write</param>
323		/// <param name="count">The maximum number of bytes to write</param>
324		/// <param name="callback">The method to be called when the asynchronous
325		/// write operation is completed</param>
326		/// <param name="state">A user-provided object that distinguishes this
327		/// particular asynchronous write request from other requests</param>
328		/// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that
329		/// references the asynchronous write</returns>
330		/// <exception cref="NotSupportedException">Any access</exception>
331		public override IAsyncResult BeginWrite(
332			byte[] buffer, int offset, int count,
333			AsyncCallback callback, object state)
334		{
335			throw new NotSupportedException(
336				"InflaterInputStream BeginWrite not supported");
337		}
338		#endregion
339
340		#region Close (Public)
341		/// <summary>
342		/// Closes the input stream.  When <see cref="IsStreamOwner"></see>
343		/// is true the underlying stream is also closed.
344		/// </summary>
345		public override void Close()
346		{
347			if (!isClosed)
348			{
349				isClosed = true;
350				if (isStreamOwner)
351				{
352					baseInputStream.Close();
353				} // if (isStreamOwner)
354			} // if ()
355		}
356		#endregion
357
358		#region Read (Public)
359		/// <summary>
360		/// Decompresses data into the byte array
361		/// </summary>
362		/// <param name="buffer">The array to read and decompress data into</param>
363		/// <param name="offset">The offset indicating where the data should be
364		/// placed</param>
365		/// <param name="count">The number of bytes to decompress</param>
366		/// <returns>The number of bytes read. Zero signals the end of stream
367		/// </returns>
368		/// <exception cref="CompressionException">Inflater needs a dictionary
369		/// </exception>
370		public override int Read(byte[] buffer, int offset, int count)
371		{
372			for (;;)
373			{
374				int length;
375				try
376				{
377					length = inf.Inflate(buffer, offset, count);
378				} // try
379				catch (Exception e)
380				{
381					throw new CompressionException(e.ToString());
382				} // catch
383
384				if (length > 0)
385				{
386					return length;
387				} // if (length)
388
389				if (inf.IsNeedingDictionary)
390				{
391					throw new CompressionException("Need a dictionary");
392				} // if (inf.IsNeedingDictionary)
393				else if (inf.IsFinished)
394				{
395					return 0;
396				} // else if
397				else if (inf.IsNeedingInput)
398				{
399					Fill();
400				} // else if
401				else
402				{
403					throw new InvalidOperationException("Don't know what to do");
404				} // else
405			} // for
406		}
407		#endregion
408
409		#region Skip (Public)
410		/// <summary>
411		/// Skip specified number of bytes of uncompressed data
412		/// </summary>
413		/// <param name="numberOfBytesToSkip">Number of bytes to skip</param>
414		/// <returns>The number of bytes skipped, zero if the end of stream has
415		/// been reached.</returns>
416		/// <exception cref="ArgumentOutOfRangeException">
417		/// Number of bytes to skip is zero or less
418		/// </exception>
419		public long Skip(long numberOfBytesToSkip)
420		{
421			if (numberOfBytesToSkip <= 0)
422			{
423				throw new ArgumentOutOfRangeException("numberOfBytesToSkip");
424			} // if (numberOfBytesToSkip)
425
426			// v0.80 Skip by seeking if underlying stream supports it...
427			if (baseInputStream.CanSeek)
428			{
429				baseInputStream.Seek(numberOfBytesToSkip, SeekOrigin.Current);
430				return numberOfBytesToSkip;
431			} // if (baseInputStream.CanSeek)
432			else
433			{
434				int len = 2048;
435				if (numberOfBytesToSkip < len)
436				{
437					len = (int)numberOfBytesToSkip;
438				} // if (numberOfBytesToSkip)
439				byte[] tmp = new byte[len];
440				return baseInputStream.Read(tmp, 0, tmp.Length);
441			} // else
442		}
443		#endregion
444
445		#region Methods (Private)
446
447		#region Fill
448		/// <summary>
449		/// Fills the buffer with more data to decompress.
450		/// </summary>
451		/// <exception cref="CompressionException">
452		/// Stream ends early
453		/// </exception>
454		protected void Fill()
455		{
456			inputBuffer.Fill();
457			inputBuffer.SetInflaterInput(inf);
458		}
459		#endregion
460
461		// Skip(numberOfBytesToSkip)
462
463		#region StopDecrypting
464		/// <summary>
465		/// Clear any cryptographic state.
466		/// </summary>		
467		protected void StopDecrypting()
468		{
469			inputBuffer.CryptoTransform = null;
470		}
471		#endregion
472
473		#endregion
474	}
475}