OSDN Git Service

Fix for PR libgcj/3426:
[pf3gnuchains/gcc-fork.git] / libjava / java / io / InputStreamReader.java
1 /* Copyright (C) 1998, 1999, 2001  Free Software Foundation
2
3    This file is part of libgcj.
4
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
7 details.  */
8  
9 package java.io;
10 import gnu.gcj.convert.*;
11
12 /**
13  * @author Per Bothner <bothner@cygnus.com>
14  * @date April 22, 1998.  
15  */
16 /* Written using "Java Class Libraries", 2nd edition, plus online
17  * API docs for JDK 1.2 beta from http://www.javasoft.com.
18  * Status:  Believed complete and correct, but only supports 8859_1.
19  */
20
21 public class InputStreamReader extends Reader
22 {
23   BufferedInputStream in;
24
25   // Buffer of chars read from in and converted but not consumed.
26   char[] work;
27   // Next available character (in work buffer) to read.
28   int wpos;
29   // Last available character (in work buffer) to read.
30   int wcount;
31
32   BytesToUnicode converter;
33
34   public InputStreamReader(InputStream in)
35   {
36     this(in, BytesToUnicode.getDefaultDecoder());
37   }
38
39   public InputStreamReader(InputStream in, String enc)
40     throws UnsupportedEncodingException
41   {
42     this(in, BytesToUnicode.getDecoder(enc));
43   }
44
45   private InputStreamReader(InputStream in, BytesToUnicode decoder)
46   {
47     // FIXME: someone could pass in a BufferedInputStream whose buffer
48     // is smaller than the longest encoded character for this
49     // encoding.  We will probably go into an infinite loop in this
50     // case.  We probably ought to just have our own byte buffering
51     // here.
52     this.in = in instanceof BufferedInputStream
53               ? (BufferedInputStream) in
54               : new BufferedInputStream(in);
55     /* Don't need to call super(in) here as long as the lock gets set. */
56     this.lock = in;
57     converter = decoder;
58     converter.setInput(this.in.buf, 0, 0);
59   }
60
61   public void close() throws IOException
62   {
63     synchronized (lock)
64       {
65         if (in != null)
66           in.close();
67         in = null;
68         work = null;
69         wpos = wcount = 0;
70       }
71   }
72
73   public String getEncoding() { return converter.getName(); }
74
75   public boolean ready() throws IOException
76   {
77     synchronized (lock)
78       {
79         if (in == null)
80           throw new IOException("Stream closed");
81
82         if (wpos < wcount)
83           return true;
84
85         // According to the spec, an InputStreamReader is ready if its
86         // input buffer is not empty (above), or if bytes are
87         // available on the underlying byte stream.
88         return in.available () > 0;
89       }
90   }
91
92   public int read(char buf[], int offset, int length) throws IOException
93   {
94     synchronized (lock)
95       {
96         if (in == null)
97           throw new IOException("Stream closed");
98
99         if (length == 0)
100           return 0;
101
102         int wavail = wcount - wpos;
103         if (wavail <= 0)
104           {
105             // Nothing waiting, so refill our buffer.
106             if (! refill ())
107               return -1;
108             wavail = wcount - wpos;
109           }
110
111         if (length > wavail)
112           length = wavail;
113         System.arraycopy(work, wpos, buf, offset, length);
114         wpos += length;
115         return length;
116       }
117   }
118
119   public int read() throws IOException
120   {
121     synchronized (lock)
122       {
123         if (in == null)
124           throw new IOException("Stream closed");
125
126         int wavail = wcount - wpos;
127         if (wavail <= 0)
128           {
129             // Nothing waiting, so refill our buffer.
130             if (! refill ())
131               return -1;
132           }
133
134         return work[wpos++];
135       }
136   }
137
138   // Read more bytes and convert them into the WORK buffer.
139   // Return false on EOF.
140   private boolean refill () throws IOException
141   {
142     wcount = wpos = 0;
143
144     if (work == null)
145       work = new char[100];
146
147     for (;;)
148       {
149         // We have knowledge of the internals of BufferedInputStream
150         // here.  Eww.
151         in.mark (0);
152         boolean r = in.refill ();
153         in.reset ();
154         if (! r)
155           return false;
156         converter.setInput(in.buf, in.pos, in.count);
157         int count = converter.read (work, wpos, work.length - wpos);
158         in.skip(converter.inpos - in.pos);
159         if (count > 0)
160           {
161             wcount += count;
162             return true;
163           }
164       }
165   }
166 }