blob: 867eff0b14497786e653b3871bafd3f15ac723ac [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-2002 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package java.util.zip;
27
28import java.io.OutputStream;
29import 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 */
37public
38class 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 * @param out the output stream
58 * @param size the output buffer size
59 * @exception IOException If an I/O error has occurred.
60 * @exception IllegalArgumentException if size is <= 0
61 */
62 public GZIPOutputStream(OutputStream out, int size) throws IOException {
63 super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size);
64 usesDefaultDeflater = true;
65 writeHeader();
66 crc.reset();
67 }
68
69 /**
70 * Creates a new output stream with a default buffer size.
71 * @param out the output stream
72 * @exception IOException If an I/O error has occurred.
73 */
74 public GZIPOutputStream(OutputStream out) throws IOException {
75 this(out, 512);
76 }
77
78 /**
79 * Writes array of bytes to the compressed output stream. This method
80 * will block until all the bytes are written.
81 * @param buf the data to be written
82 * @param off the start offset of the data
83 * @param len the length of the data
84 * @exception IOException If an I/O error has occurred.
85 */
86 public synchronized void write(byte[] buf, int off, int len)
87 throws IOException
88 {
89 super.write(buf, off, len);
90 crc.update(buf, off, len);
91 }
92
93 /**
94 * Finishes writing compressed data to the output stream without closing
95 * the underlying stream. Use this method when applying multiple filters
96 * in succession to the same output stream.
97 * @exception IOException if an I/O error has occurred
98 */
99 public void finish() throws IOException {
100 if (!def.finished()) {
101 def.finish();
102 while (!def.finished()) {
103 int len = def.deflate(buf, 0, buf.length);
104 if (def.finished() && len <= buf.length - TRAILER_SIZE) {
105 // last deflater buffer. Fit trailer at the end
106 writeTrailer(buf, len);
107 len = len + TRAILER_SIZE;
108 out.write(buf, 0, len);
109 return;
110 }
111 if (len > 0)
112 out.write(buf, 0, len);
113 }
114 // if we can't fit the trailer at the end of the last
115 // deflater buffer, we write it separately
116 byte[] trailer = new byte[TRAILER_SIZE];
117 writeTrailer(trailer, 0);
118 out.write(trailer);
119 }
120 }
121
122 /*
123 * Writes GZIP member header.
124 */
125
126 private final static byte[] header = {
127 (byte) GZIP_MAGIC, // Magic number (short)
128 (byte)(GZIP_MAGIC >> 8), // Magic number (short)
129 Deflater.DEFLATED, // Compression method (CM)
130 0, // Flags (FLG)
131 0, // Modification time MTIME (int)
132 0, // Modification time MTIME (int)
133 0, // Modification time MTIME (int)
134 0, // Modification time MTIME (int)
135 0, // Extra flags (XFLG)
136 0 // Operating system (OS)
137 };
138
139 private void writeHeader() throws IOException {
140 out.write(header);
141 }
142
143 /*
144 * Writes GZIP member trailer to a byte array, starting at a given
145 * offset.
146 */
147 private void writeTrailer(byte[] buf, int offset) throws IOException {
148 writeInt((int)crc.getValue(), buf, offset); // CRC-32 of uncompr. data
149 writeInt(def.getTotalIn(), buf, offset + 4); // Number of uncompr. bytes
150 }
151
152 /*
153 * Writes integer in Intel byte order to a byte array, starting at a
154 * given offset.
155 */
156 private void writeInt(int i, byte[] buf, int offset) throws IOException {
157 writeShort(i & 0xffff, buf, offset);
158 writeShort((i >> 16) & 0xffff, buf, offset + 2);
159 }
160
161 /*
162 * Writes short integer in Intel byte order to a byte array, starting
163 * at a given offset
164 */
165 private void writeShort(int s, byte[] buf, int offset) throws IOException {
166 buf[offset] = (byte)(s & 0xff);
167 buf[offset + 1] = (byte)((s >> 8) & 0xff);
168 }
169}