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/StreamEncoder.java (1 of 18352 files). Show all

Unified · Split

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