Commit 37317520 by cblay Committed by Oliver Woodman

Improving handling of atoms with size less than header in FragmentedMp4Extractor.

These currently lead to cryptic ArrayIndexOutOfBoundsExceptions being thrown from System.arraycopy() so my proposal is to throw a more useful ParserException instead.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=142087132
parent 86adc644
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.extractor.mp4; package com.google.android.exoplayer2.extractor.mp4;
import android.test.InstrumentationTestCase; import android.test.InstrumentationTestCase;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
...@@ -24,13 +25,21 @@ import com.google.android.exoplayer2.testutil.TestUtil; ...@@ -24,13 +25,21 @@ import com.google.android.exoplayer2.testutil.TestUtil;
*/ */
public final class FragmentedMp4ExtractorTest extends InstrumentationTestCase { public final class FragmentedMp4ExtractorTest extends InstrumentationTestCase {
private static final TestUtil.ExtractorFactory EXTRACTOR_FACTORY =
new TestUtil.ExtractorFactory() {
@Override
public Extractor create() {
return new FragmentedMp4Extractor();
}
};
public void testSample() throws Exception { public void testSample() throws Exception {
TestUtil.assertOutput(new TestUtil.ExtractorFactory() { TestUtil.assertOutput(EXTRACTOR_FACTORY, "mp4/sample_fragmented.mp4", getInstrumentation());
@Override }
public Extractor create() {
return new FragmentedMp4Extractor(); public void testAtomWithZeroSize() throws Exception {
} TestUtil.assertThrows(EXTRACTOR_FACTORY, "mp4/sample_fragmented_zero_size_atom.mp4",
}, "mp4/sample_fragmented.mp4", getInstrumentation()); getInstrumentation(), ParserException.class);
} }
} }
...@@ -257,6 +257,10 @@ public final class FragmentedMp4Extractor implements Extractor { ...@@ -257,6 +257,10 @@ public final class FragmentedMp4Extractor implements Extractor {
atomSize = atomHeader.readUnsignedLongToLong(); atomSize = atomHeader.readUnsignedLongToLong();
} }
if (atomSize < atomHeaderBytesRead) {
throw new ParserException("Atom size less than header length (unsupported).");
}
long atomPosition = input.getPosition() - atomHeaderBytesRead; long atomPosition = input.getPosition() - atomHeaderBytesRead;
if (atomType == Atom.TYPE_moof) { if (atomType == Atom.TYPE_moof) {
// The data positions may be updated when parsing the tfhd/trun. // The data positions may be updated when parsing the tfhd/trun.
......
...@@ -300,6 +300,81 @@ public class TestUtil { ...@@ -300,6 +300,81 @@ public class TestUtil {
return extractorOutput; return extractorOutput;
} }
/**
* Calls {@link #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean)} with all
* possible combinations of "simulate" parameters.
*
* @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor}
* class which is to be tested.
* @param sampleFile The path to the input sample.
* @param instrumentation To be used to load the sample file.
* @param expectedThrowable Expected {@link Throwable} class.
* @throws IOException If reading from the input fails.
* @throws InterruptedException If interrupted while reading from the input.
* @see #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean)
*/
public static void assertThrows(ExtractorFactory factory, String sampleFile,
Instrumentation instrumentation, Class<? extends Throwable> expectedThrowable)
throws IOException, InterruptedException {
byte[] fileData = getByteArray(instrumentation, sampleFile);
assertThrows(factory, fileData, expectedThrowable);
}
/**
* Calls {@link #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean)} with all
* possible combinations of "simulate" parameters.
*
* @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor}
* class which is to be tested.
* @param fileData Content of the input file.
* @param expectedThrowable Expected {@link Throwable} class.
* @throws IOException If reading from the input fails.
* @throws InterruptedException If interrupted while reading from the input.
* @see #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean)
*/
public static void assertThrows(ExtractorFactory factory, byte[] fileData,
Class<? extends Throwable> expectedThrowable) throws IOException, InterruptedException {
assertThrows(factory.create(), fileData, expectedThrowable, false, false, false);
assertThrows(factory.create(), fileData, expectedThrowable, true, false, false);
assertThrows(factory.create(), fileData, expectedThrowable, false, true, false);
assertThrows(factory.create(), fileData, expectedThrowable, true, true, false);
assertThrows(factory.create(), fileData, expectedThrowable, false, false, true);
assertThrows(factory.create(), fileData, expectedThrowable, true, false, true);
assertThrows(factory.create(), fileData, expectedThrowable, false, true, true);
assertThrows(factory.create(), fileData, expectedThrowable, true, true, true);
}
/**
* Asserts {@code extractor} throws {@code expectedThrowable} while consuming {@code sampleFile}.
*
* @param extractor The {@link Extractor} to be tested.
* @param fileData Content of the input file.
* @param expectedThrowable Expected {@link Throwable} class.
* @param simulateIOErrors If true simulates IOErrors.
* @param simulateUnknownLength If true simulates unknown input length.
* @param simulatePartialReads If true simulates partial reads.
* @throws IOException If reading from the input fails.
* @throws InterruptedException If interrupted while reading from the input.
*/
public static void assertThrows(Extractor extractor, byte[] fileData,
Class<? extends Throwable> expectedThrowable, boolean simulateIOErrors,
boolean simulateUnknownLength, boolean simulatePartialReads) throws IOException,
InterruptedException {
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(fileData)
.setSimulateIOErrors(simulateIOErrors)
.setSimulateUnknownLength(simulateUnknownLength)
.setSimulatePartialReads(simulatePartialReads).build();
try {
consumeTestData(extractor, input, 0, true);
throw new AssertionError(expectedThrowable.getSimpleName() + " expected but not thrown");
} catch (Throwable throwable) {
if (expectedThrowable.equals(throwable.getClass())) {
return; // Pass!
}
throw throwable;
}
}
public static void recursiveDelete(File fileOrDirectory) { public static void recursiveDelete(File fileOrDirectory) {
if (fileOrDirectory.isDirectory()) { if (fileOrDirectory.isDirectory()) {
for (File child : fileOrDirectory.listFiles()) { for (File child : fileOrDirectory.listFiles()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment