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