001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.io;
019:
020: import org.apache.harmony.luni.util.Msg;
021:
022: /**
023: * StringReader is used as a character input stream on a String.
024: *
025: * @see StringWriter
026: */
027: public class StringReader extends Reader {
028: private String str;
029:
030: private int markpos = -1;
031:
032: private int pos;
033:
034: private int count;
035:
036: /**
037: * Construct a StringReader on the String <code>str</code>. The size of
038: * the reader is set to the <code>length()</code> of the String and the
039: * Object to synchronize access through is set to <code>str</code>.
040: *
041: * @param str
042: * the String to filter reads on.
043: */
044: public StringReader(String str) {
045: super ();
046: this .str = str;
047: this .count = str.length();
048: }
049:
050: /**
051: * This method closes this StringReader. Once it is closed, you can no
052: * longer read from it. Only the first invocation of this method has any
053: * effect.
054: */
055: @Override
056: public void close() {
057: str = null;
058: }
059:
060: /**
061: * Answer a boolean indicating whether or not this StringReader is closed.
062: *
063: * @return <code>true</code> if closed, otherwise <code>false</code>.
064: */
065: private boolean isClosed() {
066: return str == null;
067: }
068:
069: /**
070: * Set a Mark position in this Reader. The parameter <code>readLimit</code>
071: * is ignored for StringReaders. Sending reset() will reposition the reader
072: * back to the marked position provided the mark has not been invalidated.
073: *
074: * @param readLimit
075: * ignored for StringReaders.
076: *
077: * @throws IOException
078: * If an error occurs attempting mark this StringReader.
079: */
080: @Override
081: public void mark(int readLimit) throws IOException {
082: if (readLimit < 0) {
083: throw new IllegalArgumentException();
084: }
085:
086: synchronized (lock) {
087: if (isClosed()) {
088: throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$
089: }
090: markpos = pos;
091: }
092: }
093:
094: /**
095: * Answers a boolean indicating whether or not this StringReader supports
096: * mark() and reset(). This method always returns true.
097: *
098: * @return <code>true</code> if mark() and reset() are supported,
099: * <code>false</code> otherwise. This implementation always
100: * returns <code>true</code>.
101: */
102: @Override
103: public boolean markSupported() {
104: return true;
105: }
106:
107: /**
108: * Reads a single character from this StringReader and returns the result as
109: * an int. The 2 higher-order bytes are set to 0. If the end of reader was
110: * encountered then return -1.
111: *
112: * @return the character read or -1 if end of reader.
113: *
114: * @throws IOException
115: * If the StringReader is already closed.
116: */
117: @Override
118: public int read() throws IOException {
119: synchronized (lock) {
120: if (isClosed()) {
121: throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$
122: }
123: if (pos != count) {
124: return str.charAt(pos++);
125: }
126: return -1;
127: }
128: }
129:
130: /*
131: * (non-Javadoc)
132: *
133: * @see java.io.Reader#read(char[], int, int)
134: */
135: @Override
136: public int read(char buf[], int offset, int len) throws IOException {
137: synchronized (lock) {
138: if (isClosed()) {
139: throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$
140: }
141: // avoid int overflow
142: if (offset < 0 || offset > buf.length || len < 0
143: || len > buf.length - offset) {
144: throw new ArrayIndexOutOfBoundsException();
145: }
146: if (len == 0) {
147: return 0;
148: }
149: if (pos == this .count) {
150: return -1;
151: }
152: int end = pos + len > this .count ? this .count : pos + len;
153: str.getChars(pos, end, buf, offset);
154: int read = end - pos;
155: pos = end;
156: return read;
157: }
158: }
159:
160: /**
161: * Answers a <code>boolean</code> indicating whether or not this
162: * StringReader is ready to be read without blocking. If the result is
163: * <code>true</code>, the next <code>read()</code> will not block. If
164: * the result is <code>false</code> this Reader may or may not block when
165: * <code>read()</code> is sent. The implementation in StringReader always
166: * returns <code>true</code> even when it has been closed.
167: *
168: * @return <code>true</code> if the receiver will not block when
169: * <code>read()</code> is called, <code>false</code> if unknown
170: * or blocking will occur.
171: *
172: * @throws IOException
173: * If an IO error occurs.
174: */
175: @Override
176: public boolean ready() throws IOException {
177: synchronized (lock) {
178: if (isClosed()) {
179: throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$
180: }
181: return true;
182: }
183: }
184:
185: /**
186: * Reset this StringReader's position to the last <code>mark()</code>
187: * location. Invocations of <code>read()/skip()</code> will occur from
188: * this new location. If this Reader was not marked, the StringReader is
189: * reset to the beginning of the String.
190: *
191: * @throws IOException
192: * If this StringReader has already been closed.
193: */
194: @Override
195: public void reset() throws IOException {
196: synchronized (lock) {
197: if (isClosed()) {
198: throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$
199: }
200: pos = markpos != -1 ? markpos : 0;
201: }
202: }
203:
204: /*
205: * (non-Javadoc)
206: *
207: * @see java.io.Reader#skip(long)
208: */
209: @Override
210: public long skip(long ns) throws IOException {
211: synchronized (lock) {
212: if (isClosed()) {
213: throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$
214: }
215: if (ns <= 0) {
216: return 0;
217: }
218: long skipped = 0;
219: if (ns < this .count - pos) {
220: pos = pos + (int) ns;
221: skipped = ns;
222: } else {
223: skipped = this.count - pos;
224: pos = this.count;
225: }
226: return skipped;
227: }
228: }
229: }
|