Merge from mainline
[official-gcc.git] / libjava / classpath / java / io / InputStreamReader.java
blobef8fd4542db9631dc6cbaf7ebb0c15c548ebdcfc
1 /* InputStreamReader.java -- Reader than transforms bytes to chars
2 Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package java.io;
41 import gnu.java.nio.charset.EncodingHelper;
43 import java.nio.ByteBuffer;
44 import java.nio.CharBuffer;
45 import java.nio.charset.Charset;
46 import java.nio.charset.CharsetDecoder;
47 import java.nio.charset.CoderResult;
48 import java.nio.charset.CodingErrorAction;
50 /**
51 * This class reads characters from a byte input stream. The characters
52 * read are converted from bytes in the underlying stream by a
53 * decoding layer. The decoding layer transforms bytes to chars according
54 * to an encoding standard. There are many available encodings to choose
55 * from. The desired encoding can either be specified by name, or if no
56 * encoding is selected, the system default encoding will be used. The
57 * system default encoding name is determined from the system property
58 * <code>file.encoding</code>. The only encodings that are guaranteed to
59 * be availalbe are "8859_1" (the Latin-1 character set) and "UTF8".
60 * Unforunately, Java does not provide a mechanism for listing the
61 * ecodings that are supported in a given implementation.
62 * <p>
63 * Here is a list of standard encoding names that may be available:
64 * <p>
65 * <ul>
66 * <li>8859_1 (ISO-8859-1/Latin-1)</li>
67 * <li>8859_2 (ISO-8859-2/Latin-2)</li>
68 * <li>8859_3 (ISO-8859-3/Latin-3)</li>
69 * <li>8859_4 (ISO-8859-4/Latin-4)</li>
70 * <li>8859_5 (ISO-8859-5/Latin-5)</li>
71 * <li>8859_6 (ISO-8859-6/Latin-6)</li>
72 * <li>8859_7 (ISO-8859-7/Latin-7)</li>
73 * <li>8859_8 (ISO-8859-8/Latin-8)</li>
74 * <li>8859_9 (ISO-8859-9/Latin-9)</li>
75 * <li>ASCII (7-bit ASCII)</li>
76 * <li>UTF8 (UCS Transformation Format-8)</li>
77 * <li>More later</li>
78 * </ul>
79 * <p>
80 * It is recommended that applications do not use
81 * <code>InputStreamReader</code>'s
82 * directly. Rather, for efficiency purposes, an object of this class
83 * should be wrapped by a <code>BufferedReader</code>.
84 * <p>
85 * Due to a deficiency the Java class library design, there is no standard
86 * way for an application to install its own byte-character encoding.
88 * @see BufferedReader
89 * @see InputStream
91 * @author Robert Schuster
92 * @author Aaron M. Renn (arenn@urbanophile.com)
93 * @author Per Bothner (bothner@cygnus.com)
94 * @date April 22, 1998.
96 public class InputStreamReader extends Reader
98 /**
99 * The input stream.
101 private InputStream in;
104 * The charset decoder.
106 private CharsetDecoder decoder;
109 * End of stream reached.
111 private boolean isDone = false;
114 * Need this.
116 private float maxBytesPerChar;
119 * Buffer holding surplus loaded bytes (if any)
121 private ByteBuffer byteBuffer;
124 * java.io canonical name of the encoding.
126 private String encoding;
129 * We might decode to a 2-char UTF-16 surrogate, which won't fit in the
130 * output buffer. In this case we need to save the surrogate char.
132 private char savedSurrogate;
133 private boolean hasSavedSurrogate = false;
136 * This method initializes a new instance of <code>InputStreamReader</code>
137 * to read from the specified stream using the default encoding.
139 * @param in The <code>InputStream</code> to read from
141 public InputStreamReader(InputStream in)
143 if (in == null)
144 throw new NullPointerException();
145 this.in = in;
146 try
148 encoding = System.getProperty("file.encoding");
149 // Don't use NIO if avoidable
150 if(EncodingHelper.isISOLatin1(encoding))
152 encoding = "ISO8859_1";
153 maxBytesPerChar = 1f;
154 decoder = null;
155 return;
157 Charset cs = EncodingHelper.getCharset(encoding);
158 decoder = cs.newDecoder();
159 encoding = EncodingHelper.getOldCanonical(cs.name());
160 try {
161 maxBytesPerChar = cs.newEncoder().maxBytesPerChar();
162 } catch(UnsupportedOperationException _){
163 maxBytesPerChar = 1f;
165 decoder.onMalformedInput(CodingErrorAction.REPLACE);
166 decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
167 decoder.reset();
168 } catch(RuntimeException e) {
169 encoding = "ISO8859_1";
170 maxBytesPerChar = 1f;
171 decoder = null;
172 } catch(UnsupportedEncodingException e) {
173 encoding = "ISO8859_1";
174 maxBytesPerChar = 1f;
175 decoder = null;
180 * This method initializes a new instance of <code>InputStreamReader</code>
181 * to read from the specified stream using a caller supplied character
182 * encoding scheme. Note that due to a deficiency in the Java language
183 * design, there is no way to determine which encodings are supported.
185 * @param in The <code>InputStream</code> to read from
186 * @param encoding_name The name of the encoding scheme to use
188 * @exception UnsupportedEncodingException If the encoding scheme
189 * requested is not available.
191 public InputStreamReader(InputStream in, String encoding_name)
192 throws UnsupportedEncodingException
194 if (in == null
195 || encoding_name == null)
196 throw new NullPointerException();
198 this.in = in;
199 // Don't use NIO if avoidable
200 if(EncodingHelper.isISOLatin1(encoding_name))
202 encoding = "ISO8859_1";
203 maxBytesPerChar = 1f;
204 decoder = null;
205 return;
207 try {
208 Charset cs = EncodingHelper.getCharset(encoding_name);
209 try {
210 maxBytesPerChar = cs.newEncoder().maxBytesPerChar();
211 } catch(UnsupportedOperationException _){
212 maxBytesPerChar = 1f;
215 decoder = cs.newDecoder();
216 decoder.onMalformedInput(CodingErrorAction.REPLACE);
217 decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
218 decoder.reset();
220 // The encoding should be the old name, if such exists.
221 encoding = EncodingHelper.getOldCanonical(cs.name());
222 } catch(RuntimeException e) {
223 encoding = "ISO8859_1";
224 maxBytesPerChar = 1f;
225 decoder = null;
230 * Creates an InputStreamReader that uses a decoder of the given
231 * charset to decode the bytes in the InputStream into
232 * characters.
234 * @since 1.5
236 public InputStreamReader(InputStream in, Charset charset) {
237 this.in = in;
238 decoder = charset.newDecoder();
240 decoder.onMalformedInput(CodingErrorAction.REPLACE);
241 decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
242 decoder.reset();
243 encoding = EncodingHelper.getOldCanonical(charset.name());
247 * Creates an InputStreamReader that uses the given charset decoder
248 * to decode the bytes in the InputStream into characters.
250 * @since 1.5
252 public InputStreamReader(InputStream in, CharsetDecoder decoder) {
253 this.in = in;
254 this.decoder = decoder;
256 Charset charset = decoder.charset();
257 try {
258 if (charset == null)
259 maxBytesPerChar = 1f;
260 else
261 maxBytesPerChar = charset.newEncoder().maxBytesPerChar();
262 } catch(UnsupportedOperationException _){
263 maxBytesPerChar = 1f;
266 decoder.onMalformedInput(CodingErrorAction.REPLACE);
267 decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
268 decoder.reset();
269 if (charset == null)
270 encoding = "US-ASCII";
271 else
272 encoding = EncodingHelper.getOldCanonical(decoder.charset().name());
276 * This method closes this stream, as well as the underlying
277 * <code>InputStream</code>.
279 * @exception IOException If an error occurs
281 public void close() throws IOException
283 synchronized (lock)
285 // Makes sure all intermediate data is released by the decoder.
286 if (decoder != null)
287 decoder.reset();
288 if (in != null)
289 in.close();
290 in = null;
291 isDone = true;
292 decoder = null;
297 * This method returns the name of the encoding that is currently in use
298 * by this object. If the stream has been closed, this method is allowed
299 * to return <code>null</code>.
301 * @return The current encoding name
303 public String getEncoding()
305 return in != null ? encoding : null;
309 * This method checks to see if the stream is ready to be read. It
310 * will return <code>true</code> if is, or <code>false</code> if it is not.
311 * If the stream is not ready to be read, it could (although is not required
312 * to) block on the next read attempt.
314 * @return <code>true</code> if the stream is ready to be read,
315 * <code>false</code> otherwise
317 * @exception IOException If an error occurs
319 public boolean ready() throws IOException
321 if (in == null)
322 throw new IOException("Reader has been closed");
324 return in.available() != 0;
328 * This method reads up to <code>length</code> characters from the stream into
329 * the specified array starting at index <code>offset</code> into the
330 * array.
332 * @param buf The character array to recieve the data read
333 * @param offset The offset into the array to start storing characters
334 * @param length The requested number of characters to read.
336 * @return The actual number of characters read, or -1 if end of stream.
338 * @exception IOException If an error occurs
340 public int read(char[] buf, int offset, int length) throws IOException
342 if (in == null)
343 throw new IOException("Reader has been closed");
344 if (isDone)
345 return -1;
346 if(decoder != null){
347 int totalBytes = (int)((double)length * maxBytesPerChar);
348 byte[] bytes = new byte[totalBytes];
350 int remaining = 0;
351 if(byteBuffer != null)
353 remaining = byteBuffer.remaining();
354 byteBuffer.get(bytes, 0, remaining);
356 int read;
357 if(totalBytes - remaining > 0)
359 read = in.read(bytes, remaining, totalBytes - remaining);
360 if(read == -1){
361 read = remaining;
362 isDone = true;
363 } else
364 read += remaining;
365 } else
366 read = remaining;
367 byteBuffer = ByteBuffer.wrap(bytes, 0, read);
368 CharBuffer cb = CharBuffer.wrap(buf, offset, length);
369 int startPos = cb.position();
371 if(hasSavedSurrogate){
372 hasSavedSurrogate = false;
373 cb.put(savedSurrogate);
374 read++;
377 CoderResult cr = decoder.decode(byteBuffer, cb, isDone);
378 decoder.reset();
379 // 1 char remains which is the first half of a surrogate pair.
380 if(cr.isOverflow() && cb.hasRemaining()){
381 CharBuffer overflowbuf = CharBuffer.allocate(2);
382 cr = decoder.decode(byteBuffer, overflowbuf, isDone);
383 overflowbuf.flip();
384 if(overflowbuf.hasRemaining())
386 cb.put(overflowbuf.get());
387 savedSurrogate = overflowbuf.get();
388 hasSavedSurrogate = true;
389 isDone = false;
393 if(byteBuffer.hasRemaining()) {
394 byteBuffer.compact();
395 byteBuffer.flip();
396 isDone = false;
397 } else
398 byteBuffer = null;
400 read = cb.position() - startPos;
401 return (read <= 0) ? -1 : read;
402 } else {
403 byte[] bytes = new byte[length];
404 int read = in.read(bytes);
405 for(int i=0;i<read;i++)
406 buf[offset+i] = (char)(bytes[i]&0xFF);
407 return read;
412 * Reads an char from the input stream and returns it
413 * as an int in the range of 0-65535. This method also will return -1 if
414 * the end of the stream has been reached.
415 * <p>
416 * This method will block until the char can be read.
418 * @return The char read or -1 if end of stream
420 * @exception IOException If an error occurs
422 public int read() throws IOException
424 char[] buf = new char[1];
425 int count = read(buf, 0, 1);
426 return count > 0 ? buf[0] : -1;
430 * Skips the specified number of chars in the stream. It
431 * returns the actual number of chars skipped, which may be less than the
432 * requested amount.
434 * @param count The requested number of chars to skip
436 * @return The actual number of chars skipped.
438 * @exception IOException If an error occurs
440 public long skip(long count) throws IOException
442 if (in == null)
443 throw new IOException("Reader has been closed");
445 return super.skip(count);