/[classpath]/classpath/java/io/InputStreamReader.java
ViewVC logotype

Diff of /classpath/java/io/InputStreamReader.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.21 by tromey, Thu Mar 10 19:35:51 2005 UTC revision 1.22 by smarothy, Fri Apr 15 16:13:34 2005 UTC
# Line 38  exception statement from your version. * Line 38  exception statement from your version. *
38    
39  package java.io;  package java.io;
40    
41  import java.nio.channels.Channels;  import java.nio.charset.UnsupportedCharsetException;
42    import java.nio.charset.CharacterCodingException;
43    import java.nio.charset.IllegalCharsetNameException;
44    import java.nio.charset.CoderResult;
45    import java.nio.charset.CodingErrorAction;
46  import java.nio.charset.Charset;  import java.nio.charset.Charset;
47  import java.nio.charset.CharsetDecoder;  import java.nio.charset.CharsetDecoder;
48    import java.nio.CharBuffer;
49  import gnu.java.io.EncodingManager;  import java.nio.ByteBuffer;
50  import gnu.java.io.decode.Decoder;  import gnu.java.nio.charset.EncodingHelper;
51    
52  /**  /**
53   * This class reads characters from a byte input stream.   The characters   * This class reads characters from a byte input stream.   The characters
# Line 86  import gnu.java.io.decode.Decoder; Line 90  import gnu.java.io.decode.Decoder;
90   * @see BufferedReader   * @see BufferedReader
91   * @see InputStream   * @see InputStream
92   *   *
93     * @author Robert Schuster
94   * @author Aaron M. Renn (arenn@urbanophile.com)   * @author Aaron M. Renn (arenn@urbanophile.com)
95   * @author Per Bothner (bothner@cygnus.com)   * @author Per Bothner (bothner@cygnus.com)
96   * @date April 22, 1998.     * @date April 22, 1998.  
97   */   */
98  public class InputStreamReader extends Reader  public class InputStreamReader extends Reader
99  {  {
100    /*    /**
101     * This is the byte-character decoder class that does the reading and     * The input stream.
102     * translation of bytes from the underlying stream.     */
103      private InputStream in;
104    
105      /**
106       * The charset decoder.
107       */
108      private CharsetDecoder decoder;
109    
110      /**
111       * End of stream reached.
112       */
113      private boolean isDone = false;
114    
115      /**
116       * Need this.
117     */     */
118    private Reader in;    private float maxBytesPerChar;
119    
120      /**
121       * Buffer holding surplus loaded bytes (if any)
122       */
123      private ByteBuffer byteBuffer;
124    
125      /**
126       * java.io canonical name of the encoding.
127       */
128    private String encoding;    private String encoding;
129      
130      /**
131       * We might decode to a 2-char UTF-16 surrogate, which won't fit in the
132       * output buffer. In this case we need to save the surrogate char.
133       */
134      private char savedSurrogate;
135      private boolean hasSavedSurrogate = false;
136    
137    /**    /**
138     * This method initializes a new instance of <code>InputStreamReader</code>     * This method initializes a new instance of <code>InputStreamReader</code>
139     * to read from the specified stream using the default encoding.     * to read from the specified stream using the default encoding.
# Line 110  public class InputStreamReader extends R Line 144  public class InputStreamReader extends R
144    {    {
145      if (in == null)      if (in == null)
146        throw new NullPointerException();        throw new NullPointerException();
147            this.in = in;
148      Decoder decoder =  EncodingManager.getDecoder(in);      try
149      encoding = decoder.getSchemeName();          {
150                  encoding = System.getProperty("file.encoding");
151      this.in = decoder;            // Don't use NIO if avoidable
152              if(EncodingHelper.isISOLatin1(encoding))
153                {
154                  encoding = "ISO8859_1";
155                  maxBytesPerChar = 1f;
156                  decoder = null;
157                  return;
158                }
159              Charset cs = EncodingHelper.getCharset(encoding);
160              decoder = cs.newDecoder();
161              encoding = EncodingHelper.getOldCanonical(cs.name());
162              try {
163                  maxBytesPerChar = cs.newEncoder().maxBytesPerChar();
164              } catch(UnsupportedOperationException _){
165                  maxBytesPerChar = 1f;
166              }
167              decoder.onMalformedInput(CodingErrorAction.REPLACE);
168              decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
169              decoder.reset();
170            } catch(RuntimeException e) {
171              encoding = "ISO8859_1";
172              maxBytesPerChar = 1f;
173              decoder = null;
174            } catch(UnsupportedEncodingException e) {
175              encoding = "ISO8859_1";
176              maxBytesPerChar = 1f;
177              decoder = null;
178            }
179    }    }
180    
181    /**    /**
# Line 136  public class InputStreamReader extends R Line 197  public class InputStreamReader extends R
197          || encoding_name == null)          || encoding_name == null)
198        throw new NullPointerException();        throw new NullPointerException();
199            
200      Decoder decoder = EncodingManager.getDecoder(in, encoding_name);      this.in = in;
201      encoding = decoder.getSchemeName();      // Don't use NIO if avoidable
202            if(EncodingHelper.isISOLatin1(encoding_name))
203      this.in = decoder;        {
204                encoding = "ISO8859_1";
205            maxBytesPerChar = 1f;
206            decoder = null;
207            return;
208          }
209        try {
210          Charset cs = EncodingHelper.getCharset(encoding_name);
211          try {
212            maxBytesPerChar = cs.newEncoder().maxBytesPerChar();
213          } catch(UnsupportedOperationException _){
214            maxBytesPerChar = 1f;
215          }
216    
217          decoder = cs.newDecoder();
218          decoder.onMalformedInput(CodingErrorAction.REPLACE);
219          decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
220          decoder.reset();
221    
222          // The encoding should be the old name, if such exists.
223          encoding = EncodingHelper.getOldCanonical(cs.name());
224        } catch(RuntimeException e) {
225          encoding = "ISO8859_1";
226          maxBytesPerChar = 1f;
227          decoder = null;
228        }
229    }    }
230    
231    /**    /**
232     * Creates an InputStreamReader that uses a decoder of the given     * Creates an InputStreamReader that uses a decoder of the given
233     * charset to decode the bytes in the InputStream into     * charset to decode the bytes in the InputStream into
234     * characters.     * characters.
    * @since 1.4  
235     */     */
236    public InputStreamReader(InputStream in, Charset charset)    public InputStreamReader(InputStream in, Charset charset) {
237    {      this.in = in;
238      /* FIXME: InputStream is wrapped in Channel which is read by a      decoder = charset.newDecoder();
239       * Reader-implementation for channels. However to fix this we  
240       * need to completely move to NIO-style character      // JDK reports errors, so we do the same.
241       * encoding/decoding.      decoder.onMalformedInput(CodingErrorAction.REPORT);
242       */      decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
243      this.in = Channels.newReader(Channels.newChannel(in), charset.newDecoder(),      decoder.reset();
244                                   -1);      encoding = EncodingHelper.getOldCanonical(charset.name());
     encoding = charset.name();  
245    }    }
246    
247    /**    /**
248     * Creates an InputStreamReader that uses the given charset decoder     * Creates an InputStreamReader that uses the given charset decoder
249     * to decode the bytes in the InputStream into characters.     * to decode the bytes in the InputStream into characters.
    * @since 1.4  
250     */     */
251    public InputStreamReader(InputStream in, CharsetDecoder decoder)    public InputStreamReader(InputStream in, CharsetDecoder decoder) {
252    {      this.in = in;
253      // FIXME: see {@link InputStreamReader(InputStream, Charset)      this.decoder = decoder;
254      this.in = Channels.newReader(Channels.newChannel(in), decoder, -1);  
255      encoding = decoder.charset().name();      try {
256            maxBytesPerChar = decoder.charset().newEncoder().maxBytesPerChar();
257        } catch(UnsupportedOperationException _){
258            maxBytesPerChar = 1f;
259        }
260    
261        // JDK reports errors, so we do the same.
262        decoder.onMalformedInput(CodingErrorAction.REPORT);
263        decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
264        decoder.reset();
265        encoding = EncodingHelper.getOldCanonical(decoder.charset().name());      
266    }    }
267        
268    /**    /**
# Line 183  public class InputStreamReader extends R Line 275  public class InputStreamReader extends R
275    {    {
276      synchronized (lock)      synchronized (lock)
277        {        {
278            // Makes sure all intermediate data is released by the decoder.
279            if (decoder != null)
280               decoder.reset();
281          if (in != null)          if (in != null)
282            in.close();             in.close();
283          in = null;          in = null;
284            isDone = true;
285            decoder = null;
286        }        }
287    }    }
288    
# Line 202  public class InputStreamReader extends R Line 299  public class InputStreamReader extends R
299    }    }
300    
301    /**    /**
302     * This method checks to see if the stream is read to be read.  It     * This method checks to see if the stream is ready to be read.  It
303     * will return <code>true</code> if is, or <code>false</code> if it is not.     * will return <code>true</code> if is, or <code>false</code> if it is not.
304     * If the stream is not ready to be read, it could (although is not required     * If the stream is not ready to be read, it could (although is not required
305     * to) block on the next read attempt.     * to) block on the next read attempt.
# Line 217  public class InputStreamReader extends R Line 314  public class InputStreamReader extends R
314      if (in == null)      if (in == null)
315        throw new IOException("Reader has been closed");        throw new IOException("Reader has been closed");
316            
317      return in.ready();      return in.available() != 0;
318    }    }
319    
320    /**    /**
# Line 233  public class InputStreamReader extends R Line 330  public class InputStreamReader extends R
330     *     *
331     * @exception IOException If an error occurs     * @exception IOException If an error occurs
332     */     */
333    public int read (char[] buf, int offset, int length) throws IOException    public int read(char[] buf, int offset, int length) throws IOException
334    {    {
335      if (in == null)      if (in == null)
336        throw new IOException("Reader has been closed");        throw new IOException("Reader has been closed");
337            if (isDone)
338      return in.read(buf, offset, length);        return -1;
339    
340        if(decoder != null){
341            int totalBytes = (int)((double)length * maxBytesPerChar);
342            byte[] bytes = new byte[totalBytes];
343    
344            int remaining = 0;
345            if(byteBuffer != null)
346            {
347                remaining = byteBuffer.remaining();
348                byteBuffer.get(bytes, 0, remaining);
349            }
350            int read;
351            if(totalBytes - remaining > 0)
352              {
353                read = in.read(bytes, remaining, totalBytes - remaining);
354                if(read == -1){
355                  read = remaining;
356                  isDone = true;
357                } else
358                  read += remaining;
359              } else
360                read = remaining;
361            byteBuffer = ByteBuffer.wrap(bytes, 0, read);  
362            CharBuffer cb = CharBuffer.wrap(buf, offset, length);
363    
364            if(hasSavedSurrogate){
365                hasSavedSurrogate = false;
366                cb.put(savedSurrogate);
367                read++;
368            }
369    
370            CoderResult cr = decoder.decode(byteBuffer, cb, isDone);
371            decoder.reset();
372    
373            // 1 char remains which is the first half of a surrogate pair.
374            if(cr.isOverflow() && cb.hasRemaining()){
375                CharBuffer overflowbuf = CharBuffer.allocate(2);
376                cr = decoder.decode(byteBuffer, overflowbuf, isDone);
377                overflowbuf.flip();
378                cb.put(overflowbuf.get());
379                savedSurrogate = overflowbuf.get();
380                hasSavedSurrogate = true;      
381                isDone = false;
382            }
383    
384            if(byteBuffer.hasRemaining()) {
385                byteBuffer.compact();
386                byteBuffer.flip();    
387                isDone = false;
388            } else
389                byteBuffer = null;
390    
391            return (read == 0)?-1:cb.position();
392        } else {
393            byte[] bytes = new byte[length];
394            int read = in.read(bytes);
395            for(int i=0;i<read;i++)
396              buf[offset+i] = (char)(bytes[i]&0xFF);
397            return read;
398        }
399    }    }
400    
401    /**    /**
402     * This method reads a single character of data from the stream.     * Reads an char from the input stream and returns it
403       * as an int in the range of 0-65535.  This method also will return -1 if
404       * the end of the stream has been reached.
405       * <p>
406       * This method will block until the char can be read.
407     *     *
408     * @return The char read, as an int, or -1 if end of stream.     * @return The char read or -1 if end of stream
409     *     *
410     * @exception IOException If an error occurs     * @exception IOException If an error occurs
411     */     */
412    public int read() throws IOException    public int read() throws IOException
413    {    {
414      if (in == null)      char[] buf = new char[1];
415        throw new IOException("Reader has been closed");      int count = read(buf, 0, 1);
416            return count > 0 ? buf[0] : -1;
     return in.read();  
417    }    }
418    
419     /**    /**
420      * Skips the specified number of chars in the stream.  It     * Skips the specified number of chars in the stream.  It
421      * returns the actual number of chars skipped, which may be less than the     * returns the actual number of chars skipped, which may be less than the
422      * requested amount.     * requested amount.
423      *     *
424      * @param count The requested number of chars to skip     * @param count The requested number of chars to skip
425      *     *
426      * @return The actual number of chars skipped.     * @return The actual number of chars skipped.
427      *     *
428      * @exception IOException If an error occurs     * @exception IOException If an error occurs
429      */     */
430     public long skip(long count) throws IOException     public long skip(long count) throws IOException
431     {     {
432       if (in == null)       if (in == null)
433         throw new IOException("Reader has been closed");         throw new IOException("Reader has been closed");
434            
435       return super.skip(count);       return super.skip(count);
436    }     }
437  }  }

Legend:
Removed from v.1.21  
changed lines
  Added in v.1.22

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26