< prev index next >

src/java.base/share/classes/sun/nio/cs/StreamDecoder.java

Print this page

 25 
 26 /*
 27  */
 28 
 29 package sun.nio.cs;
 30 
 31 import java.io.IOException;
 32 import java.io.InputStream;
 33 import java.io.UnsupportedEncodingException;
 34 import java.io.Reader;
 35 import java.nio.ByteBuffer;
 36 import java.nio.CharBuffer;
 37 import java.nio.channels.FileChannel;
 38 import java.nio.channels.ReadableByteChannel;
 39 import java.nio.charset.Charset;
 40 import java.nio.charset.CharsetDecoder;
 41 import java.nio.charset.CoderResult;
 42 import java.nio.charset.CodingErrorAction;
 43 import java.nio.charset.IllegalCharsetNameException;
 44 import java.nio.charset.UnsupportedCharsetException;

 45 
 46 public class StreamDecoder extends Reader {
 47 
 48     private static final int MIN_BYTE_BUFFER_SIZE = 32;
 49     private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
 50 
 51     private volatile boolean closed;
 52 
 53     private void ensureOpen() throws IOException {
 54         if (closed)
 55             throw new IOException("Stream closed");
 56     }
 57 
 58     // In order to handle surrogates properly we must never try to produce
 59     // fewer than two characters at a time.  If we're only asked to return one
 60     // character then the other is saved here to be returned later.
 61     //
 62     private boolean haveLeftoverChar = false;
 63     private char leftoverChar;
 64 

105         return new StreamDecoder(ch, dec, minBufferCap);
106     }
107 
108 
109     // -- Public methods corresponding to those in InputStreamReader --
110 
111     // All synchronization and state/argument checking is done in these public
112     // methods; the concrete stream-decoder subclasses defined below need not
113     // do any such checking.
114 
115     public String getEncoding() {
116         if (isOpen())
117             return encodingName();
118         return null;
119     }
120 
121     public int read() throws IOException {
122         return read0();
123     }
124 
125     @SuppressWarnings("fallthrough")
126     private int read0() throws IOException {
127         synchronized (lock) {
128 
129             // Return the leftover char, if there is one
130             if (haveLeftoverChar) {
131                 haveLeftoverChar = false;
132                 return leftoverChar;
133             }
134 
135             // Convert more bytes
136             char[] cb = new char[2];
137             int n = read(cb, 0, 2);
138             switch (n) {
139             case -1:
140                 return -1;
141             case 2:
142                 leftoverChar = cb[1];
143                 haveLeftoverChar = true;
144                 // FALL THROUGH
145             case 1:
146                 return cb[0];
147             default:
148                 assert false : n;
149                 return -1;
150             }
151         }
152     }
153 


























154     public int read(char[] cbuf, int offset, int length) throws IOException {
155         int off = offset;
156         int len = length;
157         synchronized (lock) {
158             ensureOpen();
159             if ((off < 0) || (off > cbuf.length) || (len < 0) ||
160                 ((off + len) > cbuf.length) || ((off + len) < 0)) {
161                 throw new IndexOutOfBoundsException();
162             }
163             if (len == 0)
164                 return 0;
165 
166             int n = 0;
167 
168             if (haveLeftoverChar) {
169                 // Copy the leftover char into the buffer
170                 cbuf[off] = leftoverChar;
171                 off++; len--;
172                 haveLeftoverChar = false;
173                 n = 1;
174                 if ((len == 0) || !implReady())
175                     // Return now if this is all we can produce w/o blocking
176                     return n;
177             }


178 
179             if (len == 1) {
180                 // Treat single-character array reads just like read()
181                 int c = read0();
182                 if (c == -1)
183                     return (n == 0) ? -1 : n;
184                 cbuf[off] = (char)c;
185                 return n + 1;
186             }
















187 
188             return n + implRead(cbuf, off, off + len);






189         }


190     }
191 
192     public boolean ready() throws IOException {
193         synchronized (lock) {
194             ensureOpen();
195             return haveLeftoverChar || implReady();








196         }
197     }
198 





