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