Path: blob/master/jcl/src/java.base/share/classes/java/lang/StringBuffer.java
12513 views
/*[INCLUDE-IF JAVA_SPEC_VERSION == 8]*/1/*******************************************************************************2* Copyright (c) 1998, 2022 IBM Corp. and others3*4* This program and the accompanying materials are made available under5* the terms of the Eclipse Public License 2.0 which accompanies this6* distribution and is available at https://www.eclipse.org/legal/epl-2.0/7* or the Apache License, Version 2.0 which accompanies this distribution and8* is available at https://www.apache.org/licenses/LICENSE-2.0.9*10* This Source Code may also be made available under the following11* Secondary Licenses when the conditions for such availability set12* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU13* General Public License, version 2 with the GNU Classpath14* Exception [1] and GNU General Public License, version 2 with the15* OpenJDK Assembly Exception [2].16*17* [1] https://www.gnu.org/software/classpath/license.html18* [2] http://openjdk.java.net/legal/assembly-exception.html19*20* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception21*******************************************************************************/22package java.lang;2324import java.io.IOException;25import java.io.ObjectInputStream;26import java.io.ObjectOutputStream;27import java.io.Serializable;28import java.io.StreamCorruptedException;29import java.util.Arrays;30import java.util.Properties;3132/**33* StringBuffer is a variable size contiguous indexable array of characters.34* The length of the StringBuffer is the number of characters it contains.35* The capacity of the StringBuffer is the number of characters it can hold.36* <p>37* Characters may be inserted at any position up to the length of the38* StringBuffer, increasing the length of the StringBuffer. Characters at any39* position in the StringBuffer may be replaced, which does not affect the40* StringBuffer length.41* <p>42* The capacity of a StringBuffer may be specified when the StringBuffer is43* created. If the capacity of the StringBuffer is exceeded, the capacity44* is increased.45*46* @author OTI47* @version initial48*49* @see String50*/51public final class StringBuffer extends AbstractStringBuilder implements Serializable, CharSequence, Appendable {52private static final long serialVersionUID = 3388685877147921107L;5354private static final int INITIAL_SIZE = 16;5556private static boolean TOSTRING_COPY_BUFFER_ENABLED = false;57private static boolean growAggressively = false;5859// Used to access compression related helper methods60private static final com.ibm.jit.JITHelpers helpers = com.ibm.jit.JITHelpers.getHelpers();6162// Represents the bit in count field to test for whether this StringBuffer backing array is not compressed63// under String compression mode. This bit is not used when String compression is disabled.64private static final int uncompressedBit = 0x80000000;6566// Represents the bit in capacity field to test for whether this StringBuffer backing array is shared.67private static final int sharedBit = 0x80000000;6869private static final java.io.ObjectStreamField serialPersistentFields[] = new java.io.ObjectStreamField[] {70new java.io.ObjectStreamField("count", Integer.TYPE), //$NON-NLS-1$71new java.io.ObjectStreamField("value", char[].class), //$NON-NLS-1$72new java.io.ObjectStreamField("shared", Boolean.TYPE), //$NON-NLS-1$73};7475private int count;76private char[] value;77private int capacity;7879private void decompress(int min) {80int currentLength = lengthInternalUnsynchronized();81int currentCapacity = capacityInternal();82char[] newValue;8384if (min > currentCapacity) {85/* twice may be negative, in which case we'll use min */86int twice = (currentCapacity << 1) + 2;8788newValue = new char[min > twice ? min : twice];89} else {90newValue = new char[currentCapacity];91}9293String.decompress(value, 0, newValue, 0, currentLength);9495count = count | uncompressedBit;96value = newValue;97capacity = newValue.length;9899String.initCompressionFlag();100}101102/**103* Constructs a new StringBuffer using the default capacity.104*/105public StringBuffer() {106this(INITIAL_SIZE);107}108109/**110* Constructs a new StringBuffer using the specified capacity.111*112* @param capacity the initial capacity113*/114public StringBuffer(int capacity) {115/* capacity argument is used to determine the byte/char array size. If116* capacity argument is Integer.MIN_VALUE (-2147483648), then capacity *= 2117* will yield a non-negative number due to overflow. We will fail to throw118* NegativeArraySizeException. The check below will assure that119* NegativeArraySizeException is thrown if capacity argument is less than 0.120*/121if (capacity < 0) {122throw new NegativeArraySizeException(String.valueOf(capacity));123}124int arraySize = capacity;125126if (String.COMPACT_STRINGS) {127arraySize = (capacity + 1) >>> 1;128}129value = new char[arraySize];130131this.capacity = capacity;132}133134/**135* Constructs a new StringBuffer containing the characters in136* the specified string and the default capacity.137*138* @param string the initial contents of this StringBuffer139* @exception NullPointerException when string is null140*/141public StringBuffer (String string) {142int stringLength = string.lengthInternal();143144int newLength = stringLength + INITIAL_SIZE;145if (newLength < stringLength) {146newLength = stringLength;147}148149if (String.COMPACT_STRINGS) {150if (string.isCompressed ()) {151value = new char[(newLength + 1) >>> 1];152153string.getBytes(0, stringLength, value, 0);154155capacity = newLength;156157count = stringLength;158} else {159value = new char[newLength];160161string.getCharsNoBoundChecks(0, stringLength, value, 0);162163capacity = newLength;164165count = stringLength | uncompressedBit;166167String.initCompressionFlag();168}169} else {170value = new char[newLength];171172string.getCharsNoBoundChecks(0, stringLength, value, 0);173174capacity = newLength;175176count = stringLength;177}178}179180/**181* Adds the character array to the end of this StringBuffer.182*183* @param chars the character array184* @return this StringBuffer185*186* @exception NullPointerException when chars is null187*/188public synchronized StringBuffer append (char[] chars) {189int currentLength = lengthInternalUnsynchronized();190int currentCapacity = capacityInternal();191192int newLength = currentLength + chars.length;193if (newLength < 0) {194/*[MSG "K0D01", "Array capacity exceeded"]*/195throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$196}197198if (String.COMPACT_STRINGS) {199// Check if the StringBuffer is compressed200if (count >= 0 && String.canEncodeAsLatin1(chars, 0, chars.length)) {201if (newLength > currentCapacity) {202ensureCapacityImpl(newLength);203}204205String.compress(chars, 0, value, currentLength, chars.length);206207count = newLength;208} else {209// Check if the StringBuffer is compressed210if (count >= 0) {211decompress(newLength);212}213214if (newLength > currentCapacity) {215ensureCapacityImpl(newLength);216}217218String.decompressedArrayCopy(chars, 0, value, currentLength, chars.length);219220count = newLength | uncompressedBit;221}222} else {223if (newLength > currentCapacity) {224ensureCapacityImpl(newLength);225}226227String.decompressedArrayCopy(chars, 0, value, currentLength, chars.length);228229count = newLength;230}231232return this;233}234235/**236* Adds the specified sequence of characters to the end of237* this StringBuffer.238*239* @param chars a character array240* @param start the starting offset241* @param length the number of characters242* @return this StringBuffer243*244* @exception IndexOutOfBoundsException when {@code length < 0, start < 0} or245* {@code start + length > chars.length}246* @exception NullPointerException when chars is null247*/248public synchronized StringBuffer append (char chars[], int start, int length) {249if (start >= 0 && 0 <= length && length <= chars.length - start) {250int currentLength = lengthInternalUnsynchronized();251int currentCapacity = capacityInternal();252253int newLength = currentLength + length;254if (newLength < 0) {255/*[MSG "K0D01", "Array capacity exceeded"]*/256throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$257}258259if (String.COMPACT_STRINGS) {260// Check if the StringBuffer is compressed261if (count >= 0 && String.canEncodeAsLatin1(chars, start, length)) {262if (newLength > currentCapacity) {263ensureCapacityImpl(newLength);264}265266String.compress(chars, start, value, currentLength, length);267268count = newLength;269} else {270// Check if the StringBuffer is compressed271if (count >= 0) {272decompress(newLength);273}274275if (newLength > currentCapacity) {276ensureCapacityImpl(newLength);277}278279String.decompressedArrayCopy(chars, start, value, currentLength, length);280281count = newLength | uncompressedBit;282}283} else {284if (newLength > currentCapacity) {285ensureCapacityImpl(newLength);286}287288String.decompressedArrayCopy(chars, start, value, currentLength, length);289290count = newLength;291}292293return this;294} else {295throw new StringIndexOutOfBoundsException();296}297}298299synchronized StringBuffer append (char[] chars, int start, int length, boolean compressed) {300int currentLength = lengthInternalUnsynchronized();301int currentCapacity = capacityInternal();302303int newLength = currentLength + length;304if (newLength < 0) {305/*[MSG "K0D01", "Array capacity exceeded"]*/306throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$307}308309if (String.COMPACT_STRINGS) {310// Check if the StringBuffer is compressed311if (count >= 0 && compressed) {312if (newLength > currentCapacity) {313ensureCapacityImpl(newLength);314}315316String.compressedArrayCopy(chars, start, value, currentLength, length);317318count = newLength;319} else {320// Check if the StringBuffer is compressed321if (count >= 0) {322decompress(newLength);323}324325if (newLength > currentCapacity) {326ensureCapacityImpl(newLength);327}328329if (compressed) {330String.decompress(chars, start, value, currentLength, length);331} else {332String.decompressedArrayCopy(chars, start, value, currentLength, length);333}334335count = newLength | uncompressedBit;336}337} else {338if (newLength > currentCapacity) {339ensureCapacityImpl(newLength);340}341342if (compressed) {343String.decompress(chars, start, value, currentLength, length);344} else {345String.decompressedArrayCopy(chars, start, value, currentLength, length);346}347348count = newLength;349}350351return this;352}353354/**355* Adds the specified character to the end of356* this StringBuffer.357*358* @param ch a character359* @return this StringBuffer360*/361@Override362public synchronized StringBuffer append(char ch) {363int currentLength = lengthInternalUnsynchronized();364int currentCapacity = capacityInternal();365366int newLength = currentLength + 1;367if (newLength < 0) {368/*[MSG "K0D01", "Array capacity exceeded"]*/369throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$370}371372if (String.COMPACT_STRINGS) {373// Check if the StringBuffer is compressed374if (count >= 0 && ch <= 255) {375if (newLength > currentCapacity) {376ensureCapacityImpl(newLength);377}378379helpers.putByteInArrayByIndex(value, currentLength, (byte) ch);380381count = newLength;382} else {383// Check if the StringBuffer is compressed384if (count >= 0) {385decompress(newLength);386}387388if (newLength > currentCapacity) {389ensureCapacityImpl(newLength);390}391392value[currentLength] = ch;393394count = newLength | uncompressedBit;395}396} else {397if (newLength > currentCapacity) {398ensureCapacityImpl(newLength);399}400401value[currentLength] = ch;402403count = newLength;404}405406return this;407}408409/**410* Adds the string representation of the specified double to the411* end of this StringBuffer.412*413* @param value the double414* @return this StringBuffer415*/416public StringBuffer append (double value) {417return append (String.valueOf (value));418}419420/**421* Adds the string representation of the specified float to the422* end of this StringBuffer.423*424* @param value the float425* @return this StringBuffer426*/427public StringBuffer append (float value) {428return append (String.valueOf (value));429}430431/**432* Adds the string representation of the specified integer to the433* end of this StringBuffer.434*435* @param value the integer436* @return this StringBuffer437*/438public synchronized StringBuffer append(int value) {439if (value != Integer.MIN_VALUE) {440if (String.COMPACT_STRINGS && count >= 0) {441return append(Integer.toString(value));442} else {443int currentLength = lengthInternalUnsynchronized();444int currentCapacity = capacityInternal();445446int valueLength;447if (value < 0) {448/* stringSize can't handle negative numbers in Java 8 */449valueLength = Integer.stringSize(-value) + 1;450} else {451valueLength = Integer.stringSize(value);452}453454int newLength = currentLength + valueLength;455if (newLength < 0) {456/*[MSG "K0D01", "Array capacity exceeded"]*/457throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$458}459460if (newLength > currentCapacity) {461ensureCapacityImpl(newLength);462}463464Integer.getChars(value, newLength, this.value);465466if (String.COMPACT_STRINGS) {467count = newLength | uncompressedBit;468} else {469count = newLength;470}471472return this;473}474} else {475// Append Integer.MIN_VALUE as a String476return append("-2147483648"); //$NON-NLS-1$477}478}479480/**481* Adds the string representation of the specified long to the482* end of this StringBuffer.483*484* @param value the long485* @return this StringBuffer486*/487public synchronized StringBuffer append(long value) {488if (value != Long.MIN_VALUE) {489if (String.COMPACT_STRINGS && count >= 0) {490return append(Long.toString(value));491} else {492int currentLength = lengthInternalUnsynchronized();493int currentCapacity = capacityInternal();494495int valueLength;496if (value < 0) {497/* stringSize can't handle negative numbers in Java 8 */498valueLength = Long.stringSize(-value) + 1;499} else {500valueLength = Long.stringSize(value);501}502503int newLength = currentLength + valueLength;504if (newLength < 0) {505/*[MSG "K0D01", "Array capacity exceeded"]*/506throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$507}508509if (newLength > currentCapacity) {510ensureCapacityImpl(newLength);511}512513Long.getChars(value, newLength, this.value);514515if (String.COMPACT_STRINGS) {516count = newLength | uncompressedBit;517} else {518count = newLength;519}520521return this;522}523} else {524// Append Long.MIN_VALUE as a String525return append("-9223372036854775808"); //$NON-NLS-1$526}527}528529/**530* Adds the string representation of the specified object to the531* end of this StringBuffer.532*533* @param value the object534* @return this StringBuffer535*/536public StringBuffer append (Object value) {537return append (String.valueOf (value));538}539540/**541* Adds the specified string to the end of this StringBuffer.542*543* @param string the string544* @return this StringBuffer545*/546public synchronized StringBuffer append (String string) {547if (string == null) {548string = "null"; //$NON-NLS-1$549}550551int currentLength = lengthInternalUnsynchronized();552int currentCapacity = capacityInternal();553554int stringLength = string.lengthInternal();555556int newLength = currentLength + stringLength;557if (newLength < 0) {558/*[MSG "K0D01", "Array capacity exceeded"]*/559throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$560}561562if (String.COMPACT_STRINGS) {563// Check if the StringBuffer is compressed564if (count >= 0 && string.isCompressed ()) {565if (newLength > currentCapacity) {566ensureCapacityImpl(newLength);567}568569string.getBytes(0, stringLength, value, currentLength);570571count = newLength;572} else {573// Check if the StringBuffer is compressed574if (count >= 0) {575decompress(newLength);576}577578if (newLength > currentCapacity) {579ensureCapacityImpl(newLength);580}581582string.getCharsNoBoundChecks(0, stringLength, value, currentLength);583584count = newLength | uncompressedBit;585}586} else {587if (newLength > currentCapacity) {588ensureCapacityImpl(newLength);589}590591string.getCharsNoBoundChecks(0, stringLength, value, currentLength);592593count = newLength;594}595596return this;597}598599/**600* Adds the string representation of the specified boolean to the601* end of this StringBuffer.602*603* @param value the boolean604* @return this StringBuffer605*/606public StringBuffer append (boolean value) {607return append (String.valueOf (value));608}609610/**611* Answers the number of characters this StringBuffer can hold without612* growing.613*614* @return the capacity of this StringBuffer615*616* @see #ensureCapacity617* @see #length618*/619public int capacity() {620return capacityInternal();621}622623/**624* Answers the number of characters this StringBuffer can hold without growing. This method is to be used internally625* within the current package whenever possible as the JIT compiler will take special precaution to avoid generating626* HCR guards for calls to this method.627*628* @return the capacity of this StringBuffer629*630* @see #ensureCapacity631* @see #length632*/633int capacityInternal() {634return capacity & ~sharedBit;635}636637/**638* Answers the character at the specified offset in this StringBuffer.639*640* @param index the zero-based index in this StringBuffer641* @return the character at the index642*643* @exception IndexOutOfBoundsException644* If {@code index < 0} or {@code index >= length()}645*/646@Override647public synchronized char charAt(int index) {648int currentLength = lengthInternalUnsynchronized();649650if (index >= 0 && index < currentLength) {651// Check if the StringBuffer is compressed652if (String.COMPACT_STRINGS && count >= 0) {653return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));654} else {655return value[index];656}657}658659throw new StringIndexOutOfBoundsException(index);660}661662/**663* Deletes a range of characters.664*665* @param start the offset of the first character666* @param end the offset one past the last character667* @return this StringBuffer668*669* @exception StringIndexOutOfBoundsException when {@code start < 0, start > end} or670* {@code end > length()}671*/672public synchronized StringBuffer delete(int start, int end) {673int currentLength = lengthInternalUnsynchronized();674675if (start >= 0) {676if (end > currentLength) {677end = currentLength;678}679680if (end > start) {681int numberOfTailChars = currentLength - end;682683try {684// Check if the StringBuffer is not shared685if (capacity >= 0) {686if (numberOfTailChars > 0) {687// Check if the StringBuffer is compressed688if (String.COMPACT_STRINGS && count >= 0) {689String.compressedArrayCopy(value, end, value, start, numberOfTailChars);690} else {691String.decompressedArrayCopy(value, end, value, start, numberOfTailChars);692}693}694} else {695char[] newData = new char[value.length];696697// Check if the StringBuffer is compressed698if (String.COMPACT_STRINGS && count >= 0) {699if (start > 0) {700String.compressedArrayCopy(value, 0, newData, 0, start);701}702703if (numberOfTailChars > 0) {704String.compressedArrayCopy(value, end, newData, start, numberOfTailChars);705}706} else {707if (start > 0) {708String.decompressedArrayCopy(value, 0, newData, 0, start);709}710711if (numberOfTailChars > 0) {712String.decompressedArrayCopy(value, end, newData, start, numberOfTailChars);713}714}715716value = newData;717718capacity = capacity & ~sharedBit;719}720} catch (IndexOutOfBoundsException e) {721throw new StringIndexOutOfBoundsException();722}723724if (String.COMPACT_STRINGS) {725// Check if the StringBuffer is compressed726if (count >= 0) {727count = currentLength - (end - start);728} else {729count = (currentLength - (end - start)) | uncompressedBit;730731String.initCompressionFlag();732}733} else {734count = currentLength - (end - start);735}736737return this;738}739740if (start == end) {741return this;742}743}744745throw new StringIndexOutOfBoundsException();746}747748/**749* Deletes a single character750*751* @param location the offset of the character to delete752* @return this StringBuffer753*754* @exception StringIndexOutOfBoundsException when {@code location < 0} or755* {@code location >= length()}756*/757public synchronized StringBuffer deleteCharAt(int location) {758int currentLength = lengthInternalUnsynchronized();759760if (currentLength != 0) {761return delete (location, location + 1);762} else {763throw new StringIndexOutOfBoundsException ();764}765}766767/**768* Ensures that this StringBuffer can hold the specified number of characters769* without growing.770*771* @param min the minimum number of elements that this772* StringBuffer will hold before growing773*/774public synchronized void ensureCapacity(int min) {775int currentCapacity = capacityInternal();776777if (min > currentCapacity) {778ensureCapacityImpl(min);779}780}781782private void ensureCapacityImpl(int min) {783int currentLength = lengthInternalUnsynchronized();784int currentCapacity = capacityInternal();785786int newCapacity = (currentCapacity << 1) + 2;787788if (growAggressively && (newCapacity < currentCapacity)) {789newCapacity = Integer.MAX_VALUE;790}791792int newLength = min > newCapacity ? min : newCapacity;793794// Check if the StringBuilder is compressed795if (String.COMPACT_STRINGS && count >= 0) {796char[] newData = new char[(newLength + 1) >>> 1];797798String.compressedArrayCopy(value, 0, newData, 0, currentLength);799800value = newData;801} else {802char[] newData = new char[newLength];803804String.decompressedArrayCopy(value, 0, newData, 0, currentLength);805value = newData;806}807808capacity = newLength;809}810811/**812* Copies the specified characters in this StringBuffer to the character array813* starting at the specified offset in the character array.814*815* @param start the starting offset of characters to copy816* @param end the ending offset of characters to copy817* @param buffer the destination character array818* @param index the starting offset in the character array819*820* @exception IndexOutOfBoundsException when {@code start < 0, end > length(),821* start > end, index < 0, end - start > buffer.length - index}822* @exception NullPointerException when buffer is null823*/824public synchronized void getChars(int start, int end, char[] buffer, int index) {825try {826int currentLength = lengthInternalUnsynchronized();827828if (start <= currentLength && end <= currentLength) {829// Note that we must explicitly check all the conditions because we are not using System.arraycopy which would830// have implicitly checked these conditions831if (start >= 0 && start <= end && index >= 0 && end - start <= buffer.length - index) {832// Check if the StringBuffer is compressed833if (String.COMPACT_STRINGS && count >= 0) {834String.decompress(value, start, buffer, index, end - start);835836return;837} else {838System.arraycopy(value, start, buffer, index, end - start);839840return;841}842}843}844} catch(IndexOutOfBoundsException e) {845// Void846}847848throw new StringIndexOutOfBoundsException ();849}850851/**852* Inserts the character array at the specified offset in this StringBuffer.853*854* @param index the index at which to insert855* @param chars the character array to insert856* @return this StringBuffer857*858* @exception StringIndexOutOfBoundsException when {@code index < 0} or859* {@code index > length()}860* @exception NullPointerException when chars is null861*/862public synchronized StringBuffer insert(int index, char[] chars) {863int currentLength = lengthInternalUnsynchronized();864865if (0 <= index && index <= currentLength) {866move(chars.length, index);867868if (String.COMPACT_STRINGS) {869// Check if the StringBuffer is compressed870if (count >= 0 && String.canEncodeAsLatin1(chars, 0, chars.length)) {871String.compress(chars, 0, value, index, chars.length);872873count = currentLength + chars.length;874875return this;876} else {877// Check if the StringBuffer is compressed878if (count >= 0) {879decompress(value.length);880}881882String.decompressedArrayCopy(chars, 0, value, index, chars.length);883884count = (currentLength + chars.length) | uncompressedBit;885886return this;887}888} else {889String.decompressedArrayCopy(chars, 0, value, index, chars.length);890891count = currentLength + chars.length;892893return this;894}895} else {896throw new StringIndexOutOfBoundsException(index);897}898}899900/**901* Inserts the specified sequence of characters at the902* specified offset in this StringBuffer.903*904* @param index the index at which to insert905* @param chars a character array906* @param start the starting offset907* @param length the number of characters908* @return this StringBuffer909*910* @exception StringIndexOutOfBoundsException when {@code length < 0, start < 0,911* start + length > chars.length, index < 0} or912* {@code index > length()}913* @exception NullPointerException when chars is null914*/915public synchronized StringBuffer insert(int index, char[] chars, int start, int length) {916int currentLength = lengthInternalUnsynchronized();917918if (0 <= index && index <= currentLength) {919if (start >= 0 && 0 <= length && length <= chars.length - start) {920move(length, index);921922if (String.COMPACT_STRINGS) {923// Check if the StringBuffer is compressed924if (count >= 0 && String.canEncodeAsLatin1(chars, start, length)) {925String.compress(chars, start, value, index, length);926927count = currentLength + length;928929return this;930} else {931// Check if the StringBuffer is compressed932if (count >= 0) {933decompress(value.length);934}935936String.decompressedArrayCopy(chars, start, value, index, length);937938count = (currentLength + length) | uncompressedBit;939940return this;941}942} else {943String.decompressedArrayCopy(chars, start, value, index, length);944945count = currentLength + length;946947return this;948}949} else {950throw new StringIndexOutOfBoundsException();951}952} else {953throw new StringIndexOutOfBoundsException(index);954}955}956957synchronized StringBuffer insert(int index, char[] chars, int start, int length, boolean compressed) {958int currentLength = lengthInternalUnsynchronized();959960move(length, index);961962if (String.COMPACT_STRINGS) {963// Check if the StringBuffer is compressed964if (count >= 0 && compressed) {965String.compressedArrayCopy(chars, start, value, index, length);966967count = currentLength + length;968969return this;970} else {971if (count >= 0) {972decompress(value.length);973}974975String.decompressedArrayCopy(chars, start, value, index, length);976977count = (currentLength + length) | uncompressedBit;978979return this;980}981} else {982String.decompressedArrayCopy(chars, start, value, index, length);983984count = currentLength + length;985986return this;987}988}989990/**991* Inserts the character at the specified offset in this StringBuffer.992*993* @param index the index at which to insert994* @param ch the character to insert995* @return this StringBuffer996*997* @exception IndexOutOfBoundsException when {@code index < 0} or998* {@code index > length()}999*/1000public synchronized StringBuffer insert(int index, char ch) {1001int currentLength = lengthInternalUnsynchronized();10021003if (0 <= index && index <= currentLength) {1004move(1, index);10051006if (String.COMPACT_STRINGS ) {1007// Check if the StringBuffer is compressed1008if (count >= 0 && ch <= 255) {1009helpers.putByteInArrayByIndex(value, index, (byte) ch);10101011count = currentLength + 1;10121013return this;1014} else {1015// Check if the StringBuffer is compressed1016if (count >= 0) {1017decompress(value.length);1018}10191020value[index] = ch;10211022count = (currentLength + 1) | uncompressedBit;10231024return this;1025}1026} else {1027value[index] = ch;10281029count = currentLength + 1;10301031return this;1032}1033} else {1034throw new StringIndexOutOfBoundsException(index);1035}1036}10371038/**1039* Inserts the string representation of the specified double at the specified1040* offset in this StringBuffer.1041*1042* @param index the index at which to insert1043* @param value the double to insert1044* @return this StringBuffer1045*1046* @exception StringIndexOutOfBoundsException when {@code index < 0} or1047* {@code index > length()}1048*/1049public StringBuffer insert(int index, double value) {1050return insert(index, String.valueOf(value));1051}10521053/**1054* Inserts the string representation of the specified float at the specified1055* offset in this StringBuffer.1056*1057* @param index the index at which to insert1058* @param value the float to insert1059* @return this StringBuffer1060*1061* @exception StringIndexOutOfBoundsException when {@code index < 0} or1062* {@code index > length()}1063*/1064public StringBuffer insert(int index, float value) {1065return insert(index, String.valueOf(value));1066}10671068/**1069* Inserts the string representation of the specified integer at the specified1070* offset in this StringBuffer.1071*1072* @param index the index at which to insert1073* @param value the integer to insert1074* @return this StringBuffer1075*1076* @exception StringIndexOutOfBoundsException when {@code index < 0} or1077* {@code index > length()}1078*/1079public StringBuffer insert(int index, int value) {1080return insert(index, Integer.toString(value));1081}10821083/**1084* Inserts the string representation of the specified long at the specified1085* offset in this StringBuffer.1086*1087* @param index the index at which to insert1088* @param value the long to insert1089* @return this StringBuffer1090*1091* @exception StringIndexOutOfBoundsException when {@code index < 0} or1092* {@code index > length()}1093*/1094public StringBuffer insert(int index, long value) {1095return insert(index, Long.toString(value));1096}10971098/**1099* Inserts the string representation of the specified object at the specified1100* offset in this StringBuffer.1101*1102* @param index the index at which to insert1103* @param value the object to insert1104* @return this StringBuffer1105*1106* @exception StringIndexOutOfBoundsException when {@code index < 0} or1107* {@code index > length()}1108*/1109public StringBuffer insert(int index, Object value) {1110return insert(index, String.valueOf(value));1111}11121113/**1114* Inserts the string at the specified offset in this StringBuffer.1115*1116* @param index the index at which to insert1117* @param string the string to insert1118* @return this StringBuffer1119*1120* @exception StringIndexOutOfBoundsException when {@code index < 0} or1121* {@code index > length()}1122*/1123public synchronized StringBuffer insert(int index, String string) {1124int currentLength = lengthInternalUnsynchronized();11251126if (0 <= index && index <= currentLength) {1127if (string == null) {1128string = "null"; //$NON-NLS-1$1129}11301131int stringLength = string.lengthInternal();11321133move(stringLength, index);11341135if (String.COMPACT_STRINGS) {1136// Check if the StringBuffer is compressed1137if (count >= 0 && string.isCompressed()) {1138string.getBytes(0, stringLength, value, index);11391140count = currentLength + stringLength;11411142return this;1143} else {1144// Check if the StringBuffer is compressed1145if (count >= 0) {1146decompress(value.length);1147}11481149string.getCharsNoBoundChecks(0, stringLength, value, index);11501151count = (currentLength + stringLength) | uncompressedBit;11521153return this;1154}1155} else {1156string.getCharsNoBoundChecks(0, stringLength, value, index);11571158count = currentLength + stringLength;11591160return this;1161}1162} else {1163throw new StringIndexOutOfBoundsException(index);1164}1165}11661167/**1168* Inserts the string representation of the specified boolean at the specified1169* offset in this StringBuffer.1170*1171* @param index the index at which to insert1172* @param value the boolean to insert1173* @return this StringBuffer1174*1175* @exception StringIndexOutOfBoundsException when {@code index < 0} or1176* {@code index > length()}1177*/1178public StringBuffer insert(int index, boolean value) {1179return insert(index, String.valueOf(value));1180}11811182/**1183* Answers the size of this StringBuffer.1184*1185* @return the number of characters in this StringBuffer1186*/1187@Override1188public synchronized int length() {1189return lengthInternalUnsynchronized();1190}11911192/**1193* Answers the size of this StringBuffer. This is an unsynchronized private method and is meant to be called only1194* from methods of this class which have already synchronized on the this StringBuffer object.1195*1196* The JIT compiler will take special precaution to avoid generating HCR guards for calls to this method.1197* @return the number of characters in this StringBuffer1198*/1199private int lengthInternalUnsynchronized() {1200if (String.COMPACT_STRINGS) {1201// Check if the StringBuffer is compressed1202if (count >= 0) {1203return count;1204} else {1205return count & ~uncompressedBit;1206}1207} else {1208return count;1209}1210}12111212private void move(int size, int index) {1213int currentLength = lengthInternalUnsynchronized();1214int currentCapacity = capacityInternal();12151216// Check if the StringBuffer is compressed1217if (String.COMPACT_STRINGS && count >= 0) {1218int newLength;12191220if (currentCapacity - currentLength >= size) {1221// Check if the StringBuffer is not shared1222if (capacity >= 0) {1223String.compressedArrayCopy(value, index, value, index + size, currentLength - index);12241225return;1226}12271228newLength = currentCapacity;1229} else {1230newLength = Integer.max(currentLength + size, (currentCapacity << 1) + 2);1231if (newLength < 0) {1232/*[MSG "K0D01", "Array capacity exceeded"]*/1233throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$1234}1235}12361237char[] newData = new char[(newLength + 1) >>> 1];12381239String.compressedArrayCopy(value, 0, newData, 0, index);1240String.compressedArrayCopy(value, index, newData, index + size, currentLength - index);12411242value = newData;12431244capacity = newLength;1245} else {1246int newLength;12471248if (currentCapacity - currentLength >= size) {1249// Check if the StringBuffer is not shared1250if (capacity >= 0) {1251String.decompressedArrayCopy(value, index, value, index + size, currentLength - index);1252return;1253}12541255newLength = currentCapacity;1256} else {1257newLength = Integer.max(currentLength + size, (currentCapacity << 1) + 2);1258if (newLength < 0) {1259/*[MSG "K0D01", "Array capacity exceeded"]*/1260throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$1261}1262}12631264char[] newData = new char[newLength];12651266String.decompressedArrayCopy(value, 0, newData, 0, index);1267String.decompressedArrayCopy(value, index, newData, index + size, currentLength - index);12681269value = newData;12701271capacity = newLength;1272}1273}12741275/**1276* Replace a range of characters with the characters in the specified String.1277*1278* @param start the offset of the first character1279* @param end the offset one past the last character1280* @param string a String1281* @return this StringBuffer1282*1283* @exception StringIndexOutOfBoundsException when {@code start < 0} or1284* {@code start > end}1285*/1286public synchronized StringBuffer replace(int start, int end, String string) {1287int currentLength = lengthInternalUnsynchronized();12881289if (String.COMPACT_STRINGS) {1290// Check if the StringBuffer is compressed1291if (count >= 0 && string.isCompressed()) {1292if (start >= 0) {1293if (end > currentLength) {1294end = currentLength;1295}12961297if (end > start) {1298int size = string.lengthInternal();12991300// Difference between the substring we wish to replace and the size of the string parameter1301int difference = end - start - size;13021303if (difference > 0) {1304// Check if the StringBuffer is not shared1305if (capacity >= 0) {1306String.compressedArrayCopy(value, end, value, start + size, currentLength - end);1307} else {1308char[] newData = new char[value.length];13091310String.compressedArrayCopy(value, 0, newData, 0, start);1311String.compressedArrayCopy(value, end, newData, start + size, currentLength - end);13121313value = newData;13141315capacity = capacity & ~sharedBit;1316}1317} else if (difference < 0) {1318move(-difference, end);1319} else if (capacity < 0) {1320value = value.clone();13211322capacity = capacity & ~sharedBit;1323}13241325string.getBytes(0, size, value, start);13261327count = currentLength - difference;13281329return this;1330}13311332if (start == end) {1333return insert(start, string);1334}1335}1336} else {1337// Check if the StringBuffer is compressed1338if (count >= 0) {1339decompress(value.length);1340}13411342if (start >= 0) {1343if (end > currentLength) {1344end = currentLength;1345}13461347if (end > start) {1348int size = string.lengthInternal();13491350// Difference between the substring we wish to replace and the size of the string parameter1351int difference = end - start - size;13521353if (difference > 0) {1354// Check if the StringBuffer is not shared1355if (capacity >= 0) {1356String.decompressedArrayCopy(value, end, value, start + size, currentLength - end);1357} else {1358char[] newData = new char[value.length];13591360String.decompressedArrayCopy(value, 0, newData, 0, start);1361String.decompressedArrayCopy(value, end, newData, start + size, currentLength - end);13621363value = newData;13641365capacity = capacity & ~sharedBit;1366}1367} else if (difference < 0) {1368move(-difference, end);1369} else if (capacity < 0) {1370value = value.clone();13711372capacity = capacity & ~sharedBit;1373}13741375string.getCharsNoBoundChecks(0, size, value, start);13761377count = (currentLength - difference) | uncompressedBit;13781379return this;1380}13811382if (start == end) {1383string.getClass(); // Implicit null check13841385return insert(start, string);1386}1387}1388}1389} else {1390if (start >= 0) {1391if (end > currentLength) {1392end = currentLength;1393}13941395if (end > start) {1396int size = string.lengthInternal();13971398// Difference between the substring we wish to replace and the size of the string parameter1399int difference = end - start - size;14001401if (difference > 0) {1402// Check if the StringBuffer is not shared1403if (capacity >= 0) {1404String.decompressedArrayCopy(value, end, value, start + size, currentLength - end);1405} else {1406char[] newData = new char[value.length];14071408String.decompressedArrayCopy(value, 0, newData, 0, start);1409String.decompressedArrayCopy(value, end, newData, start + size, currentLength - end);1410value = newData;14111412capacity = capacity & ~sharedBit;1413}1414} else if (difference < 0) {1415move(-difference, end);1416} else if (capacity < 0) {1417value = value.clone();14181419capacity = capacity & ~sharedBit;1420}14211422string.getCharsNoBoundChecks(0, size, value, start);14231424count = currentLength - difference;14251426return this;1427}14281429if (start == end) {1430string.getClass(); // Implicit null check14311432return insert(start, string);1433}1434}1435}14361437throw new StringIndexOutOfBoundsException();1438}14391440/**1441* Reverses the order of characters in this StringBuffer.1442*1443* @return this StringBuffer1444*/1445public synchronized StringBuffer reverse() {1446int currentLength = lengthInternalUnsynchronized();14471448if (currentLength < 2) {1449return this;1450}14511452// Check if the StringBuffer is compressed1453if (String.COMPACT_STRINGS && count >= 0) {1454// Check if the StringBuffer is not shared1455if (capacity >= 0) {1456for (int i = 0, mid = currentLength / 2, j = currentLength - 1; i < mid; ++i, --j) {1457byte a = helpers.getByteFromArrayByIndex(value, i);1458byte b = helpers.getByteFromArrayByIndex(value, j);14591460helpers.putByteInArrayByIndex(value, i, b);1461helpers.putByteInArrayByIndex(value, j, a);1462}14631464return this;1465} else {1466char[] newData = new char[value.length];14671468for (int i = 0, j = currentLength - 1; i < currentLength; ++i, --j) {1469helpers.putByteInArrayByIndex(newData, j, helpers.getByteFromArrayByIndex(value, i));1470}14711472value = newData;14731474capacity = capacity & ~sharedBit;14751476return this;1477}1478} else {1479// Check if the StringBuffer is not shared1480if (capacity >= 0) {1481int end = currentLength - 1;14821483char frontHigh = value[0];1484char endLow = value[end];1485boolean allowFrontSur = true, allowEndSur = true;1486for (int i = 0, mid = currentLength / 2; i < mid; i++, --end) {1487char frontLow = value[i + 1];1488char endHigh = value[end - 1];1489boolean surAtFront = false, surAtEnd = false;1490if (allowFrontSur && frontLow >= Character.MIN_LOW_SURROGATE && frontLow <= Character.MAX_LOW_SURROGATE && frontHigh >= Character.MIN_HIGH_SURROGATE && frontHigh <= Character.MAX_HIGH_SURROGATE) {1491surAtFront = true;1492if (currentLength < 3) return this;1493}1494if (allowEndSur && endHigh >= Character.MIN_HIGH_SURROGATE && endHigh <= Character.MAX_HIGH_SURROGATE && endLow >= Character.MIN_LOW_SURROGATE && endLow <= Character.MAX_LOW_SURROGATE) {1495surAtEnd = true;1496}1497allowFrontSur = true;1498allowEndSur = true;1499if (surAtFront == surAtEnd) {1500if (surAtFront) {1501// both surrogates1502value[end] = frontLow;1503value[end - 1] = frontHigh;1504value[i] = endHigh;1505value[i + 1] = endLow;1506frontHigh = value[i + 2];1507endLow = value[end - 2];1508i++;1509--end;1510} else {1511// neither surrogates1512value[end] = frontHigh;1513value[i] = endLow;1514frontHigh = frontLow;1515endLow = endHigh;1516}1517} else {1518if (surAtFront) {1519// surrogate only at the front1520value[end] = frontLow;1521value[i] = endLow;1522endLow = endHigh;1523allowFrontSur = false;1524} else {1525// surrogate only at the end1526value[end] = frontHigh;1527value[i] = endHigh;1528frontHigh = frontLow;1529allowEndSur = false;1530}1531}1532}1533if ((currentLength & 1) == 1 && (!allowFrontSur || !allowEndSur)) {1534value[end] = allowFrontSur ? endLow : frontHigh;1535}1536} else {1537char[] newData = new char[value.length];15381539for (int i = 0, end = currentLength; i < currentLength; i++) {1540char high = value[i];15411542if ((i + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {1543char low = value[i + 1];15441545if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {1546newData[--end] = low;1547i++;1548}1549}1550newData[--end] = high;1551}15521553value = newData;15541555capacity = capacity & ~sharedBit;1556}15571558return this;1559}1560}15611562/**1563* Sets the character at the specified offset in this StringBuffer.1564*1565* @param index the zero-based index in this StringBuffer1566* @param ch the character1567*1568* @exception IndexOutOfBoundsException when {@code index < 0} or1569* {@code index >= length()}1570*/1571public synchronized void setCharAt(int index, char ch) {1572int currentLength = lengthInternalUnsynchronized();15731574if (0 <= index && index < currentLength) {1575if (String.COMPACT_STRINGS) {1576// Check if the StringBuffer is compressed1577if (count >= 0 && ch <= 255) {1578if (capacity < 0) {1579value = value.clone();15801581capacity = capacity & ~sharedBit;1582}15831584helpers.putByteInArrayByIndex(value, index, (byte) ch);1585} else {1586// Check if the StringBuffer is compressed1587if (count >= 0) {1588decompress(value.length);1589}15901591if (capacity < 0) {1592value = value.clone();15931594capacity = capacity & ~sharedBit;1595}15961597value[index] = ch;1598}1599} else {1600if (capacity < 0) {1601value = value.clone();16021603capacity = capacity & ~sharedBit;1604}16051606value[index] = ch;1607}1608} else {1609throw new StringIndexOutOfBoundsException(index);1610}1611}16121613/**1614* Sets the length of this StringBuffer to the specified length. If there1615* are more than length characters in this StringBuffer, the characters1616* at end are lost. If there are less than length characters in the1617* StringBuffer, the additional characters are set to {@code \\u0000}.1618*1619* @param length the new length of this StringBuffer1620*1621* @exception IndexOutOfBoundsException when {@code length < 0}1622*1623* @see #length1624*/1625public synchronized void setLength(int length) {1626int currentLength = lengthInternalUnsynchronized();1627int currentCapacity = capacityInternal();16281629// Check if the StringBuffer is compressed1630if (String.COMPACT_STRINGS && count >= 0) {1631if (length > currentCapacity) {1632ensureCapacityImpl(length);1633} else if (length > currentLength) {1634for (int i = currentLength; i < length; ++i) {1635helpers.putByteInArrayByIndex(value, i, (byte) 0);1636}1637} else if (capacity < 0) {1638if (length < 0) {1639throw new IndexOutOfBoundsException();1640}16411642char[] newData = new char[value.length];16431644if (length > 0) {1645String.compressedArrayCopy(value, 0, newData, 0, length);1646}16471648value = newData;16491650capacity = capacity & ~sharedBit;1651} else if (length < 0) {1652throw new IndexOutOfBoundsException();1653}1654} else {1655if (length > currentCapacity) {1656ensureCapacityImpl(length);1657} else if (length > currentLength) {1658Arrays.fill(value, currentLength, length, (char) 0);1659} else if (capacity < 0) {1660if (length < 0) {1661throw new IndexOutOfBoundsException();1662}16631664char[] newData = new char[value.length];16651666if (length > 0) {1667String.decompressedArrayCopy(value, 0, newData, 0, length);1668}16691670value = newData;16711672capacity = capacity & ~sharedBit;1673} else if (length < 0) {1674throw new IndexOutOfBoundsException();1675}1676}16771678if (String.COMPACT_STRINGS) {1679// Check if the StringBuffer is compressed1680if (count >= 0) {1681count = length;1682} else {1683count = length | uncompressedBit;1684}1685} else {1686count = length;1687}1688}16891690/**1691* Copies a range of characters into a new String.1692*1693* @param start the offset of the first character1694* @return a new String containing the characters from start to the end1695* of the string1696*1697* @exception StringIndexOutOfBoundsException when {@code start < 0} or1698* {@code start > length()}1699*/1700public synchronized String substring(int start) {1701int currentLength = lengthInternalUnsynchronized();17021703// Check if the StringBuffer is compressed1704if (String.COMPACT_STRINGS && count >= 0) {1705if (0 <= start && start <= currentLength) {1706return new String(value, start, currentLength - start, true, false);1707}1708} else {1709if (0 <= start && start <= currentLength) {1710return new String(value, start, currentLength - start, false, false);1711}1712}17131714throw new StringIndexOutOfBoundsException(start);1715}17161717/**1718* Copies a range of characters into a new String.1719*1720* @param start the offset of the first character1721* @param end the offset one past the last character1722* @return a new String containing the characters from start to end - 11723*1724* @exception StringIndexOutOfBoundsException when {@code start < 0, start > end} or1725* {@code end > length()}1726*/1727public synchronized String substring(int start, int end) {1728int currentLength = lengthInternalUnsynchronized();17291730// Check if the StringBuffer is compressed1731if (String.COMPACT_STRINGS && count >= 0) {1732if (0 <= start && start <= end && end <= currentLength) {1733return new String(value, start, end - start, true, false);1734}1735} else {1736if (0 <= start && start <= end && end <= currentLength) {1737return new String(value, start, end - start, false, false);1738}1739}17401741throw new StringIndexOutOfBoundsException();1742}17431744static void initFromSystemProperties(Properties props) {1745String prop = props.getProperty("java.lang.string.create.unique"); //$NON-NLS-1$1746TOSTRING_COPY_BUFFER_ENABLED = "true".equals(prop) || "StringBuffer".equals(prop); //$NON-NLS-1$ //$NON-NLS-2$17471748// growAggressively by default1749String growAggressivelyProperty = props.getProperty("java.lang.stringBuffer.growAggressively", ""); //$NON-NLS-1$ //$NON-NLS-2$1750growAggressively = "".equals(growAggressivelyProperty) || Boolean.parseBoolean(growAggressivelyProperty); //$NON-NLS-1$1751}17521753/**1754* Answers the contents of this StringBuffer.1755*1756* @return a String containing the characters in this StringBuffer1757*/1758@Override1759public synchronized String toString () {1760int currentLength = lengthInternalUnsynchronized();1761int currentCapacity = capacityInternal();17621763if (false == TOSTRING_COPY_BUFFER_ENABLED) {1764int wasted = currentCapacity - currentLength;1765if (wasted >= 768 || (wasted >= INITIAL_SIZE && wasted >= (currentCapacity >> 1))) {1766// Check if the StringBuffer is compressed1767if (String.COMPACT_STRINGS && count >= 0) {1768return new String (value, 0, currentLength, true, false);1769} else {1770return new String (value, 0, currentLength, false, false);1771}1772}1773} else {1774// Do not copy the char[] if it will not get smaller because of object alignment1775int roundedCount = (currentLength + 3) & ~3;1776if (roundedCount < currentCapacity) {1777// Check if the StringBuffer is compressed1778if (String.COMPACT_STRINGS && count >= 0) {1779return new String (value, 0, currentLength, true, false);1780} else {1781return new String (value, 0, currentLength, false, false);1782}1783}1784}17851786capacity = capacity | sharedBit;17871788// Check if the StringBuffer is compressed1789if (String.COMPACT_STRINGS && count >= 0) {1790return new String (value, 0, currentLength, true);1791} else {1792return new String (value, 0, currentLength, false);1793}1794}17951796private synchronized void writeObject(ObjectOutputStream stream) throws IOException {1797int currentLength = lengthInternalUnsynchronized();17981799ObjectOutputStream.PutField pf = stream.putFields();18001801pf.put("count", currentLength); //$NON-NLS-1$18021803// Check if the StringBuffer is compressed1804if (String.COMPACT_STRINGS && count >= 0) {1805char[] newData = new char[currentLength];18061807String.decompress(value, 0, newData, 0, currentLength);18081809pf.put("value", newData); //$NON-NLS-1$1810} else {1811pf.put("value", value); //$NON-NLS-1$1812}18131814pf.put("shared", false); //$NON-NLS-1$18151816stream.writeFields();1817}18181819private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {1820ObjectInputStream.GetField gf = stream.readFields();1821int streamCount = gf.get("count", 0); //$NON-NLS-1$1822char[] streamValue = (char[]) gf.get("value", null); //$NON-NLS-1$18231824if ((streamCount < 0) || (streamCount > streamValue.length)) {1825/*[MSG "K0199", "count value invalid"]*/1826throw new StreamCorruptedException(com.ibm.oti.util.Msg.getString("K0199")); //$NON-NLS-1$1827}1828if (String.COMPACT_STRINGS) {1829if (String.canEncodeAsLatin1(streamValue, 0, streamValue.length)) {1830value = new char[(streamValue.length + 1) >>> 1];1831String.compress(streamValue, 0, value, 0, streamValue.length);1832count = streamCount;1833capacity = streamValue.length;1834} else {1835value = new char[streamValue.length];1836System.arraycopy(streamValue, 0, value, 0, streamValue.length);1837count = streamCount | uncompressedBit;1838capacity = streamValue.length;1839String.initCompressionFlag();1840}1841} else {1842value = new char[streamValue.length];1843System.arraycopy(streamValue, 0, value, 0, streamValue.length);1844count = streamCount;1845capacity = streamValue.length;1846}1847}18481849/**1850* Adds the specified StringBuffer to the end of this StringBuffer.1851*1852* @param buffer the StringBuffer1853* @return this StringBuffer1854*1855* @since 1.41856*/1857public synchronized StringBuffer append(StringBuffer buffer) {1858if (buffer == null) {1859return append((String)null);1860} else {1861synchronized (buffer) {1862// Check if the StringBuffer is compressed1863if (String.COMPACT_STRINGS && buffer.count >= 0) {1864return append(buffer.value, 0, buffer.lengthInternalUnsynchronized(), true);1865} else {1866return append(buffer.value, 0, buffer.lengthInternalUnsynchronized(), false);1867}1868}1869}1870}18711872/**1873* Copies a range of characters into a new String.1874*1875* @param start the offset of the first character1876* @param end the offset one past the last character1877* @return a new String containing the characters from start to end - 11878*1879* @exception IndexOutOfBoundsException when {@code start < 0, start > end} or1880* {@code end > length()}1881*1882* @since 1.41883*/1884@Override1885public CharSequence subSequence(int start, int end) {1886return substring(start, end);1887}18881889/**1890* Searches in this StringBuffer for the first index of the specified character. The1891* search for the character starts at the beginning and moves towards the1892* end.1893*1894* @param string the string to find1895* @return the index in this StringBuffer of the specified character, -1 if the1896* character isn't found1897*1898* @see #lastIndexOf(String)1899*1900* @since 1.41901*/1902public int indexOf(String string) {1903return indexOf(string, 0);1904}19051906/**1907* Searches in this StringBuffer for the index of the specified character. The1908* search for the character starts at the specified offset and moves towards1909* the end.1910*1911* @param subString the string to find1912* @param start the starting offset1913* @return the index in this StringBuffer of the specified character, -1 if the1914* character isn't found1915*1916* @see #lastIndexOf(String,int)1917*1918* @since 1.41919*/1920public synchronized int indexOf(String subString, int start) {1921int currentLength = lengthInternalUnsynchronized();19221923if (start < 0) {1924start = 0;1925}19261927int subStringLength = subString.lengthInternal();19281929if (subStringLength > 0) {1930if (subStringLength + start > currentLength) {1931return -1;1932}19331934char firstChar = subString.charAtInternal(0);19351936// Check if the StringBuffer is compressed1937if (String.COMPACT_STRINGS && count >= 0) {1938if (!subString.isCompressed()) {1939return -1;1940}19411942while (true) {1943int i = start;19441945boolean found = false;19461947for (; i < currentLength; ++i) {1948if (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i)) == firstChar) {1949found = true;1950break;1951}1952}19531954// Handles subStringLength > currentLength || start >= currentLength1955if (!found || subStringLength + i > currentLength) {1956return -1;1957}19581959int o1 = i;1960int o2 = 0;19611962while (++o2 < subStringLength && helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, ++o1)) == subString.charAtInternal(o2))1963;19641965if (o2 == subStringLength) {1966return i;1967}19681969start = i + 1;1970}1971} else {1972while (true) {1973int i = start;19741975boolean found = false;19761977for (; i < currentLength; ++i) {1978if (value[i] == firstChar) {1979found = true;1980break;1981}1982}19831984// Handles subStringLength > currentLength || start >= currentLength1985if (!found || subStringLength + i > currentLength) {1986return -1;1987}19881989int o1 = i;1990int o2 = 0;19911992while (++o2 < subStringLength && value[++o1] == subString.charAtInternal(o2))1993;19941995if (o2 == subStringLength) {1996return i;1997}19981999start = i + 1;2000}2001}20022003} else {2004return (start < currentLength || start == 0) ? start : currentLength;2005}2006}20072008/**2009* Searches in this StringBuffer for the last index of the specified character. The2010* search for the character starts at the end and moves towards the beginning.2011*2012* @param string the string to find2013* @return the index in this StringBuffer of the specified character, -1 if the2014* character isn't found2015*2016* @see #indexOf(String)2017*2018* @since 1.42019*/2020public synchronized int lastIndexOf(String string) {2021int currentLength = lengthInternalUnsynchronized();20222023return lastIndexOf(string, currentLength);2024}20252026/**2027* Searches in this StringBuffer for the index of the specified character. The2028* search for the character starts at the specified offset and moves towards2029* the beginning.2030*2031* @param subString the string to find2032* @param start the starting offset2033* @return the index in this StringBuffer of the specified character, -1 if the2034* character isn't found2035*2036* @see #indexOf(String,int)2037*2038* @since 1.42039*/2040public synchronized int lastIndexOf(String subString, int start) {2041int currentLength = lengthInternalUnsynchronized();20422043int subStringLength = subString.lengthInternal();20442045if (subStringLength <= currentLength && start >= 0) {2046if (subStringLength > 0) {2047if (start > currentLength - subStringLength) {2048start = currentLength - subStringLength;2049}20502051char firstChar = subString.charAtInternal(0);20522053// Check if the StringBuffer is compressed2054if (String.COMPACT_STRINGS && count >= 0) {2055if (!subString.isCompressed()) {2056return -1;2057}20582059while (true) {2060int i = start;20612062boolean found = false;20632064for (; i >= 0; --i) {2065if (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i)) == firstChar) {2066found = true;2067break;2068}2069}20702071if (!found) {2072return -1;2073}20742075int o1 = i;2076int o2 = 0;20772078while (++o2 < subStringLength && helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, ++o1)) == subString.charAtInternal(o2))2079;20802081if (o2 == subStringLength) {2082return i;2083}20842085start = i - 1;2086}2087} else {2088while (true) {2089int i = start;20902091boolean found = false;20922093for (; i >= 0; --i) {2094if (value[i] == firstChar) {2095found = true;2096break;2097}2098}20992100if (!found) {2101return -1;2102}21032104int o1 = i;2105int o2 = 0;21062107while (++o2 < subStringLength && value[++o1] == subString.charAtInternal(o2))2108;21092110if (o2 == subStringLength) {2111return i;2112}21132114start = i - 1;2115}2116}2117} else {2118return start < currentLength ? start : currentLength;2119}2120} else {2121return -1;2122}2123}21242125/*2126* Return the underlying buffer and set the shared flag.2127*2128*/2129char[] shareValue() {2130capacity = capacity | sharedBit;21312132return value;2133}21342135boolean isCompressed() {2136// Check if the StringBuffer is compressed2137if (String.COMPACT_STRINGS && count >= 0) {2138return true;2139} else {2140return false;2141}2142}21432144/**2145* Constructs a new StringBuffer containing the characters in2146* the specified CharSequence and the default capacity.2147*2148* @param sequence the initial contents of this StringBuffer2149* @exception NullPointerException when sequence is null2150*2151* @since 1.52152*/2153public StringBuffer(CharSequence sequence) {2154int size = sequence.length();21552156if (size < 0) {2157size = 0;2158}21592160int newLength = INITIAL_SIZE + size;2161if (newLength < size) {2162newLength = size;2163}21642165if (String.COMPACT_STRINGS) {2166value = new char[(newLength + 1) >>> 1];2167} else {2168value = new char[newLength];2169}21702171capacity = newLength;21722173if (sequence instanceof String) {2174append((String)sequence);2175} else if (sequence instanceof StringBuffer) {2176append((StringBuffer)sequence);2177} else {2178if (String.COMPACT_STRINGS) {2179boolean isCompressed = true;21802181for (int i = 0; i < size; ++i) {2182if (sequence.charAt(i) > 255) {2183isCompressed = false;21842185break;2186}2187}21882189if (isCompressed) {2190count = size;21912192for (int i = 0; i < size; ++i) {2193helpers.putByteInArrayByIndex(value, i, (byte) sequence.charAt(i));2194}2195} else {2196value = new char[newLength];21972198count = size | uncompressedBit;21992200for (int i = 0; i < size; ++i) {2201value[i] = sequence.charAt(i);2202}22032204String.initCompressionFlag();2205}2206} else {2207count = size;22082209for (int i = 0; i < size; ++i) {2210value[i] = sequence.charAt(i);2211}2212}2213}2214}22152216/**2217* Adds the specified CharSequence to the end of this StringBuffer.2218*2219* @param sequence the CharSequence2220* @return this StringBuffer2221*2222* @since 1.52223*/2224@Override2225public synchronized StringBuffer append(CharSequence sequence) {2226if (sequence == null) {2227return append(String.valueOf(sequence));2228} else if (sequence instanceof String) {2229return append((String)sequence);2230} else if (sequence instanceof StringBuffer) {2231return append((StringBuffer)sequence);2232} else {2233int currentLength = lengthInternalUnsynchronized();2234int currentCapacity = capacityInternal();22352236int sequenceLength = sequence.length();22372238int newLength = currentLength + sequenceLength;2239if (newLength < 0) {2240/*[MSG "K0D01", "Array capacity exceeded"]*/2241throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$2242}22432244if (String.COMPACT_STRINGS) {2245boolean isCompressed = true;22462247if (count >= 0) {2248for (int i = 0; i < sequence.length(); ++i) {2249if (sequence.charAt(i) > 255) {2250isCompressed = false;22512252break;2253}2254}2255}22562257// Check if the StringBuffer is compressed2258if (count >= 0 && isCompressed) {2259if (newLength > currentCapacity) {2260ensureCapacityImpl(newLength);2261}22622263for (int i = 0; i < sequence.length(); ++i) {2264helpers.putByteInArrayByIndex(value, currentLength + i, (byte) sequence.charAt(i));2265}22662267count = newLength;2268} else {2269// Check if the StringBuffer is compressed2270if (count >= 0) {2271decompress(newLength);2272}22732274if (newLength > currentCapacity) {2275ensureCapacityImpl(newLength);2276}22772278for (int i = 0; i < sequence.length(); ++i) {2279value[currentLength + i] = sequence.charAt(i);2280}22812282count = newLength | uncompressedBit;2283}2284} else {2285if (newLength > currentCapacity) {2286ensureCapacityImpl(newLength);2287}22882289for (int i = 0; i < sequence.length(); ++i) {2290value[currentLength + i] = sequence.charAt(i);2291}22922293count = newLength;2294}22952296return this;2297}2298}22992300/**2301* Adds the specified CharSequence to the end of this StringBuffer.2302*2303* @param sequence the CharSequence2304* @param start the offset of the first character2305* @param end the offset one past the last character2306* @return this StringBuffer2307*2308* @exception IndexOutOfBoundsException when {@code start < 0, start > end} or2309* {@code end > length()}2310*2311* @since 1.52312*/2313@Override2314public synchronized StringBuffer append(CharSequence sequence, int start, int end) {2315if (sequence == null) {2316return append(String.valueOf(sequence), start, end);2317} else if (sequence instanceof String) {2318return append(((String)sequence).substring(start, end));2319} else if (start >= 0 && end >= 0 && start <= end && end <= sequence.length()) {2320if (sequence instanceof StringBuffer) {2321synchronized (sequence) {2322StringBuffer buffer = (StringBuffer) sequence;23232324// Check if the StringBuffer is compressed2325if (String.COMPACT_STRINGS && buffer.count >= 0) {2326return append(buffer.value, start, end - start, true);2327} else {2328return append(buffer.value, start, end - start, false);2329}2330}2331} else if (sequence instanceof StringBuilder) {2332synchronized (sequence) {2333StringBuilder builder = (StringBuilder) sequence;23342335if (String.COMPACT_STRINGS && builder.isCompressed()) {2336return append(builder.getValue(), start, end - start, true);2337} else {2338return append(builder.getValue(), start, end - start, false);2339}2340}2341} else {2342int currentLength = lengthInternalUnsynchronized();2343int currentCapacity = capacityInternal();23442345int newLength = currentLength + end - start;2346if (newLength < 0) {2347/*[MSG "K0D01", "Array capacity exceeded"]*/2348throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$2349}23502351if (String.COMPACT_STRINGS) {2352boolean isCompressed = true;23532354if (count >= 0) {2355for (int i = 0; i < sequence.length(); ++i) {2356if (sequence.charAt(i) > 255) {2357isCompressed = false;23582359break;2360}2361}2362}23632364// Check if the StringBuffer is compressed2365if (count >= 0 && isCompressed) {2366if (newLength > currentCapacity) {2367ensureCapacityImpl(newLength);2368}23692370for (int i = 0; i < end - start; ++i) {2371helpers.putByteInArrayByIndex(value, currentLength + i, (byte) sequence.charAt(start + i));2372}23732374count = newLength;2375} else {2376// Check if the StringBuffer is compressed2377if (count >= 0) {2378decompress(newLength);2379}23802381if (newLength > currentCapacity) {2382ensureCapacityImpl(newLength);2383}23842385for (int i = 0; i < end - start; ++i) {2386value[currentLength + i] = sequence.charAt(start + i);2387}23882389count = newLength | uncompressedBit;2390}2391} else {2392if (newLength > currentCapacity) {2393ensureCapacityImpl(newLength);2394}23952396for (int i = 0; i < end - start; ++i) {2397value[currentLength + i] = sequence.charAt(start + i);2398}23992400count = newLength;2401}24022403return this;2404}2405} else {2406throw new IndexOutOfBoundsException();2407}2408}24092410/**2411* Inserts the CharSequence at the specified offset in this StringBuffer.2412*2413* @param index the index at which to insert2414* @param sequence the CharSequence to insert2415* @return this StringBuffer2416*2417* @exception IndexOutOfBoundsException when {@code index < 0} or2418* {@code index > length()}2419*2420* @since 1.52421*/2422public synchronized StringBuffer insert(int index, CharSequence sequence) {2423int currentLength = lengthInternalUnsynchronized();24242425if (index >= 0 && index <= currentLength) {2426if (sequence == null) {2427return insert(index, String.valueOf(sequence));2428} else if (sequence instanceof String) {2429return insert(index, (String) sequence);2430} else if (sequence instanceof StringBuffer) {2431synchronized(sequence) {2432StringBuffer buffer = (StringBuffer) sequence;24332434// Check if the StringBuffer is compressed2435if (String.COMPACT_STRINGS && buffer.count >= 0) {2436return insert(index, buffer.value, 0, buffer.lengthInternalUnsynchronized(), true);2437} else {2438return insert(index, buffer.value, 0, buffer.lengthInternalUnsynchronized(), false);2439}2440}2441} else if (sequence instanceof StringBuilder) {2442synchronized (sequence) {2443StringBuilder builder = (StringBuilder) sequence;24442445if (String.COMPACT_STRINGS && builder.isCompressed()) {2446return insert(index, builder.getValue(), 0, builder.lengthInternal(), true);2447} else {2448return insert(index, builder.getValue(), 0, builder.lengthInternal(), false);2449}2450}2451} else {2452int sequneceLength = sequence.length();24532454if (sequneceLength > 0) {2455move(sequneceLength, index);24562457int newLength = currentLength + sequneceLength;24582459if (String.COMPACT_STRINGS) {2460boolean isCompressed = true;24612462for (int i = 0; i < sequneceLength; ++i) {2463if (sequence.charAt(i) > 255) {2464isCompressed = false;24652466break;2467}2468}24692470// Check if the StringBuffer is compressed2471if (count >= 0 && isCompressed) {2472for (int i = 0; i < sequneceLength; ++i) {2473helpers.putByteInArrayByIndex(value, index + i, (byte) sequence.charAt(i));2474}24752476count = newLength;24772478return this;2479} else {2480// Check if the StringBuffer is compressed2481if (count >= 0) {2482decompress(value.length);2483}24842485for (int i = 0; i < sequneceLength; ++i) {2486value[index + i] = sequence.charAt(i);2487}24882489count = newLength | uncompressedBit;2490}2491} else {2492for (int i = 0; i < sequneceLength; ++i) {2493value[index + i] = sequence.charAt(i);2494}24952496count = newLength;2497}2498}24992500return this;2501}2502} else {2503throw new IndexOutOfBoundsException();2504}2505}25062507/**2508* Inserts the CharSequence at the specified offset in this StringBuffer.2509*2510* @param index the index at which to insert2511* @param sequence the CharSequence to insert2512* @param start the offset of the first character2513* @param end the offset one past the last character2514* @return this StringBuffer2515*2516* @exception IndexOutOfBoundsException when {@code index < 0} or2517* {@code index > length()}, or when {@code start < 0, start > end} or2518* {@code end > length()}2519*2520* @since 1.52521*/2522public synchronized StringBuffer insert(int index, CharSequence sequence, int start, int end) {2523int currentLength = lengthInternalUnsynchronized();25242525if (index >= 0 && index <= currentLength) {2526if (sequence == null)2527return insert(index, String.valueOf(sequence), start, end);2528if (sequence instanceof String) {2529return insert(index, ((String) sequence).substring(start, end));2530}2531if (start >= 0 && end >= 0 && start <= end && end <= sequence.length()) {2532if (sequence instanceof StringBuffer) {2533synchronized(sequence) {2534StringBuffer buffer = (StringBuffer) sequence;25352536// Check if the StringBuffer is compressed2537if (String.COMPACT_STRINGS && buffer.count >= 0) {2538return insert(index, buffer.value, start, end - start, true);2539} else {2540return insert(index, buffer.value, start, end - start, false);2541}2542}2543} else if (sequence instanceof StringBuilder) {2544synchronized(sequence) {2545StringBuilder builder = (StringBuilder) sequence;25462547if (String.COMPACT_STRINGS && builder.isCompressed()) {2548return insert(index, builder.getValue(), start, end - start, true);2549} else {2550return insert(index, builder.getValue(), start, end - start, false);2551}2552}2553} else {2554int sequenceLength = end - start;25552556if (sequenceLength > 0) {2557move(sequenceLength, index);25582559int newLength = currentLength + sequenceLength;25602561if (String.COMPACT_STRINGS) {2562boolean isCompressed = true;25632564for (int i = 0; i < sequenceLength; ++i) {2565if (sequence.charAt(start + i) > 255) {2566isCompressed = false;25672568break;2569}2570}25712572// Check if the StringBuffer is compressed2573if (count >= 0 && isCompressed) {2574for (int i = 0; i < sequenceLength; ++i) {2575helpers.putByteInArrayByIndex(value, index + i, (byte) sequence.charAt(start + i));2576}25772578count = newLength;25792580return this;2581} else {2582// Check if the StringBuffer is compressed2583if (count >= 0) {2584decompress(value.length);2585}25862587for (int i = 0; i < sequenceLength; ++i) {2588value[index + i] = sequence.charAt(start + i);2589}25902591count = newLength | uncompressedBit;2592}2593} else {2594for (int i = 0; i < sequenceLength; ++i) {2595value[index + i] = sequence.charAt(start + i);2596}25972598count = newLength;2599}2600}26012602return this;2603}2604} else {2605throw new IndexOutOfBoundsException();2606}2607} else {2608throw new IndexOutOfBoundsException();2609}2610}26112612/**2613* Optionally modify the underlying char array to only2614* be large enough to hold the characters in this StringBuffer.2615*2616* @since 1.52617*/2618public synchronized void trimToSize() {2619int currentLength = lengthInternalUnsynchronized();2620int currentCapacity = capacityInternal();26212622// Check if the StringBuffer is compressed2623if (String.COMPACT_STRINGS && count >= 0) {2624// Check if the StringBuffer is not shared2625if (capacity >= 0 && currentCapacity != currentLength) {2626char[] newData = new char[(currentLength + 1) / 2];26272628String.compressedArrayCopy(value, 0, newData, 0, currentLength);26292630value = newData;26312632capacity = currentLength;2633}2634} else {2635// Check if the StringBuffer is not shared2636if (capacity >= 0 && currentCapacity != currentLength) {2637char[] newData = new char[currentLength];26382639String.decompressedArrayCopy(value, 0, newData, 0, currentLength);2640value = newData;26412642capacity = currentLength;2643}2644}2645}26462647/**2648* Returns the Unicode character at the given point.2649*2650* @param index the character index2651* @return the Unicode character value at the index2652*2653* @since 1.52654*/2655public synchronized int codePointAt(int index) {2656int currentLength = lengthInternalUnsynchronized();26572658if (index >= 0 && index < currentLength) {2659// Check if the StringBuffer is compressed2660if (String.COMPACT_STRINGS && count >= 0) {2661return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));2662} else {2663int high = value[index];26642665if ((index + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {2666int low = value[index + 1];26672668if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {2669return 0x10000 + ((high - Character.MIN_HIGH_SURROGATE) << 10) + (low - Character.MIN_LOW_SURROGATE);2670}2671}26722673return high;2674}2675} else {2676throw new StringIndexOutOfBoundsException(index);2677}2678}26792680/**2681* Returns the Unicode character before the given point.2682*2683* @param index the character index2684* @return the Unicode character value before the index2685*2686* @since 1.52687*/2688public synchronized int codePointBefore(int index) {2689int currentLength = lengthInternalUnsynchronized();26902691if (index > 0 && index <= currentLength) {2692// Check if the StringBuffer is compressed2693if (String.COMPACT_STRINGS && count >= 0) {2694return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index - 1));2695} else {2696int low = value[index - 1];26972698if (index > 1 && low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {2699int high = value[index - 2];27002701if (high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {2702return 0x10000 + ((high - Character.MIN_HIGH_SURROGATE) << 10) + (low - Character.MIN_LOW_SURROGATE);2703}2704}27052706return low;2707}2708} else {2709throw new StringIndexOutOfBoundsException(index);2710}2711}27122713/**2714* Returns the total Unicode values in the specified range.2715*2716* @param start first index2717* @param end last index2718* @return the total Unicode values2719*2720* @since 1.52721*/2722public synchronized int codePointCount(int start, int end) {2723int currentLength = lengthInternalUnsynchronized();27242725if (start >= 0 && start <= end && end <= currentLength) {2726// Check if the StringBuffer is compressed2727if (String.COMPACT_STRINGS && count >= 0) {2728return end - start;2729} else {2730int count = 0;27312732for (int i = start; i < end; ++i) {2733int high = value[i];27342735if (i + 1 < end && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {2736int low = value[i + 1];27372738if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {2739++i;2740}2741}27422743++count;2744}27452746return count;2747}2748} else {2749throw new IndexOutOfBoundsException();2750}2751}27522753/**2754* Returns the index of the code point that was offset by {@code codePointCount}.2755*2756* @param start the position to offset2757* @param codePointCount the code point count2758* @return the offset index2759*2760* @since 1.52761*/2762public synchronized int offsetByCodePoints(int start, int codePointCount) {2763int currentLength = lengthInternalUnsynchronized();27642765if (start >= 0 && start <= currentLength) {2766// Check if the StringBuffer is compressed2767if (String.COMPACT_STRINGS && count >= 0) {2768int index = start + codePointCount;27692770if (index >= currentLength) {2771throw new IndexOutOfBoundsException();2772} else {2773return index;2774}2775} else {2776int index = start;27772778if (codePointCount == 0) {2779return start;2780} else if (codePointCount > 0) {2781for (int i = 0; i < codePointCount; ++i) {2782if (index == currentLength) {2783throw new IndexOutOfBoundsException();2784}27852786int high = value[index];27872788if ((index + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {2789int low = value[index + 1];27902791if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {2792index++;2793}2794}27952796index++;2797}2798} else {2799for (int i = codePointCount; i < 0; ++i) {2800if (index < 1) {2801throw new IndexOutOfBoundsException();2802}28032804int low = value[index - 1];28052806if (index > 1 && low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {2807int high = value[index - 2];28082809if (high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {2810index--;2811}2812}28132814index--;2815}2816}28172818return index;2819}2820} else {2821throw new IndexOutOfBoundsException();2822}2823}28242825/**2826* Adds the specified code point to the end of this StringBuffer.2827*2828* @param codePoint the code point2829* @return this StringBuffer2830*2831* @since 1.52832*/2833public synchronized StringBuffer appendCodePoint(int codePoint) {2834if (codePoint >= 0) {2835if (codePoint < 0x10000) {2836return append((char)codePoint);2837} else if (codePoint < 0x110000) {2838// Check if the StringBuffer is compressed2839if (String.COMPACT_STRINGS && count >= 0) {2840decompress(value.length);2841}28422843int currentLength = lengthInternalUnsynchronized();2844int currentCapacity = capacityInternal();28452846int newLength = currentLength + 2;2847if (newLength < 0) {2848/*[MSG "K0D01", "Array capacity exceeded"]*/2849throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$2850}28512852if (newLength > currentCapacity) {2853ensureCapacityImpl(newLength);2854}28552856codePoint -= 0x10000;28572858value[currentLength] = (char) (Character.MIN_HIGH_SURROGATE + (codePoint >> 10));2859value[currentLength + 1] = (char) (Character.MIN_LOW_SURROGATE + (codePoint & 0x3ff));28602861if (String.COMPACT_STRINGS) {2862count = newLength | uncompressedBit;2863} else {2864count = newLength;2865}28662867return this;2868}2869}28702871throw new IllegalArgumentException();2872}28732874/*2875* Returns the character array for this StringBuffer.2876*/2877char[] getValue() {2878return value;2879}28802881}288228832884