--- /home/cpdev/src/classpath/java/lang/String.java	2005-07-12 13:24:55.000000000 +0000
+++ java/lang/String.java	2005-06-30 05:34:39.000000000 +0000
@@ -1,5 +1,5 @@
 /* String.java -- immutable character sequences; the object of string literals
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
@@ -39,23 +39,11 @@
 
 package java.lang;
 
-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.text.Collator;
+import java.lang.Comparable;
 import java.util.Comparator;
 import java.util.Locale;
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 
@@ -83,7 +71,7 @@
  * @author Eric Blake (ebb9@email.byu.edu)
  * @author Per Bothner (bothner@cygnus.com)
  * @since 1.0
- * @status updated to 1.4; but could use better data sharing via offset field
+ * @status updated to 1.4
  */
 public final class String implements Serializable, Comparable, CharSequence
 {
@@ -97,33 +85,26 @@
   private static final long serialVersionUID = -6849794470754667710L;
 
   /**
-   * Stores unicode multi-character uppercase expansion table.
-   * @see #toUpperCase(char)
-   * @see CharData#UPPER_EXPAND
+   * This is the object that holds the characters that make up the
+   * String.  It might be a char[], or it could be String.  It could
+   * even be `this'.  The actual characters can't be located using
+   * pure Java code.
+   * @see #boffset
    */
-  private static final char[] upperExpand
-	= zeroBasedStringValue(CharData.UPPER_EXPAND);
+  private Object data;
 
   /**
-   * Stores unicode multi-character uppercase special casing table.
-   * @see #upperCaseExpansion(char)
-   * @see CharData#UPPER_SPECIAL
-   */
-  private static final char[] upperSpecial
-	  = zeroBasedStringValue(CharData.UPPER_SPECIAL);
-  
-  /**
-   * Characters which make up the String.
-   * Package access is granted for use by StringBuffer.
+   * This is a <emph>byte</emph> offset of the actual characters from
+   * the start of the character-holding object.  Don't use this field
+   * in Java code.
    */
-  final char[] value;
+  private int boffset;
 
   /**
-   * Holds the number of characters in value.  This number is generally
-   * the same as value.length, but can be smaller because substrings and
-   * StringBuffers can share arrays. Package visible for use by trusted code.
+   * Holds the number of characters in value.  Package visible for use
+   * by trusted code.
    */
-  final int count;
+  int count;
 
   /**
    * Caches the result of hashCode().  If this value is zero, the hashcode
@@ -132,13 +113,6 @@
   private int cachedHashCode;
 
   /**
-   * Holds the starting position for characters in value[].  Since
-   * substring()'s are common, the use of offset allows the operation
-   * to perform in O(1). Package access is granted for use by StringBuffer.
-   */
-  final int offset;
-
-  /**
    * An implementation for {@link CASE_INSENSITIVE_ORDER}.
    * This must be {@link Serializable}. The class name is dictated by
    * compatibility with Sun's JDK.
@@ -191,8 +165,8 @@
    */
   public String()
   {
-    value = "".value;
-    offset = 0;
+    data = "".data;
+    boffset = 0;
     count = 0;
   }
 
@@ -205,8 +179,8 @@
    */
   public String(String str)
   {
-    value = str.value;
-    offset = str.offset;
+    data = str.data;
+    boffset = str.boffset;
     count = str.count;
     cachedHashCode = str.cachedHashCode;
   }
@@ -220,7 +194,7 @@
    */
   public String(char[] data)
   {
-    this(data, 0, data.length, false);
+    init(data, 0, data.length, false);
   }
 
   /**
@@ -238,7 +212,7 @@
    */
   public String(char[] data, int offset, int count)
   {
-    this(data, offset, count, false);
+    init(data, offset, count, false);
   }
 
   /**
@@ -267,15 +241,7 @@
    */
   public String(byte[] ascii, int hibyte, int offset, int count)
   {
-    if (offset < 0 || count < 0 || offset + count > ascii.length)
-      throw new StringIndexOutOfBoundsException();
-    value = new char[count];
-    this.offset = 0;
-    this.count = count;
-    hibyte <<= 8;
-    offset += count;
-    while (--count >= 0)
-      value[count] = (char) (hibyte | (ascii[--offset] & 0xff));
+    init(ascii, hibyte, offset, count);
   }
 
   /**
@@ -300,7 +266,7 @@
    */
   public String(byte[] ascii, int hibyte)
   {
-    this(ascii, hibyte, 0, ascii.length);
+    init(ascii, hibyte, 0, ascii.length);
   }
 
   /**
@@ -315,7 +281,7 @@
    *
    * @param data byte array to copy
    * @param offset the offset to start at
-   * @param count the number of bytes in the array to use
+   * @param count the number of characters in the array to use
    * @param encoding the name of the encoding to use
    * @throws NullPointerException if data or encoding is null
    * @throws IndexOutOfBoundsException if offset or count is incorrect
@@ -327,36 +293,7 @@
   public String(byte[] data, int offset, int count, String encoding)
     throws UnsupportedEncodingException
   {
-    if (offset < 0 || count < 0 || offset + count > data.length)
-      throw new StringIndexOutOfBoundsException();
-    try 
-      {
-        CharsetDecoder csd = Charset.forName(encoding).newDecoder();
-	csd.onMalformedInput(CodingErrorAction.REPLACE);
-	csd.onUnmappableCharacter(CodingErrorAction.REPLACE);
-	CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count));
- 	if(cbuf.hasArray())
- 	  {
- 	    value = cbuf.array();
-	    this.offset = cbuf.position();
-	    this.count = cbuf.remaining();
- 	  } else {
-	    // Doubt this will happen. But just in case.
-	    value = new char[cbuf.remaining()];
-	    cbuf.get(value);
-	    this.offset = 0;
-	    this.count = value.length;
-	  }
-      } catch(CharacterCodingException e){
-	  throw new UnsupportedEncodingException("Encoding: "+encoding+
-						 " not found.");	  
-      } catch(IllegalCharsetNameException e){
-	  throw new UnsupportedEncodingException("Encoding: "+encoding+
-						 " not found.");
-      } catch(UnsupportedCharsetException e){
-	  throw new UnsupportedEncodingException("Encoding: "+encoding+
-						 " not found.");
-      }    
+    init (data, offset, count, encoding);
   }
 
   /**
@@ -393,7 +330,7 @@
    *
    * @param data byte array to copy
    * @param offset the offset to start at
-   * @param count the number of bytes in the array to use
+   * @param count the number of characters in the array to use
    * @throws NullPointerException if data is null
    * @throws IndexOutOfBoundsException if offset or count is incorrect
    * @throws Error if the decoding fails
@@ -402,43 +339,23 @@
    */
   public String(byte[] data, int offset, int count)
   {
-    if (offset < 0 || count < 0 || offset + count > data.length)
-      throw new StringIndexOutOfBoundsException();
-    int o, c;
-    char[] v;
-    String encoding;
-    try 
-	{
-	  encoding = System.getProperty("file.encoding");
-	  CharsetDecoder csd = Charset.forName(encoding).newDecoder();
-	  csd.onMalformedInput(CodingErrorAction.REPLACE);
-	  csd.onUnmappableCharacter(CodingErrorAction.REPLACE);
-	  CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count));
-	  if(cbuf.hasArray())
-	    {
-              v = cbuf.array();
-	      o = cbuf.position();
-	      c = cbuf.remaining();
-	    } else {
-	      // Doubt this will happen. But just in case.
-	      v = new char[cbuf.remaining()];
-	      cbuf.get(v);
-	      o = 0;
-	      c = v.length;
-	    }
-	} catch(Exception ex){
-	    // If anything goes wrong (System property not set,
-	    // NIO provider not available, etc)
-	    // Default to the 'safe' encoding ISO8859_1
-	    v = new char[count];
-	    o = 0;
-	    c = count;
-	    for (int i=0;i<count;i++)
-	      v[i] = (char)data[offset+i];
-	}
-    this.value = v;
-    this.offset = o;
-    this.count = c;
+    try
+      {
+	init (data, offset, count,
+	      System.getProperty("file.encoding", "8859_1"));
+      }
+    catch (UnsupportedEncodingException x1)
+      {
+	// Maybe the default encoding is bad.
+	try
+	  {
+	    init (data, offset, count, "8859_1");
+	  }
+	catch (UnsupportedEncodingException x2)
+	  {
+	    // We know this can't happen.
+	  }
+      }
   }
 
   /**
@@ -472,19 +389,11 @@
   {
     synchronized (buffer)
       {
-        offset = 0;
-        count = buffer.count;
-        // Share unless buffer is 3/4 empty.
-        if ((count << 2) < buffer.value.length)
-          {
-            value = new char[count];
-            VMSystem.arraycopy(buffer.value, 0, value, 0, count);
-          }
-        else
-          {
-            buffer.shared = true;
-            value = buffer.value;
-          }
+	// Share unless buffer is 3/4 empty.
+	boolean should_copy = ((buffer.count << 2) < buffer.value.length);
+	if (! should_copy)
+	  buffer.shared = true;
+	init (buffer.value, 0, buffer.count, ! should_copy);
       }
   }
 
@@ -512,20 +421,17 @@
    */
   String(char[] data, int offset, int count, boolean dont_copy)
   {
-    if (offset < 0 || count < 0 || offset + count > data.length)
-      throw new StringIndexOutOfBoundsException();
-    if (dont_copy)
-      {
-        value = data;
-        this.offset = offset;
-      }
-    else
-      {
-        value = new char[count];
-        VMSystem.arraycopy(data, offset, value, 0, count);
-        this.offset = 0;
-      }
-    this.count = count;
+    init(data, offset, count, dont_copy);
+  }
+
+  // This is used by gnu.gcj.runtime.StringBuffer, so it must have
+  // package-private protection.  It is accessed via CNI and so avoids
+  // ordinary protection mechanisms.
+  String(gnu.gcj.runtime.StringBuffer buffer)
+  {
+    // No need to synchronize or mark the buffer, since we know it is
+    // only used once.
+    init (buffer);
   }
 
   /**
@@ -546,12 +452,7 @@
    * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= length()
    *         (while unspecified, this is a StringIndexOutOfBoundsException)
    */
