1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package triptracker.testing.compress;
21
22 /***
23 * Output stream that compresses data. A compressed block
24 * is generated and transmitted once a given number of bytes
25 * have been written, or when the flush method is invoked.
26 *
27 * Copyright 2005 - Philip Isenhour - http://javatechniques.com/
28 *
29 * This software is provided 'as-is', without any express or
30 * implied warranty. In no event will the authors be held liable
31 * for any damages arising from the use of this software.
32 *
33 * Permission is granted to anyone to use this software for any
34 * purpose, including commercial applications, and to alter it and
35 * redistribute it freely, subject to the following restrictions:
36 *
37 * 1. The origin of this software must not be misrepresented; you
38 * must not claim that you wrote the original software. If you
39 * use this software in a product, an acknowledgment in the
40 * product documentation would be appreciated but is not required.
41 *
42 * 2. Altered source versions must be plainly marked as such, and
43 * must not be misrepresented as being the original software.
44 *
45 * 3. This notice may not be removed or altered from any source
46 * distribution.
47 *
48 * $Id: 1.1 2005/10/26 17:19:05 isenhour Exp $
49 */
50 import java.io.FilterOutputStream;
51 import java.io.IOException;
52 import java.io.OutputStream;
53 import java.util.zip.Deflater;
54
55 public class CompressedBlockOutputStream extends FilterOutputStream {
56 /***
57 * Buffer for input data
58 */
59 private byte[] inBuf = null;
60
61 /***
62 * Buffer for compressed data to be written
63 */
64 private byte[] outBuf = null;
65
66 /***
67 * Number of bytes in the buffer
68 */
69 private int len = 0;
70
71 /***
72 * Deflater for compressing data
73 */
74 private Deflater deflater = null;
75
76 /***
77 * Constructs a CompressedBlockOutputStream that writes to the given
78 * underlying output stream 'os' and sends a compressed block once 'size'
79 * byte have been written. The default compression strategy and level are
80 * used.
81 */
82 public CompressedBlockOutputStream(OutputStream os, int size)
83 throws IOException {
84 this(os, size, Deflater.DEFAULT_COMPRESSION, Deflater.DEFAULT_STRATEGY);
85 }
86
87 /***
88 * Constructs a CompressedBlockOutputStream that writes to the given
89 * underlying output stream 'os' and sends a compressed block once 'size'
90 * byte have been written. The compression level and strategy should be
91 * specified using the constants defined in java.util.zip.Deflator.
92 */
93 public CompressedBlockOutputStream(OutputStream os, int size, int level,
94 int strategy) throws IOException {
95 super(os);
96 this.inBuf = new byte[size];
97 this.outBuf = new byte[size + 64];
98 this.deflater = new Deflater(level);
99 this.deflater.setStrategy(strategy);
100 }
101
102 protected void compressAndSend() throws IOException {
103 if (len > 0) {
104 deflater.setInput(inBuf, 0, len);
105 deflater.finish();
106 int size = deflater.deflate(outBuf);
107
108
109
110 out.write((size >> 24) & 0xFF);
111 out.write((size >> 16) & 0xFF);
112 out.write((size >> 8) & 0xFF);
113 out.write((size >> 0) & 0xFF);
114
115 out.write((len >> 24) & 0xFF);
116 out.write((len >> 16) & 0xFF);
117 out.write((len >> 8) & 0xFF);
118 out.write((len >> 0) & 0xFF);
119
120 out.write(outBuf, 0, size);
121 out.flush();
122
123 len = 0;
124 deflater.reset();
125 }
126 }
127
128 @Override
129 public void write(int b) throws IOException {
130 inBuf[len++] = (byte) b;
131 if (len == inBuf.length) {
132 compressAndSend();
133 }
134 }
135
136 @Override
137 public void write(byte[] b, int boff, int blen) throws IOException {
138 while ((len + blen) > inBuf.length) {
139 int toCopy = inBuf.length - len;
140 System.arraycopy(b, boff, inBuf, len, toCopy);
141 len += toCopy;
142 compressAndSend();
143 boff += toCopy;
144 blen -= toCopy;
145 }
146 System.arraycopy(b, boff, inBuf, len, blen);
147 len += blen;
148 }
149
150 @Override
151 public void flush() throws IOException {
152 compressAndSend();
153 out.flush();
154 }
155
156 @Override
157 public void close() throws IOException {
158 compressAndSend();
159 out.close();
160 }
161 }