1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.caleigo.toolkit.tunnel;
20
21
22 import java.io.*;
23 import java.util.zip.*;
24
25 import org.caleigo.toolkit.log.*;
26 import org.caleigo.toolkit.util.CircularByteBuffer;
27
28 /***
29 *
30 * @author Mattias Hagstrand
31 * @version 1.00
32 *
33 *//*
34 *
35 * WHEN WHO WHY & WHAT
36 * -----------------------------------------------------------------------------
37 * 2002-07-05 Mattias Hagstrand Creation
38 */
39 public class ZipPacker implements ITunnelPacker
40 {
41
42 public ZipPacker()
43 {
44 }
45
46
47
48 /***
49 * Creates and returns an InputStream that wrapps the provided InputStream.
50 * The returned InputStream can then be used to unpack messages. The returned
51 * InputStream must be stateless.
52 */
53 public InputStream createInputStream(InputStream in)
54 {
55 return new ZipPackerInputStream(in, 1024 * 64);
56 }
57
58 /***
59 * Creates and returns an OutputStream that wrapps the provided OutputStream.
60 * The returned OutputStream can then be used to pack messages. The returned
61 * OutputStream must be stateless.
62 */
63 public OutputStream createOutputStream(OutputStream out)
64 {
65 return new ZipPackerOutputStream(out, 1024 * 64);
66 }
67
68
69 protected class ZipPackerOutputStream extends FilterOutputStream
70 {
71
72 protected byte[] mByteBuffer;
73 protected int mBufferSize;
74 protected int mCurrentPosition;
75
76 protected ZipOutputStream mZipOutputStream;
77 protected int mZipEntryID;
78
79
80
81 /***
82 * Creates a ZipPackerOutputStream that wrapps an OutputStream.
83 *
84 * @param out the OutputStream that should be used to write the zipped
85 * data to.
86 * @param bufferSize the initial size of the internal buffer. The size
87 * of the buffer is increased as needed. Each time
88 * the buffer needs to be resized its size is increased
89 * by bufferSize / 2 bytes.
90 */
91 public ZipPackerOutputStream(OutputStream out, int bufferSize)
92 {
93 super(out);
94 mByteBuffer = new byte[bufferSize];
95 mBufferSize = bufferSize;
96 mZipOutputStream = new ZipOutputStream(out);
97 mZipOutputStream.setLevel(Deflater.BEST_COMPRESSION);
98 }
99
100
101
102
103
104
105
106
107
108
109
110
111
112 public void write(int b)
113 throws IOException
114 {
115
116 if (mCurrentPosition >= mByteBuffer.length)
117 {
118 byte[] newBuffer = new byte[mByteBuffer.length + mBufferSize / 2];
119 System.arraycopy(mByteBuffer, 0, newBuffer, 0, mByteBuffer.length);
120 mByteBuffer = newBuffer;
121 }
122
123
124 mByteBuffer[mCurrentPosition] = (byte) b;
125 mCurrentPosition++;
126 }
127
128 public void flush()
129 throws IOException
130 {
131 Log.print(this, "flush(): " + mCurrentPosition + " bytes");
132 ZipEntry entry = new ZipEntry(Integer.toString(this.getNextZipEntryID()));
133 mZipOutputStream.putNextEntry(entry);
134 mZipOutputStream.write(mByteBuffer, 0, mCurrentPosition);
135 mZipOutputStream.closeEntry();
136 mZipOutputStream.flush();
137 mCurrentPosition = 0;
138 }
139
140
141 protected int getNextZipEntryID()
142 {
143 mZipEntryID = (mZipEntryID < Integer.MAX_VALUE ? mZipEntryID + 1 : 0);
144 return mZipEntryID;
145 }
146 }
147
148 /***
149 * Uses a ZipInputStream to read and unzip data from an InputStream. It uses
150 * a circular buffer to store the unziped data.
151 */
152 protected class ZipPackerInputStream extends FilterInputStream
153 {
154
155 protected byte[] mInByteBuffer;
156 protected byte[] mSingleByteBuffer = new byte[1];
157 protected CircularByteBuffer mDecompressedByteBuffer;
158
159 protected ZipInputStream mZipInputStream;
160
161
162
163 /***
164 * Creates a ZipPackerInputStream that wrapps an InputStream.
165 *
166 * @param in the InputStream that should be used to read the zipped
167 * data to from.
168 * @param bufferSize the initial size of the internal buffer. The size
169 * of the buffer is increased as needed. Each time
170 * the buffer needs to be resized its size is increased
171 * by bufferSize / 2 bytes.
172 */
173 public ZipPackerInputStream(InputStream in, int bufferSize)
174 {
175 super(in);
176 mInByteBuffer = new byte[bufferSize];
177 mDecompressedByteBuffer = new CircularByteBuffer(bufferSize);
178 mZipInputStream = new ZipInputStream(in);
179 }
180
181
182 public int available()
183 throws IOException
184 {
185 Log.print(this, "return from available(): " + mDecompressedByteBuffer.getBufferSize());
186 return mDecompressedByteBuffer.getBufferSize();
187 }
188
189
190
191
192
193
194
195
196
197
198
199
200 public int read()
201 throws IOException
202 {
203 this.read(mSingleByteBuffer, 0, 1);
204 return mSingleByteBuffer[0];
205 }
206
207 public int read(byte[] b, int off, int len)
208 throws IOException
209 {
210 while (mDecompressedByteBuffer.getBufferSize() == 0)
211 this.readFromZipStream();
212
213 return mDecompressedByteBuffer.getFromBuffer(b, off, len);
214 }
215
216
217 protected void readFromZipStream()
218 throws IOException
219 {
220 ZipEntry zipEntry = mZipInputStream.getNextEntry();
221 if (zipEntry == null)
222 throw new IOException("Couldn't read zip entry");
223 int nbrOfBytesRead = 0;
224 while ((nbrOfBytesRead = mZipInputStream.read(mInByteBuffer, 0, mInByteBuffer.length)) > -1)
225 {
226 mDecompressedByteBuffer.addToBuffer(mInByteBuffer, 0, nbrOfBytesRead);
227 }
228 Log.print(this, "Unzip message successfully: " + zipEntry.getSize() + "(" + zipEntry.getCompressedSize() + ")");
229 mZipInputStream.closeEntry();
230 }
231 }
232 }