GzipOutputStream.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. using System.Net.ApiService.Compression.Checksum;
  2. using System.Net.ApiService.Compression.Zip.Compression;
  3. using System.Net.ApiService.Compression.Zip.Compression.Streams;
  4. using System;
  5. using System.IO;
  6. namespace System.Net.ApiService.Compression.GZip {
  7. /// <summary>
  8. /// This filter stream is used to compress a stream into a "GZIP" stream.
  9. /// The "GZIP" format is described in RFC 1952.
  10. ///
  11. /// author of the original java version : John Leuner
  12. /// </summary>
  13. /// <example> This sample shows how to gzip a file
  14. /// <code>
  15. /// using System;
  16. /// using System.IO;
  17. ///
  18. /// using ICSharpCode.SharpZipLib.GZip;
  19. /// using ICSharpCode.SharpZipLib.Core;
  20. ///
  21. /// class MainClass
  22. /// {
  23. /// public static void Main(string[] args)
  24. /// {
  25. /// using (Stream s = new GZipOutputStream(File.Create(args[0] + ".gz")))
  26. /// using (FileStream fs = File.OpenRead(args[0])) {
  27. /// byte[] writeData = new byte[4096];
  28. /// Streamutils.Copy(s, fs, writeData);
  29. /// }
  30. /// }
  31. /// }
  32. /// }
  33. /// </code>
  34. /// </example>
  35. public class GZipOutputStream : DeflaterOutputStream
  36. {
  37. private enum OutputState
  38. {
  39. Header,
  40. Footer,
  41. Finished,
  42. Closed,
  43. };
  44. #region Instance Fields
  45. /// <summary>
  46. /// CRC-32 value for uncompressed data
  47. /// </summary>
  48. protected Crc32 crc = new Crc32();
  49. private OutputState state_ = OutputState.Header;
  50. #endregion Instance Fields
  51. #region Constructors
  52. /// <summary>
  53. /// Creates a GzipOutputStream with the default buffer size
  54. /// </summary>
  55. /// <param name="baseOutputStream">
  56. /// The stream to read data (to be compressed) from
  57. /// </param>
  58. public GZipOutputStream(Stream baseOutputStream)
  59. : this(baseOutputStream, 4096)
  60. {
  61. }
  62. /// <summary>
  63. /// Creates a GZipOutputStream with the specified buffer size
  64. /// </summary>
  65. /// <param name="baseOutputStream">
  66. /// The stream to read data (to be compressed) from
  67. /// </param>
  68. /// <param name="size">
  69. /// Size of the buffer to use
  70. /// </param>
  71. public GZipOutputStream(Stream baseOutputStream, int size) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size)
  72. {
  73. }
  74. #endregion Constructors
  75. #region Public API
  76. /// <summary>
  77. /// Sets the active compression level (0-9). The new level will be activated
  78. /// immediately.
  79. /// </summary>
  80. /// <param name="level">The compression level to set.</param>
  81. /// <exception cref="ArgumentOutOfRangeException">
  82. /// Level specified is not supported.
  83. /// </exception>
  84. /// <see cref="Deflater"/>
  85. public void SetLevel(int level)
  86. {
  87. if (level < Deflater.NO_COMPRESSION || level > Deflater.BEST_COMPRESSION)
  88. throw new ArgumentOutOfRangeException(nameof(level), "Compression level must be 0-9");
  89. deflater_.SetLevel(level);
  90. }
  91. /// <summary>
  92. /// Get the current compression level.
  93. /// </summary>
  94. /// <returns>The current compression level.</returns>
  95. public int GetLevel()
  96. {
  97. return deflater_.GetLevel();
  98. }
  99. #endregion Public API
  100. #region Stream overrides
  101. /// <summary>
  102. /// Write given buffer to output updating crc
  103. /// </summary>
  104. /// <param name="buffer">Buffer to write</param>
  105. /// <param name="offset">Offset of first byte in buf to write</param>
  106. /// <param name="count">Number of bytes to write</param>
  107. public override void Write(byte[] buffer, int offset, int count)
  108. {
  109. if (state_ == OutputState.Header)
  110. {
  111. WriteHeader();
  112. }
  113. if (state_ != OutputState.Footer)
  114. {
  115. throw new InvalidOperationException("Write not permitted in current state");
  116. }
  117. crc.Update(new ArraySegment<byte>(buffer, offset, count));
  118. base.Write(buffer, offset, count);
  119. }
  120. /// <summary>
  121. /// Writes remaining compressed output data to the output stream
  122. /// and closes it.
  123. /// </summary>
  124. protected override void Dispose(bool disposing)
  125. {
  126. try
  127. {
  128. Finish();
  129. }
  130. finally
  131. {
  132. if (state_ != OutputState.Closed)
  133. {
  134. state_ = OutputState.Closed;
  135. if (IsStreamOwner)
  136. {
  137. baseOutputStream_.Dispose();
  138. }
  139. }
  140. }
  141. }
  142. #endregion Stream overrides
  143. #region DeflaterOutputStream overrides
  144. /// <summary>
  145. /// Finish compression and write any footer information required to stream
  146. /// </summary>
  147. public override void Finish()
  148. {
  149. // If no data has been written a header should be added.
  150. if (state_ == OutputState.Header)
  151. {
  152. WriteHeader();
  153. }
  154. if (state_ == OutputState.Footer)
  155. {
  156. state_ = OutputState.Finished;
  157. base.Finish();
  158. var totalin = (uint)(deflater_.TotalIn & 0xffffffff);
  159. var crcval = (uint)(crc.Value & 0xffffffff);
  160. byte[] gzipFooter;
  161. unchecked
  162. {
  163. gzipFooter = new byte[] {
  164. (byte) crcval, (byte) (crcval >> 8),
  165. (byte) (crcval >> 16), (byte) (crcval >> 24),
  166. (byte) totalin, (byte) (totalin >> 8),
  167. (byte) (totalin >> 16), (byte) (totalin >> 24)
  168. };
  169. }
  170. baseOutputStream_.Write(gzipFooter, 0, gzipFooter.Length);
  171. }
  172. }
  173. #endregion DeflaterOutputStream overrides
  174. #region Support Routines
  175. private void WriteHeader()
  176. {
  177. if (state_ == OutputState.Header)
  178. {
  179. state_ = OutputState.Footer;
  180. var mod_time = (int)((DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000L); // Ticks give back 100ns intervals
  181. byte[] gzipHeader = {
  182. // The two magic bytes
  183. (byte) (GZipConstants.GZIP_MAGIC >> 8), (byte) (GZipConstants.GZIP_MAGIC & 0xff),
  184. // The compression type
  185. (byte) Deflater.DEFLATED,
  186. // The flags (not set)
  187. 0,
  188. // The modification time
  189. (byte) mod_time, (byte) (mod_time >> 8),
  190. (byte) (mod_time >> 16), (byte) (mod_time >> 24),
  191. // The extra flags
  192. 0,
  193. // The OS type (unknown)
  194. (byte) 255
  195. };
  196. baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length);
  197. }
  198. }
  199. #endregion Support Routines
  200. }
  201. }