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