Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/nio/cs/StreamDecoder.java
38918 views
1
/*
2
* Copyright (c) 2001, 2011, 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
29
package sun.nio.cs;
30
31
import java.io.*;
32
import java.nio.*;
33
import java.nio.channels.*;
34
import java.nio.charset.*;
35
36
public 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
@SuppressWarnings("fallthrough")
116
private int read0() throws IOException {
117
synchronized (lock) {
118
119
// Return the leftover char, if there is one
120
if (haveLeftoverChar) {
121
haveLeftoverChar = false;
122
return leftoverChar;
123
}
124
125
// Convert more bytes
126
char cb[] = new char[2];
127
int n = read(cb, 0, 2);
128
switch (n) {
129
case -1:
130
return -1;
131
case 2:
132
leftoverChar = cb[1];
133
haveLeftoverChar = true;
134
// FALL THROUGH
135
case 1:
136
return cb[0];
137
default:
138
assert false : n;
139
return -1;
140
}
141
}
142
}
143
144
public int read(char cbuf[], int offset, int length) throws IOException {
145
int off = offset;
146
int len = length;
147
synchronized (lock) {
148
ensureOpen();
149
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
150
((off + len) > cbuf.length) || ((off + len) < 0)) {
151
throw new IndexOutOfBoundsException();
152
}
153
if (len == 0)
154
return 0;
155
156
int n = 0;
157
158
if (haveLeftoverChar) {
159
// Copy the leftover char into the buffer
160
cbuf[off] = leftoverChar;
161
off++; len--;
162
haveLeftoverChar = false;
163
n = 1;
164
if ((len == 0) || !implReady())
165
// Return now if this is all we can produce w/o blocking
166
return n;
167
}
168
169
if (len == 1) {
170
// Treat single-character array reads just like read()
171
int c = read0();
172
if (c == -1)
173
return (n == 0) ? -1 : n;
174
cbuf[off] = (char)c;
175
return n + 1;
176
}
177
178
return n + implRead(cbuf, off, off + len);
179
}
180
}
181
182
public boolean ready() throws IOException {
183
synchronized (lock) {
184
ensureOpen();
185
return haveLeftoverChar || implReady();
186
}
187
}
188
189
public void close() throws IOException {
190
synchronized (lock) {
191
if (!isOpen)
192
return;
193
implClose();
194
isOpen = false;
195
}
196
}
197
198
private boolean isOpen() {
199
return isOpen;
200
}
201
202
203
// -- Charset-based stream decoder impl --
204
205
// In the early stages of the build we haven't yet built the NIO native
206
// code, so guard against that by catching the first UnsatisfiedLinkError
207
// and setting this flag so that later attempts fail quickly.
208
//
209
private static volatile boolean channelsAvailable = true;
210
211
private static FileChannel getChannel(FileInputStream in) {
212
if (!channelsAvailable)
213
return null;
214
try {
215
return in.getChannel();
216
} catch (UnsatisfiedLinkError x) {
217
channelsAvailable = false;
218
return null;
219
}
220
}
221
222
private Charset cs;
223
private CharsetDecoder decoder;
224
private ByteBuffer bb;
225
226
// Exactly one of these is non-null
227
private InputStream in;
228
private ReadableByteChannel ch;
229
230
StreamDecoder(InputStream in, Object lock, Charset cs) {
231
this(in, lock,
232
cs.newDecoder()
233
.onMalformedInput(CodingErrorAction.REPLACE)
234
.onUnmappableCharacter(CodingErrorAction.REPLACE));
235
}
236
237
StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) {
238
super(lock);
239
this.cs = dec.charset();
240
this.decoder = dec;
241
242
// This path disabled until direct buffers are faster
243
if (false && in instanceof FileInputStream) {
244
ch = getChannel((FileInputStream)in);
245
if (ch != null)
246
bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
247
}
248
if (ch == null) {
249
this.in = in;
250
this.ch = null;
251
bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
252
}
253
bb.flip(); // So that bb is initially empty
254
}
255
256
StreamDecoder(ReadableByteChannel ch, CharsetDecoder dec, int mbc) {
257
this.in = null;
258
this.ch = ch;
259
this.decoder = dec;
260
this.cs = dec.charset();
261
this.bb = ByteBuffer.allocate(mbc < 0
262
? DEFAULT_BYTE_BUFFER_SIZE
263
: (mbc < MIN_BYTE_BUFFER_SIZE
264
? MIN_BYTE_BUFFER_SIZE
265
: mbc));
266
bb.flip();
267
}
268
269
private int readBytes() throws IOException {
270
bb.compact();
271
try {
272
if (ch != null) {
273
// Read from the channel
274
int n = ch.read(bb);
275
if (n < 0)
276
return n;
277
} else {
278
// Read from the input stream, and then update the buffer
279
int lim = bb.limit();
280
int pos = bb.position();
281
assert (pos <= lim);
282
int rem = (pos <= lim ? lim - pos : 0);
283
assert rem > 0;
284
int n = in.read(bb.array(), bb.arrayOffset() + pos, rem);
285
if (n < 0)
286
return n;
287
if (n == 0)
288
throw new IOException("Underlying input stream returned zero bytes");
289
assert (n <= rem) : "n = " + n + ", rem = " + rem;
290
bb.position(pos + n);
291
}
292
} finally {
293
// Flip even when an IOException is thrown,
294
// otherwise the stream will stutter
295
bb.flip();
296
}
297
298
int rem = bb.remaining();
299
assert (rem != 0) : rem;
300
return rem;
301
}
302
303
int implRead(char[] cbuf, int off, int end) throws IOException {
304
305
// In order to handle surrogate pairs, this method requires that
306
// the invoker attempt to read at least two characters. Saving the
307
// extra character, if any, at a higher level is easier than trying
308
// to deal with it here.
309
assert (end - off > 1);
310
311
CharBuffer cb = CharBuffer.wrap(cbuf, off, end - off);
312
if (cb.position() != 0)
313
// Ensure that cb[0] == cbuf[off]
314
cb = cb.slice();
315
316
boolean eof = false;
317
for (;;) {
318
CoderResult cr = decoder.decode(bb, cb, eof);
319
if (cr.isUnderflow()) {
320
if (eof)
321
break;
322
if (!cb.hasRemaining())
323
break;
324
if ((cb.position() > 0) && !inReady())
325
break; // Block at most once
326
int n = readBytes();
327
if (n < 0) {
328
eof = true;
329
if ((cb.position() == 0) && (!bb.hasRemaining()))
330
break;
331
decoder.reset();
332
}
333
continue;
334
}
335
if (cr.isOverflow()) {
336
assert cb.position() > 0;
337
break;
338
}
339
cr.throwException();
340
}
341
342
if (eof) {
343
// ## Need to flush decoder
344
decoder.reset();
345
}
346
347
if (cb.position() == 0) {
348
if (eof)
349
return -1;
350
assert false;
351
}
352
return cb.position();
353
}
354
355
String encodingName() {
356
return ((cs instanceof HistoricallyNamedCharset)
357
? ((HistoricallyNamedCharset)cs).historicalName()
358
: cs.name());
359
}
360
361
private boolean inReady() {
362
try {
363
return (((in != null) && (in.available() > 0))
364
|| (ch instanceof FileChannel)); // ## RBC.available()?
365
} catch (IOException x) {
366
return false;
367
}
368
}
369
370
boolean implReady() {
371
return bb.hasRemaining() || inReady();
372
}
373
374
void implClose() throws IOException {
375
if (ch != null)
376
ch.close();
377
else
378
in.close();
379
}
380
381
}
382
383