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 ImageInputStreamImpl()64 public ImageInputStreamImpl() 65 { 66 // Do nothing here. 67 } 68 checkClosed()69 protected final void checkClosed() 70 throws IOException 71 { 72 if (closed) 73 throw new IOException("stream closed"); 74 } 75 close()76 public void close() 77 throws IOException 78 { 79 checkClosed(); 80 closed = true; 81 } 82 finalize()83 protected void finalize() 84 throws Throwable 85 { 86 if (!closed) 87 close(); 88 } 89 flush()90 public void flush() 91 throws IOException 92 { 93 flushBefore(getStreamPosition()); 94 } 95 flushBefore(long position)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 getBitOffset()108 public int getBitOffset() 109 throws IOException 110 { 111 checkClosed(); 112 return bitOffset; 113 } 114 getByteOrder()115 public ByteOrder getByteOrder() 116 { 117 return byteOrder; 118 } 119 getFlushedPosition()120 public long getFlushedPosition() 121 { 122 return flushedPos; 123 } 124 getStreamPosition()125 public long getStreamPosition() 126 throws IOException 127 { 128 checkClosed(); 129 return streamPos; 130 } 131 isCached()132 public boolean isCached() 133 { 134 return false; 135 } 136 isCachedFile()137 public boolean isCachedFile() 138 { 139 return false; 140 } 141 isCachedMemory()142 public boolean isCachedMemory() 143 { 144 return false; 145 } 146 length()147 public long length() 148 { 149 return -1L; 150 } 151 mark()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 read()164 public abstract int read() 165 throws IOException; 166 read(byte[] data, int offset, int len)167 public abstract int read(byte[] data, int offset, int len) 168 throws IOException; 169 read(byte[] data)170 public int read(byte[] data) 171 throws IOException 172 { 173 return read(data, 0, data.length); 174 } 175 readBit()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 readBits(int numBits)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 readBoolean()219 public boolean readBoolean() 220 throws IOException 221 { 222 byte data = readByte(); 223 224 return data != 0; 225 } 226 readByte()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 readBytes(IIOByteBuffer buffer, int len)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 readChar()248 public char readChar() 249 throws IOException 250 { 251 return (char) readShort(); 252 } 253 readDouble()254 public double readDouble() 255 throws IOException 256 { 257 return Double.longBitsToDouble(readLong()); 258 } 259 readFloat()260 public float readFloat() 261 throws IOException 262 { 263 return Float.intBitsToFloat(readInt()); 264 } 265 readFully(byte[] data)266 public void readFully(byte[] data) 267 throws IOException 268 { 269 readFully(data, 0, data.length); 270 } 271 readFully(byte[] data, int offset, int len)272 public void readFully(byte[] data, int offset, int len) 273 throws IOException 274 { 275 readFullyPrivate(data, offset, len); 276 } 277 readFully(char[] data, int offset, int len)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 readFully(double[] data, int offset, int len)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 readFully(float[] data, int offset, int len)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 readFully(int[] data, int offset, int len)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 readFully(long[] data, int offset, int len)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 readFully(short[] data, int offset, int len)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 readInt()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 readLine()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 readLong()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 readShort()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 readUnsignedByte()427 public int readUnsignedByte() 428 throws IOException 429 { 430 return (int) readByte() & 0xff; 431 } 432 readUnsignedInt()433 public long readUnsignedInt() 434 throws IOException 435 { 436 return (long) readInt() & 0xffffffffL; 437 } 438 readUnsignedShort()439 public int readUnsignedShort() 440 throws IOException 441 { 442 return (int) readShort() & 0xffff; 443 } 444 readUTF()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 reset()467 public void reset() 468 throws IOException 469 { 470 checkClosed(); 471 472 long mark = ((Long) markStack.pop()).longValue(); 473 seek(mark); 474 } 475 seek(long position)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 setBitOffset(int bitOffset)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 setByteOrder(ByteOrder byteOrder)499 public void setByteOrder(ByteOrder byteOrder) 500 { 501 this.byteOrder = byteOrder; 502 } 503 skipBytes(int num)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 skipBytes(long num)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 readFullyPrivate(byte[] buf, int offset, int len)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 } 543