| 1 | 14 | jlechner | // natString.cc - Implementation of java.lang.String native methods.
 | 
      
         | 2 |  |  |  
 | 
      
         | 3 |  |  | /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006  Free Software Foundation
 | 
      
         | 4 |  |  |  
 | 
      
         | 5 |  |  |    This file is part of libgcj.
 | 
      
         | 6 |  |  |  
 | 
      
         | 7 |  |  | This software is copyrighted work licensed under the terms of the
 | 
      
         | 8 |  |  | Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
 | 
      
         | 9 |  |  | details.  */
 | 
      
         | 10 |  |  |  
 | 
      
         | 11 |  |  | #include <config.h>
 | 
      
         | 12 |  |  |  
 | 
      
         | 13 |  |  | #include <string.h>
 | 
      
         | 14 |  |  | #include <stdlib.h>
 | 
      
         | 15 |  |  |  
 | 
      
         | 16 |  |  | #include <gcj/cni.h>
 | 
      
         | 17 |  |  | #include <java/lang/Character.h>
 | 
      
         | 18 |  |  | #include <java/lang/CharSequence.h>
 | 
      
         | 19 |  |  | #include <java/lang/String.h>
 | 
      
         | 20 |  |  | #include <java/lang/IndexOutOfBoundsException.h>
 | 
      
         | 21 |  |  | #include <java/lang/ArrayIndexOutOfBoundsException.h>
 | 
      
         | 22 |  |  | #include <java/lang/StringIndexOutOfBoundsException.h>
 | 
      
         | 23 |  |  | #include <java/lang/NullPointerException.h>
 | 
      
         | 24 |  |  | #include <java/lang/StringBuffer.h>
 | 
      
         | 25 |  |  | #include <java/io/ByteArrayOutputStream.h>
 | 
      
         | 26 |  |  | #include <java/io/OutputStreamWriter.h>
 | 
      
         | 27 |  |  | #include <java/io/ByteArrayInputStream.h>
 | 
      
         | 28 |  |  | #include <java/io/InputStreamReader.h>
 | 
      
         | 29 |  |  | #include <java/util/Locale.h>
 | 
      
         | 30 |  |  | #include <gnu/gcj/convert/UnicodeToBytes.h>
 | 
      
         | 31 |  |  | #include <gnu/gcj/convert/BytesToUnicode.h>
 | 
      
         | 32 |  |  | #include <gnu/gcj/runtime/StringBuffer.h>
 | 
      
         | 33 |  |  | #include <jvm.h>
 | 
      
         | 34 |  |  |  
 | 
      
         | 35 |  |  | static jstring* strhash = NULL;
 | 
      
         | 36 |  |  | static int strhash_count = 0;  /* Number of slots used in strhash. */
 | 
      
         | 37 |  |  | static int strhash_size = 0;  /* Number of slots available in strhash.
 | 
      
         | 38 |  |  |                                * Assumed be power of 2! */
 | 
      
         | 39 |  |  |  
 | 
      
         | 40 |  |  | // Some defines used by toUpperCase / toLowerCase.
 | 
      
         | 41 |  |  | #define ESSET     0x00df
 | 
      
         | 42 |  |  | #define CAPITAL_S 0x0053
 | 
      
         | 43 |  |  | #define SMALL_I   0x0069
 | 
      
         | 44 |  |  | #define CAPITAL_I_WITH_DOT 0x0130
 | 
      
         | 45 |  |  | #define SMALL_DOTLESS_I    0x0131
 | 
      
         | 46 |  |  | #define CAPITAL_I 0x0049
 | 
      
         | 47 |  |  |  
 | 
      
         | 48 |  |  | #define DELETED_STRING ((jstring)(~0))
 | 
      
         | 49 |  |  | #define SET_STRING_IS_INTERNED(STR) /* nothing */
 | 
      
         | 50 |  |  |  
 | 
      
         | 51 |  |  | #define UNMASK_PTR(Ptr) (((unsigned long) (Ptr)) & ~0x01)
 | 
      
         | 52 |  |  | #define MASK_PTR(Ptr) (((unsigned long) (Ptr)) | 0x01)
 | 
      
         | 53 |  |  | #define PTR_MASKED(Ptr) (((unsigned long) (Ptr)) & 0x01)
 | 
      
         | 54 |  |  |  
 | 
      
         | 55 |  |  | /* Find a slot where the string with elements DATA, length LEN,
 | 
      
         | 56 |  |  |    and hash HASH should go in the strhash table of interned strings. */
 | 
      
         | 57 |  |  | jstring*
 | 
      
         | 58 |  |  | _Jv_StringFindSlot (jchar* data, jint len, jint hash)
 | 
      
         | 59 |  |  | {
 | 
      
         | 60 |  |  |   JvSynchronize sync (&java::lang::String::class$);
 | 
      
         | 61 |  |  |  
 | 
      
         | 62 |  |  |   int start_index = hash & (strhash_size - 1);
 | 
      
         | 63 |  |  |   int deleted_index = -1;
 | 
      
         | 64 |  |  |  
 | 
      
         | 65 |  |  |   int index = start_index;
 | 
      
         | 66 |  |  |   /* step must be non-zero, and relatively prime with strhash_size. */
 | 
      
         | 67 |  |  |   jint step = (hash ^ (hash >> 16)) | 1;
 | 
      
         | 68 |  |  |   do
 | 
      
         | 69 |  |  |     {
 | 
      
         | 70 |  |  |       jstring* ptr = &strhash[index];
 | 
      
         | 71 |  |  |       jstring value = (jstring) UNMASK_PTR (*ptr);
 | 
      
         | 72 |  |  |       if (value == NULL)
 | 
      
         | 73 |  |  |         {
 | 
      
         | 74 |  |  |           if (deleted_index >= 0)
 | 
      
         | 75 |  |  |             return (&strhash[deleted_index]);
 | 
      
         | 76 |  |  |           else
 | 
      
         | 77 |  |  |             return ptr;
 | 
      
         | 78 |  |  |         }
 | 
      
         | 79 |  |  |       else if (*ptr == DELETED_STRING)
 | 
      
         | 80 |  |  |         deleted_index = index;
 | 
      
         | 81 |  |  |       else if (value->length() == len
 | 
      
         | 82 |  |  |                && memcmp(JvGetStringChars(value), data, 2*len) == 0)
 | 
      
         | 83 |  |  |         return (ptr);
 | 
      
         | 84 |  |  |       index = (index + step) & (strhash_size - 1);
 | 
      
         | 85 |  |  |     }
 | 
      
         | 86 |  |  |   while (index != start_index);
 | 
      
         | 87 |  |  |   // Note that we can have INDEX == START_INDEX if the table has no
 | 
      
         | 88 |  |  |   // NULL entries but does have DELETED_STRING entries.
 | 
      
         | 89 |  |  |   JvAssert (deleted_index >= 0);
 | 
      
         | 90 |  |  |   return &strhash[deleted_index];
 | 
      
         | 91 |  |  | }
 | 
      
         | 92 |  |  |  
 | 
      
         | 93 |  |  | /* Calculate a hash code for the string starting at PTR at given LENGTH.
 | 
      
         | 94 |  |  |    This uses the same formula as specified for java.lang.String.hash. */
 | 
      
         | 95 |  |  |  
 | 
      
         | 96 |  |  | static jint
 | 
      
         | 97 |  |  | hashChars (jchar* ptr, jint length)
 | 
      
         | 98 |  |  | {
 | 
      
         | 99 |  |  |   jchar* limit = ptr + length;
 | 
      
         | 100 |  |  |   jint hash = 0;
 | 
      
         | 101 |  |  |   // Updated specification from
 | 
      
         | 102 |  |  |   // http://www.javasoft.com/docs/books/jls/clarify.html.
 | 
      
         | 103 |  |  |   while (ptr < limit)
 | 
      
         | 104 |  |  |     hash = (31 * hash) + *ptr++;
 | 
      
         | 105 |  |  |   return hash;
 | 
      
         | 106 |  |  | }
 | 
      
         | 107 |  |  |  
 | 
      
         | 108 |  |  | jint
 | 
      
         | 109 |  |  | java::lang::String::hashCode()
 | 
      
         | 110 |  |  | {
 | 
      
         | 111 |  |  |   if (cachedHashCode == 0)
 | 
      
         | 112 |  |  |     cachedHashCode = hashChars(JvGetStringChars(this), length());
 | 
      
         | 113 |  |  |   return cachedHashCode;
 | 
      
         | 114 |  |  | }
 | 
      
         | 115 |  |  |  
 | 
      
         | 116 |  |  | jstring*
 | 
      
         | 117 |  |  | _Jv_StringGetSlot (jstring str)
 | 
      
         | 118 |  |  | {
 | 
      
         | 119 |  |  |   jchar* data = JvGetStringChars(str);
 | 
      
         | 120 |  |  |   int length = str->length();
 | 
      
         | 121 |  |  |   return _Jv_StringFindSlot(data, length, hashChars (data, length));
 | 
      
         | 122 |  |  | }
 | 
      
         | 123 |  |  |  
 | 
      
         | 124 |  |  | static void
 | 
      
         | 125 |  |  | rehash ()
 | 
      
         | 126 |  |  | {
 | 
      
         | 127 |  |  |   JvSynchronize sync (&java::lang::String::class$);
 | 
      
         | 128 |  |  |  
 | 
      
         | 129 |  |  |   if (strhash == NULL)
 | 
      
         | 130 |  |  |     {
 | 
      
         | 131 |  |  |       strhash_size = 1024;
 | 
      
         | 132 |  |  |       strhash = (jstring *) _Jv_AllocBytes (strhash_size * sizeof (jstring));
 | 
      
         | 133 |  |  |     }
 | 
      
         | 134 |  |  |   else
 | 
      
         | 135 |  |  |     {
 | 
      
         | 136 |  |  |       int i = strhash_size;
 | 
      
         | 137 |  |  |       jstring* ptr = strhash + i;
 | 
      
         | 138 |  |  |       int nsize = strhash_size * 2;
 | 
      
         | 139 |  |  |       jstring *next = (jstring *) _Jv_AllocBytes (nsize * sizeof (jstring));
 | 
      
         | 140 |  |  |  
 | 
      
         | 141 |  |  |       while (--i >= 0)
 | 
      
         | 142 |  |  |         {
 | 
      
         | 143 |  |  |           --ptr;
 | 
      
         | 144 |  |  |           if (*ptr == NULL || *ptr == DELETED_STRING)
 | 
      
         | 145 |  |  |             continue;
 | 
      
         | 146 |  |  |  
 | 
      
         | 147 |  |  |           /* This is faster equivalent of
 | 
      
         | 148 |  |  |            * *__JvGetInternSlot(*ptr) = *ptr; */
 | 
      
         | 149 |  |  |           jstring val = (jstring) UNMASK_PTR (*ptr);
 | 
      
         | 150 |  |  |           jint hash = val->hashCode();
 | 
      
         | 151 |  |  |           jint index = hash & (nsize - 1);
 | 
      
         | 152 |  |  |           jint step = (hash ^ (hash >> 16)) | 1;
 | 
      
         | 153 |  |  |           for (;;)
 | 
      
         | 154 |  |  |             {
 | 
      
         | 155 |  |  |               if (next[index] == NULL)
 | 
      
         | 156 |  |  |                 {
 | 
      
         | 157 |  |  |                   next[index] = *ptr;
 | 
      
         | 158 |  |  |                   break;
 | 
      
         | 159 |  |  |                 }
 | 
      
         | 160 |  |  |               index = (index + step) & (nsize - 1);
 | 
      
         | 161 |  |  |             }
 | 
      
         | 162 |  |  |         }
 | 
      
         | 163 |  |  |  
 | 
      
         | 164 |  |  |       strhash_size = nsize;
 | 
      
         | 165 |  |  |       strhash = next;
 | 
      
         | 166 |  |  |     }
 | 
      
         | 167 |  |  | }
 | 
      
         | 168 |  |  |  
 | 
      
         | 169 |  |  | jstring
 | 
      
         | 170 |  |  | java::lang::String::intern()
 | 
      
         | 171 |  |  | {
 | 
      
         | 172 |  |  |   JvSynchronize sync (&java::lang::String::class$);
 | 
      
         | 173 |  |  |   if (3 * strhash_count >= 2 * strhash_size)
 | 
      
         | 174 |  |  |     rehash();
 | 
      
         | 175 |  |  |   jstring* ptr = _Jv_StringGetSlot(this);
 | 
      
         | 176 |  |  |   if (*ptr != NULL && *ptr != DELETED_STRING)
 | 
      
         | 177 |  |  |     {
 | 
      
         | 178 |  |  |       // See description in _Jv_FinalizeString() to understand this.
 | 
      
         | 179 |  |  |       *ptr = (jstring) MASK_PTR (*ptr);
 | 
      
         | 180 |  |  |       return (jstring) UNMASK_PTR (*ptr);
 | 
      
         | 181 |  |  |     }
 | 
      
         | 182 |  |  |   jstring str = (this->data == this
 | 
      
         | 183 |  |  |                  ? this
 | 
      
         | 184 |  |  |                  : _Jv_NewString(JvGetStringChars(this), this->length()));
 | 
      
         | 185 |  |  |   SET_STRING_IS_INTERNED(str);
 | 
      
         | 186 |  |  |   strhash_count++;
 | 
      
         | 187 |  |  |   *ptr = str;
 | 
      
         | 188 |  |  |   // When string is GC'd, clear the slot in the hash table.
 | 
      
         | 189 |  |  |   _Jv_RegisterStringFinalizer (str);
 | 
      
         | 190 |  |  |   return str;
 | 
      
         | 191 |  |  | }
 | 
      
         | 192 |  |  |  
 | 
      
         | 193 |  |  | // The fake String finalizer.  This is only used when the String has
 | 
      
         | 194 |  |  | // been intern()d.  However, we must check this case, as it might be
 | 
      
         | 195 |  |  | // called by the Reference code for any String.
 | 
      
         | 196 |  |  | void
 | 
      
         | 197 |  |  | _Jv_FinalizeString (jobject obj)
 | 
      
         | 198 |  |  | {
 | 
      
         | 199 |  |  |   JvSynchronize sync (&java::lang::String::class$);
 | 
      
         | 200 |  |  |  
 | 
      
         | 201 |  |  |   // We might not actually have intern()d any strings at all, if
 | 
      
         | 202 |  |  |   // we're being called from Reference.
 | 
      
         | 203 |  |  |   if (! strhash)
 | 
      
         | 204 |  |  |     return;
 | 
      
         | 205 |  |  |  
 | 
      
         | 206 |  |  |   jstring str = reinterpret_cast<jstring> (obj);
 | 
      
         | 207 |  |  |   jstring *ptr = _Jv_StringGetSlot(str);
 | 
      
         | 208 |  |  |   if (*ptr == NULL || *ptr == DELETED_STRING
 | 
      
         | 209 |  |  |       || (jobject) UNMASK_PTR (*ptr) != obj)
 | 
      
         | 210 |  |  |     return;
 | 
      
         | 211 |  |  |  
 | 
      
         | 212 |  |  |   // We assume the lowest bit of the pointer is free for our nefarious
 | 
      
         | 213 |  |  |   // manipulations.  What we do is set it to `0' (implicitly) when
 | 
      
         | 214 |  |  |   // interning the String.  If we subsequently re-intern the same
 | 
      
         | 215 |  |  |   // String, then we set the bit.  When finalizing, if the bit is set
 | 
      
         | 216 |  |  |   // then we clear it and re-register the finalizer.  We know this is
 | 
      
         | 217 |  |  |   // a safe approach because both intern() and _Jv_FinalizeString()
 | 
      
         | 218 |  |  |   // acquire the class lock; this bit can't be manipulated when the
 | 
      
         | 219 |  |  |   // lock is not held.  So if we are finalizing and the bit is clear
 | 
      
         | 220 |  |  |   // then we know all references are gone and we can clear the entry
 | 
      
         | 221 |  |  |   // in the hash table.  The naive approach of simply clearing the
 | 
      
         | 222 |  |  |   // pointer here fails in the case where a request to intern a new
 | 
      
         | 223 |  |  |   // string with the same contents is made between the time the
 | 
      
         | 224 |  |  |   // intern()d string is found to be unreachable and when the
 | 
      
         | 225 |  |  |   // finalizer is actually run.  In this case we could clear a pointer
 | 
      
         | 226 |  |  |   // to a valid string, and future intern() calls for that particular
 | 
      
         | 227 |  |  |   // value would spuriously fail.
 | 
      
         | 228 |  |  |   if (PTR_MASKED (*ptr))
 | 
      
         | 229 |  |  |     {
 | 
      
         | 230 |  |  |       *ptr = (jstring) UNMASK_PTR (*ptr);
 | 
      
         | 231 |  |  |       _Jv_RegisterStringFinalizer (obj);
 | 
      
         | 232 |  |  |     }
 | 
      
         | 233 |  |  |   else
 | 
      
         | 234 |  |  |     {
 | 
      
         | 235 |  |  |       *ptr = DELETED_STRING;
 | 
      
         | 236 |  |  |       strhash_count--;
 | 
      
         | 237 |  |  |     }
 | 
      
         | 238 |  |  | }
 | 
      
         | 239 |  |  |  
 | 
      
         | 240 |  |  | jstring
 | 
      
         | 241 |  |  | _Jv_NewStringUTF (const char *bytes)
 | 
      
         | 242 |  |  | {
 | 
      
         | 243 |  |  |   int size = strlen (bytes);
 | 
      
         | 244 |  |  |   unsigned char *p = (unsigned char *) bytes;
 | 
      
         | 245 |  |  |  
 | 
      
         | 246 |  |  |   int length = _Jv_strLengthUtf8 ((char *) p, size);
 | 
      
         | 247 |  |  |   if (length < 0)
 | 
      
         | 248 |  |  |     return NULL;
 | 
      
         | 249 |  |  |  
 | 
      
         | 250 |  |  |   jstring jstr = JvAllocString (length);
 | 
      
         | 251 |  |  |   jchar *chrs = JvGetStringChars (jstr);
 | 
      
         | 252 |  |  |  
 | 
      
         | 253 |  |  |   p = (unsigned char *) bytes;
 | 
      
         | 254 |  |  |   unsigned char *limit = p + size;
 | 
      
         | 255 |  |  |   while (p < limit)
 | 
      
         | 256 |  |  |     *chrs++ = UTF8_GET (p, limit);
 | 
      
         | 257 |  |  |  
 | 
      
         | 258 |  |  |   return jstr;
 | 
      
         | 259 |  |  | }
 | 
      
         | 260 |  |  |  
 | 
      
         | 261 |  |  | jstring
 | 
      
         | 262 |  |  | _Jv_NewStringUtf8Const (Utf8Const* str)
 | 
      
         | 263 |  |  | {
 | 
      
         | 264 |  |  |   jchar *chrs;
 | 
      
         | 265 |  |  |   jchar buffer[100];
 | 
      
         | 266 |  |  |   jstring jstr;
 | 
      
         | 267 |  |  |   unsigned char* data = (unsigned char*) str->data;
 | 
      
         | 268 |  |  |   unsigned char* limit = data + str->length;
 | 
      
         | 269 |  |  |   int length = _Jv_strLengthUtf8(str->data, str->length);
 | 
      
         | 270 |  |  |  
 | 
      
         | 271 |  |  |   if (length <= (int) (sizeof(buffer) / sizeof(jchar)))
 | 
      
         | 272 |  |  |     {
 | 
      
         | 273 |  |  |       jstr = NULL;
 | 
      
         | 274 |  |  |       chrs = buffer;
 | 
      
         | 275 |  |  |     }
 | 
      
         | 276 |  |  |   else
 | 
      
         | 277 |  |  |     {
 | 
      
         | 278 |  |  |       jstr = JvAllocString(length);
 | 
      
         | 279 |  |  |       chrs = JvGetStringChars(jstr);
 | 
      
         | 280 |  |  |     }
 | 
      
         | 281 |  |  |  
 | 
      
         | 282 |  |  |   jint hash = 0;
 | 
      
         | 283 |  |  |   while (data < limit)
 | 
      
         | 284 |  |  |     {
 | 
      
         | 285 |  |  |       jchar ch = UTF8_GET(data, limit);
 | 
      
         | 286 |  |  |       hash = (31 * hash) + ch;
 | 
      
         | 287 |  |  |       *chrs++ = ch;
 | 
      
         | 288 |  |  |     }
 | 
      
         | 289 |  |  |   chrs -= length;
 | 
      
         | 290 |  |  |  
 | 
      
         | 291 |  |  |   JvSynchronize sync (&java::lang::String::class$);
 | 
      
         | 292 |  |  |   if (3 * strhash_count >= 2 * strhash_size)
 | 
      
         | 293 |  |  |     rehash();
 | 
      
         | 294 |  |  |   jstring* ptr = _Jv_StringFindSlot (chrs, length, hash);
 | 
      
         | 295 |  |  |   if (*ptr != NULL && *ptr != DELETED_STRING)
 | 
      
         | 296 |  |  |     return (jstring) UNMASK_PTR (*ptr);
 | 
      
         | 297 |  |  |   strhash_count++;
 | 
      
         | 298 |  |  |   if (jstr == NULL)
 | 
      
         | 299 |  |  |     {
 | 
      
         | 300 |  |  |       jstr = JvAllocString(length);
 | 
      
         | 301 |  |  |       chrs = JvGetStringChars(jstr);
 | 
      
         | 302 |  |  |       memcpy (chrs, buffer, sizeof(jchar)*length);
 | 
      
         | 303 |  |  |     }
 | 
      
         | 304 |  |  |   jstr->cachedHashCode = hash;
 | 
      
         | 305 |  |  |   *ptr = jstr;
 | 
      
         | 306 |  |  |   SET_STRING_IS_INTERNED(jstr);
 | 
      
         | 307 |  |  |   // When string is GC'd, clear the slot in the hash table.  Note that
 | 
      
         | 308 |  |  |   // we don't have to call _Jv_RegisterStringFinalizer here, as we
 | 
      
         | 309 |  |  |   // know the new object cannot be referred to by a Reference.
 | 
      
         | 310 |  |  |   _Jv_RegisterFinalizer ((void *) jstr, _Jv_FinalizeString);
 | 
      
         | 311 |  |  |   return jstr;
 | 
      
         | 312 |  |  | }
 | 
      
         | 313 |  |  |  
 | 
      
         | 314 |  |  | jsize
 | 
      
         | 315 |  |  | _Jv_GetStringUTFLength (jstring string)
 | 
      
         | 316 |  |  | {
 | 
      
         | 317 |  |  |   jsize len = 0;
 | 
      
         | 318 |  |  |   jchar *ptr = JvGetStringChars (string);
 | 
      
         | 319 |  |  |   jsize i = string->length();
 | 
      
         | 320 |  |  |   while (--i >= 0)
 | 
      
         | 321 |  |  |     {
 | 
      
         | 322 |  |  |       jchar ch = *ptr++;
 | 
      
         | 323 |  |  |       if (ch > 0 && ch <= 0x7F)
 | 
      
         | 324 |  |  |         len += 1;
 | 
      
         | 325 |  |  |       else if (ch <= 0x7FF)
 | 
      
         | 326 |  |  |         len += 2;
 | 
      
         | 327 |  |  |       else
 | 
      
         | 328 |  |  |         len += 3;
 | 
      
         | 329 |  |  |     }
 | 
      
         | 330 |  |  |   return len;
 | 
      
         | 331 |  |  | }
 | 
      
         | 332 |  |  |  
 | 
      
         | 333 |  |  | // Not sure this quite matches GetStringUTFRegion.
 | 
      
         | 334 |  |  | // null-termination of result?  len?  throw exception?
 | 
      
         | 335 |  |  | jsize
 | 
      
         | 336 |  |  | _Jv_GetStringUTFRegion (jstring str, jsize start, jsize len, char *buf)
 | 
      
         | 337 |  |  | {
 | 
      
         | 338 |  |  |   jchar *sptr = JvGetStringChars (str) + start;
 | 
      
         | 339 |  |  |   jsize i = len;
 | 
      
         | 340 |  |  |   char *dptr = buf;
 | 
      
         | 341 |  |  |   while (--i >= 0)
 | 
      
         | 342 |  |  |     {
 | 
      
         | 343 |  |  |       jchar ch = *sptr++;
 | 
      
         | 344 |  |  |       if (ch > 0 && ch <= 0x7F)
 | 
      
         | 345 |  |  |         *dptr++ = (char) ch;
 | 
      
         | 346 |  |  |       else if (ch <= 0x7FF)
 | 
      
         | 347 |  |  |         {
 | 
      
         | 348 |  |  |           *dptr++ = (char) (0xC0 + ((ch >> 6) & 0x1F));
 | 
      
         | 349 |  |  |           *dptr++ = (char) (0x80 + (ch & 0x3F));
 | 
      
         | 350 |  |  |         }
 | 
      
         | 351 |  |  |       else
 | 
      
         | 352 |  |  |         {
 | 
      
         | 353 |  |  |           *dptr++ = (char) (0xE0 + ((ch >> 12) & 0xF));
 | 
      
         | 354 |  |  |           *dptr++ = (char) (0x80 + ((ch >> 6) & 0x3F));
 | 
      
         | 355 |  |  |           *dptr++ = (char) (0x80 + (ch & 0x3F));
 | 
      
         | 356 |  |  |         }
 | 
      
         | 357 |  |  |     }
 | 
      
         | 358 |  |  |   return dptr - buf;
 | 
      
         | 359 |  |  | }
 | 
      
         | 360 |  |  |  
 | 
      
         | 361 |  |  | /* Put printed (decimal) representation of NUM in a buffer.
 | 
      
         | 362 |  |  |    BUFEND marks the end of the buffer, which must be at least 11 jchars long.
 | 
      
         | 363 |  |  |    Returns the COUNT of jchars written.  The result is in
 | 
      
         | 364 |  |  |    (BUFEND - COUNT) (inclusive) upto (BUFEND) (exclusive). */
 | 
      
         | 365 |  |  |  
 | 
      
         | 366 |  |  | jint
 | 
      
         | 367 |  |  | _Jv_FormatInt (jchar* bufend, jint num)
 | 
      
         | 368 |  |  | {
 | 
      
         | 369 |  |  |   register jchar* ptr = bufend;
 | 
      
         | 370 |  |  |   jboolean isNeg;
 | 
      
         | 371 |  |  |   if (num < 0)
 | 
      
         | 372 |  |  |     {
 | 
      
         | 373 |  |  |       isNeg = true;
 | 
      
         | 374 |  |  |       num = -(num);
 | 
      
         | 375 |  |  |       if (num < 0)
 | 
      
         | 376 |  |  |         {
 | 
      
         | 377 |  |  |           // Must be MIN_VALUE, so handle this special case.
 | 
      
         | 378 |  |  |           // FIXME use 'unsigned jint' for num.
 | 
      
         | 379 |  |  |           *--ptr = '8';
 | 
      
         | 380 |  |  |           num = 214748364;
 | 
      
         | 381 |  |  |         }
 | 
      
         | 382 |  |  |       }
 | 
      
         | 383 |  |  |     else
 | 
      
         | 384 |  |  |       isNeg = false;
 | 
      
         | 385 |  |  |  
 | 
      
         | 386 |  |  |     do
 | 
      
         | 387 |  |  |       {
 | 
      
         | 388 |  |  |         *--ptr = (jchar) ((int) '0' + (num % 10));
 | 
      
         | 389 |  |  |         num /= 10;
 | 
      
         | 390 |  |  |       }
 | 
      
         | 391 |  |  |     while (num > 0);
 | 
      
         | 392 |  |  |  
 | 
      
         | 393 |  |  |     if (isNeg)
 | 
      
         | 394 |  |  |       *--ptr = '-';
 | 
      
         | 395 |  |  |     return bufend - ptr;
 | 
      
         | 396 |  |  | }
 | 
      
         | 397 |  |  |  
 | 
      
         | 398 |  |  | jstring
 | 
      
         | 399 |  |  | java::lang::String::valueOf (jint num)
 | 
      
         | 400 |  |  | {
 | 
      
         | 401 |  |  |   // Use an array large enough for "-2147483648"; i.e. 11 chars.
 | 
      
         | 402 |  |  |   jchar buffer[11];
 | 
      
         | 403 |  |  |   int i = _Jv_FormatInt (buffer+11, num);
 | 
      
         | 404 |  |  |   return _Jv_NewString (buffer+11-i, i);
 | 
      
         | 405 |  |  | }
 | 
      
         | 406 |  |  |  
 | 
      
         | 407 |  |  | jstring
 | 
      
         | 408 |  |  | _Jv_NewString(const jchar *chars, jsize len)
 | 
      
         | 409 |  |  | {
 | 
      
         | 410 |  |  |   jstring str = _Jv_AllocString(len);
 | 
      
         | 411 |  |  |   jchar* data = JvGetStringChars (str);
 | 
      
         | 412 |  |  |   while (--len >= 0)
 | 
      
         | 413 |  |  |     *data++ = *chars++;
 | 
      
         | 414 |  |  |   return str;
 | 
      
         | 415 |  |  | }
 | 
      
         | 416 |  |  |  
 | 
      
         | 417 |  |  | jstring
 | 
      
         | 418 |  |  | _Jv_NewStringLatin1(const char *bytes, jsize len)
 | 
      
         | 419 |  |  | {
 | 
      
         | 420 |  |  |   jstring str = JvAllocString(len);
 | 
      
         | 421 |  |  |   jchar* data = JvGetStringChars (str);
 | 
      
         | 422 |  |  |   while (--len >= 0)
 | 
      
         | 423 |  |  |     *data++ = *(unsigned char*)bytes++;
 | 
      
         | 424 |  |  |   return str;
 | 
      
         | 425 |  |  | }
 | 
      
         | 426 |  |  |  
 | 
      
         | 427 |  |  | void
 | 
      
         | 428 |  |  | java::lang::String::init(jcharArray chars, jint offset, jint count,
 | 
      
         | 429 |  |  |                          jboolean dont_copy)
 | 
      
         | 430 |  |  | {
 | 
      
         | 431 |  |  |   if (! chars)
 | 
      
         | 432 |  |  |     throw new NullPointerException;
 | 
      
         | 433 |  |  |   jsize data_size = JvGetArrayLength (chars);
 | 
      
         | 434 |  |  |   if (offset < 0 || count < 0 || offset + count < 0
 | 
      
         | 435 |  |  |       || offset + count > data_size)
 | 
      
         | 436 |  |  |     throw new ArrayIndexOutOfBoundsException;
 | 
      
         | 437 |  |  |   jcharArray array;
 | 
      
         | 438 |  |  |   jchar *pdst;
 | 
      
         | 439 |  |  |   if (! dont_copy)
 | 
      
         | 440 |  |  |     {
 | 
      
         | 441 |  |  |       array = JvNewCharArray(count);
 | 
      
         | 442 |  |  |       pdst = elements (array);
 | 
      
         | 443 |  |  |       memcpy (pdst, elements (chars) + offset, count * sizeof (jchar));
 | 
      
         | 444 |  |  |     }
 | 
      
         | 445 |  |  |   else
 | 
      
         | 446 |  |  |     {
 | 
      
         | 447 |  |  |       array = chars;
 | 
      
         | 448 |  |  |       pdst = &(elements(array)[offset]);
 | 
      
         | 449 |  |  |     }
 | 
      
         | 450 |  |  |  
 | 
      
         | 451 |  |  |   data = array;
 | 
      
         | 452 |  |  |   boffset = (char *) pdst - (char *) array;
 | 
      
         | 453 |  |  |   this->count = count;
 | 
      
         | 454 |  |  | }
 | 
      
         | 455 |  |  |  
 | 
      
         | 456 |  |  | void
 | 
      
         | 457 |  |  | java::lang::String::init(jbyteArray ascii, jint hibyte, jint offset,
 | 
      
         | 458 |  |  |                          jint count)
 | 
      
         | 459 |  |  | {
 | 
      
         | 460 |  |  |   if (! ascii)
 | 
      
         | 461 |  |  |     throw new NullPointerException;
 | 
      
         | 462 |  |  |   jsize data_size = JvGetArrayLength (ascii);
 | 
      
         | 463 |  |  |   if (offset < 0 || count < 0 || offset + count < 0
 | 
      
         | 464 |  |  |       || offset + count > data_size)
 | 
      
         | 465 |  |  |     throw new ArrayIndexOutOfBoundsException;
 | 
      
         | 466 |  |  |   jcharArray array = JvNewCharArray(count);
 | 
      
         | 467 |  |  |   jbyte *psrc = elements (ascii) + offset;
 | 
      
         | 468 |  |  |   jchar *pdst = elements (array);
 | 
      
         | 469 |  |  |   data = array;
 | 
      
         | 470 |  |  |   boffset = (char *) pdst - (char *) array;
 | 
      
         | 471 |  |  |   this->count = count;
 | 
      
         | 472 |  |  |   hibyte = (hibyte & 0xff) << 8;
 | 
      
         | 473 |  |  |   while (-- count >= 0)
 | 
      
         | 474 |  |  |     {
 | 
      
         | 475 |  |  |       *pdst++ = hibyte | (*psrc++ & 0xff);
 | 
      
         | 476 |  |  |     }
 | 
      
         | 477 |  |  | }
 | 
      
         | 478 |  |  |  
 | 
      
         | 479 |  |  | void
 | 
      
         | 480 |  |  | java::lang::String::init (jbyteArray bytes, jint offset, jint count,
 | 
      
         | 481 |  |  |                           jstring encoding)
 | 
      
         | 482 |  |  | {
 | 
      
         | 483 |  |  |   if (! bytes)
 | 
      
         | 484 |  |  |     throw new NullPointerException;
 | 
      
         | 485 |  |  |   jsize data_size = JvGetArrayLength (bytes);
 | 
      
         | 486 |  |  |   if (offset < 0 || count < 0 || offset + count < 0
 | 
      
         | 487 |  |  |       || offset + count > data_size)
 | 
      
         | 488 |  |  |     throw new ArrayIndexOutOfBoundsException;
 | 
      
         | 489 |  |  |   jcharArray array = JvNewCharArray (count);
 | 
      
         | 490 |  |  |   gnu::gcj::convert::BytesToUnicode *converter
 | 
      
         | 491 |  |  |     = gnu::gcj::convert::BytesToUnicode::getDecoder(encoding);
 | 
      
         | 492 |  |  |   jint outpos = 0;
 | 
      
         | 493 |  |  |   int avail = count;
 | 
      
         | 494 |  |  |   converter->setInput(bytes, offset, offset+count);
 | 
      
         | 495 |  |  |   while (converter->inpos < converter->inlength)
 | 
      
         | 496 |  |  |     {
 | 
      
         | 497 |  |  |       int done = converter->read(array, outpos, avail);
 | 
      
         | 498 |  |  |       if (done == 0)
 | 
      
         | 499 |  |  |         {
 | 
      
         | 500 |  |  |           jint new_size = 2 * (outpos + avail);
 | 
      
         | 501 |  |  |           jcharArray new_array = JvNewCharArray (new_size);
 | 
      
         | 502 |  |  |           memcpy (elements (new_array), elements (array),
 | 
      
         | 503 |  |  |                   outpos * sizeof(jchar));
 | 
      
         | 504 |  |  |           array = new_array;
 | 
      
         | 505 |  |  |           avail = new_size - outpos;
 | 
      
         | 506 |  |  |         }
 | 
      
         | 507 |  |  |       else
 | 
      
         | 508 |  |  |         {
 | 
      
         | 509 |  |  |           outpos += done;
 | 
      
         | 510 |  |  |           avail -= done;
 | 
      
         | 511 |  |  |         }
 | 
      
         | 512 |  |  |     }
 | 
      
         | 513 |  |  |   converter->done ();
 | 
      
         | 514 |  |  |   this->data = array;
 | 
      
         | 515 |  |  |   this->boffset = (char *) elements (array) - (char *) array;
 | 
      
         | 516 |  |  |   this->count = outpos;
 | 
      
         | 517 |  |  | }
 | 
      
         | 518 |  |  |  
 | 
      
         | 519 |  |  | void
 | 
      
         | 520 |  |  | java::lang::String::init (gnu::gcj::runtime::StringBuffer *buffer)
 | 
      
         | 521 |  |  | {
 | 
      
         | 522 |  |  |   init (buffer->value, 0, buffer->count, true);
 | 
      
         | 523 |  |  | }
 | 
      
         | 524 |  |  |  
 | 
      
         | 525 |  |  | jboolean
 | 
      
         | 526 |  |  | java::lang::String::equals(jobject anObject)
 | 
      
         | 527 |  |  | {
 | 
      
         | 528 |  |  |   if (anObject == NULL)
 | 
      
         | 529 |  |  |     return false;
 | 
      
         | 530 |  |  |   if (anObject == this)
 | 
      
         | 531 |  |  |     return true;
 | 
      
         | 532 |  |  |   if (anObject->getClass() != &java::lang::String::class$)
 | 
      
         | 533 |  |  |     return false;
 | 
      
         | 534 |  |  |   jstring other = (jstring) anObject;
 | 
      
         | 535 |  |  |   if (count != other->count)
 | 
      
         | 536 |  |  |     return false;
 | 
      
         | 537 |  |  |   /* if both are interned, return false. */
 | 
      
         | 538 |  |  |   jint i = count;
 | 
      
         | 539 |  |  |   jchar *xptr = JvGetStringChars (this);
 | 
      
         | 540 |  |  |   jchar *yptr = JvGetStringChars (other);
 | 
      
         | 541 |  |  |   while (--i >= 0)
 | 
      
         | 542 |  |  |     {
 | 
      
         | 543 |  |  |       if (*xptr++ != *yptr++)
 | 
      
         | 544 |  |  |         return false;
 | 
      
         | 545 |  |  |     }
 | 
      
         | 546 |  |  |   return true;
 | 
      
         | 547 |  |  | }
 | 
      
         | 548 |  |  |  
 | 
      
         | 549 |  |  | jboolean
 | 
      
         | 550 |  |  | java::lang::String::contentEquals(java::lang::StringBuffer* buffer)
 | 
      
         | 551 |  |  | {
 | 
      
         | 552 |  |  |   if (buffer == NULL)
 | 
      
         | 553 |  |  |     throw new NullPointerException;
 | 
      
         | 554 |  |  |   JvSynchronize sync(buffer);
 | 
      
         | 555 |  |  |   if (count != buffer->count)
 | 
      
         | 556 |  |  |     return false;
 | 
      
         | 557 |  |  |   if (data == buffer->value)
 | 
      
         | 558 |  |  |     return true; // Possible if shared.
 | 
      
         | 559 |  |  |   jint i = count;
 | 
      
         | 560 |  |  |   jchar *xptr = JvGetStringChars(this);
 | 
      
         | 561 |  |  |   jchar *yptr = elements(buffer->value);
 | 
      
         | 562 |  |  |   while (--i >= 0)
 | 
      
         | 563 |  |  |     if (*xptr++ != *yptr++)
 | 
      
         | 564 |  |  |       return false;
 | 
      
         | 565 |  |  |   return true;
 | 
      
         | 566 |  |  | }
 | 
      
         | 567 |  |  |  
 | 
      
         | 568 |  |  | jboolean
 | 
      
         | 569 |  |  | java::lang::String::contentEquals(java::lang::CharSequence *seq)
 | 
      
         | 570 |  |  | {
 | 
      
         | 571 |  |  |   if (seq->length() != count)
 | 
      
         | 572 |  |  |     return false;
 | 
      
         | 573 |  |  |   jchar *value = JvGetStringChars(this);
 | 
      
         | 574 |  |  |   for (int i = 0; i < count; ++i)
 | 
      
         | 575 |  |  |     if (value[i] != seq->charAt(i))
 | 
      
         | 576 |  |  |       return false;
 | 
      
         | 577 |  |  |   return true;
 | 
      
         | 578 |  |  | }
 | 
      
         | 579 |  |  |  
 | 
      
         | 580 |  |  | jchar
 | 
      
         | 581 |  |  | java::lang::String::charAt(jint i)
 | 
      
         | 582 |  |  | {
 | 
      
         | 583 |  |  |   if (i < 0 || i >= count)
 | 
      
         | 584 |  |  |     throw new java::lang::StringIndexOutOfBoundsException(i);
 | 
      
         | 585 |  |  |   return JvGetStringChars(this)[i];
 | 
      
         | 586 |  |  | }
 | 
      
         | 587 |  |  |  
 | 
      
         | 588 |  |  | void
 | 
      
         | 589 |  |  | java::lang::String::getChars(jint srcBegin, jint srcEnd,
 | 
      
         | 590 |  |  |                              jcharArray dst, jint dstBegin)
 | 
      
         | 591 |  |  | {
 | 
      
         | 592 |  |  |   jint dst_length = JvGetArrayLength (dst);
 | 
      
         | 593 |  |  |   if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count)
 | 
      
         | 594 |  |  |     throw new java::lang::StringIndexOutOfBoundsException;
 | 
      
         | 595 |  |  |   // The 2nd part of the test below is equivalent to 
 | 
      
         | 596 |  |  |   // dstBegin + (srcEnd-srcBegin) > dst_length
 | 
      
         | 597 |  |  |   // except that it does not overflow.
 | 
      
         | 598 |  |  |   if (dstBegin < 0 || dstBegin > dst_length - (srcEnd-srcBegin))
 | 
      
         | 599 |  |  |     throw new ArrayIndexOutOfBoundsException;
 | 
      
         | 600 |  |  |   jchar *dPtr = elements (dst) + dstBegin;
 | 
      
         | 601 |  |  |   jchar *sPtr = JvGetStringChars (this) + srcBegin;
 | 
      
         | 602 |  |  |   jint i = srcEnd-srcBegin;
 | 
      
         | 603 |  |  |   while (--i >= 0)
 | 
      
         | 604 |  |  |     *dPtr++ = *sPtr++;
 | 
      
         | 605 |  |  | }
 | 
      
         | 606 |  |  |  
 | 
      
         | 607 |  |  | jbyteArray
 | 
      
         | 608 |  |  | java::lang::String::getBytes (jstring enc)
 | 
      
         | 609 |  |  | {
 | 
      
         | 610 |  |  |   jint todo = length();
 | 
      
         | 611 |  |  |   jint buflen = todo;
 | 
      
         | 612 |  |  |   jbyteArray buffer = JvNewByteArray(todo);
 | 
      
         | 613 |  |  |   jint bufpos = 0;
 | 
      
         | 614 |  |  |   jint offset = 0;
 | 
      
         | 615 |  |  |   gnu::gcj::convert::UnicodeToBytes *converter
 | 
      
         | 616 |  |  |     = gnu::gcj::convert::UnicodeToBytes::getEncoder(enc);
 | 
      
         | 617 |  |  |   while (todo > 0 || converter->havePendingBytes())
 | 
      
         | 618 |  |  |     {
 | 
      
         | 619 |  |  |       converter->setOutput(buffer, bufpos);
 | 
      
         | 620 |  |  |       int converted = converter->write(this, offset, todo, NULL);
 | 
      
         | 621 |  |  |       bufpos = converter->count;
 | 
      
         | 622 |  |  |       if (converted == 0 && bufpos == converter->count)
 | 
      
         | 623 |  |  |         {
 | 
      
         | 624 |  |  |           buflen *= 2;
 | 
      
         | 625 |  |  |           jbyteArray newbuffer = JvNewByteArray(buflen);
 | 
      
         | 626 |  |  |           memcpy (elements (newbuffer), elements (buffer), bufpos);
 | 
      
         | 627 |  |  |           buffer = newbuffer;
 | 
      
         | 628 |  |  |         }
 | 
      
         | 629 |  |  |       else
 | 
      
         | 630 |  |  |         bufpos = converter->count;
 | 
      
         | 631 |  |  |  
 | 
      
         | 632 |  |  |       offset += converted;
 | 
      
         | 633 |  |  |       todo -= converted;
 | 
      
         | 634 |  |  |     }
 | 
      
         | 635 |  |  |   converter->done ();
 | 
      
         | 636 |  |  |   if (bufpos == buflen)
 | 
      
         | 637 |  |  |     return buffer;
 | 
      
         | 638 |  |  |   jbyteArray result = JvNewByteArray(bufpos);
 | 
      
         | 639 |  |  |   memcpy (elements (result), elements (buffer), bufpos);
 | 
      
         | 640 |  |  |   return result;
 | 
      
         | 641 |  |  | }
 | 
      
         | 642 |  |  |  
 | 
      
         | 643 |  |  | void
 | 
      
         | 644 |  |  | java::lang::String::getBytes(jint srcBegin, jint srcEnd,
 | 
      
         | 645 |  |  |                              jbyteArray dst, jint dstBegin)
 | 
      
         | 646 |  |  | {
 | 
      
         | 647 |  |  |   jint dst_length = JvGetArrayLength (dst);
 | 
      
         | 648 |  |  |   if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count)
 | 
      
         | 649 |  |  |     throw new java::lang::StringIndexOutOfBoundsException;
 | 
      
         | 650 |  |  |   // The 2nd part of the test below is equivalent to 
 | 
      
         | 651 |  |  |   // dstBegin + (srcEnd-srcBegin) > dst_length
 | 
      
         | 652 |  |  |   // except that it does not overflow.
 | 
      
         | 653 |  |  |   if (dstBegin < 0 || dstBegin > dst_length - (srcEnd-srcBegin))
 | 
      
         | 654 |  |  |     throw new ArrayIndexOutOfBoundsException;
 | 
      
         | 655 |  |  |   jbyte *dPtr = elements (dst) + dstBegin;
 | 
      
         | 656 |  |  |   jchar *sPtr = JvGetStringChars (this) + srcBegin;
 | 
      
         | 657 |  |  |   jint i = srcEnd-srcBegin;
 | 
      
         | 658 |  |  |   while (--i >= 0)
 | 
      
         | 659 |  |  |     *dPtr++ = (jbyte) *sPtr++;
 | 
      
         | 660 |  |  | }
 | 
      
         | 661 |  |  |  
 | 
      
         | 662 |  |  | jcharArray
 | 
      
         | 663 |  |  | java::lang::String::toCharArray()
 | 
      
         | 664 |  |  | {
 | 
      
         | 665 |  |  |   jcharArray array = JvNewCharArray(count);
 | 
      
         | 666 |  |  |   jchar *dPtr = elements (array);
 | 
      
         | 667 |  |  |   jchar *sPtr = JvGetStringChars (this);
 | 
      
         | 668 |  |  |   jint i = count;
 | 
      
         | 669 |  |  |   while (--i >= 0)
 | 
      
         | 670 |  |  |     *dPtr++ = *sPtr++;
 | 
      
         | 671 |  |  |   return array;
 | 
      
         | 672 |  |  | }
 | 
      
         | 673 |  |  |  
 | 
      
         | 674 |  |  | jboolean
 | 
      
         | 675 |  |  | java::lang::String::equalsIgnoreCase (jstring anotherString)
 | 
      
         | 676 |  |  | {
 | 
      
         | 677 |  |  |   if (anotherString == NULL || count != anotherString->count)
 | 
      
         | 678 |  |  |     return false;
 | 
      
         | 679 |  |  |   jchar *tptr = JvGetStringChars (this);
 | 
      
         | 680 |  |  |   jchar *optr = JvGetStringChars (anotherString);
 | 
      
         | 681 |  |  |   jint i = count;
 | 
      
         | 682 |  |  |   while (--i >= 0)
 | 
      
         | 683 |  |  |     {
 | 
      
         | 684 |  |  |       jchar tch = *tptr++;
 | 
      
         | 685 |  |  |       jchar och = *optr++;
 | 
      
         | 686 |  |  |       if (tch != och
 | 
      
         | 687 |  |  |           && (java::lang::Character::toLowerCase (tch)
 | 
      
         | 688 |  |  |               != java::lang::Character::toLowerCase (och))
 | 
      
         | 689 |  |  |           && (java::lang::Character::toUpperCase (tch)
 | 
      
         | 690 |  |  |               != java::lang::Character::toUpperCase (och)))
 | 
      
         | 691 |  |  |         return false;
 | 
      
         | 692 |  |  |     }
 | 
      
         | 693 |  |  |   return true;
 | 
      
         | 694 |  |  | }
 | 
      
         | 695 |  |  |  
 | 
      
         | 696 |  |  | jboolean
 | 
      
         | 697 |  |  | java::lang::String::regionMatches (jint toffset,
 | 
      
         | 698 |  |  |                                    jstring other, jint ooffset, jint len)
 | 
      
         | 699 |  |  | {
 | 
      
         | 700 |  |  |   if (toffset < 0 || ooffset < 0 || len < 0
 | 
      
         | 701 |  |  |       || toffset > count - len
 | 
      
         | 702 |  |  |       || ooffset > other->count - len)
 | 
      
         | 703 |  |  |     return false;
 | 
      
         | 704 |  |  |   jchar *tptr = JvGetStringChars (this) + toffset;
 | 
      
         | 705 |  |  |   jchar *optr = JvGetStringChars (other) + ooffset;
 | 
      
         | 706 |  |  |   jint i = len;
 | 
      
         | 707 |  |  |   while (--i >= 0)
 | 
      
         | 708 |  |  |     {
 | 
      
         | 709 |  |  |       if (*tptr++ != *optr++)
 | 
      
         | 710 |  |  |         return false;
 | 
      
         | 711 |  |  |     }
 | 
      
         | 712 |  |  |   return true;
 | 
      
         | 713 |  |  | }
 | 
      
         | 714 |  |  |  
 | 
      
         | 715 |  |  | jint
 | 
      
         | 716 |  |  | java::lang::String::compareTo (jstring anotherString)
 | 
      
         | 717 |  |  | {
 | 
      
         | 718 |  |  |   jchar *tptr = JvGetStringChars (this);
 | 
      
         | 719 |  |  |   jchar *optr = JvGetStringChars (anotherString);
 | 
      
         | 720 |  |  |   jint tlen = this->count;
 | 
      
         | 721 |  |  |   jint olen = anotherString->count;
 | 
      
         | 722 |  |  |   jint i = tlen > olen ? olen : tlen;
 | 
      
         | 723 |  |  |   while (--i >= 0)
 | 
      
         | 724 |  |  |     {
 | 
      
         | 725 |  |  |       jchar tch = *tptr++;
 | 
      
         | 726 |  |  |       jchar och = *optr++;
 | 
      
         | 727 |  |  |       if (tch != och)
 | 
      
         | 728 |  |  |         return (jint) tch - (jint) och;
 | 
      
         | 729 |  |  |     }
 | 
      
         | 730 |  |  |   return tlen - olen;
 | 
      
         | 731 |  |  | }
 | 
      
         | 732 |  |  |  
 | 
      
         | 733 |  |  | jboolean
 | 
      
         | 734 |  |  | java::lang::String::regionMatches (jboolean ignoreCase, jint toffset,
 | 
      
         | 735 |  |  |                                    jstring other, jint ooffset, jint len)
 | 
      
         | 736 |  |  | {
 | 
      
         | 737 |  |  |   if (toffset < 0 || ooffset < 0 || len < 0
 | 
      
         | 738 |  |  |       || toffset > count - len
 | 
      
         | 739 |  |  |       || ooffset > other->count - len)
 | 
      
         | 740 |  |  |     return false;
 | 
      
         | 741 |  |  |   jchar *tptr = JvGetStringChars (this) + toffset;
 | 
      
         | 742 |  |  |   jchar *optr = JvGetStringChars (other) + ooffset;
 | 
      
         | 743 |  |  |   jint i = len;
 | 
      
         | 744 |  |  |   if (ignoreCase)
 | 
      
         | 745 |  |  |     while (--i >= 0)
 | 
      
         | 746 |  |  |       {
 | 
      
         | 747 |  |  |         jchar tch = *tptr++;
 | 
      
         | 748 |  |  |         jchar och = *optr++;
 | 
      
         | 749 |  |  |         if ((java::lang::Character::toLowerCase (tch)
 | 
      
         | 750 |  |  |              != java::lang::Character::toLowerCase (och))
 | 
      
         | 751 |  |  |             && (java::lang::Character::toUpperCase (tch)
 | 
      
         | 752 |  |  |                 != java::lang::Character::toUpperCase (och)))
 | 
      
         | 753 |  |  |           return false;
 | 
      
         | 754 |  |  |       }
 | 
      
         | 755 |  |  |   else
 | 
      
         | 756 |  |  |     while (--i >= 0)
 | 
      
         | 757 |  |  |       {
 | 
      
         | 758 |  |  |         jchar tch = *tptr++;
 | 
      
         | 759 |  |  |         jchar och = *optr++;
 | 
      
         | 760 |  |  |         if (tch != och)
 | 
      
         | 761 |  |  |           return false;
 | 
      
         | 762 |  |  |       }
 | 
      
         | 763 |  |  |   return true;
 | 
      
         | 764 |  |  | }
 | 
      
         | 765 |  |  |  
 | 
      
         | 766 |  |  | jboolean
 | 
      
         | 767 |  |  | java::lang::String::startsWith (jstring prefix, jint toffset)
 | 
      
         | 768 |  |  | {
 | 
      
         | 769 |  |  |   jint i = prefix->count;
 | 
      
         | 770 |  |  |   if (toffset < 0 || toffset > count - i)
 | 
      
         | 771 |  |  |     return false;
 | 
      
         | 772 |  |  |   jchar *xptr = JvGetStringChars (this) + toffset;
 | 
      
         | 773 |  |  |   jchar *yptr = JvGetStringChars (prefix);
 | 
      
         | 774 |  |  |   while (--i >= 0)
 | 
      
         | 775 |  |  |     {
 | 
      
         | 776 |  |  |       if (*xptr++ != *yptr++)
 | 
      
         | 777 |  |  |         return false;
 | 
      
         | 778 |  |  |     }
 | 
      
         | 779 |  |  |   return true;
 | 
      
         | 780 |  |  | }
 | 
      
         | 781 |  |  |  
 | 
      
         | 782 |  |  | jint
 | 
      
         | 783 |  |  | java::lang::String::indexOf (jint ch, jint fromIndex)
 | 
      
         | 784 |  |  | {
 | 
      
         | 785 |  |  |   if (fromIndex < 0)
 | 
      
         | 786 |  |  |     fromIndex = 0;
 | 
      
         | 787 |  |  |   jchar *ptr = JvGetStringChars(this);
 | 
      
         | 788 |  |  |   for (;; ++fromIndex)
 | 
      
         | 789 |  |  |     {
 | 
      
         | 790 |  |  |       if (fromIndex >= count)
 | 
      
         | 791 |  |  |         return -1;
 | 
      
         | 792 |  |  |       if (ptr[fromIndex] == ch)
 | 
      
         | 793 |  |  |         return fromIndex;
 | 
      
         | 794 |  |  |     }
 | 
      
         | 795 |  |  | }
 | 
      
         | 796 |  |  |  
 | 
      
         | 797 |  |  | jint
 | 
      
         | 798 |  |  | java::lang::String::indexOf (jstring s, jint fromIndex)
 | 
      
         | 799 |  |  | {
 | 
      
         | 800 |  |  |   const jchar *const xchars = JvGetStringChars(s);
 | 
      
         | 801 |  |  |   const jchar *const ychars = JvGetStringChars(this) + fromIndex;
 | 
      
         | 802 |  |  |  
 | 
      
         | 803 |  |  |   const int xlength = s->length ();
 | 
      
         | 804 |  |  |   const int ylength = length () - fromIndex;
 | 
      
         | 805 |  |  |  
 | 
      
         | 806 |  |  |   int i = 0;
 | 
      
         | 807 |  |  |   int j = 0;
 | 
      
         | 808 |  |  |  
 | 
      
         | 809 |  |  |   while (i < ylength && j < xlength)
 | 
      
         | 810 |  |  |     {
 | 
      
         | 811 |  |  |       if (xchars[j] != ychars[i])
 | 
      
         | 812 |  |  |         {
 | 
      
         | 813 |  |  |           i = i - j + 1;
 | 
      
         | 814 |  |  |           j = 0;
 | 
      
         | 815 |  |  |         }
 | 
      
         | 816 |  |  |       else
 | 
      
         | 817 |  |  |         i++, j++;
 | 
      
         | 818 |  |  |     }
 | 
      
         | 819 |  |  |  
 | 
      
         | 820 |  |  |   if (j >= xlength)
 | 
      
         | 821 |  |  |     return fromIndex + i - xlength;
 | 
      
         | 822 |  |  |   else
 | 
      
         | 823 |  |  |     return -1;
 | 
      
         | 824 |  |  | }
 | 
      
         | 825 |  |  |  
 | 
      
         | 826 |  |  | jint
 | 
      
         | 827 |  |  | java::lang::String::lastIndexOf (jint ch, jint fromIndex)
 | 
      
         | 828 |  |  | {
 | 
      
         | 829 |  |  |   if (fromIndex >= count)
 | 
      
         | 830 |  |  |     fromIndex = count - 1;
 | 
      
         | 831 |  |  |   jchar *ptr = JvGetStringChars(this);
 | 
      
         | 832 |  |  |   for (;; --fromIndex)
 | 
      
         | 833 |  |  |     {
 | 
      
         | 834 |  |  |       if (fromIndex < 0)
 | 
      
         | 835 |  |  |         return -1;
 | 
      
         | 836 |  |  |       if (ptr[fromIndex] == ch)
 | 
      
         | 837 |  |  |         return fromIndex;
 | 
      
         | 838 |  |  |     }
 | 
      
         | 839 |  |  | }
 | 
      
         | 840 |  |  |  
 | 
      
         | 841 |  |  | jstring
 | 
      
         | 842 |  |  | java::lang::String::substring (jint beginIndex, jint endIndex)
 | 
      
         | 843 |  |  | {
 | 
      
         | 844 |  |  |   if (beginIndex < 0 || endIndex > count || beginIndex > endIndex)
 | 
      
         | 845 |  |  |     throw new StringIndexOutOfBoundsException;
 | 
      
         | 846 |  |  |   if (beginIndex == 0 && endIndex == count)
 | 
      
         | 847 |  |  |     return this;
 | 
      
         | 848 |  |  |   jint newCount = endIndex - beginIndex;
 | 
      
         | 849 |  |  |   // For very small strings, just allocate a new one.  For other
 | 
      
         | 850 |  |  |   // substrings, allocate a new one unless the substring is over half
 | 
      
         | 851 |  |  |   // of the original string.
 | 
      
         | 852 |  |  |   if (newCount <= 8 || newCount < (count >> 1))
 | 
      
         | 853 |  |  |     return JvNewString(JvGetStringChars(this) + beginIndex, newCount);
 | 
      
         | 854 |  |  |   jstring s = new String();
 | 
      
         | 855 |  |  |   s->data = data;
 | 
      
         | 856 |  |  |   s->count = newCount;
 | 
      
         | 857 |  |  |   s->boffset = boffset + sizeof(jchar) * beginIndex;
 | 
      
         | 858 |  |  |   return s;
 | 
      
         | 859 |  |  | }
 | 
      
         | 860 |  |  |  
 | 
      
         | 861 |  |  | jstring
 | 
      
         | 862 |  |  | java::lang::String::concat(jstring str)
 | 
      
         | 863 |  |  | {
 | 
      
         | 864 |  |  |   jint str_count = str->count;
 | 
      
         | 865 |  |  |   if (str_count == 0)
 | 
      
         | 866 |  |  |     return this;
 | 
      
         | 867 |  |  |   jstring result = JvAllocString(count + str_count);
 | 
      
         | 868 |  |  |   jchar *dstPtr = JvGetStringChars(result);
 | 
      
         | 869 |  |  |   jchar *srcPtr = JvGetStringChars(this);
 | 
      
         | 870 |  |  |   jint i = count;
 | 
      
         | 871 |  |  |   while (--i >= 0)
 | 
      
         | 872 |  |  |     *dstPtr++ = *srcPtr++;
 | 
      
         | 873 |  |  |   srcPtr = JvGetStringChars(str);
 | 
      
         | 874 |  |  |   i = str->count;
 | 
      
         | 875 |  |  |   while (--i >= 0)
 | 
      
         | 876 |  |  |     *dstPtr++ = *srcPtr++;
 | 
      
         | 877 |  |  |   return result;
 | 
      
         | 878 |  |  | }
 | 
      
         | 879 |  |  |  
 | 
      
         | 880 |  |  | jstring
 | 
      
         | 881 |  |  | java::lang::String::replace (jchar oldChar, jchar newChar)
 | 
      
         | 882 |  |  | {
 | 
      
         | 883 |  |  |   jint i;
 | 
      
         | 884 |  |  |   jchar* chrs = JvGetStringChars (this);
 | 
      
         | 885 |  |  |   for (i = 0;  ;  i++)
 | 
      
         | 886 |  |  |     {
 | 
      
         | 887 |  |  |       if (i == count)
 | 
      
         | 888 |  |  |         return this;
 | 
      
         | 889 |  |  |       if (chrs[i] == oldChar)
 | 
      
         | 890 |  |  |         break;
 | 
      
         | 891 |  |  |     }
 | 
      
         | 892 |  |  |   jstring result = JvAllocString (count);
 | 
      
         | 893 |  |  |   jchar *dPtr = JvGetStringChars (result);
 | 
      
         | 894 |  |  |   for (int j = 0;  j < i;  j++)
 | 
      
         | 895 |  |  |     *dPtr++ = chrs[j];
 | 
      
         | 896 |  |  |   for (; i < count;  i++)
 | 
      
         | 897 |  |  |     {
 | 
      
         | 898 |  |  |       jchar ch = chrs[i];
 | 
      
         | 899 |  |  |       if (ch == oldChar)
 | 
      
         | 900 |  |  |         ch = newChar;
 | 
      
         | 901 |  |  |       *dPtr++ = ch;
 | 
      
         | 902 |  |  |     }
 | 
      
         | 903 |  |  |   return result;
 | 
      
         | 904 |  |  | }
 | 
      
         | 905 |  |  |  
 | 
      
         | 906 |  |  | jstring
 | 
      
         | 907 |  |  | java::lang::String::toLowerCase (java::util::Locale *locale)
 | 
      
         | 908 |  |  | {
 | 
      
         | 909 |  |  |   jint i;
 | 
      
         | 910 |  |  |   jchar* chrs = JvGetStringChars(this);
 | 
      
         | 911 |  |  |   jchar ch = 0;
 | 
      
         | 912 |  |  |  
 | 
      
         | 913 |  |  |   bool handle_tr = false;
 | 
      
         | 914 |  |  |   if (locale != NULL)
 | 
      
         | 915 |  |  |     {
 | 
      
         | 916 |  |  |       String *lang = locale->getLanguage ();
 | 
      
         | 917 |  |  |       if (lang->length () == 2
 | 
      
         | 918 |  |  |           && lang->charAt (0) == 't'
 | 
      
         | 919 |  |  |           && lang->charAt (1) == 'r')
 | 
      
         | 920 |  |  |         handle_tr = true;
 | 
      
         | 921 |  |  |     }
 | 
      
         | 922 |  |  |  
 | 
      
         | 923 |  |  |   for (i = 0;  ;  i++)
 | 
      
         | 924 |  |  |     {
 | 
      
         | 925 |  |  |       if (i == count)
 | 
      
         | 926 |  |  |         return this;
 | 
      
         | 927 |  |  |       jchar origChar = chrs[i];
 | 
      
         | 928 |  |  |  
 | 
      
         | 929 |  |  |       if (handle_tr && (origChar == CAPITAL_I
 | 
      
         | 930 |  |  |                         || origChar == CAPITAL_I_WITH_DOT))
 | 
      
         | 931 |  |  |         break;
 | 
      
         | 932 |  |  |  
 | 
      
         | 933 |  |  |       ch = java::lang::Character::toLowerCase(origChar);
 | 
      
         | 934 |  |  |       if (ch != origChar)
 | 
      
         | 935 |  |  |         break;
 | 
      
         | 936 |  |  |     }
 | 
      
         | 937 |  |  |   jstring result = JvAllocString(count);
 | 
      
         | 938 |  |  |   jchar *dPtr = JvGetStringChars (result);
 | 
      
         | 939 |  |  |   for (int j = 0;  j < i;  j++)
 | 
      
         | 940 |  |  |     *dPtr++ = chrs[j];
 | 
      
         | 941 |  |  |   *dPtr++ = ch;  i++;
 | 
      
         | 942 |  |  |   for (; i < count;  i++)
 | 
      
         | 943 |  |  |     {
 | 
      
         | 944 |  |  |       if (handle_tr && chrs[i] == CAPITAL_I)
 | 
      
         | 945 |  |  |         *dPtr++ = SMALL_DOTLESS_I;
 | 
      
         | 946 |  |  |       else if (handle_tr && chrs[i] == CAPITAL_I_WITH_DOT)
 | 
      
         | 947 |  |  |         *dPtr++ = SMALL_I;
 | 
      
         | 948 |  |  |       else
 | 
      
         | 949 |  |  |         *dPtr++ = java::lang::Character::toLowerCase(chrs[i]);
 | 
      
         | 950 |  |  |     }
 | 
      
         | 951 |  |  |   return result;
 | 
      
         | 952 |  |  | }
 | 
      
         | 953 |  |  |  
 | 
      
         | 954 |  |  | jstring
 | 
      
         | 955 |  |  | java::lang::String::toUpperCase (java::util::Locale *locale)
 | 
      
         | 956 |  |  | {
 | 
      
         | 957 |  |  |   jint i;
 | 
      
         | 958 |  |  |   jchar* chrs = JvGetStringChars(this);
 | 
      
         | 959 |  |  |   jchar ch;
 | 
      
         | 960 |  |  |  
 | 
      
         | 961 |  |  |   // When handling a specific locale there might be special rules.
 | 
      
         | 962 |  |  |   // Currently all existing rules are simply handled inline, as there
 | 
      
         | 963 |  |  |   // are only two and they are documented in the online 1.2 docs.
 | 
      
         | 964 |  |  |   bool handle_esset = locale != NULL;
 | 
      
         | 965 |  |  |   bool handle_tr = false;
 | 
      
         | 966 |  |  |   if (locale != NULL)
 | 
      
         | 967 |  |  |     {
 | 
      
         | 968 |  |  |       String *lang = locale->getLanguage ();
 | 
      
         | 969 |  |  |       if (lang->length () == 2
 | 
      
         | 970 |  |  |           && lang->charAt (0) == 't'
 | 
      
         | 971 |  |  |           && lang->charAt (1) == 'r')
 | 
      
         | 972 |  |  |         handle_tr = true;
 | 
      
         | 973 |  |  |     }
 | 
      
         | 974 |  |  |  
 | 
      
         | 975 |  |  |   int new_count = count;
 | 
      
         | 976 |  |  |   bool new_string = false;
 | 
      
         | 977 |  |  |   for (i = 0;  ;  i++)
 | 
      
         | 978 |  |  |     {
 | 
      
         | 979 |  |  |       if (i == count)
 | 
      
         | 980 |  |  |         break;
 | 
      
         | 981 |  |  |       jchar origChar = chrs[i];
 | 
      
         | 982 |  |  |  
 | 
      
         | 983 |  |  |       if (handle_esset && origChar == ESSET)
 | 
      
         | 984 |  |  |         {
 | 
      
         | 985 |  |  |           ++new_count;
 | 
      
         | 986 |  |  |           new_string = true;
 | 
      
         | 987 |  |  |         }
 | 
      
         | 988 |  |  |       else if (handle_tr && (origChar == SMALL_I
 | 
      
         | 989 |  |  |                              || origChar == SMALL_DOTLESS_I))
 | 
      
         | 990 |  |  |         new_string = true;
 | 
      
         | 991 |  |  |       else
 | 
      
         | 992 |  |  |         {
 | 
      
         | 993 |  |  |           ch = java::lang::Character::toUpperCase(origChar);
 | 
      
         | 994 |  |  |           if (ch != origChar)
 | 
      
         | 995 |  |  |             new_string = true;
 | 
      
         | 996 |  |  |         }
 | 
      
         | 997 |  |  |  
 | 
      
         | 998 |  |  |       if (new_string && ! handle_esset)
 | 
      
         | 999 |  |  |         break;
 | 
      
         | 1000 |  |  |     }
 | 
      
         | 1001 |  |  |   if (! new_string)
 | 
      
         | 1002 |  |  |     return this;
 | 
      
         | 1003 |  |  |   jstring result = JvAllocString(new_count);
 | 
      
         | 1004 |  |  |   jchar *dPtr = JvGetStringChars (result);
 | 
      
         | 1005 |  |  |   for (i = 0; i < count;  i++)
 | 
      
         | 1006 |  |  |     {
 | 
      
         | 1007 |  |  |       if (handle_esset && chrs[i] == ESSET)
 | 
      
         | 1008 |  |  |         {
 | 
      
         | 1009 |  |  |           *dPtr++ = CAPITAL_S;
 | 
      
         | 1010 |  |  |           *dPtr++ = CAPITAL_S;
 | 
      
         | 1011 |  |  |         }
 | 
      
         | 1012 |  |  |       else if (handle_tr && chrs[i] == SMALL_I)
 | 
      
         | 1013 |  |  |         *dPtr++ = CAPITAL_I_WITH_DOT;
 | 
      
         | 1014 |  |  |       else if (handle_tr && chrs[i] == SMALL_DOTLESS_I)
 | 
      
         | 1015 |  |  |         *dPtr++ = CAPITAL_I;
 | 
      
         | 1016 |  |  |       else
 | 
      
         | 1017 |  |  |         *dPtr++ = java::lang::Character::toUpperCase(chrs[i]);
 | 
      
         | 1018 |  |  |     }
 | 
      
         | 1019 |  |  |   return result;
 | 
      
         | 1020 |  |  | }
 | 
      
         | 1021 |  |  |  
 | 
      
         | 1022 |  |  | jstring
 | 
      
         | 1023 |  |  | java::lang::String::trim ()
 | 
      
         | 1024 |  |  | {
 | 
      
         | 1025 |  |  |   jchar* chrs = JvGetStringChars(this);
 | 
      
         | 1026 |  |  |   if (count == 0 || (chrs[0] > ' ' && chrs[count-1] > ' '))
 | 
      
         | 1027 |  |  |     return this;
 | 
      
         | 1028 |  |  |   jint preTrim = 0;
 | 
      
         | 1029 |  |  |   for (;; preTrim++)
 | 
      
         | 1030 |  |  |     {
 | 
      
         | 1031 |  |  |       if (preTrim == count)
 | 
      
         | 1032 |  |  |         return new String();
 | 
      
         | 1033 |  |  |       if (chrs[preTrim] > ' ')
 | 
      
         | 1034 |  |  |         break;
 | 
      
         | 1035 |  |  |     }
 | 
      
         | 1036 |  |  |   jint endTrim = count;
 | 
      
         | 1037 |  |  |   while (chrs[endTrim-1] <= ' ')
 | 
      
         | 1038 |  |  |     endTrim--;
 | 
      
         | 1039 |  |  |   return substring(preTrim, endTrim);
 | 
      
         | 1040 |  |  | }
 | 
      
         | 1041 |  |  |  
 | 
      
         | 1042 |  |  | jstring
 | 
      
         | 1043 |  |  | java::lang::String::valueOf(jcharArray data, jint offset, jint count)
 | 
      
         | 1044 |  |  | {
 | 
      
         | 1045 |  |  |   jint data_length = JvGetArrayLength (data);
 | 
      
         | 1046 |  |  |   if (offset < 0 || count < 0 || offset > data_length - count)
 | 
      
         | 1047 |  |  |     throw new ArrayIndexOutOfBoundsException;
 | 
      
         | 1048 |  |  |   jstring result = JvAllocString(count);
 | 
      
         | 1049 |  |  |   jchar *sPtr = elements (data) + offset;
 | 
      
         | 1050 |  |  |   jchar *dPtr = JvGetStringChars(result);
 | 
      
         | 1051 |  |  |   while (--count >= 0)
 | 
      
         | 1052 |  |  |     *dPtr++ = *sPtr++;
 | 
      
         | 1053 |  |  |   return result;
 | 
      
         | 1054 |  |  | }
 | 
      
         | 1055 |  |  |  
 | 
      
         | 1056 |  |  | jstring
 | 
      
         | 1057 |  |  | java::lang::String::valueOf(jchar c)
 | 
      
         | 1058 |  |  | {
 | 
      
         | 1059 |  |  |   jstring result = JvAllocString(1);
 | 
      
         | 1060 |  |  |   JvGetStringChars (result)[0] = c;
 | 
      
         | 1061 |  |  |   return result;
 | 
      
         | 1062 |  |  | }
 |