PageRenderTime 2531ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

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