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

Commit 30467a54 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Revert "Have AssetFileDescriptor.AutoCloseInputStream use pread""

parents eb76e6e2 f2ad1a43
Loading
Loading
Loading
Loading
+33 −201
Original line number Diff line number Diff line
@@ -21,20 +21,12 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.system.ErrnoException;
import android.system.Os;

import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

/**
 * File descriptor of an entry in the AssetManager.  This provides your own
@@ -211,26 +203,19 @@ public class AssetFileDescriptor implements Parcelable, Closeable {
     */
    public static class AutoCloseInputStream
            extends ParcelFileDescriptor.AutoCloseInputStream {
        /** Size of current file. */
        private long mTotalSize;
        /** The absolute position of current file start point. */
        private final long mFileOffset;
        /** The relative position where input stream is against mFileOffset. */
        private long mOffset;
        private OffsetCorrectFileChannel mOffsetCorrectFileChannel;
        private long mRemaining;

        public AutoCloseInputStream(AssetFileDescriptor fd) throws IOException {
            super(fd.getParcelFileDescriptor());
            mTotalSize = fd.getLength();
            mFileOffset = fd.getStartOffset();
            super.skip(fd.getStartOffset());
            mRemaining = (int) fd.getLength();
        }

        @Override
        public int available() throws IOException {
            long available = mTotalSize - mOffset;
            return available >= 0
                    ? (available < 0x7fffffff ? (int) available : 0x7fffffff)
                    : 0;
            return mRemaining >= 0
                    ? (mRemaining < 0x7fffffff ? (int) mRemaining : 0x7fffffff)
                    : super.available();
        }

        @Override
@@ -242,24 +227,15 @@ public class AssetFileDescriptor implements Parcelable, Closeable {

        @Override
        public int read(byte[] buffer, int offset, int count) throws IOException {
            int available = available();
            if (available <= 0) {
                return -1;
            }

            if (count > available) count = available;
            try {
                int res = Os.pread(getFD(), buffer, offset, count, mFileOffset + mOffset);
                // pread returns 0 at end of file, while java's InputStream interface requires -1
                if (res == 0) res = -1;
                if (res > 0) {
                    mOffset += res;
                    updateChannelPosition(mOffset + mFileOffset);
                }
            if (mRemaining >= 0) {
                if (mRemaining == 0) return -1;
                if (count > mRemaining) count = (int) mRemaining;
                int res = super.read(buffer, offset, count);
                if (res >= 0) mRemaining -= res;
                return res;
            } catch (ErrnoException e) {
                throw new IOException(e);
            }

            return super.read(buffer, offset, count);
        }

        @Override
@@ -269,185 +245,41 @@ public class AssetFileDescriptor implements Parcelable, Closeable {

        @Override
        public long skip(long count) throws IOException {
            int available = available();
            if (available <= 0) {
                return -1;
            if (mRemaining >= 0) {
                if (mRemaining == 0) return -1;
                if (count > mRemaining) count = mRemaining;
                long res = super.skip(count);
                if (res >= 0) mRemaining -= res;
                return res;
            }

            if (count > available) count = available;
            mOffset += count;
            updateChannelPosition(mOffset + mFileOffset);
            return count;
            return super.skip(count);
        }

        @Override
        public void mark(int readlimit) {
            if (mRemaining >= 0) {
                // Not supported.
                return;
            }
            super.mark(readlimit);
        }

        @Override
        public boolean markSupported() {
            if (mRemaining >= 0) {
                return false;
            }
            return super.markSupported();
        }

        @Override
        public synchronized void reset() throws IOException {
            if (mRemaining >= 0) {
                // Not supported.
                return;
            }

        @Override
        public FileChannel getChannel() {
            if (mOffsetCorrectFileChannel == null) {
                mOffsetCorrectFileChannel = new OffsetCorrectFileChannel(super.getChannel());
            }
            try {
                updateChannelPosition(mOffset + mFileOffset);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return mOffsetCorrectFileChannel;
        }

        /**
         * Update the position of mOffsetCorrectFileChannel only after it is constructed.
         *
         * @param newPosition The absolute position mOffsetCorrectFileChannel needs to be moved to.
         */
        private void updateChannelPosition(long newPosition) throws IOException {
            if (mOffsetCorrectFileChannel != null) {
                mOffsetCorrectFileChannel.position(newPosition);
            }
        }

        /**
         * A FileChannel wrapper that will update mOffset of the AutoCloseInputStream
         * to correct position when using FileChannel to read. All occurrence of position
         * should be using absolute solution and each override method just do Delegation
         * besides additional check. All methods related to write mode have been disabled
         * and will throw UnsupportedOperationException with customized message.
         */
        private class OffsetCorrectFileChannel extends FileChannel {
            private final FileChannel mDelegate;
            private static final String METHOD_NOT_SUPPORTED_MESSAGE =
                    "This Method is not supported in AutoCloseInputStream FileChannel.";

            OffsetCorrectFileChannel(FileChannel fc) {
                mDelegate = fc;
            }

            @Override
            public int read(ByteBuffer dst) throws IOException {
                if (available() <= 0) return -1;
                int bytesRead = mDelegate.read(dst);
                if (bytesRead != -1) mOffset += bytesRead;
                return bytesRead;
            }

            @Override
            public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
                if (available() <= 0) return -1;
                if (mOffset + length > mTotalSize) {
                    length = (int) (mTotalSize - mOffset);
                }
                long bytesRead = mDelegate.read(dsts, offset, length);
                if (bytesRead != -1) mOffset += bytesRead;
                return bytesRead;
            }

            @Override
            /**The only read method that does not move channel position*/
            public int read(ByteBuffer dst, long position) throws IOException {
                if (position - mFileOffset > mTotalSize) return -1;
                return mDelegate.read(dst, position);
            }

            @Override
            public long position() throws IOException {
                return mDelegate.position();
            }

            @Override
            public FileChannel position(long newPosition) throws IOException {
                mOffset = newPosition - mFileOffset;
                return mDelegate.position(newPosition);
            }

            @Override
            public long size() throws IOException {
                return mTotalSize;
            }

            @Override
            public long transferTo(long position, long count, WritableByteChannel target)
                    throws IOException {
                if (position - mFileOffset > mTotalSize) {
                    return 0;
                }
                if (position - mFileOffset + count > mTotalSize) {
                    count = mTotalSize - (position - mFileOffset);
                }
                return mDelegate.transferTo(position, count, target);
            }

            @Override
            public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {
                if (position - mFileOffset > mTotalSize) {
                    throw new IOException(
                            "Cannot map to buffer because position exceed current file size.");
                }
                if (position - mFileOffset + size > mTotalSize) {
                    size = mTotalSize - (position - mFileOffset);
                }
                return mDelegate.map(mode, position, size);
            }

            @Override
            protected void implCloseChannel() throws IOException {
                mDelegate.close();
            }

            @Override
            public int write(ByteBuffer src) throws IOException {
                throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE);
            }

            @Override
            public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
                throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE);
            }

            @Override
            public int write(ByteBuffer src, long position) throws IOException {
                throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE);
            }

            @Override
            public long transferFrom(ReadableByteChannel src, long position, long count)
                    throws IOException {
                throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE);
            }

            @Override
            public FileChannel truncate(long size) throws IOException {
                throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE);
            }

            @Override
            public void force(boolean metaData) throws IOException {
                throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE);
            }

            @Override
            public FileLock lock(long position, long size, boolean shared) throws IOException {
                throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE);
            }

            @Override
            public FileLock tryLock(long position, long size, boolean shared) throws IOException {
                throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE);
            }
            super.reset();
        }
    }