Grasshopper project system now uses csproj extension
[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/class-internals.h>
17 #include <mono/metadata/appdomain.h>
18 #include <mono/metadata/tabledefs.h>
19 #include <mono/metadata/loader.h>
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/debug-helpers.h>
23
24 /* Internal helper methods */
25
26 static gboolean
27 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr);
28
29 static MonoString*
30 empty_string (MonoDomain *domain)
31 {
32         MonoVTable *vtable = mono_class_vtable (domain, mono_defaults.string_class);
33         MonoObject *o;
34         static MonoClassField *empty_field = NULL;
35
36         if (!empty_field) {
37                 MonoClassField *field;
38                 gpointer iter;
39
40                 iter = NULL;
41                 while ((field = mono_class_get_fields (mono_defaults.string_class, &iter))) {
42                         if (!strcmp (field->name, "Empty"))
43                                 break;
44                 }
45
46                 g_assert (field);
47                 empty_field = field;
48         }
49
50         mono_field_static_get_value (vtable, empty_field, &o);
51         g_assert (o);
52         return (MonoString*)o;
53 }
54
55 MonoString *
56 ves_icall_System_String_ctor_charp (gpointer dummy, gunichar2 *value)
57 {
58         gint32 i, length;
59         MonoDomain *domain;
60
61         MONO_ARCH_SAVE_REGS;
62
63         domain = mono_domain_get ();
64
65         if (value == NULL)
66                 return empty_string (domain);
67
68         for (i = 0; *(value + i) != '\0'; i++);
69         length = i;
70
71         return mono_string_new_utf16 (domain, value, length);
72 }
73
74 MonoString *
75 ves_icall_System_String_ctor_char_int (gpointer dummy, gunichar2 value, gint32 count)
76 {
77         MonoDomain *domain;
78         MonoString *res;
79         gunichar2 *chars;
80         gint32 i;
81
82         MONO_ARCH_SAVE_REGS;
83
84         if (count < 0)
85                 mono_raise_exception (mono_get_exception_argument_out_of_range ("count"));
86
87         domain = mono_domain_get ();
88         res = mono_string_new_size (domain, count);
89
90         chars = mono_string_chars (res);
91         for (i = 0; i < count; i++)
92                 chars [i] = value;
93         
94         return res;
95 }
96
97 MonoString *
98 ves_icall_System_String_ctor_charp_int_int (gpointer dummy, gunichar2 *value, gint32 sindex, gint32 length)
99 {
100         gunichar2 *begin;
101         MonoDomain * domain;
102         
103         MONO_ARCH_SAVE_REGS;
104
105         domain = mono_domain_get ();
106
107         if ((value == NULL) && (length != 0))
108                 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
109
110         if ((sindex < 0) || (length < 0))
111                 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
112         
113         if (length == 0)
114                 return empty_string (domain);
115         
116         begin = (gunichar2 *) (value + sindex);
117
118         return mono_string_new_utf16 (domain, begin, length);
119 }
120
121 MonoString *
122 ves_icall_System_String_ctor_sbytep (gpointer dummy, gint8 *value)
123 {
124         MonoDomain *domain;
125         
126         MONO_ARCH_SAVE_REGS;
127
128         domain = mono_domain_get ();
129
130         if (NULL == value)
131                 return empty_string (domain);
132
133         return mono_string_new (domain, (const char *) value);
134 }
135
136 MonoString *
137 ves_icall_System_String_ctor_sbytep_int_int (gpointer dummy, gint8 *value, gint32 sindex, gint32 length)
138 {
139         guchar *begin;
140         MonoDomain *domain;
141         MonoString *res;
142         gunichar2 *chars;
143         int i;
144         
145         MONO_ARCH_SAVE_REGS;
146
147         domain = mono_domain_get ();
148
149         if ((value == NULL) && (length != 0))
150                 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
151
152         if ((sindex < 0) || (length < 0))
153                 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
154
155         begin = (guchar *) (value + sindex);
156         res = mono_string_new_size (domain, length);
157         chars = mono_string_chars (res);
158         for (i = 0; i < length; ++i)
159                 chars [i] = begin [i];
160
161         return res;
162 }
163
164 MonoString *
165 ves_icall_System_String_ctor_chara (gpointer dummy, MonoArray *value)
166 {
167         MonoDomain *domain;
168
169         MONO_ARCH_SAVE_REGS;
170
171         domain = mono_domain_get ();
172
173         if (value == NULL)
174                 return mono_string_new_utf16 (domain, NULL, 0);
175         else
176                 return mono_string_new_utf16 (domain, (gunichar2 *) mono_array_addr(value, gunichar2, 0),  value->max_length);
177 }
178
179 MonoString *
180 ves_icall_System_String_ctor_chara_int_int (gpointer dummy, MonoArray *value, 
181                                          gint32 sindex, gint32 length)
182 {
183         MonoDomain *domain;
184
185         MONO_ARCH_SAVE_REGS;
186
187         if (value == NULL)
188                 mono_raise_exception (mono_get_exception_argument_null ("value"));
189         if (sindex < 0)
190                 mono_raise_exception (mono_get_exception_argument_out_of_range ("startIndex"));         
191         if (length < 0)
192                 mono_raise_exception (mono_get_exception_argument_out_of_range ("length"));
193         if (sindex + length > mono_array_length (value))
194                 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
195
196         domain = mono_domain_get ();
197         
198         return mono_string_new_utf16 (domain, (gunichar2 *) mono_array_addr(value, gunichar2, sindex), length);
199 }
200
201 MonoString *
202 ves_icall_System_String_ctor_encoding (gpointer dummy, gint8 *value, gint32 sindex, 
203                                        gint32 length, MonoObject *enc)
204 {
205         MonoArray *arr;
206         MonoString *s;
207         MonoObject *exc;
208         MonoDomain *domain = mono_domain_get ();
209         MonoMethod *get_string;
210         gpointer args [1];
211         MonoClass *klass;
212
213         MONO_ARCH_SAVE_REGS;
214
215         if ((value == NULL) || (length == 0))
216                 return mono_string_new_size (mono_domain_get (), 0);
217         if (enc == NULL)
218                 mono_raise_exception (mono_get_exception_argument_null ("enc"));
219         if (sindex < 0)
220                 mono_raise_exception (mono_get_exception_argument_out_of_range ("startIndex"));         
221         if (length < 0)
222                 mono_raise_exception (mono_get_exception_argument_out_of_range ("length"));
223
224         arr = mono_array_new (domain, mono_defaults.byte_class, length);
225         memcpy (mono_array_addr (arr, guint8, 0), value + sindex, length);
226
227         /* Find the System.Text.Encoding class */
228         for (klass = enc->vtable->klass; klass->parent->parent != NULL; klass = klass->parent)
229                 ;
230         
231         get_string = mono_class_get_method_from_name (klass, "GetString", 1);
232         args [0] = arr;
233         s = (MonoString*)mono_runtime_invoke (get_string, enc, args, &exc);
234         if (!s || exc)
235                 mono_raise_exception (mono_get_exception_argument ("", "Unable to decode the array into a valid string."));
236
237         return s;
238 }
239
240 /* This function is redirected to String.CreateString ()
241    by mono_marshal_get_native_wrapper () */
242 void
243 ves_icall_System_String_ctor_RedirectToCreateString (void)
244 {
245         g_assert_not_reached ();
246 }
247
248 MonoString * 
249 ves_icall_System_String_InternalJoin (MonoString *separator, MonoArray * value, gint32 sindex, gint32 count)
250 {
251         MonoString * ret;
252         MonoString *current;
253         gint32 length;
254         gint32 pos;
255         gint32 insertlen;
256         gint32 destpos;
257         gint32 srclen;
258         gunichar2 *insert;
259         gunichar2 *dest;
260         gunichar2 *src;
261
262         MONO_ARCH_SAVE_REGS;
263
264         insert = mono_string_chars(separator);
265         insertlen = mono_string_length(separator);
266
267         length = 0;
268         for (pos = sindex; pos != sindex + count; pos++) {
269                 current = mono_array_get (value, MonoString *, pos);
270                 if (current != NULL)
271                         length += mono_string_length (current);
272
273                 if (pos < sindex + count - 1)
274                         length += insertlen;
275         }
276
277         ret = mono_string_new_size( mono_domain_get (), length);
278         dest = mono_string_chars(ret);
279         destpos = 0;
280
281         for (pos = sindex; pos != sindex + count; pos++) {
282                 current = mono_array_get (value, MonoString *, pos);
283                 if (current != NULL) {
284                         src = mono_string_chars (current);
285                         srclen = mono_string_length (current);
286
287                         memcpy (dest + destpos, src, srclen * sizeof(gunichar2));
288                         destpos += srclen;
289                 }
290
291                 if (pos < sindex + count - 1) {
292                         memcpy(dest + destpos, insert, insertlen * sizeof(gunichar2));
293                         destpos += insertlen;
294                 }
295         }
296
297         return ret;
298 }
299
300 MonoString * 
301 ves_icall_System_String_InternalInsert (MonoString *me, gint32 sindex, MonoString *value)
302 {
303         MonoString * ret;
304         gunichar2 *src;
305         gunichar2 *insertsrc;
306         gunichar2 *dest;
307         gint32 srclen;
308         gint32 insertlen;
309
310         MONO_ARCH_SAVE_REGS;
311
312         src = mono_string_chars(me);
313         srclen = mono_string_length(me);
314
315         insertsrc = mono_string_chars(value);
316         insertlen = mono_string_length(value);
317
318         ret = mono_string_new_size( mono_domain_get (), srclen + insertlen);
319         dest = mono_string_chars(ret);
320
321         memcpy(dest, src, sindex * sizeof(gunichar2));
322         memcpy(dest + sindex, insertsrc, insertlen * sizeof(gunichar2));
323         memcpy(dest + sindex + insertlen, src + sindex, (srclen - sindex) * sizeof(gunichar2));
324
325         return ret;
326 }
327
328 MonoString * 
329 ves_icall_System_String_InternalReplace_Char (MonoString *me, gunichar2 oldChar, gunichar2 newChar)
330 {
331         MonoString *ret;
332         gunichar2 *src;
333         gunichar2 *dest;
334         gint32 i, srclen;
335
336         MONO_ARCH_SAVE_REGS;
337
338         src = mono_string_chars(me);
339         srclen = mono_string_length(me);
340
341         ret = mono_string_new_size( mono_domain_get (), srclen);
342         dest = mono_string_chars(ret);
343
344         for (i = 0; i != srclen; i++) {
345                 if (src[i] == oldChar)
346                         dest[i] = newChar;
347                 else
348                         dest[i] = src[i];
349         }
350
351         return ret;
352 }
353
354 MonoString * 
355 ves_icall_System_String_InternalRemove (MonoString *me, gint32 sindex, gint32 count)
356 {
357         MonoString * ret;
358         gint32 srclen;
359         gunichar2 *dest;
360         gunichar2 *src;
361
362         MONO_ARCH_SAVE_REGS;
363
364         srclen = mono_string_length(me);
365         ret = mono_string_new_size( mono_domain_get (), srclen - count);
366
367         src = mono_string_chars(me);
368         dest = mono_string_chars(ret);
369
370         memcpy(dest, src, sindex * sizeof(gunichar2));
371         memcpy(dest + sindex, src + sindex + count, (srclen - count - sindex) * sizeof(gunichar2));
372
373         return ret;
374 }
375
376 void
377 ves_icall_System_String_InternalCopyTo (MonoString *me, gint32 sindex, MonoArray *dest, gint32 dindex, gint32 count)
378 {
379         gunichar2 *destptr = (gunichar2 *) mono_array_addr(dest, gunichar2, dindex);
380         gunichar2 *src =  mono_string_chars(me);
381
382         MONO_ARCH_SAVE_REGS;
383
384         memcpy(destptr, src + sindex, sizeof(gunichar2) * count);
385 }
386
387 MonoArray * 
388 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count)
389 {
390         MonoString * tmpstr;
391         MonoArray * retarr;
392         gunichar2 *src;
393         gint32 arrsize, srcsize, splitsize;
394         gint32 i, lastpos, arrpos;
395         gint32 tmpstrsize;
396         gunichar2 *tmpstrptr;
397
398         gunichar2 cmpchar;
399
400         MONO_ARCH_SAVE_REGS;
401
402         src = mono_string_chars(me);
403         srcsize = mono_string_length(me);
404         arrsize = mono_array_length(separator);
405
406         cmpchar = mono_array_get(separator, gunichar2, 0);
407
408         splitsize = 0;
409         for (i = 0; i != srcsize && splitsize < count; i++) {
410                 if (string_icall_is_in_array(separator, arrsize, src[i]))
411                         splitsize++;
412         }
413
414         lastpos = 0;
415         arrpos = 0;
416
417         /* if no split chars found return the string */
418         if (splitsize == 0) {
419                 retarr = mono_array_new(mono_domain_get(), mono_get_string_class (), 1);
420                 mono_array_setref (retarr, 0, me);
421
422                 return retarr;
423         }
424
425         if (splitsize != count)
426                 splitsize++;
427
428         retarr = mono_array_new(mono_domain_get(), mono_get_string_class (), splitsize);
429         for (i = 0; i != srcsize && arrpos != count; i++) {
430                 if (string_icall_is_in_array(separator, arrsize, src[i])) {
431                         if (arrpos == count - 1)
432                                 tmpstrsize = srcsize - lastpos;
433                         else
434                                 tmpstrsize = i - lastpos;
435
436                         tmpstr = mono_string_new_size( mono_domain_get (), tmpstrsize);
437                         tmpstrptr = mono_string_chars(tmpstr);
438
439                         memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
440                         mono_array_setref (retarr, arrpos, tmpstr);
441                         arrpos++;
442                         lastpos = i + 1;
443                 }
444         }
445
446         if (arrpos < count) {
447                 tmpstrsize = srcsize - lastpos;
448                 tmpstr = mono_string_new_size( mono_domain_get (), tmpstrsize);
449                 tmpstrptr = mono_string_chars(tmpstr);
450
451                 memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
452                 mono_array_setref (retarr, arrpos, tmpstr);
453         }
454
455         return retarr;
456 }
457
458 static gboolean
459 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
460 {
461         gunichar2 cmpchar;
462         gint32 arrpos;
463
464         for (arrpos = 0; arrpos != arraylength; arrpos++) {
465                 cmpchar = mono_array_get(chars, gunichar2, arrpos);
466                 if (cmpchar == chr)
467                         return TRUE;
468         }
469         
470         return FALSE;
471 }
472
473 MonoString * 
474 ves_icall_System_String_InternalTrim (MonoString *me, MonoArray *chars, gint32 typ)
475 {
476         MonoString * ret;
477         gunichar2 *src, *dest;
478         gint32 srclen, newlen, arrlen;
479         gint32 i, lenfirst, lenlast;
480
481         MONO_ARCH_SAVE_REGS;
482
483         srclen = mono_string_length(me);
484         src = mono_string_chars(me);
485         arrlen = mono_array_length(chars);
486
487         lenfirst = 0;
488         lenlast = 0;
489
490         if (0 == typ || 1 == typ) {
491                 for (i = 0; i != srclen; i++) {
492                         if (string_icall_is_in_array(chars, arrlen, src[i]))
493                                 lenfirst++;
494                         else 
495                                 break;
496                 }
497         }
498
499         if (0 == typ || 2 == typ) {
500                 for (i = srclen - 1; i > lenfirst - 1; i--) {
501                         if (string_icall_is_in_array(chars, arrlen, src[i]))
502                                 lenlast++;
503                         else 
504                                 break;
505                 }
506         }
507
508         newlen = srclen - lenfirst - lenlast;
509         if (newlen == srclen)
510                 return me;
511
512         ret = mono_string_new_size( mono_domain_get (), newlen);
513         dest = mono_string_chars(ret);
514
515         memcpy(dest, src + lenfirst, newlen *sizeof(gunichar2));
516
517         return ret;
518 }
519
520 gint32 
521 ves_icall_System_String_InternalIndexOfAny (MonoString *me, MonoArray *arr, gint32 sindex, gint32 count)
522 {
523         gint32 pos;
524         gint32 loop;
525         gint32 arraysize;
526         gunichar2 *src;
527
528         MONO_ARCH_SAVE_REGS;
529
530         arraysize = mono_array_length(arr);
531         src = mono_string_chars(me);
532
533         for (pos = sindex; pos != count + sindex; pos++) {
534                 for (loop = 0; loop != arraysize; loop++)
535                         if ( src [pos] == mono_array_get(arr, gunichar2, loop) )
536                                 return pos;
537         }
538
539         return -1;
540 }
541
542 gint32 
543 ves_icall_System_String_InternalLastIndexOf_Char (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
544 {
545         gint32 pos;
546         gunichar2 *src;
547
548         MONO_ARCH_SAVE_REGS;
549
550         src = mono_string_chars(me);
551         for (pos = sindex; pos > sindex - count; pos--) {
552                 if (src [pos] == value)
553                         return pos;
554         }
555
556         return -1;
557 }
558
559 gint32 
560 ves_icall_System_String_InternalLastIndexOf_Str (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
561 {
562         gint32 lencmpstr;
563         gint32 pos;
564         gunichar2 *src;
565         gunichar2 *cmpstr;
566
567         MONO_ARCH_SAVE_REGS;
568
569         lencmpstr = mono_string_length(value);
570
571         src = mono_string_chars(me);
572         cmpstr = mono_string_chars(value);
573
574         for (pos = sindex - lencmpstr + 1; pos > sindex - count; pos--) {
575                 if (0 == memcmp(src + pos, cmpstr, lencmpstr * sizeof(gunichar2)))
576                         return pos;
577         }
578
579         return -1;
580 }
581
582 gint32 
583 ves_icall_System_String_InternalLastIndexOfAny (MonoString *me, MonoArray *anyOf, gint32 sindex, gint32 count)
584 {
585         gint32 pos;
586         gint32 loop;
587         gint32 arraysize;
588         gunichar2 *src;
589
590         MONO_ARCH_SAVE_REGS;
591
592         arraysize = mono_array_length(anyOf);
593         src = mono_string_chars(me);
594
595         for (pos = sindex; pos > sindex - count; pos--) {
596                 for (loop = 0; loop != arraysize; loop++)
597                         if ( src [pos] == mono_array_get(anyOf, gunichar2, loop) )
598                                 return pos;
599         }
600
601         return -1;
602 }
603
604 MonoString *
605 ves_icall_System_String_InternalPad (MonoString *me, gint32 width, gunichar2 chr, MonoBoolean right)
606 {
607         MonoString * ret;
608         gunichar2 *src;
609         gunichar2 *dest;
610         gint32 fillcount;
611         gint32 srclen;
612         gint32 i;
613
614         MONO_ARCH_SAVE_REGS;
615
616         srclen = mono_string_length(me);
617         src = mono_string_chars(me);
618
619         ret = mono_string_new_size( mono_domain_get (), width);
620         dest = mono_string_chars(ret);
621         fillcount = width - srclen;
622
623         if (right) {
624                 memcpy(dest, src, srclen * sizeof(gunichar2));
625                 for (i = srclen; i != width; i++)
626                         dest[i] = chr;
627
628                 return ret;
629         }
630
631         /* left fill */
632         for (i = 0; i != fillcount; i++)
633                 dest[i] = chr;
634
635         memcpy(dest + fillcount, src, srclen * sizeof(gunichar2));
636
637         return ret;
638 }
639
640 MonoString *
641 ves_icall_System_String_InternalAllocateStr (gint32 length)
642 {
643         MONO_ARCH_SAVE_REGS;
644
645         return mono_string_new_size(mono_domain_get (), length);
646 }
647
648 void 
649 ves_icall_System_String_InternalStrcpy_Str (MonoString *dest, gint32 destPos, MonoString *src)
650 {
651         gunichar2 *srcptr;
652         gunichar2 *destptr;
653
654         MONO_ARCH_SAVE_REGS;
655
656         srcptr = mono_string_chars (src);
657         destptr = mono_string_chars (dest);
658
659         g_memmove (destptr + destPos, srcptr, mono_string_length(src) * sizeof(gunichar2));
660 }
661
662 void 
663 ves_icall_System_String_InternalStrcpy_StrN (MonoString *dest, gint32 destPos, MonoString *src, gint32 startPos, gint32 count)
664 {
665         gunichar2 *srcptr;
666         gunichar2 *destptr;
667
668         MONO_ARCH_SAVE_REGS;
669
670         srcptr = mono_string_chars (src);
671         destptr = mono_string_chars (dest);
672         g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
673 }
674
675 void 
676 ves_icall_System_String_InternalStrcpy_Chars (MonoString *dest, gint32 destPos, MonoArray *src)
677 {
678         gunichar2 *srcptr;
679         gunichar2 *destptr;
680
681         MONO_ARCH_SAVE_REGS;
682
683         srcptr = mono_array_addr (src, gunichar2, 0);
684         destptr = mono_string_chars (dest);
685
686         g_memmove (destptr + destPos, srcptr, mono_array_length (src) * sizeof(gunichar2));
687 }
688
689 void 
690 ves_icall_System_String_InternalStrcpy_CharsN (MonoString *dest, gint32 destPos, MonoArray *src, gint32 startPos, gint32 count)
691 {
692         gunichar2 *srcptr;
693         gunichar2 *destptr;
694
695         MONO_ARCH_SAVE_REGS;
696
697         srcptr = mono_array_addr (src, gunichar2, 0);
698         destptr = mono_string_chars (dest);
699
700         g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
701 }
702
703 MonoString  *
704 ves_icall_System_String_InternalIntern (MonoString *str)
705 {
706         MONO_ARCH_SAVE_REGS;
707
708         return mono_string_intern(str);
709 }
710
711 MonoString * 
712 ves_icall_System_String_InternalIsInterned (MonoString *str)
713 {
714         MONO_ARCH_SAVE_REGS;
715
716         return mono_string_is_interned(str);
717 }
718
719 gunichar2 
720 ves_icall_System_String_get_Chars (MonoString *me, gint32 idx)
721 {
722         MONO_ARCH_SAVE_REGS;
723
724         if ((idx < 0) || (idx >= mono_string_length (me)))
725                 mono_raise_exception (mono_get_exception_index_out_of_range ());
726         return mono_string_chars(me)[idx];
727 }
728
729 void
730 ves_icall_System_String_InternalCharCopy (gunichar2 *src, gunichar2 *dest, gint32 count)
731 {
732         MONO_ARCH_SAVE_REGS;
733
734         memcpy (dest, src, sizeof (gunichar2) * count);
735 }