ZlibStream.cs 12 KB

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