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    /**
152817b74b58acb99b2e161228e329a6e6ae2d9d62bElliott Hughes     * Returns the canonical 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        }
161817b74b58acb99b2e161228e329a6e6ae2d9d62bElliott Hughes        return decoder.charset().name();
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    /**
188325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes     * Reads up to {@code count} characters from this reader and stores them
189325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes     * at position {@code offset} in the character array {@code buffer}. 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     *
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IndexOutOfBoundsException
196325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes     *     if {@code offset < 0 || count < 0 || offset + count > buffer.length}.
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if this reader is closed or some other I/O error occurs.
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
201325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes    public int read(char[] buffer, int offset, int count) throws IOException {
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!isOpen()) {
204b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw new IOException("InputStreamReader is closed");
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
206a1603838fe9e865575c87982e32c6343740e464cElliott Hughes
207325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes            Arrays.checkOffsetAndCount(buffer.length, offset, count);
208325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes            if (count == 0) {
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return 0;
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
21143f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein
212325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes            CharBuffer out = CharBuffer.wrap(buffer, offset, count);
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            CoderResult result = CoderResult.UNDERFLOW;
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
21543f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein            // bytes.remaining() indicates number of bytes in buffer
21643f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein            // when 1-st time entered, it'll be equal to zero
21743f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein            boolean needInput = !bytes.hasRemaining();
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (out.hasRemaining()) {
22043f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                // fill the buffer if needed
22143f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                if (needInput) {
22255392539fea537abfb6581b474918f9d611fba27Jesse Wilson                    try {
223b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                        if (in.available() == 0 && out.position() > offset) {
22455392539fea537abfb6581b474918f9d611fba27Jesse Wilson                            // we could return the result without blocking read
22555392539fea537abfb6581b474918f9d611fba27Jesse Wilson                            break;
22655392539fea537abfb6581b474918f9d611fba27Jesse Wilson                        }
22755392539fea537abfb6581b474918f9d611fba27Jesse Wilson                    } catch (IOException e) {
22855392539fea537abfb6581b474918f9d611fba27Jesse Wilson                        // available didn't work so just try the read
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2319229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes                    int desiredByteCount = bytes.capacity() - bytes.limit();
23243f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                    int off = bytes.arrayOffset() + bytes.limit();
2339229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes                    int actualByteCount = in.read(bytes.array(), off, desiredByteCount);
23443f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein
2359229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes                    if (actualByteCount == -1) {
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        endOfInput = true;
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        break;
2389229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes                    } else if (actualByteCount == 0) {
23943f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                        break;
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
2419229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes                    bytes.limit(bytes.limit() + actualByteCount);
24243f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                    needInput = false;
24343f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                }
24443f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein
24543f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                // decode bytes
24643f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                result = decoder.decode(bytes, out, false);
24743f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein
24843f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                if (result.isUnderflow()) {
24943f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                    // compact the buffer if no space left
25043f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                    if (bytes.limit() == bytes.capacity()) {
25143f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                        bytes.compact();
25243f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                        bytes.limit(bytes.position());
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        bytes.position(0);
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
25543f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                    needInput = true;
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (result == CoderResult.UNDERFLOW && endOfInput) {
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result = decoder.decode(bytes, out, true);
263f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                decoder.flush(out);
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                decoder.reset();
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
2663bdd9bb460941429ab11dfa13596768f3dc246adElliott Hughes            if (result.isMalformed() || result.isUnmappable()) {
2673bdd9bb460941429ab11dfa13596768f3dc246adElliott Hughes                result.throwException();
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return out.position() - offset == 0 ? -1 : out.position() - offset;
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean isOpen() {
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return in != null;
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates whether this reader is ready to be read without blocking. If
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the result is {@code true}, the next {@code read()} will not block. If
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the result is {@code false} then this reader may or may not block when
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code read()} is called. This implementation returns {@code true} if
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * there are bytes available in the buffer or the source stream has bytes
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * available.
285f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if the receiver will not block when {@code read()}
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         is called, {@code false} if unknown or blocking will occur.
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if this reader is closed or some other I/O error occurs.
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean ready() throws IOException {
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (in == null) {
295b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw new IOException("InputStreamReader is closed");
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
29843f11e509433970a5f33a6e5edd9b90089fa7d88Dan Bornstein                return bytes.hasRemaining() || in.available() > 0;
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (IOException e) {
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return false;
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
305