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 CRCPacker implements ITunnelPacker
40 {
41
42 public CRCPacker()
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 CRCPackerInputStream(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 CRCPackerOutputStream(out, 1024 * 64);
66 }
67
68
69 protected class CRCPackerOutputStream extends FilterOutputStream
70 {
71
72 protected byte[] mByteBuffer;
73 protected int mBufferSize;
74 protected int mCurrentPosition;
75
76 protected CRC32 checker;
77 protected ObjectOutputStream mObjectOutputStream;
78
79
80 public CRCPackerOutputStream(OutputStream out, int bufferSize)
81 {
82 super(out);
83 mByteBuffer = new byte[bufferSize];
84 mBufferSize = bufferSize;
85 checker = new CRC32();
86 try
87 {
88 mObjectOutputStream = new ObjectOutputStream(out);
89 }
90 catch (IOException ioe)
91 {
92 Log.printError(this, "Couldn't create object output stream", ioe);
93 throw new IllegalArgumentException("Unable to create object output stream");
94 }
95 }
96
97
98 public void write(int b)
99 throws IOException
100 {
101
102 if (mCurrentPosition >= mByteBuffer.length)
103 {
104 byte[] newBuffer = new byte[mByteBuffer.length + mBufferSize / 2];
105 System.arraycopy(mByteBuffer, 0, newBuffer, 0, mByteBuffer.length);
106 mByteBuffer = newBuffer;
107 }
108
109
110 mByteBuffer[mCurrentPosition] = (byte) b;
111 mCurrentPosition++;
112 }
113
114 public void flush()
115 throws IOException
116 {
117 checker.reset();
118 checker.update(mByteBuffer, 0, mCurrentPosition);
119 Log.print(this, "flush(): checksum=" + checker.getValue());
120 mObjectOutputStream.writeObject(new CRCDataPackage(mByteBuffer, 0, mCurrentPosition));
121 mObjectOutputStream.writeLong(checker.getValue());
122 mObjectOutputStream.flush();
123 mCurrentPosition = 0;
124 }
125 }
126
127 protected class CRCPackerInputStream extends FilterInputStream
128 {
129
130 protected byte[] mInByteBuffer;
131 protected byte[] mSingleByteBuffer = new byte[1];
132 protected CircularByteBuffer mCheckedByteBuffer;
133
134 protected CRC32 checker;
135 protected ObjectInputStream mObjectInputStream;
136
137
138
139 /***
140 * Creates a CRCPackerInputStream that wrapps an InputStream.
141 *
142 * @param in the InputStream that should be used to read the
143 * data to from.
144 * @param bufferSize the initial size of the internal buffer. The size
145 * of the buffer is increased as needed. Each time
146 * the buffer needs to be resized its size is increased
147 * by bufferSize / 2 bytes.
148 */
149 public CRCPackerInputStream(InputStream in, int bufferSize)
150 {
151 super(in);
152 mInByteBuffer = new byte[bufferSize];
153 mCheckedByteBuffer = new CircularByteBuffer(bufferSize);
154 checker = new CRC32();
155 try
156 {
157 mObjectInputStream = new ObjectInputStream(in);
158 }
159 catch (IOException ioe)
160 {
161 Log.printError(this, "Couldn't create object input stream", ioe);
162 throw new IllegalArgumentException("Unable to create object input stream");
163 }
164 }
165
166
167 public int available()
168 throws IOException
169 {
170 Log.print(this, "return from available(): " + mCheckedByteBuffer.getBufferSize());
171 return mCheckedByteBuffer.getBufferSize();
172 }
173
174 public int read()
175 throws IOException
176 {
177 this.read(mSingleByteBuffer, 0, 1);
178 return mSingleByteBuffer[0];
179 }
180
181 public int read(byte[] b, int off, int len)
182 throws IOException
183 {
184 while (mCheckedByteBuffer.getBufferSize() == 0)
185 this.readFromCheckedStream();
186
187 return mCheckedByteBuffer.getFromBuffer(b, off, len);
188 }
189
190
191 protected void readFromCheckedStream()
192 throws IOException
193 {
194 CRCDataPackage dataPackage = null;
195 try
196 {
197 dataPackage = (CRCDataPackage) mObjectInputStream.readObject();
198 }
199 catch (ClassNotFoundException cnfe)
200 {
201 throw new IOException(cnfe.getMessage());
202 }
203 checker.reset();
204 checker.update(dataPackage.mData);
205 if (mObjectInputStream.readLong() != checker.getValue())
206 throw new IOException("Checksum error");
207 mCheckedByteBuffer.addToBuffer(dataPackage.mData, 0, dataPackage.mData.length);
208 }
209 }
210
211 protected static class CRCDataPackage implements Serializable
212 {
213
214 protected byte[] mData;
215
216
217 public CRCDataPackage(byte[] data, int offset, int length)
218 {
219 mData = new byte[length];
220 System.arraycopy(data, offset, mData, 0, length);
221 }
222 }
223 }