| /* |
| * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package java.io; |
| |
| |
| /** |
| * A character stream whose source is a string. |
| * |
| * @author Mark Reinhold |
| * @since 1.1 |
| */ |
| |
| public class StringReader extends Reader { |
| |
| private String str; |
| private int length; |
| private int next = 0; |
| private int mark = 0; |
| |
| /** |
| * Creates a new string reader. |
| * |
| * @param s String providing the character stream. |
| */ |
| public StringReader(String s) { |
| this.str = s; |
| this.length = s.length(); |
| } |
| |
| /** Check to make sure that the stream has not been closed */ |
| private void ensureOpen() throws IOException { |
| if (str == null) |
| throw new IOException("Stream closed"); |
| } |
| |
| /** |
| * Reads a single character. |
| * |
| * @return The character read, or -1 if the end of the stream has been |
| * reached |
| * |
| * @exception IOException If an I/O error occurs |
| */ |
| public int read() throws IOException { |
| synchronized (lock) { |
| ensureOpen(); |
| if (next >= length) |
| return -1; |
| return str.charAt(next++); |
| } |
| } |
| |
| /** |
| * Reads characters into a portion of an array. |
| * |
| * @param cbuf Destination buffer |
| * @param off Offset at which to start writing characters |
| * @param len Maximum number of characters to read |
| * |
| * @return The number of characters read, or -1 if the end of the |
| * stream has been reached |
| * |
| * @exception IOException If an I/O error occurs |
| * @exception IndexOutOfBoundsException {@inheritDoc} |
| */ |
| public int read(char cbuf[], int off, int len) throws IOException { |
| synchronized (lock) { |
| ensureOpen(); |
| if ((off < 0) || (off > cbuf.length) || (len < 0) || |
| ((off + len) > cbuf.length) || ((off + len) < 0)) { |
| throw new IndexOutOfBoundsException(); |
| } else if (len == 0) { |
| return 0; |
| } |
| if (next >= length) |
| return -1; |
| int n = Math.min(length - next, len); |
| str.getChars(next, next + n, cbuf, off); |
| next += n; |
| return n; |
| } |
| } |
| |
| /** |
| * Skips the specified number of characters in the stream. Returns |
| * the number of characters that were skipped. |
| * |
| * <p>The <code>ns</code> parameter may be negative, even though the |
| * <code>skip</code> method of the {@link Reader} superclass throws |
| * an exception in this case. Negative values of <code>ns</code> cause the |
| * stream to skip backwards. Negative return values indicate a skip |
| * backwards. It is not possible to skip backwards past the beginning of |
| * the string. |
| * |
| * <p>If the entire string has been read or skipped, then this method has |
| * no effect and always returns 0. |
| * |
| * @exception IOException If an I/O error occurs |
| */ |
| public long skip(long ns) throws IOException { |
| synchronized (lock) { |
| ensureOpen(); |
| if (next >= length) |
| return 0; |
| // Bound skip by beginning and end of the source |
| long n = Math.min(length - next, ns); |
| n = Math.max(-next, n); |
| next += n; |
| return n; |
| } |
| } |
| |
| /** |
| * Tells whether this stream is ready to be read. |
| * |
| * @return True if the next read() is guaranteed not to block for input |
| * |
| * @exception IOException If the stream is closed |
| */ |
| public boolean ready() throws IOException { |
| synchronized (lock) { |
| ensureOpen(); |
| return true; |
| } |
| } |
| |
| /** |
| * Tells whether this stream supports the mark() operation, which it does. |
| */ |
| public boolean markSupported() { |
| return true; |
| } |
| |
| /** |
| * Marks the present position in the stream. Subsequent calls to reset() |
| * will reposition the stream to this point. |
| * |
| * @param readAheadLimit Limit on the number of characters that may be |
| * read while still preserving the mark. Because |
| * the stream's input comes from a string, there |
| * is no actual limit, so this argument must not |
| * be negative, but is otherwise ignored. |
| * |
| * @exception IllegalArgumentException If {@code readAheadLimit < 0} |
| * @exception IOException If an I/O error occurs |
| */ |
| public void mark(int readAheadLimit) throws IOException { |
| if (readAheadLimit < 0){ |
| throw new IllegalArgumentException("Read-ahead limit < 0"); |
| } |
| synchronized (lock) { |
| ensureOpen(); |
| mark = next; |
| } |
| } |
| |
| /** |
| * Resets the stream to the most recent mark, or to the beginning of the |
| * string if it has never been marked. |
| * |
| * @exception IOException If an I/O error occurs |
| */ |
| public void reset() throws IOException { |
| synchronized (lock) { |
| ensureOpen(); |
| next = mark; |
| } |
| } |
| |
| /** |
| * Closes the stream and releases any system resources associated with |
| * it. Once the stream has been closed, further read(), |
| * ready(), mark(), or reset() invocations will throw an IOException. |
| * Closing a previously closed stream has no effect. This method will block |
| * while there is another thread blocking on the reader. |
| */ |
| public void close() { |
| synchronized (lock) { |
| str = null; |
| } |
| } |
| } |