deep-c-rsc/JCGO/goclsp/vm_str/java/lang/String.java
2021-07-16 17:12:20 -05:00

1546 lines
38 KiB
Java

/*
* @(#) $(JCGO)/goclsp/vm_str/java/lang/String.java --
* Space-optimized implementation of the standard String class.
**
* Project: JCGO (http://www.ivmaisoft.com/jcgo/)
* Copyright (C) 2001-2008 Ivan Maidanski <ivmai@ivmaisoft.com>
* All rights reserved.
**
* Class specification origin: GNU Classpath v0.93
*/
/*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
**
* This software is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License (GPL) for more details.
**
* Linking this library statically or dynamically with other modules is
* making a combined work based on this library. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
**
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent
* modules, and to copy and distribute the resulting executable under
* terms of your choice, provided that you also meet, for each linked
* independent module, the terms and conditions of the license of that
* module. An independent module is a module which is not derived from
* or based on this library. If you modify this library, you may extend
* this exception to your version of the library, but you are not
* obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
package java.lang;
import gnu.classpath.SystemProperties;
import gnu.java.lang.CharData;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Comparator;
import java.util.Locale;
import java.util.regex.Pattern;
public final class String /* hard-coded class name */ /* const data */
implements Serializable, Comparable, CharSequence
{
private static final class CaseInsensitiveComparator
implements Comparator, Serializable
{
private static final long serialVersionUID = 8575799808933029326L;
CaseInsensitiveComparator() {}
public int compare(Object o1, Object o2)
{
return ((String) o1).compareToIgnoreCase((String) o2);
}
}
private static final long serialVersionUID = -6849794470754667710L;
private static final char[] EMPTY_CHARS = {};
private static final char[] upperExpand =
zeroBasedStringValue(CharData.UPPER_EXPAND);
private static final char[] upperSpecial =
zeroBasedStringValue(CharData.UPPER_SPECIAL);
public static final Comparator CASE_INSENSITIVE_ORDER =
new CaseInsensitiveComparator();
final Object value; /* hard-coded type and name */ /* const data */
final int offset; /* hard-coded type and name */
final int count; /* hard-coded type and name */
private int cachedHashCode; /* hard-coded type and name */
public String()
{
value = "".value;
offset = 0;
count = 0;
}
public String(String str)
{
value = str.value;
offset = str.offset;
count = str.count;
cachedHashCode = str.cachedHashCode;
}
public String(char[] data)
{
int count = data.length;
offset = 0;
if (hasHighByte(data, 0, count))
VMSystem.arraycopy(data, 0, value = new char[count], 0, count);
else
{
byte[] newBytes = new byte[count];
copyCharsToBytes(data, 0, newBytes, 0, count);
value = newBytes;
}
this.count = count;
}
public String(char[] data, int offset, int count)
{
if ((offset | count) < 0 || data.length - offset < count)
throw new StringIndexOutOfBoundsException();
this.offset = 0;
if (hasHighByte(data, offset, count))
VMSystem.arraycopy(data, offset, value = new char[count], 0, count);
else
{
byte[] newBytes = new byte[count];
copyCharsToBytes(data, offset, newBytes, 0, count);
value = newBytes;
}
this.count = count;
}
/**
* @deprecated
*/
public String(byte[] data, int hibyte, int offset, int count)
{
if ((offset | count) < 0 || data.length - offset < count)
throw new StringIndexOutOfBoundsException();
this.offset = 0;
this.count = count;
if (hibyte != 0)
value = createCharsFromBytes(data, offset, count, hibyte << 8);
else
{
byte[] newBytes = new byte[count];
VMSystem.arraycopy(data, offset, newBytes, 0, count);
value = newBytes;
}
}
/**
* @deprecated
*/
public String(byte[] data, int hibyte)
{
int count = data.length;
offset = 0;
this.count = count;
if (hibyte != 0)
value = createCharsFromBytes(data, 0, count, hibyte << 8);
else
{
byte[] newBytes = new byte[count];
VMSystem.arraycopy(data, 0, newBytes, 0, count);
value = newBytes;
}
}
public String(byte[] data, int offset, int count, String encoding)
throws UnsupportedEncodingException
{
CharBuffer cbuf = null;
try
{
cbuf = decodeBytes(data, offset, count, encoding);
}
catch (CharacterCodingException e) {}
catch (IllegalCharsetNameException e) {}
catch (UnsupportedCharsetException e) {}
if (cbuf == null)
throw new UnsupportedEncodingException("Encoding not found: " + encoding);
if (cbuf.hasArray())
{
value = cbuf.array();
this.offset = cbuf.position();
this.count = cbuf.remaining();
}
else
{
char[] newChars = new char[cbuf.remaining()];
cbuf.get(newChars);
value = newChars;
this.offset = 0;
this.count = newChars.length;
}
}
public String(byte[] data, String encoding)
throws UnsupportedEncodingException
{
this(data, 0, data.length, encoding);
}
public String(byte[] data, int offset, int count)
{
CharBuffer cbuf = null;
try
{
cbuf = decodeBytes(data, offset, count,
SystemProperties.getProperty("file.encoding"));
}
catch (CharacterCodingException e)
{
throw (Error) (new InternalError()).initCause(e);
}
catch (IllegalCharsetNameException e)
{
throw (Error) (new InternalError()).initCause(e);
}
catch (UnsupportedCharsetException e)
{
throw (Error) (new InternalError()).initCause(e);
}
if (cbuf.hasArray())
{
value = cbuf.array();
this.offset = cbuf.position();
this.count = cbuf.remaining();
}
else
{
char[] newChars = new char[cbuf.remaining()];
cbuf.get(newChars);
value = newChars;
this.offset = 0;
this.count = newChars.length;
}
}
public String(byte[] data)
{
this(data, 0, data.length);
}
public String(StringBuffer buffer)
{
offset = 0;
synchronized (buffer)
{
buffer.setShared();
value = buffer.value();
count = buffer.length();
}
}
public String(StringBuilder buffer) /* hard-coded method signature */
{
offset = 0;
buffer.setShared();
value = buffer.value();
count = buffer.length();
}
public String(int[] codePoints, int offset, int count)
{
if ((offset | count) < 0 || codePoints.length - offset < count)
throw new IndexOutOfBoundsException();
StringBuilder buffer = new StringBuilder(count);
while (count-- > 0)
buffer.appendCodePoint(codePoints[offset++]);
this.offset = 0;
buffer.setShared();
value = buffer.value();
this.count = buffer.length();
}
String(char[] data, int offset, int count, boolean dontCopy)
{
if (offset <= 0)
offset = 0;
if (count <= 0)
count = 0;
if (data.length - offset < count) /* hack */
{
offset = 0;
count = data.length;
}
if (dontCopy)
{
value = data;
this.offset = offset;
}
else
{
this.offset = 0;
if (hasHighByte(data, offset, count))
VMSystem.arraycopy(data, offset, value = new char[count], 0, count);
else
{
byte[] newBytes = new byte[count];
copyCharsToBytes(data, offset, newBytes, 0, count);
value = newBytes;
}
}
this.count = count;
}
public int length()
{
return count;
}
public char charAt(int index)
{
if (index < 0 || index >= count)
throw new StringIndexOutOfBoundsException(index); /* hack */
Object value = this.value;
return value instanceof byte[] ?
(char) (((byte[]) value)[offset + index] & 0xff) :
((char[]) value)[offset + index];
}
public void getChars(int srcBegin, int srcEnd, char[] dest, int destBegin)
{
if (((count - srcEnd) | srcBegin) < 0 || srcEnd < srcBegin)
throw new StringIndexOutOfBoundsException();
copyToChars(value, offset + srcBegin, dest, destBegin, srcEnd - srcBegin);
}
/**
* @deprecated
*/
public void getBytes(int srcBegin, int srcEnd, byte[] dest, int destBegin)
{
if (((count - srcEnd) | srcBegin) < 0 || srcEnd < srcBegin)
throw new StringIndexOutOfBoundsException();
Object value = this.value;
if (value instanceof byte[])
VMSystem.arraycopy(value, offset + srcBegin, dest, destBegin,
srcEnd - srcBegin);
else copyCharsToBytes((char[]) value, offset + srcBegin, dest, destBegin,
srcEnd - srcBegin);
}
public byte[] getBytes(String encoding)
throws UnsupportedEncodingException
{
try
{
return encodeValue(value, offset, count, encoding);
}
catch (IllegalCharsetNameException e) {}
catch (UnsupportedCharsetException e) {}
catch (CharacterCodingException e)
{
throw (Error) (new InternalError()).initCause(e);
}
throw new UnsupportedEncodingException("Encoding not found: " + encoding);
}
public byte[] getBytes()
{
try
{
return encodeValue(value, offset, count,
SystemProperties.getProperty("file.encoding"));
}
catch (CharacterCodingException e)
{
throw (Error) (new InternalError()).initCause(e);
}
catch (IllegalCharsetNameException e)
{
throw (Error) (new InternalError()).initCause(e);
}
catch (UnsupportedCharsetException e)
{
throw (Error) (new InternalError()).initCause(e);
}
}
public boolean equals(Object obj)
{
if (obj == this)
return true;
if (!(obj instanceof String))
return false;
String anotherString = (String) obj;
int count = this.count;
return anotherString.count == count && compareValues(value, offset,
anotherString.value, anotherString.offset, count) == 0;
}
public boolean contentEquals(StringBuffer buffer)
{
int count = this.count;
synchronized (buffer)
{
return buffer.length() == count &&
compareValues(value, offset, buffer.value(), 0, count) == 0;
}
}
public boolean contentEquals(CharSequence seq)
{
if (seq != this)
{
int count = this.count;
if (seq.length() != count)
return false;
int offset = this.offset;
Object value = this.value;
if (value instanceof byte[])
{
byte[] bytes = (byte[]) value;
for (int i = 0; i < count; i++)
if ((bytes[offset + i] & 0xff) != seq.charAt(i))
return false;
}
else
{
char[] chars = (char[]) value;
for (int i = 0; i < count; i++)
if (chars[offset + i] != seq.charAt(i))
return false;
}
}
return true;
}
public boolean equalsIgnoreCase(String anotherString)
{
int count = this.count;
return anotherString != null && anotherString.count == count &&
compareValuesIgnoreCase(value, offset, anotherString.value,
anotherString.offset, count) == 0;
}
public int compareTo(String anotherString)
{
int count2 = anotherString.count;
int count = this.count;
int cmp = compareValues(value, offset, anotherString.value,
anotherString.offset, count < count2 ? count : count2);
if (cmp == 0)
cmp = count - count2;
return cmp;
}
public int compareTo(Object obj)
{
return compareTo((String) obj);
}
public int compareToIgnoreCase(String anotherString)
{
int count2 = anotherString.count;
int count = this.count;
int cmp = compareValuesIgnoreCase(value, offset, anotherString.value,
anotherString.offset, count < count2 ? count : count2);
if (cmp == 0)
cmp = count - count2;
return cmp;
}
public boolean regionMatches(int toffset, String other, int ooffset, int len)
{
return other.count - ooffset >= len && count - toffset >= len &&
(toffset | ooffset) >= 0 && compareValues(value, offset + toffset,
other.value, other.offset + ooffset, len) == 0;
}
public boolean regionMatches(boolean ignoreCase, int toffset, String other,
int ooffset, int len)
{
return other.count - ooffset >= len && count - toffset >= len &&
(toffset | ooffset) >= 0 && (ignoreCase ?
compareValuesIgnoreCase(value, offset + toffset,
other.value, other.offset + ooffset, len) :
compareValues(value, offset + toffset,
other.value, other.offset + ooffset, len)) == 0;
}
public boolean startsWith(String prefix, int toffset)
{
int count2 = prefix.count;
return count - toffset >= count2 && toffset >= 0 && compareValues(value,
offset + toffset, prefix.value, prefix.offset, count2) == 0;
}
public boolean startsWith(String prefix)
{
int count2 = prefix.count;
return count >= count2 && compareValues(value, offset, prefix.value,
prefix.offset, count2) == 0;
}
public boolean endsWith(String suffix)
{
int count2 = suffix.count;
int toffset = count - count2;
return toffset >= 0 && compareValues(value, offset + toffset, suffix.value,
suffix.offset, count2) == 0;
}
public int hashCode()
{
int hashCode = cachedHashCode;
if (hashCode == 0 &&
(hashCode = hashCodeOfValue(value, offset, count)) != 0) /* hack */
cachedHashCode = hashCode;
return hashCode;
}
public int indexOf(int ch)
{
return indexOf(ch, 0);
}
public int indexOf(int ch, int fromIndex)
{
if (((char) ch) == ch)
{
if (fromIndex <= 0)
fromIndex = 0;
int offset = this.offset;
int count = this.count;
fromIndex = indexValueOf(ch, value, offset + fromIndex,
count - fromIndex) - offset;
if (fromIndex < count)
return fromIndex;
}
return -1;
}
public int lastIndexOf(int ch)
{
return lastIndexOf(ch, count - 1);
}
public int lastIndexOf(int ch, int fromIndex)
{
if (((char) ch) != ch || fromIndex < 0)
return -1;
if (fromIndex >= count)
fromIndex = count - 1;
int offset = this.offset;
return lastIndexValueOf(ch, value, offset + fromIndex, fromIndex + 1) -
offset;
}
public int indexOf(String str)
{
return indexOf(str, 0);
}
public int indexOf(String str, int fromIndex)
{
int lastInd2 = str.count - 1;
if (fromIndex <= 0)
fromIndex = 0;
int limit = count - lastInd2;
if (fromIndex >= limit)
return -1;
if (lastInd2 >= 0)
{
Object value2 = str.value;
int offset2 = str.offset;
int ch = getValueAt(value2, offset2);
Object value = this.value;
int offset = this.offset;
offset2++;
do
{
fromIndex = indexValueOf(ch, value, offset + fromIndex,
limit - fromIndex) - offset;
if (fromIndex >= limit)
return -1;
if (compareValues(value, offset + fromIndex + 1, value2, offset2,
lastInd2) == 0)
break;
fromIndex++;
} while (true);
}
return fromIndex;
}
public int lastIndexOf(String str)
{
return lastIndexOf(str, count - str.count);
}
public int lastIndexOf(String str, int fromIndex)
{
int lastInd2 = str.count - 1;
if (count - lastInd2 <= fromIndex)
fromIndex = count - lastInd2 - 1;
if (fromIndex < 0)
return -1;
if (lastInd2 >= 0)
{
Object value2 = str.value;
int offset2 = str.offset;
int ch = getValueAt(value2, offset2);
Object value = this.value;
int offset = this.offset;
offset2++;
do
{
fromIndex = lastIndexValueOf(ch, value, offset + fromIndex,
fromIndex + 1) - offset;
if (fromIndex < 0 || compareValues(value, offset + fromIndex + 1, value2,
offset2, lastInd2) == 0)
break;
fromIndex--;
} while (true);
}
return fromIndex;
}
public String substring(int beginIndex)
{
return substring(beginIndex, count);
}
public String substring(int beginIndex, int endIndex)
{
int margins = (count - endIndex) | beginIndex;
if (margins == 0)
return this;
if (margins < 0 || endIndex < beginIndex)
throw new StringIndexOutOfBoundsException();
int len = endIndex - beginIndex;
return len > 0 ? new String(offset + beginIndex, len, value) : "";
}
public CharSequence subSequence(int beginIndex, int endIndex)
{
return substring(beginIndex, endIndex);
}
public String concat(String str)
{
int count2 = str.count;
int count = this.count;
if (count2 == 0)
return this;
if (count == 0)
return str;
Object value = this.value;
Object value2 = str.value;
int offset = this.offset;
int offset2 = str.offset;
if (getValueLength(value) - offset - count >= count2 &&
compareValues(value, offset + count, value2, offset2, count2) == 0)
return new String(offset, count + count2, value);
if (offset2 >= count &&
compareValues(value, offset, value2, offset2 - count, count) == 0)
return new String(offset2 - count, count + count2, value2);
if (value instanceof byte[] && value2 instanceof byte[])
{
byte[] newBytes = new byte[count + count2];
VMSystem.arraycopy(value, offset, newBytes, 0, count);
VMSystem.arraycopy(value2, offset2, newBytes, count, count2);
return new String(0, newBytes.length, newBytes);
}
char[] newChars = new char[count + count2];
copyToChars(value, offset, newChars, 0, count);
copyToChars(value2, offset2, newChars, count, count2);
return new String(0, newChars.length, newChars);
}
public String replace(char oldChar, char newChar)
{
int pos;
if (oldChar == newChar || (pos = indexOf(oldChar, 0)) < 0)
return this;
int count = this.count;
Object value = this.value;
if (newChar <= 0xff && value instanceof byte[])
{
byte[] newBytes = new byte[count];
VMSystem.arraycopy(value, offset, newBytes, 0, count);
newBytes[pos] = (byte) newChar;
while (++pos < count)
if ((newBytes[pos] & 0xff) == oldChar)
newBytes[pos] = (byte) newChar;
return new String(0, count, newBytes);
}
char[] newChars = new char[count];
copyToChars(value, offset, newChars, 0, count);
newChars[pos] = newChar;
while (++pos < count)
if (newChars[pos] == oldChar)
newChars[pos] = newChar;
return new String(0, count, newChars);
}
public boolean matches(String regex)
{
return Pattern.matches(regex, this);
}
public String replaceFirst(String regex, String replacement)
{
return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}
public String replaceAll(String regex, String replacement)
{
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
public String[] split(String regex, int limit)
{
return Pattern.compile(regex).split(this, limit);
}
public String[] split(String regex)
{
return split(regex, 0);
}
public String toLowerCase(Locale loc)
{
return toLowerCase("tr".equals(loc.getLanguage()));
}
public String toLowerCase()
{
return toLowerCase(false);
}
public String toUpperCase(Locale loc)
{
return toUpperCase("tr".equals(loc.getLanguage()));
}
public String toUpperCase()
{
return toUpperCase(false);
}
public String trim()
{
int limit = count;
int pos = offset;
if (limit == 0)
return this;
Object value = this.value;
limit = pos + limit - 1;
if (value instanceof byte[])
{
byte[] bytes = (byte[]) value;
while ((bytes[pos] & 0xff) <= ' ')
if (++pos > limit)
return "";
while ((bytes[limit] & 0xff) <= ' ')
limit--;
}
else
{
char[] chars = (char[]) value;
while (chars[pos] <= ' ')
if (++pos > limit)
return "";
while (chars[limit] <= ' ')
limit--;
}
limit = limit - pos + 1;
return ((pos - offset) | (count - limit)) > 0 ?
new String(pos, limit, value) : this;
}
public String toString()
{
return this;
}
public char[] toCharArray()
{
char[] newChars = new char[count];
copyToChars(value, offset, newChars, 0, newChars.length);
return newChars;
}
public static String valueOf(Object obj) /* hard-coded method signature */
{
return obj != null ? obj.toString() : "null";
}
public static String valueOf(char[] data)
{
return valueOf(data, 0, data.length);
}
public static String valueOf(char[] data, int offset, int count)
{
if ((offset | count) < 0 || data.length - offset < count)
throw new StringIndexOutOfBoundsException();
return new String(data, offset, count, false);
}
public static String copyValueOf(char[] data, int offset, int count)
{
if ((offset | count) < 0 || data.length - offset < count)
throw new StringIndexOutOfBoundsException();
return new String(data, offset, count, false);
}
public static String copyValueOf(char[] data)
{
return copyValueOf(data, 0, data.length);
}
public static String valueOf(boolean b) /* hard-coded method signature */
{
return b ? "true" : "false";
}
public static String valueOf(char c) /* hard-coded method signature */
{
return new String(0, 1, c > 0xff ? (Object) new char[] { c } :
new byte[] { (byte) c });
}
public static String valueOf(int v) /* hard-coded method signature */
{
boolean isNeg = true;
if (v >= 0)
{
isNeg = false;
v = -v;
}
int offset = 11;
if (v > -10000)
{
if (v > -100)
{
offset = 1;
if (v <= -10)
offset = 2;
}
else
{
offset = 3;
if (v <= -1000)
offset++;
}
if (isNeg)
offset++;
}
byte[] newBytes = new byte[offset];
do
{
newBytes[--offset] = (byte) ('0' - (v % 10));
v /= 10;
} while (v < 0);
if (isNeg)
newBytes[--offset] = '-';
return new String(offset, newBytes.length - offset, newBytes);
}
public static String valueOf(long l) /* hard-coded method signature */
{
return Long.toString(l);
}
public static String valueOf(float f) /* hard-coded method signature */
{
return Float.toString(f);
}
public static String valueOf(double d) /* hard-coded method signature */
{
return Double.toString(d);
}
public String intern()
{
return VMString.intern(this);
}
public int codePointAt(int index)
{
return Character.codePointAt(this, index);
}
public int codePointBefore(int index)
{
return Character.codePointBefore(this, index);
}
public boolean contains(CharSequence seq)
{
return indexOf(seq.toString(), 0) >= 0;
}
public int codePointCount(int beginIndex, int endIndex)
{
if (((count - endIndex) | beginIndex) < 0 || endIndex < beginIndex)
throw new StringIndexOutOfBoundsException();
Object value = this.value;
return value instanceof byte[] ? endIndex - beginIndex :
Character.codePointCount((char[]) value, offset + beginIndex,
endIndex - beginIndex);
}
public int offsetByCodePoints(int index, int codePointOffset)
{
int count = this.count;
if (((count - index) | index) < 0)
throw new StringIndexOutOfBoundsException(index);
Object value = this.value;
if (value instanceof byte[])
{
index = index + codePointOffset;
if (((count - index) | index) < 0)
throw new IndexOutOfBoundsException();
return index;
}
int offset = this.offset;
return Character.offsetByCodePoints((char[]) value, offset, count,
offset + index, codePointOffset) - offset;
}
public String replace(CharSequence oldSeq, CharSequence newSeq)
{
int oldLen = oldSeq.length();
int newLen = newSeq.length();
if (oldLen == 1 && newLen == 1)
return replace(oldSeq.charAt(0), newSeq.charAt(0));
String oldStr = oldSeq.toString();
int pos = indexOf(oldStr, 0);
if (pos < 0 || oldSeq.equals(newSeq))
return this;
String newStr = newSeq.toString();
StringBuilder buffer = new StringBuilder(this);
do
{
buffer.replace(pos, pos + oldLen, newStr);
pos = buffer.indexOf(oldStr, pos + newLen);
} while (pos >= 0);
return buffer.toString();
}
public boolean isEmpty()
{
return count == 0;
}
private static int upperCaseExpansion(char ch)
{
return Character.direction[0][Character.readCodePoint((int) ch) >> 7] & 0x3;
}
private static int upperCaseIndex(char ch)
{
int low = 0;
char[] upperSpecialArr = upperSpecial;
int hi = upperSpecialArr.length - 2;
int mid;
char c;
while ((c = upperSpecialArr[mid = ((low + hi) >> 2) << 1]) != ch)
if (ch < c)
hi = mid - 2;
else low = mid + 2;
return upperSpecialArr[mid + 1];
}
static char[] zeroBasedStringValue(String str)
{
Object value = str.value;
int offset = str.offset;
int count = str.count;
if (value instanceof byte[] ||
((((char[]) value).length - count) | offset) > 0)
{
if (count == 0)
return EMPTY_CHARS;
char[] newChars = new char[count];
copyToChars(value, offset, newChars, 0, count);
return newChars;
}
return (char[]) value;
}
String(int offset, byte[] bytes, int count)
{
value = bytes;
this.offset = offset;
this.count = count;
}
private String(int offset, int count, Object value)
{
this.value = value;
this.offset = offset;
this.count = count;
}
private static CharBuffer decodeBytes(byte[] bytes, int offset, int count,
String encoding)
throws CharacterCodingException, IllegalCharsetNameException,
UnsupportedCharsetException
{
if ((offset | count) < 0 || bytes.length - offset < count)
throw new StringIndexOutOfBoundsException();
CharsetDecoder csd = Charset.forName(encoding).newDecoder();
csd.onMalformedInput(CodingErrorAction.REPLACE);
csd.onUnmappableCharacter(CodingErrorAction.REPLACE);
return csd.decode(ByteBuffer.wrap(bytes, offset, count));
}
private static byte[] encodeValue(Object value, int offset, int count,
String encoding)
throws CharacterCodingException, IllegalCharsetNameException,
UnsupportedCharsetException
{
CharsetEncoder cse = Charset.forName(encoding).newEncoder();
cse.onMalformedInput(CodingErrorAction.REPLACE);
cse.onUnmappableCharacter(CodingErrorAction.REPLACE);
char[] chars;
if (value instanceof byte[])
{
chars = new char[count];
copyToChars(value, offset, chars, 0, count);
offset = 0;
}
else chars = (char[]) value;
ByteBuffer bbuf = cse.encode(CharBuffer.wrap(chars, offset, count));
int bytesLen = bbuf.remaining();
if (bbuf.hasArray() && bbuf.capacity() == bytesLen)
return bbuf.array();
byte[] newBytes = new byte[bytesLen];
bbuf.get(newBytes);
return newBytes;
}
private static boolean hasHighByte(char[] chars, int offset, int count)
{
count += offset;
while (offset < count)
if (chars[offset++] > 0xff)
return true;
return false;
}
private String toLowerCase(boolean isTurkish)
{
int offset = this.offset;
int count = this.count;
Object value = this.value;
char[] chars;
char[] newChars;
int index;
if (value instanceof byte[])
{
byte[] bytes = (byte[]) value;
index = searchForNonLower(bytes, offset, count) - offset;
if (index >= count)
return this;
if (!isTurkish &&
Character.toLowerCase((char) (bytes[offset + index] & 0xff)) <= 0xff)
{
byte[] newBytes = new byte[count];
if (index > 0)
VMSystem.arraycopy(bytes, offset, newBytes, 0, index);
index = convertToLower(bytes, offset + index, newBytes, index,
count - index);
if (index <= 0)
return new String(0, count, newBytes);
index = count - index;
newChars = new char[count];
copyToChars(newBytes, 0, newChars, 0, index);
copyToChars(bytes, offset + index, newChars, index, count - index);
}
else
{
newChars = new char[count];
copyToChars(bytes, offset, newChars, 0, count);
}
chars = newChars;
offset = 0;
}
else
{
chars = (char[]) value;
index = searchForNonLower(chars, offset, count) - offset;
if (index >= count)
return this;
newChars = new char[count];
if (index > 0)
VMSystem.arraycopy(chars, offset, newChars, 0, index);
}
convertToLower(chars, offset + index, newChars, index, count - index,
isTurkish);
return new String(0, count, newChars);
}
private static int searchForNonLower(byte[] bytes, int offset, int count)
{
while (count-- > 0)
{
char ch = (char) (bytes[offset] & 0xff);
if (Character.toLowerCase(ch) != ch)
break;
offset++;
}
return offset;
}
private static int searchForNonLower(char[] chars, int offset, int count)
{
while (count-- > 0)
{
char ch = chars[offset];
if (Character.toLowerCase(ch) != ch)
break;
offset++;
}
return offset;
}
private static int convertToLower(byte[] bytes, int offset, byte[] bytes2,
int offset2, int count)
{
if (count > 0)
{
do
{
char ch = Character.toLowerCase((char) (bytes[offset++] & 0xff));
if (ch > 0xff)
break;
bytes2[offset2++] = (byte) ch;
} while (--count > 0);
}
return count;
}
private static void convertToLower(char[] chars, int offset, char[] chars2,
int offset2, int count, boolean isTurkish)
{
if (isTurkish)
{
while (count-- > 0)
{
char ch = chars[offset++];
if (ch == 'I')
ch = '\u0131';
else if (ch == '\u0130')
ch = 'i';
else ch = Character.toLowerCase(ch);
chars2[offset2++] = ch;
}
}
else
{
while (count-- > 0)
chars2[offset2++] = Character.toLowerCase(chars[offset++]);
}
}
private String toUpperCase(boolean isTurkish)
{
int offset = this.offset;
int count = this.count;
Object value = this.value;
char[] chars;
char[] newChars = null;
int index;
if (value instanceof byte[])
{
byte[] bytes = (byte[]) value;
index = searchForNonUpper(bytes, offset, count) - offset;
if (index >= count)
return this;
if (!isTurkish &&
Character.toUpperCase((char) (bytes[offset + index] & 0xff)) <= 0xff)
{
byte[] newBytes = new byte[count];
if (index > 0)
VMSystem.arraycopy(bytes, offset, newBytes, 0, index);
index = convertToUpper(bytes, offset + index, newBytes, index,
count - index);
if (index <= 0)
return new String(0, count, newBytes);
index = count - index;
newChars = new char[count];
copyToChars(newBytes, 0, newChars, 0, index);
copyToChars(bytes, offset + index, newChars, index, count - index);
}
else
{
newChars = new char[count];
copyToChars(bytes, offset, newChars, 0, count);
}
chars = newChars;
offset = 0;
}
else
{
chars = (char[]) value;
index = searchForNonUpper(chars, offset, count) - offset;
if (index >= count)
return this;
}
int expand = getUpperExpansion(chars, offset + index, count - index);
if (expand > 0 || chars != newChars)
{
newChars = new char[count + expand];
if (index > 0)
VMSystem.arraycopy(chars, offset, newChars, 0, index);
}
if (isTurkish || expand > 0)
convertToUpper(chars, offset + index, newChars, index, count - index,
isTurkish);
else convertToUpper(chars, offset + index, newChars, index, count - index);
return new String(0, count, newChars);
}
private static int searchForNonUpper(byte[] bytes, int offset, int count)
{
while (count-- > 0)
{
char ch = (char) (bytes[offset] & 0xff);
if (Character.toUpperCase(ch) != ch || upperCaseExpansion(ch) > 0)
break;
offset++;
}
return offset;
}
private static int searchForNonUpper(char[] chars, int offset, int count)
{
while (count-- > 0)
{
char ch = chars[offset];
if (Character.toUpperCase(ch) != ch || upperCaseExpansion(ch) > 0)
break;
offset++;
}
return offset;
}
private static int getUpperExpansion(char[] chars, int offset, int count)
{
int expand = 0;
while (count-- > 0)
expand += upperCaseExpansion(chars[offset++]);
return expand;
}
private static int convertToUpper(byte[] bytes, int offset, byte[] bytes2,
int offset2, int count)
{
if (count > 0)
{
do
{
char ch = (char) (bytes[offset++] & 0xff);
if (upperCaseExpansion(ch) > 0)
break;
ch = Character.toUpperCase(ch);
if (ch > 0xff)
break;
bytes2[offset2++] = (byte) ch;
} while (--count > 0);
}
return count;
}
private static void convertToUpper(char[] chars, int offset, char[] chars2,
int offset2, int count)
{
while (count-- > 0)
chars2[offset2++] = Character.toUpperCase(chars[offset++]);
}
private static void convertToUpper(char[] chars, int offset, char[] chars2,
int offset2, int count, boolean isTurkish)
{
while (count-- > 0)
{
char ch = chars[offset++];
if (ch == '\u0131' && isTurkish)
ch = 'I';
else if (ch == 'i' && isTurkish)
ch = '\u0130';
else
{
int expand = upperCaseExpansion(ch);
if (expand > 0)
{
char[] upperExpandArr = upperExpand;
int index = upperCaseIndex(ch);
do
{
chars2[offset2++] = upperExpandArr[index++];
} while (--expand > 0);
ch = upperExpandArr[index];
}
else ch = Character.toUpperCase(ch);
}
chars2[offset2++] = ch;
}
}
private static char[] createCharsFromBytes(byte[] bytes, int offset,
int count, int orval)
{
char[] newChars = new char[count];
for (int i = 0; i < count; i++)
newChars[i] = (char) ((bytes[offset++] & 0xff) | orval);
return newChars;
}
private static void copyCharsToBytes(char[] chars, int offset, byte[] bytes2,
int offset2, int count)
{
while (count-- > 0)
bytes2[offset2++] = (byte) chars[offset++];
}
private static void copyToChars(Object value, int offset, char[] chars2,
int offset2, int count)
{
if (count > 0)
{
if (value instanceof byte[])
{
byte[] bytes = (byte[]) value;
do
{
chars2[offset2++] = (char) (bytes[offset++] & 0xff);
} while (--count > 0);
}
else VMSystem.arraycopy(value, offset, chars2, offset2, count);
}
}
private static int hashCodeOfValue(Object value, int offset, int count)
{
int hashCode = 0;
if (value instanceof byte[])
{
byte[] bytes = (byte[]) value;
while (count-- > 0)
{
hashCode = (bytes[offset] & 0xff) + (hashCode << 5) - hashCode;
offset++;
}
}
else
{
char[] chars = (char[]) value;
while (count-- > 0)
hashCode = chars[offset++] + (hashCode << 5) - hashCode;
}
return hashCode;
}
private static int indexValueOf(int ch, Object value, int pos, int count)
{
if (value instanceof byte[])
{
if (ch > 0xff)
return pos + count;
byte[] bytes = (byte[]) value;
while (count-- > 0 && (bytes[pos] & 0xff) != ch)
pos++;
}
else
{
char[] chars = (char[]) value;
while (count-- > 0 && chars[pos] != ch)
pos++;
}
return pos;
}
private static int lastIndexValueOf(int ch, Object value, int pos, int count)
{
if (value instanceof byte[])
{
if (ch > 0xff)
return pos - count;
byte[] bytes = (byte[]) value;
while (count-- > 0 && (bytes[pos] & 0xff) != ch)
pos--;
}
else
{
char[] chars = (char[]) value;
while (count-- > 0 && chars[pos] != ch)
pos--;
}
return pos;
}
private static int compareValues(Object value, int offset, Object value2,
int offset2, int count)
{
int cmp = 0;
if (offset != offset2 || value != value2)
{
if (value instanceof byte[])
{
byte[] bytes = (byte[]) value;
if (value2 instanceof byte[])
{
byte[] bytes2 = (byte[]) value2;
while (count-- > 0)
{
cmp = (bytes[offset] & 0xff) - (bytes2[offset2] & 0xff);
if (cmp != 0)
break;
offset++;
offset2++;
}
}
else
{
char[] chars2 = (char[]) value2;
while (count-- > 0)
if ((cmp = (bytes[offset++] & 0xff) - chars2[offset2++]) != 0)
break;
}
}
else
{
char[] chars = (char[]) value;
if (value2 instanceof byte[])
{
byte[] bytes2 = (byte[]) value2;
while (count-- > 0)
if ((cmp = chars[offset++] - (bytes2[offset2++] & 0xff)) != 0)
break;
}
else
{
char[] chars2 = (char[]) value2;
while (count-- > 0)
if ((cmp = chars[offset++] - chars2[offset2++]) != 0)
break;
}
}
}
return cmp;
}
private static int compareValuesIgnoreCase(Object value, int offset,
Object value2, int offset2, int count)
{
int cmp = 0;
if (offset != offset2 || value != value2)
{
if (value instanceof byte[])
{
byte[] bytes = (byte[]) value;
if (value2 instanceof byte[])
{
byte[] bytes2 = (byte[]) value2;
while (count-- > 0)
if ((cmp = compareCharsIgnoreCase(bytes[offset++] & 0xff,
bytes2[offset2++] & 0xff)) != 0)
break;
}
else
{
char[] chars2 = (char[]) value2;
while (count-- > 0)
if ((cmp = compareCharsIgnoreCase(bytes[offset++] & 0xff,
chars2[offset2++])) != 0)
break;
}
}
else
{
char[] chars = (char[]) value;
if (value2 instanceof byte[])
{
byte[] bytes2 = (byte[]) value2;
while (count-- > 0)
if ((cmp = compareCharsIgnoreCase(chars[offset++],
bytes2[offset2++] & 0xff)) != 0)
break;
}
else
{
char[] chars2 = (char[]) value2;
while (count-- > 0)
if ((cmp = compareCharsIgnoreCase(chars[offset++],
chars2[offset2++])) != 0)
break;
}
}
}
return cmp;
}
private static int compareCharsIgnoreCase(int ch, int ch2)
{
int cmp = 0;
if (ch != ch2)
{
char c = Character.toUpperCase((char) ch);
char c2 = Character.toUpperCase((char) ch2);
if (c != c2)
cmp = Character.toLowerCase(c) - Character.toLowerCase(c2);
}
return cmp;
}
private static int getValueLength(Object value)
{
return value instanceof byte[] ? ((byte[]) value).length :
((char[]) value).length;
}
private static char getValueAt(Object value, int index)
{
return value instanceof byte[] ? (char) (((byte[]) value)[index] & 0xff) :
((char[]) value)[index];
}
}