-  public char charAt(int index)
-  {
-    if (index < 0 || index >= count)
-      throw new StringIndexOutOfBoundsException(index);
-    return value[offset + index];
-  }
+  public native char charAt(int index);
 
   /**
    * Copies characters from this String starting at a specified start index,
@@ -568,13 +469,8 @@
    *         StringIndexOutOfBoundsException, and dst problems cause an
    *         ArrayIndexOutOfBoundsException)
    */
-  public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)
-  {
-    if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count)
-      throw new StringIndexOutOfBoundsException();
-    VMSystem.arraycopy(value, srcBegin + offset,
-                     dst, dstBegin, srcEnd - srcBegin);
-  }
+  public native void getChars(int srcBegin, int srcEnd,
+			      char[] dst, int dstBegin);
 
   /**
    * Copies the low byte of each character from this String starting at a
@@ -594,81 +490,56 @@
    * @see #getBytes(String)
    * @deprecated use {@link #getBytes()}, which uses a char to byte encoder
    */
-  public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin)
-  {
-    if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count)
-      throw new StringIndexOutOfBoundsException();
-    int i = srcEnd - srcBegin;
-    srcBegin += offset;
-    while (--i >= 0)
-      dst[dstBegin++] = (byte) value[srcBegin++];
-  }
+  public native void getBytes(int srcBegin, int srcEnd,
+			      byte[] dst, int dstBegin);
 
   /**
    * Converts the Unicode characters in this String to a byte array. Uses the
    * specified encoding method, so the result may be longer or shorter than
    * the String. For more encoding control, use
    * {@link java.nio.charset.CharsetEncoder}, and for valid character sets,
-   * see {@link java.nio.charset.Charset}. Unsupported characters get
-   * replaced by an encoding specific byte.
+   * see {@link java.nio.charset.Charset}. The behavior is not specified if
+   * the encoder encounters a problem; this implementation returns null.
    *
    * @param enc encoding name
-   * @return the resulting byte array
+   * @return the resulting byte array, or null on a problem
    * @throws NullPointerException if enc is null
    * @throws UnsupportedEncodingException if encoding is not supported
    * @since 1.1
    */
