blob: 7ffcaa1444acc15870ff7adc44070ac098febad9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tests.support;
import java.io.IOException;
import java.io.Reader;
public class Support_StringReader extends Reader {
private String str;
private int markpos = -1;
private int pos = 0;
private int count;
/**
* Construct a StringReader on the String <code>str</code>. The size of
* the reader is set to the <code>length()</code> of the String and the
* Object to synchronize access through is set to <code>str</code>.
*
* @param str
* the String to filter reads on.
*/
public Support_StringReader(String str) {
super(str);
this.str = str;
this.count = str.length();
}
/**
* This method closes this StringReader. Once it is closed, you can no
* longer read from it. Only the first invocation of this method has any
* effect.
*
*/
@Override
public void close() {
synchronized (lock) {
if (isOpen()) {
str = null;
}
}
}
/**
* Answer a boolean indicating whether or not this StringReader is open.
*/
private boolean isOpen() {
return str != null;
}
/**
* Set a Mark position in this Reader. The parameter <code>readLimit</code>
* is ignored for StringReaders. Sending reset() will reposition the reader
* back to the marked position provided the mark has not been invalidated.
*
* @param readlimit
* ignored for StringReaders.
*
* @exception java.io.IOException
* If an error occurs attempting mark this StringReader.
*/
@Override
public void mark(int readLimit) throws IOException {
if (readLimit >= 0) {
synchronized (lock) {
if (isOpen()) {
markpos = pos;
} else {
throw new IOException("StringReader is closed");
}
}
} else {
throw new IllegalArgumentException();
}
}
/**
* Answers a boolean indicating whether or not this StringReader supports
* mark() and reset(). This method always returns true.
*
* @return <code>true</code> if mark() and reset() are supported,
* <code>false</code> otherwise. This implementation always
* returns <code>true</code>.
*/
@Override
public boolean markSupported() {
return true;
}
/**
* Reads a single character from this StringReader and returns the result as
* an int. The 2 higher-order bytes are set to 0. If the end of reader was
* encountered then return -1.
*
* @return the character read or -1 if end of reader.
*
* @exception java.io.IOException
* If the StringReader is already closed.
*/
@Override
public int read() throws IOException {
synchronized (lock) {
if (isOpen()) {
if (pos != count) {
return str.charAt(pos++);
}
return -1;
}
throw new IOException("StringReader is closed");
}
}
/**
* Reads at most <code>count</code> characters from this StringReader and
* stores them at <code>offset</code> in the character array
* <code>buf</code>. Returns the number of characters actually read or -1
* if the end of reader was encountered.
*
* @param buf
* character array to store the read characters
* @param offset
* offset in buf to store the read characters
* @param count
* maximum number of characters to read
* @return the number of characters read or -1 if end of reader.
*
* @exception java.io.IOException
* If the StringReader is closed.
*/
@Override
public int read(char buf[], int offset, int count) throws IOException {
// avoid int overflow
if (0 <= offset && offset <= buf.length && 0 <= count
&& count <= buf.length - offset) {
synchronized (lock) {
if (isOpen()) {
if (pos == this.count) {
return -1;
}
int end = pos + count > this.count ? this.count : pos
+ count;
str.getChars(pos, end, buf, offset);
int read = end - pos;
pos = end;
return read;
}
throw new IOException("StringReader is closed");
}
}
throw new ArrayIndexOutOfBoundsException();
}
/**
* Answers a <code>boolean</code> indicating whether or not this
* StringReader is ready to be read without blocking. If the result is
* <code>true</code>, the next <code>read()</code> will not block. If
* the result is <code>false</code> this Reader may or may not block when
* <code>read()</code> is sent. The implementation in StringReader always
* returns <code>true</code> even when it has been closed.
*
* @return <code>true</code> if the receiver will not block when
* <code>read()</code> is called, <code>false</code> if unknown
* or blocking will occur.
*
* @exception java.io.IOException
* If an IO error occurs.
*/
@Override
public boolean ready() throws IOException {
synchronized (lock) {
if (isOpen()) {
return true;
}
throw new IOException("StringReader is closed");
}
}
/**
* Reset this StringReader's position to the last <code>mark()</code>
* location. Invocations of <code>read()/skip()</code> will occur from
* this new location. If this Reader was not marked, the StringReader is
* reset to the beginning of the String.
*
* @exception java.io.IOException
* If this StringReader has already been closed.
*/
@Override
public void reset() throws IOException {
synchronized (lock) {
if (isOpen()) {
pos = markpos != -1 ? markpos : 0;
} else {
throw new IOException("StringReader is closed");
}
}
}
/**
* Skips <code>count</code> number of characters in this StringReader.
* Subsequent <code>read()</code>'s will not return these characters
* unless <code>reset()</code> is used.
*
* @param count
* The number of characters to skip.
* @return the number of characters actually skipped.
*
* @exception java.io.IOException
* If this StringReader has already been closed.
*/
@Override
public long skip(long count) throws IOException {
synchronized (lock) {
if (isOpen()) {
if (count <= 0) {
return 0;
}
long skipped = 0;
if (count < this.count - pos) {
pos = pos + (int) count;
skipped = count;
} else {
skipped = this.count - pos;
pos = this.count;
}
return skipped;
}
throw new IOException("StringReader is closed");
}
}
}