001: /*
002: * Copyright 1996-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package java.io;
027:
028: /**
029: * This class implements a character buffer that can be used as a
030: * character-input stream.
031: *
032: * @author Herb Jellinek
033: * @version 1.31, 05/05/07
034: * @since JDK1.1
035: */
036: public class CharArrayReader extends Reader {
037: /** The character buffer. */
038: protected char buf[];
039:
040: /** The current buffer position. */
041: protected int pos;
042:
043: /** The position of mark in buffer. */
044: protected int markedPos = 0;
045:
046: /**
047: * The index of the end of this buffer. There is not valid
048: * data at or beyond this index.
049: */
050: protected int count;
051:
052: /**
053: * Creates a CharArrayReader from the specified array of chars.
054: * @param buf Input buffer (not copied)
055: */
056: public CharArrayReader(char buf[]) {
057: this .buf = buf;
058: this .pos = 0;
059: this .count = buf.length;
060: }
061:
062: /**
063: * Creates a CharArrayReader from the specified array of chars.
064: *
065: * <p> The resulting reader will start reading at the given
066: * <tt>offset</tt>. The total number of <tt>char</tt> values that can be
067: * read from this reader will be either <tt>length</tt> or
068: * <tt>buf.length-offset</tt>, whichever is smaller.
069: *
070: * @throws IllegalArgumentException
071: * If <tt>offset</tt> is negative or greater than
072: * <tt>buf.length</tt>, or if <tt>length</tt> is negative, or if
073: * the sum of these two values is negative.
074: *
075: * @param buf Input buffer (not copied)
076: * @param offset Offset of the first char to read
077: * @param length Number of chars to read
078: */
079: public CharArrayReader(char buf[], int offset, int length) {
080: if ((offset < 0) || (offset > buf.length) || (length < 0)
081: || ((offset + length) < 0)) {
082: throw new IllegalArgumentException();
083: }
084: this .buf = buf;
085: this .pos = offset;
086: this .count = Math.min(offset + length, buf.length);
087: this .markedPos = offset;
088: }
089:
090: /** Checks to make sure that the stream has not been closed */
091: private void ensureOpen() throws IOException {
092: if (buf == null)
093: throw new IOException("Stream closed");
094: }
095:
096: /**
097: * Reads a single character.
098: *
099: * @exception IOException If an I/O error occurs
100: */
101: public int read() throws IOException {
102: synchronized (lock) {
103: ensureOpen();
104: if (pos >= count)
105: return -1;
106: else
107: return buf[pos++];
108: }
109: }
110:
111: /**
112: * Reads characters into a portion of an array.
113: * @param b Destination buffer
114: * @param off Offset at which to start storing characters
115: * @param len Maximum number of characters to read
116: * @return The actual number of characters read, or -1 if
117: * the end of the stream has been reached
118: *
119: * @exception IOException If an I/O error occurs
120: */
121: public int read(char b[], int off, int len) throws IOException {
122: synchronized (lock) {
123: ensureOpen();
124: if ((off < 0) || (off > b.length) || (len < 0)
125: || ((off + len) > b.length) || ((off + len) < 0)) {
126: throw new IndexOutOfBoundsException();
127: } else if (len == 0) {
128: return 0;
129: }
130:
131: if (pos >= count) {
132: return -1;
133: }
134: if (pos + len > count) {
135: len = count - pos;
136: }
137: if (len <= 0) {
138: return 0;
139: }
140: System.arraycopy(buf, pos, b, off, len);
141: pos += len;
142: return len;
143: }
144: }
145:
146: /**
147: * Skips characters. Returns the number of characters that were skipped.
148: *
149: * <p>The <code>n</code> parameter may be negative, even though the
150: * <code>skip</code> method of the {@link Reader} superclass throws
151: * an exception in this case. If <code>n</code> is negative, then
152: * this method does nothing and returns <code>0</code>.
153: *
154: * @param n The number of characters to skip
155: * @return The number of characters actually skipped
156: * @exception IOException If the stream is closed, or an I/O error occurs
157: */
158: public long skip(long n) throws IOException {
159: synchronized (lock) {
160: ensureOpen();
161: if (pos + n > count) {
162: n = count - pos;
163: }
164: if (n < 0) {
165: return 0;
166: }
167: pos += n;
168: return n;
169: }
170: }
171:
172: /**
173: * Tells whether this stream is ready to be read. Character-array readers
174: * are always ready to be read.
175: *
176: * @exception IOException If an I/O error occurs
177: */
178: public boolean ready() throws IOException {
179: synchronized (lock) {
180: ensureOpen();
181: return (count - pos) > 0;
182: }
183: }
184:
185: /**
186: * Tells whether this stream supports the mark() operation, which it does.
187: */
188: public boolean markSupported() {
189: return true;
190: }
191:
192: /**
193: * Marks the present position in the stream. Subsequent calls to reset()
194: * will reposition the stream to this point.
195: *
196: * @param readAheadLimit Limit on the number of characters that may be
197: * read while still preserving the mark. Because
198: * the stream's input comes from a character array,
199: * there is no actual limit; hence this argument is
200: * ignored.
201: *
202: * @exception IOException If an I/O error occurs
203: */
204: public void mark(int readAheadLimit) throws IOException {
205: synchronized (lock) {
206: ensureOpen();
207: markedPos = pos;
208: }
209: }
210:
211: /**
212: * Resets the stream to the most recent mark, or to the beginning if it has
213: * never been marked.
214: *
215: * @exception IOException If an I/O error occurs
216: */
217: public void reset() throws IOException {
218: synchronized (lock) {
219: ensureOpen();
220: pos = markedPos;
221: }
222: }
223:
224: /**
225: * Closes the stream and releases any system resources associated with
226: * it. Once the stream has been closed, further read(), ready(),
227: * mark(), reset(), or skip() invocations will throw an IOException.
228: * Closing a previously closed stream has no effect.
229: */
230: public void close() {
231: buf = null;
232: }
233: }
|