38 |
|
|
39 |
package javax.imageio.stream; |
package javax.imageio.stream; |
40 |
|
|
41 |
|
import java.io.DataInputStream; |
42 |
|
import java.io.EOFException; |
43 |
import java.io.IOException; |
import java.io.IOException; |
44 |
import java.nio.ByteOrder; |
import java.nio.ByteOrder; |
45 |
|
import java.util.Stack; |
46 |
|
|
47 |
/** |
/** |
48 |
* @author Michael Koch (konqueror@gmx.de) |
* @author Michael Koch (konqueror@gmx.de) |
50 |
public abstract class ImageInputStreamImpl implements ImageInputStream |
public abstract class ImageInputStreamImpl implements ImageInputStream |
51 |
{ |
{ |
52 |
private boolean closed; |
private boolean closed; |
53 |
|
private Stack markStack = new Stack(); |
54 |
|
|
55 |
|
byte[] buffer = new byte[8]; |
56 |
|
|
57 |
protected int bitOffset; |
protected int bitOffset; |
58 |
protected ByteOrder byteOrder; |
protected ByteOrder byteOrder; |
105 |
public int getBitOffset() |
public int getBitOffset() |
106 |
throws IOException |
throws IOException |
107 |
{ |
{ |
108 |
|
checkClosed(); |
109 |
return bitOffset; |
return bitOffset; |
110 |
} |
} |
111 |
|
|
122 |
public long getStreamPosition() |
public long getStreamPosition() |
123 |
throws IOException |
throws IOException |
124 |
{ |
{ |
125 |
|
checkClosed(); |
126 |
return streamPos; |
return streamPos; |
127 |
} |
} |
128 |
|
|
146 |
return -1L; |
return -1L; |
147 |
} |
} |
148 |
|
|
149 |
|
public void mark() |
150 |
|
{ |
151 |
|
try |
152 |
|
{ |
153 |
|
markStack.push(new Long(getStreamPosition())); |
154 |
|
} |
155 |
|
catch (IOException e) |
156 |
|
{ |
157 |
|
// Ignored. |
158 |
|
} |
159 |
|
} |
160 |
|
|
161 |
public abstract int read() |
public abstract int read() |
162 |
throws IOException; |
throws IOException; |
163 |
|
|
170 |
public abstract int read(byte[] data, int offset, int len) |
public abstract int read(byte[] data, int offset, int len) |
171 |
throws IOException; |
throws IOException; |
172 |
|
|
173 |
public void setByteOrder (ByteOrder byteOrder) |
public int readBit() |
174 |
|
throws IOException |
175 |
|
{ |
176 |
|
checkClosed(); |
177 |
|
|
178 |
|
// Calc new bit offset here, readByte resets it. |
179 |
|
int newOffset = (bitOffset + 1) & 0x7; |
180 |
|
|
181 |
|
byte data = readByte(); |
182 |
|
|
183 |
|
if (bitOffset != 0) |
184 |
|
{ |
185 |
|
seek(getStreamPosition() - 1); |
186 |
|
data = (byte) (data >> (8 - newOffset)); |
187 |
|
} |
188 |
|
|
189 |
|
bitOffset = newOffset; |
190 |
|
return data & 0x1; |
191 |
|
} |
192 |
|
|
193 |
|
public long readBits(int numBits) |
194 |
|
throws IOException |
195 |
|
{ |
196 |
|
checkClosed(); |
197 |
|
|
198 |
|
if (numBits < 0 || numBits > 64) |
199 |
|
throw new IllegalArgumentException(); |
200 |
|
|
201 |
|
if (numBits == 0) |
202 |
|
return 0L; |
203 |
|
|
204 |
|
long bits = 0L; |
205 |
|
|
206 |
|
for (int i = 0; i < numBits; i++) |
207 |
|
{ |
208 |
|
bits <<= 1; |
209 |
|
bits |= readBit(); |
210 |
|
} |
211 |
|
|
212 |
|
return bits; |
213 |
|
} |
214 |
|
|
215 |
|
public boolean readBoolean() |
216 |
|
throws IOException |
217 |
|
{ |
218 |
|
byte data = readByte(); |
219 |
|
return data != 0; |
220 |
|
} |
221 |
|
|
222 |
|
public byte readByte() |
223 |
|
throws IOException |
224 |
|
{ |
225 |
|
int data = read(); |
226 |
|
|
227 |
|
if (data == -1) |
228 |
|
throw new EOFException(); |
229 |
|
|
230 |
|
return (byte) data; |
231 |
|
} |
232 |
|
|
233 |
|
public void readBytes(IIOByteBuffer buffer, int len) |
234 |
|
throws IOException |
235 |
|
{ |
236 |
|
int result = read(buffer.getData(), buffer.getOffset(), len); |
237 |
|
|
238 |
|
if (result == -1 || result < len) |
239 |
|
throw new EOFException(); |
240 |
|
|
241 |
|
buffer.setLength(len); |
242 |
|
} |
243 |
|
|
244 |
|
public char readChar() |
245 |
|
throws IOException |
246 |
|
{ |
247 |
|
return (char) readShort(); |
248 |
|
} |
249 |
|
|
250 |
|
public double readDouble() |
251 |
|
throws IOException |
252 |
|
{ |
253 |
|
return (double) readLong(); |
254 |
|
} |
255 |
|
|
256 |
|
public float readFloat() |
257 |
|
throws IOException |
258 |
|
{ |
259 |
|
return (float) readInt(); |
260 |
|
} |
261 |
|
|
262 |
|
public void readFully(byte[] data) |
263 |
|
throws IOException |
264 |
|
{ |
265 |
|
readFully(data, 0, data.length); |
266 |
|
} |
267 |
|
|
268 |
|
public void readFully(byte[] data, int offset, int len) |
269 |
|
throws IOException |
270 |
|
{ |
271 |
|
for (int i = 0; i < len; ++i) |
272 |
|
data[offset + i] = readByte(); |
273 |
|
} |
274 |
|
|
275 |
|
public void readFully(char[] data, int offset, int len) |
276 |
|
throws IOException |
277 |
|
{ |
278 |
|
for (int i = 0; i < len; ++i) |
279 |
|
data[offset + i] = readChar(); |
280 |
|
} |
281 |
|
|
282 |
|
public void readFully(double[] data, int offset, int len) |
283 |
|
throws IOException |
284 |
|
{ |
285 |
|
for (int i = 0; i < len; ++i) |
286 |
|
data[offset + i] = readDouble(); |
287 |
|
} |
288 |
|
|
289 |
|
public void readFully(float[] data, int offset, int len) |
290 |
|
throws IOException |
291 |
|
{ |
292 |
|
for (int i = 0; i < len; ++i) |
293 |
|
data[offset + i] = readFloat(); |
294 |
|
} |
295 |
|
|
296 |
|
public void readFully(int[] data, int offset, int len) |
297 |
|
throws IOException |
298 |
|
{ |
299 |
|
for (int i = 0; i < len; ++i) |
300 |
|
data[offset + i] = readInt(); |
301 |
|
} |
302 |
|
|
303 |
|
public void readFully(long[] data, int offset, int len) |
304 |
|
throws IOException |
305 |
|
{ |
306 |
|
for (int i = 0; i < len; ++i) |
307 |
|
data[offset + i] = readLong(); |
308 |
|
} |
309 |
|
|
310 |
|
public void readFully(short[] data, int offset, int len) |
311 |
|
throws IOException |
312 |
|
{ |
313 |
|
for (int i = 0; i < len; ++i) |
314 |
|
data[offset + i] = readShort(); |
315 |
|
} |
316 |
|
|
317 |
|
public int readInt() |
318 |
|
throws IOException |
319 |
|
{ |
320 |
|
int result = read(buffer, 0, 4); |
321 |
|
|
322 |
|
if (result == -1) |
323 |
|
throw new EOFException(); |
324 |
|
|
325 |
|
if (getByteOrder() == ByteOrder.LITTLE_ENDIAN) |
326 |
|
{ |
327 |
|
return ((buffer[0] & 0xff) |
328 |
|
+ (buffer[1] << 8) |
329 |
|
+ (buffer[2] << 16) |
330 |
|
+ (buffer[3] << 24)); |
331 |
|
} |
332 |
|
|
333 |
|
return ((buffer[4] << 24) |
334 |
|
+ (buffer[3] << 16) |
335 |
|
+ (buffer[2] << 8) |
336 |
|
+ (buffer[1] & 0xff)); |
337 |
|
} |
338 |
|
|
339 |
|
public String readLine() |
340 |
|
throws IOException |
341 |
|
{ |
342 |
|
checkClosed(); |
343 |
|
|
344 |
|
int c = -1; |
345 |
|
boolean eol = false; |
346 |
|
StringBuffer buffer = new StringBuffer(); |
347 |
|
|
348 |
|
while (!eol && (c = read()) != -1) |
349 |
|
{ |
350 |
|
switch(c) |
351 |
|
{ |
352 |
|
case '\r': |
353 |
|
// Consume following \n' |
354 |
|
long oldPosition = getStreamPosition(); |
355 |
|
if (read() != '\n') |
356 |
|
seek(oldPosition); |
357 |
|
case '\n': |
358 |
|
eol = true; |
359 |
|
break; |
360 |
|
default: |
361 |
|
buffer.append((char) c); |
362 |
|
break; |
363 |
|
} |
364 |
|
} |
365 |
|
|
366 |
|
if (c == -1 && buffer.length() == 0) |
367 |
|
return null; |
368 |
|
|
369 |
|
return buffer.toString(); |
370 |
|
} |
371 |
|
|
372 |
|
public long readLong() |
373 |
|
throws IOException |
374 |
|
{ |
375 |
|
int result = read(buffer, 0, 8); |
376 |
|
|
377 |
|
if (result == -1) |
378 |
|
throw new EOFException(); |
379 |
|
|
380 |
|
if (getByteOrder() == ByteOrder.LITTLE_ENDIAN) |
381 |
|
{ |
382 |
|
return ((buffer[0] & 0xff) |
383 |
|
+ (((buffer[1] & 0xff)) << 8) |
384 |
|
+ (((buffer[2] & 0xff)) << 16) |
385 |
|
+ (((buffer[3] & 0xffL)) << 24) |
386 |
|
+ (((buffer[4] & 0xffL)) << 32) |
387 |
|
+ (((buffer[5] & 0xffL)) << 40) |
388 |
|
+ (((buffer[6] & 0xffL)) << 48) |
389 |
|
+ (((long) buffer[7]) << 56)); |
390 |
|
} |
391 |
|
|
392 |
|
return ((((long) buffer[7]) << 56) |
393 |
|
+ ((buffer[6] & 0xffL) << 48) |
394 |
|
+ ((buffer[5] & 0xffL) << 40) |
395 |
|
+ ((buffer[4] & 0xffL) << 32) |
396 |
|
+ ((buffer[3] & 0xffL) << 24) |
397 |
|
+ ((buffer[2] & 0xff) << 16) |
398 |
|
+ ((buffer[1] & 0xff) << 8) |
399 |
|
+ (buffer[0] & 0xff)); |
400 |
|
} |
401 |
|
|
402 |
|
public short readShort() |
403 |
|
throws IOException |
404 |
|
{ |
405 |
|
int result = read(buffer, 0, 2); |
406 |
|
|
407 |
|
if (result == -1) |
408 |
|
throw new EOFException(); |
409 |
|
|
410 |
|
if (getByteOrder() == ByteOrder.LITTLE_ENDIAN) |
411 |
|
{ |
412 |
|
return (short) ((buffer[0] & 0xff) |
413 |
|
+ (buffer[1] << 8)); |
414 |
|
} |
415 |
|
|
416 |
|
return (short) ((buffer[0] << 8) |
417 |
|
+ (buffer[1] & 0xff)); |
418 |
|
} |
419 |
|
|
420 |
|
public int readUnsignedByte() |
421 |
|
throws IOException |
422 |
|
{ |
423 |
|
return readByte() & 0xff; |
424 |
|
} |
425 |
|
|
426 |
|
public long readUnsignedInt() |
427 |
|
throws IOException |
428 |
|
{ |
429 |
|
return readInt() & 0xffffffff; |
430 |
|
} |
431 |
|
|
432 |
|
public int readUnsignedShort() |
433 |
|
throws IOException |
434 |
|
{ |
435 |
|
return readShort() & 0xffff; |
436 |
|
} |
437 |
|
|
438 |
|
public String readUTF() |
439 |
|
throws IOException |
440 |
|
{ |
441 |
|
checkClosed(); |
442 |
|
|
443 |
|
String data; |
444 |
|
ByteOrder old = getByteOrder(); |
445 |
|
setByteOrder(ByteOrder.BIG_ENDIAN); // Strings are always big endian. |
446 |
|
|
447 |
|
try |
448 |
|
{ |
449 |
|
data = DataInputStream.readUTF(this); |
450 |
|
} |
451 |
|
finally |
452 |
|
{ |
453 |
|
setByteOrder(old); |
454 |
|
} |
455 |
|
|
456 |
|
return data; |
457 |
|
} |
458 |
|
|
459 |
|
public void reset() |
460 |
|
throws IOException |
461 |
|
{ |
462 |
|
checkClosed(); |
463 |
|
|
464 |
|
long mark = ((Long) markStack.pop()).longValue(); |
465 |
|
seek(mark); |
466 |
|
} |
467 |
|
|
468 |
|
public void seek(long position) |
469 |
|
throws IOException |
470 |
|
{ |
471 |
|
checkClosed(); |
472 |
|
|
473 |
|
if (position < getFlushedPosition()) |
474 |
|
throw new IndexOutOfBoundsException("position < flushed position"); |
475 |
|
|
476 |
|
streamPos = position; |
477 |
|
bitOffset = 0; |
478 |
|
} |
479 |
|
|
480 |
|
public void setBitOffset (int bitOffset) |
481 |
|
throws IOException |
482 |
|
{ |
483 |
|
checkClosed(); |
484 |
|
|
485 |
|
if (bitOffset < 0 || bitOffset > 7) |
486 |
|
throw new IllegalArgumentException(); |
487 |
|
|
488 |
|
this.bitOffset = bitOffset; |
489 |
|
} |
490 |
|
|
491 |
|
public void setByteOrder(ByteOrder byteOrder) |
492 |
{ |
{ |
493 |
this.byteOrder = byteOrder; |
this.byteOrder = byteOrder; |
494 |
} |
} |
495 |
|
|
496 |
|
public int skipBytes(int num) |
497 |
|
throws IOException |
498 |
|
{ |
499 |
|
checkClosed(); |
500 |
|
|
501 |
|
seek(getStreamPosition() + num); |
502 |
|
bitOffset = 0; |
503 |
|
return num; |
504 |
|
} |
505 |
|
|
506 |
|
public long skipBytes(long num) |
507 |
|
throws IOException |
508 |
|
{ |
509 |
|
checkClosed(); |
510 |
|
|
511 |
|
seek(getStreamPosition() + num); |
512 |
|
bitOffset = 0; |
513 |
|
return num; |
514 |
|
} |
515 |
} |
} |