1 /* 2 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util.zip; 27 28 import java.io.OutputStream; 29 import java.io.IOException; 30 31 /** 32 * This class implements a stream filter for writing compressed data in 33 * the GZIP file format. 34 * @author David Connelly 35 * 36 */ 37 public 38 class GZIPOutputStream extends DeflaterOutputStream { 39 /** 40 * CRC-32 of uncompressed data. 41 */ 42 protected CRC32 crc = new CRC32(); 43 44 /* 45 * GZIP header magic number. 46 */ 47 private final static int GZIP_MAGIC = 0x8b1f; 48 49 /* 50 * Trailer size in bytes. 51 * 52 */ 53 private final static int TRAILER_SIZE = 8; 54 55 /** 56 * Creates a new output stream with the specified buffer size. 57 * 58 * <p>The new output stream instance is created as if by invoking 59 * the 3-argument constructor GZIPOutputStream(out, size, false). 60 * 61 * @param out the output stream 62 * @param size the output buffer size 63 * @exception IOException If an I/O error has occurred. 64 * @exception IllegalArgumentException if size is <= 0 65 66 */ GZIPOutputStream(OutputStream out, int size)67 public GZIPOutputStream(OutputStream out, int size) throws IOException { 68 this(out, size, false); 69 } 70 71 /** 72 * Creates a new output stream with the specified buffer size and 73 * flush mode. 74 * 75 * @param out the output stream 76 * @param size the output buffer size 77 * @param syncFlush 78 * if {@code true} invocation of the inherited 79 * {@link DeflaterOutputStream#flush() flush()} method of 80 * this instance flushes the compressor with flush mode 81 * {@link Deflater#SYNC_FLUSH} before flushing the output 82 * stream, otherwise only flushes the output stream 83 * @exception IOException If an I/O error has occurred. 84 * @exception IllegalArgumentException if size is <= 0 85 * 86 * @since 1.7 87 */ GZIPOutputStream(OutputStream out, int size, boolean syncFlush)88 public GZIPOutputStream(OutputStream out, int size, boolean syncFlush) 89 throws IOException 90 { 91 super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true), 92 size, 93 syncFlush); 94 usesDefaultDeflater = true; 95 writeHeader(); 96 crc.reset(); 97 } 98 99 100 /** 101 * Creates a new output stream with a default buffer size. 102 * 103 * <p>The new output stream instance is created as if by invoking 104 * the 2-argument constructor GZIPOutputStream(out, false). 105 * 106 * @param out the output stream 107 * @exception IOException If an I/O error has occurred. 108 */ GZIPOutputStream(OutputStream out)109 public GZIPOutputStream(OutputStream out) throws IOException { 110 this(out, 512, false); 111 } 112 113 /** 114 * Creates a new output stream with a default buffer size and 115 * the specified flush mode. 116 * 117 * @param out the output stream 118 * @param syncFlush 119 * if {@code true} invocation of the inherited 120 * {@link DeflaterOutputStream#flush() flush()} method of 121 * this instance flushes the compressor with flush mode 122 * {@link Deflater#SYNC_FLUSH} before flushing the output 123 * stream, otherwise only flushes the output stream 124 * 125 * @exception IOException If an I/O error has occurred. 126 * 127 * @since 1.7 128 */ GZIPOutputStream(OutputStream out, boolean syncFlush)129 public GZIPOutputStream(OutputStream out, boolean syncFlush) 130 throws IOException 131 { 132 this(out, 512, syncFlush); 133 } 134 135 /** 136 * Writes array of bytes to the compressed output stream. This method 137 * will block until all the bytes are written. 138 * @param buf the data to be written 139 * @param off the start offset of the data 140 * @param len the length of the data 141 * @exception IOException If an I/O error has occurred. 142 */ write(byte[] buf, int off, int len)143 public synchronized void write(byte[] buf, int off, int len) 144 throws IOException 145 { 146 super.write(buf, off, len); 147 crc.update(buf, off, len); 148 } 149 150 /** 151 * Finishes writing compressed data to the output stream without closing 152 * the underlying stream. Use this method when applying multiple filters 153 * in succession to the same output stream. 154 * @exception IOException if an I/O error has occurred 155 */ finish()156 public void finish() throws IOException { 157 if (!def.finished()) { 158 def.finish(); 159 while (!def.finished()) { 160 int len = def.deflate(buf, 0, buf.length); 161 if (def.finished() && len <= buf.length - TRAILER_SIZE) { 162 // last deflater buffer. Fit trailer at the end 163 writeTrailer(buf, len); 164 len = len + TRAILER_SIZE; 165 out.write(buf, 0, len); 166 return; 167 } 168 if (len > 0) 169 out.write(buf, 0, len); 170 } 171 // if we can't fit the trailer at the end of the last 172 // deflater buffer, we write it separately 173 byte[] trailer = new byte[TRAILER_SIZE]; 174 writeTrailer(trailer, 0); 175 out.write(trailer); 176 } 177 } 178 179 /* 180 * Writes GZIP member header. 181 */ writeHeader()182 private void writeHeader() throws IOException { 183 out.write(new byte[] { 184 (byte) GZIP_MAGIC, // Magic number (short) 185 (byte)(GZIP_MAGIC >> 8), // Magic number (short) 186 Deflater.DEFLATED, // Compression method (CM) 187 0, // Flags (FLG) 188 0, // Modification time MTIME (int) 189 0, // Modification time MTIME (int) 190 0, // Modification time MTIME (int) 191 0, // Modification time MTIME (int) 192 0, // Extra flags (XFLG) 193 0 // Operating system (OS) 194 }); 195 } 196 197 /* 198 * Writes GZIP member trailer to a byte array, starting at a given 199 * offset. 200 */ writeTrailer(byte[] buf, int offset)201 private void writeTrailer(byte[] buf, int offset) throws IOException { 202 writeInt((int)crc.getValue(), buf, offset); // CRC-32 of uncompr. data 203 writeInt(def.getTotalIn(), buf, offset + 4); // Number of uncompr. bytes 204 } 205 206 /* 207 * Writes integer in Intel byte order to a byte array, starting at a 208 * given offset. 209 */ writeInt(int i, byte[] buf, int offset)210 private void writeInt(int i, byte[] buf, int offset) throws IOException { 211 writeShort(i & 0xffff, buf, offset); 212 writeShort((i >> 16) & 0xffff, buf, offset + 2); 213 } 214 215 /* 216 * Writes short integer in Intel byte order to a byte array, starting 217 * at a given offset 218 */ writeShort(int s, byte[] buf, int offset)219 private void writeShort(int s, byte[] buf, int offset) throws IOException { 220 buf[offset] = (byte)(s & 0xff); 221 buf[offset + 1] = (byte)((s >> 8) & 0xff); 222 } 223 } 224