/** * Finalizes this object prior to garbage collection. The * {@code close} method is called to close any open input * source. This method should not be called from application * code. * * @exception Throwable if an error occurs during superclass * finalization. */ @Override protected void finalize() throws Throwable { if (!closed) { try { close(); } catch (IOException ignore) { // Ignroe } } super.finalize(); } }
@Test public void testMarkFlushReset() throws Exception { SeekableInputStream seekable = makeInputStream(77); seekable.mark(); int position = 55; seekable.seek(position); seekable.flushBefore(position); try { seekable.reset(); fail("Reset before flushed position succeeded"); } catch (IOException e) { // Ignore } assertEquals(position, seekable.getStreamPosition()); }
public long getFlushedPosition() throws IOException { return seekable.getFlushedPosition(); }
public final void seek(long pPosition) throws IOException { checkOpen(); // NOTE: This is correct according to javax.imageio (IndexOutOfBoundsException), // but it's kind of inconsistent with reset that throws IOException... if (pPosition < flushedPosition) { throw new IndexOutOfBoundsException("position < flushedPosition"); } seekImpl(pPosition); position = pPosition; }
@Override public final void mark(int pLimit) { mark(); // TODO: We don't really need to do this.. Is it a good idea? try { flushBefore(Math.max(position - pLimit, flushedPosition)); } catch (IOException ignore) { // Ignore, as it's not really critical } }
@Test public void testSeekFlush() throws Exception { SeekableInputStream seekable = makeInputStream(133); int pos = 45; seekable.seek(pos); seekable.flushBefore(pos); long flushedPos = seekable.getFlushedPosition(); assertEquals("Flushed positon should match position", pos, flushedPos); try { seekable.seek(pos - 1); fail("Read before flushed position succeeded"); } catch (IndexOutOfBoundsException e) { // Ignore } }
@Test public void testReadAllByteValuesRegression() throws IOException { final int size = 128; // Fill bytes byte[] bytes = new byte[256]; for (int i = 0; i < bytes.length; i++) { bytes[i] = (byte) i; } // Create wrapper stream SeekableInputStream stream = makeInputStream(bytes); // Fill buffer byte[] buffer = new byte[size]; while (stream.read(buffer) >= 0) { } stream.seek(0); for (int i = 0; i < bytes.length; i += 2) { assertEquals("Wrong stream position", i, stream.getStreamPosition()); int count = stream.read(buffer, 0, 2); assertEquals(2, count); assertEquals(String.format("Wrong value read at pos %d", stream.getStreamPosition()), bytes[i], buffer[0]); assertEquals(String.format("Wrong value read at pos %d", stream.getStreamPosition()), bytes[i + 1], buffer[1]); } stream.seek(0); for (int i = 0; i < bytes.length; i++) { assertEquals("Wrong stream position", i, stream.getStreamPosition()); int actual = stream.read(); assertEquals(String.format("Wrong value read at pos %d", stream.getStreamPosition()), bytes[i] & 0xff, actual); assertEquals(String.format("Wrong value read at pos %d", stream.getStreamPosition()), bytes[i], (byte) actual); } }
@Test public void testSeekSkipRead() throws Exception { SeekableInputStream seekable = makeInputStream(133); int pos = 45; for (int i = 0; i < 10; i++) { seekable.seek(pos); //noinspection ResultOfMethodCallIgnored seekable.skip(i); byte[] bytes = FileUtil.read(seekable); assertEquals(133, seekable.getStreamPosition()); assertEquals(133 - 45- i, bytes.length); } }
public final void flushBefore(long pPosition) throws IOException { if (pPosition < flushedPosition) { throw new IndexOutOfBoundsException("position < flushedPosition"); } if (pPosition > getStreamPosition()) { throw new IndexOutOfBoundsException("position > stream position"); } checkOpen(); flushBeforeImpl(pPosition); flushedPosition = pPosition; }
@Test public void testSeek() throws Exception { SeekableInputStream seekable = makeInputStream(55); int pos = 37; seekable.seek(pos); long streamPos = seekable.getStreamPosition(); assertEquals("Stream positon should match seeked position", pos, streamPos); }
@Test public void testCloseUnderlyingStream() throws IOException { final boolean[] closed = new boolean[1]; ByteArrayInputStream input = new ByteArrayInputStream(makeRandomArray(256)) { @Override public void close() throws IOException { closed[0] = true; super.close(); } }; SeekableInputStream stream = makeInputStream(input); try { FileUtil.read(stream); // Read until EOF assertEquals("EOF not reached (test case broken)", -1, stream.read()); assertFalse("Underlying stream closed before close", closed[0]); } finally { stream.close(); } assertTrue("Underlying stream not closed", closed[0]); }
@Test public void testReadResetReadDirectBufferBug() throws IOException { // Make sure we use the exact size of the buffer final int size = 1024; // Fill bytes byte[] bytes = new byte[size * 2]; sRandom.nextBytes(bytes); // Create wrapper stream SeekableInputStream stream = makeInputStream(bytes); // Read to fill the buffer, then reset int val; val = stream.read(); assertFalse("Unexepected EOF", val == -1); val = stream.read(); assertFalse("Unexepected EOF", val == -1); val = stream.read(); assertFalse("Unexepected EOF", val == -1); val = stream.read(); assertFalse("Unexepected EOF", val == -1); stream.seek(0); // Read fully and compare byte[] result = new byte[size]; readFully(stream, result); assertTrue(rangeEquals(bytes, 0, result, 0, size)); readFully(stream, result); assertTrue(rangeEquals(bytes, size, result, 0, size)); }
public void flushBefore(final long pPosition) throws IOException { seekable.flushBefore(pPosition); }
@Override public final void reset() throws IOException { checkOpen(); if (!markedPositions.isEmpty()) { long newPos = markedPositions.pop(); // NOTE: This is correct according to javax.imageio (IOException), // but it's kind of inconsistent with seek that throws IndexOutOfBoundsException... if (newPos < flushedPosition) { throw new IOException("Previous marked position has been discarded"); } seek(newPos); } else { // TODO: To iron out some wrinkles due to conflicting contracts // (InputStream and Seekable both declare reset), // we might need to reset to the last marked position instead.. // However, that becomes REALLY confusing if that position is after // the current position... seek(0); } }
protected void testSeekSkip(SeekableInputStream pSeekable, String pStr) throws IOException { System.out.println(); pSeekable.seek(pStr.length()); FileUtil.read(pSeekable); for (int i = 0; i < 10; i++) { byte[] bytes = FileUtil.read(pSeekable); int len = bytes.length; if (len != 0) { System.err.println("Error in buffer length after full read..."); System.err.println("len: " + len); System.err.println("bytes: \"" + new String(bytes) + "\""); break; } } System.out.println(); for (int i = 0; i < 10; i++) { pSeekable.seek(0); int skip = i * 3; //noinspection ResultOfMethodCallIgnored pSeekable.skip(skip); String str = new String(FileUtil.read(pSeekable)); System.out.println(str); if (str.length() != pStr.length() - skip) { throw new Error("Error in buffer length after skip"); } } System.out.println(); System.out.println("seek/skip ok!"); System.out.println(); }
/** * Implemented using {@code seek(currentPos + pLength)}. * * @param pLength the number of bytes to skip * @return the actual number of bytes skipped (may be equal to or less * than {@code pLength}) * * @throws IOException if an I/O exception occurs during skip */ @Override public final long skip(long pLength) throws IOException { long pos = mPosition; if (pos + pLength < mFlushedPosition) { throw new IOException("position < flushedPosition"); } // Stop at stream length for compatibility, even though it's allowed // to seek past end of stream seek(Math.min(pos + pLength, pos + available())); return mPosition - pos; }
@Override public void reset() throws IOException { seekable.reset(); }