/* * 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 str. The size of * the reader is set to the length() of the String and the * Object to synchronize access through is set to str. * * @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 readLimit * 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. * @throws 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 true if mark() and reset() are supported, * false otherwise. This implementation always * returns true. */ @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. * @throws 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 count characters from this StringReader and * stores them at offset in the character array * buf. 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. * @throws 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 boolean indicating whether or not this * StringReader is ready to be read without blocking. If the result is * true, the next read() will not block. If * the result is false this Reader may or may not block when * read() is sent. The implementation in StringReader always * returns true even when it has been closed. * * @return true if the receiver will not block when * read() is called, false if unknown * or blocking will occur. * @throws 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 mark() * location. Invocations of read()/skip() will occur from * this new location. If this Reader was not marked, the StringReader is * reset to the beginning of the String. * * @throws 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 count number of characters in this StringReader. * Subsequent read()'s will not return these characters * unless reset() is used. * * @param count The number of characters to skip. * @return the number of characters actually skipped. * @throws 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"); } } }