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