]> gcc.gnu.org Git - gcc.git/blame - libjava/java/lang/natString.cc
prims.cc (_Jv_NewObjectArray): Make sure byte size doesn't overflow a jint.
[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
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{
59 JvSynchronize sync (&StringClass);
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
119void
120java::lang::String::rehash()
121{
122 JvSynchronize sync (&StringClass);
123
124 if (strhash == NULL)
125 {
126 strhash_size = 1024;
3610e0d5 127 strhash = (jstring *) _Jv_AllocBytes (strhash_size * sizeof (jstring));
ee9dd372
TT
128 memset (strhash, 0, strhash_size * sizeof (jstring));
129 }
130 else
131 {
6c80c45e
TT
132 int i = strhash_size;
133 jstring* ptr = strhash + i;
9de8be0b 134 int nsize = strhash_size * 2;
3610e0d5 135 jstring *next = (jstring *) _Jv_AllocBytes (nsize * sizeof (jstring));
9de8be0b 136 memset (next, 0, nsize * sizeof (jstring));
ee9dd372
TT
137
138 while (--i >= 0)
139 {
140 --ptr;
141 if (*ptr == NULL || *ptr == DELETED_STRING)
142 continue;
143
144 /* This is faster equivalent of
145 * *__JvGetInternSlot(*ptr) = *ptr; */
9de8be0b
TT
146 jstring val = (jstring) UNMASK_PTR (*ptr);
147 jint hash = val->hashCode();
148 jint index = hash & (nsize - 1);
ab9fa4b5 149 jint step = (hash ^ (hash >> 16)) | 1;
ee9dd372
TT
150 for (;;)
151 {
9de8be0b 152 if (next[index] == NULL)
ee9dd372 153 {
9de8be0b 154 next[index] = *ptr;
ee9dd372
TT
155 break;
156 }
9de8be0b 157 index = (index + step) & (nsize - 1);
ee9dd372
TT
158 }
159 }
9de8be0b
TT
160
161 strhash_size = nsize;
162 strhash = next;
ee9dd372
TT
163 }
164}
165
166jstring
167java::lang::String::intern()
168{
169 JvSynchronize sync (&StringClass);
ab9fa4b5 170 if (3 * strhash_count >= 2 * strhash_size)
ee9dd372
TT
171 rehash();
172 jstring* ptr = _Jv_StringGetSlot(this);
173 if (*ptr != NULL && *ptr != DELETED_STRING)
9de8be0b 174 {
2cd56142 175 // See description in _Jv_FinalizeString() to understand this.
9de8be0b
TT
176 *ptr = (jstring) MASK_PTR (*ptr);
177 return (jstring) UNMASK_PTR (*ptr);
178 }
2cd56142
TT
179 jstring str = (this->data == this
180 ? this
181 : _Jv_NewString(JvGetStringChars(this), this->length()));
a3b63299 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.
2cd56142 186 _Jv_RegisterStringFinalizer (str);
a3b63299 187 return str;
ee9dd372
TT
188}
189
2cd56142
TT
190// The fake String finalizer. This is only used when the String has
191// been intern()d. However, we must check this case, as it might be
192// called by the Reference code for any String.
193void
194_Jv_FinalizeString (jobject obj)
ee9dd372
TT
195{
196 JvSynchronize sync (&StringClass);
2cd56142
TT
197
198 // We might not actually have intern()d any strings at all, if
199 // we're being called from Reference.
200 if (! strhash)
201 return;
202
50b99cc8 203 jstring str = reinterpret_cast<jstring> (obj);
2cd56142
TT
204 jstring *ptr = _Jv_StringGetSlot(str);
205 if (*ptr == NULL || *ptr == DELETED_STRING
206 || (jobject) UNMASK_PTR (*ptr) != obj)
ee9dd372 207 return;
9de8be0b
TT
208
209 // We assume the lowest bit of the pointer is free for our nefarious
210 // manipulations. What we do is set it to `0' (implicitly) when
211 // interning the String. If we subsequently re-intern the same
212 // String, then we set the bit. When finalizing, if the bit is set
213 // then we clear it and re-register the finalizer. We know this is
2cd56142
TT
214 // a safe approach because both intern() and _Jv_FinalizeString()
215 // acquire the class lock; this bit can't be manipulated when the
216 // lock is not held. So if we are finalizing and the bit is clear
217 // then we know all references are gone and we can clear the entry
218 // in the hash table. The naive approach of simply clearing the
219 // pointer here fails in the case where a request to intern a new
220 // string with the same contents is made between the time the
221 // intern()d string is found to be unreachable and when the
222 // finalizer is actually run. In this case we could clear a pointer
223 // to a valid string, and future intern() calls for that particular
224 // value would spuriously fail.
9de8be0b
TT
225 if (PTR_MASKED (*ptr))
226 {
227 *ptr = (jstring) UNMASK_PTR (*ptr);
2cd56142 228 _Jv_RegisterStringFinalizer (obj);
9de8be0b
TT
229 }
230 else
231 {
232 *ptr = DELETED_STRING;
233 strhash_count--;
234 }
ee9dd372
TT
235}
236
237jstring
238_Jv_NewStringUTF (const char *bytes)
239{
240 int size = strlen (bytes);
241 unsigned char *p = (unsigned char *) bytes;
242
243 int length = _Jv_strLengthUtf8 ((char *) p, size);
244 if (length < 0)
245 return NULL;
246
247 jstring jstr = JvAllocString (length);
248 jchar *chrs = JvGetStringChars (jstr);
249
250 p = (unsigned char *) bytes;
251 unsigned char *limit = p + size;
252 while (p < limit)
253 *chrs++ = UTF8_GET (p, limit);
254
255 return jstr;
256}
257
258jstring
259_Jv_NewStringUtf8Const (Utf8Const* str)
260{
261 jchar *chrs;
262 jchar buffer[100];
263 jstring jstr;
6c80c45e
TT
264 unsigned char* data = (unsigned char*) str->data;
265 unsigned char* limit = data + str->length;
ee9dd372
TT
266 int length = _Jv_strLengthUtf8(str->data, str->length);
267
268 if (length <= (int) (sizeof(buffer) / sizeof(jchar)))
269 {
270 jstr = NULL;
271 chrs = buffer;
272 }
273 else
274 {
275 jstr = JvAllocString(length);
276 chrs = JvGetStringChars(jstr);
277 }
278
ab9fa4b5 279 jint hash = 0;
ee9dd372 280 while (data < limit)
ab9fa4b5
PB
281 {
282 jchar ch = UTF8_GET(data, limit);
283 hash = (31 * hash) + ch;
284 *chrs++ = ch;
285 }
ee9dd372
TT
286 chrs -= length;
287
288 JvSynchronize sync (&StringClass);
ab9fa4b5 289 if (3 * strhash_count >= 2 * strhash_size)
ee9dd372 290 java::lang::String::rehash();
ee9dd372
TT
291 jstring* ptr = _Jv_StringFindSlot (chrs, length, hash);
292 if (*ptr != NULL && *ptr != DELETED_STRING)
9de8be0b 293 return (jstring) UNMASK_PTR (*ptr);
ee9dd372
TT
294 strhash_count++;
295 if (jstr == NULL)
296 {
297 jstr = JvAllocString(length);
298 chrs = JvGetStringChars(jstr);
299 memcpy (chrs, buffer, sizeof(jchar)*length);
300 }
62a3446b 301 jstr->cachedHashCode = hash;
ee9dd372
TT
302 *ptr = jstr;
303 SET_STRING_IS_INTERNED(jstr);
2cd56142
TT
304 // When string is GC'd, clear the slot in the hash table. Note that
305 // we don't have to call _Jv_RegisterStringFinalizer here, as we
306 // know the new object cannot be referred to by a Reference.
307 _Jv_RegisterFinalizer ((void *) jstr, _Jv_FinalizeString);
ee9dd372
TT
308 return jstr;
309}
310
311jsize
312_Jv_GetStringUTFLength (jstring string)
313{
6c80c45e
TT
314 jsize len = 0;
315 jchar *ptr = JvGetStringChars (string);
316 jsize i = string->length();
ee9dd372
TT
317 while (--i >= 0)
318 {
6c80c45e 319 jchar ch = *ptr++;
ee9dd372
TT
320 if (ch > 0 && ch <= 0x7F)
321 len += 1;
322 else if (ch <= 0x7FF)
323 len += 2;
324 else
325 len += 3;
326 }
327 return len;
328}
329
330// Not sure this quite matches GetStringUTFRegion.
331// null-termination of result? len? throw exception?
332jsize
333_Jv_GetStringUTFRegion (jstring str, jsize start, jsize len, char *buf)
334{
6c80c45e
TT
335 jchar *sptr = JvGetStringChars (str) + start;
336 jsize i = len;
337 char *dptr = buf;
ee9dd372
TT
338 while (--i >= 0)
339 {
340 jchar ch = *sptr++;
341 if (ch > 0 && ch <= 0x7F)
342 *dptr++ = (char) ch;
343 else if (ch <= 0x7FF)
344 {
345 *dptr++ = (char) (0xC0 + ((ch >> 6) & 0x1F));
346 *dptr++ = (char) (0x80 + (ch & 0x3F));
347 }
348 else
349 {
350 *dptr++ = (char) (0xE0 + ((ch >> 12) & 0xF));
351 *dptr++ = (char) (0x80 + ((ch >> 6) & 0x3F));
352 *dptr++ = (char) (0x80 + (ch & 0x3F));
353 }
354 }
355 return dptr - buf;
356}
357
ef0a7b49
PB
358/* Put printed (decimal) representation of NUM in a buffer.
359 BUFEND marks the end of the buffer, which must be at least 11 jchars long.
360 Returns the COUNT of jchars written. The result is in
361 (BUFEND - COUNT) (inclusive) upto (BUFEND) (exclusive). */
362
363jint
364_Jv_FormatInt (jchar* bufend, jint num)
365{
366 register jchar* ptr = bufend;
367 jboolean isNeg;
368 if (num < 0)
369 {
370 isNeg = true;
371 num = -(num);
372 if (num < 0)
373 {
374 // Must be MIN_VALUE, so handle this special case.
375 // FIXME use 'unsigned jint' for num.
376 *--ptr = '8';
377 num = 214748364;
378 }
379 }
380 else
381 isNeg = false;
382
383 do
384 {
385 *--ptr = (jchar) ((int) '0' + (num % 10));
386 num /= 10;
387 }
388 while (num > 0);
389
390 if (isNeg)
391 *--ptr = '-';
392 return bufend - ptr;
393}
394
395jstring
396java::lang::String::valueOf (jint num)
397{
398 // Use an array large enough for "-2147483648"; i.e. 11 chars.
399 jchar buffer[11];
400 int i = _Jv_FormatInt (buffer+11, num);
401 return _Jv_NewString (buffer+11-i, i);
402}
403
ee9dd372
TT
404jstring
405_Jv_AllocString(jsize len)
406{
407 jsize sz = sizeof(java::lang::String) + len * sizeof(jchar);
408
3610e0d5
TT
409 // We assert that for strings allocated this way, the data field
410 // will always point to the object itself. Thus there is no reason
411 // for the garbage collector to scan any of it.
412 // Furthermore, we're about to overwrite the string data, so
413 // initialization of the object is not an issue.
414#ifdef ENABLE_JVMPI
415 jstring obj = (jstring) _Jv_AllocPtrFreeObject(&StringClass, sz);
416#else
417 // Class needs no initialization, and there is no finalizer, so
418 // we can go directly to the collector's allocator interface.
aa0149ff 419 jstring obj = (jstring) _Jv_AllocPtrFreeObj(sz, &StringClass);
3610e0d5 420#endif
ee9dd372
TT
421 obj->data = obj;
422 obj->boffset = sizeof(java::lang::String);
423 obj->count = len;
62a3446b 424 obj->cachedHashCode = 0;
ee9dd372
TT
425 return obj;
426}
427
428jstring
429_Jv_NewString(const jchar *chars, jsize len)
430{
431 jstring str = _Jv_AllocString(len);
432 jchar* data = JvGetStringChars (str);
433 while (--len >= 0)
434 *data++ = *chars++;
435 return str;
436}
437
438jstring
439_Jv_NewStringLatin1(const char *bytes, jsize len)
440{
441 jstring str = JvAllocString(len);
442 jchar* data = JvGetStringChars (str);
443 while (--len >= 0)
444 *data++ = *(unsigned char*)bytes++;
445 return str;
446}
447
ee9dd372
TT
448void
449java::lang::String::init(jcharArray chars, jint offset, jint count,
450 jboolean dont_copy)
451{
452 if (! chars)
b3208f56 453 throw new NullPointerException;
ee9dd372 454 jsize data_size = JvGetArrayLength (chars);
b11f6430
AG
455 if (offset < 0 || count < 0 || offset + count < 0
456 || offset + count > data_size)
cb894e07 457 throw new ArrayIndexOutOfBoundsException;
ee9dd372
TT
458 jcharArray array;
459 jchar *pdst;
460 if (! dont_copy)
461 {
462 array = JvNewCharArray(count);
463 pdst = elements (array);
464 memcpy (pdst, elements (chars) + offset, count * sizeof (jchar));
465 }
466 else
467 {
ee9dd372 468 array = chars;
93f7aeea 469 pdst = &(elements(array)[offset]);
ee9dd372
TT
470 }
471
472 data = array;
473 boffset = (char *) pdst - (char *) array;
474 this->count = count;
475}
476
477void
478java::lang::String::init(jbyteArray ascii, jint hibyte, jint offset,
479 jint count)
480{
481 if (! ascii)
b3208f56 482 throw new NullPointerException;
ee9dd372
TT
483 jsize data_size = JvGetArrayLength (ascii);
484 if (offset < 0 || count < 0 || offset + count < 0
485 || offset + count > data_size)
cb894e07 486 throw new ArrayIndexOutOfBoundsException;
ee9dd372
TT
487 jcharArray array = JvNewCharArray(count);
488 jbyte *psrc = elements (ascii) + offset;
489 jchar *pdst = elements (array);
490 data = array;
491 boffset = (char *) pdst - (char *) array;
492 this->count = count;
493 hibyte = (hibyte & 0xff) << 8;
494 while (-- count >= 0)
495 {
496 *pdst++ = hibyte | (*psrc++ & 0xff);
497 }
498}
499
500void
501java::lang::String::init (jbyteArray bytes, jint offset, jint count,
502 jstring encoding)
503{
504 if (! bytes)
b3208f56 505 throw new NullPointerException;
ee9dd372
TT
506 jsize data_size = JvGetArrayLength (bytes);
507 if (offset < 0 || count < 0 || offset + count < 0
508 || offset + count > data_size)
cb894e07 509 throw new ArrayIndexOutOfBoundsException;
ee9dd372 510 jcharArray array = JvNewCharArray (count);
a99ce7ca
PB
511 gnu::gcj::convert::BytesToUnicode *converter
512 = gnu::gcj::convert::BytesToUnicode::getDecoder(encoding);
513 jint outpos = 0;
514 int avail = count;
515 converter->setInput(bytes, offset, offset+count);
516 while (converter->inpos < converter->inlength)
517 {
518 int done = converter->read(array, outpos, avail);
519 if (done == 0)
520 {
521 jint new_size = 2 * (outpos + avail);
522 jcharArray new_array = JvNewCharArray (new_size);
523 memcpy (elements (new_array), elements (array),
524 outpos * sizeof(jchar));
525 array = new_array;
526 avail = new_size - outpos;
527 }
528 else
529 {
530 outpos += done;
531 avail -= done;
532 }
533 }
3d5aea83 534 converter->done ();
a99ce7ca
PB
535 this->data = array;
536 this->boffset = (char *) elements (array) - (char *) array;
537 this->count = outpos;
ee9dd372
TT
538}
539
651bed36
TT
540void
541java::lang::String::init (gnu::gcj::runtime::StringBuffer *buffer)
542{
543 init (buffer->value, 0, buffer->count, true);
544}
545
ee9dd372
TT
546jboolean
547java::lang::String::equals(jobject anObject)
548{
549 if (anObject == NULL)
550 return false;
551 if (anObject == this)
552 return true;
553 if (anObject->getClass() != &StringClass)
554 return false;
555 jstring other = (jstring) anObject;
556 if (count != other->count)
557 return false;
558 /* if both are interned, return false. */
6c80c45e
TT
559 jint i = count;
560 jchar *xptr = JvGetStringChars (this);
561 jchar *yptr = JvGetStringChars (other);
ee9dd372
TT
562 while (--i >= 0)
563 {
564 if (*xptr++ != *yptr++)
565 return false;
566 }
567 return true;
568}
569
7270451f
EB
570jboolean
571java::lang::String::contentEquals(java::lang::StringBuffer* buffer)
572{
573 if (buffer == NULL)
574 throw new NullPointerException;
575 JvSynchronize sync(buffer);
576 if (count != buffer->count)
577 return false;
578 if (data == buffer->value)
579 return true; // Possible if shared.
580 jint i = count;
581 jchar *xptr = JvGetStringChars(this);
582 jchar *yptr = elements(buffer->value);
583 while (--i >= 0)
584 if (*xptr++ != *yptr++)
585 return false;
586 return true;
587}
588
ee9dd372
TT
589jchar
590java::lang::String::charAt(jint i)
591{
592 if (i < 0 || i >= count)
7270451f 593 throw new java::lang::StringIndexOutOfBoundsException(i);
ee9dd372
TT
594 return JvGetStringChars(this)[i];
595}
596
597void
598java::lang::String::getChars(jint srcBegin, jint srcEnd,
599 jcharArray dst, jint dstBegin)
600{
601 jint dst_length = JvGetArrayLength (dst);
cb894e07 602 if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count)
b3208f56 603 throw new java::lang::StringIndexOutOfBoundsException;
cb894e07
TT
604 if (dstBegin < 0 || dstBegin + (srcEnd-srcBegin) > dst_length)
605 throw new ArrayIndexOutOfBoundsException;
6c80c45e
TT
606 jchar *dPtr = elements (dst) + dstBegin;
607 jchar *sPtr = JvGetStringChars (this) + srcBegin;
608 jint i = srcEnd-srcBegin;
ee9dd372
TT
609 while (--i >= 0)
610 *dPtr++ = *sPtr++;
611}
612
613jbyteArray
614java::lang::String::getBytes (jstring enc)
615{
a99ce7ca
PB
616 jint todo = length();
617 jint buflen = todo;
618 jbyteArray buffer = JvNewByteArray(todo);
619 jint bufpos = 0;
620 jint offset = 0;
621 gnu::gcj::convert::UnicodeToBytes *converter
622 = gnu::gcj::convert::UnicodeToBytes::getEncoder(enc);
60e9f0d7 623 while (todo > 0 || converter->havePendingBytes())
a99ce7ca
PB
624 {
625 converter->setOutput(buffer, bufpos);
626 int converted = converter->write(this, offset, todo, NULL);
baa288f3 627 bufpos = converter->count;
60e9f0d7 628 if (converted == 0 && bufpos == converter->count)
a99ce7ca 629 {
baa288f3
TT
630 buflen *= 2;
631 jbyteArray newbuffer = JvNewByteArray(buflen);
a99ce7ca
PB
632 memcpy (elements (newbuffer), elements (buffer), bufpos);
633 buffer = newbuffer;
634 }
635 else
60e9f0d7
MW
636 bufpos = converter->count;
637
638 offset += converted;
639 todo -= converted;
a99ce7ca 640 }
3d5aea83 641 converter->done ();
a99ce7ca
PB
642 if (bufpos == buflen)
643 return buffer;
baa288f3
TT
644 jbyteArray result = JvNewByteArray(bufpos);
645 memcpy (elements (result), elements (buffer), bufpos);
a99ce7ca 646 return result;
ee9dd372
TT
647}
648
649void
650java::lang::String::getBytes(jint srcBegin, jint srcEnd,
651 jbyteArray dst, jint dstBegin)
652{
653 jint dst_length = JvGetArrayLength (dst);
cb894e07 654 if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count)
b3208f56 655 throw new java::lang::StringIndexOutOfBoundsException;
cb894e07
TT
656 if (dstBegin < 0 || dstBegin + (srcEnd-srcBegin) > dst_length)
657 throw new ArrayIndexOutOfBoundsException;
6c80c45e
TT
658 jbyte *dPtr = elements (dst) + dstBegin;
659 jchar *sPtr = JvGetStringChars (this) + srcBegin;
660 jint i = srcEnd-srcBegin;
ee9dd372
TT
661 while (--i >= 0)
662 *dPtr++ = (jbyte) *sPtr++;
663}
664
665jcharArray
666java::lang::String::toCharArray()
667{
668 jcharArray array = JvNewCharArray(count);
6c80c45e
TT
669 jchar *dPtr = elements (array);
670 jchar *sPtr = JvGetStringChars (this);
671 jint i = count;
ee9dd372
TT
672 while (--i >= 0)
673 *dPtr++ = *sPtr++;
674 return array;
675}
676
677jboolean
678java::lang::String::equalsIgnoreCase (jstring anotherString)
679{
aa620e42 680 if (anotherString == NULL || count != anotherString->count)
ee9dd372 681 return false;
6c80c45e
TT
682 jchar *tptr = JvGetStringChars (this);
683 jchar *optr = JvGetStringChars (anotherString);
684 jint i = count;
ee9dd372
TT
685 while (--i >= 0)
686 {
687 jchar tch = *tptr++;
688 jchar och = *optr++;
689 if (tch != och
690 && (java::lang::Character::toLowerCase (tch)
691 != java::lang::Character::toLowerCase (och))
692 && (java::lang::Character::toUpperCase (tch)
693 != java::lang::Character::toUpperCase (och)))
694 return false;
695 }
696 return true;
697}
698
699jboolean
700java::lang::String::regionMatches (jint toffset,
701 jstring other, jint ooffset, jint len)
702{
703 if (toffset < 0 || ooffset < 0
704 || toffset + len > count
705 || ooffset + len > other->count)
706 return false;
6c80c45e
TT
707 jchar *tptr = JvGetStringChars (this) + toffset;
708 jchar *optr = JvGetStringChars (other) + ooffset;
709 jint i = len;
ee9dd372
TT
710 while (--i >= 0)
711 {
712 if (*tptr++ != *optr++)
713 return false;
714 }
715 return true;
716}
717
718jint
719java::lang::String::compareTo (jstring anotherString)
720{
6c80c45e
TT
721 jchar *tptr = JvGetStringChars (this);
722 jchar *optr = JvGetStringChars (anotherString);
ee9dd372
TT
723 jint tlen = this->count;
724 jint olen = anotherString->count;
6c80c45e 725 jint i = tlen > olen ? olen : tlen;
ee9dd372
TT
726 while (--i >= 0)
727 {
728 jchar tch = *tptr++;
729 jchar och = *optr++;
730 if (tch != och)
731 return (jint) tch - (jint) och;
732 }
733 return tlen - olen;
734}
735
736jboolean
737java::lang::String::regionMatches (jboolean ignoreCase, jint toffset,
738 jstring other, jint ooffset, jint len)
739{
740 if (toffset < 0 || ooffset < 0
741 || toffset + len > count
742 || ooffset + len > other->count)
743 return false;
6c80c45e
TT
744 jchar *tptr = JvGetStringChars (this) + toffset;
745 jchar *optr = JvGetStringChars (other) + ooffset;
746 jint i = len;
b11f6430
AG
747 if (ignoreCase)
748 while (--i >= 0)
749 {
750 jchar tch = *tptr++;
751 jchar och = *optr++;
752 if ((java::lang::Character::toLowerCase (tch)
753 != java::lang::Character::toLowerCase (och))
754 && (java::lang::Character::toUpperCase (tch)
755 != java::lang::Character::toUpperCase (och)))
756 return false;
757 }
758 else
759 while (--i >= 0)
760 {
761 jchar tch = *tptr++;
762 jchar och = *optr++;
763 if (tch != och)
764 return false;
765 }
ee9dd372
TT
766 return true;
767}
768
769jboolean
770java::lang::String::startsWith (jstring prefix, jint toffset)
771{
6c80c45e 772 jint i = prefix->count;
ee9dd372
TT
773 if (toffset < 0 || toffset + i > count)
774 return false;
6c80c45e
TT
775 jchar *xptr = JvGetStringChars (this) + toffset;
776 jchar *yptr = JvGetStringChars (prefix);
ee9dd372
TT
777 while (--i >= 0)
778 {
779 if (*xptr++ != *yptr++)
780 return false;
781 }
782 return true;
783}
784
785jint
786java::lang::String::indexOf (jint ch, jint fromIndex)
787{
788 if (fromIndex < 0)
789 fromIndex = 0;
6c80c45e 790 jchar *ptr = JvGetStringChars(this);
ee9dd372
TT
791 for (;; ++fromIndex)
792 {
793 if (fromIndex >= count)
794 return -1;
795 if (ptr[fromIndex] == ch)
796 return fromIndex;
797 }
798}
799
800jint
801java::lang::String::indexOf (jstring s, jint fromIndex)
802{
803 const jchar *const xchars = JvGetStringChars(s);
804 const jchar *const ychars = JvGetStringChars(this) + fromIndex;
805
806 const int xlength = s->length ();
807 const int ylength = length () - fromIndex;
808
809 int i = 0;
810 int j = 0;
811
812 while (i < ylength && j < xlength)
813 {
814 if (xchars[j] != ychars[i])
815 {
816 i = i - j + 1;
817 j = 0;
818 }
819 else
820 i++, j++;
821 }
822
823 if (j >= xlength)
824 return fromIndex + i - xlength;
825 else
826 return -1;
827}
828
829jint
830java::lang::String::lastIndexOf (jint ch, jint fromIndex)
831{
832 if (fromIndex >= count)
833 fromIndex = count - 1;
6c80c45e 834 jchar *ptr = JvGetStringChars(this);
ee9dd372
TT
835 for (;; --fromIndex)
836 {
837 if (fromIndex < 0)
838 return -1;
839 if (ptr[fromIndex] == ch)
840 return fromIndex;
841 }
842}
843
844jstring
845java::lang::String::substring (jint beginIndex, jint endIndex)
846{
847 if (beginIndex < 0 || endIndex > count || beginIndex > endIndex)
b3208f56 848 throw new StringIndexOutOfBoundsException;
41296e2a
BM
849 if (beginIndex == 0 && endIndex == count)
850 return this;
ee9dd372
TT
851 jint newCount = endIndex - beginIndex;
852 if (newCount <= 8) // Optimization, mainly for GC.
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
861jstring
862java::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);
6c80c45e
TT
868 jchar *dstPtr = JvGetStringChars(result);
869 jchar *srcPtr = JvGetStringChars(this);
870 jint i = count;
ee9dd372
TT
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
880jstring
881java::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
906jstring
98394990 907java::lang::String::toLowerCase (java::util::Locale *locale)
ee9dd372
TT
908{
909 jint i;
910 jchar* chrs = JvGetStringChars(this);
db5e4903 911 jchar ch = 0;
98394990
TT
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
ee9dd372
TT
923 for (i = 0; ; i++)
924 {
925 if (i == count)
926 return this;
927 jchar origChar = chrs[i];
98394990
TT
928
929 if (handle_tr && (origChar == CAPITAL_I
930 || origChar == CAPITAL_I_WITH_DOT))
931 break;
932
ee9dd372
TT
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 {
98394990
TT
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]);
ee9dd372
TT
950 }
951 return result;
952}
953
954jstring
98394990 955java::lang::String::toUpperCase (java::util::Locale *locale)
ee9dd372
TT
956{
957 jint i;
958 jchar* chrs = JvGetStringChars(this);
959 jchar ch;
98394990
TT
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;
ee9dd372
TT
977 for (i = 0; ; i++)
978 {
979 if (i == count)
98394990 980 break;
ee9dd372 981 jchar origChar = chrs[i];
98394990
TT
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)
ee9dd372
TT
999 break;
1000 }
98394990
TT
1001 if (! new_string)
1002 return this;
1003 jstring result = JvAllocString(new_count);
ee9dd372 1004 jchar *dPtr = JvGetStringChars (result);
98394990 1005 for (i = 0; i < count; i++)
ee9dd372 1006 {
98394990
TT
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]);
ee9dd372
TT
1018 }
1019 return result;
1020}
1021
1022jstring
1023java::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
1042jstring
1043java::lang::String::valueOf(jcharArray data, jint offset, jint count)
1044{
1045 jint data_length = JvGetArrayLength (data);
1046 if (offset < 0 || count < 0 || offset+count > data_length)
cb894e07 1047 throw new ArrayIndexOutOfBoundsException;
6c80c45e
TT
1048 jstring result = JvAllocString(count);
1049 jchar *sPtr = elements (data) + offset;
1050 jchar *dPtr = JvGetStringChars(result);
ee9dd372
TT
1051 while (--count >= 0)
1052 *dPtr++ = *sPtr++;
1053 return result;
1054}
1055
1056jstring
1057java::lang::String::valueOf(jchar c)
1058{
6c80c45e 1059 jstring result = JvAllocString(1);
ee9dd372
TT
1060 JvGetStringChars (result)[0] = c;
1061 return result;
1062}
This page took 0.48361 seconds and 5 git commands to generate.