001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.io;
019:
020: import org.apache.harmony.luni.util.Msg;
021:
022: /**
023: * CharArrayReader is used as a buffered character input stream on a character
024: * array.
025: */
026: public class CharArrayReader extends Reader {
027: /**
028: * Buffer for characters
029: */
030: protected char buf[];
031:
032: /**
033: * Current buffer position.
034: */
035: protected int pos;
036:
037: /**
038: * Current mark position.
039: */
040: protected int markedPos = -1;
041:
042: /**
043: * The ending index of the buffer.
044: */
045: protected int count;
046:
047: /**
048: * Construct a CharArrayReader on the char array <code>buffer</code>. The
049: * size of the reader is set to the <code>length()</code> of the buffer
050: * and the Object to synchronize access through is set to
051: * <code>buffer</code>.
052: *
053: * @param buf
054: * the char array to filter reads on.
055: */
056: public CharArrayReader(char[] buf) {
057: super (buf);
058: this .buf = buf;
059: this .count = buf.length;
060: }
061:
062: /**
063: * Construct a CharArrayReader on the char array <code>buffer</code>. The
064: * size of the reader is set to the parameter <code>length()</code> and
065: * the original offset is set to <code>offset</code>.
066: *
067: * @param buf
068: * the char array to filter reads on.
069: * @param offset
070: * the offset in <code>buf</code> to start streaming at.
071: * @param length
072: * the number of characters available to stream over.
073: */
074:
075: public CharArrayReader(char[] buf, int offset, int length) {
076: super (buf);
077: if (offset < 0 || offset > buf.length || length < 0) {
078: throw new IllegalArgumentException();
079: }
080: this .buf = buf;
081: this .pos = offset;
082: this .markedPos = offset;
083:
084: /* This is according to spec */
085: this .count = this .pos + length < buf.length ? length
086: : buf.length;
087: }
088:
089: /**
090: * This method closes this CharArrayReader. Once it is closed, you can no
091: * longer read from it. Only the first invocation of this method has any
092: * effect.
093: */
094: @Override
095: public void close() {
096: synchronized (lock) {
097: if (isOpen()) {
098: buf = null;
099: }
100: }
101: }
102:
103: /**
104: * Answer a boolean indicating whether or not this CharArrayReader is open.
105: *
106: * @return <code>true</code> if the reader is open, <code>false</code>
107: * otherwise.
108: */
109: private boolean isOpen() {
110: return buf != null;
111: }
112:
113: /**
114: * Answer a boolean indicating whether or not this CharArrayReader is
115: * closed.
116: *
117: * @return <code>true</code> if the reader is closed, <code>false</code>
118: * otherwise.
119: */
120: private boolean isClosed() {
121: return buf == null;
122: }
123:
124: /**
125: * Set a Mark position in this Reader. The parameter <code>readLimit</code>
126: * is ignored for CharArrayReaders. Sending reset() will reposition the
127: * reader back to the marked position provided the mark has not been
128: * invalidated.
129: *
130: * @param readLimit
131: * ignored for CharArrayReaders.
132: *
133: * @throws IOException
134: * If an error occurs attempting to mark this CharArrayReader.
135: */
136: @Override
137: public void mark(int readLimit) throws IOException {
138: synchronized (lock) {
139: if (isClosed()) {
140: throw new IOException(Msg.getString("K0060")); //$NON-NLS-1$
141: }
142: markedPos = pos;
143: }
144: }
145:
146: /**
147: * Answers a boolean indicating whether or not this CharArrayReader supports
148: * mark() and reset(). This method always returns true.
149: *
150: * @return indicates whether or not mark() and reset() are supported.
151: */
152: @Override
153: public boolean markSupported() {
154: return true;
155: }
156:
157: /**
158: * Reads a single character from this CharArrayReader and returns the result
159: * as an int. The 2 higher-order bytes are set to 0. If the end of reader
160: * was encountered then return -1.
161: *
162: * @return int the character read or -1 if end of reader.
163: *
164: * @throws IOException
165: * If the CharArrayReader is already closed.
166: */
167: @Override
168: public int read() throws IOException {
169: synchronized (lock) {
170: if (isClosed()) {
171: throw new IOException(Msg.getString("K0060")); //$NON-NLS-1$
172: }
173: if (pos == count) {
174: return -1;
175: }
176: return buf[pos++];
177: }
178: }
179:
180: /**
181: * Reads at most <code>count</code> characters from this CharArrayReader
182: * and stores them at <code>offset</code> in the character array
183: * <code>buf</code>. Returns the number of characters actually read or -1
184: * if the end of reader was encountered.
185: *
186: *
187: * @param buffer
188: * character array to store the read characters
189: * @param offset
190: * offset in buf to store the read characters
191: * @param len
192: * maximum number of characters to read
193: * @return number of characters read or -1 if end of reader.
194: *
195: * @throws IOException
196: * If the CharArrayReader is closed.
197: */
198: @Override
199: public int read(char buffer[], int offset, int len)
200: throws IOException {
201: // avoid int overflow
202: if (offset < 0 || offset > buffer.length || len < 0
203: || len > buffer.length - offset) {
204: throw new ArrayIndexOutOfBoundsException();
205: }
206: synchronized (lock) {
207: if (isClosed()) {
208: throw new IOException(Msg.getString("K0060")); //$NON-NLS-1$
209: }
210: if (pos < this .count) {
211: int bytesRead = pos + len > this .count ? this .count
212: - pos : len;
213: System.arraycopy(this .buf, pos, buffer, offset,
214: bytesRead);
215: pos += bytesRead;
216: return bytesRead;
217: }
218: return -1;
219: }
220: }
221:
222: /**
223: * Answers a <code>boolean</code> indicating whether or not this
224: * CharArrayReader is ready to be read without blocking. If the result is
225: * <code>true</code>, the next <code>read()</code> will not block. If
226: * the result is <code>false</code> this Reader may or may not block when
227: * <code>read()</code> is sent. The implementation in CharArrayReader
228: * always returns <code>true</code> even when it has been closed.
229: *
230: * @return <code>true</code> if the receiver will not block when
231: * <code>read()</code> is called, <code>false</code> if unknown
232: * or blocking will occur.
233: *
234: * @throws IOException
235: * If the CharArrayReader is closed.
236: */
237: @Override
238: public boolean ready() throws IOException {
239: synchronized (lock) {
240: if (isClosed()) {
241: throw new IOException(Msg.getString("K0060")); //$NON-NLS-1$
242: }
243: return pos != count;
244: }
245: }
246:
247: /**
248: * Reset this CharArrayReader's position to the last <code>mark()</code>
249: * location. Invocations of <code>read()/skip()</code> will occur from
250: * this new location. If this Reader was not marked, the CharArrayReader is
251: * reset to the beginning of the String.
252: *
253: * @throws IOException
254: * If this CharArrayReader has already been closed.
255: */
256: @Override
257: public void reset() throws IOException {
258: synchronized (lock) {
259: if (isClosed()) {
260: throw new IOException(Msg.getString("K0060")); //$NON-NLS-1$
261: }
262: pos = markedPos != -1 ? markedPos : 0;
263: }
264: }
265:
266: /**
267: * Skips <code>count</code> number of characters in this CharArrayReader.
268: * Subsequent <code>read()</code>'s will not return these characters
269: * unless <code>reset()</code> is used.
270: *
271: * @param n
272: * The number of characters to skip.
273: * @return long The number of characters actually skipped.
274: *
275: * @throws IOException
276: * If this CharArrayReader has already been closed.
277: */
278: @Override
279: public long skip(long n) throws IOException {
280: synchronized (lock) {
281: if (isClosed()) {
282: throw new IOException(Msg.getString("K0060")); //$NON-NLS-1$
283: }
284: if (n <= 0) {
285: return 0;
286: }
287: long skipped = 0;
288: if (n < this .count - pos) {
289: pos = pos + (int) n;
290: skipped = n;
291: } else {
292: skipped = this.count - pos;
293: pos = this.count;
294: }
295: return skipped;
296: }
297: }
298: }
|