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