Add a peekFully overload with allowEndOfInput.

This is in preparation for removing BufferingInput,
and using peeking instead.

Also add tests for peeking with allowEndOfInput and
resetPeekPosition.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=111318236
This commit is contained in:
andrewlewis 2016-01-04 07:00:56 -08:00 committed by Oliver Woodman
parent 030f26fd2d
commit 890dd5afb5
3 changed files with 152 additions and 9 deletions

View File

@ -301,6 +301,76 @@ public class DefaultExtractorInputTest extends TestCase {
}
}
public void testResetPeekPosition() throws IOException, InterruptedException {
DefaultExtractorInput input = createDefaultExtractorInput();
byte[] target = new byte[TEST_DATA.length];
input.peekFully(target, 0, TEST_DATA.length);
// Check that we read the whole of TEST_DATA.
assertTrue(Arrays.equals(TEST_DATA, target));
assertEquals(0, input.getPosition());
// Check that we can peek again after resetting.
input.resetPeekPosition();
byte[] target2 = new byte[TEST_DATA.length];
input.peekFully(target2, 0, TEST_DATA.length);
assertTrue(Arrays.equals(TEST_DATA, target2));
// Check that we fail with EOFException if we peek past the end of the input.
try {
input.peekFully(target, 0, 1);
fail();
} catch (EOFException e) {
// Expected.
}
}
public void testPeekFullyAtEndOfStreamWithAllowEndOfInputSucceeds()
throws IOException, InterruptedException {
DefaultExtractorInput input = createDefaultExtractorInput();
byte[] target = new byte[TEST_DATA.length];
// Check peeking up to the end of input succeeds.
assertTrue(input.peekFully(target, 0, TEST_DATA.length, true));
// Check peeking at the end of input with allowEndOfInput signals the end of input.
assertFalse(input.peekFully(target, 0, 1, true));
}
public void testPeekFullyAcrossEndOfInputWithAllowEndOfInputFails()
throws IOException, InterruptedException {
DefaultExtractorInput input = createDefaultExtractorInput();
byte[] target = new byte[TEST_DATA.length];
// Check peeking before the end of input with allowEndOfInput succeeds.
assertTrue(input.peekFully(target, 0, TEST_DATA.length - 1, true));
// Check peeking across the end of input with allowEndOfInput throws.
try {
input.peekFully(target, 0, 2, true);
fail();
} catch (EOFException e) {
// Expected.
}
}
public void testResetAndPeekFullyPastEndOfStreamWithAllowEndOfInputFails()
throws IOException, InterruptedException {
DefaultExtractorInput input = createDefaultExtractorInput();
byte[] target = new byte[TEST_DATA.length];
// Check peeking up to the end of input succeeds.
assertTrue(input.peekFully(target, 0, TEST_DATA.length, true));
input.resetPeekPosition();
try {
// Check peeking one more byte throws.
input.peekFully(target, 0, TEST_DATA.length + 1, true);
fail();
} catch (EOFException e) {
// Expected.
}
}
private static FakeDataSource buildDataSource() throws IOException {
FakeDataSource.Builder builder = new FakeDataSource.Builder();
builder.appendReadData(Arrays.copyOfRange(TEST_DATA, 0, 3));

View File

@ -103,21 +103,42 @@ public final class DefaultExtractorInput implements ExtractorInput {
skipFully(length, false);
}
@Override
public boolean peekFully(byte[] target, int offset, int length, boolean allowEndOfInput)
throws IOException, InterruptedException {
if (!advancePeekPosition(length, allowEndOfInput)) {
return false;
}
System.arraycopy(peekBuffer, peekBufferPosition - length, target, offset, length);
return true;
}
@Override
public void peekFully(byte[] target, int offset, int length)
throws IOException, InterruptedException {
advancePeekPosition(length);
System.arraycopy(peekBuffer, peekBufferPosition - length, target, offset, length);
peekFully(target, offset, length, false);
}
@Override
public boolean advancePeekPosition(int length, boolean allowEndOfInput)
throws IOException, InterruptedException {
ensureSpaceForPeek(length);
int bytesPeeked = Math.min(peekBufferLength - peekBufferPosition, length);
peekBufferLength += length - bytesPeeked;
while (bytesPeeked < length) {
bytesPeeked = readFromDataSource(peekBuffer, peekBufferPosition, length, bytesPeeked,
allowEndOfInput);
if (bytesPeeked == C.RESULT_END_OF_INPUT) {
return false;
}
}
peekBufferPosition += length;
return true;
}
@Override
public void advancePeekPosition(int length) throws IOException, InterruptedException {
ensureSpaceForPeek(length);
peekBufferPosition += length;
while (peekBufferPosition > peekBufferLength) {
peekBufferLength = readFromDataSource(peekBuffer, 0, peekBufferPosition, peekBufferLength,
false);
}
advancePeekPosition(length, false);
}
@Override

View File

@ -123,8 +123,38 @@ public interface ExtractorInput {
* Peeks {@code length} bytes from the peek position, writing them into {@code target} at index
* {@code offset}. The current read position is left unchanged.
* <p>
* If the end of the input is found having peeked no data, then behavior is dependent on
* {@code allowEndOfInput}. If {@code allowEndOfInput == true} then {@code false} is returned.
* Otherwise an {@link EOFException} is thrown.
* <p>
* Calling {@link #resetPeekPosition()} resets the peek position to equal the current read
* position, so the caller can peek the same data again. Reading also resets the peek position.
* position, so the caller can peek the same data again. Reading and skipping also reset the peek
* position.
*
* @param target A target array into which data should be written.
* @param offset The offset into the target array at which to write.
* @param length The number of bytes to peek from the input.
* @param allowEndOfInput True if encountering the end of the input having peeked no data is
* allowed, and should result in {@code false} being returned. False if it should be
* considered an error, causing an {@link EOFException} to be thrown.
* @return True if the peek was successful. False if the end of the input was encountered having
* peeked no data.
* @throws EOFException If the end of input was encountered having partially satisfied the peek
* (i.e. having peeked at least one byte, but fewer than {@code length}), or if no bytes were
* peeked and {@code allowEndOfInput} is false.
* @throws IOException If an error occurs peeking from the input.
* @throws InterruptedException If the thread is interrupted.
*/
boolean peekFully(byte[] target, int offset, int length, boolean allowEndOfInput)
throws IOException, InterruptedException;
/**
* Peeks {@code length} bytes from the peek position, writing them into {@code target} at index
* {@code offset}. The current read position is left unchanged.
* <p>
* Calling {@link #resetPeekPosition()} resets the peek position to equal the current read
* position, so the caller can peek the same data again. Reading and skipping also reset the peek
* position.
*
* @param target A target array into which data should be written.
* @param offset The offset into the target array at which to write.
@ -135,6 +165,28 @@ public interface ExtractorInput {
*/
void peekFully(byte[] target, int offset, int length) throws IOException, InterruptedException;
/**
* Advances the peek position by {@code length} bytes.
* <p>
* If the end of the input is encountered before advancing the peek position, then behavior is
* dependent on {@code allowEndOfInput}. If {@code allowEndOfInput == true} then {@code false} is
* returned. Otherwise an {@link EOFException} is thrown.
*
* @param length The number of bytes by which to advance the peek position.
* @param allowEndOfInput True if encountering the end of the input before advancing is allowed,
* and should result in {@code false} being returned. False if it should be considered an
* error, causing an {@link EOFException} to be thrown.
* @return True if advancing the peek position was successful. False if the end of the input was
* encountered before the peek position could be advanced.
* @throws EOFException If the end of input was encountered having partially advanced (i.e. having
* advanced by at least one byte, but fewer than {@code length}), or if the end of input was
* encountered before advancing and {@code allowEndOfInput} is false.
* @throws IOException If an error occurs advancing the peek position.
* @throws InterruptedException If the thread is interrupted.
*/
boolean advancePeekPosition(int length, boolean allowEndOfInput)
throws IOException, InterruptedException;
/**
* Advances the peek position by {@code length} bytes.
*