Source code: com/arranger/jarl/io/GZipOutputStreamEx.java
1 package com.arranger.jarl.io;
2
3 import java.util.zip.*;
4 import java.io.OutputStream;
5 import java.io.IOException;
6
7 /**
8 * This class essentially copies sources of original GZIPOutputStream,
9 * just adds ability to pass in desired compression level into constructor
10 */
11 public class GZipOutputStreamEx extends DeflaterOutputStream {
12 /**
13 * CRC-32 of uncompressed data.
14 */
15 protected CRC32 crc = new CRC32();
16
17 /*
18 * GZIP header magic number.
19 */
20 private final static int GZIP_MAGIC = 0x8b1f;
21
22 /**
23 * Creates a new output stream with the specified buffer size.
24 * @param out the output stream
25 * @param size the output buffer size
26 * @exception IOException If an I/O error has occurred.
27 * @exception IllegalArgumentException if size is <= 0
28 */
29 public GZipOutputStreamEx(OutputStream out, int size, int compression) throws IOException {
30 super(out, new Deflater(compression, true), size);
31 writeHeader();
32 crc.reset();
33 }
34
35 /**
36 * Creates a new output stream with a default buffer size.
37 * @param out the output stream
38 * @exception IOException If an I/O error has occurred.
39 */
40 public GZipOutputStreamEx(OutputStream out, int compression) throws IOException {
41 this(out, 512, compression);
42 }
43
44 /**
45 * Writes array of bytes to the compressed output stream. This method
46 * will block until all the bytes are written.
47 * @param buf the data to be written
48 * @param off the start offset of the data
49 * @param len the length of the data
50 * @exception IOException If an I/O error has occurred.
51 */
52 public synchronized void write(byte[] buf, int off, int len)
53 throws IOException
54 {
55 super.write(buf, off, len);
56 crc.update(buf, off, len);
57 }
58
59 /**
60 * Finishes writing compressed data to the output stream without closing
61 * the underlying stream. Use this method when applying multiple filters
62 * in succession to the same output stream.
63 * @exception IOException if an I/O error has occurred
64 */
65 public void finish() throws IOException {
66 if (!def.finished()) {
67 def.finish();
68 while (!def.finished()) {
69 deflate();
70 }
71 writeTrailer();
72 }
73 }
74
75 /**
76 * Writes remaining compressed data to the output stream and closes the
77 * underlying stream.
78 * @exception IOException if an I/O error has occurred
79 */
80 public void close() throws IOException {
81 finish();
82 out.close();
83 }
84
85 /*
86 * Writes GZIP member header.
87 */
88 private void writeHeader() throws IOException {
89 writeShort(GZIP_MAGIC); // Magic number
90 out.write(def.DEFLATED); // Compression method (CM)
91 out.write(0); // Flags (FLG)
92 writeInt(0); // Modification time (MTIME)
93 out.write(0); // Extra flags (XFL)
94 out.write(0); // Operating system (OS)
95 }
96
97 /*
98 * Writes GZIP member trailer.
99 */
100 private void writeTrailer() throws IOException {
101 writeInt((int)crc.getValue()); // CRC-32 of uncompressed data
102 writeInt(def.getTotalIn()); // Number of uncompressed bytes
103 }
104
105 /*
106 * Writes integer in Intel byte order.
107 */
108 private void writeInt(int i) throws IOException {
109 writeShort(i & 0xffff);
110 writeShort((i >> 16) & 0xffff);
111 }
112
113 /*
114 * Writes short integer in Intel byte order.
115 */
116 private void writeShort(int s) throws IOException {
117 out.write(s & 0xff);
118 out.write((s >> 8) & 0xff);
119 }
120 }