GzipOutputStream.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. // GZipOutputStream.cs
  2. //
  3. // Copyright (C) 2001 Mike Krueger
  4. //
  5. // This file was translated from java, it was part of the GNU Classpath
  6. // Copyright (C) 2001 Free Software Foundation, Inc.
  7. //
  8. // This program is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU General Public License
  10. // as published by the Free Software Foundation; either version 2
  11. // of the License, or (at your option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU General Public License
  19. // along with this program; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. //
  22. // Linking this library statically or dynamically with other modules is
  23. // making a combined work based on this library. Thus, the terms and
  24. // conditions of the GNU General Public License cover the whole
  25. // combination.
  26. //
  27. // As a special exception, the copyright holders of this library give you
  28. // permission to link this library with independent modules to produce an
  29. // executable, regardless of the license terms of these independent
  30. // modules, and to copy and distribute the resulting executable under
  31. // terms of your choice, provided that you also meet, for each linked
  32. // independent module, the terms and conditions of the license of that
  33. // module. An independent module is a module which is not derived from
  34. // or based on this library. If you modify this library, you may extend
  35. // this exception to your version of the library, but you are not
  36. // obligated to do so. If you do not wish to do so, delete this
  37. // exception statement from your version.
  38. using System;
  39. using System.IO;
  40. using CommonMPQ.SharpZipLib.Checksums;
  41. using CommonMPQ.SharpZipLib.Zip.Compression;
  42. using CommonMPQ.SharpZipLib.Zip.Compression.Streams;
  43. namespace CommonMPQ.SharpZipLib.GZip
  44. {
  45. /// <summary>
  46. /// This filter stream is used to compress a stream into a "GZIP" stream.
  47. /// The "GZIP" format is described in RFC 1952.
  48. ///
  49. /// author of the original java version : John Leuner
  50. /// </summary>
  51. /// <example> This sample shows how to gzip a file
  52. /// <code>
  53. /// using System;
  54. /// using System.IO;
  55. ///
  56. /// using CommonMPQ.SharpZipLib.GZip;
  57. /// using CommonMPQ.SharpZipLib.Core;
  58. ///
  59. /// class MainClass
  60. /// {
  61. /// public static void Main(string[] args)
  62. /// {
  63. /// using (Stream s = new GZipOutputStream(File.Create(args[0] + ".gz")))
  64. /// using (FileStream fs = File.OpenRead(args[0])) {
  65. /// byte[] writeData = new byte[4096];
  66. /// Streamutils.Copy(s, fs, writeData);
  67. /// }
  68. /// }
  69. /// }
  70. /// }
  71. /// </code>
  72. /// </example>
  73. public class GZipOutputStream : DeflaterOutputStream
  74. {
  75. enum OutputState
  76. {
  77. Header,
  78. Footer,
  79. Finished,
  80. Closed,
  81. };
  82. #region Instance Fields
  83. /// <summary>
  84. /// CRC-32 value for uncompressed data
  85. /// </summary>
  86. protected Crc32 crc = new Crc32();
  87. OutputState state_ = OutputState.Header;
  88. #endregion
  89. #region Constructors
  90. /// <summary>
  91. /// Creates a GzipOutputStream with the default buffer size
  92. /// </summary>
  93. /// <param name="baseOutputStream">
  94. /// The stream to read data (to be compressed) from
  95. /// </param>
  96. public GZipOutputStream(Stream baseOutputStream)
  97. : this(baseOutputStream, 4096)
  98. {
  99. }
  100. /// <summary>
  101. /// Creates a GZipOutputStream with the specified buffer size
  102. /// </summary>
  103. /// <param name="baseOutputStream">
  104. /// The stream to read data (to be compressed) from
  105. /// </param>
  106. /// <param name="size">
  107. /// Size of the buffer to use
  108. /// </param>
  109. public GZipOutputStream(Stream baseOutputStream, int size) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size)
  110. {
  111. }
  112. #endregion
  113. #region Public API
  114. /// <summary>
  115. /// Sets the active compression level (1-9). The new level will be activated
  116. /// immediately.
  117. /// </summary>
  118. /// <param name="level">The compression level to set.</param>
  119. /// <exception cref="ArgumentOutOfRangeException">
  120. /// Level specified is not supported.
  121. /// </exception>
  122. /// <see cref="Deflater"/>
  123. public void SetLevel(int level)
  124. {
  125. if (level < Deflater.BEST_SPEED) {
  126. throw new ArgumentOutOfRangeException("level");
  127. }
  128. deflater_.SetLevel(level);
  129. }
  130. /// <summary>
  131. /// Get the current compression level.
  132. /// </summary>
  133. /// <returns>The current compression level.</returns>
  134. public int GetLevel()
  135. {
  136. return deflater_.GetLevel();
  137. }
  138. #endregion
  139. #region Stream overrides
  140. /// <summary>
  141. /// Write given buffer to output updating crc
  142. /// </summary>
  143. /// <param name="buffer">Buffer to write</param>
  144. /// <param name="offset">Offset of first byte in buf to write</param>
  145. /// <param name="count">Number of bytes to write</param>
  146. public override void Write(byte[] buffer, int offset, int count)
  147. {
  148. if ( state_ == OutputState.Header ) {
  149. WriteHeader();
  150. }
  151. if( state_!=OutputState.Footer )
  152. {
  153. throw new InvalidOperationException("Write not permitted in current state");
  154. }
  155. crc.Update(buffer, offset, count);
  156. base.Write(buffer, offset, count);
  157. }
  158. /// <summary>
  159. /// Writes remaining compressed output data to the output stream
  160. /// and closes it.
  161. /// </summary>
  162. public override void Close()
  163. {
  164. try {
  165. Finish();
  166. }
  167. finally {
  168. if ( state_ != OutputState.Closed ) {
  169. state_ = OutputState.Closed;
  170. if( IsStreamOwner ) {
  171. baseOutputStream_.Close();
  172. }
  173. }
  174. }
  175. }
  176. #endregion
  177. #region DeflaterOutputStream overrides
  178. /// <summary>
  179. /// Finish compression and write any footer information required to stream
  180. /// </summary>
  181. public override void Finish()
  182. {
  183. // If no data has been written a header should be added.
  184. if ( state_ == OutputState.Header ) {
  185. WriteHeader();
  186. }
  187. if( state_ == OutputState.Footer)
  188. {
  189. state_=OutputState.Finished;
  190. base.Finish();
  191. uint totalin=(uint)(deflater_.TotalIn&0xffffffff);
  192. uint crcval=(uint)(crc.Value&0xffffffff);
  193. byte[] gzipFooter;
  194. unchecked
  195. {
  196. gzipFooter=new byte[] {
  197. (byte) crcval, (byte) (crcval >> 8),
  198. (byte) (crcval >> 16), (byte) (crcval >> 24),
  199. (byte) totalin, (byte) (totalin >> 8),
  200. (byte) (totalin >> 16), (byte) (totalin >> 24)
  201. };
  202. }
  203. baseOutputStream_.Write(gzipFooter, 0, gzipFooter.Length);
  204. }
  205. }
  206. #endregion
  207. #region Support Routines
  208. void WriteHeader()
  209. {
  210. if ( state_ == OutputState.Header )
  211. {
  212. state_=OutputState.Footer;
  213. int mod_time = (int)((DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000L); // Ticks give back 100ns intervals
  214. byte[] gzipHeader = {
  215. // The two magic bytes
  216. (byte) (GZipConstants.GZIP_MAGIC >> 8), (byte) (GZipConstants.GZIP_MAGIC & 0xff),
  217. // The compression type
  218. (byte) Deflater.DEFLATED,
  219. // The flags (not set)
  220. 0,
  221. // The modification time
  222. (byte) mod_time, (byte) (mod_time >> 8),
  223. (byte) (mod_time >> 16), (byte) (mod_time >> 24),
  224. // The extra flags
  225. 0,
  226. // The OS type (unknown)
  227. (byte) 255
  228. };
  229. baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length);
  230. }
  231. }
  232. #endregion
  233. }
  234. }