1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.io;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20a1603838fe9e865575c87982e32c6343740e464cElliott Hughesimport java.util.Arrays;
21a1603838fe9e865575c87982e32c6343740e464cElliott Hughes
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Wraps an existing {@link InputStream} and <em>buffers</em> the input.
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Expensive interaction with the underlying input stream is minimized, since
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * most (smaller) requests can be satisfied by accessing the buffer alone. The
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * drawback is that some extra space is required to hold the buffer and that
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * copying takes place when filling that buffer, but this is usually outweighed
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * by the performance benefits.
29f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p/>A typical application pattern for the class looks like this:<p/>
31f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <pre>
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * BufferedInputStream buf = new BufferedInputStream(new FileInputStream(&quot;file.java&quot;));
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * </pre>
35f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see BufferedOutputStream
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class BufferedInputStream extends FilterInputStream {
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
4029d763959dd79e8aeacf2674c074d708d596477aKenny Root     * The default buffer size if it is not specified.
4129d763959dd79e8aeacf2674c074d708d596477aKenny Root     *
4229d763959dd79e8aeacf2674c074d708d596477aKenny Root     * @hide
4329d763959dd79e8aeacf2674c074d708d596477aKenny Root     */
4429d763959dd79e8aeacf2674c074d708d596477aKenny Root    public static final int DEFAULT_BUFFER_SIZE = 8192;
4529d763959dd79e8aeacf2674c074d708d596477aKenny Root
4629d763959dd79e8aeacf2674c074d708d596477aKenny Root    /**
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The buffer containing the current bytes read from the target InputStream.
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected volatile byte[] buf;
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The total number of bytes inside the byte array {@code buf}.
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int count;
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The current limit, which when passed, invalidates the current mark.
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int marklimit;
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The currently marked position. -1 indicates no mark has been set or the
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * mark has been invalidated.
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int markpos = -1;
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The current position within the byte array {@code buf}.
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int pos;
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
73fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * Constructs a new {@code BufferedInputStream}, providing {@code in} with a buffer
74fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * of 8192 bytes.
75f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
76858dd42310622fd1b77bfa0fbd85ec851b3925c1Jesse Wilson     * <p><strong>Warning:</strong> passing a null source creates a closed
77858dd42310622fd1b77bfa0fbd85ec851b3925c1Jesse Wilson     * {@code BufferedInputStream}. All read operations on such a stream will
78858dd42310622fd1b77bfa0fbd85ec851b3925c1Jesse Wilson     * fail with an IOException.
79858dd42310622fd1b77bfa0fbd85ec851b3925c1Jesse Wilson     *
80fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * @param in the {@code InputStream} the buffer reads from.
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public BufferedInputStream(InputStream in) {
8329d763959dd79e8aeacf2674c074d708d596477aKenny Root        this(in, DEFAULT_BUFFER_SIZE);
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
87fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * Constructs a new {@code BufferedInputStream}, providing {@code in} with {@code size} bytes
88fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * of buffer.
89f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
90858dd42310622fd1b77bfa0fbd85ec851b3925c1Jesse Wilson     * <p><strong>Warning:</strong> passing a null source creates a closed
91858dd42310622fd1b77bfa0fbd85ec851b3925c1Jesse Wilson     * {@code BufferedInputStream}. All read operations on such a stream will
92858dd42310622fd1b77bfa0fbd85ec851b3925c1Jesse Wilson     * fail with an IOException.
93858dd42310622fd1b77bfa0fbd85ec851b3925c1Jesse Wilson     *
94fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * @param in the {@code InputStream} the buffer reads from.
95fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * @param size the size of buffer in bytes.
96fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * @throws IllegalArgumentException if {@code size <= 0}.
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public BufferedInputStream(InputStream in, int size) {
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(in);
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (size <= 0) {
101b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IllegalArgumentException("size <= 0");
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        buf = new byte[size];
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
107582d926fbf5f5fd4800def67f86ecfedee44681eElliott Hughes     * Returns an estimated number of bytes that can be read or skipped without blocking for more
108582d926fbf5f5fd4800def67f86ecfedee44681eElliott Hughes     * input. This method returns the number of bytes available in the buffer
109582d926fbf5f5fd4800def67f86ecfedee44681eElliott Hughes     * plus those available in the source stream, but see {@link InputStream#available} for
110582d926fbf5f5fd4800def67f86ecfedee44681eElliott Hughes     * important caveats.
111f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
112582d926fbf5f5fd4800def67f86ecfedee44681eElliott Hughes     * @return the estimated number of bytes available
113582d926fbf5f5fd4800def67f86ecfedee44681eElliott Hughes     * @throws IOException if this stream is closed or an error occurs
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized int available() throws IOException {
117f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        InputStream localIn = in; // 'in' could be invalidated by close()
118f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (buf == null || localIn == null) {
119b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw streamClosed();
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
121f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return count - pos + localIn.available();
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
124b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes    private IOException streamClosed() throws IOException {
125b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes        throw new IOException("BufferedInputStream is closed");
126b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes    }
127b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Closes this stream. The source stream is closed and any resources
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * associated with it are released.
131f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs while closing this stream.
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
136f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public void close() throws IOException {
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        buf = null;
138f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        InputStream localIn = in;
139f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        in = null;
140f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (localIn != null) {
141f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            localIn.close();
142f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
145f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    private int fillbuf(InputStream localIn, byte[] localBuf)
146f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            throws IOException {
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (markpos == -1 || (pos - markpos >= marklimit)) {
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /* Mark position not set or exceeded readlimit */
149f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            int result = localIn.read(localBuf);
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (result > 0) {
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                markpos = -1;
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                pos = 0;
15353009b25cac39d385f4b0f54af5db33d6db98ec7Andreas Gampe                count = result;
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return result;
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
157f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (markpos == 0 && marklimit > localBuf.length) {
158f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            /* Increase buffer size to accommodate the readlimit */
159f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            int newLength = localBuf.length * 2;
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (newLength > marklimit) {
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                newLength = marklimit;
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] newbuf = new byte[newLength];
164f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            System.arraycopy(localBuf, 0, newbuf, 0, localBuf.length);
165f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            // Reassign buf, which will invalidate any local references
166f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            // FIXME: what if buf was null?
167f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            localBuf = buf = newbuf;
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (markpos > 0) {
169f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            System.arraycopy(localBuf, markpos, localBuf, 0, localBuf.length
170f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    - markpos);
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /* Set the new position and mark position */
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        pos -= markpos;
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        count = markpos = 0;
175f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        int bytesread = localIn.read(localBuf, pos, localBuf.length - pos);
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        count = bytesread <= 0 ? pos : pos + bytesread;
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return bytesread;
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets a mark position in this stream. The parameter {@code readlimit}
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * indicates how many bytes can be read before a mark is invalidated.
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Calling {@code reset()} will reposition the stream back to the marked
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * position if {@code readlimit} has not been surpassed. The underlying
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * buffer may be increased in size to allow {@code readlimit} number of
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * bytes to be supported.
187f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param readlimit
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the number of bytes that can be read before the mark is
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            invalidated.
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #reset()
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized void mark(int readlimit) {
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        marklimit = readlimit;
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        markpos = pos;
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates whether {@code BufferedInputStream} supports the {@code mark()}
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * and {@code reset()} methods.
202f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} for BufferedInputStreams.
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #mark(int)
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #reset()
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean markSupported() {
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return true;
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Reads a single byte from this stream and returns it as an integer in the
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * range from 0 to 255. Returns -1 if the end of the source string has been
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * reached. If the internal buffer does not contain any available bytes then
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * it is filled from the source stream and the first byte is returned.
217f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the byte read or -1 if the end of the source stream has been
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         reached.
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if this stream is closed or another IOException occurs.
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized int read() throws IOException {
225f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Use local refs since buf and in may be invalidated by an
226f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // unsynchronized close()
227f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        byte[] localBuf = buf;
228f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        InputStream localIn = in;
229f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (localBuf == null || localIn == null) {
230b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw streamClosed();
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /* Are there buffered bytes available? */
234f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (pos >= count && fillbuf(localIn, localBuf) == -1) {
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return -1; /* no, fill buffer */
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
237f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // localBuf may have been invalidated by fillbuf
238f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (localBuf != buf) {
239f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            localBuf = buf;
240f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (localBuf == null) {
241b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw streamClosed();
242f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
243f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /* Did filling the buffer fail with -1 (EOF)? */
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (count - pos > 0) {
247f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return localBuf[pos++] & 0xFF;
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return -1;
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
252325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes    @Override public synchronized int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
253f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Use local ref since buf may be invalidated by an unsynchronized
254f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // close()
255f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        byte[] localBuf = buf;
256f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (localBuf == null) {
257b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw streamClosed();
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
259325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes        Arrays.checkOffsetAndCount(buffer.length, byteOffset, byteCount);
260a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        if (byteCount == 0) {
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
263f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        InputStream localIn = in;
264f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (localIn == null) {
265b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw streamClosed();
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int required;
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (pos < count) {
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /* There are bytes available in the buffer. */
271a1603838fe9e865575c87982e32c6343740e464cElliott Hughes            int copylength = count - pos >= byteCount ? byteCount : count - pos;
272325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes            System.arraycopy(localBuf, pos, buffer, byteOffset, copylength);
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pos += copylength;
274a1603838fe9e865575c87982e32c6343740e464cElliott Hughes            if (copylength == byteCount || localIn.available() == 0) {
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return copylength;
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
277325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes            byteOffset += copylength;
278a1603838fe9e865575c87982e32c6343740e464cElliott Hughes            required = byteCount - copylength;
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
280a1603838fe9e865575c87982e32c6343740e464cElliott Hughes            required = byteCount;
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (true) {
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int read;
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /*
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * If we're not marked and the required size is greater than the
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * buffer, simply read the bytes directly bypassing the buffer.
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
289f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (markpos == -1 && required >= localBuf.length) {
290325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes                read = localIn.read(buffer, byteOffset, required);
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (read == -1) {
292a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                    return required == byteCount ? -1 : byteCount - required;
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
295f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (fillbuf(localIn, localBuf) == -1) {
296a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                    return required == byteCount ? -1 : byteCount - required;
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
298f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // localBuf may have been invalidated by fillbuf
299f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (localBuf != buf) {
300f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    localBuf = buf;
301f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if (localBuf == null) {
302b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                        throw streamClosed();
303f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
304f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
305f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                read = count - pos >= required ? required : count - pos;
307325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes                System.arraycopy(localBuf, pos, buffer, byteOffset, read);
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                pos += read;
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            required -= read;
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (required == 0) {
312a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                return byteCount;
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
314f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (localIn.available() == 0) {
315a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                return byteCount - required;
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
317325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes            byteOffset += read;
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Resets this stream to the last marked location.
323f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if this stream is closed, no mark has been set or the mark is
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             no longer valid because more than {@code readlimit} bytes
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             have been read since setting the mark.
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #mark(int)
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized void reset() throws IOException {
332f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (buf == null) {
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IOException("Stream is closed");
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
33587c12db778a8d8621d885b5b92e86b905d0f210cHenrik Baard        if (markpos == -1) {
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IOException("Mark has been invalidated.");
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        pos = markpos;
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
342f9480f317cddcec859025833b748f096247a40aaElliott Hughes     * Skips {@code byteCount} bytes in this stream. Subsequent calls to
343f9480f317cddcec859025833b748f096247a40aaElliott Hughes     * {@code read} will not return these bytes unless {@code reset} is
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * used.
345f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
346f9480f317cddcec859025833b748f096247a40aaElliott Hughes     * @param byteCount
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the number of bytes to skip. {@code skip} does nothing and
348f9480f317cddcec859025833b748f096247a40aaElliott Hughes     *            returns 0 if {@code byteCount} is less than zero.
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the number of bytes actually skipped.
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if this stream is closed or another IOException occurs.
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
354f9480f317cddcec859025833b748f096247a40aaElliott Hughes    public synchronized long skip(long byteCount) throws IOException {
355f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Use local refs since buf and in may be invalidated by an
356f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // unsynchronized close()
357f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        byte[] localBuf = buf;
358f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        InputStream localIn = in;
359f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (localBuf == null) {
360b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw streamClosed();
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
362f9480f317cddcec859025833b748f096247a40aaElliott Hughes        if (byteCount < 1) {
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
365f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (localIn == null) {
366b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw streamClosed();
367f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
369f9480f317cddcec859025833b748f096247a40aaElliott Hughes        if (count - pos >= byteCount) {
370f9480f317cddcec859025833b748f096247a40aaElliott Hughes            pos += byteCount;
371f9480f317cddcec859025833b748f096247a40aaElliott Hughes            return byteCount;
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long read = count - pos;
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        pos = count;
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (markpos != -1) {
377f9480f317cddcec859025833b748f096247a40aaElliott Hughes            if (byteCount <= marklimit) {
378f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (fillbuf(localIn, localBuf) == -1) {
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return read;
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
381f9480f317cddcec859025833b748f096247a40aaElliott Hughes                if (count - pos >= byteCount - read) {
382f9480f317cddcec859025833b748f096247a40aaElliott Hughes                    pos += byteCount - read;
383f9480f317cddcec859025833b748f096247a40aaElliott Hughes                    return byteCount;
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Couldn't get all the bytes, skip what we read
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                read += (count - pos);
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                pos = count;
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return read;
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
391f9480f317cddcec859025833b748f096247a40aaElliott Hughes        return read + localIn.skip(byteCount - read);
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
394