Commit 1e4f8995 by aquilescanta Committed by Oliver Woodman

Add support for the data URI scheme

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=165699328
parent cc9a93d9
/*
* Copyright (C) 2017 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.exoplayer2.upstream;
import android.net.Uri;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.testutil.TestUtil;
import java.io.IOException;
import junit.framework.TestCase;
/**
* Unit tests for {@link DataSchemeDataSource}.
*/
public final class DataSchemeDataSourceTest extends TestCase {
private DataSource schemeDataDataSource;
@Override
public void setUp() {
schemeDataDataSource = new DataSchemeDataSource();
}
public void testBase64Data() throws IOException {
DataSpec dataSpec = buildDataSpec("data:text/plain;base64,eyJwcm92aWRlciI6IndpZGV2aW5lX3Rlc3QiL"
+ "CJjb250ZW50X2lkIjoiTWpBeE5WOTBaV0Z5Y3c9PSIsImtleV9pZHMiOlsiMDAwMDAwMDAwMDAwMDAwMDAwMDAwM"
+ "DAwMDAwMDAwMDAiXX0=");
TestUtil.assertDataSourceContent(schemeDataDataSource, dataSpec,
("{\"provider\":\"widevine_test\",\"content_id\":\"MjAxNV90ZWFycw==\",\"key_ids\":"
+ "[\"00000000000000000000000000000000\"]}").getBytes());
}
public void testAsciiData() throws IOException {
TestUtil.assertDataSourceContent(schemeDataDataSource, buildDataSpec("data:,A%20brief%20note"),
"A brief note".getBytes());
}
public void testPartialReads() throws IOException {
byte[] buffer = new byte[18];
DataSpec dataSpec = buildDataSpec("data:,012345678901234567");
assertEquals(18, schemeDataDataSource.open(dataSpec));
assertEquals(9, schemeDataDataSource.read(buffer, 0, 9));
assertEquals(0, schemeDataDataSource.read(buffer, 3, 0));
assertEquals(9, schemeDataDataSource.read(buffer, 9, 15));
assertEquals(0, schemeDataDataSource.read(buffer, 1, 0));
assertEquals(C.RESULT_END_OF_INPUT, schemeDataDataSource.read(buffer, 1, 1));
assertEquals("012345678901234567", new String(buffer, 0, 18));
}
public void testIncorrectScheme() {
try {
schemeDataDataSource.open(buildDataSpec("http://www.google.com"));
fail();
} catch (IOException e) {
// Expected.
}
}
public void testMalformedData() {
try {
schemeDataDataSource.open(buildDataSpec("data:text/plain;base64,,This%20is%20Content"));
fail();
} catch (IOException e) {
// Expected.
}
try {
schemeDataDataSource.open(buildDataSpec("data:text/plain;base64,IncorrectPadding=="));
fail();
} catch (IOException e) {
// Expected.
}
}
private static DataSpec buildDataSpec(String uriString) {
return new DataSpec(Uri.parse(uriString));
}
}
......@@ -74,6 +74,10 @@ public final class C {
public static final long NANOS_PER_SECOND = 1000000000L;
/**
* The name of the ASCII charset.
*/
public static final String ASCII_NAME = "US-ASCII";
/**
* The name of the UTF-8 charset.
*/
public static final String UTF8_NAME = "UTF-8";
......
/*
* Copyright (C) 2017 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.exoplayer2.upstream;
import android.net.Uri;
import android.util.Base64;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException;
import java.io.IOException;
import java.net.URLDecoder;
/**
* A {@link DataSource} for reading data URLs, as defined by RFC 2397.
*/
public final class DataSchemeDataSource implements DataSource {
public static final String SCHEME_DATA = "data";
private DataSpec dataSpec;
private int bytesRead;
private byte[] data;
@Override
public long open(DataSpec dataSpec) throws IOException {
this.dataSpec = dataSpec;
Uri uri = dataSpec.uri;
String scheme = uri.getScheme();
if (!SCHEME_DATA.equals(scheme)) {
throw new ParserException("Unsupported scheme: " + scheme);
}
String[] uriParts = uri.getSchemeSpecificPart().split(",");
if (uriParts.length > 2) {
throw new ParserException("Unexpected URI format: " + uri);
}
String dataString = uriParts[1];
if (uriParts[0].contains(";base64")) {
try {
data = Base64.decode(dataString, 0);
} catch (IllegalArgumentException e) {
throw new ParserException("Error while parsing Base64 encoded string: " + dataString, e);
}
} else {
// TODO: Add support for other charsets.
data = URLDecoder.decode(dataString, C.ASCII_NAME).getBytes();
}
return data.length;
}
@Override
public int read(byte[] buffer, int offset, int readLength) {
if (readLength == 0) {
return 0;
}
int remainingBytes = data.length - bytesRead;
if (remainingBytes == 0) {
return C.RESULT_END_OF_INPUT;
}
readLength = Math.min(readLength, remainingBytes);
System.arraycopy(data, bytesRead, buffer, offset, readLength);
bytesRead += readLength;
return readLength;
}
@Override
public Uri getUri() {
return dataSpec != null ? dataSpec.uri : null;
}
@Override
public void close() throws IOException {
dataSpec = null;
data = null;
}
}
......@@ -34,10 +34,11 @@ import java.lang.reflect.InvocationTargetException;
* <li>content: For fetching data from a content URI (e.g. content://authority/path/123).
* <li>rtmp: For fetching data over RTMP. Only supported if the project using ExoPlayer has an
* explicit dependency on ExoPlayer's RTMP extension.</li>
* <li>data: For parsing data inlined in the URI as defined in RFC 2397.</li>
* <li>http(s): For fetching data over HTTP and HTTPS (e.g. https://www.something.com/media.mp4), if
* constructed using {@link #DefaultDataSource(Context, TransferListener, String, boolean)}, or
* any other schemes supported by a base data source if constructed using
* {@link #DefaultDataSource(Context, TransferListener, DataSource)}.
* {@link #DefaultDataSource(Context, TransferListener, DataSource)}.</li>
* </ul>
*/
public final class DefaultDataSource implements DataSource {
......@@ -58,6 +59,7 @@ public final class DefaultDataSource implements DataSource {
private DataSource assetDataSource;
private DataSource contentDataSource;
private DataSource rtmpDataSource;
private DataSource dataSchemeDataSource;
private DataSource dataSource;
......@@ -130,6 +132,8 @@ public final class DefaultDataSource implements DataSource {
dataSource = getContentDataSource();
} else if (SCHEME_RTMP.equals(scheme)) {
dataSource = getRtmpDataSource();
} else if (DataSchemeDataSource.SCHEME_DATA.equals(scheme)) {
dataSource = getDataSchemeDataSource();
} else {
dataSource = baseDataSource;
}
......@@ -202,4 +206,11 @@ public final class DefaultDataSource implements DataSource {
return rtmpDataSource;
}
private DataSource getDataSchemeDataSource() {
if (dataSchemeDataSource == null) {
dataSchemeDataSource = new DataSchemeDataSource();
}
return dataSchemeDataSource;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment