diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/Samples.java b/demo/src/main/java/com/google/android/exoplayer/demo/Samples.java index 9f58528895..9be0c43b76 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/Samples.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/Samples.java @@ -242,6 +242,8 @@ import java.util.Locale; + "&key=ik0", Util.TYPE_OTHER), new Sample("Google Play (MP3 Audio)", "http://storage.googleapis.com/exoplayer-test-media-0/play.mp3", Util.TYPE_OTHER), + new Sample("Google Play (Ogg/Vorbis Audio)", + "https://storage.googleapis.com/exoplayer-test-media-1/ogg/play.ogg", Util.TYPE_OTHER), new Sample("Google Glass (WebM Video with Vorbis Audio)", "http://demos.webmproject.org/exoplayer/glass_vp9_vorbis.webm", Util.TYPE_OTHER), new Sample("Big Buck Bunny (FLV Video)", diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggReaderTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggReaderTest.java new file mode 100644 index 0000000000..12e604d99b --- /dev/null +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggReaderTest.java @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer.extractor.ogg; + +import com.google.android.exoplayer.util.ParsableByteArray; + +import android.util.Log; + +import junit.framework.TestCase; + +import java.io.IOException; + +/** + * Unit test for {@link OggReader} + */ +public final class OggReaderTest extends TestCase { + + private static final String TAG = "OggReaderTest"; + + private OggReader oggReader; + private RecordableOggExtractorInput extractorInput; + + @Override + public void setUp() throws Exception { + super.setUp(); + extractorInput = new RecordableOggExtractorInput(1024 * 64); + // we want the mocked ExtractorInput to throw errors often + extractorInput.doThrowExceptionsAtPeek(true); + extractorInput.doThrowExceptionsAtRead(true); + // create reader + oggReader = new OggReader(); + oggReader.reset(); + } + + public void testReadPacketUntilEOFIncludingAnEmptyPage() throws Exception { + // record first page with a single packet + extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x01); + extractorInput.recordOggLaces(new byte[]{0x08}); + extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(8)); + // record intermediate page with two packets + extractorInput.recordOggHeader((byte) 0x00, 16, (byte) 0x02); + extractorInput.recordOggLaces(new byte[]{(byte) 0xFF, 0x11}); + extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(255 + 17)); + // empty page + extractorInput.recordOggHeader((byte) 0x00, 16, (byte) 0x00); + // record last page with two packets (256 and 271 bytes) + extractorInput.recordOggHeader((byte) 0x04, 128, (byte) 0x04); + extractorInput.recordOggLaces(new byte[]{(byte) 0xFF, 0x01, (byte) 0xff, 0x10}); + extractorInput.recordOggPacket(RecordableExtractorInput + .getBytesGrowingValues(255 + 1 + 255 + 16)); + + + // read first packet + final ParsableByteArray packetArray = new ParsableByteArray(new byte[255 * 255], 0); + readPacketUntilSuccess(packetArray); + // verify + assertEquals(8, packetArray.limit()); + assertTrue((oggReader.getPageHeader().type & 0x02) == 0x02); + assertFalse((oggReader.getPageHeader().type & 0x04) == 0x04); + assertEquals(0x02, oggReader.getPageHeader().type); + assertEquals(27 + 1, oggReader.getPageHeader().headerSize); + assertEquals(8, oggReader.getPageHeader().bodySize); + assertEquals(RecordableExtractorInput.STREAM_REVISION, oggReader.getPageHeader().revision); + assertEquals(1, oggReader.getPageHeader().pageSegmentCount); + assertEquals(1000, oggReader.getPageHeader().pageSequenceNumber); + assertEquals(4096, oggReader.getPageHeader().streamSerialNumber); + assertEquals(0, oggReader.getPageHeader().granulePosition); + for (int i = 0; i < 8; i++) { + assertEquals(i, packetArray.readUnsignedByte()); + } + + packetArray.reset(); + // read second packet + readPacketUntilSuccess(packetArray); + // verify + assertEquals(255 + 17, packetArray.limit()); + assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02); + assertFalse((oggReader.getPageHeader().type & 0x04) == 0x04); + assertEquals(0, oggReader.getPageHeader().type); + assertEquals(27 + 2, oggReader.getPageHeader().headerSize); + assertEquals(255 + 17, oggReader.getPageHeader().bodySize); + assertEquals(2, oggReader.getPageHeader().pageSegmentCount); + assertEquals(1001, oggReader.getPageHeader().pageSequenceNumber); + assertEquals(16, oggReader.getPageHeader().granulePosition); + + packetArray.reset(); + // read next packet and skip empty page + readPacketUntilSuccess(packetArray); + // verify + assertEquals(255 + 1, packetArray.limit()); + assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02); + assertTrue((oggReader.getPageHeader().type & 0x04) == 0x04); + assertEquals(4, oggReader.getPageHeader().type); + assertEquals(27 + 4, oggReader.getPageHeader().headerSize); + assertEquals(255 + 1 + 255 + 16, oggReader.getPageHeader().bodySize); + assertEquals(4, oggReader.getPageHeader().pageSegmentCount); + // page 1002 is empty, so current is 1003 + assertEquals(1003, oggReader.getPageHeader().pageSequenceNumber); + assertEquals(128, oggReader.getPageHeader().granulePosition); + + packetArray.reset(); + // read last packet + readPacketUntilSuccess(packetArray); + assertEquals(255 + 16, packetArray.limit()); + // EOF! + readEOFUntilSuccess(packetArray, 10); + } + + public void testReadPacketWithZeroSizeTerminator() throws Exception { + // record first page with a single packet + extractorInput.recordOggHeader((byte) 0x06, 0, (byte) 0x04); + extractorInput.recordOggLaces(new byte[]{(byte) 0xff, 0x00, 0x00, 0x08}); + extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(255 + 8)); + + ParsableByteArray packetArray = new ParsableByteArray(new byte[255 * 255], 0); + readPacketUntilSuccess(packetArray); + assertEquals(255, packetArray.limit()); + + packetArray.reset(); + readPacketUntilSuccess(packetArray); + assertEquals(8, packetArray.limit()); + + readEOFUntilSuccess(packetArray, 10); + } + + public void testReadContinuedPacket() throws Exception { + // record first page with a packet continuing on the second page + extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x02); + extractorInput.recordOggLaces(new byte[]{(byte) 0xFF, (byte) 0xFF}); + extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(510)); + // record the continuing page + extractorInput.recordOggHeader((byte) 0x05, 10, (byte) 0x01); + extractorInput.recordOggLaces(new byte[]{0x08}); + extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(8, (byte) 0x22)); + + // there is only one single packet across two pages + ParsableByteArray packetArray = new ParsableByteArray(new byte[255 * 255], 0); + readPacketUntilSuccess(packetArray); + + assertEquals(255 + 255 + 8, packetArray.limit()); + assertTrue((oggReader.getPageHeader().type & 0x04) == 0x04); + assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02); + // we must be on the second page already + assertEquals(1001, oggReader.getPageHeader().pageSequenceNumber); + + // verify packet data + for (int i = 0; i < 255; i++) { + assertEquals(i, packetArray.readUnsignedByte()); + } + assertEquals(255, packetArray.getPosition()); + for (int i = 0; i < 255; i++) { + assertEquals(i, packetArray.readUnsignedByte()); + } + assertEquals(510, packetArray.getPosition()); + for (int i = 0; i < 8; i++) { + assertEquals(i + 0x22, packetArray.readUnsignedByte()); + } + assertEquals(0, packetArray.bytesLeft()); + // EOF! + readEOFUntilSuccess(packetArray, 10); + } + + // no one does this with vorbis buts it's supported + public void testReadContinuedPacketOverMoreThan2Pages() throws Exception { + // record first page with a packet continuing on the second page + extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x02); + extractorInput.recordOggLaces(new byte[]{(byte) 0xFF, (byte) 0xFF}); + extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(510)); + // record the first continuing page + extractorInput.recordOggHeader((byte) 0x01, 10, (byte) 0x01); + extractorInput.recordOggLaces(new byte[]{(byte) 0xFF}); + extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(255)); + // record the second continuing page + extractorInput.recordOggHeader((byte) 0x01, 10, (byte) 0x01); + extractorInput.recordOggLaces(new byte[]{(byte) 0xFF}); + extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(255)); + // record the third continuing page + extractorInput.recordOggHeader((byte) 0x05, 10, (byte) 0x01); + extractorInput.recordOggLaces(new byte[]{(byte) 0x08}); + extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(8, (byte) 0x22)); + + // there is only one single packet across two pages + ParsableByteArray packetArray = new ParsableByteArray(new byte[255 * 255], 0); + readPacketUntilSuccess(packetArray); + + assertEquals(255 + 255 + 255 + 255 + 8, packetArray.limit()); + assertTrue((oggReader.getPageHeader().type & 0x04) == 0x04); + assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02); + // we must be on the fourth page already + assertEquals(1003, oggReader.getPageHeader().pageSequenceNumber); + + // verify packet data + for (int i = 0; i < 255; i++) { + assertEquals(i, packetArray.readUnsignedByte()); + } + assertEquals(255, packetArray.getPosition()); + for (int i = 0; i < 255; i++) { + assertEquals(i, packetArray.readUnsignedByte()); + } + assertEquals(510, packetArray.getPosition()); + for (int i = 0; i < 255; i++) { + assertEquals(i, packetArray.readUnsignedByte()); + } + assertEquals(765, packetArray.getPosition()); + for (int i = 0; i < 255; i++) { + assertEquals(i, packetArray.readUnsignedByte()); + } + assertEquals(1020, packetArray.getPosition()); + for (int i = 0; i < 8; i++) { + assertEquals(i + 0x22, packetArray.readUnsignedByte()); + } + assertEquals(0, packetArray.bytesLeft()); + // EOF! + readEOFUntilSuccess(packetArray, 10); + } + + public void testReadExceptionThrownWhilePeekingHeader() throws Exception { + // record first page with two packets packet + extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x02); + extractorInput.recordOggLaces(new byte[]{(byte) 0x01, (byte) 0x08}); + extractorInput.recordOggPacket(new byte[]{0x10}); + extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(8)); + + // record next page + extractorInput.recordOggHeader((byte) 0x05, 10, (byte) 0x01); + extractorInput.recordOggLaces(new byte[]{0x08}); + extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(8, (byte) 0x22)); + + ParsableByteArray packetArray = new ParsableByteArray(new byte[255 * 255], 0); + readPacketUntilSuccess(packetArray); + // verify packet data + assertEquals(1, packetArray.limit()); + assertEquals(0x10, packetArray.data[0]); + // verify header + assertTrue((oggReader.getPageHeader().type & 0x02) == 0x02); + assertFalse((oggReader.getPageHeader().type & 0x04) == 0x04); + assertEquals(27 + 2, oggReader.getPageHeader().headerSize); + assertEquals(9, oggReader.getPageHeader().bodySize); + assertEquals(2, oggReader.getPageHeader().pageSegmentCount); + assertEquals(1000, oggReader.getPageHeader().pageSequenceNumber); + assertEquals(0, oggReader.getPageHeader().granulePosition); + + packetArray.reset(); + readPacketUntilSuccess(packetArray); + } + + public void testReadNoZeroSizedPacketsAreReturned() throws Exception { + extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x04); + extractorInput.recordOggLaces(new byte[]{(byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x08}); + extractorInput.recordOggPacket(new byte[]{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}); + extractorInput.recordOggPacket(new byte[]{0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}); + + ParsableByteArray packetArray = new ParsableByteArray(new byte[1024], 0); + + readPacketUntilSuccess(packetArray); + assertEquals(8, packetArray.limit()); + assertEquals(0x10, packetArray.data[0]); + assertEquals(0x10, packetArray.data[7]); + + packetArray.reset(); + readPacketUntilSuccess(packetArray); + assertEquals(8, packetArray.limit()); + assertEquals(0x20, packetArray.data[0]); + assertEquals(0x20, packetArray.data[7]); + + readEOFUntilSuccess(packetArray, 10); + } + + public void testReadZeroSizedPacketsAtEndOfStream() throws Exception { + extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x01); + extractorInput.recordOggLaces(new byte[]{(byte) 0x08}); + extractorInput.recordOggPacket(new byte[]{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}); + + extractorInput.recordOggHeader((byte) 0x04, 0, (byte) 0x03); + extractorInput.recordOggLaces(new byte[]{(byte) 0x08, (byte) 0x00, (byte) 0x00}); + extractorInput.recordOggPacket(new byte[]{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}); + + extractorInput.recordOggHeader((byte) 0x04, 0, (byte) 0x03); + extractorInput.recordOggLaces(new byte[]{(byte) 0x08, 0x00, 0x00}); + extractorInput.recordOggPacket(new byte[]{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}); + + ParsableByteArray packetArray = new ParsableByteArray(new byte[1024], 0); + + readPacketUntilSuccess(packetArray); + assertEquals(8, packetArray.limit()); + + packetArray.reset(); + readPacketUntilSuccess(packetArray); + assertEquals(8, packetArray.limit()); + + packetArray.reset(); + readPacketUntilSuccess(packetArray); + assertEquals(8, packetArray.limit()); + + packetArray.reset(); + readEOFUntilSuccess(packetArray, 10); + assertEquals(0, packetArray.limit()); + } + + private void readPacketUntilSuccess(ParsableByteArray packetArray) { + int exceptionCount = 0; + while (exceptionCount < 10) { + try { + assertTrue(oggReader.readPacket(extractorInput, packetArray)); + break; + } catch (IOException | InterruptedException e) { + exceptionCount++; + extractorInput.resetPeekPosition(); + } + } + + if (exceptionCount == 10) { + fail("maxException threshold reached"); + } + } + + private void readEOFUntilSuccess(ParsableByteArray packetArray, int maxExceptions) { + int exceptionCount = 0; + while (exceptionCount < maxExceptions) { + try { + assertFalse(oggReader.readPacket(extractorInput, packetArray)); + break; + } catch (IOException | InterruptedException e) { + exceptionCount++; + Log.e(TAG, e.getMessage(), e); + } + } + if (exceptionCount == maxExceptions) { + fail("maxException threshold reached"); + } + } + +} diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggVorbisExtractorTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggVorbisExtractorTest.java new file mode 100644 index 0000000000..cb07736aa0 --- /dev/null +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggVorbisExtractorTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer.extractor.ogg; + +import com.google.android.exoplayer.util.ParsableByteArray; + +import android.util.Log; + +import junit.framework.TestCase; + +import java.io.IOException; + +/** + * Unit test for {@link OggVorbisExtractor}. + */ +public final class OggVorbisExtractorTest extends TestCase { + + private static final String TAG = "OggVorbisExtractorTest"; + + private OggVorbisExtractor extractor; + private RecordableOggExtractorInput extractorInput; + + @Override + public void setUp() throws Exception { + super.setUp(); + extractorInput = new RecordableOggExtractorInput(1024 * 64); + extractor = new OggVorbisExtractor(); + } + + public void testSniff() throws Exception { + extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x02); + extractorInput.recordOggLaces(new byte[]{120, 120}); + assertTrue(extractor.sniff(extractorInput)); + } + + public void testSniffFails() throws Exception { + extractorInput.recordOggHeader((byte) 0x00, 0, (byte) 0); + assertFalse(extractor.sniff(extractorInput)); + } + + public void testAppendNumberOfSamples() throws Exception { + ParsableByteArray buffer = new ParsableByteArray(4); + buffer.setLimit(0); + OggVorbisExtractor.appendNumberOfSamples(buffer, 0x01234567); + assertEquals(4, buffer.limit()); + assertEquals(0x67, buffer.data[0]); + assertEquals(0x45, buffer.data[1]); + assertEquals(0x23, buffer.data[2]); + assertEquals(0x01, buffer.data[3]); + } + + public void testReadSetupHeadersWithIOExceptions() throws IOException, InterruptedException { + extractorInput.doThrowExceptionsAtRead(true); + extractorInput.doThrowExceptionsAtPeek(true); + + byte[] data = TestData.getVorbisHeaderPages(); + extractorInput.record(data); + + int exceptionCount = 0; + int maxExceptions = 20; + OggVorbisExtractor.VorbisSetup vorbisSetup; + while (exceptionCount < maxExceptions) { + try { + vorbisSetup = extractor.readSetupHeaders(extractorInput, + new ParsableByteArray(new byte[255 * 255], 0)); + + assertNotNull(vorbisSetup.idHeader); + assertNotNull(vorbisSetup.commentHeader); + assertNotNull(vorbisSetup.setupHeaderData); + assertNotNull(vorbisSetup.modes); + + assertEquals(45, vorbisSetup.commentHeader.length); + assertEquals(30, vorbisSetup.idHeader.data.length); + assertEquals(3597, vorbisSetup.setupHeaderData.length); + + assertEquals(-1, vorbisSetup.idHeader.bitrateMax); + assertEquals(-1, vorbisSetup.idHeader.bitrateMin); + assertEquals(66666, vorbisSetup.idHeader.bitrateNominal); + assertEquals(512, vorbisSetup.idHeader.blockSize0); + assertEquals(1024, vorbisSetup.idHeader.blockSize1); + assertEquals(2, vorbisSetup.idHeader.channels); + assertTrue(vorbisSetup.idHeader.framingFlag); + assertEquals(22050, vorbisSetup.idHeader.sampleRate); + assertEquals(0, vorbisSetup.idHeader.version); + + assertEquals("Xiph.Org libVorbis I 20030909", vorbisSetup.commentHeader.vendor); + assertEquals(1, vorbisSetup.iLogModes); + + assertEquals(data[data.length - 1], + vorbisSetup.setupHeaderData[vorbisSetup.setupHeaderData.length - 1]); + + assertFalse(vorbisSetup.modes[0].blockFlag); + assertTrue(vorbisSetup.modes[1].blockFlag); + break; + } catch (Throwable e) { + Log.e(TAG, e.getMessage(), e); + extractorInput.resetPeekPosition(); + exceptionCount++; + } + } + if (exceptionCount >= maxExceptions) { + fail("more than " + maxExceptions + " exceptions thrown"); + } + } + +} diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/RecordableExtractorInput.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/RecordableExtractorInput.java new file mode 100644 index 0000000000..8cb9db208e --- /dev/null +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/RecordableExtractorInput.java @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer.extractor.ogg; + +import com.google.android.exoplayer.C; +import com.google.android.exoplayer.extractor.ExtractorInput; + +import java.io.EOFException; +import java.io.IOException; + +/** + * Implementation of {@link ExtractorInput} for testing purpose. + */ +/* package */ class RecordableExtractorInput implements ExtractorInput { + protected static final byte STREAM_REVISION = 0x00; + + private byte[] data; + private int readOffset; + private int writeOffset; + private int peekOffset; + + private boolean throwExceptionsAtRead = false; + private boolean throwExceptionsAtPeek = false; + private int numberOfReadsUntilException = 1; + private int numberOfPeeksUntilException = 1; + private int readCounter; + private int peekCounter; + private int maxReadExceptions = Integer.MAX_VALUE; + private int maxPeekExceptions = Integer.MAX_VALUE; + private int readExceptionCounter; + private int peekExceptionCounter; + + + /** + * Constructs an instance with a initial array of bytes. + * + * @param data the initial data. + * @param writeOffset the {@code writeOffset} from where to start recording. + */ + public RecordableExtractorInput(byte[] data, int writeOffset) { + this.data = data; + this.writeOffset = writeOffset; + } + + /** + * Constructs an instance with an empty data array with length {@code maxBytes}. + * + * @param maxBytes the maximal number of bytes this {@code ExtractorInput} can store. + */ + public RecordableExtractorInput(int maxBytes) { + this(new byte[maxBytes], 0); + } + + @Override + public int read(byte[] target, int offset, int length) throws IOException, InterruptedException { + readFully(target, offset, length); + return isEOF() ? C.RESULT_END_OF_INPUT : length; + } + + @Override + public boolean readFully(byte[] target, int offset, int length, boolean allowEndOfInput) + throws IOException, InterruptedException { + readCounter++; + if (throwExceptionsAtRead + && readExceptionCounter < maxReadExceptions + && readCounter % numberOfReadsUntilException == 0) { + readCounter = 0; + numberOfReadsUntilException++; + readExceptionCounter++; + throw new IOException("deliberately thrown an exception for testing"); + } + if (readOffset + length > writeOffset) { + if (!allowEndOfInput) { + throw new EOFException(); + } + return false; + } + System.arraycopy(data, readOffset, target, offset, length); + readOffset += length; + peekOffset = readOffset; + return true; + } + + @Override + public void readFully(byte[] target, int offset, int length) + throws IOException, InterruptedException { + readFully(target, offset, length, false); + } + + @Override + public int skip(int length) throws IOException, InterruptedException { + skipFully(length); + return isEOF() ? C.RESULT_END_OF_INPUT : length; + } + + private boolean isEOF() { + return readOffset == writeOffset; + } + + @Override + public boolean skipFully(int length, boolean allowEndOfInput) + throws IOException, InterruptedException { + if (readOffset + length >= writeOffset) { + if (!allowEndOfInput) { + throw new EOFException(); + } + return false; + } + readOffset += length; + peekOffset = readOffset; + return true; + } + + @Override + public void skipFully(int length) throws IOException, InterruptedException { + skipFully(length, false); + } + + @Override + public boolean peekFully(byte[] target, int offset, int length, boolean allowEndOfInput) + throws IOException, InterruptedException { + peekCounter++; + if (throwExceptionsAtPeek + && peekExceptionCounter < maxPeekExceptions + && peekCounter % numberOfPeeksUntilException == 0) { + peekCounter = 0; + numberOfPeeksUntilException++; + peekExceptionCounter++; + throw new IOException("deliberately thrown an exception for testing"); + } + if (peekOffset + length > writeOffset) { + if (!allowEndOfInput) { + throw new EOFException(); + } + return false; + } + System.arraycopy(data, peekOffset, target, offset, length); + peekOffset += length; + return true; + } + + @Override + public void peekFully(byte[] target, int offset, int length) + throws IOException, InterruptedException { + peekFully(target, offset, length, false); + } + + @Override + public boolean advancePeekPosition(int length, boolean allowEndOfInput) + throws IOException, InterruptedException { + if (peekOffset + length >= writeOffset) { + if (!allowEndOfInput) { + throw new EOFException(); + } + return false; + } + peekOffset += length; + return true; + } + + @Override + public void advancePeekPosition(int length) throws IOException, InterruptedException { + advancePeekPosition(length, false); + } + + @Override + public void resetPeekPosition() { + peekOffset = readOffset; + } + + @Override + public long getPosition() { + return readOffset; + } + + @Override + public long getLength() { + return writeOffset; + } + + /** + * Records the {@code bytes}. + * + * @param bytes the bytes to record. + */ + public void record(final byte[] bytes) { + System.arraycopy(bytes, 0, data, writeOffset, bytes.length); + writeOffset += bytes.length; + } + + /** Records a single byte. **/ + public void record(byte b) { + record(new byte[]{b}); + } + + /** + * Gets a byte array with length {@code length} with ascending values starting from 0 (zero). + * + * @param length the length of the array. + * @return an array of bytes with ascending values. + */ + public static byte[] getBytesGrowingValues(int length) { + return fillBytesGrowingValues(new byte[length], length, (byte) 0); + } + + /** + * Gets a byte array with length {@code length} with ascending values starting + * from {@code startValue}. + * + * @param length the length of the array. + * @param startValue the value from which to start. + * @return an array of bytes with ascending values starting from {@code startValue}. + */ + public static byte[] getBytesGrowingValues(int length, byte startValue) { + return fillBytesGrowingValues(new byte[length], length, startValue); + } + + /** + * Fills the byte array passed as argument with ascending values. + * + * @param bytes the byte array to fill with values. + * @param limit the number of bytes to set in the array. + * @param startValue the startValue from which the values in the array have to start. + */ + public static byte[] fillBytesGrowingValues(byte[] bytes, int limit, byte startValue) { + for (int i = 0; i < bytes.length; i++) { + if (i < limit) { + bytes[i] = (byte) ((i + startValue) % 255); + } else { + bytes[i] = 0; + } + } + return bytes; + } + + public void setMaxReadExceptions(int maxReadExceptions) { + this.maxReadExceptions = maxReadExceptions; + } + + public void setMaxPeekExceptions(int maxPeekExceptions) { + this.maxPeekExceptions = maxPeekExceptions; + } + + public void setNumberOfReadsUntilException(int numberOfReadsUntilException) { + this.numberOfReadsUntilException = numberOfReadsUntilException; + } + + public void setNumberOfPeeksUntilException(int numberOfPeeksUntilException) { + this.numberOfPeeksUntilException = numberOfPeeksUntilException; + } + + public void doThrowExceptionsAtRead(boolean throwExceptionsAtRead) { + this.throwExceptionsAtRead = throwExceptionsAtRead; + } + + public void doThrowExceptionsAtPeek(boolean throwExceptionsAtPeek) { + this.throwExceptionsAtPeek = throwExceptionsAtPeek; + } + +} diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/RecordableOggExtractorInput.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/RecordableOggExtractorInput.java new file mode 100644 index 0000000000..c293178ffc --- /dev/null +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/RecordableOggExtractorInput.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer.extractor.ogg; + +/** + * A {@link RecordableOggExtractorInput} with convenient methods to record an OGG byte stream. + */ +/* package */ final class RecordableOggExtractorInput extends RecordableExtractorInput { + + private long pageSequenceCounter; + + public RecordableOggExtractorInput(byte[] data, int writeOffset) { + super(data, writeOffset); + pageSequenceCounter = 1000; + } + + public RecordableOggExtractorInput(int maxBytes) { + this(new byte[maxBytes], 0); + } + + /** + * Syntax sugar to make tests more readable. + * + * @param laces the laces to record to the data. + */ + protected void recordOggLaces(final byte[] laces) { + record(laces); + } + + /** + * Syntax sugar to make tests more readable. + * + * @param packet the packet bytes to record to the data. + */ + protected void recordOggPacket(final byte[] packet) { + record(packet); + } + + protected void recordOggHeader(final byte headerType, final long granule, + final byte pageSegmentCount) { + record((byte) 0x4F); // O + record((byte) 0x67); // g + record((byte) 0x67); // g + record((byte) 0x53); // S + record(STREAM_REVISION); + record(headerType); + recordGranulePosition(granule); + record((byte) 0x00); // LSB of data serial number + record((byte) 0x10); + record((byte) 0x00); + record((byte) 0x00); // MSB of data serial number + recordPageSequenceCounter(); + record((byte) 0x00); // LSB of page checksum + record((byte) 0x00); + record((byte) 0x00); + record((byte) 0x00); // MSB of page checksum + record(pageSegmentCount); // 0 - 255 + } + + protected void recordGranulePosition(long granule) { + record((byte) (granule & 0xFF)); + record((byte) ((granule >> 8) & 0xFF)); + record((byte) ((granule >> 16) & 0xFF)); + record((byte) ((granule >> 24) & 0xFF)); + record((byte) ((granule >> 32) & 0xFF)); + record((byte) ((granule >> 40) & 0xFF)); + record((byte) ((granule >> 48) & 0xFF)); + record((byte) ((granule >> 56) & 0xFF)); + } + + protected void recordPageSequenceCounter() { + record((byte) (pageSequenceCounter & 0xFF)); + record((byte) ((pageSequenceCounter >> 8) & 0xFF)); + record((byte) ((pageSequenceCounter >> 16) & 0xFF)); + record((byte) ((pageSequenceCounter++ >> 24) & 0xFF)); + } + +} diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/TestData.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/TestData.java new file mode 100644 index 0000000000..e76086249e --- /dev/null +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/TestData.java @@ -0,0 +1,1039 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer.extractor.ogg; + +/** + * Provides ogg/vorbis test data in bytes for unit tests. + */ +/* package */ final class TestData { + + /** + * Returns the initial two pages of bytes which by spec contain the three vorbis header packets: + * identification, comment and setup header. + */ + public static byte[] getVorbisHeaderPages() { + byte[] data = new byte[VORBIS_HEADER_PAGES.length]; + System.arraycopy(VORBIS_HEADER_PAGES, 0, data, 0, + VORBIS_HEADER_PAGES.length); + return data; + } + + /** + * Returns a valid vorbis identification header in bytes. + */ + public static byte[] getIdentificationHeaderData() { + int idHeaderStart = 28; + int idHeaderLength = 30; + byte[] idHeaderData = new byte[idHeaderLength]; + System.arraycopy(VORBIS_HEADER_PAGES, idHeaderStart, idHeaderData, 0, idHeaderLength); + return idHeaderData; + } + + /** + * Returns a valid vorbis comment header with 3 comments including utf8 chars in bytes. + */ + public static byte[] getCommentHeaderDataUTF8() { + byte[] commentHeaderData = new byte[COMMENT_HEADER_WITH_UTF8.length]; + System.arraycopy(COMMENT_HEADER_WITH_UTF8, 0, commentHeaderData, 0, + COMMENT_HEADER_WITH_UTF8.length); + return commentHeaderData; + } + + /** + * Returns a valid vorbis setup header in bytes. + */ + public static byte[] getSetupHeaderData() { + int setupHeaderStart = 146; + int setupHeaderLength = VORBIS_HEADER_PAGES.length - setupHeaderStart; + byte[] setupHeaderData = new byte[setupHeaderLength]; + System.arraycopy(VORBIS_HEADER_PAGES, setupHeaderStart, setupHeaderData, 0, setupHeaderLength); + return setupHeaderData; + } + + private static final byte[] COMMENT_HEADER_WITH_UTF8 = { + (byte) 0x03, (byte) 0x76, (byte) 0x6f, (byte) 0x72, // 3, v, o, r, + (byte) 0x62, (byte) 0x69, (byte) 0x73, (byte) 0x2b, // b, i, s, . + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x58, + (byte) 0x69, (byte) 0x70, (byte) 0x68, (byte) 0x2e, + (byte) 0x4f, (byte) 0x72, (byte) 0x67, (byte) 0x20, + (byte) 0x6c, (byte) 0x69, (byte) 0x62, (byte) 0x56, + (byte) 0x6f, (byte) 0x72, (byte) 0x62, (byte) 0x69, + (byte) 0x73, (byte) 0x20, (byte) 0x49, (byte) 0x20, + (byte) 0x32, (byte) 0x30, (byte) 0x31, (byte) 0x32, + (byte) 0x30, (byte) 0x32, (byte) 0x30, (byte) 0x33, + (byte) 0x20, (byte) 0x28, (byte) 0x4f, (byte) 0x6d, + (byte) 0x6e, (byte) 0x69, (byte) 0x70, (byte) 0x72, + (byte) 0x65, (byte) 0x73, (byte) 0x65, (byte) 0x6e, + (byte) 0x74, (byte) 0x29, (byte) 0x03, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x0a, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x41, (byte) 0x4c, + (byte) 0x42, (byte) 0x55, (byte) 0x4d, (byte) 0x3d, + (byte) 0xc3, (byte) 0xa4, (byte) 0xc3, (byte) 0xb6, + (byte) 0x13, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x54, (byte) 0x49, (byte) 0x54, (byte) 0x4c, + (byte) 0x45, (byte) 0x3d, (byte) 0x41, (byte) 0x20, + (byte) 0x73, (byte) 0x61, (byte) 0x6d, (byte) 0x70, + (byte) 0x6c, (byte) 0x65, (byte) 0x20, (byte) 0x73, + (byte) 0x6f, (byte) 0x6e, (byte) 0x67, (byte) 0x0d, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x41, + (byte) 0x52, (byte) 0x54, (byte) 0x49, (byte) 0x53, + (byte) 0x54, (byte) 0x3d, (byte) 0x47, (byte) 0x6f, + (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, + (byte) 0x01 + }; + + // two OGG pages with 3 packets (id, comment and setup header) + // length: 3743 bytes + private static final byte[] VORBIS_HEADER_PAGES = { /* capture pattern ogg header 1 */ + (byte) 0x4f, (byte) 0x67, (byte) 0x67, (byte) 0x53, // O,g,g,S : start pos 0 + (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x5e, (byte) 0x5f, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x83, (byte) 0x36, + (byte) 0xe3, (byte) 0x49, (byte) 0x01, (byte) 0x1e, /* capture pattern vorbis id header */ + (byte) 0x01, (byte) 0x76, (byte) 0x6f, (byte) 0x72, // 1,v,o,r : start pos 28 + (byte) 0x62, (byte) 0x69, (byte) 0x73, (byte) 0x00, // b,i,s,. + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + (byte) 0x22, (byte) 0x56, (byte) 0x00, (byte) 0x00, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0x6a, (byte) 0x04, (byte) 0x01, (byte) 0x00, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, /* capture pattern ogg header 2 */ + (byte) 0xa9, (byte) 0x01, (byte) 0x4f, (byte) 0x67, // .,.,O,g : start pos 86 + (byte) 0x67, (byte) 0x53, (byte) 0x00, (byte) 0x00, // g,S,.,. + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x5e, (byte) 0x5f, (byte) 0x00, (byte) 0x00, + (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x69, (byte) 0xf8, (byte) 0xeb, (byte) 0xe1, + (byte) 0x10, (byte) 0x2d, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, /* capture pattern vorbis comment header*/ + (byte) 0x1b, (byte) 0x03, (byte) 0x76, (byte) 0x6f, // .,3,v,o : start pos 101 + (byte) 0x72, (byte) 0x62, (byte) 0x69, (byte) 0x73, // r,b,i,s + (byte) 0x1d, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x58, (byte) 0x69, (byte) 0x70, (byte) 0x68, + (byte) 0x2e, (byte) 0x4f, (byte) 0x72, (byte) 0x67, + (byte) 0x20, (byte) 0x6c, (byte) 0x69, (byte) 0x62, + (byte) 0x56, (byte) 0x6f, (byte) 0x72, (byte) 0x62, + (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x49, + (byte) 0x20, (byte) 0x32, (byte) 0x30, (byte) 0x30, + (byte) 0x33, (byte) 0x30, (byte) 0x39, (byte) 0x30, + (byte) 0x39, (byte) 0x00, (byte) 0x00, (byte) 0x00, /* capture pattern vorbis setup header */ + (byte) 0x00, (byte) 0x01, (byte) 0x05, (byte) 0x76, // .,.,5,v : start pos 146 + (byte) 0x6f, (byte) 0x72, (byte) 0x62, (byte) 0x69, // o,r,b,i + (byte) 0x73, (byte) 0x22, (byte) 0x42, (byte) 0x43, // s,. + (byte) 0x56, (byte) 0x01, (byte) 0x00, (byte) 0x40, + (byte) 0x00, (byte) 0x00, (byte) 0x18, (byte) 0x42, + (byte) 0x10, (byte) 0x2a, (byte) 0x05, (byte) 0xad, + (byte) 0x63, (byte) 0x8e, (byte) 0x3a, (byte) 0xc8, + (byte) 0x15, (byte) 0x21, (byte) 0x8c, (byte) 0x19, + (byte) 0xa2, (byte) 0xa0, (byte) 0x42, (byte) 0xca, + (byte) 0x29, (byte) 0xc7, (byte) 0x1d, (byte) 0x42, + (byte) 0xd0, (byte) 0x21, (byte) 0xa3, (byte) 0x24, + (byte) 0x43, (byte) 0x88, (byte) 0x3a, (byte) 0xc6, + (byte) 0x35, (byte) 0xc7, (byte) 0x18, (byte) 0x63, + (byte) 0x47, (byte) 0xb9, (byte) 0x64, (byte) 0x8a, + (byte) 0x42, (byte) 0xc9, (byte) 0x81, (byte) 0xd0, + (byte) 0x90, (byte) 0x55, (byte) 0x00, (byte) 0x00, + (byte) 0x40, (byte) 0x00, (byte) 0x00, (byte) 0xa4, + (byte) 0x1c, (byte) 0x57, (byte) 0x50, (byte) 0x72, + (byte) 0x49, (byte) 0x2d, (byte) 0xe7, (byte) 0x9c, + (byte) 0x73, (byte) 0xa3, (byte) 0x18, (byte) 0x57, + (byte) 0xcc, (byte) 0x71, (byte) 0xe8, (byte) 0x20, + (byte) 0xe7, (byte) 0x9c, (byte) 0x73, (byte) 0xe5, + (byte) 0x20, (byte) 0x67, (byte) 0xcc, (byte) 0x71, + (byte) 0x09, (byte) 0x25, (byte) 0xe7, (byte) 0x9c, + (byte) 0x73, (byte) 0x8e, (byte) 0x39, (byte) 0xe7, + (byte) 0x92, (byte) 0x72, (byte) 0x8e, (byte) 0x31, + (byte) 0xe7, (byte) 0x9c, (byte) 0x73, (byte) 0xa3, + (byte) 0x18, (byte) 0x57, (byte) 0x0e, (byte) 0x72, + (byte) 0x29, (byte) 0x2d, (byte) 0xe7, (byte) 0x9c, + (byte) 0x73, (byte) 0x81, (byte) 0x14, (byte) 0x47, + (byte) 0x8a, (byte) 0x71, (byte) 0xa7, (byte) 0x18, + (byte) 0xe7, (byte) 0x9c, (byte) 0x73, (byte) 0xa4, + (byte) 0x1c, (byte) 0x47, (byte) 0x8a, (byte) 0x71, + (byte) 0xa8, (byte) 0x18, (byte) 0xe7, (byte) 0x9c, + (byte) 0x73, (byte) 0x6d, (byte) 0x31, (byte) 0xb7, + (byte) 0x92, (byte) 0x72, (byte) 0xce, (byte) 0x39, + (byte) 0xe7, (byte) 0x9c, (byte) 0x73, (byte) 0xe6, + (byte) 0x20, (byte) 0x87, (byte) 0x52, (byte) 0x72, + (byte) 0xae, (byte) 0x35, (byte) 0xe7, (byte) 0x9c, + (byte) 0x73, (byte) 0xa4, (byte) 0x18, (byte) 0x67, + (byte) 0x0e, (byte) 0x72, (byte) 0x0b, (byte) 0x25, + (byte) 0xe7, (byte) 0x9c, (byte) 0x73, (byte) 0xc6, + (byte) 0x20, (byte) 0x67, (byte) 0xcc, (byte) 0x71, + (byte) 0xeb, (byte) 0x20, (byte) 0xe7, (byte) 0x9c, + (byte) 0x73, (byte) 0x8c, (byte) 0x35, (byte) 0xb7, + (byte) 0xd4, (byte) 0x72, (byte) 0xce, (byte) 0x39, + (byte) 0xe7, (byte) 0x9c, (byte) 0x73, (byte) 0xce, + (byte) 0x39, (byte) 0xe7, (byte) 0x9c, (byte) 0x73, + (byte) 0xce, (byte) 0x39, (byte) 0xe7, (byte) 0x9c, + (byte) 0x73, (byte) 0x8c, (byte) 0x31, (byte) 0xe7, + (byte) 0x9c, (byte) 0x73, (byte) 0xce, (byte) 0x39, + (byte) 0xe7, (byte) 0x9c, (byte) 0x73, (byte) 0x6e, + (byte) 0x31, (byte) 0xe7, (byte) 0x16, (byte) 0x73, + (byte) 0xae, (byte) 0x39, (byte) 0xe7, (byte) 0x9c, + (byte) 0x73, (byte) 0xce, (byte) 0x39, (byte) 0xe7, + (byte) 0x1c, (byte) 0x73, (byte) 0xce, (byte) 0x39, + (byte) 0xe7, (byte) 0x9c, (byte) 0x73, (byte) 0x20, + (byte) 0x34, (byte) 0x64, (byte) 0x15, (byte) 0x00, + (byte) 0x90, (byte) 0x00, (byte) 0x00, (byte) 0xa0, + (byte) 0xa1, (byte) 0x28, (byte) 0x8a, (byte) 0xe2, + (byte) 0x28, (byte) 0x0e, (byte) 0x10, (byte) 0x1a, + (byte) 0xb2, (byte) 0x0a, (byte) 0x00, (byte) 0xc8, + (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x40, + (byte) 0x71, (byte) 0x14, (byte) 0x47, (byte) 0x91, + (byte) 0x14, (byte) 0x4b, (byte) 0xb1, (byte) 0x1c, + (byte) 0xcb, (byte) 0xd1, (byte) 0x24, (byte) 0x0d, + (byte) 0x08, (byte) 0x0d, (byte) 0x59, (byte) 0x05, + (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, + (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0xa0, + (byte) 0x48, (byte) 0x86, (byte) 0xa4, (byte) 0x48, + (byte) 0x8a, (byte) 0xa5, (byte) 0x58, (byte) 0x8e, + (byte) 0x66, (byte) 0x69, (byte) 0x9e, (byte) 0x26, + (byte) 0x7a, (byte) 0xa2, (byte) 0x28, (byte) 0x9a, + (byte) 0xa2, (byte) 0x2a, (byte) 0xab, (byte) 0xb2, + (byte) 0x69, (byte) 0xca, (byte) 0xb2, (byte) 0x2c, + (byte) 0xcb, (byte) 0xb2, (byte) 0xeb, (byte) 0xba, + (byte) 0x2e, (byte) 0x10, (byte) 0x1a, (byte) 0xb2, + (byte) 0x0a, (byte) 0x00, (byte) 0x48, (byte) 0x00, + (byte) 0x00, (byte) 0x50, (byte) 0x51, (byte) 0x14, + (byte) 0xc5, (byte) 0x70, (byte) 0x14, (byte) 0x07, + (byte) 0x08, (byte) 0x0d, (byte) 0x59, (byte) 0x05, + (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x00, + (byte) 0x08, (byte) 0x60, (byte) 0x28, (byte) 0x8a, + (byte) 0xa3, (byte) 0x38, (byte) 0x8e, (byte) 0xe4, + (byte) 0x58, (byte) 0x92, (byte) 0xa5, (byte) 0x59, + (byte) 0x9e, (byte) 0x07, (byte) 0x84, (byte) 0x86, + (byte) 0xac, (byte) 0x02, (byte) 0x00, (byte) 0x80, + (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, + (byte) 0x00, (byte) 0x50, (byte) 0x0c, (byte) 0x47, + (byte) 0xb1, (byte) 0x14, (byte) 0x4d, (byte) 0xf1, + (byte) 0x24, (byte) 0xcf, (byte) 0xf2, (byte) 0x3c, + (byte) 0xcf, (byte) 0xf3, (byte) 0x3c, (byte) 0xcf, + (byte) 0xf3, (byte) 0x3c, (byte) 0xcf, (byte) 0xf3, + (byte) 0x3c, (byte) 0xcf, (byte) 0xf3, (byte) 0x3c, + (byte) 0xcf, (byte) 0xf3, (byte) 0x3c, (byte) 0xcf, + (byte) 0xf3, (byte) 0x3c, (byte) 0x0d, (byte) 0x08, + (byte) 0x0d, (byte) 0x59, (byte) 0x05, (byte) 0x00, + (byte) 0x20, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x82, (byte) 0x28, (byte) 0x64, (byte) 0x18, + (byte) 0x03, (byte) 0x42, (byte) 0x43, (byte) 0x56, + (byte) 0x01, (byte) 0x00, (byte) 0x40, (byte) 0x00, + (byte) 0x00, (byte) 0x08, (byte) 0x21, (byte) 0x1a, + (byte) 0x19, (byte) 0x43, (byte) 0x9d, (byte) 0x52, + (byte) 0x12, (byte) 0x5c, (byte) 0x0a, (byte) 0x16, + (byte) 0x42, (byte) 0x1c, (byte) 0x11, (byte) 0x43, + (byte) 0x1d, (byte) 0x42, (byte) 0xce, (byte) 0x43, + (byte) 0xa9, (byte) 0xa5, (byte) 0x83, (byte) 0xe0, + (byte) 0x29, (byte) 0x85, (byte) 0x25, (byte) 0x63, + (byte) 0xd2, (byte) 0x53, (byte) 0xac, (byte) 0x41, + (byte) 0x08, (byte) 0x21, (byte) 0x7c, (byte) 0xef, + (byte) 0x3d, (byte) 0xf7, (byte) 0xde, (byte) 0x7b, + (byte) 0xef, (byte) 0x81, (byte) 0xd0, (byte) 0x90, + (byte) 0x55, (byte) 0x00, (byte) 0x00, (byte) 0x10, + (byte) 0x00, (byte) 0x00, (byte) 0x61, (byte) 0x14, + (byte) 0x38, (byte) 0x88, (byte) 0x81, (byte) 0xc7, + (byte) 0x24, (byte) 0x08, (byte) 0x21, (byte) 0x84, + (byte) 0x62, (byte) 0x14, (byte) 0x27, (byte) 0x44, + (byte) 0x71, (byte) 0xa6, (byte) 0x20, (byte) 0x08, + (byte) 0x21, (byte) 0x84, (byte) 0xe5, (byte) 0x24, + (byte) 0x58, (byte) 0xca, (byte) 0x79, (byte) 0xe8, + (byte) 0x24, (byte) 0x08, (byte) 0xdd, (byte) 0x83, + (byte) 0x10, (byte) 0x42, (byte) 0xb8, (byte) 0x9c, + (byte) 0x7b, (byte) 0xcb, (byte) 0xb9, (byte) 0xf7, + (byte) 0xde, (byte) 0x7b, (byte) 0x20, (byte) 0x34, + (byte) 0x64, (byte) 0x15, (byte) 0x00, (byte) 0x00, + (byte) 0x08, (byte) 0x00, (byte) 0xc0, (byte) 0x20, + (byte) 0x84, (byte) 0x10, (byte) 0x42, (byte) 0x08, + (byte) 0x21, (byte) 0x84, (byte) 0x10, (byte) 0x42, + (byte) 0x08, (byte) 0x29, (byte) 0xa4, (byte) 0x94, + (byte) 0x52, (byte) 0x48, (byte) 0x29, (byte) 0xa6, + (byte) 0x98, (byte) 0x62, (byte) 0x8a, (byte) 0x29, + (byte) 0xc7, (byte) 0x1c, (byte) 0x73, (byte) 0xcc, + (byte) 0x31, (byte) 0xc7, (byte) 0x20, (byte) 0x83, + (byte) 0x0c, (byte) 0x32, (byte) 0xe8, (byte) 0xa0, + (byte) 0x93, (byte) 0x4e, (byte) 0x3a, (byte) 0xc9, + (byte) 0xa4, (byte) 0x92, (byte) 0x4e, (byte) 0x3a, + (byte) 0xca, (byte) 0x24, (byte) 0xa3, (byte) 0x8e, + (byte) 0x52, (byte) 0x6b, (byte) 0x29, (byte) 0xb5, + (byte) 0x14, (byte) 0x53, (byte) 0x4c, (byte) 0xb1, + (byte) 0xe5, (byte) 0x16, (byte) 0x63, (byte) 0xad, + (byte) 0xb5, (byte) 0xd6, (byte) 0x9c, (byte) 0x73, + (byte) 0xaf, (byte) 0x41, (byte) 0x29, (byte) 0x63, + (byte) 0x8c, (byte) 0x31, (byte) 0xc6, (byte) 0x18, + (byte) 0x63, (byte) 0x8c, (byte) 0x31, (byte) 0xc6, + (byte) 0x18, (byte) 0x63, (byte) 0x8c, (byte) 0x31, + (byte) 0xc6, (byte) 0x18, (byte) 0x23, (byte) 0x08, + (byte) 0x0d, (byte) 0x59, (byte) 0x05, (byte) 0x00, + (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x10, + (byte) 0x06, (byte) 0x19, (byte) 0x64, (byte) 0x90, + (byte) 0x41, (byte) 0x08, (byte) 0x21, (byte) 0x84, + (byte) 0x14, (byte) 0x52, (byte) 0x48, (byte) 0x29, + (byte) 0xa6, (byte) 0x98, (byte) 0x72, (byte) 0xcc, + (byte) 0x31, (byte) 0xc7, (byte) 0x1c, (byte) 0x03, + (byte) 0x42, (byte) 0x43, (byte) 0x56, (byte) 0x01, + (byte) 0x00, (byte) 0x80, (byte) 0x00, (byte) 0x00, + (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x1c, (byte) 0x45, (byte) 0x52, (byte) 0x24, + (byte) 0x47, (byte) 0x72, (byte) 0x24, (byte) 0x47, + (byte) 0x92, (byte) 0x24, (byte) 0xc9, (byte) 0x92, + (byte) 0x2c, (byte) 0x49, (byte) 0x93, (byte) 0x3c, + (byte) 0xcb, (byte) 0xb3, (byte) 0x3c, (byte) 0xcb, + (byte) 0xb3, (byte) 0x3c, (byte) 0x4d, (byte) 0xd4, + (byte) 0x44, (byte) 0x4d, (byte) 0x15, (byte) 0x55, + (byte) 0xd5, (byte) 0x55, (byte) 0x6d, (byte) 0xd7, + (byte) 0xf6, (byte) 0x6d, (byte) 0x5f, (byte) 0xf6, + (byte) 0x6d, (byte) 0xdf, (byte) 0xd5, (byte) 0x65, + (byte) 0xdf, (byte) 0xf6, (byte) 0x65, (byte) 0xdb, + (byte) 0xd5, (byte) 0x65, (byte) 0x5d, (byte) 0x96, + (byte) 0x65, (byte) 0xdd, (byte) 0xb5, (byte) 0x6d, + (byte) 0x5d, (byte) 0xd6, (byte) 0x5d, (byte) 0x5d, + (byte) 0xd7, (byte) 0x75, (byte) 0x5d, (byte) 0xd7, + (byte) 0x75, (byte) 0x5d, (byte) 0xd7, (byte) 0x75, + (byte) 0x5d, (byte) 0xd7, (byte) 0x75, (byte) 0x5d, + (byte) 0xd7, (byte) 0x75, (byte) 0x5d, (byte) 0xd7, + (byte) 0x81, (byte) 0xd0, (byte) 0x90, (byte) 0x55, + (byte) 0x00, (byte) 0x80, (byte) 0x04, (byte) 0x00, + (byte) 0x80, (byte) 0x8e, (byte) 0xe4, (byte) 0x38, + (byte) 0x8e, (byte) 0xe4, (byte) 0x38, (byte) 0x8e, + (byte) 0xe4, (byte) 0x48, (byte) 0x8e, (byte) 0xa4, + (byte) 0x48, (byte) 0x0a, (byte) 0x10, (byte) 0x1a, + (byte) 0xb2, (byte) 0x0a, (byte) 0x00, (byte) 0x90, + (byte) 0x01, (byte) 0x00, (byte) 0x10, (byte) 0x00, + (byte) 0x80, (byte) 0xa3, (byte) 0x38, (byte) 0x8a, + (byte) 0xe3, (byte) 0x48, (byte) 0x8e, (byte) 0xe4, + (byte) 0x58, (byte) 0x8e, (byte) 0x25, (byte) 0x59, + (byte) 0x92, (byte) 0x26, (byte) 0x69, (byte) 0x96, + (byte) 0x67, (byte) 0x79, (byte) 0x96, (byte) 0xa7, + (byte) 0x79, (byte) 0x9a, (byte) 0xa8, (byte) 0x89, + (byte) 0x1e, (byte) 0x10, (byte) 0x1a, (byte) 0xb2, + (byte) 0x0a, (byte) 0x00, (byte) 0x00, (byte) 0x04, + (byte) 0x00, (byte) 0x10, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80, + (byte) 0xa2, (byte) 0x28, (byte) 0x8a, (byte) 0xa3, + (byte) 0x38, (byte) 0x8e, (byte) 0x24, (byte) 0x59, + (byte) 0x96, (byte) 0xa6, (byte) 0x69, (byte) 0x9e, + (byte) 0xa7, (byte) 0x7a, (byte) 0xa2, (byte) 0x28, + (byte) 0x9a, (byte) 0xaa, (byte) 0xaa, (byte) 0x8a, + (byte) 0xa6, (byte) 0xa9, (byte) 0xaa, (byte) 0xaa, + (byte) 0x6a, (byte) 0x9a, (byte) 0xa6, (byte) 0x69, + (byte) 0x9a, (byte) 0xa6, (byte) 0x69, (byte) 0x9a, + (byte) 0xa6, (byte) 0x69, (byte) 0x9a, (byte) 0xa6, + (byte) 0x69, (byte) 0x9a, (byte) 0xa6, (byte) 0x69, + (byte) 0x9a, (byte) 0xa6, (byte) 0x69, (byte) 0x9a, + (byte) 0xa6, (byte) 0x69, (byte) 0x9a, (byte) 0xa6, + (byte) 0x69, (byte) 0x9a, (byte) 0xa6, (byte) 0x69, + (byte) 0x9a, (byte) 0xa6, (byte) 0x69, (byte) 0x9a, + (byte) 0xa6, (byte) 0x69, (byte) 0x02, (byte) 0xa1, + (byte) 0x21, (byte) 0xab, (byte) 0x00, (byte) 0x00, + (byte) 0x09, (byte) 0x00, (byte) 0x00, (byte) 0x1d, + (byte) 0xc7, (byte) 0x71, (byte) 0x1c, (byte) 0x47, + (byte) 0x71, (byte) 0x1c, (byte) 0xc7, (byte) 0x71, + (byte) 0x24, (byte) 0x47, (byte) 0x92, (byte) 0x24, + (byte) 0x20, (byte) 0x34, (byte) 0x64, (byte) 0x15, + (byte) 0x00, (byte) 0x20, (byte) 0x03, (byte) 0x00, + (byte) 0x20, (byte) 0x00, (byte) 0x00, (byte) 0x43, + (byte) 0x51, (byte) 0x1c, (byte) 0x45, (byte) 0x72, + (byte) 0x2c, (byte) 0xc7, (byte) 0x92, (byte) 0x34, + (byte) 0x4b, (byte) 0xb3, (byte) 0x3c, (byte) 0xcb, + (byte) 0xd3, (byte) 0x44, (byte) 0xcf, (byte) 0xf4, + (byte) 0x5c, (byte) 0x51, (byte) 0x36, (byte) 0x75, + (byte) 0x53, (byte) 0x57, (byte) 0x6d, (byte) 0x20, + (byte) 0x34, (byte) 0x64, (byte) 0x15, (byte) 0x00, + (byte) 0x00, (byte) 0x08, (byte) 0x00, (byte) 0x20, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0xc7, (byte) 0x73, + (byte) 0x3c, (byte) 0xc7, (byte) 0x73, (byte) 0x3c, + (byte) 0xc9, (byte) 0x93, (byte) 0x3c, (byte) 0xcb, + (byte) 0x73, (byte) 0x3c, (byte) 0xc7, (byte) 0x93, + (byte) 0x3c, (byte) 0x49, (byte) 0xd3, (byte) 0x34, + (byte) 0x4d, (byte) 0xd3, (byte) 0x34, (byte) 0x4d, + (byte) 0xd3, (byte) 0x34, (byte) 0x4d, (byte) 0xd3, + (byte) 0x34, (byte) 0x4d, (byte) 0xd3, (byte) 0x34, + (byte) 0x4d, (byte) 0xd3, (byte) 0x34, (byte) 0x4d, + (byte) 0xd3, (byte) 0x34, (byte) 0x4d, (byte) 0xd3, + (byte) 0x34, (byte) 0x4d, (byte) 0xd3, (byte) 0x34, + (byte) 0x4d, (byte) 0xd3, (byte) 0x34, (byte) 0x4d, + (byte) 0xd3, (byte) 0x34, (byte) 0x4d, (byte) 0xd3, + (byte) 0x34, (byte) 0x4d, (byte) 0xd3, (byte) 0x34, + (byte) 0x4d, (byte) 0xd3, (byte) 0x34, (byte) 0x4d, + (byte) 0x03, (byte) 0x42, (byte) 0x43, (byte) 0x56, + (byte) 0x02, (byte) 0x00, (byte) 0x64, (byte) 0x00, + (byte) 0x00, (byte) 0x90, (byte) 0x02, (byte) 0xcf, + (byte) 0x42, (byte) 0x29, (byte) 0x2d, (byte) 0x46, + (byte) 0x02, (byte) 0x1c, (byte) 0x88, (byte) 0x98, + (byte) 0xa3, (byte) 0xd8, (byte) 0x7b, (byte) 0xef, + (byte) 0xbd, (byte) 0xf7, (byte) 0xde, (byte) 0x7b, + (byte) 0x65, (byte) 0x3c, (byte) 0x92, (byte) 0x88, + (byte) 0x49, (byte) 0xed, (byte) 0x31, (byte) 0xf4, + (byte) 0xd4, (byte) 0x31, (byte) 0x07, (byte) 0xb1, + (byte) 0x67, (byte) 0xc6, (byte) 0x23, (byte) 0x66, + (byte) 0x94, (byte) 0xa3, (byte) 0xd8, (byte) 0x29, + (byte) 0xcf, (byte) 0x1c, (byte) 0x42, (byte) 0x0c, + (byte) 0x62, (byte) 0xe8, (byte) 0x3c, (byte) 0x74, + (byte) 0x4a, (byte) 0x31, (byte) 0x88, (byte) 0x29, + (byte) 0xf5, (byte) 0x52, (byte) 0x32, (byte) 0xc6, + (byte) 0x20, (byte) 0xc6, (byte) 0xd8, (byte) 0x63, + (byte) 0x0c, (byte) 0x21, (byte) 0x94, (byte) 0x18, + (byte) 0x08, (byte) 0x0d, (byte) 0x59, (byte) 0x21, + (byte) 0x00, (byte) 0x84, (byte) 0x66, (byte) 0x00, + (byte) 0x18, (byte) 0x24, (byte) 0x09, (byte) 0x90, + (byte) 0x34, (byte) 0x0d, (byte) 0x90, (byte) 0x34, + (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x24, (byte) 0x4f, (byte) 0x03, (byte) 0x34, + (byte) 0x51, (byte) 0x04, (byte) 0x34, (byte) 0x4f, + (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x49, (byte) 0xf3, (byte) 0x00, (byte) 0x4d, + (byte) 0xf4, (byte) 0x00, (byte) 0x4d, (byte) 0x14, + (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x90, (byte) 0x3c, (byte) 0x0d, (byte) 0xf0, + (byte) 0x44, (byte) 0x11, (byte) 0xd0, (byte) 0x44, + (byte) 0x11, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x34, (byte) 0x51, (byte) 0x04, (byte) 0x44, + (byte) 0x51, (byte) 0x05, (byte) 0x44, (byte) 0xd5, + (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x4d, (byte) 0x14, (byte) 0x01, (byte) 0x4f, + (byte) 0x15, (byte) 0x01, (byte) 0xd1, (byte) 0x54, + (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x90, (byte) 0x34, (byte) 0x0f, (byte) 0xd0, + (byte) 0x44, (byte) 0x11, (byte) 0xf0, (byte) 0x44, + (byte) 0x11, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x34, (byte) 0x51, (byte) 0x04, (byte) 0x44, + (byte) 0xd5, (byte) 0x04, (byte) 0x3c, (byte) 0x51, + (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x4d, (byte) 0x14, (byte) 0x01, (byte) 0xd1, + (byte) 0x54, (byte) 0x01, (byte) 0x51, (byte) 0x15, + (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, + (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x38, + (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x58, + (byte) 0x08, (byte) 0x85, (byte) 0x86, (byte) 0xac, + (byte) 0x08, (byte) 0x00, (byte) 0xe2, (byte) 0x04, + (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10, + (byte) 0x00, (byte) 0x00, (byte) 0x30, (byte) 0xe0, + (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x60, + (byte) 0x42, (byte) 0x19, (byte) 0x28, (byte) 0x34, + (byte) 0x64, (byte) 0x45, (byte) 0x00, (byte) 0x10, + (byte) 0x27, (byte) 0x00, (byte) 0x60, (byte) 0x70, + (byte) 0x1c, (byte) 0xcb, (byte) 0x02, (byte) 0x00, + (byte) 0x00, (byte) 0x47, (byte) 0x92, (byte) 0x34, + (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x1c, + (byte) 0x49, (byte) 0xd2, (byte) 0x34, (byte) 0x00, + (byte) 0x00, (byte) 0xd0, (byte) 0x34, (byte) 0x4d, + (byte) 0x14, (byte) 0x01, (byte) 0x00, (byte) 0xc0, + (byte) 0xd2, (byte) 0x34, (byte) 0x51, (byte) 0x04, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x10, (byte) 0x00, (byte) 0x00, (byte) 0x30, + (byte) 0xe0, (byte) 0x00, (byte) 0x00, (byte) 0x10, + (byte) 0x60, (byte) 0x42, (byte) 0x19, (byte) 0x28, + (byte) 0x34, (byte) 0x64, (byte) 0x25, (byte) 0x00, + (byte) 0x10, (byte) 0x05, (byte) 0x00, (byte) 0x60, + (byte) 0x30, (byte) 0x14, (byte) 0x4d, (byte) 0x03, + (byte) 0x58, (byte) 0x16, (byte) 0xc0, (byte) 0xb2, + (byte) 0x00, (byte) 0x9a, (byte) 0x06, (byte) 0xd0, + (byte) 0x34, (byte) 0x80, (byte) 0xe7, (byte) 0x01, + (byte) 0x3c, (byte) 0x11, (byte) 0x60, (byte) 0x9a, + (byte) 0x00, (byte) 0x40, (byte) 0x00, (byte) 0x00, + (byte) 0x40, (byte) 0x81, (byte) 0x03, (byte) 0x00, + (byte) 0x40, (byte) 0x80, (byte) 0x0d, (byte) 0x9a, + (byte) 0x12, (byte) 0x8b, (byte) 0x03, (byte) 0x14, + (byte) 0x1a, (byte) 0xb2, (byte) 0x12, (byte) 0x00, + (byte) 0x88, (byte) 0x02, (byte) 0x00, (byte) 0x30, + (byte) 0x28, (byte) 0x8a, (byte) 0x24, (byte) 0x59, + (byte) 0x96, (byte) 0xe7, (byte) 0x41, (byte) 0xd3, + (byte) 0x34, (byte) 0x4d, (byte) 0x14, (byte) 0xa1, + (byte) 0x69, (byte) 0x9a, (byte) 0x26, (byte) 0x8a, + (byte) 0xf0, (byte) 0x3c, (byte) 0xcf, (byte) 0x13, + (byte) 0x45, (byte) 0x78, (byte) 0x9e, (byte) 0xe7, + (byte) 0x99, (byte) 0x26, (byte) 0x44, (byte) 0xd1, + (byte) 0xf3, (byte) 0x4c, (byte) 0x13, (byte) 0xa2, + (byte) 0xe8, (byte) 0x79, (byte) 0xa6, (byte) 0x09, + (byte) 0xd3, (byte) 0x14, (byte) 0x45, (byte) 0xd3, + (byte) 0x04, (byte) 0xa2, (byte) 0x68, (byte) 0x9a, + (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x0a, + (byte) 0x1c, (byte) 0x00, (byte) 0x00, (byte) 0x02, + (byte) 0x6c, (byte) 0xd0, (byte) 0x94, (byte) 0x58, + (byte) 0x1c, (byte) 0xa0, (byte) 0xd0, (byte) 0x90, + (byte) 0x95, (byte) 0x00, (byte) 0x40, (byte) 0x48, + (byte) 0x00, (byte) 0x80, (byte) 0x41, (byte) 0x51, + (byte) 0x2c, (byte) 0xcb, (byte) 0xf3, (byte) 0x44, + (byte) 0x51, (byte) 0x14, (byte) 0x4d, (byte) 0x53, + (byte) 0x55, (byte) 0x5d, (byte) 0x17, (byte) 0x9a, + (byte) 0xe6, (byte) 0x79, (byte) 0xa2, (byte) 0x28, + (byte) 0x8a, (byte) 0xa6, (byte) 0xa9, (byte) 0xaa, + (byte) 0xae, (byte) 0x0b, (byte) 0x4d, (byte) 0xf3, + (byte) 0x3c, (byte) 0x51, (byte) 0x14, (byte) 0x45, + (byte) 0xd3, (byte) 0x54, (byte) 0x55, (byte) 0xd7, + (byte) 0x85, (byte) 0xe7, (byte) 0x79, (byte) 0xa2, + (byte) 0x29, (byte) 0x9a, (byte) 0xa6, (byte) 0x69, + (byte) 0xaa, (byte) 0xaa, (byte) 0xeb, (byte) 0xc2, + (byte) 0xf3, (byte) 0x44, (byte) 0xd1, (byte) 0x34, + (byte) 0x4d, (byte) 0x53, (byte) 0x55, (byte) 0x55, + (byte) 0xd7, (byte) 0x75, (byte) 0xe1, (byte) 0x79, + (byte) 0xa2, (byte) 0x68, (byte) 0x9a, (byte) 0xa6, + (byte) 0xa9, (byte) 0xaa, (byte) 0xae, (byte) 0xeb, + (byte) 0xba, (byte) 0xf0, (byte) 0x3c, (byte) 0x51, + (byte) 0x34, (byte) 0x4d, (byte) 0xd3, (byte) 0x54, + (byte) 0x55, (byte) 0xd7, (byte) 0x95, (byte) 0x65, + (byte) 0x88, (byte) 0xa2, (byte) 0x28, (byte) 0x9a, + (byte) 0xa6, (byte) 0x69, (byte) 0xaa, (byte) 0xaa, + (byte) 0xeb, (byte) 0xca, (byte) 0x32, (byte) 0x10, + (byte) 0x45, (byte) 0xd3, (byte) 0x34, (byte) 0x4d, + (byte) 0x55, (byte) 0x75, (byte) 0x5d, (byte) 0x59, + (byte) 0x06, (byte) 0xa2, (byte) 0x68, (byte) 0x9a, + (byte) 0xaa, (byte) 0xea, (byte) 0xba, (byte) 0xae, + (byte) 0x2b, (byte) 0xcb, (byte) 0x40, (byte) 0x14, + (byte) 0x4d, (byte) 0x53, (byte) 0x55, (byte) 0x5d, + (byte) 0xd7, (byte) 0x75, (byte) 0x65, (byte) 0x19, + (byte) 0x98, (byte) 0xa6, (byte) 0x6a, (byte) 0xaa, + (byte) 0xaa, (byte) 0xeb, (byte) 0xca, (byte) 0xb2, + (byte) 0x2c, (byte) 0x03, (byte) 0x4c, (byte) 0x53, + (byte) 0x55, (byte) 0x5d, (byte) 0x57, (byte) 0x96, + (byte) 0x65, (byte) 0x19, (byte) 0xa0, (byte) 0xaa, + (byte) 0xae, (byte) 0xeb, (byte) 0xba, (byte) 0xb2, + (byte) 0x6c, (byte) 0xdb, (byte) 0x00, (byte) 0x55, + (byte) 0x75, (byte) 0x5d, (byte) 0xd7, (byte) 0x95, + (byte) 0x65, (byte) 0xdb, (byte) 0x06, (byte) 0xb8, + (byte) 0xae, (byte) 0xeb, (byte) 0xca, (byte) 0xb2, + (byte) 0x2c, (byte) 0xdb, (byte) 0x36, (byte) 0x00, + (byte) 0xd7, (byte) 0x95, (byte) 0x65, (byte) 0x59, + (byte) 0xb6, (byte) 0x6d, (byte) 0x01, (byte) 0x00, + (byte) 0x00, (byte) 0x07, (byte) 0x0e, (byte) 0x00, + (byte) 0x00, (byte) 0x01, (byte) 0x46, (byte) 0xd0, + (byte) 0x49, (byte) 0x46, (byte) 0x95, (byte) 0x45, + (byte) 0xd8, (byte) 0x68, (byte) 0xc2, (byte) 0x85, + (byte) 0x07, (byte) 0xa0, (byte) 0xd0, (byte) 0x90, + (byte) 0x15, (byte) 0x01, (byte) 0x40, (byte) 0x14, + (byte) 0x00, (byte) 0x00, (byte) 0x60, (byte) 0x8c, + (byte) 0x52, (byte) 0x8a, (byte) 0x29, (byte) 0x65, + (byte) 0x18, (byte) 0x93, (byte) 0x50, (byte) 0x4a, + (byte) 0x09, (byte) 0x0d, (byte) 0x63, (byte) 0x52, + (byte) 0x4a, (byte) 0x2a, (byte) 0xa5, (byte) 0x92, + (byte) 0x92, (byte) 0x52, (byte) 0x4a, (byte) 0xa5, + (byte) 0x54, (byte) 0x12, (byte) 0x52, (byte) 0x4a, + (byte) 0xa9, (byte) 0x94, (byte) 0x4a, (byte) 0x4a, + (byte) 0x4a, (byte) 0x29, (byte) 0x95, (byte) 0x92, + (byte) 0x51, (byte) 0x4a, (byte) 0x29, (byte) 0xb5, + (byte) 0x96, (byte) 0x2a, (byte) 0x29, (byte) 0xa9, + (byte) 0x94, (byte) 0x94, (byte) 0x52, (byte) 0x25, + (byte) 0xa5, (byte) 0xa4, (byte) 0x92, (byte) 0x52, + (byte) 0x2a, (byte) 0x00, (byte) 0x00, (byte) 0xec, + (byte) 0xc0, (byte) 0x01, (byte) 0x00, (byte) 0xec, + (byte) 0xc0, (byte) 0x42, (byte) 0x28, (byte) 0x34, + (byte) 0x64, (byte) 0x25, (byte) 0x00, (byte) 0x90, + (byte) 0x07, (byte) 0x00, (byte) 0x40, (byte) 0x10, + (byte) 0x82, (byte) 0x14, (byte) 0x63, (byte) 0x8c, + (byte) 0x39, (byte) 0x27, (byte) 0xa5, (byte) 0x54, + (byte) 0x8a, (byte) 0x31, (byte) 0xe7, (byte) 0x9c, + (byte) 0x93, (byte) 0x52, (byte) 0x2a, (byte) 0xc5, + (byte) 0x98, (byte) 0x73, (byte) 0xce, (byte) 0x49, + (byte) 0x29, (byte) 0x19, (byte) 0x63, (byte) 0xcc, + (byte) 0x39, (byte) 0xe7, (byte) 0xa4, (byte) 0x94, + (byte) 0x8c, (byte) 0x31, (byte) 0xe6, (byte) 0x9c, + (byte) 0x73, (byte) 0x52, (byte) 0x4a, (byte) 0xc6, + (byte) 0x9c, (byte) 0x73, (byte) 0xce, (byte) 0x39, + (byte) 0x29, (byte) 0x25, (byte) 0x63, (byte) 0xce, + (byte) 0x39, (byte) 0xe7, (byte) 0x9c, (byte) 0x94, + (byte) 0xd2, (byte) 0x39, (byte) 0xe7, (byte) 0x9c, + (byte) 0x83, (byte) 0x50, (byte) 0x4a, (byte) 0x29, + (byte) 0xa5, (byte) 0x73, (byte) 0xce, (byte) 0x41, + (byte) 0x28, (byte) 0xa5, (byte) 0x94, (byte) 0x12, + (byte) 0x42, (byte) 0xe7, (byte) 0x20, (byte) 0x94, + (byte) 0x52, (byte) 0x4a, (byte) 0xe9, (byte) 0x9c, + (byte) 0x73, (byte) 0x10, (byte) 0x0a, (byte) 0x00, + (byte) 0x00, (byte) 0x2a, (byte) 0x70, (byte) 0x00, + (byte) 0x00, (byte) 0x08, (byte) 0xb0, (byte) 0x51, + (byte) 0x64, (byte) 0x73, (byte) 0x82, (byte) 0x91, + (byte) 0xa0, (byte) 0x42, (byte) 0x43, (byte) 0x56, + (byte) 0x02, (byte) 0x00, (byte) 0xa9, (byte) 0x00, + (byte) 0x00, (byte) 0x06, (byte) 0xc7, (byte) 0xb1, + (byte) 0x2c, (byte) 0x4d, (byte) 0xd3, (byte) 0x34, + (byte) 0xcf, (byte) 0x13, (byte) 0x45, (byte) 0x4b, + (byte) 0x92, (byte) 0x34, (byte) 0xcf, (byte) 0x13, + (byte) 0x3d, (byte) 0x4f, (byte) 0x14, (byte) 0x4d, + (byte) 0xd5, (byte) 0x92, (byte) 0x24, (byte) 0xcf, + (byte) 0x13, (byte) 0x45, (byte) 0xcf, (byte) 0x13, + (byte) 0x4d, (byte) 0x53, (byte) 0xe5, (byte) 0x79, + (byte) 0x9e, (byte) 0x28, (byte) 0x8a, (byte) 0xa2, + (byte) 0x68, (byte) 0x9a, (byte) 0xaa, (byte) 0x4a, + (byte) 0x14, (byte) 0x45, (byte) 0x4f, (byte) 0x14, + (byte) 0x45, (byte) 0xd1, (byte) 0x34, (byte) 0x55, + (byte) 0x95, (byte) 0x2c, (byte) 0x8b, (byte) 0xa2, + (byte) 0x69, (byte) 0x9a, (byte) 0xa6, (byte) 0xaa, + (byte) 0xba, (byte) 0x2e, (byte) 0x5b, (byte) 0x16, + (byte) 0x45, (byte) 0xd3, (byte) 0x34, (byte) 0x4d, + (byte) 0x55, (byte) 0x75, (byte) 0x5d, (byte) 0x98, + (byte) 0xa6, (byte) 0x28, (byte) 0xaa, (byte) 0xaa, + (byte) 0xeb, (byte) 0xca, (byte) 0x2e, (byte) 0x4c, + (byte) 0x53, (byte) 0x14, (byte) 0x4d, (byte) 0xd3, + (byte) 0x75, (byte) 0x65, (byte) 0x19, (byte) 0xb2, + (byte) 0xad, (byte) 0x9a, (byte) 0xaa, (byte) 0xea, + (byte) 0xba, (byte) 0xb2, (byte) 0x0d, (byte) 0xdb, + (byte) 0x36, (byte) 0x4d, (byte) 0x55, (byte) 0x75, + (byte) 0x5d, (byte) 0x59, (byte) 0x06, (byte) 0xae, + (byte) 0xeb, (byte) 0xba, (byte) 0xb2, (byte) 0x6c, + (byte) 0xeb, (byte) 0xc0, (byte) 0x75, (byte) 0x5d, + (byte) 0x57, (byte) 0x96, (byte) 0x6d, (byte) 0x5d, + (byte) 0x00, (byte) 0x00, (byte) 0x78, (byte) 0x82, + (byte) 0x03, (byte) 0x00, (byte) 0x50, (byte) 0x81, + (byte) 0x0d, (byte) 0xab, (byte) 0x23, (byte) 0x9c, + (byte) 0x14, (byte) 0x8d, (byte) 0x05, (byte) 0x16, + (byte) 0x1a, (byte) 0xb2, (byte) 0x12, (byte) 0x00, + (byte) 0xc8, (byte) 0x00, (byte) 0x00, (byte) 0x20, + (byte) 0x08, (byte) 0x41, (byte) 0x48, (byte) 0x29, + (byte) 0x85, (byte) 0x90, (byte) 0x52, (byte) 0x0a, + (byte) 0x21, (byte) 0xa5, (byte) 0x14, (byte) 0x42, + (byte) 0x4a, (byte) 0x29, (byte) 0x84, (byte) 0x04, + (byte) 0x00, (byte) 0x00, (byte) 0x0c, (byte) 0x38, + (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x98, + (byte) 0x50, (byte) 0x06, (byte) 0x0a, (byte) 0x0d, + (byte) 0x59, (byte) 0x09, (byte) 0x00, (byte) 0xa4, + (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x10, + (byte) 0x42, (byte) 0x08, (byte) 0x21, (byte) 0x84, + (byte) 0x10, (byte) 0x42, (byte) 0x08, (byte) 0x21, + (byte) 0x84, (byte) 0x10, (byte) 0x42, (byte) 0x08, + (byte) 0x21, (byte) 0x84, (byte) 0x10, (byte) 0x42, + (byte) 0x08, (byte) 0x21, (byte) 0x84, (byte) 0x10, + (byte) 0x42, (byte) 0x08, (byte) 0x21, (byte) 0x84, + (byte) 0x10, (byte) 0x42, (byte) 0x08, (byte) 0x21, + (byte) 0x84, (byte) 0x10, (byte) 0x42, (byte) 0x08, + (byte) 0x21, (byte) 0x84, (byte) 0x10, (byte) 0x42, + (byte) 0x08, (byte) 0x21, (byte) 0x84, (byte) 0x10, + (byte) 0x42, (byte) 0x08, (byte) 0x21, (byte) 0x84, + (byte) 0x10, (byte) 0x42, (byte) 0x08, (byte) 0x21, + (byte) 0x84, (byte) 0xce, (byte) 0x39, (byte) 0xe7, + (byte) 0x9c, (byte) 0x73, (byte) 0xce, (byte) 0x39, + (byte) 0xe7, (byte) 0x9c, (byte) 0x73, (byte) 0xce, + (byte) 0x39, (byte) 0xe7, (byte) 0x9c, (byte) 0x73, + (byte) 0xce, (byte) 0x39, (byte) 0xe7, (byte) 0x9c, + (byte) 0x73, (byte) 0xce, (byte) 0x39, (byte) 0xe7, + (byte) 0x9c, (byte) 0x73, (byte) 0xce, (byte) 0x39, + (byte) 0xe7, (byte) 0x9c, (byte) 0x73, (byte) 0xce, + (byte) 0x39, (byte) 0xe7, (byte) 0x9c, (byte) 0x73, + (byte) 0xce, (byte) 0x39, (byte) 0xe7, (byte) 0x9c, + (byte) 0x73, (byte) 0xce, (byte) 0x39, (byte) 0xe7, + (byte) 0x9c, (byte) 0x73, (byte) 0xce, (byte) 0x39, + (byte) 0xe7, (byte) 0x9c, (byte) 0x73, (byte) 0xce, + (byte) 0x39, (byte) 0xe7, (byte) 0x9c, (byte) 0x73, + (byte) 0x02, (byte) 0x00, (byte) 0xb1, (byte) 0x2b, + (byte) 0x1c, (byte) 0x00, (byte) 0x76, (byte) 0x22, + (byte) 0x6c, (byte) 0x58, (byte) 0x1d, (byte) 0xe1, + (byte) 0xa4, (byte) 0x68, (byte) 0x2c, (byte) 0xb0, + (byte) 0xd0, (byte) 0x90, (byte) 0x95, (byte) 0x00, + (byte) 0x40, (byte) 0x38, (byte) 0x00, (byte) 0x00, + (byte) 0x60, (byte) 0x8c, (byte) 0x31, (byte) 0xce, + (byte) 0x59, (byte) 0xac, (byte) 0xb5, (byte) 0xd6, + (byte) 0x5a, (byte) 0x2b, (byte) 0xa5, (byte) 0x94, + (byte) 0x92, (byte) 0x50, (byte) 0x6b, (byte) 0xad, + (byte) 0xb5, (byte) 0xd6, (byte) 0x9a, (byte) 0x29, + (byte) 0xa4, (byte) 0x94, (byte) 0x84, (byte) 0x16, + (byte) 0x63, (byte) 0x8c, (byte) 0x31, (byte) 0xc6, + (byte) 0x98, (byte) 0x31, (byte) 0x08, (byte) 0x29, + (byte) 0xb5, (byte) 0x18, (byte) 0x63, (byte) 0x8c, + (byte) 0x31, (byte) 0xc6, (byte) 0x8c, (byte) 0x39, + (byte) 0x47, (byte) 0x2d, (byte) 0xc6, (byte) 0x18, + (byte) 0x63, (byte) 0x8c, (byte) 0x31, (byte) 0xb6, + (byte) 0x56, (byte) 0x4a, (byte) 0x6c, (byte) 0x31, + (byte) 0xc6, (byte) 0x18, (byte) 0x63, (byte) 0x8c, + (byte) 0xb1, (byte) 0xb5, (byte) 0x52, (byte) 0x62, + (byte) 0x8c, (byte) 0x31, (byte) 0xc6, (byte) 0x18, + (byte) 0x63, (byte) 0x8c, (byte) 0x31, (byte) 0xc6, + (byte) 0x16, (byte) 0x5b, (byte) 0x8c, (byte) 0x31, + (byte) 0xc6, (byte) 0x18, (byte) 0x63, (byte) 0x8c, + (byte) 0x31, (byte) 0xb6, (byte) 0x18, (byte) 0x63, + (byte) 0x8c, (byte) 0x31, (byte) 0xc6, (byte) 0x18, + (byte) 0x63, (byte) 0x8c, (byte) 0x31, (byte) 0xc6, + (byte) 0x18, (byte) 0x63, (byte) 0x8c, (byte) 0x31, + (byte) 0xc6, (byte) 0x18, (byte) 0x63, (byte) 0x8c, + (byte) 0x31, (byte) 0xb6, (byte) 0x18, (byte) 0x63, + (byte) 0x8c, (byte) 0x31, (byte) 0xc6, (byte) 0x18, + (byte) 0x63, (byte) 0x8c, (byte) 0x31, (byte) 0xc6, + (byte) 0x18, (byte) 0x63, (byte) 0x8c, (byte) 0x31, + (byte) 0xc6, (byte) 0x18, (byte) 0x63, (byte) 0x8c, + (byte) 0x31, (byte) 0xc6, (byte) 0x18, (byte) 0x63, + (byte) 0x8c, (byte) 0x31, (byte) 0xc6, (byte) 0x18, + (byte) 0x63, (byte) 0x6c, (byte) 0x31, (byte) 0xc6, + (byte) 0x18, (byte) 0x63, (byte) 0x8c, (byte) 0x31, + (byte) 0xc6, (byte) 0x18, (byte) 0x63, (byte) 0x8c, + (byte) 0x31, (byte) 0xc6, (byte) 0x18, (byte) 0x63, + (byte) 0x2c, (byte) 0x00, (byte) 0xc0, (byte) 0xe4, + (byte) 0xc1, (byte) 0x01, (byte) 0x00, (byte) 0x2a, + (byte) 0xc1, (byte) 0xc6, (byte) 0x19, (byte) 0x56, + (byte) 0x92, (byte) 0xce, (byte) 0x0a, (byte) 0x47, + (byte) 0x83, (byte) 0x0b, (byte) 0x0d, (byte) 0x59, + (byte) 0x09, (byte) 0x00, (byte) 0xe4, (byte) 0x06, + (byte) 0x00, (byte) 0x00, (byte) 0xc6, (byte) 0x28, + (byte) 0xc5, (byte) 0x98, (byte) 0x63, (byte) 0xce, + (byte) 0x41, (byte) 0x08, (byte) 0xa1, (byte) 0x94, + (byte) 0x12, (byte) 0x4a, (byte) 0x49, (byte) 0xad, + (byte) 0x75, (byte) 0xce, (byte) 0x39, (byte) 0x08, + (byte) 0x21, (byte) 0x94, (byte) 0x52, (byte) 0x4a, + (byte) 0x49, (byte) 0xa9, (byte) 0xb4, (byte) 0x94, + (byte) 0x62, (byte) 0xca, (byte) 0x98, (byte) 0x73, + (byte) 0xce, (byte) 0x41, (byte) 0x08, (byte) 0xa5, + (byte) 0x94, (byte) 0x12, (byte) 0x4a, (byte) 0x49, + (byte) 0xa9, (byte) 0xa5, (byte) 0xd4, (byte) 0x39, + (byte) 0xe7, (byte) 0x20, (byte) 0x94, (byte) 0x52, + (byte) 0x4a, (byte) 0x4a, (byte) 0x29, (byte) 0xa5, + (byte) 0x94, (byte) 0x5a, (byte) 0x6a, (byte) 0xad, + (byte) 0x73, (byte) 0x10, (byte) 0x42, (byte) 0x08, + (byte) 0xa5, (byte) 0x94, (byte) 0x52, (byte) 0x4a, + (byte) 0x4a, (byte) 0x29, (byte) 0xa5, (byte) 0xd4, + (byte) 0x52, (byte) 0x08, (byte) 0x21, (byte) 0x94, + (byte) 0x52, (byte) 0x4a, (byte) 0x2a, (byte) 0x29, + (byte) 0xa5, (byte) 0x94, (byte) 0x52, (byte) 0x6b, + (byte) 0xad, (byte) 0xa5, (byte) 0x10, (byte) 0x42, + (byte) 0x28, (byte) 0xa5, (byte) 0x94, (byte) 0x94, + (byte) 0x52, (byte) 0x4a, (byte) 0x29, (byte) 0xa5, + (byte) 0xd4, (byte) 0x5a, (byte) 0x8b, (byte) 0xa1, + (byte) 0x94, (byte) 0x90, (byte) 0x4a, (byte) 0x29, + (byte) 0x25, (byte) 0xa5, (byte) 0x94, (byte) 0x52, + (byte) 0x49, (byte) 0x2d, (byte) 0xb5, (byte) 0x96, + (byte) 0x5a, (byte) 0x2a, (byte) 0xa1, (byte) 0x94, + (byte) 0x54, (byte) 0x52, (byte) 0x4a, (byte) 0x29, + (byte) 0xa5, (byte) 0x94, (byte) 0x52, (byte) 0x6b, + (byte) 0xa9, (byte) 0xb5, (byte) 0x56, (byte) 0x4a, + (byte) 0x49, (byte) 0x25, (byte) 0xa5, (byte) 0x94, + (byte) 0x52, (byte) 0x4a, (byte) 0x29, (byte) 0xa5, + (byte) 0xd4, (byte) 0x62, (byte) 0x6b, (byte) 0x29, + (byte) 0x94, (byte) 0x92, (byte) 0x52, (byte) 0x49, + (byte) 0x29, (byte) 0xb5, (byte) 0x94, (byte) 0x52, + (byte) 0x4a, (byte) 0xad, (byte) 0xc5, (byte) 0xd8, + (byte) 0x62, (byte) 0x29, (byte) 0xad, (byte) 0xa4, + (byte) 0x94, (byte) 0x52, (byte) 0x4a, (byte) 0x29, + (byte) 0xa5, (byte) 0xd6, (byte) 0x52, (byte) 0x6c, + (byte) 0xad, (byte) 0xb5, (byte) 0xd8, (byte) 0x52, + (byte) 0x4a, (byte) 0x29, (byte) 0xa5, (byte) 0x96, + (byte) 0x5a, (byte) 0x4a, (byte) 0x29, (byte) 0xb5, + (byte) 0x16, (byte) 0x5b, (byte) 0x6a, (byte) 0x2d, + (byte) 0xa5, (byte) 0x94, (byte) 0x52, (byte) 0x4b, + (byte) 0x29, (byte) 0xa5, (byte) 0x96, (byte) 0x52, + (byte) 0x4b, (byte) 0x2d, (byte) 0xc6, (byte) 0xd6, + (byte) 0x5a, (byte) 0x4b, (byte) 0x29, (byte) 0xa5, + (byte) 0xd4, (byte) 0x52, (byte) 0x6a, (byte) 0xa9, + (byte) 0xa5, (byte) 0x94, (byte) 0x52, (byte) 0x6c, + (byte) 0xad, (byte) 0xb5, (byte) 0x98, (byte) 0x52, + (byte) 0x6a, (byte) 0x2d, (byte) 0xa5, (byte) 0xd4, + (byte) 0x52, (byte) 0x6b, (byte) 0x2d, (byte) 0xb5, + (byte) 0xd8, (byte) 0x52, (byte) 0x6a, (byte) 0x2d, + (byte) 0xb5, (byte) 0x94, (byte) 0x52, (byte) 0x6b, + (byte) 0xa9, (byte) 0xa5, (byte) 0x94, (byte) 0x5a, + (byte) 0x6b, (byte) 0x2d, (byte) 0xb6, (byte) 0xd8, + (byte) 0x5a, (byte) 0x6b, (byte) 0x29, (byte) 0xb5, + (byte) 0x94, (byte) 0x52, (byte) 0x4a, (byte) 0xa9, + (byte) 0xb5, (byte) 0x16, (byte) 0x5b, (byte) 0x8a, + (byte) 0xb1, (byte) 0xb5, (byte) 0xd4, (byte) 0x4a, + (byte) 0x4a, (byte) 0x29, (byte) 0xb5, (byte) 0xd4, + (byte) 0x5a, (byte) 0x6a, (byte) 0x2d, (byte) 0xb6, + (byte) 0x16, (byte) 0x5b, (byte) 0x6b, (byte) 0xad, + (byte) 0xa5, (byte) 0xd6, (byte) 0x5a, (byte) 0x6a, + (byte) 0x29, (byte) 0xa5, (byte) 0x16, (byte) 0x5b, + (byte) 0x8c, (byte) 0x31, (byte) 0xc6, (byte) 0x16, + (byte) 0x63, (byte) 0x6b, (byte) 0x31, (byte) 0xa5, + (byte) 0x94, (byte) 0x52, (byte) 0x4b, (byte) 0xa9, + (byte) 0xa5, (byte) 0x02, (byte) 0x00, (byte) 0x80, + (byte) 0x0e, (byte) 0x1c, (byte) 0x00, (byte) 0x00, + (byte) 0x02, (byte) 0x8c, (byte) 0xa8, (byte) 0xb4, + (byte) 0x10, (byte) 0x3b, (byte) 0xcd, (byte) 0xb8, + (byte) 0xf2, (byte) 0x08, (byte) 0x1c, (byte) 0x51, + (byte) 0xc8, (byte) 0x30, (byte) 0x01, (byte) 0x15, + (byte) 0x1a, (byte) 0xb2, (byte) 0x12, (byte) 0x00, + (byte) 0x20, (byte) 0x03, (byte) 0x00, (byte) 0x20, + (byte) 0x90, (byte) 0x69, (byte) 0x92, (byte) 0x39, + (byte) 0x49, (byte) 0xa9, (byte) 0x11, (byte) 0x26, + (byte) 0x39, (byte) 0xc5, (byte) 0xa0, (byte) 0x94, + (byte) 0xe6, (byte) 0x9c, (byte) 0x53, (byte) 0x4a, + (byte) 0x29, (byte) 0xa5, (byte) 0x34, (byte) 0x44, + (byte) 0x96, (byte) 0x64, (byte) 0x90, (byte) 0x62, + (byte) 0x50, (byte) 0x1d, (byte) 0x99, (byte) 0x8c, + (byte) 0x39, (byte) 0x49, (byte) 0x39, (byte) 0x43, + (byte) 0xa4, (byte) 0x31, (byte) 0xa4, (byte) 0x20, + (byte) 0xf5, (byte) 0x4c, (byte) 0x91, (byte) 0xc7, + (byte) 0x94, (byte) 0x62, (byte) 0x10, (byte) 0x43, + (byte) 0x48, (byte) 0x2a, (byte) 0x74, (byte) 0x8a, + (byte) 0x39, (byte) 0x6c, (byte) 0x35, (byte) 0xf9, + (byte) 0x58, (byte) 0x42, (byte) 0x07, (byte) 0xb1, + (byte) 0x06, (byte) 0x65, (byte) 0x8c, (byte) 0x70, + (byte) 0x29, (byte) 0xc5, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x08, (byte) 0x02, (byte) 0x00, + (byte) 0x04, (byte) 0x84, (byte) 0x04, (byte) 0x00, + (byte) 0x18, (byte) 0x20, (byte) 0x28, (byte) 0x98, + (byte) 0x01, (byte) 0x00, (byte) 0x06, (byte) 0x07, + (byte) 0x08, (byte) 0x23, (byte) 0x07, (byte) 0x02, + (byte) 0x1d, (byte) 0x01, (byte) 0x04, (byte) 0x0e, + (byte) 0x6d, (byte) 0x00, (byte) 0x80, (byte) 0x81, + (byte) 0x08, (byte) 0x99, (byte) 0x09, (byte) 0x0c, + (byte) 0x0a, (byte) 0xa1, (byte) 0xc1, (byte) 0x41, + (byte) 0x26, (byte) 0x00, (byte) 0x3c, (byte) 0x40, + (byte) 0x44, (byte) 0x48, (byte) 0x05, (byte) 0x00, + (byte) 0x89, (byte) 0x09, (byte) 0x8a, (byte) 0xd2, + (byte) 0x85, (byte) 0x2e, (byte) 0x08, (byte) 0x21, + (byte) 0x82, (byte) 0x74, (byte) 0x11, (byte) 0x64, + (byte) 0xf1, (byte) 0xc0, (byte) 0x85, (byte) 0x13, + (byte) 0x37, (byte) 0x9e, (byte) 0xb8, (byte) 0xe1, + (byte) 0x84, (byte) 0x0e, (byte) 0x6d, (byte) 0x20, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0xf0, + (byte) 0x01, (byte) 0x00, (byte) 0x90, (byte) 0x50, + (byte) 0x00, (byte) 0x11, (byte) 0x11, (byte) 0xd1, + (byte) 0xcc, (byte) 0x55, (byte) 0x58, (byte) 0x5c, + (byte) 0x60, (byte) 0x64, (byte) 0x68, (byte) 0x6c, + (byte) 0x70, (byte) 0x74, (byte) 0x78, (byte) 0x7c, + (byte) 0x80, (byte) 0x84, (byte) 0x08, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x10, (byte) 0x00, (byte) 0x7c, (byte) 0x00, + (byte) 0x00, (byte) 0x24, (byte) 0x22, (byte) 0x40, + (byte) 0x44, (byte) 0x44, (byte) 0x34, (byte) 0x73, + (byte) 0x15, (byte) 0x16, (byte) 0x17, (byte) 0x18, + (byte) 0x19, (byte) 0x1a, (byte) 0x1b, (byte) 0x1c, + (byte) 0x1d, (byte) 0x1e, (byte) 0x1f, (byte) 0x20, + (byte) 0x21, (byte) 0x01, (byte) 0x00, (byte) 0x80, + (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x20, (byte) 0x80, + (byte) 0x00, (byte) 0x04, (byte) 0x04, (byte) 0x04, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x04, (byte) 0x04 + }; + +} diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisBitArrayTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisBitArrayTest.java new file mode 100644 index 0000000000..954b7f39fc --- /dev/null +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisBitArrayTest.java @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer.extractor.ogg; + +import com.google.android.exoplayer.ParserException; +import com.google.android.exoplayer.util.ParsableBitArray; + +import junit.framework.TestCase; + +/** + * Unit test for {@link VorbisBitArray}. + */ +public final class VorbisBitArrayTest extends TestCase { + + public void testReadBit() throws ParserException { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + (byte) 0x5c, 0x50 + }); + + assertFalse(bitArray.readBit()); + assertFalse(bitArray.readBit()); + assertTrue(bitArray.readBit()); + assertTrue(bitArray.readBit()); + + assertTrue(bitArray.readBit()); + assertFalse(bitArray.readBit()); + assertTrue(bitArray.readBit()); + assertFalse(bitArray.readBit()); + + assertFalse(bitArray.readBit()); + assertFalse(bitArray.readBit()); + assertFalse(bitArray.readBit()); + assertFalse(bitArray.readBit()); + + assertTrue(bitArray.readBit()); + assertFalse(bitArray.readBit()); + assertTrue(bitArray.readBit()); + assertFalse(bitArray.readBit()); + + try { + assertFalse(bitArray.readBit()); + fail(); + } catch (IllegalStateException e) {/* ignored */} + } + + public void testSkipBits() throws ParserException { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + (byte) 0xF0, 0x0F + }); + + bitArray.skipBits(10); + assertEquals(10, bitArray.getPosition()); + assertTrue(bitArray.readBit()); + assertTrue(bitArray.readBit()); + assertFalse(bitArray.readBit()); + bitArray.skipBits(1); + assertEquals(14, bitArray.getPosition()); + assertFalse(bitArray.readBit()); + assertFalse(bitArray.readBit()); + try { + bitArray.readBit(); + fail(); + } catch (IllegalStateException e) { + // ignored + } + } + + + public void testSkipBitsThrowsErrorIfEOB() throws ParserException { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + (byte) 0xF0, 0x0F + }); + + try { + bitArray.skipBits(17); + fail(); + } catch (IllegalStateException e) {/* ignored */} + } + + public void testGetPosition() throws Exception { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + (byte) 0xF0, 0x0F + }); + + assertEquals(0, bitArray.getPosition()); + bitArray.readBit(); + assertEquals(1, bitArray.getPosition()); + bitArray.readBit(); + bitArray.readBit(); + bitArray.skipBits(4); + assertEquals(7, bitArray.getPosition()); + } + + public void testSetPosition() throws Exception { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + (byte) 0xF0, 0x0F + }); + + assertEquals(0, bitArray.getPosition()); + bitArray.setPosition(4); + assertEquals(4, bitArray.getPosition()); + + bitArray.setPosition(15); + assertFalse(bitArray.readBit()); + try { + bitArray.readBit(); + fail(); + } catch (IllegalStateException e) {/* ignored */} + + } + public void testSetPositionIllegalPositions() throws Exception { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + (byte) 0xF0, 0x0F + }); + + try { + bitArray.setPosition(16); + fail(); + } catch (IllegalArgumentException e) { + assertEquals(0, bitArray.getPosition()); + } + + try { + bitArray.setPosition(-1); + fail(); + } catch (IllegalArgumentException e) { + assertEquals(0, bitArray.getPosition()); + } + } + + public void testReadInt32() throws ParserException { + byte[] data = {(byte) 0xF0, 0x0F, (byte) 0xF0, 0x0F}; + VorbisBitArray lsb = new VorbisBitArray(data); + assertEquals(0x0FF00FF0, lsb.readBits(32)); + + data = new byte[]{0x0F, (byte) 0xF0, 0x0F, (byte) 0xF0}; + lsb = new VorbisBitArray(data); + assertEquals(0xF00FF00F, lsb.readBits(32)); + } + + public void testReadBits() throws Exception { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + (byte) 0x03, 0x22 + }); + + assertEquals(3, bitArray.readBits(2)); + bitArray.skipBits(6); + assertEquals(2, bitArray.readBits(2)); + bitArray.skipBits(2); + assertEquals(2, bitArray.readBits(2)); + + bitArray.reset(); + assertEquals(0x2203, bitArray.readBits(16)); + } + + public void testRead4BitsBeyondBoundary() throws Exception { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + 0x2e, 0x10 + }); + assertEquals(0x2e, bitArray.readBits(7)); + assertEquals(7, bitArray.getPosition()); + assertEquals(0x0, bitArray.readBits(4)); + } + + public void testReadBitsBeyondByteBoundaries() throws Exception { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + (byte) 0xFF, (byte) 0x0F, (byte) 0xFF, (byte) 0x0F + }); + + assertEquals(0x0FFF0FFF, bitArray.readBits(32)); + + bitArray.reset(); + bitArray.skipBits(4); + assertEquals(0xF0FF, bitArray.readBits(16)); + + bitArray.reset(); + bitArray.skipBits(6); + assertEquals(0xc3F, bitArray.readBits(12)); + + bitArray.reset(); + bitArray.skipBits(6); + assertTrue(bitArray.readBit()); + assertTrue(bitArray.readBit()); + assertEquals(24, bitArray.bitsLeft()); + + bitArray.reset(); + bitArray.skipBits(10); + assertEquals(3, bitArray.readBits(5)); + assertEquals(15, bitArray.getPosition()); + } + + public void testReadBitsIllegalLengths() throws Exception { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + (byte) 0x03, 0x22, 0x30 + }); + + // reading zero bits gets 0 without advancing position + // (like a zero-bit read is defined to yield zer0) + assertEquals(0, bitArray.readBits(0)); + assertEquals(0, bitArray.getPosition()); + bitArray.readBit(); + assertEquals(1, bitArray.getPosition()); + + try { + bitArray.readBits(24); + fail(); + } catch (IllegalStateException e) { + assertEquals(1, bitArray.getPosition()); + } + } + + public void testLimit() throws ParserException { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + (byte) 0xc0, 0x02 + }, 1); + + try { + bitArray.skipBits(9); + fail(); + } catch (IllegalStateException e) { + assertEquals(0, bitArray.getPosition()); + } + + try { + bitArray.readBits(9); + fail(); + } catch (IllegalStateException e) { + assertEquals(0, bitArray.getPosition()); + } + + bitArray.readBits(8); + assertEquals(8, bitArray.getPosition()); + try { + bitArray.readBit(); + fail(); + } catch (IllegalStateException e) { + assertEquals(8, bitArray.getPosition()); + } + } + + public void testBitsLeft() throws ParserException { + VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ + (byte) 0xc0, 0x02 + }); + assertEquals(16, bitArray.bitsLeft()); + assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); + + bitArray.skipBits(1); + assertEquals(15, bitArray.bitsLeft()); + assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); + + bitArray.skipBits(3); + assertEquals(12, bitArray.bitsLeft()); + assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); + + bitArray.setPosition(6); + assertEquals(10, bitArray.bitsLeft()); + assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); + + bitArray.readBit(); + assertEquals(9, bitArray.bitsLeft()); + assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); + + bitArray.readBits(1); + assertEquals(8, bitArray.bitsLeft()); + assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); + + bitArray.readBits(4); + assertEquals(4, bitArray.bitsLeft()); + assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); + + bitArray.readBits(4); + assertEquals(0, bitArray.bitsLeft()); + assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); + + try { + bitArray.readBit(); + fail(); + } catch (IllegalStateException e) { + assertEquals(0, bitArray.bitsLeft()); + } + } + + public void testReadBitCompareWithMSb() throws ParserException { + byte[] data = {0x0F}; + VorbisBitArray lsb = new VorbisBitArray(data); + ParsableBitArray msb = new ParsableBitArray(data); + + assertEquals(lsb.readBit(), !msb.readBit()); + assertEquals(lsb.readBit(), !msb.readBit()); + assertEquals(lsb.readBit(), !msb.readBit()); + assertEquals(lsb.readBit(), !msb.readBit()); + assertEquals(lsb.readBit(), !msb.readBit()); + assertEquals(lsb.readBit(), !msb.readBit()); + assertEquals(lsb.readBit(), !msb.readBit()); + assertEquals(lsb.readBit(), !msb.readBit()); + } + + public void testReadBitsCompareWithMSb() throws ParserException { + byte[] data = {0x0F}; + VorbisBitArray lsb = new VorbisBitArray(data); + ParsableBitArray msb = new ParsableBitArray(data); + + assertEquals(15, lsb.readBits(4)); + assertEquals(lsb.readBits(4), msb.readBits(4)); + assertEquals(15, msb.readBits(4)); + } + + public void testReadBitsCompareWithMSbBeyondByteBoundary() throws ParserException { + byte[] data = {(byte) 0xF0, 0x0F}; + VorbisBitArray lsb = new VorbisBitArray(data); + ParsableBitArray msb = new ParsableBitArray(data); + + assertEquals(0x00, lsb.readBits(4)); + assertEquals(0x0F, msb.readBits(4)); + + assertEquals(0xFF, lsb.readBits(8)); + assertEquals(0x00, msb.readBits(8)); + + assertEquals(0x00, lsb.readBits(4)); + assertEquals(0x0F, msb.readBits(4)); + } + +} diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisUtilTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisUtilTest.java new file mode 100644 index 0000000000..7bd17fb65a --- /dev/null +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisUtilTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer.extractor.ogg; + +import com.google.android.exoplayer.ParserException; +import com.google.android.exoplayer.util.ParsableByteArray; + +import junit.framework.TestCase; + +/** + * Unit test for {@link VorbisUtil}. + */ +public final class VorbisUtilTest extends TestCase { + + public void testILog() throws Exception { + assertEquals(0, VorbisUtil.iLog(0)); + assertEquals(1, VorbisUtil.iLog(1)); + assertEquals(2, VorbisUtil.iLog(2)); + assertEquals(2, VorbisUtil.iLog(3)); + assertEquals(3, VorbisUtil.iLog(4)); + assertEquals(3, VorbisUtil.iLog(5)); + assertEquals(4, VorbisUtil.iLog(8)); + + assertEquals(0, VorbisUtil.iLog(-1)); + assertEquals(0, VorbisUtil.iLog(-122)); + } + + public void testReadBits() throws Exception { + assertEquals(0, VorbisUtil.readBits((byte) 0x00, 2, 2)); + assertEquals(1, VorbisUtil.readBits((byte) 0x02, 1, 1)); + assertEquals(15, VorbisUtil.readBits((byte) 0xF0, 4, 4)); + assertEquals(1, VorbisUtil.readBits((byte) 0x80, 1, 7)); + } + + public void testReadIdHeader() throws Exception { + byte[] data = TestData.getIdentificationHeaderData(); + ParsableByteArray headerData = new ParsableByteArray(data, data.length); + + VorbisUtil.VorbisIdHeader vorbisIdHeader = + VorbisUtil.readVorbisIdentificationHeader(headerData); + + assertEquals(22050, vorbisIdHeader.sampleRate); + assertEquals(0, vorbisIdHeader.version); + assertTrue(vorbisIdHeader.framingFlag); + assertEquals(2, vorbisIdHeader.channels); + assertEquals(512, vorbisIdHeader.blockSize0); + assertEquals(1024, vorbisIdHeader.blockSize1); + assertEquals(-1, vorbisIdHeader.bitrateMax); + assertEquals(-1, vorbisIdHeader.bitrateMin); + assertEquals(66666, vorbisIdHeader.bitrateNominal); + assertEquals(66666, vorbisIdHeader.getApproximateBitrate()); + } + + public void testReadCommentHeader() throws ParserException { + byte[] data = TestData.getCommentHeaderDataUTF8(); + ParsableByteArray headerData = new ParsableByteArray(data, data.length); + + VorbisUtil.CommentHeader commentHeader = VorbisUtil.readVorbisCommentHeader(headerData); + assertEquals("Xiph.Org libVorbis I 20120203 (Omnipresent)", commentHeader.vendor); + assertEquals(3, commentHeader.comments.length); + assertEquals("ALBUM=รครถ", commentHeader.comments[0]); + assertEquals("TITLE=A sample song", commentHeader.comments[1]); + assertEquals("ARTIST=Google", commentHeader.comments[2]); + } + + public void testReadVorbisModes() throws ParserException { + byte[] data = TestData.getSetupHeaderData(); + ParsableByteArray headerData = new ParsableByteArray(data, data.length); + + VorbisUtil.Mode[] modes = VorbisUtil.readVorbisModes(headerData, 2); + + assertEquals(2, modes.length); + + assertEquals(false, modes[0].blockFlag); + assertEquals(0, modes[0].mapping); + assertEquals(0, modes[0].transformType); + assertEquals(0, modes[0].windowType); + + assertEquals(true, modes[1].blockFlag); + assertEquals(1, modes[1].mapping); + assertEquals(0, modes[1].transformType); + assertEquals(0, modes[1].windowType); + } + +} diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java b/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java index e13bb16422..2033b7b4bc 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java @@ -154,6 +154,13 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe } catch (ClassNotFoundException e) { // Extractor not found. } + try { + DEFAULT_EXTRACTOR_CLASSES.add( + Class.forName("com.google.android.exoplayer.extractor.ogg.OggVorbisExtractor") + .asSubclass(Extractor.class)); + } catch (ClassNotFoundException e) { + // Extractor not found. + } } private final ExtractorHolder extractorHolder; diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ogg/OggReader.java b/library/src/main/java/com/google/android/exoplayer/extractor/ogg/OggReader.java new file mode 100644 index 0000000000..b913aed4c9 --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ogg/OggReader.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer.extractor.ogg; + +import com.google.android.exoplayer.ParserException; +import com.google.android.exoplayer.extractor.ExtractorInput; +import com.google.android.exoplayer.util.Assertions; +import com.google.android.exoplayer.util.ParsableByteArray; +import com.google.android.exoplayer.util.Util; + +import java.io.IOException; + +/** + * Reads OGG packets from an {@link ExtractorInput}. + */ +/* package */ final class OggReader { + + private static final String CAPTURE_PATTERN_PAGE = "OggS"; + + private final PageHeader pageHeader = new PageHeader(); + private final ParsableByteArray headerArray = new ParsableByteArray(27 + 255); + + private int currentSegmentIndex = -1; + + /** + * Resets this reader. + */ + public void reset() { + pageHeader.reset(); + headerArray.reset(); + currentSegmentIndex = -1; + } + + /** + * Reads the next packet of the ogg stream. In case of an {@code IOException} the caller must make + * sure to pass the same instance of {@code ParsableByteArray} to this method again so this reader + * can resume properly from an error while reading a continued packet spanned across multiple + * pages. + * + * @param input the {@link ExtractorInput} to read data from. + * @param packetArray the {@link ParsableByteArray} to write the packet data into. + * @return {@code true} if the read was successful. {@code false} if the end of the input was + * encountered having read no data. + * @throws IOException thrown if reading from the input fails. + * @throws InterruptedException thrown if interrupted while reading from input. + */ + public boolean readPacket(ExtractorInput input, ParsableByteArray packetArray) + throws IOException, InterruptedException { + Assertions.checkState(input != null && packetArray != null); + + boolean packetComplete = false; + while (!packetComplete) { + if (currentSegmentIndex < 0) { + // We're at the start of a page. + if (!populatePageHeader(input, pageHeader, headerArray, false)) { + return false; + } + currentSegmentIndex = 0; + } + + int packetSize = 0; + int segmentIndex = currentSegmentIndex; + // add up packetSize from laces + while (segmentIndex < pageHeader.pageSegmentCount) { + int segmentLength = pageHeader.laces[segmentIndex++]; + packetSize += segmentLength; + if (segmentLength != 255) { + // packets end at first lace < 255 + break; + } + } + + if (packetSize > 0) { + input.readFully(packetArray.data, packetArray.limit(), packetSize); + packetArray.setLimit(packetArray.limit() + packetSize); + packetComplete = pageHeader.laces[segmentIndex - 1] != 255; + } + // advance now since we are sure reading didn't throw an exception + currentSegmentIndex = segmentIndex == pageHeader.pageSegmentCount ? -1 : segmentIndex; + } + return true; + } + + /** + * Returns the {@link OggReader.PageHeader} of the current page. The header might not have been + * populated if the first packet has yet to be read. + *
+ * Note that there is only a single instance of {@code OggReader.PageHeader} which is mutable.
+ * The value of the fields might be changed by the reader when reading the stream advances and
+ * the next page is read (which implies reading and populating the next header).
+ *
+ * @return the {@code PageHeader} of the current page or {@code null}.
+ */
+ public PageHeader getPageHeader() {
+ return pageHeader;
+ }
+
+ /**
+ * Reads/peeks an Ogg page header and stores the data in the {@code header} object passed
+ * as argument.
+ *
+ * @param input the {@link ExtractorInput} to read from.
+ * @param header the {@link PageHeader} to read from.
+ * @param scratch a scratch array temporary use.
+ * @param peek pass {@code true} if data should only be peeked from current peek position.
+ * @return {@code true} if the read was successful. {@code false} if the end of the
+ * input was encountered having read no data.
+ * @throws IOException thrown if reading data fails or the stream is invalid.
+ * @throws InterruptedException thrown if thread is interrupted when reading/peeking.
+ */
+ public static boolean populatePageHeader(ExtractorInput input, PageHeader header,
+ ParsableByteArray scratch, boolean peek) throws IOException, InterruptedException {
+
+ scratch.reset();
+ header.reset();
+ if (!input.peekFully(scratch.data, 0, 27, true)) {
+ return false;
+ }
+ if (scratch.readUnsignedInt() != Util.getIntegerCodeForString(CAPTURE_PATTERN_PAGE)) {
+ throw new ParserException("expected OggS capture pattern at begin of page");
+ }
+
+ header.revision = scratch.readUnsignedByte();
+ if (header.revision != 0x00) {
+ throw new ParserException("unsupported bit stream revision");
+ }
+ header.type = scratch.readUnsignedByte();
+
+ header.granulePosition = scratch.readLittleEndianLong();
+ header.streamSerialNumber = scratch.readLittleEndianUnsignedInt();
+ header.pageSequenceNumber = scratch.readLittleEndianUnsignedInt();
+ header.pageChecksum = scratch.readLittleEndianUnsignedInt();
+ header.pageSegmentCount = scratch.readUnsignedByte();
+
+ scratch.reset();
+ // calculate total size of header including laces
+ header.headerSize = 27 + header.pageSegmentCount;
+ input.peekFully(scratch.data, 0, header.pageSegmentCount);
+ for (int i = 0; i < header.pageSegmentCount; i++) {
+ header.laces[i] = scratch.readUnsignedByte();
+ header.bodySize += header.laces[i];
+ }
+ if (!peek) {
+ input.skipFully(header.headerSize);
+ }
+ return true;
+ }
+
+ /**
+ * Data object to store header information. Be aware that {@code laces.length} is always 255.
+ * Instead use {@code pageSegmentCount} to iterate.
+ */
+ public static final class PageHeader {
+
+ public int revision;
+ public int type;
+ public long granulePosition;
+ public long streamSerialNumber;
+ public long pageSequenceNumber;
+ public long pageChecksum;
+ public int pageSegmentCount;
+ public int headerSize;
+ public int bodySize;
+ public int[] laces = new int[255];
+
+ /**
+ * Resets all primitive member fields to zero.
+ */
+ public void reset() {
+ revision = 0;
+ type = 0;
+ granulePosition = 0;
+ streamSerialNumber = 0;
+ pageSequenceNumber = 0;
+ pageChecksum = 0;
+ pageSegmentCount = 0;
+ headerSize = 0;
+ bodySize = 0;
+ }
+
+ }
+
+}
diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ogg/OggVorbisExtractor.java b/library/src/main/java/com/google/android/exoplayer/extractor/ogg/OggVorbisExtractor.java
new file mode 100644
index 0000000000..b96b7d1146
--- /dev/null
+++ b/library/src/main/java/com/google/android/exoplayer/extractor/ogg/OggVorbisExtractor.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.exoplayer.extractor.ogg;
+
+import com.google.android.exoplayer.C;
+import com.google.android.exoplayer.MediaFormat;
+import com.google.android.exoplayer.ParserException;
+import com.google.android.exoplayer.extractor.Extractor;
+import com.google.android.exoplayer.extractor.ExtractorInput;
+import com.google.android.exoplayer.extractor.ExtractorOutput;
+import com.google.android.exoplayer.extractor.PositionHolder;
+import com.google.android.exoplayer.extractor.SeekMap;
+import com.google.android.exoplayer.extractor.TrackOutput;
+import com.google.android.exoplayer.extractor.ogg.VorbisUtil.Mode;
+import com.google.android.exoplayer.util.MimeTypes;
+import com.google.android.exoplayer.util.ParsableByteArray;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * {@link Extractor} to extract Vorbis data out of Ogg byte stream.
+ */
+public final class OggVorbisExtractor implements Extractor {
+
+ private static final String TAG = "OggVorbisExtractor";
+
+ private static final int OGG_MAX_SEGMENT_SIZE = 255;
+
+ private final ParsableByteArray scratch = new ParsableByteArray(
+ new byte[OGG_MAX_SEGMENT_SIZE * 255], 0);
+ private final OggReader oggReader = new OggReader();
+
+ private TrackOutput trackOutput;
+ private VorbisSetup vorbisSetup;
+ private int previousPacketBlockSize;
+ private long elapsedSamples;
+ private boolean seenFirstAudioPacket;
+
+ private VorbisUtil.VorbisIdHeader vorbisIdHeader;
+ private VorbisUtil.CommentHeader commentHeader;
+
+ @Override
+ public boolean sniff(ExtractorInput input) throws IOException, InterruptedException {
+ try {
+ OggReader.PageHeader header = new OggReader.PageHeader();
+ OggReader.populatePageHeader(input, header, scratch, true);
+ if ((header.type & 0x02) != 0x02) {
+ throw new ParserException("expected page to be first page of a logical stream");
+ }
+ input.resetPeekPosition();
+ } catch (ParserException e) {
+ Log.e(TAG, e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void init(ExtractorOutput output) {
+ trackOutput = output.track(0);
+ output.endTracks();
+ output.seekMap(SeekMap.UNSEEKABLE);
+ }
+
+ @Override
+ public void seek() {
+ oggReader.reset();
+ previousPacketBlockSize = -1;
+ elapsedSamples = 0;
+ seenFirstAudioPacket = false;
+ scratch.reset();
+ }
+
+ @Override
+ public int read(ExtractorInput input, PositionHolder seekPosition)
+ throws IOException, InterruptedException {
+
+ if (vorbisSetup == null) {
+ vorbisSetup = readSetupHeaders(input, scratch);
+ ArrayList