1 | /* Copyright (C) 1998, 1999, 2001, 2003 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()
|
---|
74 | {
|
---|
75 | return in != null ? converter.getName() : null;
|
---|
76 | }
|
---|
77 |
|
---|
78 | public boolean ready() throws IOException
|
---|
79 | {
|
---|
80 | synchronized (lock)
|
---|
81 | {
|
---|
82 | if (in == null)
|
---|
83 | throw new IOException("Stream closed");
|
---|
84 |
|
---|
85 | if (wpos < wcount)
|
---|
86 | return true;
|
---|
87 |
|
---|
88 | // According to the spec, an InputStreamReader is ready if its
|
---|
89 | // input buffer is not empty (above), or if bytes are
|
---|
90 | // available on the underlying byte stream.
|
---|
91 | return in.available () > 0;
|
---|
92 | }
|
---|
93 | }
|
---|
94 |
|
---|
95 | public int read(char buf[], int offset, int length) throws IOException
|
---|
96 | {
|
---|
97 | synchronized (lock)
|
---|
98 | {
|
---|
99 | if (in == null)
|
---|
100 | throw new IOException("Stream closed");
|
---|
101 |
|
---|
102 | if (length == 0)
|
---|
103 | return 0;
|
---|
104 |
|
---|
105 | int wavail = wcount - wpos;
|
---|
106 | if (wavail <= 0)
|
---|
107 | {
|
---|
108 | // Nothing waiting, so refill our buffer.
|
---|
109 | if (! refill ())
|
---|
110 | return -1;
|
---|
111 | wavail = wcount - wpos;
|
---|
112 | }
|
---|
113 |
|
---|
114 | if (length > wavail)
|
---|
115 | length = wavail;
|
---|
116 | System.arraycopy(work, wpos, buf, offset, length);
|
---|
117 | wpos += length;
|
---|
118 | return length;
|
---|
119 | }
|
---|
120 | }
|
---|
121 |
|
---|
122 | public int read() throws IOException
|
---|
123 | {
|
---|
124 | synchronized (lock)
|
---|
125 | {
|
---|
126 | if (in == null)
|
---|
127 | throw new IOException("Stream closed");
|
---|
128 |
|
---|
129 | int wavail = wcount - wpos;
|
---|
130 | if (wavail <= 0)
|
---|
131 | {
|
---|
132 | // Nothing waiting, so refill our buffer.
|
---|
133 | if (! refill ())
|
---|
134 | return -1;
|
---|
135 | }
|
---|
136 |
|
---|
137 | return work[wpos++];
|
---|
138 | }
|
---|
139 | }
|
---|
140 |
|
---|
141 | // Read more bytes and convert them into the WORK buffer.
|
---|
142 | // Return false on EOF.
|
---|
143 | private boolean refill () throws IOException
|
---|
144 | {
|
---|
145 | wcount = wpos = 0;
|
---|
146 |
|
---|
147 | if (work == null)
|
---|
148 | work = new char[100];
|
---|
149 |
|
---|
150 | for (;;)
|
---|
151 | {
|
---|
152 | // We have knowledge of the internals of BufferedInputStream
|
---|
153 | // here. Eww.
|
---|
154 | in.mark (0);
|
---|
155 | // BufferedInputStream.refill() can only be called when
|
---|
156 | // `pos>=count'.
|
---|
157 | boolean r = in.pos < in.count || in.refill ();
|
---|
158 | in.reset ();
|
---|
159 | if (! r)
|
---|
160 | return false;
|
---|
161 | converter.setInput(in.buf, in.pos, in.count);
|
---|
162 | int count = converter.read (work, wpos, work.length - wpos);
|
---|
163 | in.skip(converter.inpos - in.pos);
|
---|
164 | if (count > 0)
|
---|
165 | {
|
---|
166 | wcount += count;
|
---|
167 | return true;
|
---|
168 | }
|
---|
169 | }
|
---|
170 | }
|
---|
171 | }
|
---|