Move inflate method to Util class

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=207857927
This commit is contained in:
eguven 2018-08-08 02:58:32 -07:00 committed by Oliver Woodman
parent a3c08465eb
commit eda408dc09
3 changed files with 79 additions and 32 deletions

View File

@ -25,7 +25,6 @@ import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
/** A {@link SimpleSubtitleDecoder} for PGS subtitles. */
@ -39,25 +38,22 @@ public final class PgsDecoder extends SimpleSubtitleDecoder {
private static final byte INFLATE_HEADER = 0x78;
private final ParsableByteArray buffer;
private final ParsableByteArray inflatedBuffer;
private final CueBuilder cueBuilder;
private Inflater inflater;
private byte[] inflatedData;
private int inflatedDataSize;
public PgsDecoder() {
super("PgsDecoder");
buffer = new ParsableByteArray();
inflatedBuffer = new ParsableByteArray();
cueBuilder = new CueBuilder();
}
@Override
protected Subtitle decode(byte[] data, int size, boolean reset) throws SubtitleDecoderException {
if (maybeInflateData(data, size)) {
buffer.reset(inflatedData, inflatedDataSize);
} else {
buffer.reset(data, size);
}
maybeInflateData(buffer);
cueBuilder.reset();
ArrayList<Cue> cues = new ArrayList<>();
while (buffer.bytesLeft() >= 3) {
@ -69,31 +65,14 @@ public final class PgsDecoder extends SimpleSubtitleDecoder {
return new PgsSubtitle(Collections.unmodifiableList(cues));
}
private boolean maybeInflateData(byte[] data, int size) {
if (size == 0 || data[0] != INFLATE_HEADER) {
return false;
}
private void maybeInflateData(ParsableByteArray buffer) {
if (buffer.bytesLeft() > 0 && buffer.peekUnsignedByte() == INFLATE_HEADER) {
if (inflater == null) {
inflater = new Inflater();
inflatedData = new byte[size];
}
inflatedDataSize = 0;
inflater.setInput(data, 0, size);
try {
while (!inflater.finished() && !inflater.needsDictionary() && !inflater.needsInput()) {
if (inflatedDataSize == inflatedData.length) {
inflatedData = Arrays.copyOf(inflatedData, inflatedData.length * 2);
}
inflatedDataSize +=
inflater.inflate(
inflatedData, inflatedDataSize, inflatedData.length - inflatedDataSize);
}
return inflater.finished();
} catch (DataFormatException e) {
// Assume data is not compressed.
return false;
} finally {
inflater.reset();
if (Util.inflate(buffer, inflatedBuffer, inflater)) {
buffer.reset(inflatedBuffer.data, inflatedBuffer.limit());
} // else assume data is not compressed.
}
}

View File

@ -69,6 +69,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
import org.checkerframework.checker.nullness.qual.PolyNull;
@ -1639,6 +1641,53 @@ public final class Util {
return toUpperInvariant(Locale.getDefault().getCountry());
}
/**
* Uncompresses the data in {@code input}.
*
* @param input Wraps the compressed input data.
* @param output Wraps an output buffer to be used to store the uncompressed data. If {@code
* output.data} is null or it isn't big enough to hold the uncompressed data, a new array is
* created. If {@code true} is returned then the output's position will be set to 0 and its
* length will be set to the length of the uncompressed data.
* @param inflater If not null, used to uncompressed the input. Otherwise a new {@link Inflater}
* is created.
* @return Whether the input is uncompressed successfully.
*/
public static boolean inflate(
ParsableByteArray input, ParsableByteArray output, @Nullable Inflater inflater) {
if (input.bytesLeft() <= 0) {
return false;
}
byte[] outputData = output.data;
if (outputData == null) {
outputData = new byte[input.bytesLeft()];
}
if (inflater == null) {
inflater = new Inflater();
}
inflater.setInput(input.data, input.getPosition(), input.bytesLeft());
try {
int outputSize = 0;
while (true) {
outputSize += inflater.inflate(outputData, outputSize, outputData.length - outputSize);
if (inflater.finished()) {
output.reset(outputData, outputSize);
return true;
}
if (inflater.needsDictionary() || inflater.needsInput()) {
return false;
}
if (outputSize == outputData.length) {
outputData = Arrays.copyOf(outputData, outputData.length * 2);
}
}
} catch (DataFormatException e) {
return false;
} finally {
inflater.reset();
}
}
/**
* Gets the physical size of the default display, in pixels.
*

View File

@ -27,8 +27,10 @@ import static com.google.common.truth.Truth.assertThat;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.testutil.TestUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.zip.Deflater;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@ -247,6 +249,23 @@ public class UtilTest {
}
}
@Test
public void testInflate() {
byte[] testData = TestUtil.buildTestData(/*arbitrary test data size*/ 256 * 1024);
byte[] compressedData = new byte[testData.length * 2];
Deflater compresser = new Deflater(9);
compresser.setInput(testData);
compresser.finish();
int compressedDataLength = compresser.deflate(compressedData);
compresser.end();
ParsableByteArray input = new ParsableByteArray(compressedData, compressedDataLength);
ParsableByteArray output = new ParsableByteArray();
assertThat(Util.inflate(input, output, /* inflater= */ null)).isTrue();
assertThat(output.limit()).isEqualTo(testData.length);
assertThat(Arrays.copyOf(output.data, output.limit())).isEqualTo(testData);
}
private static void assertEscapeUnescapeFileName(String fileName, String escapedFileName) {
assertThat(escapeFileName(fileName)).isEqualTo(escapedFileName);
assertThat(unescapeFileName(escapedFileName)).isEqualTo(fileName);