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.lang;
19
20import java.io.IOException;
21import java.io.ObjectInputStream;
22import java.io.ObjectOutputStream;
23import java.io.ObjectStreamField;
24import java.io.Serializable;
25
26/**
27 * StringBuffer is a variable size contiguous indexable array of characters. The
28 * length of the StringBuffer is the number of characters it contains. The
29 * capacity of the StringBuffer is the number of characters it can hold.
30 * <p>
31 * Characters may be inserted at any position up to the length of the
32 * StringBuffer, increasing the length of the StringBuffer. Characters at any
33 * position in the StringBuffer may be replaced, which does not affect the
34 * StringBuffer length.
35 * <p>
36 * The capacity of a StringBuffer may be specified when the StringBuffer is
37 * created. If the capacity of the StringBuffer is exceeded, the capacity is
38 * increased.
39 *
40 * @see String
41 * @see StringBuilder
42 * @since Android 1.0
43 */
44public final class StringBuffer extends AbstractStringBuilder implements
45        Appendable, Serializable, CharSequence {
46
47    private static final long serialVersionUID = 3388685877147921107L;
48
49    private static final ObjectStreamField serialPersistentFields[] = {
50            new ObjectStreamField("count", int.class), //$NON-NLS-1$
51            new ObjectStreamField("shared", boolean.class), //$NON-NLS-1$
52            new ObjectStreamField("value", char[].class), }; //$NON-NLS-1$
53
54    /**
55     * Constructs a new StringBuffer using the default capacity which is 16.
56     *
57     * @since Android 1.0
58     */
59    public StringBuffer() {
60        super();
61    }
62
63    /**
64     * Constructs a new StringBuffer using the specified capacity.
65     *
66     * @param capacity
67     *            the initial capacity.
68     * @since Android 1.0
69     */
70    public StringBuffer(int capacity) {
71        super(capacity);
72    }
73
74    /**
75     * Constructs a new StringBuffer containing the characters in the specified
76     * stringy. The capacity of the new buffer will be the length of the
77     * {@code String} plus the default capacity.
78     *
79     * @param string
80     *            the string content with which to initialize the new instance.
81     * @since Android 1.0
82     */
83    public StringBuffer(String string) {
84        super(string);
85    }
86
87    /**
88     * Constructs a StringBuffer and initializes it with the content from the
89     * specified {@code CharSequence}. The capacity of the new buffer will be
90     * the length of the {@code CharSequence} plus the default capacity.
91     *
92     * @param cs
93     *            the content to initialize the instance.
94     * @since Android 1.0
95     */
96    public StringBuffer(CharSequence cs) {
97        super(cs.toString());
98    }
99
100    /**
101     * Adds the string representation of the specified boolean to the end of
102     * this StringBuffer.
103     * <p>
104     * If the argument is {@code true} the string {@code "true"} is appended,
105     * otherwise the string {@code "false"} is appended.
106     * </p>
107     *
108     * @param b
109     *            the boolean to append.
110     * @return this StringBuffer.
111     * @see String#valueOf(boolean)
112     * @since Android 1.0
113     */
114    public StringBuffer append(boolean b) {
115        return append(b ? "true" : "false"); //$NON-NLS-1$//$NON-NLS-2$
116    }
117
118    /**
119     * Adds the specified character to the end of this buffer.
120     *
121     * @param ch
122     *            the character to append.
123     * @return this StringBuffer.
124     * @see String#valueOf(char)
125     * @since Android 1.0
126     */
127    public synchronized StringBuffer append(char ch) {
128        append0(ch);
129        return this;
130    }
131
132    /**
133     * Adds the string representation of the specified double to the end of this
134     * StringBuffer.
135     *
136     * @param d
137     *            the double to append.
138     * @return this StringBuffer.
139     * @see String#valueOf(double)
140     * @since Android 1.0
141     */
142    public StringBuffer append(double d) {
143        return append(Double.toString(d));
144    }
145
146    /**
147     * Adds the string representation of the specified float to the end of this
148     * StringBuffer.
149     *
150     * @param f
151     *            the float to append.
152     * @return this StringBuffer.
153     * @see String#valueOf(float)
154     * @since Android 1.0
155     */
156    public StringBuffer append(float f) {
157        return append(Float.toString(f));
158    }
159
160    /**
161     * Adds the string representation of the specified integer to the end of
162     * this StringBuffer.
163     *
164     * @param i
165     *            the integer to append.
166     * @return this StringBuffer.
167     * @see String#valueOf(int)
168     * @since Android 1.0
169     */
170    public StringBuffer append(int i) {
171        return append(Integer.toString(i));
172    }
173
174    /**
175     * Adds the string representation of the specified long to the end of this
176     * StringBuffer.
177     *
178     * @param l
179     *            the long to append.
180     * @return this StringBuffer.
181     * @see String#valueOf(long)
182     * @since Android 1.0
183     */
184    public StringBuffer append(long l) {
185        return append(Long.toString(l));
186    }
187
188    /**
189     * Adds the string representation of the specified object to the end of this
190     * StringBuffer.
191     * <p>
192     * If the specified object is {@code null} the string {@code "null"} is
193     * appended, otherwise the objects {@code toString} is used to get its
194     * string representation.
195     * </p>
196     *
197     * @param obj
198     *            the object to append (may be null).
199     * @return this StringBuffer.
200     * @see String#valueOf(Object)
201     * @since Android 1.0
202     */
203    public synchronized StringBuffer append(Object obj) {
204        if (obj == null) {
205            appendNull();
206        } else {
207            append0(obj.toString());
208        }
209        return this;
210    }
211
212    /**
213     * Adds the specified string to the end of this buffer.
214     * <p>
215     * If the specified string is {@code null} the string {@code "null"} is
216     * appended, otherwise the contents of the specified string is appended.
217     * </p>
218     *
219     * @param string
220     *            the string to append (may be null).
221     * @return this StringBuffer.
222     * @since Android 1.0
223     */
224    public synchronized StringBuffer append(String string) {
225        append0(string);
226        return this;
227    }
228
229    /**
230     * Adds the specified StringBuffer to the end of this buffer.
231     * <p>
232     * If the specified StringBuffer is {@code null} the string {@code "null"}
233     * is appended, otherwise the contents of the specified StringBuffer is
234     * appended.
235     * </p>
236     *
237     * @param sb
238     *            the StringBuffer to append (may be null).
239     * @return this StringBuffer.
240     * @since Android 1.0
241     */
242    public synchronized StringBuffer append(StringBuffer sb) {
243        if (sb == null) {
244            appendNull();
245        } else {
246            synchronized (sb) {
247                append0(sb.getValue(), 0, sb.length());
248            }
249        }
250        return this;
251    }
252
253    /**
254     * Adds the character array to the end of this buffer.
255     *
256     * @param chars
257     *            the character array to append.
258     * @return this StringBuffer.
259     * @since Android 1.0
260     */
261    public synchronized StringBuffer append(char chars[]) {
262        append0(chars);
263        return this;
264    }
265
266    /**
267     * Adds the specified sequence of characters to the end of this buffer.
268     *
269     * @param chars
270     *            the character array to append.
271     * @param start
272     *            the starting offset.
273     * @param length
274     *            the number of characters.
275     * @return this StringBuffer.
276     * @throws ArrayIndexOutOfBoundsException
277     *             if {@code length < 0} , {@code start < 0} or {@code start +
278     *             length > chars.length}.
279     * @since Android 1.0
280     */
281    public synchronized StringBuffer append(char chars[], int start, int length) {
282        append0(chars, start, length);
283        return this;
284    }
285
286    /**
287     * Appends the specified CharSequence to this buffer.
288     * <p>
289     * If the specified CharSequence is {@code null} the string {@code "null"}
290     * is appended, otherwise the contents of the specified CharSequence is
291     * appended.
292     * </p>
293     *
294     * @param s
295     *            the CharSequence to append.
296     * @return this StringBuffer.
297     * @since Android 1.0
298     */
299    public synchronized StringBuffer append(CharSequence s) {
300        if (s == null) {
301            appendNull();
302        } else {
303            append0(s.toString());
304        }
305        return this;
306    }
307
308    /**
309     * Appends the specified subsequence of the CharSequence to this buffer.
310     * <p>
311     * If the specified CharSequence is {@code null}, then the string {@code
312     * "null"} is used to extract a subsequence.
313     * </p>
314     *
315     * @param s
316     *            the CharSequence to append.
317     * @param start
318     *            the inclusive start index.
319     * @param end
320     *            the exclusive end index.
321     * @return this StringBuffer.
322     * @throws IndexOutOfBoundsException
323     *             if {@code start} or {@code end} are negative, {@code start}
324     *             is greater than {@code end} or {@code end} is greater than
325     *             the length of {@code s}.
326     * @since Android 1.0
327     */
328    public synchronized StringBuffer append(CharSequence s, int start, int end) {
329        append0(s, start, end);
330        return this;
331    }
332
333    /**
334     * Appends the string representation of the specified Unicode code point to
335     * the end of this buffer.
336     * <p>
337     * The code point is converted to a {@code char[]} as defined by
338     * {@link Character#toChars(int)}.
339     * </p>
340     *
341     * @param codePoint
342     *            the Unicode code point to encode and append.
343     * @return this StringBuffer.
344     * @see Character#toChars(int)
345     * @since Android 1.0
346     */
347    public StringBuffer appendCodePoint(int codePoint) {
348        return append(Character.toChars(codePoint));
349    }
350
351    @Override
352    public synchronized char charAt(int index) {
353        return super.charAt(index);
354    }
355
356    @Override
357    public synchronized int codePointAt(int index) {
358        return super.codePointAt(index);
359    }
360
361    @Override
362    public synchronized int codePointBefore(int index) {
363        return super.codePointBefore(index);
364    }
365
366    @Override
367    public synchronized int codePointCount(int beginIndex, int endIndex) {
368        return super.codePointCount(beginIndex, endIndex);
369    }
370
371    /**
372     * Deletes a range of characters.
373     *
374     * @param start
375     *            the offset of the first character.
376     * @param end
377     *            the offset one past the last character.
378     * @return this StringBuffer.
379     * @throws StringIndexOutOfBoundsException
380     *             if {@code start < 0}, {@code start > end} or {@code end >
381     *             length()}.
382     * @since Android 1.0
383     */
384    public synchronized StringBuffer delete(int start, int end) {
385        delete0(start, end);
386        return this;
387    }
388
389    /**
390     * Deletes the character at the specified offset.
391     *
392     * @param location
393     *            the offset of the character to delete.
394     * @return this StringBuffer.
395     * @throws StringIndexOutOfBoundsException
396     *             if {@code location < 0} or {@code location >= length()}
397     * @since Android 1.0
398     */
399    public synchronized StringBuffer deleteCharAt(int location) {
400        deleteCharAt0(location);
401        return this;
402    }
403
404    @Override
405    public synchronized void ensureCapacity(int min) {
406        super.ensureCapacity(min);
407    }
408    /**
409     * Copies the requested sequence of characters to the {@code char[]} passed
410     * starting at {@code idx}.
411     *
412     * @param start
413     *            the starting offset of characters to copy.
414     * @param end
415     *            the ending offset of characters to copy.
416     * @param buffer
417     *            the destination character array.
418     * @param idx
419     *            the starting offset in the character array.
420     * @throws IndexOutOfBoundsException
421     *             if {@code start < 0}, {@code end > length()}, {@code start >
422     *             end}, {@code index < 0}, {@code end - start > buffer.length -
423     *             index}
424     * @since Android 1.0
425     */
426    @Override
427    public synchronized void getChars(int start, int end, char[] buffer, int idx) {
428        super.getChars(start, end, buffer, idx);
429    }
430
431    @Override
432    public synchronized int indexOf(String subString, int start) {
433        return super.indexOf(subString, start);
434    }
435
436    /**
437     * Inserts the character into this buffer at the specified offset.
438     *
439     * @param index
440     *            the index at which to insert.
441     * @param ch
442     *            the character to insert.
443     * @return this buffer.
444     * @throws ArrayIndexOutOfBoundsException
445     *             if {@code index < 0} or {@code index > length()}.
446     * @since Android 1.0
447     */
448    public synchronized StringBuffer insert(int index, char ch) {
449        insert0(index, ch);
450        return this;
451    }
452
453    /**
454     * Inserts the string representation of the specified boolean into this
455     * buffer at the specified offset.
456     *
457     * @param index
458     *            the index at which to insert.
459     * @param b
460     *            the boolean to insert.
461     * @return this buffer.
462     * @throws StringIndexOutOfBoundsException
463     *             if {@code index < 0} or {@code index > length()}.
464     * @since Android 1.0
465     */
466    public StringBuffer insert(int index, boolean b) {
467        return insert(index, b ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
468    }
469
470    /**
471     * Inserts the string representation of the specified integer into this
472     * buffer at the specified offset.
473     *
474     * @param index
475     *            the index at which to insert.
476     * @param i
477     *            the integer to insert.
478     * @return this buffer.
479     * @throws StringIndexOutOfBoundsException
480     *             if {@code index < 0} or {@code index > length()}.
481     * @since Android 1.0
482     */
483    public StringBuffer insert(int index, int i) {
484        return insert(index, Integer.toString(i));
485    }
486
487    /**
488     * Inserts the string representation of the specified long into this buffer
489     * at the specified offset.
490     *
491     * @param index
492     *            the index at which to insert.
493     * @param l
494     *            the long to insert.
495     * @return this buffer.
496     * @throws StringIndexOutOfBoundsException
497     *             if {@code index < 0} or {@code index > length()}.
498     * @since Android 1.0
499     */
500    public StringBuffer insert(int index, long l) {
501        return insert(index, Long.toString(l));
502    }
503
504    /**
505     * Inserts the string representation of the specified into this buffer
506     * double at the specified offset.
507     *
508     * @param index
509     *            the index at which to insert.
510     * @param d
511     *            the double to insert.
512     * @return this buffer.
513     * @throws StringIndexOutOfBoundsException
514     *             if {@code index < 0} or {@code index > length()}.
515     * @since Android 1.0
516     */
517    public StringBuffer insert(int index, double d) {
518        return insert(index, Double.toString(d));
519    }
520
521    /**
522     * Inserts the string representation of the specified float into this buffer
523     * at the specified offset.
524     *
525     * @param index
526     *            the index at which to insert.
527     * @param f
528     *            the float to insert.
529     * @return this buffer.
530     * @throws StringIndexOutOfBoundsException
531     *             if {@code index < 0} or {@code index > length()}.
532     * @since Android 1.0
533     */
534    public StringBuffer insert(int index, float f) {
535        return insert(index, Float.toString(f));
536    }
537
538    /**
539     * Inserts the string representation of the specified object into this
540     * buffer at the specified offset.
541     * <p>
542     * If the specified object is {@code null}, the string {@code "null"} is
543     * inserted, otherwise the objects {@code toString} method is used to get
544     * its string representation.
545     * </p>
546     *
547     * @param index
548     *            the index at which to insert.
549     * @param obj
550     *            the object to insert (may be null).
551     * @return this buffer.
552     * @throws StringIndexOutOfBoundsException
553     *             if {@code index < 0} or {@code index > length()}.
554     * @since Android 1.0
555     */
556    public StringBuffer insert(int index, Object obj) {
557        return insert(index, obj == null ? "null" : obj.toString()); //$NON-NLS-1$
558    }
559
560    /**
561     * Inserts the string into this buffer at the specified offset.
562     * <p>
563     * If the specified string is {@code null}, the string {@code "null"} is
564     * inserted, otherwise the contents of the string is inserted.
565     * </p>
566     *
567     * @param index
568     *            the index at which to insert.
569     * @param string
570     *            the string to insert (may be null).
571     * @return this buffer.
572     * @throws StringIndexOutOfBoundsException
573     *             if {@code index < 0} or {@code index > length()}.
574     * @since Android 1.0
575     */
576    public synchronized StringBuffer insert(int index, String string) {
577        insert0(index, string);
578        return this;
579    }
580
581    /**
582     * Inserts the character array into this buffer at the specified offset.
583     *
584     * @param index
585     *            the index at which to insert.
586     * @param chars
587     *            the character array to insert.
588     * @return this buffer.
589     * @throws StringIndexOutOfBoundsException
590     *             if {@code index < 0} or {@code index > length()}.
591     * @since Android 1.0
592     */
593    public synchronized StringBuffer insert(int index, char[] chars) {
594        insert0(index, chars);
595        return this;
596    }
597
598    /**
599     * Inserts the specified subsequence of characters into this buffer at the
600     * specified index.
601     *
602     * @param index
603     *            the index at which to insert.
604     * @param chars
605     *            the character array to insert.
606     * @param start
607     *            the starting offset.
608     * @param length
609     *            the number of characters.
610     * @return this buffer.
611     * @throws StringIndexOutOfBoundsException
612     *             if {@code length < 0}, {@code start < 0}, {@code start +
613     *             length > chars.length}, {@code index < 0} or {@code index >
614     *             length()}
615     * @since Android 1.0
616     */
617    public synchronized StringBuffer insert(int index, char chars[], int start,
618            int length) {
619        insert0(index, chars, start, length);
620        return this;
621    }
622
623    /**
624     * Inserts the specified CharSequence into this buffer at the specified
625     * index.
626     * <p>
627     * If the specified CharSequence is {@code null}, the string {@code "null"}
628     * is inserted, otherwise the contents of the CharSequence.
629     * </p>
630     *
631     * @param index
632     *            The index at which to insert.
633     * @param s
634     *            The char sequence to insert.
635     * @return this buffer.
636     * @throws IndexOutOfBoundsException
637     *             if {@code index < 0} or {@code index > length()}.
638     * @since Android 1.0
639     */
640    public synchronized StringBuffer insert(int index, CharSequence s) {
641        insert0(index, s == null ? "null" : s.toString()); //$NON-NLS-1$
642        return this;
643    }
644
645    /**
646     * Inserts the specified subsequence into this buffer at the specified
647     * index.
648     * <p>
649     * If the specified CharSequence is {@code null}, the string {@code "null"}
650     * is inserted, otherwise the contents of the CharSequence.
651     * </p>
652     *
653     * @param index
654     *            The index at which to insert.
655     * @param s
656     *            The char sequence to insert.
657     * @param start
658     *            The inclusive start index in the char sequence.
659     * @param end
660     *            The exclusive end index in the char sequence.
661     * @return this buffer.
662     * @throws IndexOutOfBoundsException
663     *             if {@code index} is negative or greater than the current
664     *             length, {@code start} or {@code end} are negative, {@code
665     *             start} is greater than {@code end} or {@code end} is greater
666     *             than the length of {@code s}.
667     * @since Android 1.0
668     */
669    public synchronized StringBuffer insert(int index, CharSequence s,
670            int start, int end) {
671        insert0(index, s, start, end);
672        return this;
673    }
674
675    @Override
676    public synchronized int lastIndexOf(String subString, int start) {
677        return super.lastIndexOf(subString, start);
678    }
679
680    @Override
681    public synchronized int offsetByCodePoints(int index, int codePointOffset) {
682        return super.offsetByCodePoints(index, codePointOffset);
683    }
684
685    /**
686     * Replaces the characters in the specified range with the contents of the
687     * specified string.
688     *
689     * @param start
690     *            the inclusive begin index.
691     * @param end
692     *            the exclusive end index.
693     * @param string
694     *            the string that will replace the contents in the range.
695     * @return this buffer.
696     * @throws StringIndexOutOfBoundsException
697     *             if {@code start} or {@code end} are negative, {@code start}
698     *             is greater than {@code end} or {@code end} is greater than
699     *             the length of {@code s}.
700     * @since Android 1.0
701     */
702    public synchronized StringBuffer replace(int start, int end, String string) {
703        replace0(start, end, string);
704        return this;
705    }
706
707    /**
708     * Reverses the order of characters in this buffer.
709     *
710     * @return this buffer.
711     * @since Android 1.0
712     */
713    public synchronized StringBuffer reverse() {
714        reverse0();
715        return this;
716    }
717
718    @Override
719    public synchronized void setCharAt(int index, char ch) {
720        super.setCharAt(index, ch);
721    }
722
723    @Override
724    public synchronized void setLength(int length) {
725        super.setLength(length);
726    }
727
728    @Override
729    public synchronized CharSequence subSequence(int start, int end) {
730        return super.substring(start, end);
731    }
732
733    @Override
734    public synchronized String substring(int start) {
735        return super.substring(start);
736    }
737
738    @Override
739    public synchronized String substring(int start, int end) {
740        return super.substring(start, end);
741    }
742
743    @Override
744    public synchronized String toString() {
745        return super.toString();
746    }
747
748    @Override
749    public synchronized void trimToSize() {
750        super.trimToSize();
751    }
752
753    private synchronized void writeObject(ObjectOutputStream out)
754            throws IOException {
755        ObjectOutputStream.PutField fields = out.putFields();
756        fields.put("count", length()); //$NON-NLS-1$
757        fields.put("shared", false); //$NON-NLS-1$
758        fields.put("value", getValue()); //$NON-NLS-1$
759        out.writeFields();
760    }
761
762    private void readObject(ObjectInputStream in) throws IOException,
763            ClassNotFoundException {
764        ObjectInputStream.GetField fields = in.readFields();
765        int count = fields.get("count", 0); //$NON-NLS-1$
766        char[] value = (char[]) fields.get("value", null); //$NON-NLS-1$
767        set(value, count);
768    }
769}
770