1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package tests.support; 19 20 import java.io.IOException; 21 import java.io.Reader; 22 23 public class Support_StringReader extends Reader { 24 private String str; 25 26 private int markpos = -1; 27 28 private int pos = 0; 29 30 private int count; 31 32 /** 33 * Construct a StringReader on the String <code>str</code>. The size of 34 * the reader is set to the <code>length()</code> of the String and the 35 * Object to synchronize access through is set to <code>str</code>. 36 * 37 * @param str 38 * the String to filter reads on. 39 */ 40 public Support_StringReader(String str) { 41 super(str); 42 this.str = str; 43 this.count = str.length(); 44 } 45 46 /** 47 * This method closes this StringReader. Once it is closed, you can no 48 * longer read from it. Only the first invocation of this method has any 49 * effect. 50 * 51 */ 52 @Override 53 public void close() { 54 synchronized (lock) { 55 if (isOpen()) { 56 str = null; 57 } 58 } 59 } 60 61 /** 62 * Answer a boolean indicating whether or not this StringReader is open. 63 */ 64 private boolean isOpen() { 65 return str != null; 66 } 67 68 /** 69 * Set a Mark position in this Reader. The parameter <code>readLimit</code> 70 * is ignored for StringReaders. Sending reset() will reposition the reader 71 * back to the marked position provided the mark has not been invalidated. 72 * 73 * @param readlimit 74 * ignored for StringReaders. 75 * 76 * @exception java.io.IOException 77 * If an error occurs attempting mark this StringReader. 78 */ 79 @Override 80 public void mark(int readLimit) throws IOException { 81 if (readLimit >= 0) { 82 synchronized (lock) { 83 if (isOpen()) { 84 markpos = pos; 85 } else { 86 throw new IOException("StringReader is closed"); 87 } 88 } 89 } else { 90 throw new IllegalArgumentException(); 91 } 92 } 93 94 /** 95 * Answers a boolean indicating whether or not this StringReader supports 96 * mark() and reset(). This method always returns true. 97 * 98 * @return <code>true</code> if mark() and reset() are supported, 99 * <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 * @exception java.io.IOException 115 * If the StringReader is already closed. 116 */ 117 @Override 118 public int read() throws IOException { 119 synchronized (lock) { 120 if (isOpen()) { 121 if (pos != count) { 122 return str.charAt(pos++); 123 } 124 return -1; 125 } 126 throw new IOException("StringReader is closed"); 127 } 128 } 129 130 /** 131 * Reads at most <code>count</code> characters from this StringReader and 132 * stores them at <code>offset</code> in the character array 133 * <code>buf</code>. Returns the number of characters actually read or -1 134 * if the end of reader was encountered. 135 * 136 * @param buf 137 * character array to store the read characters 138 * @param offset 139 * offset in buf to store the read characters 140 * @param count 141 * maximum number of characters to read 142 * @return the number of characters read or -1 if end of reader. 143 * 144 * @exception java.io.IOException 145 * If the StringReader is closed. 146 */ 147 @Override 148 public int read(char buf[], int offset, int count) throws IOException { 149 // avoid int overflow 150 if (0 <= offset && offset <= buf.length && 0 <= count 151 && count <= buf.length - offset) { 152 synchronized (lock) { 153 if (isOpen()) { 154 if (pos == this.count) { 155 return -1; 156 } 157 int end = pos + count > this.count ? this.count : pos 158 + count; 159 str.getChars(pos, end, buf, offset); 160 int read = end - pos; 161 pos = end; 162 return read; 163 } 164 throw new IOException("StringReader is closed"); 165 } 166 } 167 throw new ArrayIndexOutOfBoundsException(); 168 } 169 170 /** 171 * Answers a <code>boolean</code> indicating whether or not this 172 * StringReader is ready to be read without blocking. If the result is 173 * <code>true</code>, the next <code>read()</code> will not block. If 174 * the result is <code>false</code> this Reader may or may not block when 175 * <code>read()</code> is sent. The implementation in StringReader always 176 * returns <code>true</code> even when it has been closed. 177 * 178 * @return <code>true</code> if the receiver will not block when 179 * <code>read()</code> is called, <code>false</code> if unknown 180 * or blocking will occur. 181 * 182 * @exception java.io.IOException 183 * If an IO error occurs. 184 */ 185 @Override 186 public boolean ready() throws IOException { 187 synchronized (lock) { 188 if (isOpen()) { 189 return true; 190 } 191 throw new IOException("StringReader is closed"); 192 } 193 } 194 195 /** 196 * Reset this StringReader's position to the last <code>mark()</code> 197 * location. Invocations of <code>read()/skip()</code> will occur from 198 * this new location. If this Reader was not marked, the StringReader is 199 * reset to the beginning of the String. 200 * 201 * @exception java.io.IOException 202 * If this StringReader has already been closed. 203 */ 204 @Override 205 public void reset() throws IOException { 206 synchronized (lock) { 207 if (isOpen()) { 208 pos = markpos != -1 ? markpos : 0; 209 } else { 210 throw new IOException("StringReader is closed"); 211 } 212 } 213 } 214 215 /** 216 * Skips <code>count</code> number of characters in this StringReader. 217 * Subsequent <code>read()</code>'s will not return these characters 218 * unless <code>reset()</code> is used. 219 * 220 * @param count 221 * The number of characters to skip. 222 * @return the number of characters actually skipped. 223 * 224 * @exception java.io.IOException 225 * If this StringReader has already been closed. 226 */ 227 @Override 228 public long skip(long count) throws IOException { 229 synchronized (lock) { 230 if (isOpen()) { 231 if (count <= 0) { 232 return 0; 233 } 234 long skipped = 0; 235 if (count < this.count - pos) { 236 pos = pos + (int) count; 237 skipped = count; 238 } else { 239 skipped = this.count - pos; 240 pos = this.count; 241 } 242 return skipped; 243 } 244 throw new IOException("StringReader is closed"); 245 } 246 } 247 } 248