Wed Dec 4 10:44:01 CET 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / string-icalls.c
1 /*
2  * string-icalls.c: String internal calls for the corlib
3  *
4  * Author:
5  *   Patrik Torstensson (patrik.torstensson@labs2.com)
6  *   Duncan Mak  (duncan@ximian.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  */
10 #include <config.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <mono/metadata/string-icalls.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/unicode.h>
21 #include <mono/metadata/exception.h>
22
23 /* Internal helper methods */
24
25 static gboolean
26 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr);
27
28 static gint32
29 string_icall_cmp_char (gunichar2 c1, gunichar2 c2, gint16 mode);
30
31 MonoString *
32 ves_icall_System_String_ctor_charp (gpointer dummy, gunichar2 *value)
33 {
34         gint32 i, length;
35         MonoDomain *domain;
36
37         MONO_ARCH_SAVE_REGS;
38
39         domain = mono_domain_get ();
40
41         if (value == NULL)
42                 length = 0;
43         else {
44                 for (i = 0; *(value + i) != '\0'; i++);
45                 length = i;
46         }
47
48         return mono_string_new_utf16 (domain, value, length);
49 }
50
51 MonoString *
52 ves_icall_System_String_ctor_char_int (gpointer dummy, gunichar2 value, gint32 count)
53 {
54         MonoDomain *domain;
55         MonoString *res;
56         gunichar2 *chars;
57         gint32 i;
58
59         MONO_ARCH_SAVE_REGS;
60
61         domain = mono_domain_get ();
62         res = mono_string_new_size (domain, count);
63
64         chars = mono_string_chars (res);
65         for (i = 0; i < count; i++)
66                 chars [i] = value;
67         
68         return res;
69 }
70
71 MonoString *
72 ves_icall_System_String_ctor_charp_int_int (gpointer dummy, gunichar2 *value, gint32 sindex, gint32 length)
73 {
74         gunichar2 *begin;
75         MonoDomain * domain;
76         
77         MONO_ARCH_SAVE_REGS;
78
79         domain = mono_domain_get ();
80
81         if ((value == NULL) && (length != 0))
82                 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
83
84         if ((sindex < 0) || (length < 0))
85                 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
86         
87         if (length == 0) {      /* fixme: return String.Empty here */
88                 g_warning ("string doesn't yet support empy strings in char* constructor");
89                 g_assert_not_reached ();
90         }
91         
92         begin = (gunichar2 *) (value + sindex);
93
94         return mono_string_new_utf16 (domain, begin, length);
95 }
96
97 MonoString *
98 ves_icall_System_String_ctor_sbytep (gpointer dummy, gint8 *value)
99 {
100         MonoDomain *domain;
101         
102         MONO_ARCH_SAVE_REGS;
103
104         domain = mono_domain_get ();
105
106         if (NULL == value) {    /* fixme: return String.Empty here */
107                 g_warning ("string doesn't yet support empy strings in char* constructor");
108                 g_assert_not_reached ();
109         }
110
111         return mono_string_new (domain, (const char *) value);
112 }
113
114 MonoString *
115 ves_icall_System_String_ctor_sbytep_int_int (gpointer dummy, gint8 *value, gint32 sindex, gint32 length)
116 {
117         guchar *begin;
118         MonoDomain *domain;
119         MonoString *res;
120         gunichar2 *chars;
121         int i;
122         
123         MONO_ARCH_SAVE_REGS;
124
125         domain = mono_domain_get ();
126
127         if ((value == NULL) && (length != 0))
128                 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
129
130         if ((sindex < 0) || (length < 0))
131                 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
132
133         begin = (guchar *) (value + sindex);
134         res = mono_string_new_size (domain, length);
135         chars = mono_string_chars (res);
136         for (i = 0; i < length; ++i)
137                 chars [i] = begin [i];
138
139         return res;
140 }
141
142 MonoString *
143 ves_icall_System_String_ctor_chara (gpointer dummy, MonoArray *value)
144 {
145         MonoDomain *domain;
146
147         MONO_ARCH_SAVE_REGS;
148
149         MONO_CHECK_ARG_NULL (value);
150         
151         domain = mono_domain_get ();
152         
153         return mono_string_new_utf16 (domain, (gunichar2 *) mono_array_addr(value, gunichar2, 0),  value->max_length);
154 }
155
156 MonoString *
157 ves_icall_System_String_ctor_chara_int_int (gpointer dummy, MonoArray *value, 
158                                          gint32 sindex, gint32 length)
159 {
160         MonoDomain *domain;
161
162         MONO_ARCH_SAVE_REGS;
163
164         MONO_CHECK_ARG_NULL (value);
165
166         domain = mono_domain_get ();
167         
168         return mono_string_new_utf16 (domain, (gunichar2 *) mono_array_addr(value, gunichar2, sindex), length);
169 }
170
171 MonoString *
172 ves_icall_System_String_ctor_encoding (gpointer dummy, gint8 *value, gint32 sindex, 
173                                     gint32 length, MonoObject *enc)
174 {
175         MONO_ARCH_SAVE_REGS;
176
177         g_warning("string.ctor with encoding obj unimplemented");
178         g_assert_not_reached ();
179         return NULL;
180 }
181
182 MonoBoolean 
183 ves_icall_System_String_InternalEquals (MonoString *str1, MonoString *str2)
184 {
185         gunichar2 *str1ptr;
186         gunichar2 *str2ptr;
187         gint32 str1len;
188
189         MONO_ARCH_SAVE_REGS;
190
191         /* Length checking is done in C# */
192         str1len = mono_string_length(str1);
193
194         str1ptr = mono_string_chars(str1);
195         str2ptr = mono_string_chars(str2);
196
197         return (0 == memcmp(str1ptr, str2ptr, str1len * sizeof(gunichar2)));
198 }
199
200 MonoString * 
201 ves_icall_System_String_InternalJoin (MonoString *separator, MonoArray * value, gint32 sindex, gint32 count)
202 {
203         MonoString * ret;
204         gint32 length;
205         gint32 pos;
206         gint32 insertlen;
207         gint32 destpos;
208         gint32 srclen;
209         gunichar2 *insert;
210         gunichar2 *dest;
211         gunichar2 *src;
212
213         MONO_ARCH_SAVE_REGS;
214
215         insert = mono_string_chars(separator);
216         insertlen = mono_string_length(separator);
217
218         length = 0;
219         for (pos = sindex; pos != sindex + count; pos++) {
220                 length += mono_string_length(mono_array_get(value, MonoString *, pos));
221                 if (pos < sindex + count - 1)
222                         length += insertlen;
223         }
224
225         ret = mono_string_new_size( mono_domain_get (), length);
226         dest = mono_string_chars(ret);
227         destpos = 0;
228
229         for (pos = sindex; pos != sindex + count; pos++) {
230                 src = mono_string_chars(mono_array_get(value, MonoString *, pos));
231                 srclen = mono_string_length(mono_array_get(value, MonoString *, pos));
232
233                 memcpy(dest + destpos, src, srclen * sizeof(gunichar2));
234                 destpos += srclen;
235
236                 if (pos < sindex + count - 1) {
237                         memcpy(dest + destpos, insert, insertlen * sizeof(gunichar2));
238                         destpos += insertlen;
239                 }
240         }
241
242         return ret;
243 }
244
245 MonoString * 
246 ves_icall_System_String_InternalInsert (MonoString *me, gint32 sindex, MonoString *value)
247 {
248         MonoString * ret;
249         gunichar2 *src;
250         gunichar2 *insertsrc;
251         gunichar2 *dest;
252         gint32 srclen;
253         gint32 insertlen;
254
255         MONO_ARCH_SAVE_REGS;
256
257         src = mono_string_chars(me);
258         srclen = mono_string_length(me);
259
260         insertsrc = mono_string_chars(value);
261         insertlen = mono_string_length(value);
262
263         ret = mono_string_new_size( mono_domain_get (), srclen + insertlen);
264         dest = mono_string_chars(ret);
265
266         memcpy(dest, src, sindex * sizeof(gunichar2));
267         memcpy(dest + sindex, insertsrc, insertlen * sizeof(gunichar2));
268         memcpy(dest + sindex + insertlen, src + sindex, (srclen - sindex) * sizeof(gunichar2));
269
270         return ret;
271 }
272
273 MonoString * 
274 ves_icall_System_String_InternalReplace_Char (MonoString *me, gunichar2 oldChar, gunichar2 newChar)
275 {
276         MonoString *ret;
277         gunichar2 *src;
278         gunichar2 *dest;
279         gint32 i, srclen;
280
281         MONO_ARCH_SAVE_REGS;
282
283         src = mono_string_chars(me);
284         srclen = mono_string_length(me);
285
286         ret = mono_string_new_size( mono_domain_get (), srclen);
287         dest = mono_string_chars(ret);
288
289         for (i = 0; i != srclen; i++) {
290                 if (src[i] == oldChar)
291                         dest[i] = newChar;
292                 else
293                         dest[i] = src[i];
294         }
295
296         return ret;
297 }
298
299 MonoString * 
300 ves_icall_System_String_InternalReplace_Str (MonoString *me, MonoString *oldValue, MonoString *newValue)
301 {
302         MonoString *ret;
303         gunichar2 *src;
304         gunichar2 *dest;
305         gunichar2 *oldstr;
306         gunichar2 *newstr;
307         gint32 i, destpos;
308         gint32 occurr;
309         gint32 newsize;
310         gint32 oldstrlen;
311         gint32 newstrlen;
312         gint32 srclen;
313
314         MONO_ARCH_SAVE_REGS;
315
316         occurr = 0;
317         destpos = 0;
318
319         oldstr = mono_string_chars(oldValue);
320         oldstrlen = mono_string_length(oldValue);
321
322         if (NULL != newValue) {
323                 newstr = mono_string_chars(newValue);
324                 newstrlen = mono_string_length(newValue);
325         } else
326                 newstrlen = 0;
327
328         src = mono_string_chars(me);
329         srclen = mono_string_length(me);
330
331         if (oldstrlen != newstrlen) {
332                 for (i = 0; i <= srclen - oldstrlen; i++)
333                         if (0 == memcmp(src + i, oldstr, oldstrlen * sizeof(gunichar2)))
334                                 occurr++;
335
336                 newsize = srclen + ((newstrlen - oldstrlen) * occurr);
337         } else
338                 newsize = srclen;
339
340         ret = mono_string_new_size( mono_domain_get (), newsize);
341         dest = mono_string_chars(ret);
342
343         i = 0;
344         while (i < srclen) {
345                 if (0 == memcmp(src + i, oldstr, oldstrlen * sizeof(gunichar2))) {
346                         if (newstrlen > 0) {
347                                 memcpy(dest + destpos, newstr, newstrlen * sizeof(gunichar2));
348                                 destpos += newstrlen;
349                         }
350                         i += oldstrlen;
351                 } else {
352                         dest[destpos] = src[i];
353                         destpos++;
354                         i++;
355                 }
356         }
357
358         return ret;
359 }
360
361 MonoString * 
362 ves_icall_System_String_InternalRemove (MonoString *me, gint32 sindex, gint32 count)
363 {
364         MonoString * ret;
365         gint32 srclen;
366         gunichar2 *dest;
367         gunichar2 *src;
368
369         MONO_ARCH_SAVE_REGS;
370
371         srclen = mono_string_length(me);
372         ret = mono_string_new_size( mono_domain_get (), srclen - count);
373
374         src = mono_string_chars(me);
375         dest = mono_string_chars(ret);
376
377         memcpy(dest, src, sindex * sizeof(gunichar2));
378         memcpy(dest + sindex, src + sindex + count, (srclen - count - sindex) * sizeof(gunichar2));
379
380         return ret;
381 }
382
383 void
384 ves_icall_System_String_InternalCopyTo (MonoString *me, gint32 sindex, MonoArray *dest, gint32 dindex, gint32 count)
385 {
386         gunichar2 *destptr = (gunichar2 *) mono_array_addr(dest, gunichar2, dindex);
387         gunichar2 *src =  mono_string_chars(me);
388
389         MONO_ARCH_SAVE_REGS;
390
391         memcpy(destptr, src + sindex, sizeof(gunichar2) * count);
392 }
393
394 MonoArray * 
395 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count)
396 {
397         MonoString * tmpstr;
398         MonoArray * retarr;
399         gunichar2 *src;
400         gint32 arrsize, srcsize, splitsize;
401         gint32 i, lastpos, arrpos;
402         gint32 tmpstrsize;
403         gunichar2 *tmpstrptr;
404
405         gunichar2 cmpchar;
406
407         MONO_ARCH_SAVE_REGS;
408
409         src = mono_string_chars(me);
410         srcsize = mono_string_length(me);
411         arrsize = mono_array_length(separator);
412
413         cmpchar = mono_array_get(separator, gunichar2, 0);
414
415         splitsize = 0;
416         for (i = 0; i != srcsize && splitsize < count; i++) {
417                 if (string_icall_is_in_array(separator, arrsize, src[i]))
418                         splitsize++;
419         }
420
421         lastpos = 0;
422         arrpos = 0;
423
424         /* if no split chars found return the string */
425         if (splitsize == 0) {
426                 retarr = mono_array_new(mono_domain_get(), mono_defaults.string_class, 1);
427                 tmpstr = mono_string_new_size( mono_domain_get (), srcsize);
428                 tmpstrptr = mono_string_chars(tmpstr);
429
430                 memcpy(tmpstrptr, src, srcsize * sizeof(gunichar2));
431                 mono_array_set(retarr, MonoString *, 0, tmpstr);
432
433                 return retarr;
434         }
435
436         if (splitsize != count)
437                 splitsize++;
438
439         retarr = mono_array_new(mono_domain_get(), mono_defaults.string_class, splitsize);
440         for (i = 0; i != srcsize && arrpos != count; i++) {
441                 if (string_icall_is_in_array(separator, arrsize, src[i])) {
442                         if (arrpos == count - 1)
443                                 tmpstrsize = srcsize - lastpos;
444                         else
445                                 tmpstrsize = i - lastpos;
446
447                         tmpstr = mono_string_new_size( mono_domain_get (), tmpstrsize);
448                         tmpstrptr = mono_string_chars(tmpstr);
449
450                         memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
451                         mono_array_set(retarr, MonoString *, arrpos, tmpstr);
452                         arrpos++;
453                         lastpos = i + 1;
454                 }
455         }
456
457         if (arrpos < count) {
458                 tmpstrsize = srcsize - lastpos;
459                 tmpstr = mono_string_new_size( mono_domain_get (), tmpstrsize);
460                 tmpstrptr = mono_string_chars(tmpstr);
461
462                 memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
463                 mono_array_set(retarr, MonoString *, arrpos, tmpstr);
464         }
465
466         return retarr;
467 }
468
469 static gboolean
470 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
471 {
472         gunichar2 cmpchar;
473         gint32 arrpos;
474
475         for (arrpos = 0; arrpos != arraylength; arrpos++) {
476                 cmpchar = mono_array_get(chars, gunichar2, arrpos);
477                 if (cmpchar == chr)
478                         return TRUE;
479         }
480         
481         return FALSE;
482 }
483
484 MonoString * 
485 ves_icall_System_String_InternalTrim (MonoString *me, MonoArray *chars, gint32 typ)
486 {
487         MonoString * ret;
488         gunichar2 *src, *dest;
489         gint32 srclen, newlen, arrlen;
490         gint32 i, lenfirst, lenlast;
491
492         MONO_ARCH_SAVE_REGS;
493
494         srclen = mono_string_length(me);
495         src = mono_string_chars(me);
496         arrlen = mono_array_length(chars);
497
498         lenfirst = 0;
499         lenlast = 0;
500
501         if (0 == typ || 1 == typ) {
502                 for (i = 0; i != srclen; i++) {
503                         if (string_icall_is_in_array(chars, arrlen, src[i]))
504                                 lenfirst++;
505                         else 
506                                 break;
507                 }
508         }
509
510         if (0 == typ || 2 == typ) {
511                 for (i = srclen - 1; i > lenfirst - 1; i--) {
512                         if (string_icall_is_in_array(chars, arrlen, src[i]))
513                                 lenlast++;
514                         else 
515                                 break;
516                 }
517         }
518
519         newlen = srclen - lenfirst - lenlast;
520
521         ret = mono_string_new_size( mono_domain_get (), newlen);
522         dest = mono_string_chars(ret);
523
524         memcpy(dest, src + lenfirst, newlen *sizeof(gunichar2));
525
526         return ret;
527 }
528
529 gint32 
530 ves_icall_System_String_InternalIndexOf_Char (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
531 {
532         gint32 pos;
533         gunichar2 *src;
534
535         MONO_ARCH_SAVE_REGS;
536
537         src = mono_string_chars(me);
538         for (pos = sindex; pos != count + sindex; pos++) {
539                 if ( src [pos] == value)
540                         return pos;
541         }
542
543         return -1;
544 }
545
546 gint32 
547 ves_icall_System_String_InternalIndexOf_Str (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
548 {
549         gint32 lencmpstr;
550         gint32 pos, i;
551         gunichar2 *src;
552         gunichar2 *cmpstr;
553
554         MONO_ARCH_SAVE_REGS;
555
556         lencmpstr = mono_string_length(value);
557
558         src = mono_string_chars(me);
559         cmpstr = mono_string_chars(value);
560
561         count -= lencmpstr;
562         for (pos = sindex; pos <= sindex + count; pos++) {
563                 for (i = 0; src [pos + i] == cmpstr [i];) {
564                         if (++i == lencmpstr)
565                                 return pos;
566                 }
567         }
568
569         return -1;
570 }
571
572 gint32 
573 ves_icall_System_String_InternalIndexOfAny (MonoString *me, MonoArray *arr, gint32 sindex, gint32 count)
574 {
575         gint32 pos;
576         gint32 loop;
577         gint32 arraysize;
578         gunichar2 *src;
579
580         MONO_ARCH_SAVE_REGS;
581
582         arraysize = mono_array_length(arr);
583         src = mono_string_chars(me);
584
585         for (pos = sindex; pos != count + sindex; pos++) {
586                 for (loop = 0; loop != arraysize; loop++)
587                         if ( src [pos] == mono_array_get(arr, gunichar2, loop) )
588                                 return pos;
589         }
590
591         return -1;
592 }
593
594 gint32 
595 ves_icall_System_String_InternalLastIndexOf_Char (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
596 {
597         gint32 pos;
598         gunichar2 *src;
599
600         MONO_ARCH_SAVE_REGS;
601
602         src = mono_string_chars(me);
603         for (pos = sindex; pos > sindex - count; pos--) {
604                 if (src [pos] == value)
605                         return pos;
606         }
607
608         return -1;
609 }
610
611 gint32 
612 ves_icall_System_String_InternalLastIndexOf_Str (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
613 {
614         gint32 lencmpstr;
615         gint32 pos;
616         gunichar2 *src;
617         gunichar2 *cmpstr;
618
619         MONO_ARCH_SAVE_REGS;
620
621         lencmpstr = mono_string_length(value);
622
623         src = mono_string_chars(me);
624         cmpstr = mono_string_chars(value);
625
626         for (pos = sindex - lencmpstr + 1; pos > sindex - count; pos--) {
627                 if (0 == memcmp(src + pos, cmpstr, lencmpstr * sizeof(gunichar2)))
628                         return pos;
629         }
630
631         return -1;
632 }
633
634 gint32 
635 ves_icall_System_String_InternalLastIndexOfAny (MonoString *me, MonoArray *anyOf, gint32 sindex, gint32 count)
636 {
637         gint32 pos;
638         gint32 loop;
639         gint32 arraysize;
640         gunichar2 *src;
641
642         MONO_ARCH_SAVE_REGS;
643
644         arraysize = mono_array_length(anyOf);
645         src = mono_string_chars(me);
646
647         for (pos = sindex; pos > sindex - count; pos--) {
648                 for (loop = 0; loop != arraysize; loop++)
649                         if ( src [pos] == mono_array_get(anyOf, gunichar2, loop) )
650                                 return pos;
651         }
652
653         return -1;
654 }
655
656 MonoString *
657 ves_icall_System_String_InternalPad (MonoString *me, gint32 width, gunichar2 chr, MonoBoolean right)
658 {
659         MonoString * ret;
660         gunichar2 *src;
661         gunichar2 *dest;
662         gint32 fillcount;
663         gint32 srclen;
664         gint32 i;
665
666         MONO_ARCH_SAVE_REGS;
667
668         srclen = mono_string_length(me);
669         src = mono_string_chars(me);
670
671         ret = mono_string_new_size( mono_domain_get (), width);
672         dest = mono_string_chars(ret);
673         fillcount = width - srclen;
674
675         if (right) {
676                 memcpy(dest, src, srclen * sizeof(gunichar2));
677                 for (i = srclen; i != width; i++)
678                         dest[i] = chr;
679
680                 return ret;
681         }
682
683         /* left fill */
684         for (i = 0; i != fillcount; i++)
685                 dest[i] = chr;
686
687         memcpy(dest + fillcount, src, srclen * sizeof(gunichar2));
688
689         return ret;
690 }
691
692 MonoString *
693 ves_icall_System_String_InternalToLower (MonoString *me)
694 {
695         MonoString * ret;
696         gunichar2 *src; 
697         gunichar2 *dest;
698         gint32 i;
699
700         MONO_ARCH_SAVE_REGS;
701
702         ret = mono_string_new_size(mono_domain_get (), mono_string_length(me));
703
704         src = mono_string_chars (me);
705         dest = mono_string_chars (ret);
706
707         for (i = 0; i < mono_string_length (me); ++i)
708                 dest[i] = g_unichar_tolower(src[i]);
709
710         return ret;
711 }
712
713 MonoString *
714 ves_icall_System_String_InternalToUpper (MonoString *me)
715 {
716         int i;
717         MonoString * ret;
718         gunichar2 *src; 
719         gunichar2 *dest;
720
721         MONO_ARCH_SAVE_REGS;
722
723         ret = mono_string_new_size(mono_domain_get (), mono_string_length(me));
724
725         src = mono_string_chars (me);
726         dest = mono_string_chars (ret);
727
728         for (i = 0; i < mono_string_length (me); ++i)
729                 dest[i] = g_unichar_toupper(src[i]);
730
731         return ret;
732 }
733
734 MonoString *
735 ves_icall_System_String_InternalAllocateStr (gint32 length)
736 {
737         MONO_ARCH_SAVE_REGS;
738
739         return mono_string_new_size(mono_domain_get (), length);
740 }
741
742 void 
743 ves_icall_System_String_InternalStrcpy_Str (MonoString *dest, gint32 destPos, MonoString *src)
744 {
745         gunichar2 *srcptr;
746         gunichar2 *destptr;
747
748         MONO_ARCH_SAVE_REGS;
749
750         srcptr = mono_string_chars (src);
751         destptr = mono_string_chars (dest);
752
753         memcpy(destptr + destPos, srcptr, mono_string_length(src) * sizeof(gunichar2));
754 }
755
756 void 
757 ves_icall_System_String_InternalStrcpy_StrN (MonoString *dest, gint32 destPos, MonoString *src, gint32 startPos, gint32 count)
758 {
759         gunichar2 *srcptr;
760         gunichar2 *destptr;
761
762         MONO_ARCH_SAVE_REGS;
763
764         srcptr = mono_string_chars (src);
765         destptr = mono_string_chars (dest);
766         memcpy(destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
767 }
768
769 MonoString  *
770 ves_icall_System_String_InternalIntern (MonoString *str)
771 {
772         MONO_ARCH_SAVE_REGS;
773
774         return mono_string_intern(str);
775 }
776
777 MonoString * 
778 ves_icall_System_String_InternalIsInterned (MonoString *str)
779 {
780         MONO_ARCH_SAVE_REGS;
781
782         return mono_string_is_interned(str);
783 }
784
785 gint32
786 ves_icall_System_String_InternalCompareStr_N (MonoString *s1, gint32 i1, MonoString *s2, gint32 i2, gint32 length, MonoBoolean inCase)
787 {
788         /* c translation of C# code from old string.cs.. :) */
789         gint32 lenstr1;
790         gint32 lenstr2;
791         gint32 charcmp;
792         gunichar2 *str1;
793         gunichar2 *str2;
794
795         gint32 pos;
796         gint16 mode;
797         
798         MONO_ARCH_SAVE_REGS;
799
800         if (inCase)
801                 mode = 1;
802         else
803                 mode = 0;
804
805         lenstr1 = mono_string_length(s1);
806         lenstr2 = mono_string_length(s2);
807
808         str1 = mono_string_chars(s1);
809         str2 = mono_string_chars(s2);
810
811         pos = 0;
812
813         for (pos = 0; pos != length; pos++) {
814                 if (i1 + pos >= lenstr1 || i2 + pos >= lenstr2)
815                         break;
816
817                 charcmp = string_icall_cmp_char(str1[i1 + pos], str2[i2 + pos], mode);
818                 if (charcmp != 0)
819                         return charcmp;
820         }
821
822         /* the lesser wins, so if we have looped until length we just need to check the last char */
823         if (pos == length) {
824                 return string_icall_cmp_char(str1[i1 + pos - 1], str2[i2 + pos - 1], mode);
825         }
826
827         /* Test if one the strings has been compared to the end */
828         if (i1 + pos >= lenstr1) {
829                 if (i2 + pos >= lenstr2)
830                         return 0;
831                 else
832                         return -1;
833         } else if (i2 + pos >= lenstr2)
834                 return 1;
835
836         /* if not, check our last char only.. (can this happen?) */
837         return string_icall_cmp_char(str1[i1 + pos], str2[i2 + pos], mode);
838 }
839
840 gint32
841 ves_icall_System_String_GetHashCode (MonoString *me)
842 {
843         int i, h = 0;
844         gunichar2 *data = mono_string_chars (me);
845
846         MONO_ARCH_SAVE_REGS;
847
848         for (i = 0; i < mono_string_length (me); ++i)
849                 h = (h << 5) - h + data [i];
850
851         return h;
852 }
853
854 gunichar2 
855 ves_icall_System_String_get_Chars (MonoString *me, gint32 idx)
856 {
857         MONO_ARCH_SAVE_REGS;
858
859         return mono_string_chars(me)[idx];
860 }
861
862 /* @mode :      0 = StringCompareModeDirect
863                         1 = StringCompareModeCaseInsensitive
864                         2 = StringCompareModeOrdinal
865 */
866 static gint32 
867 string_icall_cmp_char (gunichar2 c1, gunichar2 c2, gint16 mode)
868 {
869         gint32 result;
870         GUnicodeType c1type, c2type;
871
872         c1type = g_unichar_type (c1);
873         c2type = g_unichar_type (c2);
874
875         switch (mode) {
876         case 0: 
877                 /* TODO: compare with culture info */
878                 if (c1type == G_UNICODE_UPPERCASE_LETTER && c2type == G_UNICODE_LOWERCASE_LETTER)
879                         return 1;
880                                         
881                 if (c1type == G_UNICODE_LOWERCASE_LETTER && c2type == G_UNICODE_UPPERCASE_LETTER)
882                         return -1;
883         
884                 result = (gint32) c1 - c2;
885                 break;
886         case 1: 
887                 result = (gint32) (c1type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c1) : c1) - 
888                                   (c2type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c2) : c2);
889                 break;
890         case 2:
891                 result = (gint32) c1 - c2;
892                 break;
893         }
894
895         return ((result < 0) ? -1 : (result > 0) ? 1 : 0);
896 }