2005-03-04 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / string-icalls.c
1 /*
2  * string-icalls.c: String internal calls for the corlib
3  *
4  * Author:
5  *   Patrik Torstensson (patrik.torstensson@labs2.com)
6  *   Duncan Mak  (duncan@ximian.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  */
10 #include <config.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <mono/metadata/string-icalls.h>
16 #include <mono/metadata/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
214         MONO_ARCH_SAVE_REGS;
215
216         if ((value == NULL) || (length == 0))
217                 return mono_string_new_size (mono_domain_get (), 0);
218         if (enc == NULL)
219                 mono_raise_exception (mono_get_exception_argument_null ("enc"));
220         if (sindex < 0)
221                 mono_raise_exception (mono_get_exception_argument_out_of_range ("startIndex"));         
222         if (length < 0)
223                 mono_raise_exception (mono_get_exception_argument_out_of_range ("length"));
224
225         arr = mono_array_new (domain, mono_defaults.byte_class, length);
226         memcpy (mono_array_addr (arr, guint8*, 0), value + sindex, length);
227
228         get_string = mono_class_get_method_from_name (enc->vtable->klass, "GetString", 1);
229         args [0] = arr;
230         s = (MonoString*)mono_runtime_invoke (get_string, enc, args, &exc);
231         if (!s || exc)
232                 mono_raise_exception (mono_get_exception_argument ("", "Unable to decode the array into a valid string."));
233
234         return s;
235 }
236
237 MonoString * 
238 ves_icall_System_String_InternalJoin (MonoString *separator, MonoArray * value, gint32 sindex, gint32 count)
239 {
240         MonoString * ret;
241         MonoString *current;
242         gint32 length;
243         gint32 pos;
244         gint32 insertlen;
245         gint32 destpos;
246         gint32 srclen;
247         gunichar2 *insert;
248         gunichar2 *dest;
249         gunichar2 *src;
250
251         MONO_ARCH_SAVE_REGS;
252
253         insert = mono_string_chars(separator);
254         insertlen = mono_string_length(separator);
255
256         length = 0;
257         for (pos = sindex; pos != sindex + count; pos++) {
258                 current = mono_array_get (value, MonoString *, pos);
259                 if (current != NULL)
260                         length += mono_string_length (current);
261
262                 if (pos < sindex + count - 1)
263                         length += insertlen;
264         }
265
266         ret = mono_string_new_size( mono_domain_get (), length);
267         dest = mono_string_chars(ret);
268         destpos = 0;
269
270         for (pos = sindex; pos != sindex + count; pos++) {
271                 current = mono_array_get (value, MonoString *, pos);
272                 if (current != NULL) {
273                         src = mono_string_chars (current);
274                         srclen = mono_string_length (current);
275
276                         memcpy (dest + destpos, src, srclen * sizeof(gunichar2));
277                         destpos += srclen;
278                 }
279
280                 if (pos < sindex + count - 1) {
281                         memcpy(dest + destpos, insert, insertlen * sizeof(gunichar2));
282                         destpos += insertlen;
283                 }
284         }
285
286         return ret;
287 }
288
289 MonoString * 
290 ves_icall_System_String_InternalInsert (MonoString *me, gint32 sindex, MonoString *value)
291 {
292         MonoString * ret;
293         gunichar2 *src;
294         gunichar2 *insertsrc;
295         gunichar2 *dest;
296         gint32 srclen;
297         gint32 insertlen;
298
299         MONO_ARCH_SAVE_REGS;
300
301         src = mono_string_chars(me);
302         srclen = mono_string_length(me);
303
304         insertsrc = mono_string_chars(value);
305         insertlen = mono_string_length(value);
306
307         ret = mono_string_new_size( mono_domain_get (), srclen + insertlen);
308         dest = mono_string_chars(ret);
309
310         memcpy(dest, src, sindex * sizeof(gunichar2));
311         memcpy(dest + sindex, insertsrc, insertlen * sizeof(gunichar2));
312         memcpy(dest + sindex + insertlen, src + sindex, (srclen - sindex) * sizeof(gunichar2));
313
314         return ret;
315 }
316
317 MonoString * 
318 ves_icall_System_String_InternalReplace_Char (MonoString *me, gunichar2 oldChar, gunichar2 newChar)
319 {
320         MonoString *ret;
321         gunichar2 *src;
322         gunichar2 *dest;
323         gint32 i, srclen;
324
325         MONO_ARCH_SAVE_REGS;
326
327         src = mono_string_chars(me);
328         srclen = mono_string_length(me);
329
330         ret = mono_string_new_size( mono_domain_get (), srclen);
331         dest = mono_string_chars(ret);
332
333         for (i = 0; i != srclen; i++) {
334                 if (src[i] == oldChar)
335                         dest[i] = newChar;
336                 else
337                         dest[i] = src[i];
338         }
339
340         return ret;
341 }
342
343 MonoString * 
344 ves_icall_System_String_InternalRemove (MonoString *me, gint32 sindex, gint32 count)
345 {
346         MonoString * ret;
347         gint32 srclen;
348         gunichar2 *dest;
349         gunichar2 *src;
350
351         MONO_ARCH_SAVE_REGS;
352
353         srclen = mono_string_length(me);
354         ret = mono_string_new_size( mono_domain_get (), srclen - count);
355
356         src = mono_string_chars(me);
357         dest = mono_string_chars(ret);
358
359         memcpy(dest, src, sindex * sizeof(gunichar2));
360         memcpy(dest + sindex, src + sindex + count, (srclen - count - sindex) * sizeof(gunichar2));
361
362         return ret;
363 }
364
365 void
366 ves_icall_System_String_InternalCopyTo (MonoString *me, gint32 sindex, MonoArray *dest, gint32 dindex, gint32 count)
367 {
368         gunichar2 *destptr = (gunichar2 *) mono_array_addr(dest, gunichar2, dindex);
369         gunichar2 *src =  mono_string_chars(me);
370
371         MONO_ARCH_SAVE_REGS;
372
373         memcpy(destptr, src + sindex, sizeof(gunichar2) * count);
374 }
375
376 MonoArray * 
377 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count)
378 {
379         MonoString * tmpstr;
380         MonoArray * retarr;
381         gunichar2 *src;
382         gint32 arrsize, srcsize, splitsize;
383         gint32 i, lastpos, arrpos;
384         gint32 tmpstrsize;
385         gunichar2 *tmpstrptr;
386
387         gunichar2 cmpchar;
388
389         MONO_ARCH_SAVE_REGS;
390
391         src = mono_string_chars(me);
392         srcsize = mono_string_length(me);
393         arrsize = mono_array_length(separator);
394
395         cmpchar = mono_array_get(separator, gunichar2, 0);
396
397         splitsize = 0;
398         for (i = 0; i != srcsize && splitsize < count; i++) {
399                 if (string_icall_is_in_array(separator, arrsize, src[i]))
400                         splitsize++;
401         }
402
403         lastpos = 0;
404         arrpos = 0;
405
406         /* if no split chars found return the string */
407         if (splitsize == 0) {
408                 retarr = mono_array_new(mono_domain_get(), mono_get_string_class (), 1);
409                 mono_array_set(retarr, MonoString *, 0, me);
410
411                 return retarr;
412         }
413
414         if (splitsize != count)
415                 splitsize++;
416
417         retarr = mono_array_new(mono_domain_get(), mono_get_string_class (), splitsize);
418         for (i = 0; i != srcsize && arrpos != count; i++) {
419                 if (string_icall_is_in_array(separator, arrsize, src[i])) {
420                         if (arrpos == count - 1)
421                                 tmpstrsize = srcsize - lastpos;
422                         else
423                                 tmpstrsize = i - lastpos;
424
425                         tmpstr = mono_string_new_size( mono_domain_get (), tmpstrsize);
426                         tmpstrptr = mono_string_chars(tmpstr);
427
428                         memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
429                         mono_array_set(retarr, MonoString *, arrpos, tmpstr);
430                         arrpos++;
431                         lastpos = i + 1;
432                 }
433         }
434
435         if (arrpos < count) {
436                 tmpstrsize = srcsize - lastpos;
437                 tmpstr = mono_string_new_size( mono_domain_get (), tmpstrsize);
438                 tmpstrptr = mono_string_chars(tmpstr);
439
440                 memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
441                 mono_array_set(retarr, MonoString *, arrpos, tmpstr);
442         }
443
444         return retarr;
445 }
446
447 static gboolean
448 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
449 {
450         gunichar2 cmpchar;
451         gint32 arrpos;
452
453         for (arrpos = 0; arrpos != arraylength; arrpos++) {
454                 cmpchar = mono_array_get(chars, gunichar2, arrpos);
455                 if (cmpchar == chr)
456                         return TRUE;
457         }
458         
459         return FALSE;
460 }
461
462 MonoString * 
463 ves_icall_System_String_InternalTrim (MonoString *me, MonoArray *chars, gint32 typ)
464 {
465         MonoString * ret;
466         gunichar2 *src, *dest;
467         gint32 srclen, newlen, arrlen;
468         gint32 i, lenfirst, lenlast;
469
470         MONO_ARCH_SAVE_REGS;
471
472         srclen = mono_string_length(me);
473         src = mono_string_chars(me);
474         arrlen = mono_array_length(chars);
475
476         lenfirst = 0;
477         lenlast = 0;
478
479         if (0 == typ || 1 == typ) {
480                 for (i = 0; i != srclen; i++) {
481                         if (string_icall_is_in_array(chars, arrlen, src[i]))
482                                 lenfirst++;
483                         else 
484                                 break;
485                 }
486         }
487
488         if (0 == typ || 2 == typ) {
489                 for (i = srclen - 1; i > lenfirst - 1; i--) {
490                         if (string_icall_is_in_array(chars, arrlen, src[i]))
491                                 lenlast++;
492                         else 
493                                 break;
494                 }
495         }
496
497         newlen = srclen - lenfirst - lenlast;
498         if (newlen == srclen)
499                 return me;
500
501         ret = mono_string_new_size( mono_domain_get (), newlen);
502         dest = mono_string_chars(ret);
503
504         memcpy(dest, src + lenfirst, newlen *sizeof(gunichar2));
505
506         return ret;
507 }
508
509 gint32 
510 ves_icall_System_String_InternalIndexOfAny (MonoString *me, MonoArray *arr, gint32 sindex, gint32 count)
511 {
512         gint32 pos;
513         gint32 loop;
514         gint32 arraysize;
515         gunichar2 *src;
516
517         MONO_ARCH_SAVE_REGS;
518
519         arraysize = mono_array_length(arr);
520         src = mono_string_chars(me);
521
522         for (pos = sindex; pos != count + sindex; pos++) {
523                 for (loop = 0; loop != arraysize; loop++)
524                         if ( src [pos] == mono_array_get(arr, gunichar2, loop) )
525                                 return pos;
526         }
527
528         return -1;
529 }
530
531 gint32 
532 ves_icall_System_String_InternalLastIndexOf_Char (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
533 {
534         gint32 pos;
535         gunichar2 *src;
536
537         MONO_ARCH_SAVE_REGS;
538
539         src = mono_string_chars(me);
540         for (pos = sindex; pos > sindex - count; pos--) {
541                 if (src [pos] == value)
542                         return pos;
543         }
544
545         return -1;
546 }
547
548 gint32 
549 ves_icall_System_String_InternalLastIndexOf_Str (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
550 {
551         gint32 lencmpstr;
552         gint32 pos;
553         gunichar2 *src;
554         gunichar2 *cmpstr;
555
556         MONO_ARCH_SAVE_REGS;
557
558         lencmpstr = mono_string_length(value);
559
560         src = mono_string_chars(me);
561         cmpstr = mono_string_chars(value);
562
563         for (pos = sindex - lencmpstr + 1; pos > sindex - count; pos--) {
564                 if (0 == memcmp(src + pos, cmpstr, lencmpstr * sizeof(gunichar2)))
565                         return pos;
566         }
567
568         return -1;
569 }
570
571 gint32 
572 ves_icall_System_String_InternalLastIndexOfAny (MonoString *me, MonoArray *anyOf, gint32 sindex, gint32 count)
573 {
574         gint32 pos;
575         gint32 loop;
576         gint32 arraysize;
577         gunichar2 *src;
578
579         MONO_ARCH_SAVE_REGS;
580
581         arraysize = mono_array_length(anyOf);
582         src = mono_string_chars(me);
583
584         for (pos = sindex; pos > sindex - count; pos--) {
585                 for (loop = 0; loop != arraysize; loop++)
586                         if ( src [pos] == mono_array_get(anyOf, gunichar2, loop) )
587                                 return pos;
588         }
589
590         return -1;
591 }
592
593 MonoString *
594 ves_icall_System_String_InternalPad (MonoString *me, gint32 width, gunichar2 chr, MonoBoolean right)
595 {
596         MonoString * ret;
597         gunichar2 *src;
598         gunichar2 *dest;
599         gint32 fillcount;
600         gint32 srclen;
601         gint32 i;
602
603         MONO_ARCH_SAVE_REGS;
604
605         srclen = mono_string_length(me);
606         src = mono_string_chars(me);
607
608         ret = mono_string_new_size( mono_domain_get (), width);
609         dest = mono_string_chars(ret);
610         fillcount = width - srclen;
611
612         if (right) {
613                 memcpy(dest, src, srclen * sizeof(gunichar2));
614                 for (i = srclen; i != width; i++)
615                         dest[i] = chr;
616
617                 return ret;
618         }
619
620         /* left fill */
621         for (i = 0; i != fillcount; i++)
622                 dest[i] = chr;
623
624         memcpy(dest + fillcount, src, srclen * sizeof(gunichar2));
625
626         return ret;
627 }
628
629 MonoString *
630 ves_icall_System_String_InternalAllocateStr (gint32 length)
631 {
632         MONO_ARCH_SAVE_REGS;
633
634         return mono_string_new_size(mono_domain_get (), length);
635 }
636
637 void 
638 ves_icall_System_String_InternalStrcpy_Str (MonoString *dest, gint32 destPos, MonoString *src)
639 {
640         gunichar2 *srcptr;
641         gunichar2 *destptr;
642
643         MONO_ARCH_SAVE_REGS;
644
645         srcptr = mono_string_chars (src);
646         destptr = mono_string_chars (dest);
647
648         g_memmove (destptr + destPos, srcptr, mono_string_length(src) * sizeof(gunichar2));
649 }
650
651 void 
652 ves_icall_System_String_InternalStrcpy_StrN (MonoString *dest, gint32 destPos, MonoString *src, gint32 startPos, gint32 count)
653 {
654         gunichar2 *srcptr;
655         gunichar2 *destptr;
656
657         MONO_ARCH_SAVE_REGS;
658
659         srcptr = mono_string_chars (src);
660         destptr = mono_string_chars (dest);
661         g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
662 }
663
664 void 
665 ves_icall_System_String_InternalStrcpy_Chars (MonoString *dest, gint32 destPos, MonoArray *src)
666 {
667         gunichar2 *srcptr;
668         gunichar2 *destptr;
669
670         MONO_ARCH_SAVE_REGS;
671
672         srcptr = mono_array_addr (src, gunichar2, 0);
673         destptr = mono_string_chars (dest);
674
675         g_memmove (destptr + destPos, srcptr, mono_array_length (src) * sizeof(gunichar2));
676 }
677
678 void 
679 ves_icall_System_String_InternalStrcpy_CharsN (MonoString *dest, gint32 destPos, MonoArray *src, gint32 startPos, gint32 count)
680 {
681         gunichar2 *srcptr;
682         gunichar2 *destptr;
683
684         MONO_ARCH_SAVE_REGS;
685
686         srcptr = mono_array_addr (src, gunichar2, 0);
687         destptr = mono_string_chars (dest);
688
689         g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
690 }
691
692 MonoString  *
693 ves_icall_System_String_InternalIntern (MonoString *str)
694 {
695         MONO_ARCH_SAVE_REGS;
696
697         return mono_string_intern(str);
698 }
699
700 MonoString * 
701 ves_icall_System_String_InternalIsInterned (MonoString *str)
702 {
703         MONO_ARCH_SAVE_REGS;
704
705         return mono_string_is_interned(str);
706 }
707
708 gunichar2 
709 ves_icall_System_String_get_Chars (MonoString *me, gint32 idx)
710 {
711         MONO_ARCH_SAVE_REGS;
712
713         if ((idx < 0) || (idx >= mono_string_length (me)))
714                 mono_raise_exception (mono_get_exception_index_out_of_range ());
715         return mono_string_chars(me)[idx];
716 }
717
718 void
719 ves_icall_System_String_InternalCharCopy (gunichar2 *src, gunichar2 *dest, gint32 count)
720 {
721         MONO_ARCH_SAVE_REGS;
722
723         memcpy (dest, src, sizeof (gunichar2) * count);
724 }