d86231f0dd8ec88cfe91617fb2775557a6b2413d
[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         gint32 length;
216         gint32 pos;
217         gint32 insertlen;
218         gint32 destpos;
219         gint32 srclen;
220         gunichar2 *insert;
221         gunichar2 *dest;
222         gunichar2 *src;
223
224         MONO_ARCH_SAVE_REGS;
225
226         insert = mono_string_chars(separator);
227         insertlen = mono_string_length(separator);
228
229         length = 0;
230         for (pos = sindex; pos != sindex + count; pos++) {
231                 length += mono_string_length(mono_array_get(value, MonoString *, pos));
232                 if (pos < sindex + count - 1)
233                         length += insertlen;
234         }
235
236         ret = mono_string_new_size( mono_domain_get (), length);
237         dest = mono_string_chars(ret);
238         destpos = 0;
239
240         for (pos = sindex; pos != sindex + count; pos++) {
241                 src = mono_string_chars(mono_array_get(value, MonoString *, pos));
242                 srclen = mono_string_length(mono_array_get(value, MonoString *, pos));
243
244                 memcpy(dest + destpos, src, srclen * sizeof(gunichar2));
245                 destpos += srclen;
246
247                 if (pos < sindex + count - 1) {
248                         memcpy(dest + destpos, insert, insertlen * sizeof(gunichar2));
249                         destpos += insertlen;
250                 }
251         }
252
253         return ret;
254 }
255
256 MonoString * 
257 ves_icall_System_String_InternalInsert (MonoString *me, gint32 sindex, MonoString *value)
258 {
259         MonoString * ret;
260         gunichar2 *src;
261         gunichar2 *insertsrc;
262         gunichar2 *dest;
263         gint32 srclen;
264         gint32 insertlen;
265
266         MONO_ARCH_SAVE_REGS;
267
268         src = mono_string_chars(me);
269         srclen = mono_string_length(me);
270
271         insertsrc = mono_string_chars(value);
272         insertlen = mono_string_length(value);
273
274         ret = mono_string_new_size( mono_domain_get (), srclen + insertlen);
275         dest = mono_string_chars(ret);
276
277         memcpy(dest, src, sindex * sizeof(gunichar2));
278         memcpy(dest + sindex, insertsrc, insertlen * sizeof(gunichar2));
279         memcpy(dest + sindex + insertlen, src + sindex, (srclen - sindex) * sizeof(gunichar2));
280
281         return ret;
282 }
283
284 MonoString * 
285 ves_icall_System_String_InternalReplace_Char (MonoString *me, gunichar2 oldChar, gunichar2 newChar)
286 {
287         MonoString *ret;
288         gunichar2 *src;
289         gunichar2 *dest;
290         gint32 i, srclen;
291
292         MONO_ARCH_SAVE_REGS;
293
294         src = mono_string_chars(me);
295         srclen = mono_string_length(me);
296
297         ret = mono_string_new_size( mono_domain_get (), srclen);
298         dest = mono_string_chars(ret);
299
300         for (i = 0; i != srclen; i++) {
301                 if (src[i] == oldChar)
302                         dest[i] = newChar;
303                 else
304                         dest[i] = src[i];
305         }
306
307         return ret;
308 }
309
310 MonoString * 
311 ves_icall_System_String_InternalReplace_Str (MonoString *me, MonoString *oldValue, MonoString *newValue)
312 {
313         MonoString *ret;
314         gunichar2 *src;
315         gunichar2 *dest;
316         gunichar2 *oldstr;
317         gunichar2 *newstr;
318         gint32 i, destpos;
319         gint32 occurr;
320         gint32 newsize;
321         gint32 oldstrlen;
322         gint32 newstrlen;
323         gint32 srclen;
324
325         MONO_ARCH_SAVE_REGS;
326
327         occurr = 0;
328         destpos = 0;
329
330         oldstr = mono_string_chars(oldValue);
331         oldstrlen = mono_string_length(oldValue);
332
333         if (NULL != newValue) {
334                 newstr = mono_string_chars(newValue);
335                 newstrlen = mono_string_length(newValue);
336         } else
337                 newstrlen = 0;
338
339         src = mono_string_chars(me);
340         srclen = mono_string_length(me);
341
342         if (oldstrlen != newstrlen) {
343                 for (i = 0; i <= srclen - oldstrlen; i++)
344                         if (0 == memcmp(src + i, oldstr, oldstrlen * sizeof(gunichar2)))
345                                 occurr++;
346                 if (occurr == 0)
347                         return me;
348                 newsize = srclen + ((newstrlen - oldstrlen) * occurr);
349         } else
350                 newsize = srclen;
351
352         ret = NULL;
353         i = 0;
354         while (i < srclen) {
355                 if (0 == memcmp(src + i, oldstr, oldstrlen * sizeof(gunichar2))) {
356                         if (ret == NULL) {
357                                 ret = mono_string_new_size( mono_domain_get (), newsize);
358                                 dest = mono_string_chars(ret);
359                                 memcpy (dest, src, i * sizeof(gunichar2));
360                         }
361                         if (newstrlen > 0) {
362                                 memcpy(dest + destpos, newstr, newstrlen * sizeof(gunichar2));
363                                 destpos += newstrlen;
364                         }
365                         i += oldstrlen;
366                         continue;
367                 } else if (ret != NULL) {
368                         dest[destpos] = src[i];
369                 }
370                         destpos++;
371                         i++;
372                 }
373         
374         if (ret == NULL)
375                 return me;
376
377         return ret;
378 }
379
380 MonoString * 
381 ves_icall_System_String_InternalRemove (MonoString *me, gint32 sindex, gint32 count)
382 {
383         MonoString * ret;
384         gint32 srclen;
385         gunichar2 *dest;
386         gunichar2 *src;
387
388         MONO_ARCH_SAVE_REGS;
389
390         srclen = mono_string_length(me);
391         ret = mono_string_new_size( mono_domain_get (), srclen - count);
392
393         src = mono_string_chars(me);
394         dest = mono_string_chars(ret);
395
396         memcpy(dest, src, sindex * sizeof(gunichar2));
397         memcpy(dest + sindex, src + sindex + count, (srclen - count - sindex) * sizeof(gunichar2));
398
399         return ret;
400 }
401
402 void
403 ves_icall_System_String_InternalCopyTo (MonoString *me, gint32 sindex, MonoArray *dest, gint32 dindex, gint32 count)
404 {
405         gunichar2 *destptr = (gunichar2 *) mono_array_addr(dest, gunichar2, dindex);
406         gunichar2 *src =  mono_string_chars(me);
407
408         MONO_ARCH_SAVE_REGS;
409
410         memcpy(destptr, src + sindex, sizeof(gunichar2) * count);
411 }
412
413 MonoArray * 
414 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count)
415 {
416         MonoString * tmpstr;
417         MonoArray * retarr;
418         gunichar2 *src;
419         gint32 arrsize, srcsize, splitsize;
420         gint32 i, lastpos, arrpos;
421         gint32 tmpstrsize;
422         gunichar2 *tmpstrptr;
423
424         gunichar2 cmpchar;
425
426         MONO_ARCH_SAVE_REGS;
427
428         src = mono_string_chars(me);
429         srcsize = mono_string_length(me);
430         arrsize = mono_array_length(separator);
431
432         cmpchar = mono_array_get(separator, gunichar2, 0);
433
434         splitsize = 0;
435         for (i = 0; i != srcsize && splitsize < count; i++) {
436                 if (string_icall_is_in_array(separator, arrsize, src[i]))
437                         splitsize++;
438         }
439
440         lastpos = 0;
441         arrpos = 0;
442
443         /* if no split chars found return the string */
444         if (splitsize == 0) {
445                 retarr = mono_array_new(mono_domain_get(), mono_defaults.string_class, 1);
446                 tmpstr = mono_string_new_size( mono_domain_get (), srcsize);
447                 tmpstrptr = mono_string_chars(tmpstr);
448
449                 memcpy(tmpstrptr, src, srcsize * sizeof(gunichar2));
450                 mono_array_set(retarr, MonoString *, 0, tmpstr);
451
452                 return retarr;
453         }
454
455         if (splitsize != count)
456                 splitsize++;
457
458         retarr = mono_array_new(mono_domain_get(), mono_defaults.string_class, splitsize);
459         for (i = 0; i != srcsize && arrpos != count; i++) {
460                 if (string_icall_is_in_array(separator, arrsize, src[i])) {
461                         if (arrpos == count - 1)
462                                 tmpstrsize = srcsize - lastpos;
463                         else
464                                 tmpstrsize = i - lastpos;
465
466                         tmpstr = mono_string_new_size( mono_domain_get (), tmpstrsize);
467                         tmpstrptr = mono_string_chars(tmpstr);
468
469                         memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
470                         mono_array_set(retarr, MonoString *, arrpos, tmpstr);
471                         arrpos++;
472                         lastpos = i + 1;
473                 }
474         }
475
476         if (arrpos < count) {
477                 tmpstrsize = srcsize - lastpos;
478                 tmpstr = mono_string_new_size( mono_domain_get (), tmpstrsize);
479                 tmpstrptr = mono_string_chars(tmpstr);
480
481                 memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
482                 mono_array_set(retarr, MonoString *, arrpos, tmpstr);
483         }
484
485         return retarr;
486 }
487
488 static gboolean
489 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
490 {
491         gunichar2 cmpchar;
492         gint32 arrpos;
493
494         for (arrpos = 0; arrpos != arraylength; arrpos++) {
495                 cmpchar = mono_array_get(chars, gunichar2, arrpos);
496                 if (cmpchar == chr)
497                         return TRUE;
498         }
499         
500         return FALSE;
501 }
502
503 MonoString * 
504 ves_icall_System_String_InternalTrim (MonoString *me, MonoArray *chars, gint32 typ)
505 {
506         MonoString * ret;
507         gunichar2 *src, *dest;
508         gint32 srclen, newlen, arrlen;
509         gint32 i, lenfirst, lenlast;
510
511         MONO_ARCH_SAVE_REGS;
512
513         srclen = mono_string_length(me);
514         src = mono_string_chars(me);
515         arrlen = mono_array_length(chars);
516
517         lenfirst = 0;
518         lenlast = 0;
519
520         if (0 == typ || 1 == typ) {
521                 for (i = 0; i != srclen; i++) {
522                         if (string_icall_is_in_array(chars, arrlen, src[i]))
523                                 lenfirst++;
524                         else 
525                                 break;
526                 }
527         }
528
529         if (0 == typ || 2 == typ) {
530                 for (i = srclen - 1; i > lenfirst - 1; i--) {
531                         if (string_icall_is_in_array(chars, arrlen, src[i]))
532                                 lenlast++;
533                         else 
534                                 break;
535                 }
536         }
537
538         newlen = srclen - lenfirst - lenlast;
539         if (newlen == srclen)
540                 return me;
541
542         ret = mono_string_new_size( mono_domain_get (), newlen);
543         dest = mono_string_chars(ret);
544
545         memcpy(dest, src + lenfirst, newlen *sizeof(gunichar2));
546
547         return ret;
548 }
549
550 gint32 
551 ves_icall_System_String_InternalIndexOf_Char (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
552 {
553         gint32 pos;
554         gunichar2 *src;
555
556         MONO_ARCH_SAVE_REGS;
557
558         src = mono_string_chars(me);
559         for (pos = sindex; pos != count + sindex; pos++) {
560                 if ( src [pos] == value)
561                         return pos;
562         }
563
564         return -1;
565 }
566
567 gint32 
568 ves_icall_System_String_InternalIndexOf_Str (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
569 {
570         gint32 lencmpstr;
571         gint32 pos, i;
572         gunichar2 *src;
573         gunichar2 *cmpstr;
574
575         MONO_ARCH_SAVE_REGS;
576
577         lencmpstr = mono_string_length(value);
578
579         src = mono_string_chars(me);
580         cmpstr = mono_string_chars(value);
581
582         count -= lencmpstr;
583         for (pos = sindex; pos <= sindex + count; pos++) {
584                 for (i = 0; src [pos + i] == cmpstr [i];) {
585                         if (++i == lencmpstr)
586                                 return pos;
587                 }
588         }
589
590         return -1;
591 }
592
593 gint32 
594 ves_icall_System_String_InternalIndexOfAny (MonoString *me, MonoArray *arr, gint32 sindex, gint32 count)
595 {
596         gint32 pos;
597         gint32 loop;
598         gint32 arraysize;
599         gunichar2 *src;
600
601         MONO_ARCH_SAVE_REGS;
602
603         arraysize = mono_array_length(arr);
604         src = mono_string_chars(me);
605
606         for (pos = sindex; pos != count + sindex; pos++) {
607                 for (loop = 0; loop != arraysize; loop++)
608                         if ( src [pos] == mono_array_get(arr, gunichar2, loop) )
609                                 return pos;
610         }
611
612         return -1;
613 }
614
615 gint32 
616 ves_icall_System_String_InternalLastIndexOf_Char (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
617 {
618         gint32 pos;
619         gunichar2 *src;
620
621         MONO_ARCH_SAVE_REGS;
622
623         src = mono_string_chars(me);
624         for (pos = sindex; pos > sindex - count; pos--) {
625                 if (src [pos] == value)
626                         return pos;
627         }
628
629         return -1;
630 }
631
632 gint32 
633 ves_icall_System_String_InternalLastIndexOf_Str (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
634 {
635         gint32 lencmpstr;
636         gint32 pos;
637         gunichar2 *src;
638         gunichar2 *cmpstr;
639
640         MONO_ARCH_SAVE_REGS;
641
642         lencmpstr = mono_string_length(value);
643
644         src = mono_string_chars(me);
645         cmpstr = mono_string_chars(value);
646
647         for (pos = sindex - lencmpstr + 1; pos > sindex - count; pos--) {
648                 if (0 == memcmp(src + pos, cmpstr, lencmpstr * sizeof(gunichar2)))
649                         return pos;
650         }
651
652         return -1;
653 }
654
655 gint32 
656 ves_icall_System_String_InternalLastIndexOfAny (MonoString *me, MonoArray *anyOf, gint32 sindex, gint32 count)
657 {
658         gint32 pos;
659         gint32 loop;
660         gint32 arraysize;
661         gunichar2 *src;
662
663         MONO_ARCH_SAVE_REGS;
664
665         arraysize = mono_array_length(anyOf);
666         src = mono_string_chars(me);
667
668         for (pos = sindex; pos > sindex - count; pos--) {
669                 for (loop = 0; loop != arraysize; loop++)
670                         if ( src [pos] == mono_array_get(anyOf, gunichar2, loop) )
671                                 return pos;
672         }
673
674         return -1;
675 }
676
677 MonoString *
678 ves_icall_System_String_InternalPad (MonoString *me, gint32 width, gunichar2 chr, MonoBoolean right)
679 {
680         MonoString * ret;
681         gunichar2 *src;
682         gunichar2 *dest;
683         gint32 fillcount;
684         gint32 srclen;
685         gint32 i;
686
687         MONO_ARCH_SAVE_REGS;
688
689         srclen = mono_string_length(me);
690         src = mono_string_chars(me);
691
692         ret = mono_string_new_size( mono_domain_get (), width);
693         dest = mono_string_chars(ret);
694         fillcount = width - srclen;
695
696         if (right) {
697                 memcpy(dest, src, srclen * sizeof(gunichar2));
698                 for (i = srclen; i != width; i++)
699                         dest[i] = chr;
700
701                 return ret;
702         }
703
704         /* left fill */
705         for (i = 0; i != fillcount; i++)
706                 dest[i] = chr;
707
708         memcpy(dest + fillcount, src, srclen * sizeof(gunichar2));
709
710         return ret;
711 }
712
713 MonoString *
714 ves_icall_System_String_InternalToLower (MonoString *me)
715 {
716         MonoString * ret;
717         gunichar2 *src; 
718         gunichar2 *dest;
719         gint32 i;
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_tolower(src[i]);
730
731         return ret;
732 }
733
734 MonoString *
735 ves_icall_System_String_InternalToUpper (MonoString *me)
736 {
737         int i;
738         MonoString * ret;
739         gunichar2 *src; 
740         gunichar2 *dest;
741
742         MONO_ARCH_SAVE_REGS;
743
744         ret = mono_string_new_size(mono_domain_get (), mono_string_length(me));
745
746         src = mono_string_chars (me);
747         dest = mono_string_chars (ret);
748
749         for (i = 0; i < mono_string_length (me); ++i)
750                 dest[i] = g_unichar_toupper(src[i]);
751
752         return ret;
753 }
754
755 MonoString *
756 ves_icall_System_String_InternalAllocateStr (gint32 length)
757 {
758         MONO_ARCH_SAVE_REGS;
759
760         return mono_string_new_size(mono_domain_get (), length);
761 }
762
763 void 
764 ves_icall_System_String_InternalStrcpy_Str (MonoString *dest, gint32 destPos, MonoString *src)
765 {
766         gunichar2 *srcptr;
767         gunichar2 *destptr;
768
769         MONO_ARCH_SAVE_REGS;
770
771         srcptr = mono_string_chars (src);
772         destptr = mono_string_chars (dest);
773
774         memcpy(destptr + destPos, srcptr, mono_string_length(src) * sizeof(gunichar2));
775 }
776
777 void 
778 ves_icall_System_String_InternalStrcpy_StrN (MonoString *dest, gint32 destPos, MonoString *src, gint32 startPos, gint32 count)
779 {
780         gunichar2 *srcptr;
781         gunichar2 *destptr;
782
783         MONO_ARCH_SAVE_REGS;
784
785         srcptr = mono_string_chars (src);
786         destptr = mono_string_chars (dest);
787         memcpy(destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
788 }
789
790 MonoString  *
791 ves_icall_System_String_InternalIntern (MonoString *str)
792 {
793         MONO_ARCH_SAVE_REGS;
794
795         return mono_string_intern(str);
796 }
797
798 MonoString * 
799 ves_icall_System_String_InternalIsInterned (MonoString *str)
800 {
801         MONO_ARCH_SAVE_REGS;
802
803         return mono_string_is_interned(str);
804 }
805
806 gint32
807 ves_icall_System_String_InternalCompareStr_N (MonoString *s1, gint32 i1, MonoString *s2, gint32 i2, gint32 length, gint32 mode)
808 {
809         /* c translation of C# code from old string.cs.. :) */
810         gint32 lenstr1;
811         gint32 lenstr2;
812         gint32 charcmp;
813         gunichar2 *str1;
814         gunichar2 *str2;
815
816         gint32 pos;
817         
818         MONO_ARCH_SAVE_REGS;
819
820         lenstr1 = mono_string_length(s1);
821         lenstr2 = mono_string_length(s2);
822
823         str1 = mono_string_chars(s1);
824         str2 = mono_string_chars(s2);
825
826         pos = 0;
827
828         for (pos = 0; pos != length; pos++) {
829                 if (i1 + pos >= lenstr1 || i2 + pos >= lenstr2)
830                         break;
831
832                 charcmp = string_icall_cmp_char(str1[i1 + pos], str2[i2 + pos], mode);
833                 if (charcmp != 0)
834                         return charcmp;
835         }
836
837         /* the lesser wins, so if we have looped until length we just need to check the last char */
838         if (pos == length) {
839                 return string_icall_cmp_char(str1[i1 + pos - 1], str2[i2 + pos - 1], mode);
840         }
841
842         /* Test if one the strings has been compared to the end */
843         if (i1 + pos >= lenstr1) {
844                 if (i2 + pos >= lenstr2)
845                         return 0;
846                 else
847                         return -1;
848         } else if (i2 + pos >= lenstr2)
849                 return 1;
850
851         /* if not, check our last char only.. (can this happen?) */
852         return string_icall_cmp_char(str1[i1 + pos], str2[i2 + pos], mode);
853 }
854
855 gint32
856 ves_icall_System_String_GetHashCode (MonoString *me)
857 {
858         int i, h = 0;
859         gunichar2 *data = mono_string_chars (me);
860
861         MONO_ARCH_SAVE_REGS;
862
863         for (i = 0; i < mono_string_length (me); ++i)
864                 h = (h << 5) - h + data [i];
865
866         return h;
867 }
868
869 gunichar2 
870 ves_icall_System_String_get_Chars (MonoString *me, gint32 idx)
871 {
872         MONO_ARCH_SAVE_REGS;
873
874         if ((idx < 0) || (idx >= mono_string_length (me)))
875                 mono_raise_exception (mono_get_exception_index_out_of_range ());
876         return mono_string_chars(me)[idx];
877 }
878
879 /*
880  * @mode:
881  * 0 = StringCompareModeDirect
882  * 1 = StringCompareModeCaseInsensitive
883  * 2 = StringCompareModeOrdinal
884  */
885 static gint32 
886 string_icall_cmp_char (gunichar2 c1, gunichar2 c2, gint32 mode)
887 {
888         gint32 result;
889         GUnicodeType c1type, c2type;
890
891         c1type = g_unichar_type (c1);
892         c2type = g_unichar_type (c2);
893
894         switch (mode) {
895         case 0: 
896                 /* TODO: compare with culture info */
897                 if (c1type == G_UNICODE_UPPERCASE_LETTER && c2type == G_UNICODE_LOWERCASE_LETTER)
898                         return 1;
899                                         
900                 if (c1type == G_UNICODE_LOWERCASE_LETTER && c2type == G_UNICODE_UPPERCASE_LETTER)
901                         return -1;
902         
903                 result = (gint32) c1 - c2;
904                 break;
905         case 1: 
906                 result = (gint32) (c1type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c1) : c1) - 
907                                   (c2type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c2) : c2);
908                 break;
909         case 2:
910                 // Rotor/ms return the full value just not -1 and 1
911                 return (gint32) c1 - c2; break;
912         }
913
914         return ((result < 0) ? -1 : (result > 0) ? 1 : 0);
915 }