199     public void close() throws IOException {
200         synchronized (lock) {
201             if (closed)
202                 return;
203             try {
204                 implClose();
205             } finally {
206                 closed = true;
207             }














208         }
209     }
210 
211     private boolean isOpen() {
212         return !closed;
213     }
214 
215 
216     // -- Charset-based stream decoder impl --
217 
218     private final Charset cs;
219     private final CharsetDecoder decoder;
220     private final ByteBuffer bb;
221 
222     // Exactly one of these is non-null
223     private final InputStream in;
224     private final ReadableByteChannel ch;
225 
226     StreamDecoder(InputStream in, Object lock, Charset cs) {
227         this(in, lock,
228             cs.newDecoder()
229                 .onMalformedInput(CodingErrorAction.REPLACE)
230                 .onUnmappableCharacter(CodingErrorAction.REPLACE));
231     }
232 
233     StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) {
234         super(lock);
235         this.cs = dec.charset();
236         this.decoder = dec;
237         this.in = in;
238         this.ch = null;
239         bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
240         bb.flip();                      // So that bb is initially empty
241     }
242 
243     StreamDecoder(ReadableByteChannel ch, CharsetDecoder dec, int mbc) {
244         this.in = null;
245         this.ch = ch;
246         this.decoder = dec;
247         this.cs = dec.charset();
248         this.bb = ByteBuffer.allocate(mbc < 0
249                                   ? DEFAULT_BYTE_BUFFER_SIZE
250                                   : (mbc < MIN_BYTE_BUFFER_SIZE
251                                      ? MIN_BYTE_BUFFER_SIZE
252                                      : mbc));
253         bb.flip();
254     }
255 
256     private int readBytes() throws IOException {
257         bb.compact();
258         try {
259             if (ch != null) {

 25 
 26 /*
 27  */
 28 
 29 package sun.nio.cs;
 30 
 31 import java.io.IOException;
 32 import java.io.InputStream;
 33 import java.io.UnsupportedEncodingException;
 34 import java.io.Reader;
 35 import java.nio.ByteBuffer;
 36 import java.nio.CharBuffer;
 37 import java.nio.channels.FileChannel;
 38 import java.nio.channels.ReadableByteChannel;
 39 import java.nio.charset.Charset;
 40 import java.nio.charset.CharsetDecoder;
 41 import java.nio.charset.CoderResult;
 42 import java.nio.charset.CodingErrorAction;
 43 import java.nio.charset.IllegalCharsetNameException;
 44 import java.nio.charset.UnsupportedCharsetException;
 45 import jdk.internal.misc.InternalLock;
 46 
 47 public class StreamDecoder extends Reader {
 48 
 49     private static final int MIN_BYTE_BUFFER_SIZE = 32;
 50     private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
 51 
 52     private volatile boolean closed;
 53 
 54     private void ensureOpen() throws IOException {
 55         if (closed)
 56             throw new IOException("Stream closed");
 57     }
 58 
 59     // In order to handle surrogates properly we must never try to produce
 60     // fewer than two characters at a time.  If we're only asked to return one
 61     // character then the other is saved here to be returned later.
 62     //
 63     private boolean haveLeftoverChar = false;
 64     private char leftoverChar;
 65 

106         return new StreamDecoder(ch, dec, minBufferCap);
107     }
108 
109 
110     // -- Public methods corresponding to those in InputStreamReader --
111 
112     // All synchronization and state/argument checking is done in these public
113     // methods; the concrete stream-decoder subclasses defined below need not
114     // do any such checking.
115 
116     public String getEncoding() {
117         if (isOpen())
118             return encodingName();
119         return null;
120     }
121 
122     public int read() throws IOException {
123         return read0();
124     }
125 

126     private int read0() throws IOException {
127         if (lock instanceof InternalLock locker) {
128             locker.lock();
129             try {
130                 return lockedRead0();
131             } finally {
132                 locker.unlock();
133             }
134         } else {
135             synchronized (lock) {
136                 return lockedRead0();













137             }
138         }
139     }
140 
141     @SuppressWarnings("fallthrough")
142     private int lockedRead0() throws IOException {
143         // Return the leftover char, if there is one
144         if (haveLeftoverChar) {
145             haveLeftoverChar = false;
146             return leftoverChar;
147         }
148 
149         // Convert more bytes
150         char[] cb = new char[2];
151         int n = read(cb, 0, 2);
152         switch (n) {
153         case -1:
154             return -1;
155         case 2:
156             leftoverChar = cb[1];
157             haveLeftoverChar = true;
158             // FALL THROUGH
159         case 1:
160             return cb[0];
161         default:
162             assert false : n;
163             return -1;
164         }
165     }
166 
167     public int read(char[] cbuf, int offset, int length) throws IOException {
168         if (lock instanceof InternalLock locker) {
169             locker.lock();
170             try {
171                 return lockedRead(cbuf, offset, length);
172             } finally {
173                 locker.unlock();

174             }
175         } else {
176             synchronized (lock) {
177                 return lockedRead(cbuf, offset, length);











178             }
179         }
180     }
181 
182     private int lockedRead(char[] cbuf, int offset, int length) throws IOException {
183         int off = offset;
184         int len = length;
185 
186         ensureOpen();
187         if ((off < 0) || (off > cbuf.length) || (len < 0) ||
188             ((off + len) > cbuf.length) || ((off + len) < 0)) {
189             throw new IndexOutOfBoundsException();
190         }
191         if (len == 0)
192             return 0;
193 
194         int n = 0;
195 
196         if (haveLeftoverChar) {
197             // Copy the leftover char into the buffer
198             cbuf[off] = leftoverChar;
199             off++; len--;
200             haveLeftoverChar = false;
201             n = 1;
202             if ((len == 0) || !implReady())
203                 // Return now if this is all we can produce w/o blocking
204                 return n;
205         }
206 
207         if (len == 1) {
208             // Treat single-character array reads just like read()
209             int c = read0();
210             if (c == -1)
211                 return (n == 0) ? -1 : n;
212             cbuf[off] = (char)c;
213             return n + 1;
214         }
215 
216         return n + implRead(cbuf, off, off + len);
217     }
218 
219     public boolean ready() throws IOException {
220         if (lock instanceof InternalLock locker) {
221             locker.lock();
222             try {
223                 return lockedReady();
224             } finally {
225                 locker.unlock();
226             }
227         } else {
228             synchronized (lock) {
229                 return lockedReady();
230             }
231         }
232     }
233 
234     private boolean lockedReady() throws IOException {
235         ensureOpen();
236         return haveLeftoverChar || implReady();
237     }
238 
239     public void close() throws IOException {
240         if (lock instanceof InternalLock locker) {
241             locker.lock();

242             try {
243                 lockedClose();
244             } finally {
245                 locker.unlock();
246             }
247         } else {
248             synchronized (lock) {
249                 lockedClose();
250             }
251         }
252     }
253 
254     private void lockedClose() throws IOException {
255         if (closed)
256             return;
257         try {
258             implClose();
259         } finally {
260             closed = true;
261         }
262     }
263 
264     private boolean isOpen() {
265         return !closed;
266     }
267 
268 
269     // -- Charset-based stream decoder impl --
270 
271     private final Charset cs;
272     private final CharsetDecoder decoder;
273     private final ByteBuffer bb;
274 
275     // Exactly one of these is non-null
276     private final InputStream in;
277     private final ReadableByteChannel ch;
278 
279     StreamDecoder(InputStream in, Object lock, Charset cs) {
280         this(in, lock,
281             cs.newDecoder()
282                 .onMalformedInput(CodingErrorAction.REPLACE)
283                 .onUnmappableCharacter(CodingErrorAction.REPLACE));
284     }
285 
286     StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) {
287         super(lock);
288         this.cs = dec.charset();
289         this.decoder = dec;
290         this.in = in;
291         this.ch = null;
292         this.bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
293         bb.flip();                      // So that bb is initially empty
294     }
295 
296     StreamDecoder(ReadableByteChannel ch, CharsetDecoder dec, int mbc) {
297         this.in = null;
298         this.ch = ch;
299         this.decoder = dec;
300         this.cs = dec.charset();
301         this.bb = ByteBuffer.allocate(mbc < 0
302                                   ? DEFAULT_BYTE_BUFFER_SIZE
303                                   : (mbc < MIN_BYTE_BUFFER_SIZE
304                                      ? MIN_BYTE_BUFFER_SIZE
305                                      : mbc));
306         bb.flip();
307     }
308 
309     private int readBytes() throws IOException {
310         bb.compact();
311         try {
312             if (ch != null) {
< prev index next >