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 }