1 // natString.cc - Implementation of java.lang.String native methods.
3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007, 2008 Free Software Foundation
6 This file is part of libgcj.
8 This software is copyrighted work licensed under the terms of the
9 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
18 #include <java/lang/Character.h>
19 #include <java/lang/CharSequence.h>
20 #include <java/lang/String.h>
21 #include <java/lang/IndexOutOfBoundsException.h>
22 #include <java/lang/ArrayIndexOutOfBoundsException.h>
23 #include <java/lang/StringIndexOutOfBoundsException.h>
24 #include <java/lang/NullPointerException.h>
25 #include <java/lang/StringBuffer.h>
26 #include <java/io/ByteArrayOutputStream.h>
27 #include <java/io/CharConversionException.h>
28 #include <java/io/OutputStreamWriter.h>
29 #include <java/io/ByteArrayInputStream.h>
30 #include <java/io/InputStreamReader.h>
31 #include <java/util/Locale.h>
32 #include <gnu/gcj/convert/UnicodeToBytes.h>
33 #include <gnu/gcj/convert/BytesToUnicode.h>
34 #include <gnu/gcj/runtime/StringBuffer.h>
37 static jstring
* strhash
= NULL
;
38 static int strhash_count
= 0; /* Number of slots used in strhash. */
39 static int strhash_size
= 0; /* Number of slots available in strhash.
40 * Assumed be power of 2! */
42 // Some defines used by toUpperCase / toLowerCase.
44 #define CAPITAL_S 0x0053
45 #define SMALL_I 0x0069
46 #define CAPITAL_I_WITH_DOT 0x0130
47 #define SMALL_DOTLESS_I 0x0131
48 #define CAPITAL_I 0x0049
50 #define DELETED_STRING ((jstring)(~0))
51 #define SET_STRING_IS_INTERNED(STR) /* nothing */
53 #define UNMASK_PTR(Ptr) (((unsigned long) (Ptr)) & ~0x01)
54 #define MASK_PTR(Ptr) (((unsigned long) (Ptr)) | 0x01)
55 #define PTR_MASKED(Ptr) (((unsigned long) (Ptr)) & 0x01)
57 /* Find a slot where the string with elements DATA, length LEN,
58 and hash HASH should go in the strhash table of interned strings. */
60 _Jv_StringFindSlot (jchar
* data
, jint len
, jint hash
)
62 JvSynchronize
sync (&java::lang::String::class$
);
64 int start_index
= hash
& (strhash_size
- 1);
65 int deleted_index
= -1;
67 int index
= start_index
;
68 /* step must be non-zero, and relatively prime with strhash_size. */
69 jint step
= (hash
^ (hash
>> 16)) | 1;
72 jstring
* ptr
= &strhash
[index
];
73 jstring value
= (jstring
) UNMASK_PTR (*ptr
);
76 if (deleted_index
>= 0)
77 return (&strhash
[deleted_index
]);
81 else if (*ptr
== DELETED_STRING
)
82 deleted_index
= index
;
83 else if (value
->length() == len
84 && memcmp(JvGetStringChars(value
), data
, 2*len
) == 0)
86 index
= (index
+ step
) & (strhash_size
- 1);
88 while (index
!= start_index
);
89 // Note that we can have INDEX == START_INDEX if the table has no
90 // NULL entries but does have DELETED_STRING entries.
91 JvAssert (deleted_index
>= 0);
92 return &strhash
[deleted_index
];
95 /* Calculate a hash code for the string starting at PTR at given LENGTH.
96 This uses the same formula as specified for java.lang.String.hash. */
99 hashChars (jchar
* ptr
, jint length
)
101 jchar
* limit
= ptr
+ length
;
103 // Updated specification from
104 // http://www.javasoft.com/docs/books/jls/clarify.html.
106 hash
= (31 * hash
) + *ptr
++;
111 java::lang::String::hashCode()
113 if (cachedHashCode
== 0)
114 cachedHashCode
= hashChars(JvGetStringChars(this), length());
115 return cachedHashCode
;
119 _Jv_StringGetSlot (jstring str
)
121 jchar
* data
= JvGetStringChars(str
);
122 int length
= str
->length();
123 return _Jv_StringFindSlot(data
, length
, hashChars (data
, length
));
129 JvSynchronize
sync (&java::lang::String::class$
);
134 strhash
= (jstring
*) _Jv_AllocBytes (strhash_size
* sizeof (jstring
));
138 int i
= strhash_size
;
139 jstring
* ptr
= strhash
+ i
;
140 int nsize
= strhash_size
* 2;
141 jstring
*next
= (jstring
*) _Jv_AllocBytes (nsize
* sizeof (jstring
));
146 if (*ptr
== NULL
|| *ptr
== DELETED_STRING
)
149 /* This is faster equivalent of
150 * *__JvGetInternSlot(*ptr) = *ptr; */
151 jstring val
= (jstring
) UNMASK_PTR (*ptr
);
152 jint hash
= val
->hashCode();
153 jint index
= hash
& (nsize
- 1);
154 jint step
= (hash
^ (hash
>> 16)) | 1;
157 if (next
[index
] == NULL
)
162 index
= (index
+ step
) & (nsize
- 1);
166 strhash_size
= nsize
;
172 java::lang::String::intern()
174 JvSynchronize
sync (&java::lang::String::class$
);
175 if (3 * strhash_count
>= 2 * strhash_size
)
177 jstring
* ptr
= _Jv_StringGetSlot(this);
178 if (*ptr
!= NULL
&& *ptr
!= DELETED_STRING
)
180 // See description in _Jv_FinalizeString() to understand this.
181 *ptr
= (jstring
) MASK_PTR (*ptr
);
182 return (jstring
) UNMASK_PTR (*ptr
);
184 jstring str
= (this->data
== this
186 : _Jv_NewString(JvGetStringChars(this), this->length()));
187 SET_STRING_IS_INTERNED(str
);
190 // When string is GC'd, clear the slot in the hash table.
191 _Jv_RegisterStringFinalizer (str
);
195 // The fake String finalizer. This is only used when the String has
196 // been intern()d. However, we must check this case, as it might be
197 // called by the Reference code for any String.
199 _Jv_FinalizeString (jobject obj
)
201 JvSynchronize
sync (&java::lang::String::class$
);
203 // We might not actually have intern()d any strings at all, if
204 // we're being called from Reference.
208 jstring str
= reinterpret_cast<jstring
> (obj
);
209 jstring
*ptr
= _Jv_StringGetSlot(str
);
210 if (*ptr
== NULL
|| *ptr
== DELETED_STRING
211 || (jobject
) UNMASK_PTR (*ptr
) != obj
)
214 // We assume the lowest bit of the pointer is free for our nefarious
215 // manipulations. What we do is set it to `0' (implicitly) when
216 // interning the String. If we subsequently re-intern the same
217 // String, then we set the bit. When finalizing, if the bit is set
218 // then we clear it and re-register the finalizer. We know this is
219 // a safe approach because both intern() and _Jv_FinalizeString()
220 // acquire the class lock; this bit can't be manipulated when the
221 // lock is not held. So if we are finalizing and the bit is clear
222 // then we know all references are gone and we can clear the entry
223 // in the hash table. The naive approach of simply clearing the
224 // pointer here fails in the case where a request to intern a new
225 // string with the same contents is made between the time the
226 // intern()d string is found to be unreachable and when the
227 // finalizer is actually run. In this case we could clear a pointer
228 // to a valid string, and future intern() calls for that particular
229 // value would spuriously fail.
230 if (PTR_MASKED (*ptr
))
232 *ptr
= (jstring
) UNMASK_PTR (*ptr
);
233 _Jv_RegisterStringFinalizer (obj
);
237 *ptr
= DELETED_STRING
;
243 _Jv_NewStringUTF (const char *bytes
)
245 int size
= strlen (bytes
);
246 unsigned char *p
= (unsigned char *) bytes
;
248 int length
= _Jv_strLengthUtf8 ((char *) p
, size
);
252 jstring jstr
= JvAllocString (length
);
253 jchar
*chrs
= JvGetStringChars (jstr
);
255 p
= (unsigned char *) bytes
;
256 unsigned char *limit
= p
+ size
;
258 *chrs
++ = UTF8_GET (p
, limit
);
264 _Jv_NewStringUtf8Const (Utf8Const
* str
)
269 unsigned char* data
= (unsigned char*) str
->data
;
270 unsigned char* limit
= data
+ str
->length
;
271 int length
= _Jv_strLengthUtf8(str
->data
, str
->length
);
273 if (length
<= (int) (sizeof(buffer
) / sizeof(jchar
)))
280 jstr
= JvAllocString(length
);
281 chrs
= JvGetStringChars(jstr
);
287 jchar ch
= UTF8_GET(data
, limit
);
288 hash
= (31 * hash
) + ch
;
293 JvSynchronize
sync (&java::lang::String::class$
);
294 if (3 * strhash_count
>= 2 * strhash_size
)
296 jstring
* ptr
= _Jv_StringFindSlot (chrs
, length
, hash
);
297 if (*ptr
!= NULL
&& *ptr
!= DELETED_STRING
)
298 return (jstring
) UNMASK_PTR (*ptr
);
302 jstr
= JvAllocString(length
);
303 chrs
= JvGetStringChars(jstr
);
304 memcpy (chrs
, buffer
, sizeof(jchar
)*length
);
306 jstr
->cachedHashCode
= hash
;
308 SET_STRING_IS_INTERNED(jstr
);
309 // When string is GC'd, clear the slot in the hash table. Note that
310 // we don't have to call _Jv_RegisterStringFinalizer here, as we
311 // know the new object cannot be referred to by a Reference.
312 _Jv_RegisterFinalizer ((void *) jstr
, _Jv_FinalizeString
);
317 _Jv_GetStringUTFLength (jstring string
)
320 jchar
*ptr
= JvGetStringChars (string
);
321 jsize i
= string
->length();
325 if (ch
> 0 && ch
<= 0x7F)
327 else if (ch
<= 0x7FF)
335 // Not sure this quite matches GetStringUTFRegion.
336 // null-termination of result? len? throw exception?
338 _Jv_GetStringUTFRegion (jstring str
, jsize start
, jsize len
, char *buf
)
340 jchar
*sptr
= JvGetStringChars (str
) + start
;
346 if (ch
> 0 && ch
<= 0x7F)
348 else if (ch
<= 0x7FF)
350 *dptr
++ = (char) (0xC0 + ((ch
>> 6) & 0x1F));
351 *dptr
++ = (char) (0x80 + (ch
& 0x3F));
355 *dptr
++ = (char) (0xE0 + ((ch
>> 12) & 0xF));
356 *dptr
++ = (char) (0x80 + ((ch
>> 6) & 0x3F));
357 *dptr
++ = (char) (0x80 + (ch
& 0x3F));
363 /* Put printed (decimal) representation of NUM in a buffer.
364 BUFEND marks the end of the buffer, which must be at least 11 jchars long.
365 Returns the COUNT of jchars written. The result is in
366 (BUFEND - COUNT) (inclusive) upto (BUFEND) (exclusive). */
369 _Jv_FormatInt (jchar
* bufend
, jint num
)
371 register jchar
* ptr
= bufend
;
376 if (num
!= (jint
) -2147483648U)
380 // Handle special case of MIN_VALUE.
390 *--ptr
= (jchar
) ((int) '0' + (num
% 10));
401 java::lang::String::valueOf (jint num
)
403 // Use an array large enough for "-2147483648"; i.e. 11 chars.
405 int i
= _Jv_FormatInt (buffer
+11, num
);
406 return _Jv_NewString (buffer
+11-i
, i
);
410 _Jv_NewString(const jchar
*chars
, jsize len
)
412 jstring str
= _Jv_AllocString(len
);
413 jchar
* data
= JvGetStringChars (str
);
414 memcpy (data
, chars
, len
* sizeof (jchar
));
419 _Jv_NewStringLatin1(const char *bytes
, jsize len
)
421 jstring str
= JvAllocString(len
);
422 jchar
* data
= JvGetStringChars (str
);
424 *data
++ = *(unsigned char*)bytes
++;
429 java::lang::String::init(jcharArray chars
, jint offset
, jint count
,
433 throw new NullPointerException
;
434 jsize data_size
= JvGetArrayLength (chars
);
435 if (offset
< 0 || count
< 0 || offset
+ count
< 0
436 || offset
+ count
> data_size
)
437 throw new ArrayIndexOutOfBoundsException
;
442 array
= JvNewCharArray(count
);
443 pdst
= elements (array
);
444 memcpy (pdst
, elements (chars
) + offset
, count
* sizeof (jchar
));
449 pdst
= &(elements(array
)[offset
]);
453 boffset
= (char *) pdst
- (char *) array
;
458 java::lang::String::init(jbyteArray ascii
, jint hibyte
, jint offset
,
462 throw new NullPointerException
;
463 jsize data_size
= JvGetArrayLength (ascii
);
464 if (offset
< 0 || count
< 0 || offset
+ count
< 0
465 || offset
+ count
> data_size
)
466 throw new ArrayIndexOutOfBoundsException
;
467 jcharArray array
= JvNewCharArray(count
);
468 jbyte
*psrc
= elements (ascii
) + offset
;
469 jchar
*pdst
= elements (array
);
471 boffset
= (char *) pdst
- (char *) array
;
473 hibyte
= (hibyte
& 0xff) << 8;
474 while (-- count
>= 0)
476 *pdst
++ = hibyte
| (*psrc
++ & 0xff);
481 java::lang::String::init (jbyteArray bytes
, jint offset
, jint count
,
485 throw new NullPointerException
;
486 jsize data_size
= JvGetArrayLength (bytes
);
487 if (offset
< 0 || count
< 0 || offset
+ count
< 0
488 || offset
+ count
> data_size
)
489 throw new ArrayIndexOutOfBoundsException
;
490 jcharArray array
= JvNewCharArray (count
);
491 gnu::gcj::convert::BytesToUnicode
*converter
492 = gnu::gcj::convert::BytesToUnicode::getDecoder(encoding
);
495 converter
->setInput(bytes
, offset
, offset
+count
);
496 while (converter
->inpos
< converter
->inlength
)
501 done
= converter
->read(array
, outpos
, avail
);
503 catch (::java::io::CharConversionException
*e
)
505 // Ignore it and silently throw away the offending data.
510 // done is zero if either there is no space available in the
511 // output *or* the input is incomplete. We assume that if
512 // there are 20 characters available in the output, the
513 // input must be incomplete and there is no more work to do.
514 // This means we may skip several bytes of input, but that
515 // is OK as the behavior is explicitly unspecified in this
517 if (avail
- outpos
> 20)
520 jint new_size
= 2 * (outpos
+ avail
);
521 jcharArray new_array
= JvNewCharArray (new_size
);
522 memcpy (elements (new_array
), elements (array
),
523 outpos
* sizeof(jchar
));
525 avail
= new_size
- outpos
;
535 this->boffset
= (char *) elements (array
) - (char *) array
;
536 this->count
= outpos
;
540 java::lang::String::init (gnu::gcj::runtime::StringBuffer
*buffer
)
542 init (buffer
->value
, 0, buffer
->count
, true);
546 java::lang::String::equals(jobject anObject
)
548 if (anObject
== NULL
)
550 if (anObject
== this)
552 if (anObject
->getClass() != &java::lang::String::class$
)
554 jstring other
= (jstring
) anObject
;
555 if (count
!= other
->count
)
558 // If both have cached hash codes, check that. If the cached hash
559 // codes are zero, don't bother trying to compute them.
560 int myHash
= cachedHashCode
;
561 int otherHash
= other
->cachedHashCode
;
562 if (myHash
&& otherHash
&& myHash
!= otherHash
)
565 // We could see if both are interned, and return false. But that
566 // seems too expensive.
568 jchar
*xptr
= JvGetStringChars (this);
569 jchar
*yptr
= JvGetStringChars (other
);
570 return ! memcmp (xptr
, yptr
, count
* sizeof (jchar
));
574 java::lang::String::contentEquals(java::lang::StringBuffer
* buffer
)
577 throw new NullPointerException
;
578 JvSynchronize
sync(buffer
);
579 if (count
!= buffer
->count
)
581 if (data
== buffer
->value
)
582 return true; // Possible if shared.
583 jchar
*xptr
= JvGetStringChars(this);
584 jchar
*yptr
= elements(buffer
->value
);
585 return ! memcmp (xptr
, yptr
, count
* sizeof (jchar
));
589 java::lang::String::contentEquals(java::lang::CharSequence
*seq
)
591 if (seq
->length() != count
)
593 jchar
*value
= JvGetStringChars(this);
594 for (int i
= 0; i
< count
; ++i
)
595 if (value
[i
] != seq
->charAt(i
))
601 java::lang::String::charAt(jint i
)
603 if (i
< 0 || i
>= count
)
604 throw new java::lang::StringIndexOutOfBoundsException(i
);
605 return JvGetStringChars(this)[i
];
609 java::lang::String::getChars(jint srcBegin
, jint srcEnd
,
610 jcharArray dst
, jint dstBegin
)
612 jint dst_length
= JvGetArrayLength (dst
);
613 if (srcBegin
< 0 || srcBegin
> srcEnd
|| srcEnd
> count
)
614 throw new java::lang::StringIndexOutOfBoundsException
;
615 // The 2nd part of the test below is equivalent to
616 // dstBegin + (srcEnd-srcBegin) > dst_length
617 // except that it does not overflow.
618 if (dstBegin
< 0 || dstBegin
> dst_length
- (srcEnd
-srcBegin
))
619 throw new ArrayIndexOutOfBoundsException
;
620 jchar
*dPtr
= elements (dst
) + dstBegin
;
621 jchar
*sPtr
= JvGetStringChars (this) + srcBegin
;
622 jint i
= srcEnd
- srcBegin
;
623 memcpy (dPtr
, sPtr
, i
* sizeof (jchar
));
627 java::lang::String::getBytes (jstring enc
)
629 jint todo
= length();
631 jbyteArray buffer
= JvNewByteArray(todo
);
634 gnu::gcj::convert::UnicodeToBytes
*converter
635 = gnu::gcj::convert::UnicodeToBytes::getEncoder(enc
);
636 while (todo
> 0 || converter
->havePendingBytes())
638 converter
->setOutput(buffer
, bufpos
);
639 int converted
= converter
->write(this, offset
, todo
, NULL
);
640 bufpos
= converter
->count
;
644 jbyteArray newbuffer
= JvNewByteArray(buflen
);
645 memcpy (elements (newbuffer
), elements (buffer
), bufpos
);
656 converter
->setFinished();
657 converter
->write(this, 0, 0, NULL
);
660 if (bufpos
== buflen
)
662 jbyteArray result
= JvNewByteArray(bufpos
);
663 memcpy (elements (result
), elements (buffer
), bufpos
);
668 java::lang::String::getBytes(jint srcBegin
, jint srcEnd
,
669 jbyteArray dst
, jint dstBegin
)
671 jint dst_length
= JvGetArrayLength (dst
);
672 if (srcBegin
< 0 || srcBegin
> srcEnd
|| srcEnd
> count
)
673 throw new java::lang::StringIndexOutOfBoundsException
;
674 // The 2nd part of the test below is equivalent to
675 // dstBegin + (srcEnd-srcBegin) > dst_length
676 // except that it does not overflow.
677 if (dstBegin
< 0 || dstBegin
> dst_length
- (srcEnd
-srcBegin
))
678 throw new ArrayIndexOutOfBoundsException
;
679 jbyte
*dPtr
= elements (dst
) + dstBegin
;
680 jchar
*sPtr
= JvGetStringChars (this) + srcBegin
;
681 jint i
= srcEnd
-srcBegin
;
683 *dPtr
++ = (jbyte
) *sPtr
++;
687 java::lang::String::toCharArray()
689 jcharArray array
= JvNewCharArray(count
);
690 jchar
*dPtr
= elements (array
);
691 jchar
*sPtr
= JvGetStringChars (this);
693 memcpy (dPtr
, sPtr
, i
* sizeof (jchar
));
698 java::lang::String::equalsIgnoreCase (jstring anotherString
)
700 if (anotherString
== NULL
|| count
!= anotherString
->count
)
702 jchar
*tptr
= JvGetStringChars (this);
703 jchar
*optr
= JvGetStringChars (anotherString
);
710 && (java::lang::Character::toLowerCase (tch
)
711 != java::lang::Character::toLowerCase (och
))
712 && (java::lang::Character::toUpperCase (tch
)
713 != java::lang::Character::toUpperCase (och
)))
720 java::lang::String::regionMatches (jint toffset
,
721 jstring other
, jint ooffset
, jint len
)
723 if (toffset
< 0 || ooffset
< 0 || len
< 0
724 || toffset
> count
- len
725 || ooffset
> other
->count
- len
)
727 jchar
*tptr
= JvGetStringChars (this) + toffset
;
728 jchar
*optr
= JvGetStringChars (other
) + ooffset
;
730 return ! memcmp (tptr
, optr
, i
* sizeof (jchar
));
734 java::lang::String::nativeCompareTo (jstring anotherString
)
736 jchar
*tptr
= JvGetStringChars (this);
737 jchar
*optr
= JvGetStringChars (anotherString
);
738 jint tlen
= this->count
;
739 jint olen
= anotherString
->count
;
740 jint i
= tlen
> olen
? olen
: tlen
;
746 return (jint
) tch
- (jint
) och
;
752 java::lang::String::regionMatches (jboolean ignoreCase
, jint toffset
,
753 jstring other
, jint ooffset
, jint len
)
755 if (toffset
< 0 || ooffset
< 0 || len
< 0
756 || toffset
> count
- len
757 || ooffset
> other
->count
- len
)
759 jchar
*tptr
= JvGetStringChars (this) + toffset
;
760 jchar
*optr
= JvGetStringChars (other
) + ooffset
;
768 if ((java::lang::Character::toLowerCase (tch
)
769 != java::lang::Character::toLowerCase (och
))
770 && (java::lang::Character::toUpperCase (tch
)
771 != java::lang::Character::toUpperCase (och
)))
776 return ! memcmp (tptr
, optr
, i
* sizeof (jchar
));
780 java::lang::String::startsWith (jstring prefix
, jint toffset
)
782 jint i
= prefix
->count
;
783 if (toffset
< 0 || toffset
> count
- i
)
785 jchar
*xptr
= JvGetStringChars (this) + toffset
;
786 jchar
*yptr
= JvGetStringChars (prefix
);
787 return ! memcmp (xptr
, yptr
, i
* sizeof (jchar
));
791 java::lang::String::indexOf (jint ch
, jint fromIndex
)
795 jchar
*ptr
= JvGetStringChars(this);
798 if (fromIndex
>= count
)
800 if (ptr
[fromIndex
] == ch
)
806 java::lang::String::indexOf (jstring s
, jint fromIndex
)
808 const jchar
*const xchars
= JvGetStringChars(s
);
809 const jchar
*const ychars
= JvGetStringChars(this) + fromIndex
;
811 const int xlength
= s
->length ();
812 const int ylength
= length () - fromIndex
;
817 while (i
< ylength
&& j
< xlength
)
819 if (xchars
[j
] != ychars
[i
])
829 return fromIndex
+ i
- xlength
;
835 java::lang::String::lastIndexOf (jint ch
, jint fromIndex
)
837 if (fromIndex
>= count
)
838 fromIndex
= count
- 1;
839 jchar
*ptr
= JvGetStringChars(this);
844 if (ptr
[fromIndex
] == ch
)
850 java::lang::String::substring (jint beginIndex
, jint endIndex
)
852 if (beginIndex
< 0 || endIndex
> count
|| beginIndex
> endIndex
)
853 throw new StringIndexOutOfBoundsException
;
854 if (beginIndex
== 0 && endIndex
== count
)
856 jint newCount
= endIndex
- beginIndex
;
857 // For very small strings, just allocate a new one. For other
858 // substrings, allocate a new one unless the substring is over half
859 // of the original string.
860 if (newCount
<= 8 || newCount
< (count
>> 1))
861 return JvNewString(JvGetStringChars(this) + beginIndex
, newCount
);
862 jstring s
= new String();
865 s
->boffset
= boffset
+ sizeof(jchar
) * beginIndex
;
870 java::lang::String::concat(jstring str
)
872 jint str_count
= str
->count
;
875 jstring result
= JvAllocString(count
+ str_count
);
876 jchar
*dstPtr
= JvGetStringChars(result
);
877 jchar
*srcPtr
= JvGetStringChars(this);
879 memcpy (dstPtr
, srcPtr
, i
* sizeof (jchar
));
881 srcPtr
= JvGetStringChars(str
);
883 memcpy (dstPtr
, srcPtr
, i
* sizeof (jchar
));
888 java::lang::String::replace (jchar oldChar
, jchar newChar
)
891 jchar
* chrs
= JvGetStringChars (this);
896 if (chrs
[i
] == oldChar
)
899 jstring result
= JvAllocString (count
);
900 jchar
*dPtr
= JvGetStringChars (result
);
901 for (int j
= 0; j
< i
; j
++)
903 for (; i
< count
; i
++)
914 java::lang::String::toLowerCase (java::util::Locale
*locale
)
917 jchar
* chrs
= JvGetStringChars(this);
920 bool handle_tr
= false;
923 String
*lang
= locale
->getLanguage ();
924 if (lang
->length () == 2
925 && lang
->charAt (0) == 't'
926 && lang
->charAt (1) == 'r')
934 jchar origChar
= chrs
[i
];
936 if (handle_tr
&& (origChar
== CAPITAL_I
937 || origChar
== CAPITAL_I_WITH_DOT
))
940 ch
= java::lang::Character::toLowerCase(origChar
);
944 jstring result
= JvAllocString(count
);
945 jchar
*dPtr
= JvGetStringChars (result
);
946 for (int j
= 0; j
< i
; j
++)
949 for (; i
< count
; i
++)
951 if (handle_tr
&& chrs
[i
] == CAPITAL_I
)
952 *dPtr
++ = SMALL_DOTLESS_I
;
953 else if (handle_tr
&& chrs
[i
] == CAPITAL_I_WITH_DOT
)
956 *dPtr
++ = java::lang::Character::toLowerCase(chrs
[i
]);
962 java::lang::String::toUpperCase (java::util::Locale
*locale
)
965 jchar
* chrs
= JvGetStringChars(this);
968 // When handling a specific locale there might be special rules.
969 // Currently all existing rules are simply handled inline, as there
970 // are only two and they are documented in the online 1.2 docs.
971 bool handle_esset
= locale
!= NULL
;
972 bool handle_tr
= false;
975 String
*lang
= locale
->getLanguage ();
976 if (lang
->length () == 2
977 && lang
->charAt (0) == 't'
978 && lang
->charAt (1) == 'r')
982 int new_count
= count
;
983 bool new_string
= false;
988 jchar origChar
= chrs
[i
];
990 if (handle_esset
&& origChar
== ESSET
)
995 else if (handle_tr
&& (origChar
== SMALL_I
996 || origChar
== SMALL_DOTLESS_I
))
1000 ch
= java::lang::Character::toUpperCase(origChar
);
1005 if (new_string
&& ! handle_esset
)
1010 jstring result
= JvAllocString(new_count
);
1011 jchar
*dPtr
= JvGetStringChars (result
);
1012 for (i
= 0; i
< count
; i
++)
1014 if (handle_esset
&& chrs
[i
] == ESSET
)
1016 *dPtr
++ = CAPITAL_S
;
1017 *dPtr
++ = CAPITAL_S
;
1019 else if (handle_tr
&& chrs
[i
] == SMALL_I
)
1020 *dPtr
++ = CAPITAL_I_WITH_DOT
;
1021 else if (handle_tr
&& chrs
[i
] == SMALL_DOTLESS_I
)
1022 *dPtr
++ = CAPITAL_I
;
1024 *dPtr
++ = java::lang::Character::toUpperCase(chrs
[i
]);
1030 java::lang::String::trim ()
1032 jchar
* chrs
= JvGetStringChars(this);
1033 if (count
== 0 || (chrs
[0] > ' ' && chrs
[count
-1] > ' '))
1038 if (preTrim
== count
)
1039 return new String();
1040 if (chrs
[preTrim
] > ' ')
1043 jint endTrim
= count
;
1044 while (chrs
[endTrim
-1] <= ' ')
1046 return substring(preTrim
, endTrim
);
1050 java::lang::String::valueOf(jcharArray data
, jint offset
, jint count
)
1052 jint data_length
= JvGetArrayLength (data
);
1053 if (offset
< 0 || count
< 0 || offset
> data_length
- count
)
1054 throw new ArrayIndexOutOfBoundsException
;
1055 jstring result
= JvAllocString(count
);
1056 jchar
*sPtr
= elements (data
) + offset
;
1057 jchar
*dPtr
= JvGetStringChars(result
);
1058 memcpy (dPtr
, sPtr
, count
* sizeof (jchar
));
1063 java::lang::String::valueOf(jchar c
)
1065 jstring result
= JvAllocString(1);
1066 JvGetStringChars (result
)[0] = c
;