-  public byte[] getBytes(String enc) throws UnsupportedEncodingException
-  {
-    try 
-      {
-	CharsetEncoder cse = Charset.forName(enc).newEncoder();
-	cse.onMalformedInput(CodingErrorAction.REPLACE);
-	cse.onUnmappableCharacter(CodingErrorAction.REPLACE);
-	ByteBuffer bbuf = cse.encode(CharBuffer.wrap(value, offset, count));
-	if(bbuf.hasArray())
-	  return bbuf.array();
-
-	// Doubt this will happen. But just in case.
-	byte[] bytes = new byte[bbuf.remaining()];
-	bbuf.get(bytes);
-	return bytes;
-
-      } catch(IllegalCharsetNameException e){
-	  throw new UnsupportedEncodingException("Encoding: "+enc+
-						 " not found.");
-      } catch(UnsupportedCharsetException e){
-	  throw new UnsupportedEncodingException("Encoding: "+enc+
-						 " not found.");
-      } catch(CharacterCodingException e){
-	  // XXX - Ignore coding exceptions? They shouldn't really happen.
-	  return null;
-      }	  
-  }
+  public native byte[] getBytes(String enc)
+    throws UnsupportedEncodingException;
 
   /**
    * Converts the Unicode characters in this String to a byte array. Uses the
    * encoding of the platform's default charset, so the result may be longer
    * or shorter than the String. For more encoding control, use
-   * {@link java.nio.charset.CharsetEncoder}. Unsupported characters get
-   * replaced by an encoding specific byte.
+   * {@link java.nio.charset.CharsetEncoder}.  The behavior is not specified if
+   * the encoder encounters a problem; this implementation returns null.
    *
    * @return the resulting byte array, or null on a problem
    * @since 1.1
    */
   public byte[] getBytes()
