1 /* 2 * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.io; 27 28 29 /** 30 * A character stream whose source is a string. 31 * 32 * @author Mark Reinhold 33 * @since JDK1.1 34 */ 35 36 public class StringReader extends Reader { 37 38 private String str; 39 private int length; 40 private int next = 0; 41 private int mark = 0; 42 43 /** 44 * Creates a new string reader. 45 * 46 * @param s String providing the character stream. 47 */ StringReader(String s)48 public StringReader(String s) { 49 this.str = s; 50 this.length = s.length(); 51 } 52 53 /** Check to make sure that the stream has not been closed */ ensureOpen()54 private void ensureOpen() throws IOException { 55 if (str == null) 56 throw new IOException("Stream closed"); 57 } 58 59 /** 60 * Reads a single character. 61 * 62 * @return The character read, or -1 if the end of the stream has been 63 * reached 64 * 65 * @exception IOException If an I/O error occurs 66 */ read()67 public int read() throws IOException { 68 synchronized (lock) { 69 ensureOpen(); 70 if (next >= length) 71 return -1; 72 return str.charAt(next++); 73 } 74 } 75 76 /** 77 * Reads characters into a portion of an array. 78 * 79 * @param cbuf Destination buffer 80 * @param off Offset at which to start writing characters 81 * @param len Maximum number of characters to read 82 * 83 * @return The number of characters read, or -1 if the end of the 84 * stream has been reached 85 * 86 * @exception IOException If an I/O error occurs 87 */ read(char cbuf[], int off, int len)88 public int read(char cbuf[], int off, int len) throws IOException { 89 synchronized (lock) { 90 ensureOpen(); 91 if ((off < 0) || (off > cbuf.length) || (len < 0) || 92 ((off + len) > cbuf.length) || ((off + len) < 0)) { 93 throw new IndexOutOfBoundsException(); 94 } else if (len == 0) { 95 return 0; 96 } 97 if (next >= length) 98 return -1; 99 int n = Math.min(length - next, len); 100 str.getChars(next, next + n, cbuf, off); 101 next += n; 102 return n; 103 } 104 } 105 106 /** 107 * Skips the specified number of characters in the stream. Returns 108 * the number of characters that were skipped. 109 * 110 * <p>The <code>ns</code> parameter may be negative, even though the 111 * <code>skip</code> method of the {@link Reader} superclass throws 112 * an exception in this case. Negative values of <code>ns</code> cause the 113 * stream to skip backwards. Negative return values indicate a skip 114 * backwards. It is not possible to skip backwards past the beginning of 115 * the string. 116 * 117 * <p>If the entire string has been read or skipped, then this method has 118 * no effect and always returns 0. 119 * 120 * @exception IOException If an I/O error occurs 121 */ skip(long ns)122 public long skip(long ns) throws IOException { 123 synchronized (lock) { 124 ensureOpen(); 125 if (next >= length) 126 return 0; 127 // Bound skip by beginning and end of the source 128 long n = Math.min(length - next, ns); 129 n = Math.max(-next, n); 130 next += n; 131 return n; 132 } 133 } 134 135 /** 136 * Tells whether this stream is ready to be read. 137 * 138 * @return True if the next read() is guaranteed not to block for input 139 * 140 * @exception IOException If the stream is closed 141 */ ready()142 public boolean ready() throws IOException { 143 synchronized (lock) { 144 ensureOpen(); 145 return true; 146 } 147 } 148 149 /** 150 * Tells whether this stream supports the mark() operation, which it does. 151 */ markSupported()152 public boolean markSupported() { 153 return true; 154 } 155 156 /** 157 * Marks the present position in the stream. Subsequent calls to reset() 158 * will reposition the stream to this point. 159 * 160 * @param readAheadLimit Limit on the number of characters that may be 161 * read while still preserving the mark. Because 162 * the stream's input comes from a string, there 163 * is no actual limit, so this argument must not 164 * be negative, but is otherwise ignored. 165 * 166 * @exception IllegalArgumentException If readAheadLimit is < 0 167 * @exception IOException If an I/O error occurs 168 */ mark(int readAheadLimit)169 public void mark(int readAheadLimit) throws IOException { 170 if (readAheadLimit < 0){ 171 throw new IllegalArgumentException("Read-ahead limit < 0"); 172 } 173 synchronized (lock) { 174 ensureOpen(); 175 mark = next; 176 } 177 } 178 179 /** 180 * Resets the stream to the most recent mark, or to the beginning of the 181 * string if it has never been marked. 182 * 183 * @exception IOException If an I/O error occurs 184 */ reset()185 public void reset() throws IOException { 186 synchronized (lock) { 187 ensureOpen(); 188 next = mark; 189 } 190 } 191 192 /** 193 * Closes the stream and releases any system resources associated with 194 * it. Once the stream has been closed, further read(), 195 * ready(), mark(), or reset() invocations will throw an IOException. 196 * Closing a previously closed stream has no effect. 197 */ close()198 public void close() { 199 str = null; 200 } 201 } 202