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
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.ByteBuffer;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.CharBuffer;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.Charset;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.CharsetDecoder;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.CoderResult;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.CodingErrorAction;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.MalformedInputException;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.UnmappableCharacterException;
28a1603838fe9e865575c87982e32c6343740e464cElliott Hughesimport java.util.Arrays;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * A class for turning a byte stream into a character stream. Data read from the
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * source input stream is converted into characters by either a default or a
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * provided character converter. The default encoding is taken from the
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * "file.encoding" system property. {@code InputStreamReader} contains a buffer
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * of bytes read from the source stream and converts these into characters as
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * needed. The buffer size is 8K.
37f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see OutputStreamWriter
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class InputStreamReader extends Reader {
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private InputStream in;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean endOfInput = false;
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
45b748a9b827665a8b19d60af4b419503b45e74329Elliott Hughes    private CharsetDecoder decoder;
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
47b748a9b827665a8b19d60af4b419503b45e74329Elliott Hughes    private final ByteBuffer bytes = ByteBuffer.allocate(8192);
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new {@code InputStreamReader} on the {@link InputStream}
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code in}. This constructor sets the character converter to the encoding
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specified in the "file.encoding" property and falls back to ISO 8859_1
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * (ISO-Latin-1) if the property doesn't exist.
54f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input stream from which to read characters.
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public InputStreamReader(InputStream in) {
5946ff2ede6c9f5ad431303d388986ec3d72b2fbd3Elliott Hughes        this(in, Charset.defaultCharset());
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new InputStreamReader on the InputStream {@code in}. The
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * character converter that is used to decode bytes into characters is
659b9e9145bc55a47be42a9d3f7ecc9f6b533739b2Elliott Hughes     * identified by name by {@code charsetName}. If the encoding cannot be found, an
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * UnsupportedEncodingException error is thrown.
67f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the InputStream from which to read characters.
709b9e9145bc55a47be42a9d3f7ecc9f6b533739b2Elliott Hughes     * @param charsetName
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            identifies the character converter to use.
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NullPointerException
739b9e9145bc55a47be42a9d3f7ecc9f6b533739b2Elliott Hughes     *             if {@code charsetName} is {@code null}.
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws UnsupportedEncodingException
759b9e9145bc55a47be42a9d3f7ecc9f6b533739b2Elliott Hughes     *             if the encoding specified by {@code charsetName} cannot be found.
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
779b9e9145bc55a47be42a9d3f7ecc9f6b533739b2Elliott Hughes    public InputStreamReader(InputStream in, final String charsetName)
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws UnsupportedEncodingException {
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(in);
809b9e9145bc55a47be42a9d3f7ecc9f6b533739b2Elliott Hughes        if (charsetName == null) {
819b9e9145bc55a47be42a9d3f7ecc9f6b533739b2Elliott Hughes            throw new NullPointerException("charsetName == null");
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.in = in;
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
859b9e9145bc55a47be42a9d3f7ecc9f6b533739b2Elliott Hughes            decoder = Charset.forName(charsetName).newDecoder().onMalformedInput(
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    CodingErrorAction.REPLACE).onUnmappableCharacter(
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    CodingErrorAction.REPLACE);
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IllegalArgumentException e) {
8943f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein            throw (UnsupportedEncodingException)
909b9e9145bc55a47be42a9d3f7ecc9f6b533739b2Elliott Hughes                    new UnsupportedEncodingException(charsetName).initCause(e);
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
9243f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein        bytes.limit(0);
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new InputStreamReader on the InputStream {@code in} and
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * CharsetDecoder {@code dec}.
98f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the source InputStream from which to read characters.
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param dec
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the CharsetDecoder used by the character conversion.
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public InputStreamReader(InputStream in, CharsetDecoder dec) {
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(in);
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        dec.averageCharsPerByte();
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.in = in;
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        decoder = dec;
10943f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein        bytes.limit(0);
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new InputStreamReader on the InputStream {@code in} and
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Charset {@code charset}.
115f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the source InputStream from which to read characters.
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param charset
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the Charset that defines the character converter
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public InputStreamReader(InputStream in, Charset charset) {
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(in);
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.in = in;
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        decoder = charset.newDecoder().onMalformedInput(
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                CodingErrorAction.REPLACE).onUnmappableCharacter(
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                CodingErrorAction.REPLACE);
12743f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein        bytes.limit(0);
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Closes this reader. This implementation closes the source InputStream and
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * releases all local storage.
133f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs attempting to close this reader.
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void close() throws IOException {
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (decoder != null) {
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                decoder.reset();
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            decoder = null;
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (in != null) {
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                in.close();
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                in = null;
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
152dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes     * Returns the historical name of the encoding used by this writer to convert characters to
153dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes     * bytes, or null if this writer has been closed. Most callers should probably keep
154dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes     * track of the String or Charset they passed in; this method may not return the same
155dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes     * name.
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getEncoding() {
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!isOpen()) {
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1618e9f4948e08c238998b44228ee30aea9d57a7573Elliott Hughes        return HistoricalCharsetNames.get(decoder.charset());
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Reads a single character from this reader and returns it as an integer
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * with the two higher-order bytes set to 0. Returns -1 if the end of the
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * reader has been reached. The byte value is either obtained from
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * converting bytes in this reader's buffer or by first filling the buffer
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * from the source InputStream and then reading from the buffer.
170f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the character read or -1 if the end of the reader has been
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         reached.
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if this reader is closed or some other I/O error occurs.
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int read() throws IOException {
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!isOpen()) {
180b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw new IOException("InputStreamReader is closed");
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
182171dc20afe5071d5cbfad7103903bfa2c1f8d00fElliott Hughes            char[] buf = new char[1];
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return read(buf, 0, 1) != -1 ? buf[0] : -1;
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Reads at most {@code length} characters from this reader and stores them
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * at position {@code offset} in the character array {@code buf}. Returns
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the number of characters actually read or -1 if the end of the reader has
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * been reached. The bytes are either obtained from converting bytes in this
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * reader's buffer or by first filling the buffer from the source
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * InputStream and then reading from the buffer.
194f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
195bf87c56b39383f6b11c36c3cdc93df4b03fed914Brian Carlstrom     * @param buffer
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the array to store the characters read.
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param offset
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the initial position in {@code buf} to store the characters
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            read from this reader.
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param length
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the maximum number of characters to read.
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the number of characters read or -1 if the end of the reader has
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         been reached.
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IndexOutOfBoundsException
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if {@code offset < 0} or {@code length < 0}, or if
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@code offset + length} is greater than the length of
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@code buf}.
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if this reader is closed or some other I/O error occurs.
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
212b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes    public int read(char[] buffer, int offset, int length) throws IOException {
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!isOpen()) {
215b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw new IOException("InputStreamReader is closed");
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
217a1603838fe9e865575c87982e32c6343740e464cElliott Hughes
218a1603838fe9e865575c87982e32c6343740e464cElliott Hughes            Arrays.checkOffsetAndCount(buffer.length, offset, length);
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length == 0) {
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return 0;
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
22243f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein
223b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            CharBuffer out = CharBuffer.wrap(buffer, offset, length);
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            CoderResult result = CoderResult.UNDERFLOW;
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
22643f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein            // bytes.remaining() indicates number of bytes in buffer
22743f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein            // when 1-st time entered, it'll be equal to zero
22843f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein            boolean needInput = !bytes.hasRemaining();
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (out.hasRemaining()) {
23143f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                // fill the buffer if needed
23243f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                if (needInput) {
23355392539fea537abfb6581b474918f9d611fba27Jesse Wilson                    try {
234b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                        if (in.available() == 0 && out.position() > offset) {
23555392539fea537abfb6581b474918f9d611fba27Jesse Wilson                            // we could return the result without blocking read
23655392539fea537abfb6581b474918f9d611fba27Jesse Wilson                            break;
23755392539fea537abfb6581b474918f9d611fba27Jesse Wilson                        }
23855392539fea537abfb6581b474918f9d611fba27Jesse Wilson                    } catch (IOException e) {
23955392539fea537abfb6581b474918f9d611fba27Jesse Wilson                        // available didn't work so just try the read
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2429229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes                    int desiredByteCount = bytes.capacity() - bytes.limit();
24343f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                    int off = bytes.arrayOffset() + bytes.limit();
2449229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes                    int actualByteCount = in.read(bytes.array(), off, desiredByteCount);
24543f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein
2469229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes                    if (actualByteCount == -1) {
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        endOfInput = true;
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        break;
2499229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes                    } else if (actualByteCount == 0) {
25043f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                        break;
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
2529229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes                    bytes.limit(bytes.limit() + actualByteCount);
25343f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                    needInput = false;
25443f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                }
25543f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein
25643f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                // decode bytes
25743f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                result = decoder.decode(bytes, out, false);
25843f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein
25943f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                if (result.isUnderflow()) {
26043f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                    // compact the buffer if no space left
26143f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                    if (bytes.limit() == bytes.capacity()) {
26243f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                        bytes.compact();
26343f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                        bytes.limit(bytes.position());
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        bytes.position(0);
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
26643f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                    needInput = true;
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (result == CoderResult.UNDERFLOW && endOfInput) {
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result = decoder.decode(bytes, out, true);
274f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                decoder.flush(out);
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                decoder.reset();
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
2773bdd9bb460941429ab11dfa13596768f3dc246adElliott Hughes            if (result.isMalformed() || result.isUnmappable()) {
2783bdd9bb460941429ab11dfa13596768f3dc246adElliott Hughes                result.throwException();
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return out.position() - offset == 0 ? -1 : out.position() - offset;
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean isOpen() {
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return in != null;
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates whether this reader is ready to be read without blocking. If
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the result is {@code true}, the next {@code read()} will not block. If
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the result is {@code false} then this reader may or may not block when
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code read()} is called. This implementation returns {@code true} if
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * there are bytes available in the buffer or the source stream has bytes
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * available.
296f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if the receiver will not block when {@code read()}
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         is called, {@code false} if unknown or blocking will occur.
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if this reader is closed or some other I/O error occurs.
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean ready() throws IOException {
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (in == null) {
306b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw new IOException("InputStreamReader is closed");
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
30943f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                return bytes.hasRemaining() || in.available() > 0;
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (IOException e) {
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return false;
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
316