Merge "Improve DataSource interface."
am: ce4c9d7108
* commit 'ce4c9d71080d27ce321b1aa49e2189ee55bb25fa':
Improve DataSource interface.
Change-Id: I8a1df06ee64785ae48414b2468e760c41d7f41f3
diff --git a/tools/apksigner/core/src/com/android/apksigner/core/internal/util/ByteBufferDataSource.java b/tools/apksigner/core/src/com/android/apksigner/core/internal/util/ByteBufferDataSource.java
index 76f4fda..f12f02e 100644
--- a/tools/apksigner/core/src/com/android/apksigner/core/internal/util/ByteBufferDataSource.java
+++ b/tools/apksigner/core/src/com/android/apksigner/core/internal/util/ByteBufferDataSource.java
@@ -28,7 +28,7 @@
public class ByteBufferDataSource implements DataSource {
private final ByteBuffer mBuffer;
- private final long mSize;
+ private final int mSize;
/**
* Constructs a new {@code ByteBufferDigestSource} based on the data contained in the provided
@@ -45,7 +45,59 @@
}
@Override
- public void feed(long offset, int size, DataSink sink) throws IOException {
+ public ByteBufferDataSource slice(long offset, long size) {
+ if ((offset == 0) && (size == mSize)) {
+ return this;
+ }
+ checkChunkValid(offset, size);
+
+ // checkChunkValid ensures that it's OK to cast offset and size to int.
+ int chunkPosition = (int) offset;
+ int chunkLimit = (int) (chunkPosition + size);
+ // Creating a slice of ByteBuffer modifies the state of the source ByteBuffer (position
+ // and limit fields, to be more specific). We thus use synchronization around these
+ // state-changing operations to make instances of this class thread-safe.
+ synchronized (mBuffer) {
+ // ByteBuffer.limit(int) and .position(int) check that that the position >= limit
+ // invariant is not broken. Thus, the only way to safely change position and limit
+ // without caring about their current values is to first set position to 0 or set the
+ // limit to capacity.
+ mBuffer.position(0);
+
+ mBuffer.limit(chunkLimit);
+ mBuffer.position(chunkPosition);
+ // Create a ByteBufferDataSource for the slice of the buffer between limit and position.
+ return new ByteBufferDataSource(mBuffer);
+ }
+ }
+
+ @Override
+ public void feed(long offset, long size, DataSink sink) throws IOException {
+ checkChunkValid(offset, size);
+
+ // checkChunkValid ensures that it's OK to cast offset and size to int.
+ int chunkPosition = (int) offset;
+ int chunkLimit = (int) (chunkPosition + size);
+ ByteBuffer chunk;
+ // Creating a slice of ByteBuffer modifies the state of the source ByteBuffer (position
+ // and limit fields, to be more specific). We thus use synchronization around these
+ // state-changing operations to make instances of this class thread-safe.
+ synchronized (mBuffer) {
+ // ByteBuffer.limit(int) and .position(int) check that that the position >= limit
+ // invariant is not broken. Thus, the only way to safely change position and limit
+ // without caring about their current values is to first set position to 0 or set the
+ // limit to capacity.
+ mBuffer.position(0);
+
+ mBuffer.limit(chunkLimit);
+ mBuffer.position(chunkPosition);
+ chunk = mBuffer.slice();
+ }
+
+ sink.consume(chunk);
+ }
+
+ private void checkChunkValid(long offset, long size) {
if (offset < 0) {
throw new IllegalArgumentException("offset: " + offset);
}
@@ -65,25 +117,5 @@
throw new IllegalArgumentException(
"offset (" + offset + ") + size (" + size + ") > source size (" + mSize +")");
}
-
- int chunkPosition = (int) offset; // safe to downcast because mSize <= Integer.MAX_VALUE
- int chunkLimit = (int) endOffset; // safe to downcast because mSize <= Integer.MAX_VALUE
- ByteBuffer chunk;
- // Creating a slice of ByteBuffer modifies the state of the source ByteBuffer (position
- // and limit fields, to be more specific). We thus use synchronization around these
- // state-changing operations to make instances of this class thread-safe.
- synchronized (mBuffer) {
- // ByteBuffer.limit(int) and .position(int) check that that the position >= limit
- // invariant is not broken. Thus, the only way to safely change position and limit
- // without caring about their current values is to first set position to 0 or set the
- // limit to capacity.
- mBuffer.position(0);
-
- mBuffer.limit(chunkLimit);
- mBuffer.position(chunkPosition);
- chunk = mBuffer.slice();
- }
-
- sink.consume(chunk);
}
}
diff --git a/tools/apksigner/core/src/com/android/apksigner/core/util/DataSource.java b/tools/apksigner/core/src/com/android/apksigner/core/util/DataSource.java
index 04560cb..27ff7a8 100644
--- a/tools/apksigner/core/src/com/android/apksigner/core/util/DataSource.java
+++ b/tools/apksigner/core/src/com/android/apksigner/core/util/DataSource.java
@@ -43,5 +43,11 @@
* @param offset index (in bytes) at which the chunk starts inside data source
* @param size size (in bytes) of the chunk
*/
- void feed(long offset, int size, DataSink sink) throws IOException;
+ void feed(long offset, long size, DataSink sink) throws IOException;
+
+ /**
+ * Returns a data source representing the specified region of data of this data source. Changes
+ * to data represented by this data source will also be visible in the returned data source.
+ */
+ DataSource slice(long offset, long size);
}
diff --git a/tools/apksigner/core/src/com/android/apksigner/core/util/DataSources.java b/tools/apksigner/core/src/com/android/apksigner/core/util/DataSources.java
index 978afae..6ce0ac8 100644
--- a/tools/apksigner/core/src/com/android/apksigner/core/util/DataSources.java
+++ b/tools/apksigner/core/src/com/android/apksigner/core/util/DataSources.java
@@ -12,7 +12,8 @@
/**
* Returns a {@link DataSource} backed by the provided {@link ByteBuffer}. The data source
- * represents the data contained between the position and limit of the buffer.
+ * represents the data contained between the position and limit of the buffer. Changes to the
+ * buffer's contents will be visible in the data source.
*/
public static DataSource asDataSource(ByteBuffer buffer) {
if (buffer == null) {