-  { 
-      try 
+  {
+    try
+      {
+	return getBytes (System.getProperty("file.encoding", "8859_1"));
+      }
+    catch (UnsupportedEncodingException x)
+      {
+	// This probably shouldn't happen, but could if file.encoding
+	// is somehow changed to a value we don't understand.
+	try
 	  {
-	      return getBytes(System.getProperty("file.encoding"));
-	  } catch(Exception e) {
-	      // XXX - Throw an error here? 
-	      // For now, default to the 'safe' encoding.
-	      byte[] bytes = new byte[count];
-	      for(int i=0;i<count;i++)
-		  bytes[i] = (byte)((value[offset+i] <= 0xFF)?
-				    value[offset+i]:'?');
-	      return bytes;
+	    return getBytes ("8859_1");
+	  }
+	catch (UnsupportedEncodingException x2)
+	  {
+	    // This really shouldn't happen, because the 8859_1
+	    // encoding should always be available.
+	    throw new InternalError ("couldn't find 8859_1 encoder");
+	  }
       }
   }
 
@@ -681,23 +552,7 @@
    * @see #compareTo(String)
    * @see #equalsIgnoreCase(String)
    */
-  public boolean equals(Object anObject)
-  {
-    if (! (anObject instanceof String))
-      return false;
-    String str2 = (String) anObject;
-    if (count != str2.count)
-      return false;
-    if (value == str2.value && offset == str2.offset)
-      return true;
-    int i = count;
-    int x = offset;
-    int y = str2.offset;
-    while (--i >= 0)
-      if (value[x++] != str2.value[y++])
-        return false;
-    return true;
-  }
+  public native boolean equals(Object anObject);
 
   /**
    * Compares the given StringBuffer to this String. This is true if the
@@ -708,22 +563,7 @@
    * @throws NullPointerException if the given StringBuffer is null
    * @since 1.4
    */
-  public boolean contentEquals(StringBuffer buffer)
-  {
-    synchronized (buffer)
-      {
-        if (count != buffer.count)
-          return false;
-        if (value == buffer.value)
-          return true; // Possible if shared.
-        int i = count;
-        int x = offset + count;
-        while (--i >= 0)
-          if (value[--x] != buffer.value[i])
-            return false;
-        return true;
-      }
-  }
+  public native boolean contentEquals(StringBuffer buffer);
 
   /**
    * Compares a String to this String, ignoring case. This does not handle
@@ -742,25 +582,7 @@
    * @see Character#toUpperCase(char)
    * @see Character#toLowerCase(char)
    */
-  public boolean equalsIgnoreCase(String anotherString)
-  {
-    if (anotherString == null || count != anotherString.count)
-      return false;
-    int i = count;
-    int x = offset;
-    int y = anotherString.offset;
-    while (--i >= 0)
-      {
-        char c1 = value[x++];
-        char c2 = anotherString.value[y++];
-        // Note that checking c1 != c2 is redundant, but avoids method calls.
-        if (c1 != c2
-            && Character.toUpperCase(c1) != Character.toUpperCase(c2)
-            && Character.toLowerCase(c1) != Character.toLowerCase(c2))
-          return false;
-      }
-    return true;
-  }
+  public native boolean equalsIgnoreCase(String anotherString);
 
   /**
    * Compares this String and another String (case sensitive,
@@ -776,19 +598,7 @@
    * @return the comparison
    * @throws NullPointerException if anotherString is null
    */
-  public int compareTo(String anotherString)
-  {
-    int i = Math.min(count, anotherString.count);
-    int x = offset;
-    int y = anotherString.offset;
-    while (--i >= 0)
-      {
-        int result = value[x++] - anotherString.value[y++];
-        if (result != 0)
-          return result;
-      }
-    return count - anotherString.count;
-  }
+  public native int compareTo(String anotherString);
 
   /**
    * Behaves like <code>compareTo(java.lang.String)</code> unless the Object
@@ -822,17 +632,8 @@
    */
   public int compareToIgnoreCase(String str)
   {
-    int i = Math.min(count, str.count);
-    int x = offset;
-    int y = str.offset;
-    while (--i >= 0)
-      {
-        int result = Character.toLowerCase(Character.toUpperCase(value[x++]))
-          - Character.toLowerCase(Character.toUpperCase(str.value[y++]));
-        if (result != 0)
-          return result;
-      }
-    return count - str.count;
+    return this.toUpperCase().toLowerCase().compareTo(
+     str.toUpperCase().toLowerCase());
   }  
 
   /**
@@ -848,10 +649,8 @@
    * @return true if regions match (case sensitive)
    * @throws NullPointerException if other is null
    */
-  public boolean regionMatches(int toffset, String other, int ooffset, int len)
-  {
-    return regionMatches(false, toffset, other, ooffset, len);
-  }
+  public native boolean regionMatches(int toffset,
+				      String other, int ooffset, int len);
 
   /**
    * Predicate which determines if this String matches another String
@@ -865,34 +664,13 @@
    * @param ignoreCase true if case should be ignored in comparision
    * @param toffset index to start comparison at for this String
    * @param other String to compare region to this String
-   * @param ooffset index to start comparison at for other
+   * @param oofset index to start comparison at for other
    * @param len number of characters to compare
    * @return true if regions match, false otherwise
    * @throws NullPointerException if other is null
    */
-  public boolean regionMatches(boolean ignoreCase, int toffset,
-                               String other, int ooffset, int len)
-  {
-    if (toffset < 0 || ooffset < 0 || toffset + len > count
-        || ooffset + len > other.count)
-      return false;
-    toffset += offset;
-    ooffset += other.offset;
-    while (--len >= 0)
-      {
-        char c1 = value[toffset++];
-        char c2 = other.value[ooffset++];
-        // Note that checking c1 != c2 is redundant when ignoreCase is true,
-        // but it avoids method calls.
-        if (c1 != c2
-            && (! ignoreCase
-                || (Character.toLowerCase(c1) != Character.toLowerCase(c2)
-                    && (Character.toUpperCase(c1)
-                        != Character.toUpperCase(c2)))))
-          return false;
-      }
-    return true;
-  }
+  public native boolean regionMatches(boolean ignoreCase, int toffset,
+				      String other, int ooffset, int len);
 
   /**
    * Predicate which determines if this String contains the given prefix,
@@ -906,10 +684,7 @@
    * @throws NullPointerException if prefix is null
    * @see #regionMatches(boolean, int, String, int, int)
    */
-  public boolean startsWith(String prefix, int toffset)
-  {
-    return regionMatches(false, toffset, prefix, 0, prefix.count);
-  }
+  public native boolean startsWith(String prefix, int toffset);
 
   /**
    * Predicate which determines if this String starts with a given prefix.
@@ -922,7 +697,7 @@
    */
   public boolean startsWith(String prefix)
   {
-    return regionMatches(false, 0, prefix, 0, prefix.count);
+    return startsWith (prefix, 0);
   }
 
   /**
@@ -936,7 +711,7 @@
    */
   public boolean endsWith(String suffix)
   {
-    return regionMatches(false, count - suffix.count, suffix, 0, suffix.count);
+    return regionMatches (this.count - suffix.count, suffix, 0, suffix.count);
   }
 
   /**
@@ -946,18 +721,7 @@
    *
    * @return hashcode value of this String
    */
-  public int hashCode()
-  {
-    if (cachedHashCode != 0)
-      return cachedHashCode;
-
-    // Compute the hash code using a local variable to be reentrant.
-    int hashCode = 0;
-    int limit = count + offset;
-    for (int i = offset; i < limit; i++)
-      hashCode = hashCode * 31 + value[i];
-    return cachedHashCode = hashCode;
-  }
+  public native int hashCode();
 
   /**
    * Finds the first instance of a character in this String.
@@ -980,18 +744,7 @@
    * @param fromIndex index to start the search
    * @return location (base 0) of the character, or -1 if not found
    */
-  public int indexOf(int ch, int fromIndex)
-  {
-    if ((char) ch != ch)
-      return -1;
-    if (fromIndex < 0)
-      fromIndex = 0;
-    int i = fromIndex + offset;
-    for ( ; fromIndex < count; fromIndex++)
-      if (value[i++] == ch)
-        return fromIndex;
-    return -1;
-  }
+  public native int indexOf(int ch, int fromIndex);
 
   /**
    * Finds the last instance of a character in this String.
@@ -1014,18 +767,7 @@
    * @param fromIndex index to start the search
    * @return location (base 0) of the character, or -1 if not found
    */
-  public int lastIndexOf(int ch, int fromIndex)
-  {
-    if ((char) ch != ch)
-      return -1;
-    if (fromIndex >= count)
-      fromIndex = count - 1;
-    int i = fromIndex + offset;
-    for ( ; fromIndex >= 0; fromIndex--)
-      if (value[i--] == ch)
-        return fromIndex;
-    return -1;
-  }
+  public native int lastIndexOf(int ch, int fromIndex);
 
   /**
    * Finds the first instance of a String in this String.
@@ -1050,16 +792,7 @@
    * @return location (base 0) of the String, or -1 if not found
    * @throws NullPointerException if str is null
    */
-  public int indexOf(String str, int fromIndex)
-  {
-    if (fromIndex < 0)
-      fromIndex = 0;
-    int limit = count - str.count;
-    for ( ; fromIndex <= limit; fromIndex++)
-      if (regionMatches(fromIndex, str, 0, str.count))
-        return fromIndex;
-    return -1;
-  }
+  public native int indexOf(String str, int fromIndex);
 
   /**
    * Finds the last instance of a String in this String.
@@ -1086,11 +819,15 @@
    */
   public int lastIndexOf(String str, int fromIndex)
   {
-    fromIndex = Math.min(fromIndex, count - str.count);
-    for ( ; fromIndex >= 0; fromIndex--)
-      if (regionMatches(fromIndex, str, 0, str.count))
-        return fromIndex;
-    return -1;
+    if (fromIndex >= count)
+      fromIndex = count - str.count;
+    for (;; --fromIndex)
+      {
+	if (fromIndex < 0)
+	  return -1;
+	if (startsWith(str, fromIndex))
+	  return fromIndex;
+      }
   }
 
   /**
@@ -1111,24 +848,14 @@
    * Creates a substring of this String, starting at a specified index
    * and ending at one character before a specified index.
    *
-   * @param beginIndex index to start substring (inclusive, base 0)
-   * @param endIndex index to end at (exclusive)
+   * @param begin index to start substring (inclusive, base 0)
+   * @param end index to end at (exclusive)
    * @return new String which is a substring of this String
    * @throws IndexOutOfBoundsException if begin &lt; 0 || end &gt; length()
    *         || begin &gt; end (while unspecified, this is a
    *         StringIndexOutOfBoundsException)
    */
-  public String substring(int beginIndex, int endIndex)
-  {
-    if (beginIndex < 0 || endIndex > count || beginIndex > endIndex)
-      throw new StringIndexOutOfBoundsException();
-    if (beginIndex == 0 && endIndex == count)
-      return this;
-    int len = endIndex - beginIndex;
-    // Package constructor avoids an array copy.
-    return new String(value, beginIndex + offset, len,
-                      (len << 2) >= value.length);
-  }
+  public native String substring(int begin, int end);
 
   /**
    * Creates a substring of this String, starting at a specified index
@@ -1155,18 +882,7 @@
    * @return newly concatenated String
    * @throws NullPointerException if str is null
    */
-  public String concat(String str)
-  {
-    if (str.count == 0)
-      return this;
-    if (count == 0)
-      return str;
-    char[] newStr = new char[count + str.count];
-    VMSystem.arraycopy(value, offset, newStr, 0, count);
-    VMSystem.arraycopy(str.value, str.offset, newStr, count, str.count);
-    // Package constructor avoids an array copy.
-    return new String(newStr, 0, newStr.length, true);
-  }
+  public native String concat(String str);
 
   /**
    * Replaces every instance of a character in this String with a new
@@ -1176,25 +892,7 @@
    * @param newChar the new character
    * @return new String with all instances of oldChar replaced with newChar
    */
-  public String replace(char oldChar, char newChar)
-  {
-    if (oldChar == newChar)
-      return this;
-    int i = count;
-    int x = offset - 1;
-    while (--i >= 0)
-      if (value[++x] == oldChar)
-        break;
-    if (i < 0)
-      return this;
-    char[] newStr = (char[]) value.clone();
-    newStr[x] = newChar;
-    while (--i >= 0)
-      if (value[++x] == oldChar)
-        newStr[x] = newChar;
-    // Package constructor avoids an array copy.
-    return new String(newStr, offset, count, true);
-  }
+  public native String replace(char oldChar, char newChar);
 
   /**
    * Test if this String matches a regular expression. This is shorthand for
@@ -1325,36 +1023,7 @@
    * @see #toUpperCase(Locale)
    * @since 1.1
    */
-  public String toLowerCase(Locale loc)
-  {
-    // First, see if the current string is already lower case.
-    boolean turkish = "tr".equals(loc.getLanguage());
-    int i = count;
-    int x = offset - 1;
-    while (--i >= 0)
-      {
-        char ch = value[++x];
-        if ((turkish && ch == '\u0049')
-            || ch != Character.toLowerCase(ch))
-          break;
-      }
-    if (i < 0)
-      return this;
-
-    // Now we perform the conversion. Fortunately, there are no multi-character
-    // lowercase expansions in Unicode 3.0.0.
-    char[] newStr = (char[]) value.clone();
-    do
-      {
-        char ch = value[x];
-        // Hardcoded special case.
-        newStr[x++] = (turkish && ch == '\u0049') ? '\u0131'
-          : Character.toLowerCase(ch);
-      }
-    while (--i >= 0);
-    // Package constructor avoids an array copy.
-    return new String(newStr, offset, count, true);
-  }
+  public native String toLowerCase(Locale locale);
 
   /**
    * Lowercases this String. This uses Unicode's special case mappings, as
@@ -1367,7 +1036,11 @@
    */
   public String toLowerCase()
   {
-    return toLowerCase(Locale.getDefault());
+    // The JDK is a bit confused about what to do here.  If we pass in
+    // the default Locale then special Locale handling might be
+    // invoked.  However, the docs also say that Character.toLowerCase
+    // rules here.  We go with the latter.
+    return toLowerCase (null);
   }
 
   /**
@@ -1381,67 +1054,7 @@
    * @see #toLowerCase(Locale)
    * @since 1.1
    */
-  public String toUpperCase(Locale loc)
-  {
-    // First, see how many characters we have to grow by, as well as if the
-    // current string is already upper case.
-    boolean turkish = "tr".equals(loc.getLanguage());
-    int expand = 0;
-    boolean unchanged = true;
-    int i = count;
-    int x = i + offset;
-    while (--i >= 0)
-      {
-        char ch = value[--x];
-        expand += upperCaseExpansion(ch);
-        unchanged = (unchanged && expand == 0
-                     && ! (turkish && ch == '\u0069')
-                     && ch == Character.toUpperCase(ch));
-      }
-    if (unchanged)
-      return this;
-
-    // Now we perform the conversion.
-    i = count;
-    if (expand == 0)
-      {
-        char[] newStr = (char[]) value.clone();
-        while (--i >= 0)
-          {
-            char ch = value[x];
-            // Hardcoded special case.
-            newStr[x++] = (turkish && ch == '\u0069') ? '\u0130'
-              : Character.toUpperCase(ch);
-          }
-        // Package constructor avoids an array copy.
-        return new String(newStr, offset, count, true);
-      }
-
-    // Expansion is necessary.
-    char[] newStr = new char[count + expand];
-    int j = 0;
-    while (--i >= 0)
-      {
-        char ch = value[x++];
-        // Hardcoded special case.
-        if (turkish && ch == '\u0069')
-          {
-            newStr[j++] = '\u0130';
-            continue;
-          }
-        expand = upperCaseExpansion(ch);
-        if (expand > 0)
-          {
-            int index = upperCaseIndex(ch);
-            while (expand-- >= 0)
-              newStr[j++] = upperExpand[index++];
-          }
-        else
-          newStr[j++] = Character.toUpperCase(ch);
-      }
-    // Package constructor avoids an array copy.
-    return new String(newStr, 0, newStr.length, true);
-  }
+  public native String toUpperCase(Locale locale);
 
   /**
    * Uppercases this String. This uses Unicode's special case mappings, as
@@ -1454,32 +1067,22 @@
    */
   public String toUpperCase()
   {
-    return toUpperCase(Locale.getDefault());
+    // The JDK is a bit confused about what to do here.  If we pass in
+    // the default Locale then special Locale handling might be
+    // invoked.  However, the docs also say that Character.toLowerCase
+    // rules here.  We go with the latter.
+    return toUpperCase (null);
   }
 
   /**
    * Trims all characters less than or equal to <code>'\u0020'</code>
    * (<code>' '</code>) from the beginning and end of this String. This
    * includes many, but not all, ASCII control characters, and all
-   * {@link Character#isWhitespace(char)}.
+   * {@link Character#whitespace(char)}.
    *
    * @return new trimmed String, or this if nothing trimmed
    */
-  public String trim()
-  {
-    int limit = count + offset;
-    if (count == 0 || (value[offset] > '\u0020'
-                       && value[limit - 1] > '\u0020'))
-      return this;
-    int begin = offset;
-    do
-      if (begin == limit)
-        return "";
-    while (value[begin++] <= '\u0020');
-    int end = limit;
-    while (value[--end] <= '\u0020');
-    return substring(begin - offset - 1, end - offset + 1);
-  }
+  public native String trim();
 
   /**
    * Returns this, as it is already a String!
@@ -1497,15 +1100,7 @@
    *
    * @return character array copying the String
    */
-  public char[] toCharArray()
-  {
-    if (count == value.length)
-      return (char[]) value.clone();
-
-    char[] copy = new char[count];
-    VMSystem.arraycopy(value, offset, copy, 0, count);
-    return copy;
-  }
+  public native char[] toCharArray();
 
   /**
    * Returns a String representation of an Object. This is "null" if the
@@ -1550,10 +1145,7 @@
    *         (while unspecified, this is a StringIndexOutOfBoundsException)
    * @see #String(char[], int, int)
    */
-  public static String valueOf(char[] data, int offset, int count)
-  {
-    return new String(data, offset, count, false);
-  }
+  public static native String valueOf(char[] data, int offset, int count);
 
   /**
    * Returns a String representing the character sequence of the char array,
@@ -1572,7 +1164,9 @@
    */
   public static String copyValueOf(char[] data, int offset, int count)
   {
-    return new String(data, offset, count, false);
+    String r = new String ();
+    r.init(data, offset, count, false);
+    return r;
   }
 
   /**
@@ -1607,11 +1201,7 @@
    * @param c the character
    * @return String containing the single character c
    */
-  public static String valueOf(char c)
-  {
-    // Package constructor avoids an array copy.
-    return new String(new char[] { c }, 0, 1, true);
-  }
+  public static native String valueOf(char c);
 
   /**
    * Returns a String representing an integer.
@@ -1620,11 +1210,7 @@
    * @return String containing the integer in base 10
    * @see Integer#toString(int)
    */
-  public static String valueOf(int i)
-  {
-    // See Integer to understand why we call the two-arg variant.
-    return Integer.toString(i, 10);
-  }
+  public static native String valueOf(int i);
 
   /**
    * Returns a String representing a long.
@@ -1663,88 +1249,21 @@
   }
 
   /**
-   * If two Strings are considered equal, by the equals() method, 
-   * then intern() will return the same String instance. ie. 
-   * if (s1.equals(s2)) then (s1.intern() == s2.intern()). 
-   * All string literals and string-valued constant expressions 
-   * are already interned.
+   * Fetches this String from the intern hashtable. If two Strings are
+   * considered equal, by the equals() method, then intern() will return the
+   * same String instance. ie. if (s1.equals(s2)) then
+   * (s1.intern() == s2.intern()). All string literals and string-valued
+   * constant expressions are already interned.
    *
    * @return the interned String
    */
-  public String intern()
-  {
-    return VMString.intern(this);
-  }
+  public native String intern();
 
-  /**
-   * Helper function used to detect which characters have a multi-character
-   * uppercase expansion. Note that this is only used in locations which
-   * track one-to-many capitalization (java.lang.Character does not do this).
-   * As of Unicode 3.0.0, the result is limited in the range 0 to 2, as the
-   * longest uppercase expansion is three characters (a growth of 2 from the
-   * lowercase character).
-   *
-   * @param ch the char to check
-   * @return the number of characters to add when converting to uppercase
-   * @see CharData#DIRECTION
-   * @see CharData#UPPER_SPECIAL
-   * @see #toUpperCase(Locale)
-   */
-  private static int upperCaseExpansion(char ch)
-  {
-    return Character.direction[Character.readChar(ch) >> 7] & 3;
-  }
 
-  /**
-   * Helper function used to locate the offset in upperExpand given a
-   * character with a multi-character expansion. The binary search is
-   * optimized under the assumption that this method will only be called on
-   * characters which exist in upperSpecial.
-   *
-   * @param ch the char to check
-   * @return the index where its expansion begins
-   * @see CharData#UPPER_SPECIAL
-   * @see CharData#UPPER_EXPAND
-   * @see #toUpperCase(Locale)
-   */
-  private static int upperCaseIndex(char ch)
-  {
-    // Simple binary search for the correct character.
-    int low = 0;
-    int hi = upperSpecial.length - 2;
-    int mid = ((low + hi) >> 2) << 1;
-    char c = upperSpecial[mid];
-    while (ch != c)
-      {
-        if (ch < c)
-          hi = mid - 2;
-        else
-          low = mid + 2;
-        mid = ((low + hi) >> 2) << 1;
-        c = upperSpecial[mid];
-      }
-    return upperSpecial[mid + 1];
-  }
-
-  /**
-   * Returns the value array of the given string if it is zero based or a
-   * copy of it that is zero based (stripping offset and making length equal
-   * to count). Used for accessing the char[]s of gnu.java.lang.CharData.
-   * Package private for use in Character.
-   */
-  static char[] zeroBasedStringValue(String s)
-  {
-    char[] value;
-
-    if (s.offset == 0 && s.count == s.value.length)
-      value = s.value;
-    else
-      {
-	int count = s.count;
-	value = new char[count];
-	VMSystem.arraycopy(s.value, s.offset, value, 0, count);
-      }
-
-    return value;
-  }
+  private native void init(char[] chars, int offset, int count,
+			   boolean dont_copy);
+  private native void init(byte[] chars, int hibyte, int offset, int count);
+  private native void init(byte[] chars, int offset, int count, String enc)
+    throws UnsupportedEncodingException;
+  private native void init(gnu.gcj.runtime.StringBuffer buffer);
 }
