1. /*
  2. * @(#)ImageInputStreamImpl.java 1.53 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.imageio.stream;
  8. import java.io.DataInput;
  9. import java.io.DataInputStream;
  10. import java.io.EOFException;
  11. import java.io.File;
  12. import java.io.FileNotFoundException;
  13. import java.io.IOException;
  14. import java.io.RandomAccessFile;
  15. import java.nio.ByteOrder;
  16. import java.util.Stack;
  17. import javax.imageio.IIOException;
  18. /**
  19. * An abstract class implementing the <code>ImageInputStream</code> interface.
  20. * This class is designed to reduce the number of methods that must
  21. * be implemented by subclasses.
  22. *
  23. * <p> In particular, this class handles most or all of the details of
  24. * byte order interpretation, buffering, mark/reset, discarding,
  25. * closing, and disposing.
  26. */
  27. public abstract class ImageInputStreamImpl implements ImageInputStream {
  28. private Stack markByteStack = new Stack();
  29. private Stack markBitStack = new Stack();
  30. private boolean isClosed = false;
  31. // Length of the buffer used for readFully(type[], int, int)
  32. private static final int BYTE_BUF_LENGTH = 8192;
  33. // Byte buffer used for readFully(type[], int, int)
  34. private byte[] byteBuf = new byte[BYTE_BUF_LENGTH];
  35. /**
  36. * The byte order of the stream as an instance of the enumeration
  37. * class <code>java.nio.ByteOrder</code>, where
  38. * <code>ByteOrder.BIG_ENDIAN</code> indicates network byte order
  39. * and <code>ByteOrder.LITTLE_ENDIAN</code> indicates the reverse
  40. * order. By default, the value is
  41. * <code>ByteOrder.BIG_ENDIAN</code>.
  42. */
  43. protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
  44. /**
  45. * The current read position within the stream. Subclasses are
  46. * responsible for keeping this value current from any method they
  47. * override that alters the read position.
  48. */
  49. protected long streamPos;
  50. /**
  51. * The current bit offset within the stream. Subclasses are
  52. * responsible for keeping this value current from any method they
  53. * override that alters the bit offset.
  54. */
  55. protected int bitOffset;
  56. /**
  57. * The position prior to which data may be discarded. Seeking
  58. * to a smaller position is not allowed. <code>flushedPos</code>
  59. * will always be >= 0.
  60. */
  61. protected long flushedPos = 0;
  62. /**
  63. * Constructs an <code>ImageInputStreamImpl</code>.
  64. */
  65. public ImageInputStreamImpl() {
  66. }
  67. /**
  68. * Throws an <code>IOException</code> if the stream has been closed.
  69. * Subclasses may call this method from any of their methods that
  70. * require the stream not to be closed.
  71. *
  72. * @exception IOException if the stream is closed.
  73. */
  74. protected final void checkClosed() throws IOException {
  75. if (isClosed) {
  76. throw new IOException("closed");
  77. }
  78. }
  79. public void setByteOrder(ByteOrder byteOrder) {
  80. this.byteOrder = byteOrder;
  81. }
  82. public ByteOrder getByteOrder() {
  83. return byteOrder;
  84. }
  85. /*
  86. * Reads a single byte from the stream and returns it as an
  87. * <code>int</code> between 0 and 255. If EOF is reached,
  88. * <code>-1</code> is returned.
  89. *
  90. * <p> Subclasses must provide an implementation for this method.
  91. * The subclass implementation should update the stream position
  92. * before exiting.
  93. *
  94. * <p> The bit offset within the stream must be reset to zero before
  95. * the read occurs.
  96. *
  97. * @return the value of the next byte in the stream, or <code>-1</code>
  98. * if EOF is reached.
  99. *
  100. * @exception IOException if the stream has been closed.
  101. */
  102. public abstract int read() throws IOException;
  103. /**
  104. * A convenience method that calls <code>read(b, 0, b.length)</code>.
  105. *
  106. * <p> The bit offset within the stream is reset to zero before
  107. * the read occurs.
  108. *
  109. * @return the number of bytes actually read, or <code>-1</code>
  110. * to indicate EOF.
  111. *
  112. * @exception NullPointerException if <code>b</code> is
  113. * <code>null</code>.
  114. * @exception IOException if an I/O error occurs.
  115. */
  116. public int read(byte[] b) throws IOException {
  117. return read(b, 0, b.length);
  118. }
  119. /**
  120. * Reads up to <code>len</code> bytes from the stream, and stores
  121. * them into <code>b</code> starting at index <code>off</code>.
  122. * If no bytes can be read because the end of the stream has been
  123. * reached, <code>-1</code> is returned.
  124. *
  125. * <p> The bit offset within the stream must be reset to zero before
  126. * the read occurs.
  127. *
  128. * <p> Subclasses must provide an implementation for this method.
  129. * The subclass implementation should update the stream position
  130. * before exiting.
  131. *
  132. * @param b an array of bytes to be written to.
  133. * @param off the starting position within <code>b</code> to write to.
  134. * @param len the maximum number of bytes to read.
  135. *
  136. * @return the number of bytes actually read, or <code>-1</code>
  137. * to indicate EOF.
  138. *
  139. * @exception IndexOutOfBoundsException if <code>off</code> is
  140. * negative, <code>len</code> is negative, or <code>off +
  141. * len</code> is greater than <code>b.length</code>.
  142. * @exception NullPointerException if <code>b</code> is
  143. * <code>null</code>.
  144. * @exception IOException if an I/O error occurs.
  145. */
  146. public abstract int read(byte[] b, int off, int len) throws IOException;
  147. public void readBytes(IIOByteBuffer buf, int len) throws IOException {
  148. if (len < 0) {
  149. throw new IndexOutOfBoundsException("len < 0!");
  150. }
  151. if (buf == null) {
  152. throw new NullPointerException("buf == null!");
  153. }
  154. byte[] data = new byte[len];
  155. len = read(data, 0, len);
  156. buf.setData(data);
  157. buf.setOffset(0);
  158. buf.setLength(len);
  159. }
  160. public boolean readBoolean() throws IOException {
  161. int ch = this.read();
  162. if (ch < 0) {
  163. throw new EOFException();
  164. }
  165. return (ch != 0);
  166. }
  167. public byte readByte() throws IOException {
  168. int ch = this.read();
  169. if (ch < 0) {
  170. throw new EOFException();
  171. }
  172. return (byte)ch;
  173. }
  174. public int readUnsignedByte() throws IOException {
  175. int ch = this.read();
  176. if (ch < 0) {
  177. throw new EOFException();
  178. }
  179. return ch;
  180. }
  181. public short readShort() throws IOException {
  182. int ch1 = this.read();
  183. int ch2 = this.read();
  184. if ((ch1 | ch2) < 0) {
  185. throw new EOFException();
  186. }
  187. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  188. return (short)((ch1 << 8) + (ch2 << 0));
  189. } else {
  190. return (short)((ch2 << 8) + (ch1 << 0));
  191. }
  192. }
  193. public int readUnsignedShort() throws IOException {
  194. return ((int)readShort()) & 0xffff;
  195. }
  196. public char readChar() throws IOException {
  197. return (char)readShort();
  198. }
  199. public int readInt() throws IOException {
  200. int ch1 = this.read();
  201. int ch2 = this.read();
  202. int ch3 = this.read();
  203. int ch4 = this.read();
  204. if ((ch1 | ch2 | ch3 | ch4) < 0) {
  205. throw new EOFException();
  206. }
  207. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  208. return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
  209. } else {
  210. return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0));
  211. }
  212. }
  213. public long readUnsignedInt() throws IOException {
  214. return ((long)readInt()) & 0xffffffffL;
  215. }
  216. public long readLong() throws IOException {
  217. int i1 = readInt();
  218. int i2 = readInt();
  219. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  220. return ((long)i1 << 32) + (i2 & 0xFFFFFFFFL);
  221. } else {
  222. return ((long)i2 << 32) + (i1 & 0xFFFFFFFFL);
  223. }
  224. }
  225. public float readFloat() throws IOException {
  226. return Float.intBitsToFloat(readInt());
  227. }
  228. public double readDouble() throws IOException {
  229. return Double.longBitsToDouble(readLong());
  230. }
  231. public String readLine() throws IOException {
  232. StringBuffer input = new StringBuffer();
  233. int c = -1;
  234. boolean eol = false;
  235. while (!eol) {
  236. switch (c = read()) {
  237. case -1:
  238. case '\n':
  239. eol = true;
  240. break;
  241. case '\r':
  242. eol = true;
  243. long cur = getStreamPosition();
  244. if ((read()) != '\n') {
  245. seek(cur);
  246. }
  247. break;
  248. default:
  249. input.append((char)c);
  250. break;
  251. }
  252. }
  253. if ((c == -1) && (input.length() == 0)) {
  254. return null;
  255. }
  256. return input.toString();
  257. }
  258. public String readUTF() throws IOException {
  259. this.bitOffset = 0;
  260. // Fix 4494369: method ImageInputStreamImpl.readUTF()
  261. // does not work as specified (it should always assume
  262. // network byte order).
  263. ByteOrder oldByteOrder = getByteOrder();
  264. setByteOrder(ByteOrder.BIG_ENDIAN);
  265. String ret;
  266. try {
  267. ret = DataInputStream.readUTF(this);
  268. } catch (IOException e) {
  269. // Restore the old byte order even if an exception occurs
  270. setByteOrder(oldByteOrder);
  271. throw e;
  272. }
  273. setByteOrder(oldByteOrder);
  274. return ret;
  275. }
  276. public void readFully(byte[] b, int off, int len) throws IOException {
  277. // Fix 4430357 - if off + len < 0, overflow occurred
  278. if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
  279. throw new IndexOutOfBoundsException
  280. ("off < 0 || len < 0 || off + len > b.length!");
  281. }
  282. while (len > 0) {
  283. int nbytes = read(b, off, len);
  284. if (nbytes == -1) {
  285. throw new EOFException();
  286. }
  287. off += nbytes;
  288. len -= nbytes;
  289. }
  290. }
  291. public void readFully(byte[] b) throws IOException {
  292. readFully(b, 0, b.length);
  293. }
  294. public void readFully(short[] s, int off, int len) throws IOException {
  295. // Fix 4430357 - if off + len < 0, overflow occurred
  296. if (off < 0 || len < 0 || off + len > s.length || off + len < 0) {
  297. throw new IndexOutOfBoundsException
  298. ("off < 0 || len < 0 || off + len > s.length!");
  299. }
  300. while (len > 0) {
  301. int nelts = Math.min(len, byteBuf.length2);
  302. readFully(byteBuf, 0, nelts*2);
  303. toShorts(byteBuf, s, off, nelts);
  304. off += nelts;
  305. len -= nelts;
  306. }
  307. }
  308. public void readFully(char[] c, int off, int len) throws IOException {
  309. // Fix 4430357 - if off + len < 0, overflow occurred
  310. if (off < 0 || len < 0 || off + len > c.length || off + len < 0) {
  311. throw new IndexOutOfBoundsException
  312. ("off < 0 || len < 0 || off + len > c.length!");
  313. }
  314. while (len > 0) {
  315. int nelts = Math.min(len, byteBuf.length2);
  316. readFully(byteBuf, 0, nelts*2);
  317. toChars(byteBuf, c, off, nelts);
  318. off += nelts;
  319. len -= nelts;
  320. }
  321. }
  322. public void readFully(int[] i, int off, int len) throws IOException {
  323. // Fix 4430357 - if off + len < 0, overflow occurred
  324. if (off < 0 || len < 0 || off + len > i.length || off + len < 0) {
  325. throw new IndexOutOfBoundsException
  326. ("off < 0 || len < 0 || off + len > i.length!");
  327. }
  328. while (len > 0) {
  329. int nelts = Math.min(len, byteBuf.length4);
  330. readFully(byteBuf, 0, nelts*4);
  331. toInts(byteBuf, i, off, nelts);
  332. off += nelts;
  333. len -= nelts;
  334. }
  335. }
  336. public void readFully(long[] l, int off, int len) throws IOException {
  337. // Fix 4430357 - if off + len < 0, overflow occurred
  338. if (off < 0 || len < 0 || off + len > l.length || off + len < 0) {
  339. throw new IndexOutOfBoundsException
  340. ("off < 0 || len < 0 || off + len > l.length!");
  341. }
  342. while (len > 0) {
  343. int nelts = Math.min(len, byteBuf.length8);
  344. readFully(byteBuf, 0, nelts*8);
  345. toLongs(byteBuf, l, off, nelts);
  346. off += nelts;
  347. len -= nelts;
  348. }
  349. }
  350. public void readFully(float[] f, int off, int len) throws IOException {
  351. // Fix 4430357 - if off + len < 0, overflow occurred
  352. if (off < 0 || len < 0 || off + len > f.length || off + len < 0) {
  353. throw new IndexOutOfBoundsException
  354. ("off < 0 || len < 0 || off + len > f.length!");
  355. }
  356. while (len > 0) {
  357. int nelts = Math.min(len, byteBuf.length4);
  358. readFully(byteBuf, 0, nelts*4);
  359. toFloats(byteBuf, f, off, nelts);
  360. off += nelts;
  361. len -= nelts;
  362. }
  363. }
  364. public void readFully(double[] d, int off, int len) throws IOException {
  365. // Fix 4430357 - if off + len < 0, overflow occurred
  366. if (off < 0 || len < 0 || off + len > d.length || off + len < 0) {
  367. throw new IndexOutOfBoundsException
  368. ("off < 0 || len < 0 || off + len > d.length!");
  369. }
  370. while (len > 0) {
  371. int nelts = Math.min(len, byteBuf.length8);
  372. readFully(byteBuf, 0, nelts*8);
  373. toDoubles(byteBuf, d, off, nelts);
  374. off += nelts;
  375. len -= nelts;
  376. }
  377. }
  378. private void toShorts(byte[] b, short[] s, int off, int len) {
  379. int boff = 0;
  380. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  381. for (int j = 0; j < len; j++) {
  382. int b0 = b[boff];
  383. int b1 = b[boff + 1] & 0xff;
  384. s[off + j] = (short)((b0 << 8) | b1);
  385. boff += 2;
  386. }
  387. } else {
  388. for (int j = 0; j < len; j++) {
  389. int b0 = b[boff + 1];
  390. int b1 = b[boff] & 0xff;
  391. s[off + j] = (short)((b0 << 8) | b1);
  392. boff += 2;
  393. }
  394. }
  395. }
  396. private void toChars(byte[] b, char[] c, int off, int len) {
  397. int boff = 0;
  398. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  399. for (int j = 0; j < len; j++) {
  400. int b0 = b[boff];
  401. int b1 = b[boff + 1] & 0xff;
  402. c[off + j] = (char)((b0 << 8) | b1);
  403. boff += 2;
  404. }
  405. } else {
  406. for (int j = 0; j < len; j++) {
  407. int b0 = b[boff + 1];
  408. int b1 = b[boff] & 0xff;
  409. c[off + j] = (char)((b0 << 8) | b1);
  410. boff += 2;
  411. }
  412. }
  413. }
  414. private void toInts(byte[] b, int[] i, int off, int len) {
  415. int boff = 0;
  416. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  417. for (int j = 0; j < len; j++) {
  418. int b0 = b[boff];
  419. int b1 = b[boff + 1] & 0xff;
  420. int b2 = b[boff + 2] & 0xff;
  421. int b3 = b[boff + 3] & 0xff;
  422. i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
  423. boff += 4;
  424. }
  425. } else {
  426. for (int j = 0; j < len; j++) {
  427. int b0 = b[boff + 3];
  428. int b1 = b[boff + 2] & 0xff;
  429. int b2 = b[boff + 1] & 0xff;
  430. int b3 = b[boff] & 0xff;
  431. i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
  432. boff += 4;
  433. }
  434. }
  435. }
  436. private void toLongs(byte[] b, long[] l, int off, int len) {
  437. int boff = 0;
  438. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  439. for (int j = 0; j < len; j++) {
  440. int b0 = b[boff];
  441. int b1 = b[boff + 1] & 0xff;
  442. int b2 = b[boff + 2] & 0xff;
  443. int b3 = b[boff + 3] & 0xff;
  444. int b4 = b[boff + 4];
  445. int b5 = b[boff + 5] & 0xff;
  446. int b6 = b[boff + 6] & 0xff;
  447. int b7 = b[boff + 7] & 0xff;
  448. int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
  449. int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
  450. l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);
  451. boff += 8;
  452. }
  453. } else {
  454. for (int j = 0; j < len; j++) {
  455. int b0 = b[boff + 7];
  456. int b1 = b[boff + 6] & 0xff;
  457. int b2 = b[boff + 5] & 0xff;
  458. int b3 = b[boff + 4] & 0xff;
  459. int b4 = b[boff + 3];
  460. int b5 = b[boff + 2] & 0xff;
  461. int b6 = b[boff + 1] & 0xff;
  462. int b7 = b[boff] & 0xff;
  463. int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
  464. int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
  465. l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);
  466. boff += 8;
  467. }
  468. }
  469. }
  470. private void toFloats(byte[] b, float[] f, int off, int len) {
  471. int boff = 0;
  472. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  473. for (int j = 0; j < len; j++) {
  474. int b0 = b[boff];
  475. int b1 = b[boff + 1] & 0xff;
  476. int b2 = b[boff + 2] & 0xff;
  477. int b3 = b[boff + 3] & 0xff;
  478. int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
  479. f[off + j] = Float.intBitsToFloat(i);
  480. boff += 4;
  481. }
  482. } else {
  483. for (int j = 0; j < len; j++) {
  484. int b0 = b[boff + 3];
  485. int b1 = b[boff + 2] & 0xff;
  486. int b2 = b[boff + 1] & 0xff;
  487. int b3 = b[boff + 0] & 0xff;
  488. int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
  489. f[off + j] = Float.intBitsToFloat(i);
  490. boff += 4;
  491. }
  492. }
  493. }
  494. private void toDoubles(byte[] b, double[] d, int off, int len) {
  495. int boff = 0;
  496. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  497. for (int j = 0; j < len; j++) {
  498. int b0 = b[boff];
  499. int b1 = b[boff + 1] & 0xff;
  500. int b2 = b[boff + 2] & 0xff;
  501. int b3 = b[boff + 3] & 0xff;
  502. int b4 = b[boff + 4];
  503. int b5 = b[boff + 5] & 0xff;
  504. int b6 = b[boff + 6] & 0xff;
  505. int b7 = b[boff + 7] & 0xff;
  506. int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
  507. int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
  508. long l = ((long)i0 << 32) | (i1 & 0xffffffffL);
  509. d[off + j] = Double.longBitsToDouble(l);
  510. boff += 8;
  511. }
  512. } else {
  513. for (int j = 0; j < len; j++) {
  514. int b0 = b[boff + 7];
  515. int b1 = b[boff + 6] & 0xff;
  516. int b2 = b[boff + 5] & 0xff;
  517. int b3 = b[boff + 4] & 0xff;
  518. int b4 = b[boff + 3];
  519. int b5 = b[boff + 2] & 0xff;
  520. int b6 = b[boff + 1] & 0xff;
  521. int b7 = b[boff] & 0xff;
  522. int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
  523. int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
  524. long l = ((long)i0 << 32) | (i1 & 0xffffffffL);
  525. d[off + j] = Double.longBitsToDouble(l);
  526. boff += 8;
  527. }
  528. }
  529. }
  530. public long getStreamPosition() throws IOException {
  531. checkClosed();
  532. return streamPos;
  533. }
  534. public int getBitOffset() throws IOException {
  535. checkClosed();
  536. return bitOffset;
  537. }
  538. public void setBitOffset(int bitOffset) throws IOException {
  539. checkClosed();
  540. if (bitOffset < 0 || bitOffset > 7) {
  541. throw new IllegalArgumentException("bitOffset must be betwwen 0 and 7!");
  542. }
  543. this.bitOffset = bitOffset;
  544. }
  545. public int readBit() throws IOException {
  546. checkClosed();
  547. // Compute final bit offset before we call read() and seek()
  548. int newBitOffset = (this.bitOffset + 1) & 0x7;
  549. int val = read();
  550. if (val == -1) {
  551. throw new EOFException();
  552. }
  553. if (newBitOffset != 0) {
  554. // Move byte position back if in the middle of a byte
  555. seek(getStreamPosition() - 1);
  556. // Shift the bit to be read to the rightmost position
  557. val >>= 8 - newBitOffset;
  558. }
  559. this.bitOffset = newBitOffset;
  560. return val & 0x1;
  561. }
  562. public long readBits(int numBits) throws IOException {
  563. checkClosed();
  564. if (numBits < 0 || numBits > 64) {
  565. throw new IllegalArgumentException();
  566. }
  567. if (numBits == 0) {
  568. return 0L;
  569. }
  570. // Have to read additional bits on the left equal to the bit offset
  571. int bitsToRead = numBits + bitOffset;
  572. // Compute final bit offset before we call read() and seek()
  573. int newBitOffset = (this.bitOffset + numBits) & 0x7;
  574. // Read a byte at a time, accumulate
  575. long accum = 0L;
  576. while (bitsToRead > 0) {
  577. int val = read();
  578. if (val == -1) {
  579. throw new EOFException();
  580. }
  581. accum <<= 8;
  582. accum |= val;
  583. bitsToRead -= 8;
  584. }
  585. // Move byte position back if in the middle of a byte
  586. if (newBitOffset != 0) {
  587. seek(getStreamPosition() - 1);
  588. }
  589. this.bitOffset = newBitOffset;
  590. // Shift away unwanted bits on the right.
  591. accum >>>= (-bitsToRead); // Negative of bitsToRead == extra bits read
  592. // Mask out unwanted bits on the left
  593. accum &= (-1L >>> (64 - numBits));
  594. return accum;
  595. }
  596. /**
  597. * Returns <code>-1L</code> to indicate that the stream has unknown
  598. * length. Subclasses must override this method to provide actual
  599. * length information.
  600. *
  601. * @return -1L to indicate unknown length.
  602. */
  603. public long length() {
  604. return -1L;
  605. }
  606. /**
  607. * Advances the current stream position by calling
  608. * <code>seek(getStreamPosition() + n)</code>.
  609. *
  610. * <p> The bit offset is reset to zero.
  611. *
  612. * @param n the number of bytes to seek forward.
  613. *
  614. * @return an <code>int</code> representing the number of bytes
  615. * skipped.
  616. *
  617. * @exception IOException if <code>getStreamPosition</code>
  618. * throws an <code>IOException</code> when computing either
  619. * the starting or ending position.
  620. */
  621. public int skipBytes(int n) throws IOException {
  622. long pos = getStreamPosition();
  623. seek(pos + n);
  624. return (int)(getStreamPosition() - pos);
  625. }
  626. /**
  627. * Advances the current stream position by calling
  628. * <code>seek(getStreamPosition() + n)</code>.
  629. *
  630. * <p> The bit offset is reset to zero.
  631. *
  632. * @param n the number of bytes to seek forward.
  633. *
  634. * @return a <code>long</code> representing the number of bytes
  635. * skipped.
  636. *
  637. * @exception IOException if <code>getStreamPosition</code>
  638. * throws an <code>IOException</code> when computing either
  639. * the starting or ending position.
  640. */
  641. public long skipBytes(long n) throws IOException {
  642. long pos = getStreamPosition();
  643. seek(pos + n);
  644. return getStreamPosition() - pos;
  645. }
  646. public void seek(long pos) throws IOException {
  647. checkClosed();
  648. // This test also covers pos < 0
  649. if (pos < flushedPos) {
  650. throw new IndexOutOfBoundsException("pos < flushedPos!");
  651. }
  652. this.streamPos = pos;
  653. this.bitOffset = 0;
  654. }
  655. /**
  656. * Pushes the current stream position onto a stack of marked
  657. * positions.
  658. */
  659. public void mark() {
  660. try {
  661. markByteStack.push(new Long(getStreamPosition()));
  662. markBitStack.push(new Integer(getBitOffset()));
  663. } catch (IOException e) {
  664. }
  665. }
  666. /**
  667. * Resets the current stream byte and bit positions from the stack
  668. * of marked positions.
  669. *
  670. * <p> An <code>IOException</code> will be thrown if the previous
  671. * marked position lies in the discarded portion of the stream.
  672. *
  673. * @exception IOException if an I/O error occurs.
  674. */
  675. public void reset() throws IOException {
  676. if (markByteStack.empty()) {
  677. return;
  678. }
  679. long pos = ((Long)markByteStack.pop()).longValue();
  680. if (pos < flushedPos) {
  681. throw new IIOException
  682. ("Previous marked position has been discarded!");
  683. }
  684. seek(pos);
  685. int offset = ((Integer)markBitStack.pop()).intValue();
  686. setBitOffset(offset);
  687. }
  688. public void flushBefore(long pos) throws IOException {
  689. if (pos < flushedPos) {
  690. throw new IndexOutOfBoundsException("pos < flushedPos!");
  691. }
  692. if (pos > getStreamPosition()) {
  693. throw new IndexOutOfBoundsException("pos > getStreamPosition()!");
  694. }
  695. // Invariant: flushedPos >= 0
  696. flushedPos = pos;
  697. }
  698. public void flush() throws IOException {
  699. flushBefore(getStreamPosition());
  700. }
  701. public long getFlushedPosition() {
  702. return flushedPos;
  703. }
  704. /**
  705. * Default implementation returns false. Subclasses should
  706. * override this if they cache data.
  707. */
  708. public boolean isCached() {
  709. return false;
  710. }
  711. /**
  712. * Default implementation returns false. Subclasses should
  713. * override this if they cache data in main memory.
  714. */
  715. public boolean isCachedMemory() {
  716. return false;
  717. }
  718. /**
  719. * Default implementation returns false. Subclasses should
  720. * override this if they cache data in a temporary file.
  721. */
  722. public boolean isCachedFile() {
  723. return false;
  724. }
  725. public void close() throws IOException {
  726. checkClosed();
  727. isClosed = true;
  728. }
  729. /**
  730. * Finalizes this object prior to garbage collection. The
  731. * <code>close</code> method is called to close any open input
  732. * source. This method should not be called from application
  733. * code.
  734. *
  735. * @exception Throwable if an error occurs during superclass
  736. * finalization.
  737. */
  738. protected void finalize() throws Throwable {
  739. if (!isClosed) {
  740. try {
  741. close();
  742. } catch (IOException e) {
  743. }
  744. }
  745. super.finalize();
  746. }
  747. }