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 18package java.io; 19 20// BEGIN android-added 21import org.apache.harmony.luni.util.Msg; 22// ENd android-added 23 24/** 25 * A specialized {@link Writer} that writes characters to a {@code StringBuffer} 26 * in a sequential manner, appending them in the process. The result can later 27 * be queried using the {@link #StringWriter(int)} or {@link #toString()} 28 * methods. 29 * 30 * @see StringReader 31 */ 32public class StringWriter extends Writer { 33 34 private StringBuffer buf; 35 36 /** 37 * Constructs a new {@code StringWriter} which has a {@link StringBuffer} 38 * allocated with the default size of 16 characters. The {@code 39 * StringBuffer} is also the {@code lock} used to synchronize access to this 40 * writer. 41 */ 42 public StringWriter() { 43 super(); 44 buf = new StringBuffer(16); 45 lock = buf; 46 } 47 48 /** 49 * Constructs a new {@code StringWriter} which has a {@link StringBuffer} 50 * allocated with a size of {@code initialSize} characters. The {@code 51 * StringBuffer} is also the {@code lock} used to synchronize access to this 52 * writer. 53 * 54 * @param initialSize 55 * the intial size of the target string buffer. 56 */ 57 public StringWriter(int initialSize) { 58 if (initialSize < 0) { 59 throw new IllegalArgumentException(); 60 } 61 buf = new StringBuffer(initialSize); 62 lock = buf; 63 } 64 65 /** 66 * Calling this method has no effect. In contrast to most {@code Writer} subclasses, 67 * the other methods in {@code StringWriter} do not throw an {@code IOException} if 68 * {@code close()} has been called. 69 * 70 * @throws IOException 71 * if an error occurs while closing this writer. 72 */ 73 @Override 74 public void close() throws IOException { 75 /* empty */ 76 } 77 78 /** 79 * Calling this method has no effect. 80 */ 81 @Override 82 public void flush() { 83 /* empty */ 84 } 85 86 /** 87 * Gets a reference to this writer's internal {@link StringBuffer}. Any 88 * changes made to the returned buffer are reflected in this writer. 89 * 90 * @return a reference to this writer's internal {@code StringBuffer}. 91 */ 92 public StringBuffer getBuffer() { 93 return buf; 94 } 95 96 /** 97 * Gets a copy of the contents of this writer as a string. 98 * 99 * @return this writer's contents as a string. 100 */ 101 @Override 102 public String toString() { 103 return buf.toString(); 104 } 105 106 /** 107 * Writes {@code count} characters starting at {@code offset} in {@code buf} 108 * to this writer's {@code StringBuffer}. 109 * 110 * @param cbuf 111 * the non-null character array to write. 112 * @param offset 113 * the index of the first character in {@code cbuf} to write. 114 * @param count 115 * the maximum number of characters to write. 116 * @throws IndexOutOfBoundsException 117 * if {@code offset < 0} or {@code count < 0}, or if {@code 118 * offset + count} is greater than the size of {@code buf}. 119 */ 120 @Override 121 public void write(char[] cbuf, int offset, int count) { 122 // avoid int overflow 123 // BEGIN android-changed 124 // Exception priorities (in case of multiple errors) differ from 125 // RI, but are spec-compliant. 126 // removed redundant check, added null check, used (offset | count) < 0 127 // instead of (offset < 0) || (count < 0) to safe one operation 128 if (cbuf == null) { 129 throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$ 130 } 131 if ((offset | count) < 0 || count > cbuf.length - offset) { 132 throw new IndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$ 133 } 134 // END android-changed 135 if (count == 0) { 136 return; 137 } 138 buf.append(cbuf, offset, count); 139 } 140 141 /** 142 * Writes one character to this writer's {@code StringBuffer}. Only the two 143 * least significant bytes of the integer {@code oneChar} are written. 144 * 145 * @param oneChar 146 * the character to write to this writer's {@code StringBuffer}. 147 */ 148 @Override 149 public void write(int oneChar) { 150 buf.append((char) oneChar); 151 } 152 153 /** 154 * Writes the characters from the specified string to this writer's {@code 155 * StringBuffer}. 156 * 157 * @param str 158 * the non-null string containing the characters to write. 159 */ 160 @Override 161 public void write(String str) { 162 buf.append(str); 163 } 164 165 /** 166 * Writes {@code count} characters from {@code str} starting at {@code 167 * offset} to this writer's {@code StringBuffer}. 168 * 169 * @param str 170 * the non-null string containing the characters to write. 171 * @param offset 172 * the index of the first character in {@code str} to write. 173 * @param count 174 * the number of characters from {@code str} to write. 175 * @throws StringIndexOutOfBoundsException 176 * if {@code offset < 0} or {@code count < 0}, or if {@code 177 * offset + count} is greater than the length of {@code str}. 178 */ 179 @Override 180 public void write(String str, int offset, int count) { 181 String sub = str.substring(offset, offset + count); 182 buf.append(sub); 183 } 184 185 /** 186 * Appends the character {@code c} to this writer's {@code StringBuffer}. 187 * This method works the same way as {@link #write(int)}. 188 * 189 * @param c 190 * the character to append to the target stream. 191 * @return this writer. 192 */ 193 @Override 194 public StringWriter append(char c) { 195 write(c); 196 return this; 197 } 198 199 /** 200 * Appends the character sequence {@code csq} to this writer's {@code 201 * StringBuffer}. This method works the same way as {@code 202 * StringWriter.write(csq.toString())}. If {@code csq} is {@code null}, then 203 * the string "null" is written to the target stream. 204 * 205 * @param csq 206 * the character sequence appended to the target. 207 * @return this writer. 208 */ 209 @Override 210 public StringWriter append(CharSequence csq) { 211 if (null == csq) { 212 write(TOKEN_NULL); 213 } else { 214 write(csq.toString()); 215 } 216 return this; 217 } 218 219 /** 220 * Appends a subsequence of the character sequence {@code csq} to this 221 * writer's {@code StringBuffer}. This method works the same way as {@code 222 * StringWriter.writer(csq.subsequence(start, end).toString())}. If {@code 223 * csq} is {@code null}, then the specified subsequence of the string "null" 224 * will be written to the target. 225 * 226 * @param csq 227 * the character sequence appended to the target. 228 * @param start 229 * the index of the first char in the character sequence appended 230 * to the target. 231 * @param end 232 * the index of the character following the last character of the 233 * subsequence appended to the target. 234 * @return this writer. 235 * @throws IndexOutOfBoundsException 236 * if {@code start > end}, {@code start < 0}, {@code end < 0} or 237 * either {@code start} or {@code end} are greater or equal than 238 * the length of {@code csq}. 239 */ 240 @Override 241 public StringWriter append(CharSequence csq, int start, int end) { 242 if (null == csq) { 243 csq = TOKEN_NULL; 244 } 245 String output = csq.subSequence(start, end).toString(); 246 write(output, 0, output.length()); 247 return this; 248 } 249} 250