1. /*
  2. * @(#)GZIPOutputStream.java 1.21 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.util.zip;
  8. import java.io.OutputStream;
  9. import java.io.IOException;
  10. /**
  11. * This class implements a stream filter for writing compressed data in
  12. * the GZIP file format.
  13. * @version 1.21, 01/23/03
  14. * @author David Connelly
  15. *
  16. */
  17. public
  18. class GZIPOutputStream extends DeflaterOutputStream {
  19. /**
  20. * CRC-32 of uncompressed data.
  21. */
  22. protected CRC32 crc = new CRC32();
  23. /*
  24. * GZIP header magic number.
  25. */
  26. private final static int GZIP_MAGIC = 0x8b1f;
  27. /*
  28. * Trailer size in bytes.
  29. *
  30. */
  31. private final static int TRAILER_SIZE = 8;
  32. /**
  33. * Creates a new output stream with the specified buffer size.
  34. * @param out the output stream
  35. * @param size the output buffer size
  36. * @exception IOException If an I/O error has occurred.
  37. * @exception IllegalArgumentException if size is <= 0
  38. */
  39. public GZIPOutputStream(OutputStream out, int size) throws IOException {
  40. super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size);
  41. usesDefaultDeflater = true;
  42. writeHeader();
  43. crc.reset();
  44. }
  45. /**
  46. * Creates a new output stream with a default buffer size.
  47. * @param out the output stream
  48. * @exception IOException If an I/O error has occurred.
  49. */
  50. public GZIPOutputStream(OutputStream out) throws IOException {
  51. this(out, 512);
  52. }
  53. /**
  54. * Writes array of bytes to the compressed output stream. This method
  55. * will block until all the bytes are written.
  56. * @param buf the data to be written
  57. * @param off the start offset of the data
  58. * @param len the length of the data
  59. * @exception IOException If an I/O error has occurred.
  60. */
  61. public synchronized void write(byte[] buf, int off, int len)
  62. throws IOException
  63. {
  64. super.write(buf, off, len);
  65. crc.update(buf, off, len);
  66. }
  67. /**
  68. * Finishes writing compressed data to the output stream without closing
  69. * the underlying stream. Use this method when applying multiple filters
  70. * in succession to the same output stream.
  71. * @exception IOException if an I/O error has occurred
  72. */
  73. public void finish() throws IOException {
  74. if (!def.finished()) {
  75. def.finish();
  76. while (!def.finished()) {
  77. int len = def.deflate(buf, 0, buf.length);
  78. if (def.finished() && len <= buf.length - TRAILER_SIZE) {
  79. // last deflater buffer. Fit trailer at the end
  80. writeTrailer(buf, len);
  81. len = len + TRAILER_SIZE;
  82. out.write(buf, 0, len);
  83. return;
  84. }
  85. if (len > 0)
  86. out.write(buf, 0, len);
  87. }
  88. // if we can't fit the trailer at the end of the last
  89. // deflater buffer, we write it separately
  90. byte[] trailer = new byte[TRAILER_SIZE];
  91. writeTrailer(trailer, 0);
  92. out.write(trailer);
  93. }
  94. }
  95. /*
  96. * Writes GZIP member header.
  97. */
  98. private final static byte[] header = {
  99. (byte) GZIP_MAGIC, // Magic number (short)
  100. (byte)(GZIP_MAGIC >> 8), // Magic number (short)
  101. Deflater.DEFLATED, // Compression method (CM)
  102. 0, // Flags (FLG)
  103. 0, // Modification time MTIME (int)
  104. 0, // Modification time MTIME (int)
  105. 0, // Modification time MTIME (int)
  106. 0, // Modification time MTIME (int)
  107. 0, // Extra flags (XFLG)
  108. 0 // Operating system (OS)
  109. };
  110. private void writeHeader() throws IOException {
  111. out.write(header);
  112. }
  113. /*
  114. * Writes GZIP member trailer to a byte array, starting at a given
  115. * offset.
  116. */
  117. private void writeTrailer(byte[] buf, int offset) throws IOException {
  118. writeInt((int)crc.getValue(), buf, offset); // CRC-32 of uncompr. data
  119. writeInt(def.getTotalIn(), buf, offset + 4); // Number of uncompr. bytes
  120. }
  121. /*
  122. * Writes integer in Intel byte order to a byte array, starting at a
  123. * given offset.
  124. */
  125. private void writeInt(int i, byte[] buf, int offset) throws IOException {
  126. writeShort(i & 0xffff, buf, offset);
  127. writeShort((i >> 16) & 0xffff, buf, offset + 2);
  128. }
  129. /*
  130. * Writes short integer in Intel byte order to a byte array, starting
  131. * at a given offset
  132. */
  133. private void writeShort(int s, byte[] buf, int offset) throws IOException {
  134. buf[offset] = (byte)(s & 0xff);
  135. buf[offset + 1] = (byte)((s >> 8) & 0xff);
  136. }
  137. }