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