Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce4c9d71 authored by Alex Klyubin's avatar Alex Klyubin Committed by Gerrit Code Review
Browse files

Merge "Improve DataSource interface."

parents 85f004c6 7b977ea0
Loading
Loading
Loading
Loading
+53 −21
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ import java.nio.ByteBuffer;
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,29 +45,39 @@ public class ByteBufferDataSource implements DataSource {
    }

    @Override
    public void feed(long offset, int size, DataSink sink) throws IOException {
        if (offset < 0) {
            throw new IllegalArgumentException("offset: " + offset);
    public ByteBufferDataSource slice(long offset, long size) {
        if ((offset == 0) && (size == mSize)) {
            return this;
        }
        if (size < 0) {
            throw new IllegalArgumentException("size: " + size);
        }
        if (offset > mSize) {
            throw new IllegalArgumentException(
                    "offset (" + offset + ") > source size (" + mSize + ")");
        }
        long endOffset = offset + size;
        if (endOffset < offset) {
            throw new IllegalArgumentException(
                    "offset (" + offset + ") + size (" + size + ") overflow");
        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);
        }
        if (endOffset > mSize) {
            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
    @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
@@ -86,4 +96,26 @@ public class ByteBufferDataSource implements DataSource {

        sink.consume(chunk);
    }

    private void checkChunkValid(long offset, long size) {
        if (offset < 0) {
            throw new IllegalArgumentException("offset: " + offset);
        }
        if (size < 0) {
            throw new IllegalArgumentException("size: " + size);
        }
        if (offset > mSize) {
            throw new IllegalArgumentException(
                    "offset (" + offset + ") > source size (" + mSize + ")");
        }
        long endOffset = offset + size;
        if (endOffset < offset) {
            throw new IllegalArgumentException(
                    "offset (" + offset + ") + size (" + size + ") overflow");
        }
        if (endOffset > mSize) {
            throw new IllegalArgumentException(
                    "offset (" + offset + ") + size (" + size + ") > source size (" + mSize  +")");
        }
    }
}
+7 −1
Original line number Diff line number Diff line
@@ -43,5 +43,11 @@ public interface DataSource {
     * @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);
}
+2 −1
Original line number Diff line number Diff line
@@ -12,7 +12,8 @@ public abstract class DataSources {

    /**
     * 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) {