1 /*
2 * Copyright (c) 2004 Beeyond Software Holding BV
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #define BEECRYPT_CXX_DLL_EXPORT
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include "beecrypt/c++/io/DataInputStream.h"
26 #include "beecrypt/c++/io/EOFException.h"
27 #include "beecrypt/c++/io/PushbackInputStream.h"
28 #include "beecrypt/c++/lang/NullPointerException.h"
29 using beecrypt::lang::NullPointerException;
30
31 #define MAX_BYTES_PER_CHARACTER 8
32
33 using namespace beecrypt::io;
34
DataInputStream(InputStream & in)35 DataInputStream::DataInputStream(InputStream& in) : FilterInputStream(in)
36 {
37 _pin = ∈
38 _del = false;
39 _utf = 0;
40 _loc = 0;
41 }
42
~DataInputStream()43 DataInputStream::~DataInputStream()
44 {
45 if (_utf)
46 {
47 ucnv_close(_utf);
48 _utf = 0;
49 }
50
51 if (_loc)
52 {
53 ucnv_close(_loc);
54 _loc = 0;
55 }
56
57 if (_del)
58 {
59 delete _pin;
60 _pin = 0;
61 }
62 }
63
readBoolean()64 bool DataInputStream::readBoolean() throw (IOException)
65 {
66 register jint b = _pin->read();
67
68 if (b < 0)
69 throw EOFException();
70
71 return (b != 0);
72 }
73
readByte()74 jbyte DataInputStream::readByte() throw (IOException)
75 {
76 register jint b = _pin->read();
77
78 if (b < 0)
79 throw EOFException();
80
81 return static_cast<jbyte>(b);
82 }
83
readUnsignedByte()84 jint DataInputStream::readUnsignedByte() throw (IOException)
85 {
86 register jint b = _pin->read();
87
88 if (b < 0)
89 throw EOFException();
90
91 return b;
92 }
93
readShort()94 jshort DataInputStream::readShort() throw (IOException)
95 {
96 register jshort tmp = 0;
97 register jint rc;
98
99 for (register unsigned i = 0; i < 2; i++)
100 {
101 if ((rc = _pin->read()) < 0)
102 throw EOFException();
103
104 tmp = (tmp << 8) + rc;
105 }
106
107 return tmp;
108 }
109
readUnsignedShort()110 jint DataInputStream::readUnsignedShort() throw (IOException)
111 {
112 register jint tmp = 0, rc;
113
114 for (register unsigned i = 0; i < 2; i++)
115 {
116 if ((rc = _pin->read()) < 0)
117 throw EOFException();
118
119 tmp = (tmp << 8) + rc;
120 }
121
122 return tmp;
123 }
124
readChar()125 jchar DataInputStream::readChar() throw (IOException)
126 {
127 register jchar tmp = 0;
128 register jint rc;
129
130 for (register unsigned i = 0; i < 2; i++)
131 {
132 if ((rc = _pin->read()) < 0)
133 throw EOFException();
134
135 tmp = (tmp << 8) + rc;
136 }
137
138 return tmp;
139 }
140
readInt()141 jint DataInputStream::readInt() throw (IOException)
142 {
143 register jint tmp = 0;
144 register jint rc;
145
146 for (register unsigned i = 0; i < 4; i++)
147 {
148 if ((rc = _pin->read()) < 0)
149 throw EOFException();
150
151 tmp = (tmp << 8) + rc;
152 }
153
154 return tmp;
155 }
156
readLong()157 jlong DataInputStream::readLong() throw (IOException)
158 {
159 register jlong tmp = 0;
160 register jint rc;
161
162 for (register unsigned i = 0; i < 8; i++)
163 {
164 if ((rc = _pin->read()) < 0)
165 throw EOFException();
166
167 tmp = (tmp << 8) + rc;
168 }
169
170 return tmp;
171 }
172
readUTF()173 String DataInputStream::readUTF() throw (IOException)
174 {
175 UErrorCode status = U_ZERO_ERROR;
176
177 if (!_utf)
178 {
179 // UTF-8 converter lazy initialization
180 _utf = ucnv_open("UTF-8", &status);
181 if (U_FAILURE(status))
182 throw IOException("unable to open ICU UTF-8 converter");
183 }
184
185 jint utflen = readUnsignedShort();
186
187 if (utflen > 0)
188 {
189 byte* data = new byte[utflen];
190
191 readFully(data, 0, utflen);
192
193 status = U_ZERO_ERROR;
194 jint ulen = ucnv_toUChars(_utf, 0, 0, (const char*) data, (jint) utflen, &status);
195 if (status != U_BUFFER_OVERFLOW_ERROR)
196 {
197 delete[] data;
198 throw IOException("ucnv_toUChars failed");
199 }
200
201 jchar* buffer = new jchar[ulen+1];
202
203 status = U_ZERO_ERROR;
204 ucnv_toUChars(_utf, buffer, ulen+1, (const char*) data, (jint) utflen, &status);
205
206 delete[] data;
207
208 if (status != U_ZERO_ERROR)
209 throw IOException("error in ucnv_toUChars");
210
211 String result(buffer, 0, ulen);
212
213 delete[] buffer;
214
215 return result;
216 }
217 else
218 return String();
219 }
220
readLine()221 String DataInputStream::readLine() throw (IOException)
222 {
223 UErrorCode status = U_ZERO_ERROR;
224
225 if (!_loc)
226 {
227 // default locale converter lazy initialization
228 _loc = ucnv_open(0, &status);
229 if (U_FAILURE(status))
230 throw IOException("unable to open ICU default locale converter");
231 }
232
233 array<jchar> target_buffer(80);
234 jint target_offset = 0;
235 UChar* target = target_buffer.data();
236 const UChar* target_limit = target+1;
237 char source_buffer[MAX_BYTES_PER_CHARACTER];
238 const char* source = source_buffer;
239 char* source_limit = source_buffer;
240
241 bool cr = false;
242
243 jint ch;
244
245 do
246 {
247 ch = _pin->read();
248
249 if (ch >= 0)
250 {
251 if ((source_limit-source_buffer) == MAX_BYTES_PER_CHARACTER)
252 throw IOException("fubar in readLine");
253
254 *(source_limit++) = (byte) ch;
255 }
256
257 // use the default locale converter; flush if ch == -1
258 ucnv_toUnicode(_loc, &target, target_limit, &source, source_limit, NULL, (UBool) (ch == -1), &status);
259 if (U_FAILURE(status))
260 throw IOException("ucnv_toUnicode failed");
261
262 if (target == target_limit)
263 {
264 // we got a whole character from the converter
265 if (cr)
266 {
267 // last character read was ASCII <CR>; is this one a <LF>?
268 if (target[-1] != 0x0A)
269 {
270 // unread the right number of bytes
271 PushbackInputStream* p = dynamic_cast<PushbackInputStream*>(_pin);
272 if (p)
273 p->unread((const byte*) source_buffer, 0, source-source_buffer);
274 else
275 throw IOException("fubar in dynamic_cast");
276 }
277 // we're now officially at the end of the line
278 break;
279 }
280
281 // did we get an ASCII <LF>?
282 if (target[-1] == 0x0A)
283 break;
284
285 // did we get an ASCII <CR>?
286 if (target[-1] == 0x0D)
287 {
288 cr = true;
289
290 // the next character may be a <LF> but if not we'll have to 'unread' it
291 if (!_del)
292 {
293 // lazy push
294 _pin = new PushbackInputStream(in, MAX_BYTES_PER_CHARACTER);
295 _del = true;
296 }
297 }
298 else
299 {
300 // reset source pointers
301 source = source_limit = source_buffer;
302 // advance target_limit and target_offset
303 target_limit++;
304 target_offset++;
305 // check if we have room left in the buffer
306 if (target_offset == target_buffer.size())
307 {
308 // no; double the size
309 target_buffer.resize(target_buffer.size() * 2);
310 }
311 }
312 }
313 } while (ch >= 0);
314
315 return String(target_buffer.data(), 0, target_offset);
316 }
317
readFully(byte * data,jint offset,jint length)318 void DataInputStream::readFully(byte* data, jint offset, jint length) throw (IOException)
319 {
320 if (!data)
321 throw NullPointerException();
322
323 jint total = 0;
324
325 while (total < length)
326 {
327 jint rc = _pin->read(data, offset+total, length-total);
328 if (rc < 0)
329 throw EOFException();
330 total += rc;
331 }
332 }
333
readFully(bytearray & b)334 void DataInputStream::readFully(bytearray& b) throw (IOException)
335 {
336 readFully(b.data(), 0, b.size());
337 }
338
skipBytes(jint n)339 jint DataInputStream::skipBytes(jint n) throw (IOException)
340 {
341 jint total = 0, rc;
342
343 while ((total < n) && ((rc = _pin->skip(n - total)) > 0))
344 total += rc;
345
346 return total;
347 }
348