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