Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java
41159 views
1
/*
2
* Copyright (c) 2001, 2021, 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
package sun.nio.cs;
27
28
import java.io.IOException;
29
import java.io.OutputStream;
30
import java.io.UnsupportedEncodingException;
31
import java.io.Writer;
32
import java.nio.ByteBuffer;
33
import java.nio.CharBuffer;
34
import java.nio.channels.WritableByteChannel;
35
import java.nio.charset.Charset;
36
import java.nio.charset.CharsetEncoder;
37
import java.nio.charset.CoderResult;
38
import java.nio.charset.CodingErrorAction;
39
import java.nio.charset.IllegalCharsetNameException;
40
import java.nio.charset.UnsupportedCharsetException;
41
42
public class StreamEncoder extends Writer
43
{
44
45
private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
46
47
private volatile boolean closed;
48
49
private void ensureOpen() throws IOException {
50
if (closed)
51
throw new IOException("Stream closed");
52
}
53
54
// Factories for java.io.OutputStreamWriter
55
public static StreamEncoder forOutputStreamWriter(OutputStream out,
56
Object lock,
57
String charsetName)
58
throws UnsupportedEncodingException
59
{
60
String csn = charsetName;
61
if (csn == null) {
62
csn = Charset.defaultCharset().name();
63
}
64
try {
65
return new StreamEncoder(out, lock, Charset.forName(csn));
66
} catch (IllegalCharsetNameException | UnsupportedCharsetException x) {
67
throw new UnsupportedEncodingException (csn);
68
}
69
}
70
71
public static StreamEncoder forOutputStreamWriter(OutputStream out,
72
Object lock,
73
Charset cs)
74
{
75
return new StreamEncoder(out, lock, cs);
76
}
77
78
public static StreamEncoder forOutputStreamWriter(OutputStream out,
79
Object lock,
80
CharsetEncoder enc)
81
{
82
return new StreamEncoder(out, lock, enc);
83
}
84
85
86
// Factory for java.nio.channels.Channels.newWriter
87
88
public static StreamEncoder forEncoder(WritableByteChannel ch,
89
CharsetEncoder enc,
90
int minBufferCap)
91
{
92
return new StreamEncoder(ch, enc, minBufferCap);
93
}
94
95
96
// -- Public methods corresponding to those in OutputStreamWriter --
97
98
// All synchronization and state/argument checking is done in these public
99
// methods; the concrete stream-encoder subclasses defined below need not
100
// do any such checking.
101
102
public String getEncoding() {
103
if (isOpen())
104
return encodingName();
105
return null;
106
}
107
108
public void flushBuffer() throws IOException {
109
synchronized (lock) {
110
if (isOpen())
111
implFlushBuffer();
112
else
113
throw new IOException("Stream closed");
114
}
115
}
116
117
public void write(int c) throws IOException {
118
char[] cbuf = new char[1];
119
cbuf[0] = (char) c;
120
write(cbuf, 0, 1);
121
}
122
123
public void write(char[] cbuf, int off, int len) throws IOException {
124
synchronized (lock) {
125
ensureOpen();
126
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
127
((off + len) > cbuf.length) || ((off + len) < 0)) {
128
throw new IndexOutOfBoundsException();
129
} else if (len == 0) {
130
return;
131
}
132
implWrite(cbuf, off, len);
133
}
134
}
135
136
public void write(String str, int off, int len) throws IOException {
137
/* Check the len before creating a char buffer */
138
if (len < 0)
139
throw new IndexOutOfBoundsException();
140
char[] cbuf = new char[len];
141
str.getChars(off, off + len, cbuf, 0);
142
write(cbuf, 0, len);
143
}
144
145
public void write(CharBuffer cb) throws IOException {
146
int position = cb.position();
147
try {
148
synchronized (lock) {
149
ensureOpen();
150
implWrite(cb);
151
}
152
} finally {
153
cb.position(position);
154
}
155
}
156
157
public void flush() throws IOException {
158
synchronized (lock) {
159
ensureOpen();
160
implFlush();
161
}
162
}
163
164
public void close() throws IOException {
165
synchronized (lock) {
166
if (closed)
167
return;
168
try {
169
implClose();
170
} finally {
171
closed = true;
172
}
173
}
174
}
175
176
private boolean isOpen() {
177
return !closed;
178
}
179
180
181
// -- Charset-based stream encoder impl --
182
183
private final Charset cs;
184
private final CharsetEncoder encoder;
185
private final ByteBuffer bb;
186
187
// Exactly one of these is non-null
188
private final OutputStream out;
189
private final WritableByteChannel ch;
190
191
// Leftover first char in a surrogate pair
192
private boolean haveLeftoverChar = false;
193
private char leftoverChar;
194
private CharBuffer lcb = null;
195
196
private StreamEncoder(OutputStream out, Object lock, Charset cs) {
197
this(out, lock,
198
cs.newEncoder()
199
.onMalformedInput(CodingErrorAction.REPLACE)
200
.onUnmappableCharacter(CodingErrorAction.REPLACE));
201
}
202
203
private StreamEncoder(OutputStream out, Object lock, CharsetEncoder enc) {
204
super(lock);
205
this.out = out;
206
this.ch = null;
207
this.cs = enc.charset();
208
this.encoder = enc;
209
this.bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
210
}
211
212
private StreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
213
this.out = null;
214
this.ch = ch;
215
this.cs = enc.charset();
216
this.encoder = enc;
217
this.bb = ByteBuffer.allocate(mbc < 0
218
? DEFAULT_BYTE_BUFFER_SIZE
219
: mbc);
220
}
221
222
private void writeBytes() throws IOException {
223
bb.flip();
224
int lim = bb.limit();
225
int pos = bb.position();
226
assert (pos <= lim);
227
int rem = (pos <= lim ? lim - pos : 0);
228
229
if (rem > 0) {
230
if (ch != null) {
231
int wc = ch.write(bb);
232
assert wc == rem : rem;
233
} else {
234
out.write(bb.array(), bb.arrayOffset() + pos, rem);
235
}
236
}
237
bb.clear();
238
}
239
240
private void flushLeftoverChar(CharBuffer cb, boolean endOfInput)
241
throws IOException
242
{
243
if (!haveLeftoverChar && !endOfInput)
244
return;
245
if (lcb == null)
246
lcb = CharBuffer.allocate(2);
247
else
248
lcb.clear();
249
if (haveLeftoverChar)
250
lcb.put(leftoverChar);
251
if ((cb != null) && cb.hasRemaining())
252
lcb.put(cb.get());
253
lcb.flip();
254
while (lcb.hasRemaining() || endOfInput) {
255
CoderResult cr = encoder.encode(lcb, bb, endOfInput);
256
if (cr.isUnderflow()) {
257
if (lcb.hasRemaining()) {
258
leftoverChar = lcb.get();
259
if (cb != null && cb.hasRemaining()) {
260
lcb.clear();
261
lcb.put(leftoverChar).put(cb.get()).flip();
262
continue;
263
}
264
return;
265
}
266
break;
267
}
268
if (cr.isOverflow()) {
269
assert bb.position() > 0;
270
writeBytes();
271
continue;
272
}
273
cr.throwException();
274
}
275
haveLeftoverChar = false;
276
}
277
278
void implWrite(char[] cbuf, int off, int len)
279
throws IOException
280
{
281
CharBuffer cb = CharBuffer.wrap(cbuf, off, len);
282
implWrite(cb);
283
}
284
285
void implWrite(CharBuffer cb)
286
throws IOException
287
{
288
if (haveLeftoverChar) {
289
flushLeftoverChar(cb, false);
290
}
291
292
while (cb.hasRemaining()) {
293
CoderResult cr = encoder.encode(cb, bb, false);
294
if (cr.isUnderflow()) {
295
assert (cb.remaining() <= 1) : cb.remaining();
296
if (cb.remaining() == 1) {
297
haveLeftoverChar = true;
298
leftoverChar = cb.get();
299
}
300
break;
301
}
302
if (cr.isOverflow()) {
303
assert bb.position() > 0;
304
writeBytes();
305
continue;
306
}
307
cr.throwException();
308
}
309
}
310
311
void implFlushBuffer() throws IOException {
312
if (bb.position() > 0) {
313
writeBytes();
314
}
315
}
316
317
void implFlush() throws IOException {
318
implFlushBuffer();
319
if (out != null) {
320
out.flush();
321
}
322
}
323
324
void implClose() throws IOException {
325
flushLeftoverChar(null, true);
326
try {
327
for (;;) {
328
CoderResult cr = encoder.flush(bb);
329
if (cr.isUnderflow())
330
break;
331
if (cr.isOverflow()) {
332
assert bb.position() > 0;
333
writeBytes();
334
continue;
335
}
336
cr.throwException();
337
}
338
339
if (bb.position() > 0)
340
writeBytes();
341
if (ch != null)
342
ch.close();
343
else {
344
try {
345
out.flush();
346
} finally {
347
out.close();
348
}
349
}
350
} catch (IOException x) {
351
encoder.reset();
352
throw x;
353
}
354
}
355
356
String encodingName() {
357
return ((cs instanceof HistoricallyNamedCharset)
358
? ((HistoricallyNamedCharset)cs).historicalName()
359
: cs.name());
360
}
361
}
362
363