2 * string-icalls.c: String internal calls for the corlib
5 * Patrik Torstensson (patrik.torstensson@labs2.com)
7 * (C) 2001 Ximian, Inc.
14 #include <mono/metadata/string-icalls.h>
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/loader.h>
18 #include <mono/metadata/object.h>
19 #include <mono/metadata/unicode.h>
20 #include <mono/metadata/exception.h>
23 mono_string_Internal_ctor_charp (gpointer dummy, gunichar2 *value)
28 domain = mono_domain_get ();
33 for (i = 0; *(value + i) != '\0'; i++);
37 return mono_string_new_utf16 (domain, value, length);
41 mono_string_Internal_ctor_char_int (gpointer dummy, gunichar2 value, gint32 count)
48 domain = mono_domain_get ();
49 res = mono_string_new_size (domain, count);
51 chars = mono_string_chars (res);
52 for (i = 0; i < count; i++)
59 mono_string_Internal_ctor_charp_int_int (gpointer dummy, gunichar2 *value, gint32 sindex, gint32 length)
64 domain = mono_domain_get ();
66 if ((value == NULL) && (sindex != 0) && (length != 0))
67 mono_raise_exception (mono_get_exception_argument_null ("Argument null"));
69 if ((sindex < 0) || (length < 0))
70 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
72 begin = (gunichar2 *) (value + sindex);
74 return mono_string_new_utf16 (domain, begin, length);
78 mono_string_Internal_ctor_sbytep (gpointer dummy, gint8 *value)
83 domain = mono_domain_get ();
88 for (i = 0; *(value + i) != '\0'; i++);
92 return mono_string_new_utf16 (domain, (gunichar2 *) value, length);
96 mono_string_Internal_ctor_sbytep_int_int (gpointer dummy, gint8 *value, gint32 sindex, gint32 length)
101 domain = mono_domain_get ();
103 if ((value == NULL) && (sindex != 0) && (length != 0))
104 mono_raise_exception (mono_get_exception_argument_null ("Argument null"));
106 if ((sindex > 0) || (length < 0))
107 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
109 begin = (gunichar2 *) (value + sindex);
111 return mono_string_new_utf16 (domain, begin, length);
115 mono_string_Internal_ctor_chara (gpointer dummy, MonoArray *value)
119 MONO_CHECK_ARG_NULL (value);
121 domain = mono_domain_get ();
123 return mono_string_new_utf16 (domain, (gunichar2 *) mono_array_addr(value, gunichar2, 0), value->max_length);
127 mono_string_Internal_ctor_chara_int_int (gpointer dummy, MonoArray *value,
128 gint32 sindex, gint32 length)
132 MONO_CHECK_ARG_NULL (value);
134 domain = ((MonoObject *) value)->vtable->domain;
136 return mono_string_new_utf16 (domain, (gunichar2 *) mono_array_addr(value, gunichar2, sindex), length);
140 mono_string_Internal_ctor_encoding (gpointer dummy, gint8 *value, gint32 sindex,
141 gint32 length, MonoObject *enc)
143 g_assert_not_reached ();
148 mono_string_InternalJoin (MonoString *separator, MonoArray * value, gint32 sindex, gint32 count)
160 insert = mono_string_chars(separator);
161 insertlen = mono_string_length(separator);
164 for (pos = sindex; pos != sindex + count; pos++) {
165 length += mono_string_length(mono_array_get(value, MonoString *, pos));
166 if (pos < sindex + count - 1)
170 ret = mono_string_InternalAllocateStr(length);
171 dest = mono_string_chars(ret);
174 for (pos = sindex; pos != sindex + count; pos++) {
175 src = mono_string_chars(mono_array_get(value, MonoString *, pos));
176 srclen = mono_string_length(mono_array_get(value, MonoString *, pos));
178 memcpy(dest + destpos, src, srclen * sizeof(gunichar2));
181 if (pos < sindex + count - 1) {
182 memcpy(dest + destpos, insert, insertlen * sizeof(gunichar2));
183 destpos += insertlen;
191 mono_string_InternalInsert (MonoString *me, gint32 sindex, MonoString *value)
195 gunichar2 *insertsrc;
200 src = mono_string_chars(me);
201 srclen = mono_string_length(me);
203 insertsrc = mono_string_chars(value);
204 insertlen = mono_string_length(value);
206 ret = mono_string_InternalAllocateStr(mono_string_length(me) + insertlen);
207 dest = mono_string_chars(ret);
209 memcpy(dest, src, sindex * sizeof(gunichar2));
210 memcpy(dest + sindex, insertsrc, insertlen * sizeof(gunichar2));
211 memcpy(dest + sindex + insertlen, src + sindex, (srclen - sindex) * sizeof(gunichar2));
217 mono_string_InternalReplaceChar (MonoString *me, gunichar2 oldChar, gunichar2 newChar)
219 g_warning("mono_string_InternalReplaceChar not impl");
220 return mono_string_new_utf16(mono_domain_get(), mono_string_chars(me), mono_string_length(me));
224 mono_string_InternalReplaceStr (MonoString *me, MonoString *oldValue, MonoString *newValue)
226 g_warning("mono_string_InternalReplaceStr not impl");
227 return mono_string_new_utf16(mono_domain_get(), mono_string_chars(me), mono_string_length(me));
231 mono_string_InternalRemove (MonoString *me, gint32 sindex, gint32 count)
240 me_bytes = mono_string_length(me);
241 ret = mono_string_InternalAllocateStr(me_bytes - count);
242 index_bytes = sindex * sizeof(gunichar2);
243 count_bytes = count * sizeof(gunichar2);
245 src = mono_string_chars(me);
246 dest = mono_string_chars(ret);
248 memcpy(dest, src, index_bytes);
249 memcpy(dest + sindex, src + sindex + count, me_bytes - count_bytes);
255 mono_string_InternalCopyTo (MonoString *me, gint32 sindex, MonoArray *dest, gint32 dindex, gint32 count)
257 gunichar2 *destptr = (gunichar2 *) mono_array_addr(dest, gunichar2, dindex);
258 gunichar2 *src = mono_string_chars(me);
260 memcpy(destptr, src + sindex, sizeof(gunichar2) * count);
264 mono_string_InternalSplit (MonoString *me, MonoArray *separator, gint32 count)
269 gint32 arrsize, srcsize, splitsize;
270 gint32 i, lastpos, arrpos;
272 gunichar2 *tmpstrptr;
274 src = mono_string_chars(me);
275 srcsize = mono_string_length(me);
276 arrsize = mono_array_length(separator);
279 for (i = 0; i != srcsize && splitsize < count; i++) {
280 if (mono_string_isinarray(separator, arrsize, src[i]))
287 /* if no split chars found return the string */
288 if (splitsize == 0) {
289 retarr = mono_array_new(mono_domain_get(), mono_defaults.string_class, 1);
290 tmpstr = mono_string_InternalAllocateStr(srcsize);
291 tmpstrptr = mono_string_chars(tmpstr);
293 memcpy(tmpstrptr, src, srcsize * sizeof(gunichar2));
294 mono_array_set(retarr, MonoString *, 0, tmpstr);
299 if (splitsize + 1 < count)
302 retarr = mono_array_new(mono_domain_get(), mono_defaults.string_class, splitsize);
303 for (i = 0; i != srcsize && arrpos != count; i++) {
304 if (mono_string_isinarray(separator, arrsize, src[i])) {
305 if (arrpos == count - 1)
306 tmpstrsize = srcsize - lastpos;
308 tmpstrsize = i - lastpos;
310 tmpstr = mono_string_InternalAllocateStr(tmpstrsize);
311 tmpstrptr = mono_string_chars(tmpstr);
313 memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
314 mono_array_set(retarr, MonoString *, arrpos, tmpstr);
320 if (arrpos < count) {
321 tmpstrsize = srcsize - lastpos;
322 tmpstr = mono_string_InternalAllocateStr(tmpstrsize);
323 tmpstrptr = mono_string_chars(tmpstr);
325 memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
326 mono_array_set(retarr, MonoString *, arrpos, tmpstr);
333 mono_string_isinarray (MonoArray *chars, gint32 arraylength, gunichar2 chr)
338 for (arrpos = 0; arrpos != arraylength; arrpos++) {
339 cmpchar = mono_array_get(chars, gunichar2, arrpos);
340 if (mono_string_cmp_char(cmpchar, chr, 1) == 0)
348 mono_string_InternalTrim (MonoString *me, MonoArray *chars, gint32 typ)
351 gunichar2 *src, *dest;
352 gint32 srclen, newlen, arrlen;
353 gint32 i, lenfirst, lenlast;
355 srclen = mono_string_length(me);
356 src = mono_string_chars(me);
357 arrlen = mono_array_length(chars);
362 if (0 == typ || 1 == typ) {
363 for (i = 0; i != srclen; i++) {
364 if (mono_string_isinarray(chars, arrlen, src[i]))
371 if (0 == typ || 2 == typ) {
372 for (i = srclen - 1; i > lenfirst - 1; i--) {
373 if (mono_string_isinarray(chars, arrlen, src[i]))
380 newlen = srclen - lenfirst - lenlast;
382 ret = mono_string_InternalAllocateStr(newlen);
383 dest = mono_string_chars(ret);
385 memcpy(dest, src + lenfirst, newlen *sizeof(gunichar2));
391 mono_string_InternalIndexOfChar (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
396 src = mono_string_chars(me);
397 for (pos = sindex; pos != count + sindex; pos++) {
398 if ( src [pos] == value)
406 mono_string_InternalIndexOfStr (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
413 lencmpstr = mono_string_length(value);
415 src = mono_string_chars(me);
416 cmpstr = mono_string_chars(value);
418 for (pos = sindex; pos != count + sindex; pos++) {
419 if (pos + lencmpstr > count + sindex)
422 if (0 == memcmp(src + pos, cmpstr, lencmpstr * sizeof(gunichar2)))
430 mono_string_InternalIndexOfAny (MonoString *me, MonoArray *arr, gint32 sindex, gint32 count)
437 arraysize = mono_array_length(arr);
438 src = mono_string_chars(me);
440 for (pos = sindex; pos != count + sindex; pos++) {
441 for (loop = 0; loop != arraysize; loop++)
442 if ( src [pos] == mono_array_get(arr, gunichar2, loop) )
450 mono_string_InternalLastIndexOfChar (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
455 src = mono_string_chars(me);
456 for (pos = sindex; pos > sindex - count; pos--) {
457 if (src [pos] == value)
465 mono_string_InternalLastIndexOfStr (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
472 lencmpstr = mono_string_length(value);
474 src = mono_string_chars(me);
475 cmpstr = mono_string_chars(value);
477 for (pos = sindex; pos > sindex - count; pos--) {
478 if (0 == memcmp(src + pos, cmpstr, lencmpstr * sizeof(gunichar2)))
486 mono_string_InternalLastIndexOfAny (MonoString *me, MonoArray *anyOf, gint32 sindex, gint32 count)
493 arraysize = mono_array_length(anyOf);
494 src = mono_string_chars(me);
496 for (pos = sindex; pos > sindex - count; pos--) {
497 for (loop = 0; loop != arraysize; loop++)
498 if ( src [pos] == mono_array_get(anyOf, gunichar2, loop) )
506 mono_string_InternalPad (MonoString *me, gint32 width, gunichar2 chr, MonoBoolean right)
515 srclen = mono_string_length(me);
516 src = mono_string_chars(me);
518 ret = mono_string_InternalAllocateStr(width);
519 dest = mono_string_chars(ret);
520 fillcount = width - srclen;
523 memcpy(dest, src, srclen * sizeof(gunichar2));
524 for (i = srclen; i != width; i++)
531 for (i = 0; i != fillcount; i++)
534 memcpy(dest + fillcount, src, srclen * sizeof(gunichar2));
540 mono_string_InternalToLower (MonoString *me)
547 ret = mono_string_new_size(mono_domain_get (), mono_string_length(me));
549 src = mono_string_chars (me);
550 dest = mono_string_chars (ret);
552 for (i = 0; i < mono_string_length (me); ++i)
553 dest[i] = g_unichar_tolower(src[i]);
559 mono_string_InternalToUpper (MonoString *me)
566 ret = mono_string_new_size(mono_domain_get (), mono_string_length(me));
568 src = mono_string_chars (me);
569 dest = mono_string_chars (ret);
571 for (i = 0; i < mono_string_length (me); ++i)
572 dest[i] = g_unichar_toupper(src[i]);
578 mono_string_InternalAllocateStr(gint32 length)
580 return mono_string_new_size(mono_domain_get (), length);
584 mono_string_InternalStrcpyStr (MonoString *dest, gint32 destPos, MonoString *src)
589 srcptr = mono_string_chars (src);
590 destptr = mono_string_chars (dest);
592 memcpy(destptr + destPos, srcptr, mono_string_length(src) * sizeof(gunichar2));
596 mono_string_InternalStrcpyStrN (MonoString *dest, gint32 destPos, MonoString *src, gint32 startPos, gint32 count)
601 srcptr = mono_string_chars (src);
602 destptr = mono_string_chars (dest);
603 memcpy(destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
607 mono_string_InternalIntern (MonoString *str)
609 return mono_string_intern(str);
613 mono_string_InternalIsInterned (MonoString *str)
615 return mono_string_is_interned(str);
619 mono_string_InternalCompareStrN (MonoString *s1, gint32 i1, MonoString *s2, gint32 i2, gint32 length, MonoBoolean inCase)
621 /* c translation of C# code.. :)
637 lenstr1 = mono_string_length(s1);
638 lenstr2 = mono_string_length(s2);
640 str1 = mono_string_chars(s1);
641 str2 = mono_string_chars(s2);
645 for (pos = 0; pos != length; pos++) {
646 if (i1 + pos >= lenstr1 || i2 + pos >= lenstr2)
649 charcmp = mono_string_cmp_char(str1[i1 + pos], str2[i2 + pos], mode);
654 /* the lesser wins, so if we have looped until length we just need to check the last char */
656 return mono_string_cmp_char(str1[i1 + pos - 1], str2[i2 + pos - 1], mode);
659 /* Test if one the strings has been compared to the end */
660 if (i1 + pos >= lenstr1) {
661 if (i2 + pos >= lenstr2)
665 } else if (i2 + pos >= lenstr2)
668 /* if not, check our last char only.. (can this happen?) */
669 return mono_string_cmp_char(str1[i1 + pos], str2[i2 + pos], mode);
673 mono_string_GetHashCode (MonoString *me)
676 gunichar2 *data = mono_string_chars (me);
678 for (i = 0; i < mono_string_length (me); ++i)
679 h = (h << 5) - h + data [i];
685 mono_string_get_Chars (MonoString *me, gint32 idx)
687 return mono_string_chars(me)[idx];
690 /* @mode : 0 = StringCompareModeDirect
691 1 = StringCompareModeCaseInsensitive
692 2 = StringCompareModeOrdinal
695 mono_string_cmp_char (gunichar2 c1, gunichar2 c2, gint16 mode)
698 GUnicodeType c1type, c2type;
700 c1type = g_unichar_type (c1);
701 c2type = g_unichar_type (c2);
704 /* TODO: compare with culture info */
705 if (c1type == G_UNICODE_UPPERCASE_LETTER && c2type == G_UNICODE_LOWERCASE_LETTER)
708 if (c1type == G_UNICODE_LOWERCASE_LETTER && c2type == G_UNICODE_UPPERCASE_LETTER)
711 result = (gint32) c1 - c2;
714 result = (gint32) (c1type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c1) : c1) -
715 (c2type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c2) : c2);
717 /* fix: compare ordinal */
719 result = (gint32) g_unichar_tolower(c1) - g_unichar_tolower(c2);
723 return ((result < 0) ? -1 : (result > 0) ? 1 : 0);