/* * 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 java.io; import java.util.Arrays; /** * A specialized {@link Writer} for class for writing content to an (internal) * char array. As bytes are written to this writer, the char array may be * expanded to hold more characters. When the writing is considered to be * finished, a copy of the char array can be requested from the class. * * @see CharArrayReader */ public class CharArrayWriter extends Writer { /** * The buffer for characters. */ protected char[] buf; /** * The ending index of the buffer. */ protected int count; /** * Constructs a new {@code CharArrayWriter} which has a buffer allocated * with the default size of 32 characters. This buffer is also used as the * {@code lock} to synchronize access to this writer. */ public CharArrayWriter() { buf = new char[32]; lock = buf; } /** * Constructs a new {@code CharArrayWriter} which has a buffer allocated * with the size of {@code initialSize} characters. The buffer is also used * as the {@code lock} to synchronize access to this writer. * * @param initialSize * the initial size of this CharArrayWriters buffer. * @throws IllegalArgumentException * if {@code initialSize < 0}. */ public CharArrayWriter(int initialSize) { if (initialSize < 0) { throw new IllegalArgumentException("size < 0"); } buf = new char[initialSize]; lock = buf; } /** * Closes this writer. The implementation in {@code CharArrayWriter} does nothing. */ @Override public void close() { /* empty */ } private void expand(int i) { /* Can the buffer handle @i more chars, if not expand it */ if (count + i <= buf.length) { return; } int newLen = Math.max(2 * buf.length, count + i); char[] newbuf = new char[newLen]; System.arraycopy(buf, 0, newbuf, 0, count); buf = newbuf; } /** * Flushes this writer. The implementation in {@code CharArrayWriter} does nothing. */ @Override public void flush() { /* empty */ } /** * Resets this writer. The current write position is reset to the beginning * of the buffer. All written characters are lost and the size of this * writer is set to 0. */ public void reset() { synchronized (lock) { count = 0; } } /** * Returns the size of this writer, that is the number of characters it * stores. This number changes if this writer is reset or when more * characters are written to it. * * @return this CharArrayWriter's current size in characters. */ public int size() { synchronized (lock) { return count; } } /** * Returns the contents of the receiver as a char array. The array returned * is a copy and any modifications made to this writer after calling this * method are not reflected in the result. * * @return this CharArrayWriter's contents as a new char array. */ public char[] toCharArray() { synchronized (lock) { char[] result = new char[count]; System.arraycopy(buf, 0, result, 0, count); return result; } } /** * Returns the contents of this {@code CharArrayWriter} as a string. The * string returned is a copy and any modifications made to this writer after * calling this method are not reflected in the result. * * @return this CharArrayWriters contents as a new string. */ @Override public String toString() { synchronized (lock) { return new String(buf, 0, count); } } /** * Writes {@code count} characters starting at {@code offset} in {@code c} * to this writer. * * @param buffer * the non-null array containing characters to write. * @param offset * the index of the first character in {@code buf} to write. * @param len * maximum number of characters to write. * @throws IndexOutOfBoundsException * if {@code offset < 0} or {@code len < 0}, or if * {@code offset + len} is bigger than the size of {@code c}. */ @Override public void write(char[] buffer, int offset, int len) { Arrays.checkOffsetAndCount(buffer.length, offset, len); synchronized (lock) { expand(len); System.arraycopy(buffer, offset, this.buf, this.count, len); this.count += len; } } /** * Writes the specified character {@code oneChar} to this writer. * This implementation writes the two low order bytes of the integer * {@code oneChar} to the buffer. * * @param oneChar * the character to write. */ @Override public void write(int oneChar) { synchronized (lock) { expand(1); buf[count++] = (char) oneChar; } } /** * Writes {@code count} characters starting at {@code offset} from * the string {@code str} to this CharArrayWriter. * * @throws NullPointerException * if {@code str} is {@code null}. * @throws StringIndexOutOfBoundsException * if {@code offset < 0} or {@code count < 0}, or if * {@code offset + count} is bigger than the length of * {@code str}. */ @Override public void write(String str, int offset, int count) { if (str == null) { throw new NullPointerException("str == null"); } if ((offset | count) < 0 || offset > str.length() - count) { throw new StringIndexOutOfBoundsException(str, offset, count); } synchronized (lock) { expand(count); str.getChars(offset, offset + count, buf, this.count); this.count += count; } } /** * Writes the contents of this {@code CharArrayWriter} to another {@code * Writer}. The output is all the characters that have been written to the * receiver since the last reset or since it was created. * * @param out * the non-null {@code Writer} on which to write the contents. * @throws NullPointerException * if {@code out} is {@code null}. * @throws IOException * if an error occurs attempting to write out the contents. */ public void writeTo(Writer out) throws IOException { synchronized (lock) { out.write(buf, 0, count); } } /** * Appends a char {@code c} to the {@code CharArrayWriter}. The method works * the same way as {@code write(c)}. * * @param c * the character appended to the CharArrayWriter. * @return this CharArrayWriter. */ @Override public CharArrayWriter append(char c) { write(c); return this; } /** * Appends a {@code CharSequence} to the {@code CharArrayWriter}. The method * works the same way as {@code write(csq.toString())}. If {@code csq} is * {@code null}, then it will be substituted with the string {@code "null"}. * * @param csq * the {@code CharSequence} appended to the {@code * CharArrayWriter}, may be {@code null}. * @return this CharArrayWriter. */ @Override public CharArrayWriter append(CharSequence csq) { if (csq == null) { csq = "null"; } append(csq, 0, csq.length()); return this; } /** * Append a subsequence of a {@code CharSequence} to the {@code * CharArrayWriter}. The first and last characters of the subsequence are * specified by the parameters {@code start} and {@code end}. A call to * {@code CharArrayWriter.append(csq)} works the same way as {@code * CharArrayWriter.write(csq.subSequence(start, end).toString)}. If {@code * csq} is {@code null}, then it will be substituted with the string {@code * "null"}. * * @param csq * the {@code CharSequence} appended to the {@code * CharArrayWriter}, may be {@code null}. * @param start * the index of the first character in the {@code CharSequence} * appended to the {@code CharArrayWriter}. * @param end * the index of the character after the last one in the {@code * CharSequence} appended to the {@code CharArrayWriter}. * @return this CharArrayWriter. * @throws IndexOutOfBoundsException * if {@code start < 0}, {@code end < 0}, {@code start > end}, * or if {@code end} is greater than the length of {@code csq}. */ @Override public CharArrayWriter append(CharSequence csq, int start, int end) { if (csq == null) { csq = "null"; } String output = csq.subSequence(start, end).toString(); write(output, 0, output.length()); return this; } }