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