Source for javax.imageio.stream.ImageInputStreamImpl

   1: /* ImageInputStream.java --
   2:    Copyright (C) 2004  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.imageio.stream;
  40: 
  41: import gnu.java.lang.CPStringBuilder;
  42: 
  43: import java.io.DataInputStream;
  44: import java.io.EOFException;
  45: import java.io.IOException;
  46: import java.nio.ByteOrder;
  47: import java.util.Stack;
  48: 
  49: /**
  50:  * @author Michael Koch (konqueror@gmx.de)
  51:  */
  52: public abstract class ImageInputStreamImpl implements ImageInputStream
  53: {
  54:   private boolean closed;
  55:   private Stack markStack = new Stack();
  56: 
  57:   byte[] buffer = new byte[8];
  58: 
  59:   protected int bitOffset;
  60:   protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
  61:   protected long flushedPos;
  62:   protected long streamPos;
  63: 
  64:   public ImageInputStreamImpl()
  65:   {
  66:     // Do nothing here.
  67:   }
  68: 
  69:   protected final void checkClosed()
  70:     throws IOException
  71:   {
  72:     if (closed)
  73:       throw new IOException("stream closed");
  74:   }
  75: 
  76:   public void close()
  77:     throws IOException
  78:   {
  79:     checkClosed();
  80:     closed = true;
  81:   }
  82: 
  83:   protected void finalize()
  84:     throws Throwable
  85:   {
  86:     if (!closed)
  87:       close();
  88:   }
  89: 
  90:   public void flush()
  91:     throws IOException
  92:   {
  93:     flushBefore(getStreamPosition());
  94:   }
  95: 
  96:   public void flushBefore(long position)
  97:     throws IOException
  98:   {
  99:     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: }