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 }