DeflateStream.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. // DeflateStream.cs
  2. // ------------------------------------------------------------------
  3. //
  4. // Copyright (c) 2009-2010 Dino Chiesa.
  5. // All rights reserved.
  6. //
  7. // This code module is part of DotNetZip, a zipfile class library.
  8. //
  9. // ------------------------------------------------------------------
  10. //
  11. // This code is licensed under the Microsoft Public License.
  12. // See the file License.txt for the license details.
  13. // More info on: http://dotnetzip.codeplex.com
  14. //
  15. // ------------------------------------------------------------------
  16. //
  17. // last saved (in emacs):
  18. // Time-stamp: <2010-February-05 08:49:04>
  19. //
  20. // ------------------------------------------------------------------
  21. //
  22. // This module defines the DeflateStream class, which can be used as a replacement for
  23. // the System.IO.Compression.DeflateStream class in the .NET BCL.
  24. //
  25. // ------------------------------------------------------------------
  26. using System;
  27. using System.IO;
  28. using System.Text;
  29. namespace SharpCompress.Compressors.Deflate
  30. {
  31. public class DeflateStream : Stream
  32. {
  33. private readonly ZlibBaseStream _baseStream;
  34. private bool _disposed;
  35. public DeflateStream(Stream stream, CompressionMode mode,
  36. CompressionLevel level = CompressionLevel.Default,
  37. Encoding forceEncoding = null)
  38. {
  39. _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, forceEncoding);
  40. }
  41. #region Zlib properties
  42. /// <summary>
  43. /// This property sets the flush behavior on the stream.
  44. /// </summary>
  45. /// <remarks> See the ZLIB documentation for the meaning of the flush behavior.
  46. /// </remarks>
  47. public virtual FlushType FlushMode
  48. {
  49. get => (_baseStream._flushMode);
  50. set
  51. {
  52. if (_disposed)
  53. {
  54. throw new ObjectDisposedException("DeflateStream");
  55. }
  56. _baseStream._flushMode = value;
  57. }
  58. }
  59. /// <summary>
  60. /// The size of the working buffer for the compression codec.
  61. /// </summary>
  62. ///
  63. /// <remarks>
  64. /// <para>
  65. /// The working buffer is used for all stream operations. The default size is
  66. /// 1024 bytes. The minimum size is 128 bytes. You may get better performance
  67. /// with a larger buffer. Then again, you might not. You would have to test
  68. /// it.
  69. /// </para>
  70. ///
  71. /// <para>
  72. /// Set this before the first call to <c>Read()</c> or <c>Write()</c> on the
  73. /// stream. If you try to set it afterwards, it will throw.
  74. /// </para>
  75. /// </remarks>
  76. public int BufferSize
  77. {
  78. get => _baseStream._bufferSize;
  79. set
  80. {
  81. if (_disposed)
  82. {
  83. throw new ObjectDisposedException("DeflateStream");
  84. }
  85. if (_baseStream._workingBuffer != null)
  86. {
  87. throw new ZlibException("The working buffer is already set.");
  88. }
  89. if (value < ZlibConstants.WorkingBufferSizeMin)
  90. {
  91. throw new ZlibException(
  92. String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value,
  93. ZlibConstants.WorkingBufferSizeMin));
  94. }
  95. _baseStream._bufferSize = value;
  96. }
  97. }
  98. /// <summary>
  99. /// The ZLIB strategy to be used during compression.
  100. /// </summary>
  101. ///
  102. /// <remarks>
  103. /// By tweaking this parameter, you may be able to optimize the compression for
  104. /// data with particular characteristics.
  105. /// </remarks>
  106. public CompressionStrategy Strategy
  107. {
  108. get => _baseStream.Strategy;
  109. set
  110. {
  111. if (_disposed)
  112. {
  113. throw new ObjectDisposedException("DeflateStream");
  114. }
  115. _baseStream.Strategy = value;
  116. }
  117. }
  118. /// <summary> Returns the total number of bytes input so far.</summary>
  119. public virtual long TotalIn => _baseStream._z.TotalBytesIn;
  120. /// <summary> Returns the total number of bytes output so far.</summary>
  121. public virtual long TotalOut => _baseStream._z.TotalBytesOut;
  122. #endregion
  123. #region System.IO.Stream methods
  124. /// <summary>
  125. /// Indicates whether the stream can be read.
  126. /// </summary>
  127. /// <remarks>
  128. /// The return value depends on whether the captive stream supports reading.
  129. /// </remarks>
  130. public override bool CanRead
  131. {
  132. get
  133. {
  134. if (_disposed)
  135. {
  136. throw new ObjectDisposedException("DeflateStream");
  137. }
  138. return _baseStream._stream.CanRead;
  139. }
  140. }
  141. /// <summary>
  142. /// Indicates whether the stream supports Seek operations.
  143. /// </summary>
  144. /// <remarks>
  145. /// Always returns false.
  146. /// </remarks>
  147. public override bool CanSeek => false;
  148. /// <summary>
  149. /// Indicates whether the stream can be written.
  150. /// </summary>
  151. /// <remarks>
  152. /// The return value depends on whether the captive stream supports writing.
  153. /// </remarks>
  154. public override bool CanWrite
  155. {
  156. get
  157. {
  158. if (_disposed)
  159. {
  160. throw new ObjectDisposedException("DeflateStream");
  161. }
  162. return _baseStream._stream.CanWrite;
  163. }
  164. }
  165. /// <summary>
  166. /// Reading this property always throws a <see cref="NotImplementedException"/>.
  167. /// </summary>
  168. public override long Length => throw new NotSupportedException();
  169. /// <summary>
  170. /// The position of the stream pointer.
  171. /// </summary>
  172. ///
  173. /// <remarks>
  174. /// Setting this property always throws a <see
  175. /// cref="NotImplementedException"/>. Reading will return the total bytes
  176. /// written out, if used in writing, or the total bytes read in, if used in
  177. /// reading. The count may refer to compressed bytes or uncompressed bytes,
  178. /// depending on how you've used the stream.
  179. /// </remarks>
  180. public override long Position
  181. {
  182. get
  183. {
  184. if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer)
  185. {
  186. return _baseStream._z.TotalBytesOut;
  187. }
  188. if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader)
  189. {
  190. return _baseStream._z.TotalBytesIn;
  191. }
  192. return 0;
  193. }
  194. set => throw new NotSupportedException();
  195. }
  196. /// <summary>
  197. /// Dispose the stream.
  198. /// </summary>
  199. /// <remarks>
  200. /// This may or may not result in a <c>Close()</c> call on the captive stream.
  201. /// </remarks>
  202. protected override void Dispose(bool disposing)
  203. {
  204. try
  205. {
  206. if (!_disposed)
  207. {
  208. if (disposing)
  209. {
  210. _baseStream?.Dispose();
  211. }
  212. _disposed = true;
  213. }
  214. }
  215. finally
  216. {
  217. base.Dispose(disposing);
  218. }
  219. }
  220. /// <summary>
  221. /// Flush the stream.
  222. /// </summary>
  223. public override void Flush()
  224. {
  225. if (_disposed)
  226. {
  227. throw new ObjectDisposedException("DeflateStream");
  228. }
  229. _baseStream.Flush();
  230. }
  231. /// <summary>
  232. /// Read data from the stream.
  233. /// </summary>
  234. /// <remarks>
  235. ///
  236. /// <para>
  237. /// If you wish to use the <c>DeflateStream</c> to compress data while
  238. /// reading, you can create a <c>DeflateStream</c> with
  239. /// <c>CompressionMode.Compress</c>, providing an uncompressed data stream.
  240. /// Then call Read() on that <c>DeflateStream</c>, and the data read will be
  241. /// compressed as you read. If you wish to use the <c>DeflateStream</c> to
  242. /// decompress data while reading, you can create a <c>DeflateStream</c> with
  243. /// <c>CompressionMode.Decompress</c>, providing a readable compressed data
  244. /// stream. Then call Read() on that <c>DeflateStream</c>, and the data read
  245. /// will be decompressed as you read.
  246. /// </para>
  247. ///
  248. /// <para>
  249. /// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not both.
  250. /// </para>
  251. ///
  252. /// </remarks>
  253. /// <param name="buffer">The buffer into which the read data should be placed.</param>
  254. /// <param name="offset">the offset within that data array to put the first byte read.</param>
  255. /// <param name="count">the number of bytes to read.</param>
  256. /// <returns>the number of bytes actually read</returns>
  257. public override int Read(byte[] buffer, int offset, int count)
  258. {
  259. if (_disposed)
  260. {
  261. throw new ObjectDisposedException("DeflateStream");
  262. }
  263. return _baseStream.Read(buffer, offset, count);
  264. }
  265. public override int ReadByte()
  266. {
  267. if (_disposed)
  268. {
  269. throw new ObjectDisposedException("DeflateStream");
  270. }
  271. return _baseStream.ReadByte();
  272. }
  273. /// <summary>
  274. /// Calling this method always throws a <see cref="NotImplementedException"/>.
  275. /// </summary>
  276. /// <param name="offset">this is irrelevant, since it will always throw!</param>
  277. /// <param name="origin">this is irrelevant, since it will always throw!</param>
  278. /// <returns>irrelevant!</returns>
  279. public override long Seek(long offset, SeekOrigin origin)
  280. {
  281. throw new NotSupportedException();
  282. }
  283. /// <summary>
  284. /// Calling this method always throws a <see cref="NotImplementedException"/>.
  285. /// </summary>
  286. /// <param name="value">this is irrelevant, since it will always throw!</param>
  287. public override void SetLength(long value)
  288. {
  289. throw new NotSupportedException();
  290. }
  291. /// <summary>
  292. /// Write data to the stream.
  293. /// </summary>
  294. /// <remarks>
  295. ///
  296. /// <para>
  297. /// If you wish to use the <c>DeflateStream</c> to compress data while
  298. /// writing, you can create a <c>DeflateStream</c> with
  299. /// <c>CompressionMode.Compress</c>, and a writable output stream. Then call
  300. /// <c>Write()</c> on that <c>DeflateStream</c>, providing uncompressed data
  301. /// as input. The data sent to the output stream will be the compressed form
  302. /// of the data written. If you wish to use the <c>DeflateStream</c> to
  303. /// decompress data while writing, you can create a <c>DeflateStream</c> with
  304. /// <c>CompressionMode.Decompress</c>, and a writable output stream. Then
  305. /// call <c>Write()</c> on that stream, providing previously compressed
  306. /// data. The data sent to the output stream will be the decompressed form of
  307. /// the data written.
  308. /// </para>
  309. ///
  310. /// <para>
  311. /// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>,
  312. /// but not both.
  313. /// </para>
  314. ///
  315. /// </remarks>
  316. ///
  317. /// <param name="buffer">The buffer holding data to write to the stream.</param>
  318. /// <param name="offset">the offset within that data array to find the first byte to write.</param>
  319. /// <param name="count">the number of bytes to write.</param>
  320. public override void Write(byte[] buffer, int offset, int count)
  321. {
  322. if (_disposed)
  323. {
  324. throw new ObjectDisposedException("DeflateStream");
  325. }
  326. _baseStream.Write(buffer, offset, count);
  327. }
  328. public override void WriteByte(byte value)
  329. {
  330. if (_disposed)
  331. {
  332. throw new ObjectDisposedException("DeflateStream");
  333. }
  334. _baseStream.WriteByte(value);
  335. }
  336. #endregion
  337. public MemoryStream InputBuffer => new MemoryStream(_baseStream._z.InputBuffer, _baseStream._z.NextIn,
  338. _baseStream._z.AvailableBytesIn);
  339. }
  340. }