1 /* 2 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.imageio.stream; 27 28 import java.io.DataInputStream; 29 import java.io.EOFException; 30 import java.io.IOException; 31 import java.nio.ByteOrder; 32 import java.util.Stack; 33 import javax.imageio.IIOException; 34 35 /** 36 * An abstract class implementing the {@code ImageInputStream} interface. 37 * This class is designed to reduce the number of methods that must 38 * be implemented by subclasses. 39 * 40 * <p> In particular, this class handles most or all of the details of 41 * byte order interpretation, buffering, mark/reset, discarding, 42 * closing, and disposing. 43 */ 44 public abstract class ImageInputStreamImpl implements ImageInputStream { 45 46 private Stack<Long> markByteStack = new Stack<>(); 47 48 private Stack<Integer> markBitStack = new Stack<>(); 49 50 private boolean isClosed = false; 51 52 // Length of the buffer used for readFully(type[], int, int) 53 private static final int BYTE_BUF_LENGTH = 8192; 54 55 /** 56 * Byte buffer used for readFully(type[], int, int). Note that this 57 * array is also used for bulk reads in readShort(), readInt(), etc, so 58 * it should be large enough to hold a primitive value (i.e. >= 8 bytes). 59 * Also note that this array is package protected, so that it can be 60 * used by ImageOutputStreamImpl in a similar manner. 61 */ 62 byte[] byteBuf = new byte[BYTE_BUF_LENGTH]; 63 64 /** 65 * The byte order of the stream as an instance of the enumeration 66 * class {@code java.nio.ByteOrder}, where 67 * {@code ByteOrder.BIG_ENDIAN} indicates network byte order 68 * and {@code ByteOrder.LITTLE_ENDIAN} indicates the reverse 69 * order. By default, the value is 70 * {@code ByteOrder.BIG_ENDIAN}. 71 */ 72 protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN; 73 74 /** 75 * The current read position within the stream. Subclasses are 76 * responsible for keeping this value current from any method they 77 * override that alters the read position. 78 */ 79 protected long streamPos; 80 81 /** 82 * The current bit offset within the stream. Subclasses are 83 * responsible for keeping this value current from any method they 84 * override that alters the bit offset. 85 */ 86 protected int bitOffset; 87 88 /** 89 * The position prior to which data may be discarded. Seeking 90 * to a smaller position is not allowed. {@code flushedPos} 91 * will always be {@literal >= 0}. 92 */ 93 protected long flushedPos = 0; 94 95 /** 96 * Constructs an {@code ImageInputStreamImpl}. 97 */ 98 public ImageInputStreamImpl() { 99 } 100 101 /** 102 * Throws an {@code IOException} if the stream has been closed. 103 * Subclasses may call this method from any of their methods that 104 * require the stream not to be closed. 105 * 106 * @exception IOException if the stream is closed. 107 */ 108 protected final void checkClosed() throws IOException { 109 if (isClosed) { 110 throw new IOException("closed"); 111 } 112 } 113 114 public void setByteOrder(ByteOrder byteOrder) { 115 this.byteOrder = byteOrder; 116 } 117 118 public ByteOrder getByteOrder() { 119 return byteOrder; 120 } 121 122 /** 123 * Reads a single byte from the stream and returns it as an 124 * {@code int} between 0 and 255. If EOF is reached, 125 * {@code -1} is returned. 126 * 127 * <p> Subclasses must provide an implementation for this method. 128 * The subclass implementation should update the stream position 129 * before exiting. 130 * 131 * <p> The bit offset within the stream must be reset to zero before 132 * the read occurs. 133 * 134 * @return the value of the next byte in the stream, or {@code -1} 135 * if EOF is reached. 136 * 137 * @exception IOException if the stream has been closed. 138 */ 139 public abstract int read() throws IOException; 140 141 /** 142 * A convenience method that calls {@code read(b, 0, b.length)}. 143 * 144 * <p> The bit offset within the stream is reset to zero before 145 * the read occurs. 146 * 147 * @return the number of bytes actually read, or {@code -1} 148 * to indicate EOF. 149 * 150 * @exception NullPointerException if {@code b} is 151 * {@code null}. 152 * @exception IOException if an I/O error occurs. 153 */ 154 public int read(byte[] b) throws IOException { 155 return read(b, 0, b.length); 156 } 157 158 /** 159 * Reads up to {@code len} bytes from the stream, and stores 160 * them into {@code b} starting at index {@code off}. 161 * If no bytes can be read because the end of the stream has been 162 * reached, {@code -1} is returned. 163 * 164 * <p> The bit offset within the stream must be reset to zero before 165 * the read occurs. 166 * 167 * <p> Subclasses must provide an implementation for this method. 168 * The subclass implementation should update the stream position 169 * before exiting. 170 * 171 * @param b an array of bytes to be written to. 172 * @param off the starting position within {@code b} to write to. 173 * @param len the maximum number of bytes to read. 174 * 175 * @return the number of bytes actually read, or {@code -1} 176 * to indicate EOF. 177 * 178 * @exception IndexOutOfBoundsException if {@code off} is 179 * negative, {@code len} is negative, or {@code off + len} 180 * is greater than {@code b.length}. 181 * @exception NullPointerException if {@code b} is 182 * {@code null}. 183 * @exception IOException if an I/O error occurs. 184 */ 185 public abstract int read(byte[] b, int off, int len) throws IOException; 186 187 public void readBytes(IIOByteBuffer buf, int len) throws IOException { 188 if (len < 0) { 189 throw new IndexOutOfBoundsException("len < 0!"); 190 } 191 if (buf == null) { 192 throw new NullPointerException("buf == null!"); 193 } 194 195 byte[] data = new byte[len]; 196 len = read(data, 0, len); 197 198 buf.setData(data); 199 buf.setOffset(0); 200 buf.setLength(len); 201 } 202 203 public boolean readBoolean() throws IOException { 204 int ch = this.read(); 205 if (ch < 0) { 206 throw new EOFException(); 207 } 208 return (ch != 0); 209 } 210 211 public byte readByte() throws IOException { 212 int ch = this.read(); 213 if (ch < 0) { 214 throw new EOFException(); 215 } 216 return (byte)ch; 217 } 218 219 public int readUnsignedByte() throws IOException { 220 int ch = this.read(); 221 if (ch < 0) { 222 throw new EOFException(); 223 } 224 return ch; 225 } 226 227 public short readShort() throws IOException { 228 if (read(byteBuf, 0, 2) != 2) { 229 throw new EOFException(); 230 } 231 232 if (byteOrder == ByteOrder.BIG_ENDIAN) { 233 return (short) 234 (((byteBuf[0] & 0xff) << 8) | ((byteBuf[1] & 0xff) << 0)); 235 } else { 236 return (short) 237 (((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0)); 238 } 239 } 240 241 public int readUnsignedShort() throws IOException { 242 return ((int)readShort()) & 0xffff; 243 } 244 245 public char readChar() throws IOException { 246 return (char)readShort(); 247 } 248 249 public int readInt() throws IOException { 250 if (read(byteBuf, 0, 4) != 4) { 251 throw new EOFException(); 252 } 253 254 if (byteOrder == ByteOrder.BIG_ENDIAN) { 255 return 256 (((byteBuf[0] & 0xff) << 24) | ((byteBuf[1] & 0xff) << 16) | 257 ((byteBuf[2] & 0xff) << 8) | ((byteBuf[3] & 0xff) << 0)); 258 } else { 259 return 260 (((byteBuf[3] & 0xff) << 24) | ((byteBuf[2] & 0xff) << 16) | 261 ((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0)); 262 } 263 } 264 265 public long readUnsignedInt() throws IOException { 266 return ((long)readInt()) & 0xffffffffL; 267 } 268 269 public long readLong() throws IOException { 270 // REMIND: Once 6277756 is fixed, we should do a bulk read of all 8 271 // bytes here as we do in readShort() and readInt() for even better 272 // performance (see 6347575 for details). 273 int i1 = readInt(); 274 int i2 = readInt(); 275 276 if (byteOrder == ByteOrder.BIG_ENDIAN) { 277 return ((long)i1 << 32) + (i2 & 0xFFFFFFFFL); 278 } else { 279 return ((long)i2 << 32) + (i1 & 0xFFFFFFFFL); 280 } 281 } 282 283 public float readFloat() throws IOException { 284 return Float.intBitsToFloat(readInt()); 285 } 286 287 public double readDouble() throws IOException { 288 return Double.longBitsToDouble(readLong()); 289 } 290 291 public String readLine() throws IOException { 292 StringBuilder input = new StringBuilder(); 293 int c = -1; 294 boolean eol = false; 295 296 while (!eol) { 297 switch (c = read()) { 298 case -1: 299 case '\n': 300 eol = true; 301 break; 302 case '\r': 303 eol = true; 304 long cur = getStreamPosition(); 305 if ((read()) != '\n') { 306 seek(cur); 307 } 308 break; 309 default: 310 input.append((char)c); 311 break; 312 } 313 } 314 315 if ((c == -1) && (input.length() == 0)) { 316 return null; 317 } 318 return input.toString(); 319 } 320 321 public String readUTF() throws IOException { 322 this.bitOffset = 0; 323 324 // Fix 4494369: method ImageInputStreamImpl.readUTF() 325 // does not work as specified (it should always assume 326 // network byte order). 327 ByteOrder oldByteOrder = getByteOrder(); 328 setByteOrder(ByteOrder.BIG_ENDIAN); 329 330 String ret; 331 try { 332 ret = DataInputStream.readUTF(this); 333 } catch (IOException e) { 334 // Restore the old byte order even if an exception occurs 335 setByteOrder(oldByteOrder); 336 throw e; 337 } 338 339 setByteOrder(oldByteOrder); 340 return ret; 341 } 342 343 public void readFully(byte[] b, int off, int len) throws IOException { 344 // Fix 4430357 - if off + len < 0, overflow occurred 345 if (off < 0 || len < 0 || off + len > b.length || off + len < 0) { 346 throw new IndexOutOfBoundsException 347 ("off < 0 || len < 0 || off + len > b.length!"); 348 } 349 350 while (len > 0) { 351 int nbytes = read(b, off, len); 352 if (nbytes == -1) { 353 throw new EOFException(); 354 } 355 off += nbytes; 356 len -= nbytes; 357 } 358 } 359 360 public void readFully(byte[] b) throws IOException { 361 readFully(b, 0, b.length); 362 } 363 364 public void readFully(short[] s, int off, int len) throws IOException { 365 // Fix 4430357 - if off + len < 0, overflow occurred 366 if (off < 0 || len < 0 || off + len > s.length || off + len < 0) { 367 throw new IndexOutOfBoundsException 368 ("off < 0 || len < 0 || off + len > s.length!"); 369 } 370 371 while (len > 0) { 372 int nelts = Math.min(len, byteBuf.length/2); 373 readFully(byteBuf, 0, nelts*2); 374 toShorts(byteBuf, s, off, nelts); 375 off += nelts; 376 len -= nelts; 377 } 378 } 379 380 public void readFully(char[] c, int off, int len) throws IOException { 381 // Fix 4430357 - if off + len < 0, overflow occurred 382 if (off < 0 || len < 0 || off + len > c.length || off + len < 0) { 383 throw new IndexOutOfBoundsException 384 ("off < 0 || len < 0 || off + len > c.length!"); 385 } 386 387 while (len > 0) { 388 int nelts = Math.min(len, byteBuf.length/2); 389 readFully(byteBuf, 0, nelts*2); 390 toChars(byteBuf, c, off, nelts); 391 off += nelts; 392 len -= nelts; 393 } 394 } 395 396 public void readFully(int[] i, int off, int len) throws IOException { 397 // Fix 4430357 - if off + len < 0, overflow occurred 398 if (off < 0 || len < 0 || off + len > i.length || off + len < 0) { 399 throw new IndexOutOfBoundsException 400 ("off < 0 || len < 0 || off + len > i.length!"); 401 } 402 403 while (len > 0) { 404 int nelts = Math.min(len, byteBuf.length/4); 405 readFully(byteBuf, 0, nelts*4); 406 toInts(byteBuf, i, off, nelts); 407 off += nelts; 408 len -= nelts; 409 } 410 } 411 412 public void readFully(long[] l, int off, int len) throws IOException { 413 // Fix 4430357 - if off + len < 0, overflow occurred 414 if (off < 0 || len < 0 || off + len > l.length || off + len < 0) { 415 throw new IndexOutOfBoundsException 416 ("off < 0 || len < 0 || off + len > l.length!"); 417 } 418 419 while (len > 0) { 420 int nelts = Math.min(len, byteBuf.length/8); 421 readFully(byteBuf, 0, nelts*8); 422 toLongs(byteBuf, l, off, nelts); 423 off += nelts; 424 len -= nelts; 425 } 426 } 427 428 public void readFully(float[] f, int off, int len) throws IOException { 429 // Fix 4430357 - if off + len < 0, overflow occurred 430 if (off < 0 || len < 0 || off + len > f.length || off + len < 0) { 431 throw new IndexOutOfBoundsException 432 ("off < 0 || len < 0 || off + len > f.length!"); 433 } 434 435 while (len > 0) { 436 int nelts = Math.min(len, byteBuf.length/4); 437 readFully(byteBuf, 0, nelts*4); 438 toFloats(byteBuf, f, off, nelts); 439 off += nelts; 440 len -= nelts; 441 } 442 } 443 444 public void readFully(double[] d, int off, int len) throws IOException { 445 // Fix 4430357 - if off + len < 0, overflow occurred 446 if (off < 0 || len < 0 || off + len > d.length || off + len < 0) { 447 throw new IndexOutOfBoundsException 448 ("off < 0 || len < 0 || off + len > d.length!"); 449 } 450 451 while (len > 0) { 452 int nelts = Math.min(len, byteBuf.length/8); 453 readFully(byteBuf, 0, nelts*8); 454 toDoubles(byteBuf, d, off, nelts); 455 off += nelts; 456 len -= nelts; 457 } 458 } 459 460 private void toShorts(byte[] b, short[] s, int off, int len) { 461 int boff = 0; 462 if (byteOrder == ByteOrder.BIG_ENDIAN) { 463 for (int j = 0; j < len; j++) { 464 int b0 = b[boff]; 465 int b1 = b[boff + 1] & 0xff; 466 s[off + j] = (short)((b0 << 8) | b1); 467 boff += 2; 468 } 469 } else { 470 for (int j = 0; j < len; j++) { 471 int b0 = b[boff + 1]; 472 int b1 = b[boff] & 0xff; 473 s[off + j] = (short)((b0 << 8) | b1); 474 boff += 2; 475 } 476 } 477 } 478 479 private void toChars(byte[] b, char[] c, int off, int len) { 480 int boff = 0; 481 if (byteOrder == ByteOrder.BIG_ENDIAN) { 482 for (int j = 0; j < len; j++) { 483 int b0 = b[boff]; 484 int b1 = b[boff + 1] & 0xff; 485 c[off + j] = (char)((b0 << 8) | b1); 486 boff += 2; 487 } 488 } else { 489 for (int j = 0; j < len; j++) { 490 int b0 = b[boff + 1]; 491 int b1 = b[boff] & 0xff; 492 c[off + j] = (char)((b0 << 8) | b1); 493 boff += 2; 494 } 495 } 496 } 497 498 private void toInts(byte[] b, int[] i, int off, int len) { 499 int boff = 0; 500 if (byteOrder == ByteOrder.BIG_ENDIAN) { 501 for (int j = 0; j < len; j++) { 502 int b0 = b[boff]; 503 int b1 = b[boff + 1] & 0xff; 504 int b2 = b[boff + 2] & 0xff; 505 int b3 = b[boff + 3] & 0xff; 506 i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 507 boff += 4; 508 } 509 } else { 510 for (int j = 0; j < len; j++) { 511 int b0 = b[boff + 3]; 512 int b1 = b[boff + 2] & 0xff; 513 int b2 = b[boff + 1] & 0xff; 514 int b3 = b[boff] & 0xff; 515 i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 516 boff += 4; 517 } 518 } 519 } 520 521 private void toLongs(byte[] b, long[] l, int off, int len) { 522 int boff = 0; 523 if (byteOrder == ByteOrder.BIG_ENDIAN) { 524 for (int j = 0; j < len; j++) { 525 int b0 = b[boff]; 526 int b1 = b[boff + 1] & 0xff; 527 int b2 = b[boff + 2] & 0xff; 528 int b3 = b[boff + 3] & 0xff; 529 int b4 = b[boff + 4]; 530 int b5 = b[boff + 5] & 0xff; 531 int b6 = b[boff + 6] & 0xff; 532 int b7 = b[boff + 7] & 0xff; 533 534 int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 535 int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; 536 537 l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL); 538 boff += 8; 539 } 540 } else { 541 for (int j = 0; j < len; j++) { 542 int b0 = b[boff + 7]; 543 int b1 = b[boff + 6] & 0xff; 544 int b2 = b[boff + 5] & 0xff; 545 int b3 = b[boff + 4] & 0xff; 546 int b4 = b[boff + 3]; 547 int b5 = b[boff + 2] & 0xff; 548 int b6 = b[boff + 1] & 0xff; 549 int b7 = b[boff] & 0xff; 550 551 int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 552 int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; 553 554 l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL); 555 boff += 8; 556 } 557 } 558 } 559 560 private void toFloats(byte[] b, float[] f, int off, int len) { 561 int boff = 0; 562 if (byteOrder == ByteOrder.BIG_ENDIAN) { 563 for (int j = 0; j < len; j++) { 564 int b0 = b[boff]; 565 int b1 = b[boff + 1] & 0xff; 566 int b2 = b[boff + 2] & 0xff; 567 int b3 = b[boff + 3] & 0xff; 568 int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 569 f[off + j] = Float.intBitsToFloat(i); 570 boff += 4; 571 } 572 } else { 573 for (int j = 0; j < len; j++) { 574 int b0 = b[boff + 3]; 575 int b1 = b[boff + 2] & 0xff; 576 int b2 = b[boff + 1] & 0xff; 577 int b3 = b[boff + 0] & 0xff; 578 int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 579 f[off + j] = Float.intBitsToFloat(i); 580 boff += 4; 581 } 582 } 583 } 584 585 private void toDoubles(byte[] b, double[] d, int off, int len) { 586 int boff = 0; 587 if (byteOrder == ByteOrder.BIG_ENDIAN) { 588 for (int j = 0; j < len; j++) { 589 int b0 = b[boff]; 590 int b1 = b[boff + 1] & 0xff; 591 int b2 = b[boff + 2] & 0xff; 592 int b3 = b[boff + 3] & 0xff; 593 int b4 = b[boff + 4]; 594 int b5 = b[boff + 5] & 0xff; 595 int b6 = b[boff + 6] & 0xff; 596 int b7 = b[boff + 7] & 0xff; 597 598 int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 599 int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; 600 long l = ((long)i0 << 32) | (i1 & 0xffffffffL); 601 602 d[off + j] = Double.longBitsToDouble(l); 603 boff += 8; 604 } 605 } else { 606 for (int j = 0; j < len; j++) { 607 int b0 = b[boff + 7]; 608 int b1 = b[boff + 6] & 0xff; 609 int b2 = b[boff + 5] & 0xff; 610 int b3 = b[boff + 4] & 0xff; 611 int b4 = b[boff + 3]; 612 int b5 = b[boff + 2] & 0xff; 613 int b6 = b[boff + 1] & 0xff; 614 int b7 = b[boff] & 0xff; 615 616 int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 617 int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; 618 long l = ((long)i0 << 32) | (i1 & 0xffffffffL); 619 620 d[off + j] = Double.longBitsToDouble(l); 621 boff += 8; 622 } 623 } 624 } 625 626 public long getStreamPosition() throws IOException { 627 checkClosed(); 628 return streamPos; 629 } 630 631 public int getBitOffset() throws IOException { 632 checkClosed(); 633 return bitOffset; 634 } 635 636 public void setBitOffset(int bitOffset) throws IOException { 637 checkClosed(); 638 if (bitOffset < 0 || bitOffset > 7) { 639 throw new IllegalArgumentException("bitOffset must be betwwen 0 and 7!"); 640 } 641 this.bitOffset = bitOffset; 642 } 643 644 public int readBit() throws IOException { 645 checkClosed(); 646 647 // Compute final bit offset before we call read() and seek() 648 int newBitOffset = (this.bitOffset + 1) & 0x7; 649 650 int val = read(); 651 if (val == -1) { 652 throw new EOFException(); 653 } 654 655 if (newBitOffset != 0) { 656 // Move byte position back if in the middle of a byte 657 seek(getStreamPosition() - 1); 658 // Shift the bit to be read to the rightmost position 659 val >>= 8 - newBitOffset; 660 } 661 this.bitOffset = newBitOffset; 662 663 return val & 0x1; 664 } 665 666 public long readBits(int numBits) throws IOException { 667 checkClosed(); 668 669 if (numBits < 0 || numBits > 64) { 670 throw new IllegalArgumentException(); 671 } 672 if (numBits == 0) { 673 return 0L; 674 } 675 676 // Have to read additional bits on the left equal to the bit offset 677 int bitsToRead = numBits + bitOffset; 678 679 // Compute final bit offset before we call read() and seek() 680 int newBitOffset = (this.bitOffset + numBits) & 0x7; 681 682 // Read a byte at a time, accumulate 683 long accum = 0L; 684 while (bitsToRead > 0) { 685 int val = read(); 686 if (val == -1) { 687 throw new EOFException(); 688 } 689 690 accum <<= 8; 691 accum |= val; 692 bitsToRead -= 8; 693 } 694 695 // Move byte position back if in the middle of a byte 696 if (newBitOffset != 0) { 697 seek(getStreamPosition() - 1); 698 } 699 this.bitOffset = newBitOffset; 700 701 // Shift away unwanted bits on the right. 702 accum >>>= (-bitsToRead); // Negative of bitsToRead == extra bits read 703 704 // Mask out unwanted bits on the left 705 accum &= (-1L >>> (64 - numBits)); 706 707 return accum; 708 } 709 710 /** 711 * Returns {@code -1L} to indicate that the stream has unknown 712 * length. Subclasses must override this method to provide actual 713 * length information. 714 * 715 * @return -1L to indicate unknown length. 716 */ 717 public long length() { 718 return -1L; 719 } 720 721 /** 722 * Advances the current stream position by calling 723 * {@code seek(getStreamPosition() + n)}. 724 * 725 * <p> The bit offset is reset to zero. 726 * 727 * @param n the number of bytes to seek forward. 728 * 729 * @return an {@code int} representing the number of bytes 730 * skipped. 731 * 732 * @exception IOException if {@code getStreamPosition} 733 * throws an {@code IOException} when computing either 734 * the starting or ending position. 735 */ 736 public int skipBytes(int n) throws IOException { 737 long pos = getStreamPosition(); 738 seek(pos + n); 739 return (int)(getStreamPosition() - pos); 740 } 741 742 /** 743 * Advances the current stream position by calling 744 * {@code seek(getStreamPosition() + n)}. 745 * 746 * <p> The bit offset is reset to zero. 747 * 748 * @param n the number of bytes to seek forward. 749 * 750 * @return a {@code long} representing the number of bytes 751 * skipped. 752 * 753 * @exception IOException if {@code getStreamPosition} 754 * throws an {@code IOException} when computing either 755 * the starting or ending position. 756 */ 757 public long skipBytes(long n) throws IOException { 758 long pos = getStreamPosition(); 759 seek(pos + n); 760 return getStreamPosition() - pos; 761 } 762 763 public void seek(long pos) throws IOException { 764 checkClosed(); 765 766 // This test also covers pos < 0 767 if (pos < flushedPos) { 768 throw new IndexOutOfBoundsException("pos < flushedPos!"); 769 } 770 771 this.streamPos = pos; 772 this.bitOffset = 0; 773 } 774 775 /** 776 * Pushes the current stream position onto a stack of marked 777 * positions. 778 */ 779 public void mark() { 780 try { 781 markByteStack.push(Long.valueOf(getStreamPosition())); 782 markBitStack.push(Integer.valueOf(getBitOffset())); 783 } catch (IOException e) { 784 } 785 } 786 787 /** 788 * Resets the current stream byte and bit positions from the stack 789 * of marked positions. 790 * 791 * <p> An {@code IOException} will be thrown if the previous 792 * marked position lies in the discarded portion of the stream. 793 * 794 * @exception IOException if an I/O error occurs. 795 */ 796 public void reset() throws IOException { 797 if (markByteStack.empty()) { 798 return; 799 } 800 801 long pos = markByteStack.pop().longValue(); 802 if (pos < flushedPos) { 803 throw new IIOException 804 ("Previous marked position has been discarded!"); 805 } 806 seek(pos); 807 808 int offset = markBitStack.pop().intValue(); 809 setBitOffset(offset); 810 } 811 812 public void flushBefore(long pos) throws IOException { 813 checkClosed(); 814 if (pos < flushedPos) { 815 throw new IndexOutOfBoundsException("pos < flushedPos!"); 816 } 817 if (pos > getStreamPosition()) { 818 throw new IndexOutOfBoundsException("pos > getStreamPosition()!"); 819 } 820 // Invariant: flushedPos >= 0 821 flushedPos = pos; 822 } 823 824 public void flush() throws IOException { 825 flushBefore(getStreamPosition()); 826 } 827 828 public long getFlushedPosition() { 829 return flushedPos; 830 } 831 832 /** 833 * Default implementation returns false. Subclasses should 834 * override this if they cache data. 835 */ 836 public boolean isCached() { 837 return false; 838 } 839 840 /** 841 * Default implementation returns false. Subclasses should 842 * override this if they cache data in main memory. 843 */ 844 public boolean isCachedMemory() { 845 return false; 846 } 847 848 /** 849 * Default implementation returns false. Subclasses should 850 * override this if they cache data in a temporary file. 851 */ 852 public boolean isCachedFile() { 853 return false; 854 } 855 856 public void close() throws IOException { 857 checkClosed(); 858 859 isClosed = true; 860 } 861 862 /** 863 * Finalizes this object prior to garbage collection. The 864 * {@code close} method is called to close any open input 865 * source. This method should not be called from application 866 * code. 867 * 868 * @exception Throwable if an error occurs during superclass 869 * finalization. 870 * 871 * @deprecated The {@code finalize} method has been deprecated. 872 * Subclasses that override {@code finalize} in order to perform cleanup 873 * should be modified to use alternative cleanup mechanisms and 874 * to remove the overriding {@code finalize} method. 875 * When overriding the {@code finalize} method, its implementation must explicitly 876 * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}. 877 * See the specification for {@link Object#finalize()} for further 878 * information about migration options. 879 */ 880 @Deprecated(since="9") 881 protected void finalize() throws Throwable { 882 if (!isClosed) { 883 try { 884 close(); 885 } catch (IOException e) { 886 } 887 } 888 super.finalize(); 889 } 890 }