class RandomAccessInputStream extends InputStream
{
    private static final Logger LOG = LogManager.getLogger(RandomAccessInputStream.class);

    private final RandomAccessRead input;
    private long position;

    /**
     * Creates a new RandomAccessInputStream, with a position of zero. The InputStream will maintain
     * its own position independent of the RandomAccessRead.
     *
     * @param randomAccessRead The RandomAccessRead to read from.
     */
    public RandomAccessInputStream(RandomAccessRead randomAccessRead)
    {
        input = randomAccessRead;
        position = 0;
    }

    void restorePosition() throws IOException
    {
        input.seek(position);
    }
    
    @Override
    public int available() throws IOException
    {
        return (int) Math.max(0, Math.min(input.length() - position, Integer.MAX_VALUE));
    }

    @Override
    public int read() throws IOException
    {
        restorePosition();
        if (input.isEOF())
        {
            return -1;
        }
        int b = input.read();
        if (b != -1)
        {
            position += 1;
        }
        else
        {
            // should never happen due to prior isEOF() check
            // unless there is an unsynchronized concurrent access
            LOG.error("read() returns -1, assumed position: {}, actual position: {}", position,
                    input.getPosition());
        }
        return b;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException
    {<FILL_FUNCTION_BODY>}

    @Override
    public long skip(long n) throws IOException
    {
        if (n <= 0)
        {
            return 0;
        }
        restorePosition();
        input.seek(position + n);
        position += n;
        return n;
    }
}

        restorePosition();
        if (input.isEOF())
        {
            return -1;
        }
        int n = input.read(b, off, len);
        if (n != -1)
        {
            position += n;
        }
        else
        {
            // should never happen due to prior isEOF() check
            // unless there is an unsynchronized concurrent access
            LOG.error("read() returns -1, assumed position: {}, actual position: {}", position,
                    input.getPosition());
        }
        return n;
    
<methods>public void <init>() ,public int available() throws java.io.IOException,public void close() throws java.io.IOException,public synchronized void mark(int) ,public boolean markSupported() ,public static java.io.InputStream nullInputStream() ,public abstract int read() throws java.io.IOException,public int read(byte[]) throws java.io.IOException,public int read(byte[], int, int) throws java.io.IOException,public byte[] readAllBytes() throws java.io.IOException,public byte[] readNBytes(int) throws java.io.IOException,public int readNBytes(byte[], int, int) throws java.io.IOException,public synchronized void reset() throws java.io.IOException,public long skip(long) throws java.io.IOException,public void skipNBytes(long) throws java.io.IOException,public long transferTo(java.io.OutputStream) throws java.io.IOException<variables>private static final int DEFAULT_BUFFER_SIZE,private static final int MAX_BUFFER_SIZE,private static final int MAX_SKIP_BUFFER_SIZE