• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package java.io;
19 
20 import java.util.Arrays;
21 
22 /**
23  * A specialized {@link Reader} for reading the contents of a char array.
24  *
25  * @see CharArrayWriter
26  */
27 public class CharArrayReader extends Reader {
28     /**
29      * The buffer for characters.
30      */
31     protected char[] buf;
32 
33     /**
34      * The current buffer position.
35      */
36     protected int pos;
37 
38     /**
39      * The current mark position.
40      */
41     protected int markedPos = -1;
42 
43     /**
44      * The ending index of the buffer.
45      */
46     protected int count;
47 
48     /**
49      * Constructs a CharArrayReader on the char array {@code buf}. The size of
50      * the reader is set to the length of the buffer and the object to to read
51      * from is set to {@code buf}.
52      *
53      * @param buf
54      *            the char array from which to read.
55      */
CharArrayReader(char[] buf)56     public CharArrayReader(char[] buf) {
57         this.buf = buf;
58         this.count = buf.length;
59     }
60 
61     /**
62      * Constructs a CharArrayReader on the char array {@code buf}. The size of
63      * the reader is set to {@code length} and the start position from which to
64      * read the buffer is set to {@code offset}.
65      *
66      * @param buf
67      *            the char array from which to read.
68      * @param offset
69      *            the index of the first character in {@code buf} to read.
70      * @param length
71      *            the number of characters that can be read from {@code buf}.
72      * @throws IllegalArgumentException
73      *             if {@code offset < 0} or {@code length < 0}, or if
74      *             {@code offset} is greater than the size of {@code buf} .
75      */
CharArrayReader(char[] buf, int offset, int length)76     public CharArrayReader(char[] buf, int offset, int length) {
77         /*
78          * The spec of this constructor is broken. In defining the legal values
79          * of offset and length, it doesn't consider buffer's length. And to be
80          * compatible with the broken spec, we must also test whether
81          * (offset + length) overflows.
82          */
83         if (offset < 0 || offset > buf.length || length < 0 || offset + length < 0) {
84             throw new IllegalArgumentException();
85         }
86         this.buf = buf;
87         this.pos = offset;
88         this.markedPos = offset;
89 
90         /* This is according to spec */
91         int bufferLength = buf.length;
92         this.count = offset + length < bufferLength ? length : bufferLength;
93     }
94 
95     /**
96      * This method closes this CharArrayReader. Once it is closed, you can no
97      * longer read from it. Only the first invocation of this method has any
98      * effect.
99      */
100     @Override
101     public void close() {
102         synchronized (lock) {
103             if (isOpen()) {
104                 buf = null;
105             }
106         }
107     }
108 
109     /**
110      * Indicates whether this reader is open.
111      *
112      * @return {@code true} if the reader is open, {@code false} otherwise.
113      */
114     private boolean isOpen() {
115         return buf != null;
116     }
117 
118     /**
119      * Indicates whether this reader is closed.
120      *
121      * @return {@code true} if the reader is closed, {@code false} otherwise.
122      */
123     private boolean isClosed() {
124         return buf == null;
125     }
126 
127     /**
128      * Sets a mark position in this reader. The parameter {@code readLimit} is
129      * ignored for CharArrayReaders. Calling {@code reset()} will reposition the
130      * reader back to the marked position provided the mark has not been
131      * invalidated.
132      *
133      * @param readLimit
134      *            ignored for CharArrayReaders.
135      * @throws IOException
136      *             if this reader is closed.
137      */
138     @Override
139     public void mark(int readLimit) throws IOException {
140         synchronized (lock) {
141             checkNotClosed();
142             markedPos = pos;
143         }
144     }
145 
146     private void checkNotClosed() throws IOException {
147         if (isClosed()) {
148             throw new IOException("CharArrayReader is closed");
149         }
150     }
151 
152     /**
153      * Indicates whether this reader supports the {@code mark()} and
154      * {@code reset()} methods.
155      *
156      * @return {@code true} for CharArrayReader.
157      * @see #mark(int)
158      * @see #reset()
159      */
160     @Override
161     public boolean markSupported() {
162         return true;
163     }
164 
165     /**
166      * Reads a single character from this reader and returns it as an integer
167      * with the two higher-order bytes set to 0. Returns -1 if no more
168      * characters are available from this reader.
169      *
170      * @return the character read as an int or -1 if the end of the reader has
171      *         been reached.
172      * @throws IOException
173      *             if this reader is closed.
174      */
175     @Override
176     public int read() throws IOException {
177         synchronized (lock) {
178             checkNotClosed();
179             if (pos == count) {
180                 return -1;
181             }
182             return buf[pos++];
183         }
184     }
185 
186     /**
187      * Reads up to {@code count} characters from this CharArrayReader and
188      * stores them at {@code offset} in the character array {@code buffer}.
189      * Returns the number of characters actually read or -1 if the end of reader
190      * was encountered.
191      *
192      * @throws IndexOutOfBoundsException
193      * if {@code offset < 0 || count < 0 || offset + count > buffer.length}.
194      * @throws IOException
195      *             if this reader is closed.
196      */
197     @Override
198     public int read(char[] buffer, int offset, int count) throws IOException {
199         Arrays.checkOffsetAndCount(buffer.length, offset, count);
200         synchronized (lock) {
201             checkNotClosed();
202             if (pos < this.count) {
203                 int bytesRead = pos + count > this.count ? this.count - pos : count;
204                 System.arraycopy(this.buf, pos, buffer, offset, bytesRead);
205                 pos += bytesRead;
206                 return bytesRead;
207             }
208             return -1;
209         }
210     }
211 
212     /**
213      * Indicates whether this reader is ready to be read without blocking.
214      * Returns {@code true} if the next {@code read} will not block. Returns
215      * {@code false} if this reader may or may not block when {@code read} is
216      * called. The implementation in CharArrayReader always returns {@code true}
217      * even when it has been closed.
218      *
219      * @return {@code true} if this reader will not block when {@code read} is
220      *         called, {@code false} if unknown or blocking will occur.
221      * @throws IOException
222      *             if this reader is closed.
223      */
224     @Override
225     public boolean ready() throws IOException {
226         synchronized (lock) {
227             checkNotClosed();
228             return pos != count;
229         }
230     }
231 
232     /**
233      * Resets this reader's position to the last {@code mark()} location.
234      * Invocations of {@code read()} and {@code skip()} will occur from this new
235      * location. If this reader has not been marked, it is reset to the
236      * beginning of the string.
237      *
238      * @throws IOException
239      *             if this reader is closed.
240      */
241     @Override
242     public void reset() throws IOException {
243         synchronized (lock) {
244             checkNotClosed();
245             pos = markedPos != -1 ? markedPos : 0;
246         }
247     }
248 
249     /**
250      * Skips {@code charCount} characters in this reader. Subsequent calls to
251      * {@code read} will not return these characters unless {@code reset}
252      * is used. This method does nothing and returns 0 if {@code charCount <= 0}.
253      *
254      * @return the number of characters actually skipped.
255      * @throws IOException
256      *             if this reader is closed.
257      */
258     @Override
259     public long skip(long charCount) throws IOException {
260         synchronized (lock) {
261             checkNotClosed();
262             if (charCount <= 0) {
263                 return 0;
264             }
265             long skipped = 0;
266             if (charCount < this.count - pos) {
267                 pos = pos + (int) charCount;
268                 skipped = charCount;
269             } else {
270                 skipped = this.count - pos;
271                 pos = this.count;
272             }
273             return skipped;
274         }
275     }
276 }
277