001 /* ImageInputStream.java --
002 Copyright (C) 2004 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.imageio.stream;
040
041 import java.io.DataInputStream;
042 import java.io.EOFException;
043 import java.io.IOException;
044 import java.nio.ByteOrder;
045 import java.util.Stack;
046
047 /**
048 * @author Michael Koch (konqueror@gmx.de)
049 */
050 public abstract class ImageInputStreamImpl implements ImageInputStream
051 {
052 private boolean closed;
053 private Stack markStack = new Stack();
054
055 byte[] buffer = new byte[8];
056
057 protected int bitOffset;
058 protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
059 protected long flushedPos;
060 protected long streamPos;
061
062 public ImageInputStreamImpl()
063 {
064 // Do nothing here.
065 }
066
067 protected final void checkClosed()
068 throws IOException
069 {
070 if (closed)
071 throw new IOException("stream closed");
072 }
073
074 public void close()
075 throws IOException
076 {
077 checkClosed();
078 closed = true;
079 }
080
081 protected void finalize()
082 throws Throwable
083 {
084 if (!closed)
085 close();
086 }
087
088 public void flush()
089 throws IOException
090 {
091 flushBefore(getStreamPosition());
092 }
093
094 public void flushBefore(long position)
095 throws IOException
096 {
097 if (position < flushedPos)
098 throw new IndexOutOfBoundsException();
099
100 if (position > streamPos)
101 throw new IndexOutOfBoundsException();
102
103 flushedPos = position;
104 }
105
106 public int getBitOffset()
107 throws IOException
108 {
109 checkClosed();
110 return bitOffset;
111 }
112
113 public ByteOrder getByteOrder()
114 {
115 return byteOrder;
116 }
117
118 public long getFlushedPosition()
119 {
120 return flushedPos;
121 }
122
123 public long getStreamPosition()
124 throws IOException
125 {
126 checkClosed();
127 return streamPos;
128 }
129
130 public boolean isCached()
131 {
132 return false;
133 }
134
135 public boolean isCachedFile()
136 {
137 return false;
138 }
139
140 public boolean isCachedMemory()
141 {
142 return false;
143 }
144
145 public long length()
146 {
147 return -1L;
148 }
149
150 public void mark()
151 {
152 try
153 {
154 markStack.push(new Long(getStreamPosition()));
155 }
156 catch (IOException e)
157 {
158 throw new RuntimeException(e);
159 }
160 }
161
162 public abstract int read()
163 throws IOException;
164
165 public abstract int read(byte[] data, int offset, int len)
166 throws IOException;
167
168 public int read(byte[] data)
169 throws IOException
170 {
171 return read(data, 0, data.length);
172 }
173
174 public int readBit()
175 throws IOException
176 {
177 checkClosed();
178
179 // Calculate new bit offset here as readByte clears it.
180 int newOffset = (bitOffset + 1) & 0x7;
181
182 // Clears bitOffset.
183 byte data = readByte();
184
185 // If newOffset is 0 it means we just read the 8th bit in a byte
186 // and therefore we want to advance to the next byte. Otherwise
187 // we want to roll back the stream one byte so that future readBit
188 // calls read bits from the same current byte.
189 if (newOffset != 0)
190 {
191 seek(getStreamPosition() - 1);
192 data = (byte) (data >> (8 - newOffset));
193 }
194
195 bitOffset = newOffset;
196 return data & 0x1;
197 }
198
199 public long readBits(int numBits)
200 throws IOException
201 {
202 checkClosed();
203
204 if (numBits < 0 || numBits > 64)
205 throw new IllegalArgumentException();
206
207 long bits = 0L;
208
209 for (int i = 0; i < numBits; i++)
210 {
211 bits <<= 1;
212 bits |= readBit();
213 }
214 return bits;
215 }
216
217 public boolean readBoolean()
218 throws IOException
219 {
220 byte data = readByte();
221
222 return data != 0;
223 }
224
225 public byte readByte()
226 throws IOException
227 {
228 checkClosed();
229
230 int data = read();
231
232 if (data == -1)
233 throw new EOFException();
234
235 return (byte) data;
236 }
237
238 public void readBytes(IIOByteBuffer buffer, int len)
239 throws IOException
240 {
241 readFullyPrivate(buffer.getData(), buffer.getOffset(), len);
242
243 buffer.setLength(len);
244 }
245
246 public char readChar()
247 throws IOException
248 {
249 return (char) readShort();
250 }
251
252 public double readDouble()
253 throws IOException
254 {
255 return Double.longBitsToDouble(readLong());
256 }
257
258 public float readFloat()
259 throws IOException
260 {
261 return Float.intBitsToFloat(readInt());
262 }
263
264 public void readFully(byte[] data)
265 throws IOException
266 {
267 readFully(data, 0, data.length);
268 }
269
270 public void readFully(byte[] data, int offset, int len)
271 throws IOException
272 {
273 readFullyPrivate(data, offset, len);
274 }
275
276 public void readFully(char[] data, int offset, int len)
277 throws IOException
278 {
279 for (int i = 0; i < len; ++i)
280 data[offset + i] = readChar();
281 }
282
283 public void readFully(double[] data, int offset, int len)
284 throws IOException
285 {
286 for (int i = 0; i < len; ++i)
287 data[offset + i] = readDouble();
288 }
289
290 public void readFully(float[] data, int offset, int len)
291 throws IOException
292 {
293 for (int i = 0; i < len; ++i)
294 data[offset + i] = readFloat();
295 }
296
297 public void readFully(int[] data, int offset, int len)
298 throws IOException
299 {
300 for (int i = 0; i < len; ++i)
301 data[offset + i] = readInt();
302 }
303
304 public void readFully(long[] data, int offset, int len)
305 throws IOException
306 {
307 for (int i = 0; i < len; ++i)
308 data[offset + i] = readLong();
309 }
310
311 public void readFully(short[] data, int offset, int len)
312 throws IOException
313 {
314 for (int i = 0; i < len; ++i)
315 data[offset + i] = readShort();
316 }
317
318 public int readInt()
319 throws IOException
320 {
321 readFullyPrivate(buffer, 0, 4);
322
323 if (getByteOrder() == ByteOrder.LITTLE_ENDIAN)
324 return (int)
325 (((int) (buffer[0] & 0xff) << 0)
326 | ((int) (buffer[1] & 0xff) << 8)
327 | ((int) (buffer[2] & 0xff) << 16)
328 | ((int) (buffer[3] & 0xff) << 24));
329
330 return (int)
331 (((int) (buffer[0] & 0xff) << 24)
332 + ((int) (buffer[1] & 0xff) << 16)
333 + ((int) (buffer[2] & 0xff) << 8)
334 + ((int) (buffer[3] & 0xff) << 0));
335 }
336
337 public String readLine()
338 throws IOException
339 {
340 checkClosed();
341
342 int c = -1;
343 boolean eol = false;
344 StringBuffer buffer = new StringBuffer();
345
346 c = read();
347 if (c == -1)
348 return null;
349
350 while (!eol)
351 {
352 switch(c)
353 {
354 case '\r':
355 // Check for following '\n'.
356 long oldPosition = getStreamPosition();
357 c = read();
358 if (c == -1 || c == '\n')
359 eol = true;
360 else
361 {
362 seek(oldPosition);
363 eol = true;
364 }
365 continue;
366
367 case '\n':
368 eol = true;
369 continue;
370
371 default:
372 buffer.append((char) c);
373 break;
374 }
375 c = read();
376 if (c == -1)
377 eol = true;
378 }
379
380 return buffer.toString();
381 }
382
383 public long readLong()
384 throws IOException
385 {
386 readFullyPrivate(buffer, 0, 8);
387
388 if (getByteOrder() == ByteOrder.LITTLE_ENDIAN)
389 return (long)
390 (((long) (buffer[0] & 0xff) << 0)
391 | ((long) (buffer[1] & 0xff) << 8)
392 | ((long) (buffer[2] & 0xff) << 16)
393 | ((long) (buffer[3] & 0xff) << 24)
394 | ((long) (buffer[4] & 0xff) << 32)
395 | ((long) (buffer[5] & 0xff) << 40)
396 | ((long) (buffer[6] & 0xff) << 48)
397 | ((long) (buffer[7] & 0xff) << 56));
398
399 return (long)
400 (((long) (buffer[0] & 0xff) << 56)
401 | ((long) (buffer[1] & 0xff) << 48)
402 | ((long) (buffer[2] & 0xff) << 40)
403 | ((long) (buffer[3] & 0xff) << 32)
404 | ((long) (buffer[4] & 0xff) << 24)
405 | ((long) (buffer[5] & 0xff) << 16)
406 | ((long) (buffer[6] & 0xff) << 8)
407 | ((long) (buffer[7] & 0xff) << 0));
408 }
409
410 public short readShort()
411 throws IOException
412 {
413 readFullyPrivate(buffer, 0, 2);
414
415 if (getByteOrder() == ByteOrder.LITTLE_ENDIAN)
416 return (short)
417 (((short) (buffer[0] & 0xff) << 0)
418 | ((short) (buffer[1] & 0xff) << 8));
419
420 return (short)
421 (((short) (buffer[0] & 0xff) << 8)
422 | ((short) (buffer[1] & 0xff) << 0));
423 }
424
425 public int readUnsignedByte()
426 throws IOException
427 {
428 return (int) readByte() & 0xff;
429 }
430
431 public long readUnsignedInt()
432 throws IOException
433 {
434 return (long) readInt() & 0xffffffffL;
435 }
436
437 public int readUnsignedShort()
438 throws IOException
439 {
440 return (int) readShort() & 0xffff;
441 }
442
443 public String readUTF()
444 throws IOException
445 {
446 checkClosed();
447
448 String data;
449 ByteOrder old = getByteOrder();
450 // Strings are always big endian.
451 setByteOrder(ByteOrder.BIG_ENDIAN);
452
453 try
454 {
455 data = DataInputStream.readUTF(this);
456 }
457 finally
458 {
459 setByteOrder(old);
460 }
461
462 return data;
463 }
464
465 public void reset()
466 throws IOException
467 {
468 checkClosed();
469
470 long mark = ((Long) markStack.pop()).longValue();
471 seek(mark);
472 }
473
474 public void seek(long position)
475 throws IOException
476 {
477 checkClosed();
478
479 if (position < getFlushedPosition())
480 throw new IndexOutOfBoundsException("position < flushed position");
481
482 streamPos = position;
483 bitOffset = 0;
484 }
485
486 public void setBitOffset (int bitOffset)
487 throws IOException
488 {
489 checkClosed();
490
491 if (bitOffset < 0 || bitOffset > 7)
492 throw new IllegalArgumentException("bitOffset not between 0 and 7 inclusive");
493
494 this.bitOffset = bitOffset;
495 }
496
497 public void setByteOrder(ByteOrder byteOrder)
498 {
499 this.byteOrder = byteOrder;
500 }
501
502 public int skipBytes(int num)
503 throws IOException
504 {
505 checkClosed();
506
507 seek(getStreamPosition() + num);
508 bitOffset = 0;
509 return num;
510 }
511
512 public long skipBytes(long num)
513 throws IOException
514 {
515 checkClosed();
516
517 seek(getStreamPosition() + num);
518 bitOffset = 0;
519 return num;
520 }
521
522 private void readFullyPrivate (byte[] buf, int offset, int len) throws IOException
523 {
524 checkClosed();
525
526 if (len < 0)
527 throw new IndexOutOfBoundsException("Negative length: " + len);
528
529 while (len > 0)
530 {
531 // read will block until some data is available.
532 int numread = read (buf, offset, len);
533 if (numread < 0)
534 throw new EOFException ();
535 len -= numread;
536 offset += numread;
537 }
538 bitOffset = 0;
539 }
540 }