History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/nio/cs/StreamDecoder.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/nio/cs/StreamDecoder.java+380−0
@@ -0,0 +1,380 @@
1/*
2 * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 */
28
29package sun.nio.cs;
30
31import java.io.*;
32import java.nio.*;
33import java.nio.channels.*;
34import java.nio.charset.*;
35
36public class StreamDecoder extends Reader
37{
38
39 private static final int MIN_BYTE_BUFFER_SIZE = 32;
40 private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
41
42 private volatile boolean isOpen = true;
43
44 private void ensureOpen() throws IOException {
45 if (!isOpen)
46 throw new IOException("Stream closed");
47 }
48
49 // In order to handle surrogates properly we must never try to produce
50 // fewer than two characters at a time. If we're only asked to return one
51 // character then the other is saved here to be returned later.
52 //
53 private boolean haveLeftoverChar = false;
54 private char leftoverChar;
55
56
57 // Factories for java.io.InputStreamReader
58
59 public static StreamDecoder forInputStreamReader(InputStream in,
60 Object lock,
61 String charsetName)
62 throws UnsupportedEncodingException
63 {
64 String csn = charsetName;
65 if (csn == null)
66 csn = Charset.defaultCharset().name();
67 try {
68 if (Charset.isSupported(csn))
69 return new StreamDecoder(in, lock, Charset.forName(csn));
70 } catch (IllegalCharsetNameException x) { }
71 throw new UnsupportedEncodingException (csn);
72 }
73
74 public static StreamDecoder forInputStreamReader(InputStream in,
75 Object lock,
76 Charset cs)
77 {
78 return new StreamDecoder(in, lock, cs);
79 }
80
81 public static StreamDecoder forInputStreamReader(InputStream in,
82 Object lock,
83 CharsetDecoder dec)
84 {
85 return new StreamDecoder(in, lock, dec);
86 }
87
88
89 // Factory for java.nio.channels.Channels.newReader
90
91 public static StreamDecoder forDecoder(ReadableByteChannel ch,
92 CharsetDecoder dec,
93 int minBufferCap)
94 {
95 return new StreamDecoder(ch, dec, minBufferCap);
96 }
97
98
99 // -- Public methods corresponding to those in InputStreamReader --
100
101 // All synchronization and state/argument checking is done in these public
102 // methods; the concrete stream-decoder subclasses defined below need not
103 // do any such checking.
104
105 public String getEncoding() {
106 if (isOpen())
107 return encodingName();
108 return null;
109 }
110
111 public int read() throws IOException {
112 return read0();
113 }
114
115 private int read0() throws IOException {
116 synchronized (lock) {
117
118 // Return the leftover char, if there is one
119 if (haveLeftoverChar) {
120 haveLeftoverChar = false;
121 return leftoverChar;
122 }
123
124 // Convert more bytes
125 char cb[] = new char[2];
126 int n = read(cb, 0, 2);
127 switch (n) {
128 case -1:
129 return -1;
130 case 2:
131 leftoverChar = cb[1];
132 haveLeftoverChar = true;
133 // FALL THROUGH
134 case 1:
135 return cb[0];
136 default:
137 assert false : n;
138 return -1;
139 }
140 }
141 }
142
143 public int read(char cbuf[], int offset, int length) throws IOException {
144 int off = offset;
145 int len = length;
146 synchronized (lock) {
147 ensureOpen();
148 if ((off < 0) || (off > cbuf.length) || (len < 0) ||
149 ((off + len) > cbuf.length) || ((off + len) < 0)) {
150 throw new IndexOutOfBoundsException();
151 }
152 if (len == 0)
153 return 0;
154
155 int n = 0;
156
157 if (haveLeftoverChar) {
158 // Copy the leftover char into the buffer
159 cbuf[off] = leftoverChar;
160 off++; len--;
161 haveLeftoverChar = false;
162 n = 1;
163 if ((len == 0) || !implReady())
164 // Return now if this is all we can produce w/o blocking
165 return n;
166 }
167
168 if (len == 1) {
169 // Treat single-character array reads just like read()
170 int c = read0();
171 if (c == -1)
172 return (n == 0) ? -1 : n;
173 cbuf[off] = (char)c;
174 return n + 1;
175 }
176
177 return n + implRead(cbuf, off, off + len);
178 }
179 }
180
181 public boolean ready() throws IOException {
182 synchronized (lock) {
183 ensureOpen();
184 return haveLeftoverChar || implReady();
185 }
186 }
187
188 public void close() throws IOException {
189 synchronized (lock) {
190 if (!isOpen)
191 return;
192 implClose();
193 isOpen = false;
194 }
195 }
196
197 private boolean isOpen() {
198 return isOpen;
199 }
200
201
202 // -- Charset-based stream decoder impl --
203
204 // In the early stages of the build we haven't yet built the NIO native
205 // code, so guard against that by catching the first UnsatisfiedLinkError
206 // and setting this flag so that later attempts fail quickly.
207 //
208 private static volatile boolean channelsAvailable = true;
209
210 private static FileChannel getChannel(FileInputStream in) {
211 if (!channelsAvailable)
212 return null;
213 try {
214 return in.getChannel();
215 } catch (UnsatisfiedLinkError x) {
216 channelsAvailable = false;
217 return null;
218 }
219 }
220
221 private Charset cs;
222 private CharsetDecoder decoder;
223 private ByteBuffer bb;
224
225 // Exactly one of these is non-null
226 private InputStream in;
227 private ReadableByteChannel ch;
228
229 StreamDecoder(InputStream in, Object lock, Charset cs) {
230 this(in, lock,
231 cs.newDecoder()
232 .onMalformedInput(CodingErrorAction.REPLACE)
233 .onUnmappableCharacter(CodingErrorAction.REPLACE));
234 }
235
236 StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) {
237 super(lock);
238 this.cs = dec.charset();
239 this.decoder = dec;
240
241 // This path disabled until direct buffers are faster
242 if (false && in instanceof FileInputStream) {
243 ch = getChannel((FileInputStream)in);
244 if (ch != null)
245 bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
246 }
247 if (ch == null) {
248 this.in = in;
249 this.ch = null;
250 bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
251 }
252 bb.flip(); // So that bb is initially empty
253 }
254
255 StreamDecoder(ReadableByteChannel ch, CharsetDecoder dec, int mbc) {
256 this.in = null;
257 this.ch = ch;
258 this.decoder = dec;
259 this.cs = dec.charset();
260 this.bb = ByteBuffer.allocate(mbc < 0
261 ? DEFAULT_BYTE_BUFFER_SIZE
262 : (mbc < MIN_BYTE_BUFFER_SIZE
263 ? MIN_BYTE_BUFFER_SIZE
264 : mbc));
265 bb.flip();
266 }
267
268 private int readBytes() throws IOException {
269 bb.compact();
270 try {
271 if (ch != null) {
272 // Read from the channel
273 int n = ch.read(bb);
274 if (n < 0)
275 return n;
276 } else {
277 // Read from the input stream, and then update the buffer
278 int lim = bb.limit();
279 int pos = bb.position();
280 assert (pos <= lim);
281 int rem = (pos <= lim ? lim - pos : 0);
282 assert rem > 0;
283 int n = in.read(bb.array(), bb.arrayOffset() + pos, rem);
284 if (n < 0)
285 return n;
286 if (n == 0)
287 throw new IOException("Underlying input stream returned zero bytes");
288 assert (n <= rem) : "n = " + n + ", rem = " + rem;
289 bb.position(pos + n);
290 }
291 } finally {
292 // Flip even when an IOException is thrown,
293 // otherwise the stream will stutter
294 bb.flip();
295 }
296
297 int rem = bb.remaining();
298 assert (rem != 0) : rem;
299 return rem;
300 }
301
302 int implRead(char[] cbuf, int off, int end) throws IOException {
303
304 // In order to handle surrogate pairs, this method requires that
305 // the invoker attempt to read at least two characters. Saving the
306 // extra character, if any, at a higher level is easier than trying
307 // to deal with it here.
308 assert (end - off > 1);
309
310 CharBuffer cb = CharBuffer.wrap(cbuf, off, end - off);
311 if (cb.position() != 0)
312 // Ensure that cb[0] == cbuf[off]
313 cb = cb.slice();
314
315 boolean eof = false;
316 for (;;) {
317 CoderResult cr = decoder.decode(bb, cb, eof);
318 if (cr.isUnderflow()) {
319 if (eof)
320 break;
321 if (!cb.hasRemaining())
322 break;
323 if ((cb.position() > 0) && !inReady())
324 break; // Block at most once
325 int n = readBytes();
326 if (n < 0) {
327 eof = true;
328 if ((cb.position() == 0) && (!bb.hasRemaining()))
329 break;
330 decoder.reset();
331 }
332 continue;
333 }
334 if (cr.isOverflow()) {
335 assert cb.position() > 0;
336 break;
337 }
338 cr.throwException();
339 }
340
341 if (eof) {
342 // ## Need to flush decoder
343 decoder.reset();
344 }
345
346 if (cb.position() == 0) {
347 if (eof)
348 return -1;
349 assert false;
350 }
351 return cb.position();
352 }
353
354 String encodingName() {
355 return ((cs instanceof HistoricallyNamedCharset)
356 ? ((HistoricallyNamedCharset)cs).historicalName()
357 : cs.name());
358 }
359
360 private boolean inReady() {
361 try {
362 return (((in != null) && (in.available() > 0))
363 || (ch instanceof FileChannel)); // ## RBC.available()?
364 } catch (IOException x) {
365 return false;
366 }
367 }
368
369 boolean implReady() {
370 return bb.hasRemaining() || inReady();
371 }
372
373 void implClose() throws IOException {
374 if (ch != null)
375 ch.close();
376 else
377 in.close();
378 }
379
380}