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