//
// Copyright (C) 2012 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package java.lang;
import java.io.ObjectStreamField;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* MJI adapter for java.lang.String, based on jdk 1.7.0_07 source.
* Adapted by frank.
*
* We have to model java.lang.String since it changed its implementation between
* Java 1.6 and Java 1.7, and JPF is initializing string objects internally without
* doing roundtrips (for performance reasons), i.e. we need to be able to rely
* on fields of the String implementation.
*
* The silver lining is that most methods are now native and don't appear in
* traces anymore. Spending a lot of JPF cycles (instruction.execute()) on
* String is just not worth it in terms of potential properties.
*/
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
public String() {
this.value = new char[0];
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
public String(char value[], int offset, int count) {
String proxy=init(value,offset,count);
this.value=proxy.value;
this.hash=proxy.hash;
}
private native String init(char[] value, int offset, int count);
public String(int[] codePoints, int offset, int count) {
String proxy=init(codePoints,offset,count);
this.value=proxy.value;
this.hash=proxy.hash;
}
private native String init(int[] codePoints, int offset, int count);
@Deprecated
public String(byte ascii[], int hibyte, int offset, int count) {
String proxy=init(ascii,hibyte,offset,count);
this.value=proxy.value;
this.hash=proxy.hash;
}
private native String init(byte ascii[], int hibyte, int offset, int count);
@Deprecated
public String(byte ascii[], int hibyte) {
this(ascii, hibyte, 0, ascii.length);
}
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
public String(byte bytes[], int offset, int length, String charsetName){
String proxy=init(bytes,offset,length,charsetName);
this.value=proxy.value;
this.hash=proxy.hash;
}
private native String init(byte bytes[], int offset, int length, String charsetName);
public String(byte x[], int offset, int length, Charset cset) {
// no Charset model
if (cset == null){
throw new NullPointerException("cset");
}
if (length < 0){
throw new StringIndexOutOfBoundsException(length);
}
if (offset < 0){
throw new StringIndexOutOfBoundsException(offset);
}
if (offset > x.length - length){
throw new StringIndexOutOfBoundsException(offset + length);
}
this.value = StringCoding.decode(cset, x, offset, length);
}
public String(byte bytes[], String charsetName)
throws UnsupportedEncodingException {
this(bytes, 0, bytes.length, charsetName);
}
public String(byte bytes[], Charset charset) {
this(bytes, 0, bytes.length, charset);
}
public String(byte bytes[], int offset, int length) {
String proxy=init(bytes,offset,length);
this.value=proxy.value;
this.hash=proxy.hash;
}
private native String init(byte bytes[], int offset, int length);
public String(byte bytes[]) {
this(bytes, 0, bytes.length);
}
public String(StringBuffer x) {
synchronized(x) {
this.value = Arrays.copyOf(x.getValue(), x.length());
}
}
public String(StringBuilder x) {
this.value = Arrays.copyOf(x.getValue(), x.length());
}
@Deprecated
String(int offset, int count, char[] value) {
this(value, offset, count);
}
public int length() {
return value.length;
}
public boolean isEmpty() {
return value.length == 0;
}
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
native public int codePointAt(int index);
native public int codePointBefore(int index);
native public int codePointCount(int beginIndex, int endIndex);
native public int offsetByCodePoints(int index, int codePointOffset);
void getChars(char dst[], int dstBegin) {
System.arraycopy(value, 0, dst, dstBegin, value.length);
}
native public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin);
@Deprecated
native public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin);
native public byte[] getBytes(String charsetName)
throws UnsupportedEncodingException;
public byte[] getBytes(Charset x){
// No Charset model.
if (x == null){
throw new NullPointerException();
}
return StringCoding.encode(x, value, 0, value.length);
}
native public byte[] getBytes();
native public boolean equals(Object anObject);
public boolean contentEquals(StringBuffer stringBuffer){
// No StringBuffer model.
synchronized (stringBuffer) {
return contentEquals((CharSequence) stringBuffer);
}
}
native static boolean equals0 (char[] a, char[] b, int len);
/**
* we can't turn this into a native method at top level since it would require a bunch
* of round trips
*/
public boolean contentEquals (CharSequence charSequence){
if (value.length != charSequence.length()){
return false;
}
// that should be the common case (String)
if (charSequence.equals(this)){
return true;
}
// we can do that natively, too
if (charSequence instanceof AbstractStringBuilder) {
return equals0( value, ((AbstractStringBuilder) charSequence).getValue(), value.length);
}
// generic CharSequence - expensive
char v[] = value;
for (int n=value.length, i=0; n >= 0; n--,i++){
if (v[i] != charSequence.charAt(i)){
return false;
}
}
return true;
}
native public boolean equalsIgnoreCase(String anotherString);
native public int compareTo(String anotherString);
public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 8575799808933029326L;
public int compare(String s1, String s2) {
return MJIcompare(s1,s2);
}
}
native private static int MJIcompare(String s1,String s2);
public int compareToIgnoreCase(String str) {
return CASE_INSENSITIVE_ORDER.compare(this, str);
}
native public boolean regionMatches(int toffset, String other, int ooffset, int len);
native public boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len);
native public boolean startsWith(String prefix, int toffset);
public boolean startsWith(String prefix) {
return startsWith(prefix, 0);
}
public boolean endsWith(String suffix) {
return startsWith(suffix, value.length - suffix.value.length);
}
native public int hashCode();
public int indexOf(int ch) {
return indexOf(ch, 0);
}
native public int indexOf(int ch, int fromIndex);
native public int lastIndexOf(int ch);
native public int lastIndexOf(int ch, int fromIndex);
native public int indexOf(String str);
native public int indexOf(String str, int fromIndex);
public int lastIndexOf(String str) {
return lastIndexOf(str, value.length);
}
native public int lastIndexOf(String str, int fromIndex);
native public String substring(int beginIndex);
native public String substring(int beginIndex, int endIndex);
public CharSequence subSequence(int beginIndex, int endIndex) {
return this.substring(beginIndex, endIndex);
}
native public String concat(String str);
native public String replace(char oldChar, char newChar);
native public boolean matches(String regex);
public boolean contains(CharSequence charSequence) {
// No CharSequence model
return indexOf(charSequence.toString()) > -1;
}
native public String replaceFirst(String regex, String replacement);
native public String replaceAll(String regex, String replacement);
public String replace(CharSequence target, CharSequence other) {
// No CharSequence model
int PATTERN= 0x10;
Matcher pattern=Pattern.compile(target.toString(), PATTERN).matcher(this);
return pattern.replaceAll(Matcher.quoteReplacement(other.toString()));
}
native public String[] split(String regex, int limit);
native public String[] split(String regex);
native public String toLowerCase(Locale locale);
native public String toLowerCase();
native public String toUpperCase(Locale locale);
native public String toUpperCase();
native public String trim();
public String toString() {
return this;
}
native public char[] toCharArray();
native public static String format(String format, Object... args);
native public static String format(Locale l, String format, Object... args);
public static String valueOf(Object x){
// can't translate arbitrary object
return (x == null) ? "null" : x.toString();
}
public static String valueOf(char values[]) {
return new String(values);
}
public static String valueOf(char values[], int offset, int count) {
return new String(values, offset, count);
}
public static String copyValueOf(char values[], int offset, int count) {
return new String(values, offset, count);
}
public static String copyValueOf(char values[]) {
return new String(values);
}
public static String valueOf(boolean bool) {
return bool ? "true" : "false";
}
public static String valueOf(char character) {
char data[] = {character};
return new String(data);
}
native public static String valueOf(int i);
native public static String valueOf(long l);
native public static String valueOf(float f);
native public static String valueOf(double d);
public native String intern();
}