Fix DataSources

Bug: 118363127
Test: N/A

Change-Id: I56748506f3c93715f9d05ad98a763bd046f59f35
diff --git a/src/main/java/com/android/apksig/internal/util/ChainedDataSource.java b/src/main/java/com/android/apksig/internal/util/ChainedDataSource.java
index 25f23c9..ab56acc 100644
--- a/src/main/java/com/android/apksig/internal/util/ChainedDataSource.java
+++ b/src/main/java/com/android/apksig/internal/util/ChainedDataSource.java
@@ -106,7 +106,7 @@
         long beginLocalOffset = firstSource.getSecond();
         DataSource beginSource = mSources[beginIndex];
 
-        if (beginLocalOffset + size <= beginSource.size()) {
+        if (beginLocalOffset + size <= beginSource.size() || size == 0) {
             return beginSource.slice(beginLocalOffset, size);
         }
 
@@ -115,15 +115,15 @@
         sources.add(beginSource.slice(
                 beginLocalOffset, beginSource.size() - beginLocalOffset));
 
-        Pair<Integer, Long> lastSource = locateDataSource(offset + size);
+        Pair<Integer, Long> lastSource = locateDataSource(offset + size - 1);
         int endIndex = lastSource.getFirst();
         long endLocalOffset = lastSource.getSecond();
 
-        for (int i = beginIndex + 1; i < endIndex - 1; i++) {
+        for (int i = beginIndex + 1; i < endIndex; i++) {
             sources.add(mSources[i]);
         }
 
-        sources.add(mSources[endIndex].slice(0, endLocalOffset));
+        sources.add(mSources[endIndex].slice(0, endLocalOffset + 1));
         return new ChainedDataSource(sources.toArray(new DataSource[0]));
     }
 
diff --git a/src/main/java/com/android/apksig/internal/util/RandomAccessFileDataSource.java b/src/main/java/com/android/apksig/internal/util/RandomAccessFileDataSource.java
index 3492399..6f59b51 100644
--- a/src/main/java/com/android/apksig/internal/util/RandomAccessFileDataSource.java
+++ b/src/main/java/com/android/apksig/internal/util/RandomAccessFileDataSource.java
@@ -29,19 +29,19 @@
  */
 public class RandomAccessFileDataSource implements DataSource {
 
-    private static final int MAX_READ_CHUNK_SIZE = 65536;
+    private static final int MAX_READ_CHUNK_SIZE = 1024 * 1024;
 
-    private final RandomAccessFile mFile;
+    private final FileChannel mChannel;
     private final long mOffset;
     private final long mSize;
 
     /**
      * Constructs a new {@code RandomAccessFileDataSource} based on the data contained in the
-     * specified the whole file. Changes to the contents of the file, including the size of the
-     * file, will be visible in this data source.
+     * whole file. Changes to the contents of the file, including the size of the file,
+     * will be visible in this data source.
      */
     public RandomAccessFileDataSource(RandomAccessFile file) {
-        mFile = file;
+        mChannel = file.getChannel();
         mOffset = 0;
         mSize = -1;
     }
@@ -54,13 +54,17 @@
      * @throws IndexOutOfBoundsException if {@code offset} or {@code size} is negative.
      */
     public RandomAccessFileDataSource(RandomAccessFile file, long offset, long size) {
+        this(file.getChannel(), offset, size);
+    }
+
+    private RandomAccessFileDataSource(FileChannel channel, long offset, long size) {
         if (offset < 0) {
             throw new IndexOutOfBoundsException("offset: " + size);
         }
         if (size < 0) {
             throw new IndexOutOfBoundsException("size: " + size);
         }
-        mFile = file;
+        mChannel = channel;
         mOffset = offset;
         mSize = size;
     }
@@ -69,7 +73,7 @@
     public long size() {
         if (mSize == -1) {
             try {
-                return mFile.length();
+                return mChannel.size();
             } catch (IOException e) {
                 return 0;
             }
@@ -86,7 +90,7 @@
             return this;
         }
 
-        return new RandomAccessFileDataSource(mFile, mOffset + offset, size);
+        return new RandomAccessFileDataSource(mChannel, mOffset + offset, size);
     }
 
     @Override
@@ -99,14 +103,24 @@
 
         long chunkOffsetInFile = mOffset + offset;
         long remaining = size;
-        byte[] buf = new byte[(int) Math.min(remaining, MAX_READ_CHUNK_SIZE)];
+        ByteBuffer buf = ByteBuffer.allocateDirect((int) Math.min(remaining, MAX_READ_CHUNK_SIZE));
+
         while (remaining > 0) {
-            int chunkSize = (int) Math.min(remaining, buf.length);
-            synchronized (mFile) {
-                mFile.seek(chunkOffsetInFile);
-                mFile.readFully(buf, 0, chunkSize);
+            int chunkSize = (int) Math.min(remaining, buf.capacity());
+            int chunkRemaining = chunkSize;
+            synchronized (mChannel) {
+                mChannel.position(chunkOffsetInFile);
+                while (chunkRemaining > 0) {
+                    int read = mChannel.read(buf);
+                    if (read < 0) {
+                        throw new IOException("Unexpected EOF encountered");
+                    }
+                    chunkRemaining -= read;
+                }
             }
-            sink.consume(buf, 0, chunkSize);
+            buf.flip();
+            sink.consume(buf);
+            buf.clear();
             chunkOffsetInFile += chunkSize;
             remaining -= chunkSize;
         }
@@ -130,12 +144,11 @@
             // FileChannel.read(ByteBuffer) reads up to dest.remaining(). Thus, we need to adjust
             // the buffer's limit to avoid reading more than size bytes.
             dest.limit(dest.position() + size);
-            FileChannel fileChannel = mFile.getChannel();
             while (remaining > 0) {
                 int chunkSize;
-                synchronized (mFile) {
-                    fileChannel.position(offsetInFile);
-                    chunkSize = fileChannel.read(dest);
+                synchronized (mChannel) {
+                    mChannel.position(offsetInFile);
+                    chunkSize = mChannel.read(dest);
                 }
                 offsetInFile += chunkSize;
                 remaining -= chunkSize;