mirror of
https://github.com/corda/corda.git
synced 2025-01-09 14:33:30 +00:00
693 lines
17 KiB
Java
693 lines
17 KiB
Java
/* Copyright (c) 2008-2009, Avian Contributors
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
for any purpose with or without fee is hereby granted, provided
|
|
that the above copyright notice and this permission notice appear
|
|
in all copies.
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
details. */
|
|
|
|
package java.lang;
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.util.regex.Pattern;
|
|
import java.util.Comparator;
|
|
import java.util.Locale;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.Serializable;
|
|
|
|
public final class String
|
|
implements Comparable<String>, CharSequence, Serializable
|
|
{
|
|
public static Comparator<String> CASE_INSENSITIVE_ORDER
|
|
= new Comparator<String>() {
|
|
public int compare(String a, String b) {
|
|
return a.compareToIgnoreCase(b);
|
|
}
|
|
};
|
|
|
|
private final Object data;
|
|
private final int offset;
|
|
private final int length;
|
|
private int hashCode;
|
|
|
|
public String() {
|
|
this(new char[0], 0, 0);
|
|
}
|
|
|
|
public String(char[] data, int offset, int length, boolean copy) {
|
|
this((Object) data, offset, length, copy);
|
|
}
|
|
|
|
public String(char[] data, int offset, int length) {
|
|
this(data, offset, length, true);
|
|
}
|
|
|
|
public String(char[] data) {
|
|
this(data, 0, data.length);
|
|
}
|
|
|
|
public String(byte bytes[], int offset, int length, String charsetName)
|
|
throws UnsupportedEncodingException
|
|
{
|
|
this(bytes, offset, length);
|
|
if (! charsetName.equalsIgnoreCase("UTF-8")) {
|
|
throw new UnsupportedEncodingException(charsetName);
|
|
}
|
|
}
|
|
|
|
public String(byte[] data, int offset, int length, boolean copy) {
|
|
this((Object) data, offset, length, copy);
|
|
}
|
|
|
|
public String(byte[] data, int offset, int length) {
|
|
this(data, offset, length, true);
|
|
}
|
|
|
|
public String(byte[] data) {
|
|
this(data, 0, data.length);
|
|
}
|
|
|
|
public String(String s) {
|
|
this(s.toCharArray());
|
|
}
|
|
|
|
public String(byte[] data, String charset)
|
|
throws UnsupportedEncodingException
|
|
{
|
|
this(data);
|
|
if (! charset.equals("UTF-8")) {
|
|
throw new UnsupportedEncodingException(charset);
|
|
}
|
|
}
|
|
|
|
public String(byte bytes[], int highByte, int offset, int length) {
|
|
if (offset < 0 || offset + length > bytes.length) {
|
|
throw new IndexOutOfBoundsException
|
|
(offset + " < 0 or " + offset + " + " + length + " > " + bytes.length);
|
|
}
|
|
|
|
char[] c = new char[length];
|
|
int mask = highByte << 8;
|
|
for (int i = 0; i < length; ++i) {
|
|
c[i] = (char) ((bytes[offset + i] & 0xFF) | mask);
|
|
}
|
|
|
|
this.data = c;
|
|
this.offset = 0;
|
|
this.length = length;
|
|
}
|
|
|
|
private String(Object data, int offset, int length, boolean copy) {
|
|
int l;
|
|
if (data instanceof char[]) {
|
|
l = ((char[]) data).length;
|
|
} else {
|
|
l = ((byte[]) data).length;
|
|
}
|
|
|
|
if (offset < 0 || offset + length > l) {
|
|
throw new IndexOutOfBoundsException
|
|
(offset + " < 0 or " + offset + " + " + length + " > " + l);
|
|
}
|
|
|
|
if(!copy && isUTF8(data)) copy = true;
|
|
|
|
if (copy) {
|
|
Object c;
|
|
if (data instanceof char[]) {
|
|
c = new char[length];
|
|
System.arraycopy(data, offset, c, 0, length);
|
|
} else {
|
|
c = decodeUTF8((byte[])data, offset, length);
|
|
if(c instanceof char[]) length = ((char[])c).length;
|
|
}
|
|
|
|
this.data = c;
|
|
this.offset = 0;
|
|
this.length = length;
|
|
} else {
|
|
this.data = data;
|
|
this.offset = offset;
|
|
this.length = length;
|
|
}
|
|
}
|
|
|
|
private static boolean isUTF8(Object data) {
|
|
if(!(data instanceof byte[])) return false;
|
|
byte[] b = (byte[])data;
|
|
for(int i = 0; i < b.length; ++i) {
|
|
if(((int)b[i] & 0x080) != 0) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static byte[] encodeUTF8(char[] s16, int offset, int length) {
|
|
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
|
for(int i = offset; i < offset+length; ++i) {
|
|
char c = s16[i];
|
|
if(c == '\u0000') { // null char
|
|
buf.write(0);
|
|
buf.write(0);
|
|
} else if(c < 0x080) { // 1 byte char
|
|
buf.write(c);
|
|
} else if(c < 0x0800) { // 2 byte char
|
|
buf.write(0x0c0 | (c >>> 6));
|
|
buf.write(0x080 | (c & 0x03f));
|
|
} else { // 3 byte char
|
|
buf.write(0x0e0 | ((c >>> 12) & 0x0f));
|
|
buf.write(0x080 | ((c >>> 6) & 0x03f));
|
|
buf.write(0x080 | (c & 0x03f));
|
|
}
|
|
}
|
|
return buf.toByteArray();
|
|
}
|
|
|
|
private static void decodeUTF8_insert(Object data, int index, int val) {
|
|
if(data instanceof byte[]) ((byte[])data)[index] = (byte)val;
|
|
else ((char[])data)[index] = (char)val;
|
|
}
|
|
|
|
private static Object decodeUTF8_widen(Object data, int length, int capacity) {
|
|
byte[] src = (byte[])data;
|
|
char[] result = new char[capacity];
|
|
for(int i = 0; i < length; ++i) result[i] = (char)((int)src[i] & 0x0ff);
|
|
return result;
|
|
}
|
|
|
|
private static Object decodeUTF8_trim(Object data, int length) {
|
|
if(data instanceof byte[]) return data;
|
|
if(((char[])data).length == length) return data;
|
|
char[] result = new char[length];
|
|
System.arraycopy(data, 0, result, 0, length);
|
|
return result;
|
|
}
|
|
|
|
private static Object decodeUTF8(byte[] s8, int offset, int length) {
|
|
Object buf = new byte[s8.length];
|
|
boolean isMultiByte = false;
|
|
int i=offset, j=0;
|
|
while(i < offset+length) {
|
|
int x = s8[i++];
|
|
if((x & 0x080) == 0x0) { // 1 byte char
|
|
if(x == 0) ++i; // 2 byte null char
|
|
decodeUTF8_insert(buf, j++, x);
|
|
} else if((x & 0x0e0) == 0x0c0) { // 2 byte char
|
|
if(!isMultiByte) {
|
|
buf = decodeUTF8_widen(buf, j, s8.length-1);
|
|
isMultiByte = true;
|
|
}
|
|
int y = s8[i++];
|
|
decodeUTF8_insert(buf, j++, ((x & 0x1f) << 6) | (y & 0x3f));
|
|
} else if((x & 0x0f0) == 0x0e0) { // 3 byte char
|
|
if(!isMultiByte) {
|
|
buf = decodeUTF8_widen(buf, j, s8.length-2);
|
|
isMultiByte = true;
|
|
}
|
|
int y = s8[i++]; int z = s8[i++];
|
|
decodeUTF8_insert(buf, j++, ((x & 0xf) << 12) | ((y & 0x3f) << 6) | (z & 0x3f));
|
|
}
|
|
}
|
|
|
|
return decodeUTF8_trim(buf, j);
|
|
}
|
|
|
|
public String toString() {
|
|
return this;
|
|
}
|
|
|
|
public int length() {
|
|
return length;
|
|
}
|
|
|
|
public int hashCode() {
|
|
if (hashCode == 0) {
|
|
int h = 0;
|
|
for (int i = 0; i < length; ++i) h = (h * 31) + charAt(i);
|
|
hashCode = h;
|
|
}
|
|
return hashCode;
|
|
}
|
|
|
|
public boolean equals(Object o) {
|
|
return this == o || (o instanceof String && compareTo((String) o) == 0);
|
|
}
|
|
|
|
public boolean equalsIgnoreCase(String s) {
|
|
return this == s || compareToIgnoreCase(s) == 0;
|
|
}
|
|
|
|
public int compareTo(String s) {
|
|
if (this == s) return 0;
|
|
|
|
int idx = 0;
|
|
int result;
|
|
|
|
int end = (length < s.length ? length : s.length);
|
|
|
|
while (idx < end) {
|
|
if ((result = charAt(idx) - s.charAt(idx)) != 0) {
|
|
return result;
|
|
}
|
|
idx++;
|
|
}
|
|
return length - s.length;
|
|
}
|
|
|
|
public int compareToIgnoreCase(String s) {
|
|
if (this == s) return 0;
|
|
|
|
int idx = 0;
|
|
int result;
|
|
|
|
int end = (length < s.length ? length : s.length);
|
|
|
|
while (idx < end) {
|
|
if ((result =
|
|
Character.toLowerCase(charAt(idx)) -
|
|
Character.toLowerCase(s.charAt(idx))) != 0) {
|
|
return result;
|
|
}
|
|
idx++;
|
|
}
|
|
return length - s.length;
|
|
}
|
|
|
|
public String trim() {
|
|
int start = -1;
|
|
for (int i = 0; i < length; ++i) {
|
|
char c = charAt(i);
|
|
if (start == -1 && ! Character.isWhitespace(c)) {
|
|
start = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
int end = -1;
|
|
for (int i = length - 1; i >= 0; --i) {
|
|
char c = charAt(i);
|
|
if (end == -1 && ! Character.isWhitespace(c)) {
|
|
end = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (start >= end) {
|
|
return "";
|
|
} else {
|
|
return substring(start, end);
|
|
}
|
|
}
|
|
|
|
public String toLowerCase() {
|
|
char[] b = new char[length];
|
|
for (int i = 0; i < length; ++i) {
|
|
b[i] = Character.toLowerCase(charAt(i));
|
|
}
|
|
return new String(b, 0, length, false);
|
|
}
|
|
|
|
public String toUpperCase() {
|
|
char[] b = new char[length];
|
|
for (int i = 0; i < length; ++i) {
|
|
b[i] = Character.toUpperCase(charAt(i));
|
|
}
|
|
return new String(b, 0, length, false);
|
|
}
|
|
|
|
public int indexOf(int c) {
|
|
return indexOf(c, 0);
|
|
}
|
|
|
|
public int indexOf(int c, int start) {
|
|
for (int i = start; i < length; ++i) {
|
|
if (charAt(i) == c) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public int lastIndexOf(int ch) {
|
|
return lastIndexOf(ch, length-1);
|
|
}
|
|
|
|
public int indexOf(String s) {
|
|
return indexOf(s, 0);
|
|
}
|
|
|
|
public int indexOf(String s, int start) {
|
|
if (s.length == 0) return start;
|
|
|
|
for (int i = start; i < length - s.length + 1; ++i) {
|
|
int j = 0;
|
|
for (; j < s.length; ++j) {
|
|
if (charAt(i + j) != s.charAt(j)) {
|
|
break;
|
|
}
|
|
}
|
|
if (j == s.length) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public int lastIndexOf(String s) {
|
|
if (s.length == 0) return length;
|
|
|
|
for (int i = length - s.length; i >= 0; --i) {
|
|
int j = 0;
|
|
for (; j < s.length && i + j < length; ++j) {
|
|
if (charAt(i + j) != s.charAt(j)) {
|
|
break;
|
|
}
|
|
}
|
|
if (j == s.length) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public String replace(char oldChar, char newChar) {
|
|
if (data instanceof char[]) {
|
|
char[] buf = new char[length];
|
|
for (int i=0; i < length; i++) {
|
|
if (charAt(i) == oldChar) {
|
|
buf[i] = newChar;
|
|
} else {
|
|
buf[i] = charAt(i);
|
|
}
|
|
}
|
|
return new String(buf, 0, length, false);
|
|
} else {
|
|
byte[] buf = new byte[length];
|
|
byte[] orig = (byte[])data;
|
|
byte oldByte = (byte)oldChar;
|
|
byte newByte = (byte)newChar;
|
|
for (int i=0; i < length; i++) {
|
|
if (orig[i+offset] == oldByte) {
|
|
buf[i] = newByte;
|
|
} else {
|
|
buf[i] = orig[i+offset];
|
|
}
|
|
}
|
|
return new String(buf, 0, length, false);
|
|
}
|
|
}
|
|
|
|
public String substring(int start) {
|
|
return substring(start, length);
|
|
}
|
|
|
|
public String substring(int start, int end) {
|
|
if (start >= 0 && end >= start && end <= length) {
|
|
if (start == 0 && end == length) {
|
|
return this;
|
|
} else if (end - start == 0) {
|
|
return "";
|
|
} else {
|
|
return new String(data, offset + start, end - start, false);
|
|
}
|
|
} else {
|
|
throw new IndexOutOfBoundsException
|
|
(start + " not in [0, " + end + ") or " + end + " > " + length);
|
|
}
|
|
}
|
|
|
|
public boolean startsWith(String s) {
|
|
if (length >= s.length) {
|
|
return substring(0, s.length).compareTo(s) == 0;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public boolean startsWith(String s, int start) {
|
|
if (length >= s.length + start) {
|
|
return substring(start, s.length).compareTo(s) == 0;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public boolean endsWith(String s) {
|
|
if (length >= s.length) {
|
|
return substring(length - s.length).compareTo(s) == 0;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public String concat(String s) {
|
|
if (s.length() == 0) {
|
|
return this;
|
|
} else {
|
|
return this + s;
|
|
}
|
|
}
|
|
|
|
public void getBytes(int srcOffset, int srcLength,
|
|
byte[] dst, int dstOffset)
|
|
{
|
|
if (srcOffset < 0 || srcOffset + srcLength > length) {
|
|
throw new IndexOutOfBoundsException();
|
|
}
|
|
|
|
if (data instanceof char[]) {
|
|
char[] src = (char[]) data;
|
|
for (int i = 0; i < srcLength; ++i) {
|
|
dst[i + dstOffset] = (byte) src[i + offset + srcOffset];
|
|
}
|
|
} else {
|
|
byte[] src = (byte[]) data;
|
|
System.arraycopy(src, offset + srcOffset, dst, dstOffset, srcLength);
|
|
}
|
|
}
|
|
|
|
public byte[] getBytes() {
|
|
if(data instanceof byte[]) {
|
|
byte[] b = new byte[length];
|
|
getBytes(0, length, b, 0);
|
|
return b;
|
|
}
|
|
return encodeUTF8((char[])data, offset, length);
|
|
}
|
|
|
|
public byte[] getBytes(String format)
|
|
throws java.io.UnsupportedEncodingException
|
|
{
|
|
return getBytes();
|
|
}
|
|
|
|
public void getChars(int srcOffset, int srcEnd,
|
|
char[] dst, int dstOffset)
|
|
{
|
|
if (srcOffset < 0 || srcEnd > length) {
|
|
throw new IndexOutOfBoundsException();
|
|
}
|
|
int srcLength = srcEnd-srcOffset;
|
|
if (data instanceof char[]) {
|
|
char[] src = (char[]) data;
|
|
System.arraycopy(src, offset + srcOffset, dst, dstOffset, srcLength);
|
|
} else {
|
|
byte[] src = (byte[]) data;
|
|
for (int i = 0; i < srcLength; ++i) {
|
|
dst[i + dstOffset] = (char) src[i + offset + srcOffset];
|
|
}
|
|
}
|
|
}
|
|
|
|
public char[] toCharArray() {
|
|
char[] b = new char[length];
|
|
getChars(0, length, b, 0);
|
|
return b;
|
|
}
|
|
|
|
public char charAt(int index) {
|
|
if (index < 0 || index > length) {
|
|
throw new IndexOutOfBoundsException();
|
|
}
|
|
|
|
if (data instanceof char[]) {
|
|
return ((char[]) data)[index + offset];
|
|
} else {
|
|
return (char) ((byte[]) data)[index + offset];
|
|
}
|
|
}
|
|
|
|
public String[] split(String s) {
|
|
String[] array = new String[(length / s.length) + 1];
|
|
int index = 0;
|
|
int last = 0;
|
|
int position = 0;
|
|
for (int i = 0; i < length - s.length + 1;) {
|
|
int j;
|
|
for (j = 0; j < s.length; ++j) {
|
|
if (charAt(i + j) != s.charAt(j)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (j == s.length) {
|
|
if (i > 0) {
|
|
if (i > position) {
|
|
last = index;
|
|
}
|
|
array[index++] = substring(position, i);
|
|
}
|
|
i = position = i + s.length;
|
|
} else {
|
|
++ i;
|
|
}
|
|
}
|
|
|
|
if (position < length) {
|
|
last = index;
|
|
array[index] = substring(position, length);
|
|
}
|
|
|
|
if (last + 1 < array.length) {
|
|
String[] a = new String[last + 1];
|
|
System.arraycopy(array, 0, a, 0, last + 1);
|
|
array = a;
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
public CharSequence subSequence(int start, int end) {
|
|
return substring(start, end);
|
|
}
|
|
|
|
public boolean matches(String regex) {
|
|
return Pattern.matches(regex, this);
|
|
}
|
|
|
|
public String replaceAll(String regex, String replacement) {
|
|
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
|
|
}
|
|
|
|
public native String intern();
|
|
|
|
public static String valueOf(Object s) {
|
|
return s == null ? "null" : s.toString();
|
|
}
|
|
|
|
public static String valueOf(boolean v) {
|
|
return Boolean.toString(v);
|
|
}
|
|
|
|
public static String valueOf(byte v) {
|
|
return Byte.toString(v);
|
|
}
|
|
|
|
public static String valueOf(short v) {
|
|
return Short.toString(v);
|
|
}
|
|
|
|
public static String valueOf(char v) {
|
|
return Character.toString(v);
|
|
}
|
|
|
|
public static String valueOf(int v) {
|
|
// use Integer.toString(int, int), because GNU Classpath's
|
|
// Integer.toString(int) just calls String.valueOf(int):
|
|
return Integer.toString(v, 10);
|
|
}
|
|
|
|
public static String valueOf(long v) {
|
|
return Long.toString(v);
|
|
}
|
|
|
|
public static String valueOf(float v) {
|
|
return Float.toString(v);
|
|
}
|
|
|
|
public static String valueOf(double v) {
|
|
return Double.toString(v);
|
|
}
|
|
|
|
public static String valueOf(char[] data, int offset, int length) {
|
|
return new String(data, offset, length);
|
|
}
|
|
|
|
public static String valueOf(char[] data) {
|
|
return valueOf(data, 0, data.length);
|
|
}
|
|
|
|
public int lastIndexOf(int ch, int lastIndex) {
|
|
for (int i = lastIndex ; i >= 0; --i) {
|
|
if (charAt(i) == ch) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public boolean regionMatches(int thisOffset, String match, int matchOffset,
|
|
int length)
|
|
{
|
|
return regionMatches(false, thisOffset, match, matchOffset, length);
|
|
}
|
|
|
|
public boolean regionMatches(boolean ignoreCase, int thisOffset,
|
|
String match, int matchOffset, int length)
|
|
{
|
|
String a = substring(thisOffset, thisOffset + length);
|
|
String b = match.substring(matchOffset, matchOffset + length);
|
|
if (ignoreCase) {
|
|
return a.equalsIgnoreCase(b);
|
|
} else {
|
|
return a.equals(b);
|
|
}
|
|
}
|
|
|
|
public boolean isEmpty() {
|
|
return length == 0;
|
|
}
|
|
|
|
public boolean contains(String match) {
|
|
return indexOf(match) != -1;
|
|
}
|
|
|
|
public int codePointAt(int offset) {
|
|
return Character.codePointAt(this, offset);
|
|
}
|
|
|
|
public int codePointCount(int start, int end) {
|
|
return Character.codePointCount(this, start, end);
|
|
}
|
|
|
|
public String replace(CharSequence match, CharSequence replacement) {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
public String toUpperCase(Locale locale) {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
public String toLowerCase(Locale locale) {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
// for GNU Classpath compatibility:
|
|
static char[] zeroBasedStringValue(String s) {
|
|
if (s.offset == 0) {
|
|
if (s.data instanceof char[]) {
|
|
char[] data = (char[]) s.data;
|
|
if (data.length == s.length) {
|
|
return data;
|
|
}
|
|
}
|
|
}
|
|
return s.toCharArray();
|
|
}
|
|
}
|