001/* StringReader.java -- permits a String to be read as a character input stream 002 Copyright (C) 1998, 1999, 2000, 2003 Free Software Foundation 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038package java.io; 039 040/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 041 * "The Java Language Specification", ISBN 0-201-63451-1 042 * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. 043 * Status: Believed complete and correct 044 */ 045 046/** 047 * This class permits a <code>String</code> to be read as a character 048 * input stream. 049 * <p> 050 * The mark/reset functionality in this class behaves differently than 051 * normal. If no mark has been set, then calling the <code>reset()</code> 052 * method rewinds the read pointer to the beginning of the <code>String</code>. 053 * 054 * @author Aaron M. Renn (arenn@urbanophile.com) 055 * @author Warren Levy (warrenl@cygnus.com) 056 * @date October 19, 1998. 057 */ 058public class StringReader extends Reader 059{ 060 /* A String provided by the creator of the stream. */ 061 private String buf; 062 063 /* Position of the next char in buf to be read. */ 064 private int pos; 065 066 /* The currently marked position in the stream. */ 067 private int markedPos; 068 069 /* The index in buf one greater than the last valid character. */ 070 private int count; 071 072 /** 073 * Create a new <code>StringReader</code> that will read chars from the 074 * passed in <code>String</code>. This stream will read from the beginning 075 * to the end of the <code>String</code>. 076 * 077 * @param buffer The <code>String</code> this stream will read from. 078 */ 079 public StringReader(String buffer) 080 { 081 super(); 082 buf = buffer; 083 084 count = buffer.length(); 085 markedPos = pos = 0; 086 } 087 088 public void close() 089 { 090 synchronized (lock) 091 { 092 buf = null; 093 } 094 } 095 096 public void mark(int readAheadLimit) throws IOException 097 { 098 synchronized (lock) 099 { 100 if (buf == null) 101 throw new IOException("Stream closed"); 102 103 // readAheadLimit is ignored per Java Class Lib. book, p. 1692. 104 markedPos = pos; 105 } 106 } 107 108 public boolean markSupported() 109 { 110 return true; 111 } 112 113 public int read() throws IOException 114 { 115 synchronized (lock) 116 { 117 if (buf == null) 118 throw new IOException("Stream closed"); 119 120 if (pos < count) 121 return ((int) buf.charAt(pos++)) & 0xFFFF; 122 return -1; 123 } 124 } 125 126 public int read(char[] b, int off, int len) throws IOException 127 { 128 synchronized (lock) 129 { 130 if (buf == null) 131 throw new IOException("Stream closed"); 132 133 /* Don't need to check pos value, arraycopy will check it. */ 134 if (off < 0 || len < 0 || off + len > b.length) 135 throw new ArrayIndexOutOfBoundsException(); 136 137 if (pos >= count) 138 return -1; 139 140 int lastChar = Math.min(count, pos + len); 141 buf.getChars(pos, lastChar, b, off); 142 int numChars = lastChar - pos; 143 pos = lastChar; 144 return numChars; 145 } 146 } 147 148 /** 149 * This method determines if the stream is ready to be read. This class 150 * is always ready to read and so always returns <code>true</code>, unless 151 * close() has previously been called in which case an IOException is 152 * thrown. 153 * 154 * @return <code>true</code> to indicate that this object is ready to be read. 155 * @exception IOException If the stream is closed. 156 */ 157 public boolean ready() throws IOException 158 { 159 if (buf == null) 160 throw new IOException("Stream closed"); 161 162 return true; 163 } 164 165 /** 166 * Sets the read position in the stream to the previously 167 * marked position or to 0 (i.e., the beginning of the stream) if the mark 168 * has not already been set. 169 */ 170 public void reset() throws IOException 171 { 172 synchronized (lock) 173 { 174 if (buf == null) 175 throw new IOException("Stream closed"); 176 177 pos = markedPos; 178 } 179 } 180 181 /** 182 * This method attempts to skip the requested number of chars in the 183 * input stream. It does this by advancing the <code>pos</code> value by 184 * the specified number of chars. It this would exceed the length of the 185 * buffer, then only enough chars are skipped to position the stream at 186 * the end of the buffer. The actual number of chars skipped is returned. 187 * 188 * @param n The requested number of chars to skip 189 * 190 * @return The actual number of chars skipped. 191 */ 192 public long skip(long n) throws IOException 193 { 194 synchronized (lock) 195 { 196 if (buf == null) 197 throw new IOException("Stream closed"); 198 199 // Even though the var numChars is a long, in reality it can never 200 // be larger than an int since the result of subtracting 2 positive 201 // ints will always fit in an int. Since we have to return a long 202 // anyway, numChars might as well just be a long. 203 long numChars = Math.min((long) (count - pos), n < 0 ? 0L : n); 204 pos += numChars; 205 return numChars; 206 } 207 } 208}