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 java.io; 19 20 import java.util.Arrays; 21 22 /** 23 * A specialized {@link Writer} for class for writing content to an (internal) 24 * char array. As bytes are written to this writer, the char array may be 25 * expanded to hold more characters. When the writing is considered to be 26 * finished, a copy of the char array can be requested from the class. 27 * 28 * @see CharArrayReader 29 */ 30 public class CharArrayWriter extends Writer { 31 32 /** 33 * The buffer for characters. 34 */ 35 protected char[] buf; 36 37 /** 38 * The ending index of the buffer. 39 */ 40 protected int count; 41 42 /** 43 * Constructs a new {@code CharArrayWriter} which has a buffer allocated 44 * with the default size of 32 characters. This buffer is also used as the 45 * {@code lock} to synchronize access to this writer. 46 */ 47 public CharArrayWriter() { 48 buf = new char[32]; 49 lock = buf; 50 } 51 52 /** 53 * Constructs a new {@code CharArrayWriter} which has a buffer allocated 54 * with the size of {@code initialSize} characters. The buffer is also used 55 * as the {@code lock} to synchronize access to this writer. 56 * 57 * @param initialSize 58 * the initial size of this CharArrayWriters buffer. 59 * @throws IllegalArgumentException 60 * if {@code initialSize < 0}. 61 */ 62 public CharArrayWriter(int initialSize) { 63 if (initialSize < 0) { 64 throw new IllegalArgumentException("size < 0"); 65 } 66 buf = new char[initialSize]; 67 lock = buf; 68 } 69 70 /** 71 * Closes this writer. The implementation in {@code CharArrayWriter} does nothing. 72 */ 73 @Override 74 public void close() { 75 /* empty */ 76 } 77 78 private void expand(int i) { 79 /* Can the buffer handle @i more chars, if not expand it */ 80 if (count + i <= buf.length) { 81 return; 82 } 83 84 int newLen = Math.max(2 * buf.length, count + i); 85 char[] newbuf = new char[newLen]; 86 System.arraycopy(buf, 0, newbuf, 0, count); 87 buf = newbuf; 88 } 89 90 /** 91 * Flushes this writer. The implementation in {@code CharArrayWriter} does nothing. 92 */ 93 @Override 94 public void flush() { 95 /* empty */ 96 } 97 98 /** 99 * Resets this writer. The current write position is reset to the beginning 100 * of the buffer. All written characters are lost and the size of this 101 * writer is set to 0. 102 */ 103 public void reset() { 104 synchronized (lock) { 105 count = 0; 106 } 107 } 108 109 /** 110 * Returns the size of this writer, that is the number of characters it 111 * stores. This number changes if this writer is reset or when more 112 * characters are written to it. 113 * 114 * @return this CharArrayWriter's current size in characters. 115 */ 116 public int size() { 117 synchronized (lock) { 118 return count; 119 } 120 } 121 122 /** 123 * Returns the contents of the receiver as a char array. The array returned 124 * is a copy and any modifications made to this writer after calling this 125 * method are not reflected in the result. 126 * 127 * @return this CharArrayWriter's contents as a new char array. 128 */ 129 public char[] toCharArray() { 130 synchronized (lock) { 131 char[] result = new char[count]; 132 System.arraycopy(buf, 0, result, 0, count); 133 return result; 134 } 135 } 136 137 /** 138 * Returns the contents of this {@code CharArrayWriter} as a string. The 139 * string returned is a copy and any modifications made to this writer after 140 * calling this method are not reflected in the result. 141 * 142 * @return this CharArrayWriters contents as a new string. 143 */ 144 @Override 145 public String toString() { 146 synchronized (lock) { 147 return new String(buf, 0, count); 148 } 149 } 150 151 /** 152 * Writes {@code count} characters starting at {@code offset} in {@code c} 153 * to this writer. 154 * 155 * @param buffer 156 * the non-null array containing characters to write. 157 * @param offset 158 * the index of the first character in {@code buf} to write. 159 * @param len 160 * maximum number of characters to write. 161 * @throws IndexOutOfBoundsException 162 * if {@code offset < 0} or {@code len < 0}, or if 163 * {@code offset + len} is bigger than the size of {@code c}. 164 */ 165 @Override 166 public void write(char[] buffer, int offset, int len) { 167 Arrays.checkOffsetAndCount(buffer.length, offset, len); 168 synchronized (lock) { 169 expand(len); 170 System.arraycopy(buffer, offset, this.buf, this.count, len); 171 this.count += len; 172 } 173 } 174 175 /** 176 * Writes the specified character {@code oneChar} to this writer. 177 * This implementation writes the two low order bytes of the integer 178 * {@code oneChar} to the buffer. 179 * 180 * @param oneChar 181 * the character to write. 182 */ 183 @Override 184 public void write(int oneChar) { 185 synchronized (lock) { 186 expand(1); 187 buf[count++] = (char) oneChar; 188 } 189 } 190 191 /** 192 * Writes {@code count} characters starting at {@code offset} from 193 * the string {@code str} to this CharArrayWriter. 194 * 195 * @throws NullPointerException 196 * if {@code str} is {@code null}. 197 * @throws StringIndexOutOfBoundsException 198 * if {@code offset < 0} or {@code count < 0}, or if 199 * {@code offset + count} is bigger than the length of 200 * {@code str}. 201 */ 202 @Override 203 public void write(String str, int offset, int count) { 204 if (str == null) { 205 throw new NullPointerException("str == null"); 206 } 207 if ((offset | count) < 0 || offset > str.length() - count) { 208 throw new StringIndexOutOfBoundsException(str, offset, count); 209 } 210 synchronized (lock) { 211 expand(count); 212 str.getChars(offset, offset + count, buf, this.count); 213 this.count += count; 214 } 215 } 216 217 /** 218 * Writes the contents of this {@code CharArrayWriter} to another {@code 219 * Writer}. The output is all the characters that have been written to the 220 * receiver since the last reset or since it was created. 221 * 222 * @param out 223 * the non-null {@code Writer} on which to write the contents. 224 * @throws NullPointerException 225 * if {@code out} is {@code null}. 226 * @throws IOException 227 * if an error occurs attempting to write out the contents. 228 */ 229 public void writeTo(Writer out) throws IOException { 230 synchronized (lock) { 231 out.write(buf, 0, count); 232 } 233 } 234 235 /** 236 * Appends a char {@code c} to the {@code CharArrayWriter}. The method works 237 * the same way as {@code write(c)}. 238 * 239 * @param c 240 * the character appended to the CharArrayWriter. 241 * @return this CharArrayWriter. 242 */ 243 @Override 244 public CharArrayWriter append(char c) { 245 write(c); 246 return this; 247 } 248 249 /** 250 * Appends a {@code CharSequence} to the {@code CharArrayWriter}. The method 251 * works the same way as {@code write(csq.toString())}. If {@code csq} is 252 * {@code null}, then it will be substituted with the string {@code "null"}. 253 * 254 * @param csq 255 * the {@code CharSequence} appended to the {@code 256 * CharArrayWriter}, may be {@code null}. 257 * @return this CharArrayWriter. 258 */ 259 @Override 260 public CharArrayWriter append(CharSequence csq) { 261 if (csq == null) { 262 csq = "null"; 263 } 264 append(csq, 0, csq.length()); 265 return this; 266 } 267 268 /** 269 * Append a subsequence of a {@code CharSequence} to the {@code 270 * CharArrayWriter}. The first and last characters of the subsequence are 271 * specified by the parameters {@code start} and {@code end}. A call to 272 * {@code CharArrayWriter.append(csq)} works the same way as {@code 273 * CharArrayWriter.write(csq.subSequence(start, end).toString)}. If {@code 274 * csq} is {@code null}, then it will be substituted with the string {@code 275 * "null"}. 276 * 277 * @param csq 278 * the {@code CharSequence} appended to the {@code 279 * CharArrayWriter}, may be {@code null}. 280 * @param start 281 * the index of the first character in the {@code CharSequence} 282 * appended to the {@code CharArrayWriter}. 283 * @param end 284 * the index of the character after the last one in the {@code 285 * CharSequence} appended to the {@code CharArrayWriter}. 286 * @return this CharArrayWriter. 287 * @throws IndexOutOfBoundsException 288 * if {@code start < 0}, {@code end < 0}, {@code start > end}, 289 * or if {@code end} is greater than the length of {@code csq}. 290 */ 291 @Override 292 public CharArrayWriter append(CharSequence csq, int start, int end) { 293 if (csq == null) { 294 csq = "null"; 295 } 296 String output = csq.subSequence(start, end).toString(); 297 write(output, 0, output.length()); 298 return this; 299 } 300 } 301