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+
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+ 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+}