001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.util.string;
018
019import java.io.IOException;
020
021/**
022 * This is a copy or combination of <code>java.lang.StringBuffer</code> and
023 * <code>java.lang.String</code> It has a special method getValue() which returns the internal char
024 * array.
025 * 
026 * Hashcode and equals methods are also implemented.
027 * 
028 * This AppendingStringBuffer is not synchronized.
029 * 
030 * @author Johan Compagner
031 * @see java.lang.StringBuffer
032 */
033public final class AppendingStringBuffer implements java.io.Serializable, CharSequence
034{
035        /** use serialVersionUID from JDK 1.0.2 for interoperability */
036        private static final long serialVersionUID = 1L;
037
038        private static final AppendingStringBuffer NULL = new AppendingStringBuffer("null");
039        private static final StringBuilder SB_NULL = new StringBuilder("null");
040        private static final StringBuffer SBF_NULL = new StringBuffer("null");
041
042        /**
043         * The value is used for character storage.
044         * 
045         * @serial
046         */
047        private char value[];
048
049        /**
050         * The count is the number of characters in the buffer.
051         * 
052         * @serial
053         */
054        private int count;
055
056        /**
057         * Constructs a string buffer with no characters in it and an initial capacity of 16 characters.
058         */
059        public AppendingStringBuffer()
060        {
061                this(16);
062        }
063
064        /**
065         * Constructs a string buffer with no characters in it and an initial capacity specified by the
066         * <code>length</code> argument.
067         * 
068         * @param length
069         *            the initial capacity.
070         * @exception NegativeArraySizeException
071         *                if the <code>length</code> argument is less than <code>0</code>.
072         */
073        public AppendingStringBuffer(final int length)
074        {
075                value = new char[length];
076        }
077
078        /**
079         * Constructs a string buffer so that it represents the same sequence of characters as the
080         * string argument; in other words, the initial contents of the string buffer is a copy of the
081         * argument string. The initial capacity of the string buffer is <code>16</code> plus the length
082         * of the string argument.
083         * 
084         * @param str
085         *            the initial contents of the buffer.
086         * @exception NullPointerException
087         *                if <code>str</code> is <code>null</code>
088         */
089        public AppendingStringBuffer(final CharSequence str)
090        {
091                this(str.length() + 16);
092                append(str);
093        }
094
095        /**
096         * Returns the length (character count) of this string buffer.
097         * 
098         * @return the length of the sequence of characters currently represented by this string buffer.
099         */
100        @Override
101        public int length()
102        {
103                return count;
104        }
105
106        /**
107         * Returns the current capacity of the String buffer. The capacity is the amount of storage
108         * available for newly inserted characters; beyond which an allocation will occur.
109         * 
110         * @return the current capacity of this string buffer.
111         */
112        public int capacity()
113        {
114                return value.length;
115        }
116
117        /**
118         * Ensures that the capacity of the buffer is at least equal to the specified minimum. If the
119         * current capacity of this string buffer is less than the argument, then a new internal buffer
120         * is allocated with greater capacity. The new capacity is the larger of:
121         * <ul>
122         * <li>The <code>minimumCapacity</code> argument.
123         * <li>Twice the old capacity, plus <code>2</code>.
124         * </ul>
125         * If the <code>minimumCapacity</code> argument is nonpositive, this method takes no action and
126         * simply returns.
127         * 
128         * @param minimumCapacity
129         *            the minimum desired capacity.
130         */
131        public void ensureCapacity(final int minimumCapacity)
132        {
133                if (minimumCapacity > value.length)
134                {
135                        expandCapacity(minimumCapacity);
136                }
137        }
138
139        /**
140         * This implements the expansion semantics of ensureCapacity but is unsynchronized for use
141         * internally by methods which are already synchronized.
142         * 
143         * @param minimumCapacity
144         * 
145         * @see java.lang.StringBuffer#ensureCapacity(int)
146         */
147        private void expandCapacity(final int minimumCapacity)
148        {
149                int newCapacity = (value.length + 1) * 2;
150                if (newCapacity < 0)
151                {
152                        newCapacity = Integer.MAX_VALUE;
153                }
154                else if (minimumCapacity > newCapacity)
155                {
156                        newCapacity = minimumCapacity;
157                }
158
159                char newValue[] = new char[newCapacity];
160                System.arraycopy(value, 0, newValue, 0, count);
161                value = newValue;
162        }
163
164        /**
165         * Sets the length of this String buffer. This string buffer is altered to represent a new
166         * character sequence whose length is specified by the argument. For every nonnegative index
167         * <i>k</i> less than <code>newLength</code>, the character at index <i>k</i> in the new
168         * character sequence is the same as the character at index <i>k</i> in the old sequence if
169         * <i>k</i> is less than the length of the old character sequence; otherwise, it is the null
170         * character <code>'&#92;u0000'</code>.
171         * 
172         * In other words, if the <code>newLength</code> argument is less than the current length of the
173         * string buffer, the string buffer is truncated to contain exactly the number of characters
174         * given by the <code>newLength</code> argument.
175         * <p>
176         * If the <code>newLength</code> argument is greater than or equal to the current length,
177         * sufficient null characters (<code>'&#92;u0000'</code>) are appended to the string buffer so
178         * that length becomes the <code>newLength</code> argument.
179         * <p>
180         * The <code>newLength</code> argument must be greater than or equal to <code>0</code>.
181         * 
182         * @param newLength
183         *            the new length of the buffer.
184         * @exception IndexOutOfBoundsException
185         *                if the <code>newLength</code> argument is negative.
186         * @see java.lang.StringBuffer#length()
187         */
188        public void setLength(final int newLength)
189        {
190                if (newLength < 0)
191                {
192                        throw new StringIndexOutOfBoundsException(newLength);
193                }
194
195                if (newLength > value.length)
196                {
197                        expandCapacity(newLength);
198                }
199
200                if (count < newLength)
201                {
202                        for (; count < newLength; count++)
203                        {
204                                value[count] = '\0';
205                        }
206                }
207                else
208                {
209                        count = newLength;
210                }
211        }
212
213        /**
214         * The specified character of the sequence currently represented by the string buffer, as
215         * indicated by the <code>index</code> argument, is returned. The first character of a string
216         * buffer is at index <code>0</code>, the next at index <code>1</code>, and so on, for array
217         * indexing.
218         * <p>
219         * The index argument must be greater than or equal to <code>0</code>, and less than the length
220         * of this string buffer.
221         * 
222         * @param index
223         *            the index of the desired character.
224         * @return the character at the specified index of this string buffer.
225         * @exception IndexOutOfBoundsException
226         *                if <code>index</code> is negative or greater than or equal to
227         *                <code>length()</code>.
228         * @see java.lang.StringBuffer#length()
229         */
230        @Override
231        public char charAt(final int index)
232        {
233                if ((index < 0) || (index >= count))
234                {
235                        throw new StringIndexOutOfBoundsException(index);
236                }
237                return value[index];
238        }
239
240        /**
241         * Characters are copied from this string buffer into the destination character array
242         * <code>dst</code>. The first character to be copied is at index <code>srcBegin</code>; the
243         * last character to be copied is at index <code>srcEnd-1</code>. The total number of characters
244         * to be copied is <code>srcEnd-srcBegin</code>. The characters are copied into the subarray of
245         * <code>dst</code> starting at index <code>dstBegin</code> and ending at index:
246         * <p>
247         * <blockquote>
248         * 
249         * <pre>
250         * dstbegin + (srcEnd - srcBegin) - 1
251         * </pre>
252         * 
253         * </blockquote>
254         * 
255         * @param srcBegin
256         *            start copying at this offset in the string buffer.
257         * @param srcEnd
258         *            stop copying at this offset in the string buffer.
259         * @param dst
260         *            the array to copy the data into.
261         * @param dstBegin
262         *            offset into <code>dst</code>.
263         * @exception NullPointerException
264         *                if <code>dst</code> is <code>null</code>.
265         * @exception IndexOutOfBoundsException
266         *                if any of the following is true:
267         *                <ul>
268         *                <li><code>srcBegin</code> is negative <li><code>dstBegin</code> is negative
269         *                <li>the <code>srcBegin</code> argument is greater than the <code>srcEnd</code>
270         *                argument. <li><code>srcEnd</code> is greater than <code>this.length()</code>,
271         *                the current length of this string buffer. <li><code>dstBegin+srcEnd-srcBegin
272         *                </code> is greater than <code>dst.length</code>
273         *                </ul>
274         */
275        public void getChars(final int srcBegin, final int srcEnd, final char dst[], final int dstBegin)
276        {
277                if (srcBegin < 0)
278                {
279                        throw new StringIndexOutOfBoundsException(srcBegin);
280                }
281                if ((srcEnd < 0) || (srcEnd > count))
282                {
283                        throw new StringIndexOutOfBoundsException(srcEnd);
284                }
285                if (srcBegin > srcEnd)
286                {
287                        throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
288                }
289                System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
290        }
291
292        /**
293         * The character at the specified index of this string buffer is set to <code>ch</code>. The
294         * string buffer is altered to represent a new character sequence that is identical to the old
295         * character sequence, except that it contains the character <code>ch</code> at position
296         * <code>index</code>.
297         * <p>
298         * The index argument must be greater than or equal to <code>0</code>, and less than the length
299         * of this string buffer.
300         * 
301         * @param index
302         *            the index of the character to modify.
303         * @param ch
304         *            the new character.
305         * @exception IndexOutOfBoundsException
306         *                if <code>index</code> is negative or greater than or equal to
307         *                <code>length()</code>.
308         * @see java.lang.StringBuffer#length()
309         */
310        public void setCharAt(final int index, final char ch)
311        {
312                if ((index < 0) || (index >= count))
313                {
314                        throw new StringIndexOutOfBoundsException(index);
315                }
316                value[index] = ch;
317        }
318
319        /**
320         * Appends the string representation of the <code>Object</code> argument to this string buffer.
321         * <p>
322         * The argument is converted to a string as if by the method <code>String.valueOf</code>, and
323         * the characters of that string are then appended to this string buffer.
324         * 
325         * @param obj
326         *            an <code>Object</code>.
327         * @return a reference to this <code>AppendingStringBuffer</code> object.
328         * @see java.lang.String#valueOf(java.lang.Object)
329         * @see java.lang.StringBuffer#append(java.lang.String)
330         */
331        public AppendingStringBuffer append(final Object obj)
332        {
333                if (obj instanceof AppendingStringBuffer)
334                {
335                        return append((AppendingStringBuffer)obj);
336                }
337                else if (obj instanceof StringBuilder)
338                {
339                        return append((StringBuilder)obj);
340                }
341                else if (obj instanceof StringBuffer)
342                {
343                        return append(obj.toString());
344                }
345                return append(String.valueOf(obj));
346        }
347
348        /**
349         * Appends the string to this string buffer.
350         * <p>
351         * The characters of the <code>String</code> argument are appended, in order, to the contents of
352         * this string buffer, increasing the length of this string buffer by the length of the
353         * argument. If <code>str</code> is <code>null</code>, then the four characters
354         * <code>"null"</code> are appended to this string buffer.
355         * <p>
356         * Let <i>n</i> be the length of the old character sequence, the one contained in the string
357         * buffer just prior to execution of the <code>append</code> method. Then the character at index
358         * <i>k</i> in the new character sequence is equal to the character at index <i>k</i> in the old
359         * character sequence, if <i>k</i> is less than <i>n</i>; otherwise, it is equal to the
360         * character at index <i>k-n</i> in the argument <code>str</code>.
361         * 
362         * @param str
363         *            a string.
364         * @return a reference to this <code>AppendingStringBuffer</code>.
365         */
366        public AppendingStringBuffer append(String str)
367        {
368                if (str == null)
369                {
370                        str = String.valueOf(str);
371                }
372
373                int len = str.length();
374                int newcount = count + len;
375                if (newcount > value.length)
376                {
377                        expandCapacity(newcount);
378                }
379                str.getChars(0, len, value, count);
380                count = newcount;
381                return this;
382        }
383
384        /**
385         * Appends the specified <tt>AppendingStringBuffer</tt> to this <tt>AppendingStringBuffer</tt>.
386         * <p>
387         * The characters of the <tt>AppendingStringBuffer</tt> argument are appended, in order, to the
388         * contents of this <tt>AppendingStringBuffer</tt>, increasing the length of this
389         * <tt>AppendingStringBuffer</tt> by the length of the argument. If <tt>sb</tt> is <tt>null</tt>
390         * , then the four characters <tt>"null"</tt> are appended to this
391         * <tt>AppendingStringBuffer</tt>.
392         * <p>
393         * Let <i>n</i> be the length of the old character sequence, the one contained in the
394         * <tt>AppendingStringBuffer</tt> just prior to execution of the <tt>append</tt> method. Then
395         * the character at index <i>k</i> in the new character sequence is equal to the character at
396         * index <i>k</i> in the old character sequence, if <i>k</i> is less than <i>n</i>; otherwise,
397         * it is equal to the character at index <i>k-n</i> in the argument <code>sb</code>.
398         * <p>
399         * The method <tt>ensureCapacity</tt> is first called on this <tt>AppendingStringBuffer</tt>
400         * with the new buffer length as its argument. (This ensures that the storage of this
401         * <tt>AppendingStringBuffer</tt> is adequate to contain the additional characters being
402         * appended.)
403         * 
404         * @param sb
405         *            the <tt>AppendingStringBuffer</tt> to append.
406         * @return a reference to this <tt>AppendingStringBuffer</tt>.
407         * @since 1.4
408         */
409        public AppendingStringBuffer append(AppendingStringBuffer sb)
410        {
411                if (sb == null)
412                {
413                        sb = NULL;
414                }
415
416                int len = sb.length();
417                int newcount = count + len;
418                if (newcount > value.length)
419                {
420                        expandCapacity(newcount);
421                }
422                sb.getChars(0, len, value, count);
423                count = newcount;
424                return this;
425        }
426
427        /**
428         * Appends the specified <tt>AppendingStringBuffer</tt> to this <tt>AppendingStringBuffer</tt>.
429         * <p>
430         * The characters of the <tt>AppendingStringBuffer</tt> argument are appended, in order, to the
431         * contents of this <tt>AppendingStringBuffer</tt>, increasing the length of this
432         * <tt>AppendingStringBuffer</tt> by the length of the argument. If <tt>sb</tt> is <tt>null</tt>
433         * , then the four characters <tt>"null"</tt> are appended to this
434         * <tt>AppendingStringBuffer</tt>.
435         * <p>
436         * Let <i>n</i> be the length of the old character sequence, the one contained in the
437         * <tt>AppendingStringBuffer</tt> just prior to execution of the <tt>append</tt> method. Then
438         * the character at index <i>k</i> in the new character sequence is equal to the character at
439         * index <i>k</i> in the old character sequence, if <i>k</i> is less than <i>n</i>; otherwise,
440         * it is equal to the character at index <i>k-n</i> in the argument <code>sb</code>.
441         * <p>
442         * The method <tt>ensureCapacity</tt> is first called on this <tt>AppendingStringBuffer</tt>
443         * with the new buffer length as its argument. (This ensures that the storage of this
444         * <tt>AppendingStringBuffer</tt> is adequate to contain the additional characters being
445         * appended.)
446         * 
447         * @param sb
448         *            the <tt>AppendingStringBuffer</tt> to append.
449         * @return a reference to this <tt>AppendingStringBuffer</tt>.
450         * @since 1.4
451         */
452        public AppendingStringBuffer append(StringBuilder sb)
453        {
454                if (sb == null)
455                {
456                        sb = SB_NULL;
457                }
458
459                int len = sb.length();
460                int newcount = count + len;
461                if (newcount > value.length)
462                {
463                        expandCapacity(newcount);
464                }
465                sb.getChars(0, len, value, count);
466                count = newcount;
467                return this;
468        }
469
470        /**
471         * Appends the string representation of the <code>char</code> array argument to this string
472         * buffer.
473         * <p>
474         * The characters of the array argument are appended, in order, to the contents of this string
475         * buffer. The length of this string buffer increases by the length of the argument.
476         * <p>
477         * The overall effect is exactly as if the argument were converted to a string by the method
478         * {@link String#valueOf(char[])} and the characters of that string were then
479         * {@link #append(String) appended} to this <code>AppendingStringBuffer</code> object.
480         * 
481         * @param str
482         *            the characters to be appended.
483         * @return a reference to this <code>AppendingStringBuffer</code> object.
484         */
485        public AppendingStringBuffer append(final char str[])
486        {
487                int len = str.length;
488                int newcount = count + len;
489                if (newcount > value.length)
490                {
491                        expandCapacity(newcount);
492                }
493                System.arraycopy(str, 0, value, count, len);
494                count = newcount;
495                return this;
496        }
497
498        /**
499         * Appends the string representation of a subarray of the <code>char</code> array argument to
500         * this string buffer.
501         * <p>
502         * Characters of the character array <code>str</code>, starting at index <code>offset</code>,
503         * are appended, in order, to the contents of this string buffer. The length of this string
504         * buffer increases by the value of <code>len</code>.
505         * <p>
506         * The overall effect is exactly as if the arguments were converted to a string by the method
507         * {@link String#valueOf(char[],int,int)} and the characters of that string were then
508         * {@link #append(String) appended} to this <code>AppendingStringBuffer</code> object.
509         * 
510         * @param str
511         *            the characters to be appended.
512         * @param offset
513         *            the index of the first character to append.
514         * @param len
515         *            the number of characters to append.
516         * @return a reference to this <code>AppendingStringBuffer</code> object.
517         */
518        public AppendingStringBuffer append(final char str[], final int offset, final int len)
519        {
520                int newcount = count + len;
521                if (newcount > value.length)
522                {
523                        expandCapacity(newcount);
524                }
525                System.arraycopy(str, offset, value, count, len);
526                count = newcount;
527                return this;
528        }
529
530        /**
531         * Appends the string representation of the <code>boolean</code> argument to the string buffer.
532         * <p>
533         * The argument is converted to a string as if by the method <code>String.valueOf</code>, and
534         * the characters of that string are then appended to this string buffer.
535         * 
536         * @param b
537         *            a <code>boolean</code>.
538         * @return a reference to this <code>AppendingStringBuffer</code>.
539         * @see java.lang.String#valueOf(boolean)
540         * @see java.lang.StringBuffer#append(java.lang.String)
541         */
542        public AppendingStringBuffer append(final boolean b)
543        {
544                if (b)
545                {
546                        int newcount = count + 4;
547                        if (newcount > value.length)
548                        {
549                                expandCapacity(newcount);
550                        }
551                        value[count++] = 't';
552                        value[count++] = 'r';
553                        value[count++] = 'u';
554                        value[count++] = 'e';
555                }
556                else
557                {
558                        int newcount = count + 5;
559                        if (newcount > value.length)
560                        {
561                                expandCapacity(newcount);
562                        }
563                        value[count++] = 'f';
564                        value[count++] = 'a';
565                        value[count++] = 'l';
566                        value[count++] = 's';
567                        value[count++] = 'e';
568                }
569                return this;
570        }
571
572        /**
573         * Appends the string representation of the <code>char</code> argument to this string buffer.
574         * <p>
575         * The argument is appended to the contents of this string buffer. The length of this string
576         * buffer increases by <code>1</code>.
577         * <p>
578         * The overall effect is exactly as if the argument were converted to a string by the method
579         * {@link String#valueOf(char)} and the character in that string were then
580         * {@link #append(String) appended} to this <code>AppendingStringBuffer</code> object.
581         * 
582         * @param c
583         *            a <code>char</code>.
584         * @return a reference to this <code>AppendingStringBuffer</code> object.
585         */
586        public AppendingStringBuffer append(final char c)
587        {
588                int newcount = count + 1;
589                if (newcount > value.length)
590                {
591                        expandCapacity(newcount);
592                }
593                value[count++] = c;
594                return this;
595        }
596
597        /**
598         * Appends the string representation of the <code>int</code> argument to this string buffer.
599         * <p>
600         * The argument is converted to a string as if by the method <code>String.valueOf</code>, and
601         * the characters of that string are then appended to this string buffer.
602         * 
603         * @param i
604         *            an <code>int</code>.
605         * @return a reference to this <code>AppendingStringBuffer</code> object.
606         * @see java.lang.String#valueOf(int)
607         * @see java.lang.StringBuffer#append(java.lang.String)
608         */
609        public AppendingStringBuffer append(final int i)
610        {
611                return append(String.valueOf(i));
612        }
613
614        /**
615         * Appends the string representation of the <code>long</code> argument to this string buffer.
616         * <p>
617         * The argument is converted to a string as if by the method <code>String.valueOf</code>, and
618         * the characters of that string are then appended to this string buffer.
619         * 
620         * @param l
621         *            a <code>long</code>.
622         * @return a reference to this <code>AppendingStringBuffer</code> object.
623         * @see java.lang.String#valueOf(long)
624         * @see java.lang.StringBuffer#append(java.lang.String)
625         */
626        public AppendingStringBuffer append(final long l)
627        {
628                return append(String.valueOf(l));
629        }
630
631        /**
632         * Appends the string representation of the <code>float</code> argument to this string buffer.
633         * <p>
634         * The argument is converted to a string as if by the method <code>String.valueOf</code>, and
635         * the characters of that string are then appended to this string buffer.
636         * 
637         * @param f
638         *            a <code>float</code>.
639         * @return a reference to this <code>AppendingStringBuffer</code> object.
640         * @see java.lang.String#valueOf(float)
641         * @see java.lang.StringBuffer#append(java.lang.String)
642         */
643        public AppendingStringBuffer append(final float f)
644        {
645                return append(String.valueOf(f));
646        }
647
648        /**
649         * Appends the string representation of the <code>double</code> argument to this string buffer.
650         * <p>
651         * The argument is converted to a string as if by the method <code>String.valueOf</code>, and
652         * the characters of that string are then appended to this string buffer.
653         * 
654         * @param d
655         *            a <code>double</code>.
656         * @return a reference to this <code>AppendingStringBuffer</code> object.
657         * @see java.lang.String#valueOf(double)
658         * @see java.lang.StringBuffer#append(java.lang.String)
659         */
660        public AppendingStringBuffer append(final double d)
661        {
662                return append(String.valueOf(d));
663        }
664
665        /**
666         * Removes the characters in a substring of this <code>AppendingStringBuffer</code>. The
667         * substring begins at the specified <code>start</code> and extends to the character at index
668         * <code>end - 1</code> or to the end of the <code>AppendingStringBuffer</code> if no such
669         * character exists. If <code>start</code> is equal to <code>end</code>, no changes are made.
670         * 
671         * @param start
672         *            The beginning index, inclusive.
673         * @param end
674         *            The ending index, exclusive.
675         * @return This string buffer.
676         * @exception StringIndexOutOfBoundsException
677         *                if <code>start</code> is negative, greater than <code>length()</code>, or
678         *                greater than <code>end</code>.
679         * @since 1.2
680         */
681        public AppendingStringBuffer delete(final int start, int end)
682        {
683                if (start < 0)
684                {
685                        throw new StringIndexOutOfBoundsException(start);
686                }
687                if (end > count)
688                {
689                        end = count;
690                }
691                if (start > end)
692                {
693                        throw new StringIndexOutOfBoundsException();
694                }
695
696                int len = end - start;
697                if (len > 0)
698                {
699                        System.arraycopy(value, start + len, value, start, count - end);
700                        count -= len;
701                }
702                return this;
703        }
704
705        /**
706         * Removes the character at the specified position in this <code>AppendingStringBuffer</code>
707         * (shortening the <code>AppendingStringBuffer</code> by one character).
708         * 
709         * @param index
710         *            Index of character to remove
711         * @return This string buffer.
712         * @exception StringIndexOutOfBoundsException
713         *                if the <code>index</code> is negative or greater than or equal to
714         *                <code>length()</code>.
715         * @since 1.2
716         */
717        public AppendingStringBuffer deleteCharAt(final int index)
718        {
719                if ((index < 0) || (index >= count))
720                {
721                        throw new StringIndexOutOfBoundsException();
722                }
723                System.arraycopy(value, index + 1, value, index, count - index - 1);
724                count--;
725                return this;
726        }
727
728        /**
729         * Replaces the characters in a substring of this <code>AppendingStringBuffer</code> with
730         * characters in the specified <code>String</code>. The substring begins at the specified
731         * <code>start</code> and extends to the character at index <code>end - 1</code> or to the end
732         * of the <code>AppendingStringBuffer</code> if no such character exists. First the characters
733         * in the substring are removed and then the specified <code>String</code> is inserted at
734         * <code>start</code>. (The <code>AppendingStringBuffer</code> will be lengthened to accommodate
735         * the specified String if necessary.)
736         * 
737         * @param start
738         *            The beginning index, inclusive.
739         * @param end
740         *            The ending index, exclusive.
741         * @param str
742         *            String that will replace previous contents.
743         * @return This string buffer.
744         * @exception StringIndexOutOfBoundsException
745         *                if <code>start</code> is negative, greater than <code>length()</code>, or
746         *                greater than <code>end</code>.
747         * @since 1.2
748         */
749        public AppendingStringBuffer replace(final int start, int end, final String str)
750        {
751                if (start < 0)
752                {
753                        throw new StringIndexOutOfBoundsException(start);
754                }
755                if (end > count)
756                {
757                        end = count;
758                }
759                if (start > end)
760                {
761                        throw new StringIndexOutOfBoundsException();
762                }
763
764                int len = str.length();
765                int newCount = count + len - (end - start);
766                if (newCount > value.length)
767                {
768                        expandCapacity(newCount);
769                }
770
771                System.arraycopy(value, end, value, start + len, count - end);
772                str.getChars(0, len, value, start);
773                count = newCount;
774                return this;
775        }
776
777        /**
778         * Returns a new <code>String</code> that contains a subsequence of characters currently
779         * contained in this <code>AppendingStringBuffer</code>.The substring begins at the specified
780         * index and extends to the end of the <code>AppendingStringBuffer</code>.
781         * 
782         * @param start
783         *            The beginning index, inclusive.
784         * @return The new string.
785         * @exception StringIndexOutOfBoundsException
786         *                if <code>start</code> is less than zero, or greater than the length of this
787         *                <code>AppendingStringBuffer</code>.
788         * @since 1.2
789         */
790        public String substring(final int start)
791        {
792                return substring(start, count);
793        }
794
795        /**
796         * Returns a new character sequence that is a subsequence of this sequence.
797         * 
798         * <p>
799         * An invocation of this method of the form
800         * 
801         * <blockquote>
802         * 
803         * <pre>
804         * sb.subSequence(begin, end)
805         * </pre>
806         * 
807         * </blockquote>
808         * 
809         * behaves in exactly the same way as the invocation
810         * 
811         * <blockquote>
812         * 
813         * <pre>
814         * sb.substring(begin, end)
815         * </pre>
816         * 
817         * </blockquote>
818         * 
819         * This method is provided so that the <tt>AppendingStringBuffer</tt> class can implement the
820         * {@link CharSequence} interface.
821         * </p>
822         * 
823         * @param start
824         *            the start index, inclusive.
825         * @param end
826         *            the end index, exclusive.
827         * @return the specified subsequence.
828         * 
829         * @throws IndexOutOfBoundsException
830         *             if <tt>start</tt> or <tt>end</tt> are negative, if <tt>end</tt> is greater than
831         *             <tt>length()</tt>, or if <tt>start</tt> is greater than <tt>end</tt>
832         * 
833         * @since 1.4
834         * Specification: JSR-51
835         */
836        @Override
837        public CharSequence subSequence(final int start, final int end)
838        {
839                return this.substring(start, end);
840        }
841
842        /**
843         * Returns a new <code>String</code> that contains a subsequence of characters currently
844         * contained in this <code>AppendingStringBuffer</code>. The substring begins at the specified
845         * <code>start</code> and extends to the character at index <code>end - 1</code>. An exception
846         * is thrown if
847         * 
848         * @param start
849         *            The beginning index, inclusive.
850         * @param end
851         *            The ending index, exclusive.
852         * @return The new string.
853         * @exception StringIndexOutOfBoundsException
854         *                if <code>start</code> or <code>end</code> are negative or greater than
855         *                <code>length()</code>, or <code>start</code> is greater than <code>end</code>.
856         * @since 1.2
857         */
858        public String substring(final int start, final int end)
859        {
860                if (start < 0)
861                {
862                        throw new StringIndexOutOfBoundsException(start);
863                }
864                if (end > count)
865                {
866                        throw new StringIndexOutOfBoundsException(end);
867                }
868                if (start > end)
869                {
870                        throw new StringIndexOutOfBoundsException(end - start);
871                }
872                return new String(value, start, end - start);
873        }
874
875        /**
876         * Inserts the string representation of a subarray of the <code>str</code> array argument into
877         * this string buffer. The subarray begins at the specified <code>offset</code> and extends
878         * <code>len</code> characters. The characters of the subarray are inserted into this string
879         * buffer at the position indicated by <code>index</code>. The length of this
880         * <code>AppendingStringBuffer</code> increases by <code>len</code> characters.
881         * 
882         * @param index
883         *            position at which to insert subarray.
884         * @param str
885         *            A character array.
886         * @param offset
887         *            the index of the first character in subarray to to be inserted.
888         * @param len
889         *            the number of characters in the subarray to to be inserted.
890         * @return This string buffer.
891         * @exception StringIndexOutOfBoundsException
892         *                if <code>index</code> is negative or greater than <code>length()</code>, or
893         *                <code>offset</code> or <code>len</code> are negative, or
894         *                <code>(offset+len)</code> is greater than <code>str.length</code>.
895         * @since 1.2
896         */
897        public AppendingStringBuffer insert(final int index, final char str[], final int offset,
898                final int len)
899        {
900                if ((index < 0) || (index > count))
901                {
902                        throw new StringIndexOutOfBoundsException();
903                }
904                if ((offset < 0) || (offset + len < 0) || (offset + len > str.length))
905                {
906                        throw new StringIndexOutOfBoundsException(offset);
907                }
908                if (len < 0)
909                {
910                        throw new StringIndexOutOfBoundsException(len);
911                }
912                int newCount = count + len;
913                if (newCount > value.length)
914                {
915                        expandCapacity(newCount);
916                }
917                System.arraycopy(value, index, value, index + len, count - index);
918                System.arraycopy(str, offset, value, index, len);
919                count = newCount;
920                return this;
921        }
922
923        /**
924         * Inserts the string representation of the <code>Object</code> argument into this string
925         * buffer.
926         * <p>
927         * The second argument is converted to a string as if by the method <code>String.valueOf</code>,
928         * and the characters of that string are then inserted into this string buffer at the indicated
929         * offset.
930         * <p>
931         * The offset argument must be greater than or equal to <code>0</code>, and less than or equal
932         * to the length of this string buffer.
933         * 
934         * @param offset
935         *            the offset.
936         * @param obj
937         *            an <code>Object</code>.
938         * @return a reference to this <code>AppendingStringBuffer</code> object.
939         * @exception StringIndexOutOfBoundsException
940         *                if the offset is invalid.
941         * @see java.lang.String#valueOf(java.lang.Object)
942         * @see AppendingStringBuffer#insert(int, java.lang.String)
943         * @see AppendingStringBuffer#length()
944         */
945        public AppendingStringBuffer insert(final int offset, final Object obj)
946        {
947                if (obj instanceof AppendingStringBuffer)
948                {
949                        AppendingStringBuffer asb = (AppendingStringBuffer)obj;
950                        return insert(offset, asb.value, 0, asb.count);
951                }
952                else if (obj instanceof StringBuffer)
953                {
954                        return insert(offset, (StringBuffer)obj);
955                }
956                else if (obj instanceof StringBuilder)
957                {
958                        return insert(offset, (StringBuilder)obj);
959                }
960                return insert(offset, String.valueOf(obj));
961        }
962
963        /**
964         * Inserts the string into this string buffer.
965         * <p>
966         * The characters of the <code>String</code> argument are inserted, in order, into this string
967         * buffer at the indicated offset, moving up any characters originally above that position and
968         * increasing the length of this string buffer by the length of the argument. If
969         * <code>str</code> is <code>null</code>, then the four characters <code>"null"</code> are
970         * inserted into this string buffer.
971         * <p>
972         * The character at index <i>k</i> in the new character sequence is equal to:
973         * <ul>
974         * <li>the character at index <i>k</i> in the old character sequence, if <i>k</i> is less than
975         * <code>offset</code>
976         * <li>the character at index <i>k</i><code>-offset</code> in the argument <code>str</code>, if
977         * <i>k</i> is not less than <code>offset</code> but is less than
978         * <code>offset+str.length()</code>
979         * <li>the character at index <i>k</i><code>-str.length()</code> in the old character sequence,
980         * if <i>k</i> is not less than <code>offset+str.length()</code>
981         * </ul>
982         * <p>
983         * The offset argument must be greater than or equal to <code>0</code>, and less than or equal
984         * to the length of this string buffer.
985         * 
986         * @param offset
987         *            the offset.
988         * @param str
989         *            a string.
990         * @return a reference to this <code>AppendingStringBuffer</code> object.
991         * @exception StringIndexOutOfBoundsException
992         *                if the offset is invalid.
993         * @see java.lang.StringBuffer#length()
994         */
995        public AppendingStringBuffer insert(final int offset, String str)
996        {
997                if ((offset < 0) || (offset > count))
998                {
999                        throw new StringIndexOutOfBoundsException();
1000                }
1001
1002                if (str == null)
1003                {
1004                        str = String.valueOf(str);
1005                }
1006                int len = str.length();
1007                int newcount = count + len;
1008                if (newcount > value.length)
1009                {
1010                        expandCapacity(newcount);
1011                }
1012                System.arraycopy(value, offset, value, offset + len, count - offset);
1013                str.getChars(0, len, value, offset);
1014                count = newcount;
1015                return this;
1016        }
1017
1018        /**
1019         * Inserts the string into this string buffer.
1020         * <p>
1021         * The characters of the <code>StringBuilder</code> argument are inserted, in order, into this
1022         * string buffer at the indicated offset, moving up any characters originally above that
1023         * position and increasing the length of this string buffer by the length of the argument. If
1024         * <code>str</code> is <code>null</code>, then the four characters <code>"null"</code> are
1025         * inserted into this string buffer.
1026         * <p>
1027         * The character at index <i>k</i> in the new character sequence is equal to:
1028         * <ul>
1029         * <li>the character at index <i>k</i> in the old character sequence, if <i>k</i> is less than
1030         * <code>offset</code>
1031         * <li>the character at index <i>k</i><code>-offset</code> in the argument <code>str</code>, if
1032         * <i>k</i> is not less than <code>offset</code> but is less than
1033         * <code>offset+str.length()</code>
1034         * <li>the character at index <i>k</i><code>-str.length()</code> in the old character sequence,
1035         * if <i>k</i> is not less than <code>offset+str.length()</code>
1036         * </ul>
1037         * <p>
1038         * The offset argument must be greater than or equal to <code>0</code>, and less than or equal
1039         * to the length of this string buffer.
1040         * 
1041         * @param offset
1042         *            the offset.
1043         * @param str
1044         *            a string.
1045         * @return a reference to this <code>AppendingStringBuffer</code> object.
1046         * @exception StringIndexOutOfBoundsException
1047         *                if the offset is invalid.
1048         * @see java.lang.StringBuffer#length()
1049         */
1050        public AppendingStringBuffer insert(final int offset, StringBuilder str)
1051        {
1052                if ((offset < 0) || (offset > count))
1053                {
1054                        throw new StringIndexOutOfBoundsException();
1055                }
1056
1057                if (str == null)
1058                {
1059                        str = SB_NULL;
1060                }
1061                int len = str.length();
1062                int newcount = count + len;
1063                if (newcount > value.length)
1064                {
1065                        expandCapacity(newcount);
1066                }
1067                System.arraycopy(value, offset, value, offset + len, count - offset);
1068                str.getChars(0, len, value, offset);
1069                count = newcount;
1070                return this;
1071        }
1072
1073        /**
1074         * Inserts the string into this string buffer.
1075         * <p>
1076         * The characters of the <code>StringBuffer</code> argument are inserted, in order, into this
1077         * string buffer at the indicated offset, moving up any characters originally above that
1078         * position and increasing the length of this string buffer by the length of the argument. If
1079         * <code>str</code> is <code>null</code>, then the four characters <code>"null"</code> are
1080         * inserted into this string buffer.
1081         * <p>
1082         * The character at index <i>k</i> in the new character sequence is equal to:
1083         * <ul>
1084         * <li>the character at index <i>k</i> in the old character sequence, if <i>k</i> is less than
1085         * <code>offset</code>
1086         * <li>the character at index <i>k</i><code>-offset</code> in the argument <code>str</code>, if
1087         * <i>k</i> is not less than <code>offset</code> but is less than
1088         * <code>offset+str.length()</code>
1089         * <li>the character at index <i>k</i><code>-str.length()</code> in the old character sequence,
1090         * if <i>k</i> is not less than <code>offset+str.length()</code>
1091         * </ul>
1092         * <p>
1093         * The offset argument must be greater than or equal to <code>0</code>, and less than or equal
1094         * to the length of this string buffer.
1095         * 
1096         * @param offset
1097         *            the offset.
1098         * @param str
1099         *            a string.
1100         * @return a reference to this <code>AppendingStringBuffer</code> object.
1101         * @exception StringIndexOutOfBoundsException
1102         *                if the offset is invalid.
1103         * @see java.lang.StringBuffer#length()
1104         */
1105        public AppendingStringBuffer insert(final int offset, StringBuffer str)
1106        {
1107                if ((offset < 0) || (offset > count))
1108                {
1109                        throw new StringIndexOutOfBoundsException();
1110                }
1111
1112                if (str == null)
1113                {
1114                        str = SBF_NULL;
1115                }
1116                int len = str.length();
1117                int newcount = count + len;
1118                if (newcount > value.length)
1119                {
1120                        expandCapacity(newcount);
1121                }
1122                System.arraycopy(value, offset, value, offset + len, count - offset);
1123                str.getChars(0, len, value, offset);
1124                count = newcount;
1125                return this;
1126        }
1127
1128        /**
1129         * Inserts the string representation of the <code>char</code> array argument into this string
1130         * buffer.
1131         * <p>
1132         * The characters of the array argument are inserted into the contents of this string buffer at
1133         * the position indicated by <code>offset</code>. The length of this string buffer increases by
1134         * the length of the argument.
1135         * <p>
1136         * The overall effect is exactly as if the argument were converted to a string by the method
1137         * {@link String#valueOf(char[])} and the characters of that string were then
1138         * {@link #insert(int,String) inserted} into this <code>AppendingStringBuffer</code> object at
1139         * the position indicated by <code>offset</code>.
1140         * 
1141         * @param offset
1142         *            the offset.
1143         * @param str
1144         *            a character array.
1145         * @return a reference to this <code>AppendingStringBuffer</code> object.
1146         * @exception StringIndexOutOfBoundsException
1147         *                if the offset is invalid.
1148         */
1149        public AppendingStringBuffer insert(final int offset, final char str[])
1150        {
1151                if ((offset < 0) || (offset > count))
1152                {
1153                        throw new StringIndexOutOfBoundsException();
1154                }
1155                int len = str.length;
1156                int newcount = count + len;
1157                if (newcount > value.length)
1158                {
1159                        expandCapacity(newcount);
1160                }
1161                System.arraycopy(value, offset, value, offset + len, count - offset);
1162                System.arraycopy(str, 0, value, offset, len);
1163                count = newcount;
1164                return this;
1165        }
1166
1167        /**
1168         * Inserts the string representation of the <code>boolean</code> argument into this string
1169         * buffer.
1170         * <p>
1171         * The second argument is converted to a string as if by the method <code>String.valueOf</code>,
1172         * and the characters of that string are then inserted into this string buffer at the indicated
1173         * offset.
1174         * <p>
1175         * The offset argument must be greater than or equal to <code>0</code>, and less than or equal
1176         * to the length of this string buffer.
1177         * 
1178         * @param offset
1179         *            the offset.
1180         * @param b
1181         *            a <code>boolean</code>.
1182         * @return a reference to this <code>AppendingStringBuffer</code> object.
1183         * @exception StringIndexOutOfBoundsException
1184         *                if the offset is invalid.
1185         * @see java.lang.String#valueOf(boolean)
1186         * @see java.lang.StringBuffer#insert(int, java.lang.String)
1187         * @see java.lang.StringBuffer#length()
1188         */
1189        public AppendingStringBuffer insert(final int offset, final boolean b)
1190        {
1191                return insert(offset, String.valueOf(b));
1192        }
1193
1194        /**
1195         * Inserts the string representation of the <code>char</code> argument into this string buffer.
1196         * <p>
1197         * The second argument is inserted into the contents of this string buffer at the position
1198         * indicated by <code>offset</code>. The length of this string buffer increases by one.
1199         * <p>
1200         * The overall effect is exactly as if the argument were converted to a string by the method
1201         * {@link String#valueOf(char)} and the character in that string were then
1202         * {@link #insert(int, String) inserted} into this <code>AppendingStringBuffer</code> object at
1203         * the position indicated by <code>offset</code>.
1204         * <p>
1205         * The offset argument must be greater than or equal to <code>0</code>, and less than or equal
1206         * to the length of this string buffer.
1207         * 
1208         * @param offset
1209         *            the offset.
1210         * @param c
1211         *            a <code>char</code>.
1212         * @return a reference to this <code>AppendingStringBuffer</code> object.
1213         * @exception IndexOutOfBoundsException
1214         *                if the offset is invalid.
1215         * @see java.lang.StringBuffer#length()
1216         */
1217        public AppendingStringBuffer insert(final int offset, final char c)
1218        {
1219                int newcount = count + 1;
1220                if (newcount > value.length)
1221                {
1222                        expandCapacity(newcount);
1223                }
1224                System.arraycopy(value, offset, value, offset + 1, count - offset);
1225                value[offset] = c;
1226                count = newcount;
1227                return this;
1228        }
1229
1230        /**
1231         * Inserts the string representation of the second <code>int</code> argument into this string
1232         * buffer.
1233         * <p>
1234         * The second argument is converted to a string as if by the method <code>String.valueOf</code>,
1235         * and the characters of that string are then inserted into this string buffer at the indicated
1236         * offset.
1237         * <p>
1238         * The offset argument must be greater than or equal to <code>0</code>, and less than or equal
1239         * to the length of this string buffer.
1240         * 
1241         * @param offset
1242         *            the offset.
1243         * @param i
1244         *            an <code>int</code>.
1245         * @return a reference to this <code>AppendingStringBuffer</code> object.
1246         * @exception StringIndexOutOfBoundsException
1247         *                if the offset is invalid.
1248         * @see java.lang.String#valueOf(int)
1249         * @see java.lang.StringBuffer#insert(int, java.lang.String)
1250         * @see java.lang.StringBuffer#length()
1251         */
1252        public AppendingStringBuffer insert(final int offset, final int i)
1253        {
1254                return insert(offset, String.valueOf(i));
1255        }
1256
1257        /**
1258         * Inserts the string representation of the <code>long</code> argument into this string buffer.
1259         * <p>
1260         * The second argument is converted to a string as if by the method <code>String.valueOf</code>,
1261         * and the characters of that string are then inserted into this string buffer at the position
1262         * indicated by <code>offset</code>.
1263         * <p>
1264         * The offset argument must be greater than or equal to <code>0</code>, and less than or equal
1265         * to the length of this string buffer.
1266         * 
1267         * @param offset
1268         *            the offset.
1269         * @param l
1270         *            a <code>long</code>.
1271         * @return a reference to this <code>AppendingStringBuffer</code> object.
1272         * @exception StringIndexOutOfBoundsException
1273         *                if the offset is invalid.
1274         * @see java.lang.String#valueOf(long)
1275         * @see java.lang.StringBuffer#insert(int, java.lang.String)
1276         * @see java.lang.StringBuffer#length()
1277         */
1278        public AppendingStringBuffer insert(final int offset, final long l)
1279        {
1280                return insert(offset, String.valueOf(l));
1281        }
1282
1283        /**
1284         * Inserts the string representation of the <code>float</code> argument into this string buffer.
1285         * <p>
1286         * The second argument is converted to a string as if by the method <code>String.valueOf</code>,
1287         * and the characters of that string are then inserted into this string buffer at the indicated
1288         * offset.
1289         * <p>
1290         * The offset argument must be greater than or equal to <code>0</code>, and less than or equal
1291         * to the length of this string buffer.
1292         * 
1293         * @param offset
1294         *            the offset.
1295         * @param f
1296         *            a <code>float</code>.
1297         * @return a reference to this <code>AppendingStringBuffer</code> object.
1298         * @exception StringIndexOutOfBoundsException
1299         *                if the offset is invalid.
1300         * @see java.lang.String#valueOf(float)
1301         * @see java.lang.StringBuffer#insert(int, java.lang.String)
1302         * @see java.lang.StringBuffer#length()
1303         */
1304        public AppendingStringBuffer insert(final int offset, final float f)
1305        {
1306                return insert(offset, String.valueOf(f));
1307        }
1308
1309        /**
1310         * Inserts the string representation of the <code>double</code> argument into this string
1311         * buffer.
1312         * <p>
1313         * The second argument is converted to a string as if by the method <code>String.valueOf</code>,
1314         * and the characters of that string are then inserted into this string buffer at the indicated
1315         * offset.
1316         * <p>
1317         * The offset argument must be greater than or equal to <code>0</code>, and less than or equal
1318         * to the length of this string buffer.
1319         * 
1320         * @param offset
1321         *            the offset.
1322         * @param d
1323         *            a <code>double</code>.
1324         * @return a reference to this <code>AppendingStringBuffer</code> object.
1325         * @exception StringIndexOutOfBoundsException
1326         *                if the offset is invalid.
1327         * @see java.lang.String#valueOf(double)
1328         * @see java.lang.StringBuffer#insert(int, java.lang.String)
1329         * @see java.lang.StringBuffer#length()
1330         */
1331        public AppendingStringBuffer insert(final int offset, final double d)
1332        {
1333                return insert(offset, String.valueOf(d));
1334        }
1335
1336        /**
1337         * Returns the index within this string of the first occurrence of the specified substring. The
1338         * integer returned is the smallest value <i>k</i> such that: <blockquote>
1339         * 
1340         * <pre>
1341         *       this.toString().startsWith(str, &lt;i&gt;k&lt;/i&gt;)
1342         * </pre>
1343         * 
1344         * </blockquote> is <code>true</code>.
1345         * 
1346         * @param str
1347         *            any string.
1348         * @return if the string argument occurs as a substring within this object, then the index of
1349         *         the first character of the first such substring is returned; if it does not occur as
1350         *         a substring, <code>-1</code> is returned.
1351         * @exception java.lang.NullPointerException
1352         *                if <code>str</code> is <code>null</code>.
1353         * @since 1.4
1354         */
1355        public int indexOf(final String str)
1356        {
1357                return indexOf(str, 0);
1358        }
1359
1360        /**
1361         * Returns the index within this string of the first occurrence of the specified substring,
1362         * starting at the specified index. The integer returned is the smallest value <tt>k</tt> for
1363         * which: <blockquote>
1364         * 
1365         * <pre>
1366         * k &gt;= Math.min(fromIndex, str.length()) &amp;&amp; this.toString().startsWith(str, k)
1367         * </pre>
1368         * 
1369         * </blockquote> If no such value of <i>k</i> exists, then -1 is returned.
1370         * 
1371         * @param str
1372         *            the substring for which to search.
1373         * @param fromIndex
1374         *            the index from which to start the search.
1375         * @return the index within this string of the first occurrence of the specified substring,
1376         *         starting at the specified index.
1377         * @exception java.lang.NullPointerException
1378         *                if <code>str</code> is <code>null</code>.
1379         * @since 1.4
1380         */
1381        public int indexOf(final String str, final int fromIndex)
1382        {
1383                return indexOf(value, 0, count, str.toCharArray(), 0, str.length(), fromIndex);
1384        }
1385
1386        static int indexOf(final char[] source, final int sourceOffset, final int sourceCount,
1387                final char[] target, final int targetOffset, final int targetCount, int fromIndex)
1388        {
1389                if (fromIndex >= sourceCount)
1390                {
1391                        return (targetCount == 0 ? sourceCount : -1);
1392                }
1393                if (fromIndex < 0)
1394                {
1395                        fromIndex = 0;
1396                }
1397                if (targetCount == 0)
1398                {
1399                        return fromIndex;
1400                }
1401
1402                char first = target[targetOffset];
1403                int i = sourceOffset + fromIndex;
1404                int max = sourceOffset + (sourceCount - targetCount);
1405
1406                startSearchForFirstChar : while (true)
1407                {
1408                        /* Look for first character. */
1409                        while ((i <= max) && (source[i] != first))
1410                        {
1411                                i++;
1412                        }
1413                        if (i > max)
1414                        {
1415                                return -1;
1416                        }
1417
1418                        /* Found first character, now look at the rest of v2 */
1419                        int j = i + 1;
1420                        int end = j + targetCount - 1;
1421                        int k = targetOffset + 1;
1422                        while (j < end)
1423                        {
1424                                if (source[j++] != target[k++])
1425                                {
1426                                        i++;
1427                                        /* Look for str's first char again. */
1428                                        continue startSearchForFirstChar;
1429                                }
1430                        }
1431                        return i - sourceOffset; /* Found whole string. */
1432                }
1433        }
1434
1435        /**
1436         * Returns the index within this string of the rightmost occurrence of the specified substring.
1437         * The rightmost empty string "" is considered to occur at the index value
1438         * <code>this.length()</code>. The returned index is the largest value <i>k</i> such that
1439         * <blockquote>
1440         * 
1441         * <pre>
1442         * this.toString().startsWith(str, k)
1443         * </pre>
1444         * 
1445         * </blockquote> is true.
1446         * 
1447         * @param str
1448         *            the substring to search for.
1449         * @return if the string argument occurs one or more times as a substring within this object,
1450         *         then the index of the first character of the last such substring is returned. If it
1451         *         does not occur as a substring, <code>-1</code> is returned.
1452         * @exception java.lang.NullPointerException
1453         *                if <code>str</code> is <code>null</code>.
1454         * @since 1.4
1455         */
1456        public int lastIndexOf(final String str)
1457        {
1458                return lastIndexOf(str, count);
1459        }
1460
1461        /**
1462         * Returns the index within this string of the last occurrence of the specified substring. The
1463         * integer returned is the largest value <i>k</i> such that: <blockquote>
1464         * 
1465         * <pre>
1466         * k &lt;= Math.min(fromIndex, str.length()) &amp;&amp; this.toString().startsWith(str, k)
1467         * </pre>
1468         * 
1469         * </blockquote> If no such value of <i>k</i> exists, then -1 is returned.
1470         * 
1471         * @param str
1472         *            the substring to search for.
1473         * @param fromIndex
1474         *            the index to start the search from.
1475         * @return the index within this string of the last occurrence of the specified substring.
1476         * @exception java.lang.NullPointerException
1477         *                if <code>str</code> is <code>null</code>.
1478         * @since 1.4
1479         */
1480        public int lastIndexOf(final String str, final int fromIndex)
1481        {
1482                return lastIndexOf(value, 0, count, str.toCharArray(), 0, str.length(), fromIndex);
1483        }
1484
1485        static int lastIndexOf(final char[] source, final int sourceOffset, final int sourceCount,
1486                final char[] target, final int targetOffset, final int targetCount, int fromIndex)
1487        {
1488                /*
1489                 * Check arguments; return immediately where possible. For consistency, don't check for null
1490                 * str.
1491                 */
1492                int rightIndex = sourceCount - targetCount;
1493                if (fromIndex < 0)
1494                {
1495                        return -1;
1496                }
1497                if (fromIndex > rightIndex)
1498                {
1499                        fromIndex = rightIndex;
1500                }
1501                /* Empty string always matches. */
1502                if (targetCount == 0)
1503                {
1504                        return fromIndex;
1505                }
1506
1507                int strLastIndex = targetOffset + targetCount - 1;
1508                char strLastChar = target[strLastIndex];
1509                int min = sourceOffset + targetCount - 1;
1510                int i = min + fromIndex;
1511
1512                startSearchForLastChar : while (true)
1513                {
1514                        while ((i >= min) && (source[i] != strLastChar))
1515                        {
1516                                i--;
1517                        }
1518                        if (i < min)
1519                        {
1520                                return -1;
1521                        }
1522                        int j = i - 1;
1523                        int start = j - (targetCount - 1);
1524                        int k = strLastIndex - 1;
1525
1526                        while (j > start)
1527                        {
1528                                if (source[j--] != target[k--])
1529                                {
1530                                        i--;
1531                                        continue startSearchForLastChar;
1532                                }
1533                        }
1534                        return start - sourceOffset + 1;
1535                }
1536        }
1537
1538        /**
1539         * Tests if this AppendingStringBuffer starts with the specified prefix beginning a specified
1540         * index.
1541         * 
1542         * @param prefix
1543         *            the prefix.
1544         * @param toffset
1545         *            where to begin looking in the string.
1546         * @return <code>true</code> if the character sequence represented by the argument is a prefix
1547         *         of the substring of this object starting at index <code>toffset</code>;
1548         *         <code>false</code> otherwise. The result is <code>false</code> if
1549         *         <code>toffset</code> is negative or greater than the length of this
1550         *         <code>String</code> object; otherwise the result is the same as the result of the
1551         *         expression
1552         * 
1553         *         <pre>
1554         * this.subString(toffset).startsWith(prefix)
1555         * </pre>
1556         */
1557        public boolean startsWith(final CharSequence prefix, final int toffset)
1558        {
1559                char ta[] = value;
1560                int to = toffset;
1561                int po = 0;
1562                int pc = prefix.length();
1563                // Note: toffset might be near -1>>>1.
1564                if ((toffset < 0) || (toffset > count - pc))
1565                {
1566                        return false;
1567                }
1568                while (--pc >= 0)
1569                {
1570                        if (ta[to++] != prefix.charAt(po++))
1571                        {
1572                                return false;
1573                        }
1574                }
1575                return true;
1576        }
1577
1578        /**
1579         * Tests if this AppendingStringBuffer starts with the specified prefix.
1580         * 
1581         * @param prefix
1582         *            the prefix.
1583         * @return <code>true</code> if the character sequence represented by the argument is a prefix
1584         *         of the character sequence represented by this AppendingStringBuffer;
1585         *         <code>false</code> otherwise. Note also that <code>true</code> will be returned if
1586         *         the argument is an empty string or is equal to this
1587         *         <code>AppendingStringBuffer</code> object as determined by the
1588         *         {@link #equals(Object)} method.
1589         * @since 1. 0
1590         */
1591        public boolean startsWith(final CharSequence prefix)
1592        {
1593                return startsWith(prefix, 0);
1594        }
1595
1596        /**
1597         * Tests if this AppendingStringBuffer ends with the specified suffix.
1598         * 
1599         * @param suffix
1600         *            the suffix.
1601         * @return <code>true</code> if the character sequence represented by the argument is a suffix
1602         *         of the character sequence represented by this AppendingStringBuffer;
1603         *         <code>false</code> otherwise. Note that the result will be <code>true</code> if the
1604         *         argument is the empty string or is equal to this <code>AppendingStringBuffer</code>
1605         *         object as determined by the {@link #equals(Object)} method.
1606         */
1607        public boolean endsWith(final CharSequence suffix)
1608        {
1609                return startsWith(suffix, count - suffix.length());
1610        }
1611
1612        /**
1613         * Converts to a string representing the data in this AppendingStringBuffer. A new
1614         * <code>String</code> object is allocated and initialized to contain the character sequence
1615         * currently represented by this string buffer. This <code>String</code> is then returned.
1616         * Subsequent changes to the string buffer do not affect the contents of the <code>String</code>
1617         * .
1618         * <p>
1619         * Implementation advice: This method can be coded so as to create a new <code>String</code>
1620         * object without allocating new memory to hold a copy of the character sequence. Instead, the
1621         * string can share the memory used by the string buffer. Any subsequent operation that alters
1622         * the content or capacity of the string buffer must then make a copy of the internal buffer at
1623         * that time. This strategy is effective for reducing the amount of memory allocated by a string
1624         * concatenation operation when it is implemented using a string buffer.
1625         * 
1626         * @return a string representation of the string buffer.
1627         */
1628        @Override
1629        public String toString()
1630        {
1631                return new String(value, 0, count);
1632        }
1633
1634        /**
1635         * This method returns the internal char array. So it is not
1636         * 
1637         * @return The internal char array
1638         */
1639        public final char[] getValue()
1640        {
1641                return value;
1642        }
1643
1644
1645        /**
1646         * readObject is called to restore the state of the AppendingStringBuffer from a stream.
1647         * 
1648         * @param s
1649         * @throws ClassNotFoundException
1650         * @throws IOException
1651         */
1652        private void readObject(final java.io.ObjectInputStream s) throws IOException,
1653                ClassNotFoundException
1654        {
1655                s.defaultReadObject();
1656                value = value.clone();
1657        }
1658
1659        /**
1660         * Compares this AppendingStringBuffer to the specified object. The result is <code>true</code>
1661         * if and only if the argument is not <code>null</code> and is a
1662         * <code>AppendingStringBuffer</code> object or another charsequence object! that represents the
1663         * same sequence of characters as this object.
1664         * 
1665         * @param anObject
1666         *            the object to compare this <code>AppendingStringBuffer</code> against.
1667         * @return <code>true</code> if the <code>AppendingStringBuffer</code>are equal;
1668         *         <code>false</code> otherwise.
1669         */
1670        @Override
1671        public boolean equals(final Object anObject)
1672        {
1673                if (this == anObject)
1674                {
1675                        return true;
1676                }
1677                if (anObject instanceof AppendingStringBuffer)
1678                {
1679                        AppendingStringBuffer anotherString = (AppendingStringBuffer)anObject;
1680                        int n = count;
1681                        if (n == anotherString.count)
1682                        {
1683                                char v1[] = value;
1684                                char v2[] = anotherString.value;
1685                                int i = 0;
1686                                while (n-- != 0)
1687                                {
1688                                        if (v1[i] != v2[i++])
1689                                        {
1690                                                return false;
1691                                        }
1692                                }
1693                                return true;
1694                        }
1695                }
1696                else if (anObject instanceof CharSequence)
1697                {
1698                        CharSequence sequence = (CharSequence)anObject;
1699                        int n = count;
1700                        if (sequence.length() == count)
1701                        {
1702                                char v1[] = value;
1703                                int i = 0;
1704                                while (n-- != 0)
1705                                {
1706                                        if (v1[i] != sequence.charAt(i++))
1707                                        {
1708                                                return false;
1709                                        }
1710                                }
1711                                return true;
1712                        }
1713                }
1714                return false;
1715        }
1716
1717        /**
1718         * Returns a hash code for this AppendingStringBuffer. The hash code for a
1719         * <code>AppendingStringBuffer</code> object is computed as <blockquote>
1720         * 
1721         * <pre>
1722         *    s[0]*31&circ;(n-1) + s[1]*31&circ;(n-2) + ... + s[n-1]
1723         * </pre>
1724         * 
1725         * </blockquote> using <code>int</code> arithmetic, where <code>s[i]</code> is the <i>i</i>th
1726         * character of the AppendingStringBuffer, <code>n</code> is the length of the
1727         * AppendingStringBuffer, and <code>^</code> indicates exponentiation. (The hash value of the
1728         * empty AppendingStringBuffer is zero.)
1729         * 
1730         * @return a hash code value for this object.
1731         */
1732        @Override
1733        public int hashCode()
1734        {
1735                int h = 0;
1736                if (h == 0)
1737                {
1738                        int off = 0;
1739                        char val[] = value;
1740                        int len = count;
1741
1742                        for (int i = 0; i < len; i++)
1743                        {
1744                                h = 31 * h + val[off++];
1745                        }
1746                }
1747                return h;
1748        }
1749
1750        /**
1751         * Clears the buffer contents, but leaves the allocated size intact
1752         */
1753        public void clear()
1754        {
1755                count = 0;
1756        }
1757}