From f8ed4cfdeeac04c6119b246bbaadb4907c3f79b7 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 4 Oct 2016 12:15:28 -0700 Subject: [PATCH] Clean up some DataSource implementations - Make read return 0 if readLength==0 - Return RESULT_END_OF_INPUT properly in the case that bytesRemaining is unset (this was broken previously, but only applies for assets > 2^31 bytes, so it's unlikely anyone ever hit this issue) ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=135136541 --- .../ext/okhttp/OkHttpDataSource.java | 16 ++++--- .../exoplayer2/upstream/AssetDataSource.java | 48 +++++++++++-------- .../upstream/ByteArrayDataSource.java | 17 ++++--- .../upstream/ContentDataSource.java | 48 +++++++++++-------- .../exoplayer2/upstream/DataSource.java | 12 +++-- .../upstream/DefaultHttpDataSource.java | 11 ++++- .../upstream/RawResourceDataSource.java | 48 +++++++++++-------- 7 files changed, 118 insertions(+), 82 deletions(-) diff --git a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java index e6ecd77d02..e4e3d7ba00 100644 --- a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java +++ b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java @@ -338,17 +338,21 @@ public class OkHttpDataSource implements HttpDataSource { * @throws IOException If an error occurs reading from the source. */ private int readInternal(byte[] buffer, int offset, int readLength) throws IOException { - readLength = bytesToRead == C.LENGTH_UNSET ? readLength - : (int) Math.min(readLength, bytesToRead - bytesRead); if (readLength == 0) { - // We've read all of the requested data. - return C.RESULT_END_OF_INPUT; + return 0; + } + if (bytesToRead != C.LENGTH_UNSET) { + long bytesRemaining = bytesToRead - bytesRead; + if (bytesRemaining == 0) { + return C.RESULT_END_OF_INPUT; + } + readLength = (int) Math.min(readLength, bytesRemaining); } int read = responseByteStream.read(buffer, offset, readLength); if (read == -1) { - if (bytesToRead != C.LENGTH_UNSET && bytesToRead != bytesRead) { - // The server closed the connection having not sent sufficient data. + if (bytesToRead != C.LENGTH_UNSET) { + // End of stream reached having not read sufficient data. throw new EOFException(); } return C.RESULT_END_OF_INPUT; diff --git a/library/src/main/java/com/google/android/exoplayer2/upstream/AssetDataSource.java b/library/src/main/java/com/google/android/exoplayer2/upstream/AssetDataSource.java index 1a685ca1af..d0b18bb765 100644 --- a/library/src/main/java/com/google/android/exoplayer2/upstream/AssetDataSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/upstream/AssetDataSource.java @@ -104,29 +104,35 @@ public final class AssetDataSource implements DataSource { @Override public int read(byte[] buffer, int offset, int readLength) throws AssetDataSourceException { - if (bytesRemaining == 0) { + if (readLength == 0) { + return 0; + } else if (bytesRemaining == 0) { return C.RESULT_END_OF_INPUT; - } else { - int bytesRead; - try { - int bytesToRead = bytesRemaining == C.LENGTH_UNSET ? readLength - : (int) Math.min(bytesRemaining, readLength); - bytesRead = inputStream.read(buffer, offset, bytesToRead); - } catch (IOException e) { - throw new AssetDataSourceException(e); - } - - if (bytesRead > 0) { - if (bytesRemaining != C.LENGTH_UNSET) { - bytesRemaining -= bytesRead; - } - if (listener != null) { - listener.onBytesTransferred(this, bytesRead); - } - } - - return bytesRead; } + + int bytesRead; + try { + int bytesToRead = bytesRemaining == C.LENGTH_UNSET ? readLength + : (int) Math.min(bytesRemaining, readLength); + bytesRead = inputStream.read(buffer, offset, bytesToRead); + } catch (IOException e) { + throw new AssetDataSourceException(e); + } + + if (bytesRead == -1) { + if (bytesRemaining != C.LENGTH_UNSET) { + // End of stream reached having not read sufficient data. + throw new AssetDataSourceException(new EOFException()); + } + return C.RESULT_END_OF_INPUT; + } + if (bytesRemaining != C.LENGTH_UNSET) { + bytesRemaining -= bytesRead; + } + if (listener != null) { + listener.onBytesTransferred(this, bytesRead); + } + return bytesRead; } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/upstream/ByteArrayDataSource.java b/library/src/main/java/com/google/android/exoplayer2/upstream/ByteArrayDataSource.java index dd787d05b9..e5311e783b 100644 --- a/library/src/main/java/com/google/android/exoplayer2/upstream/ByteArrayDataSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/upstream/ByteArrayDataSource.java @@ -54,15 +54,18 @@ public final class ByteArrayDataSource implements DataSource { } @Override - public int read(byte[] buffer, int offset, int length) throws IOException { - if (bytesRemaining == 0) { + public int read(byte[] buffer, int offset, int readLength) throws IOException { + if (readLength == 0) { + return 0; + } else if (bytesRemaining == 0) { return C.RESULT_END_OF_INPUT; } - length = Math.min(length, bytesRemaining); - System.arraycopy(data, readPosition, buffer, offset, length); - readPosition += length; - bytesRemaining -= length; - return length; + + readLength = Math.min(readLength, bytesRemaining); + System.arraycopy(data, readPosition, buffer, offset, readLength); + readPosition += readLength; + bytesRemaining -= readLength; + return readLength; } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java b/library/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java index 2a0ad01489..f806f47410 100644 --- a/library/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java @@ -103,29 +103,35 @@ public final class ContentDataSource implements DataSource { @Override public int read(byte[] buffer, int offset, int readLength) throws ContentDataSourceException { - if (bytesRemaining == 0) { + if (readLength == 0) { + return 0; + } else if (bytesRemaining == 0) { return C.RESULT_END_OF_INPUT; - } else { - int bytesRead; - try { - int bytesToRead = bytesRemaining == C.LENGTH_UNSET ? readLength - : (int) Math.min(bytesRemaining, readLength); - bytesRead = inputStream.read(buffer, offset, bytesToRead); - } catch (IOException e) { - throw new ContentDataSourceException(e); - } - - if (bytesRead > 0) { - if (bytesRemaining != C.LENGTH_UNSET) { - bytesRemaining -= bytesRead; - } - if (listener != null) { - listener.onBytesTransferred(this, bytesRead); - } - } - - return bytesRead; } + + int bytesRead; + try { + int bytesToRead = bytesRemaining == C.LENGTH_UNSET ? readLength + : (int) Math.min(bytesRemaining, readLength); + bytesRead = inputStream.read(buffer, offset, bytesToRead); + } catch (IOException e) { + throw new ContentDataSourceException(e); + } + + if (bytesRead == -1) { + if (bytesRemaining != C.LENGTH_UNSET) { + // End of stream reached having not read sufficient data. + throw new ContentDataSourceException(new EOFException()); + } + return C.RESULT_END_OF_INPUT; + } + if (bytesRemaining != C.LENGTH_UNSET) { + bytesRemaining -= bytesRead; + } + if (listener != null) { + listener.onBytesTransferred(this, bytesRead); + } + return bytesRead; } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java b/library/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java index 2b445fc05b..0ddf17cbe9 100644 --- a/library/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java @@ -55,14 +55,18 @@ public interface DataSource { /** * Reads up to {@code length} bytes of data and stores them into {@code buffer}, starting at - * index {@code offset}. Blocks until at least one byte of data can be read, the end of the opened - * range is detected, or an exception is thrown. + * index {@code offset}. + *

+ * If {@code length} is zero then 0 is returned. Otherwise, if no data is available because the + * end of the opened range has been reached, then {@link C#RESULT_END_OF_INPUT} is returned. + * Otherwise, the call will block until at least one byte of data has been read and the number of + * bytes read is returned. * * @param buffer The buffer into which the read data should be stored. * @param offset The start offset into {@code buffer} at which data should be written. * @param readLength The maximum number of bytes to read. - * @return The number of bytes read, or {@link C#RESULT_END_OF_INPUT} if the end of the opened - * range is reached. + * @return The number of bytes read, or {@link C#RESULT_END_OF_INPUT} if no data is avaliable + * because the end of the opened range has been reached. * @throws IOException If an error occurs reading from the source. */ int read(byte[] buffer, int offset, int readLength) throws IOException; diff --git a/library/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java b/library/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java index e00f93aa19..b193b446c2 100644 --- a/library/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java @@ -550,11 +550,18 @@ public class DefaultHttpDataSource implements HttpDataSource { if (readLength == 0) { return 0; } + if (bytesToRead != C.LENGTH_UNSET) { + long bytesRemaining = bytesToRead - bytesRead; + if (bytesRemaining == 0) { + return C.RESULT_END_OF_INPUT; + } + readLength = (int) Math.min(readLength, bytesRemaining); + } int read = inputStream.read(buffer, offset, readLength); if (read == -1) { - if (bytesToRead != C.LENGTH_UNSET && bytesToRead != bytesRead) { - // The server closed the connection having not sent sufficient data. + if (bytesToRead != C.LENGTH_UNSET) { + // End of stream reached having not read sufficient data. throw new EOFException(); } return C.RESULT_END_OF_INPUT; diff --git a/library/src/main/java/com/google/android/exoplayer2/upstream/RawResourceDataSource.java b/library/src/main/java/com/google/android/exoplayer2/upstream/RawResourceDataSource.java index 74c38ba31e..3a9ea0cff0 100644 --- a/library/src/main/java/com/google/android/exoplayer2/upstream/RawResourceDataSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/upstream/RawResourceDataSource.java @@ -132,29 +132,35 @@ public final class RawResourceDataSource implements DataSource { @Override public int read(byte[] buffer, int offset, int readLength) throws RawResourceDataSourceException { - if (bytesRemaining == 0) { + if (readLength == 0) { + return 0; + } else if (bytesRemaining == 0) { return C.RESULT_END_OF_INPUT; - } else { - int bytesRead; - try { - int bytesToRead = bytesRemaining == C.LENGTH_UNSET ? readLength - : (int) Math.min(bytesRemaining, readLength); - bytesRead = inputStream.read(buffer, offset, bytesToRead); - } catch (IOException e) { - throw new RawResourceDataSourceException(e); - } - - if (bytesRead > 0) { - if (bytesRemaining != C.LENGTH_UNSET) { - bytesRemaining -= bytesRead; - } - if (listener != null) { - listener.onBytesTransferred(this, bytesRead); - } - } - - return bytesRead; } + + int bytesRead; + try { + int bytesToRead = bytesRemaining == C.LENGTH_UNSET ? readLength + : (int) Math.min(bytesRemaining, readLength); + bytesRead = inputStream.read(buffer, offset, bytesToRead); + } catch (IOException e) { + throw new RawResourceDataSourceException(e); + } + + if (bytesRead == -1) { + if (bytesRemaining != C.LENGTH_UNSET) { + // End of stream reached having not read sufficient data. + throw new RawResourceDataSourceException(new EOFException()); + } + return C.RESULT_END_OF_INPUT; + } + if (bytesRemaining != C.LENGTH_UNSET) { + bytesRemaining -= bytesRead; + } + if (listener != null) { + listener.onBytesTransferred(this, bytesRead); + } + return bytesRead; } @Override