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
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038 package 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 */
058 public 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 }