2 * string-icalls.c: String internal calls for the corlib
5 * Patrik Torstensson (patrik.torstensson@labs2.com)
6 * Duncan Mak (duncan@ximian.com)
8 * (C) 2001 Ximian, Inc.
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>
25 /* Internal helper methods */
28 string_icall_is_in_array (MonoArray
*chars
, gint32 arraylength
, gunichar2 chr
);
31 ves_icall_System_String_ctor_charp (gpointer dummy
, gunichar2
*value
)
38 domain
= mono_domain_get ();
43 for (i
= 0; *(value
+ i
) != '\0'; i
++);
47 return mono_string_new_utf16 (domain
, value
, length
);
51 ves_icall_System_String_ctor_char_int (gpointer dummy
, gunichar2 value
, gint32 count
)
61 mono_raise_exception (mono_get_exception_argument_out_of_range ("count"));
63 domain
= mono_domain_get ();
64 res
= mono_string_new_size (domain
, count
);
66 chars
= mono_string_chars (res
);
67 for (i
= 0; i
< count
; i
++)
74 ves_icall_System_String_ctor_charp_int_int (gpointer dummy
, gunichar2
*value
, gint32 sindex
, gint32 length
)
81 domain
= mono_domain_get ();
83 if ((value
== NULL
) && (length
!= 0))
84 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
86 if ((sindex
< 0) || (length
< 0))
87 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
89 if (length
== 0) { /* fixme: return String.Empty here */
90 g_warning ("string doesn't yet support empy strings in char* constructor");
91 g_assert_not_reached ();
94 begin
= (gunichar2
*) (value
+ sindex
);
96 return mono_string_new_utf16 (domain
, begin
, length
);
100 ves_icall_System_String_ctor_sbytep (gpointer dummy
, gint8
*value
)
106 domain
= mono_domain_get ();
108 if (NULL
== value
) { /* fixme: return String.Empty here */
109 g_warning ("string doesn't yet support empy strings in char* constructor");
110 g_assert_not_reached ();
113 return mono_string_new (domain
, (const char *) value
);
117 ves_icall_System_String_ctor_sbytep_int_int (gpointer dummy
, gint8
*value
, gint32 sindex
, gint32 length
)
127 domain
= mono_domain_get ();
129 if ((value
== NULL
) && (length
!= 0))
130 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
132 if ((sindex
< 0) || (length
< 0))
133 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
135 begin
= (guchar
*) (value
+ sindex
);
136 res
= mono_string_new_size (domain
, length
);
137 chars
= mono_string_chars (res
);
138 for (i
= 0; i
< length
; ++i
)
139 chars
[i
] = begin
[i
];
145 ves_icall_System_String_ctor_chara (gpointer dummy
, MonoArray
*value
)
151 domain
= mono_domain_get ();
154 return mono_string_new_utf16 (domain
, NULL
, 0);
156 return mono_string_new_utf16 (domain
, (gunichar2
*) mono_array_addr(value
, gunichar2
, 0), value
->max_length
);
160 ves_icall_System_String_ctor_chara_int_int (gpointer dummy
, MonoArray
*value
,
161 gint32 sindex
, gint32 length
)
168 mono_raise_exception (mono_get_exception_argument_null ("value"));
170 mono_raise_exception (mono_get_exception_argument_out_of_range ("startIndex"));
172 mono_raise_exception (mono_get_exception_argument_out_of_range ("length"));
173 if (sindex
+ length
> mono_array_length (value
))
174 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
176 domain
= mono_domain_get ();
178 return mono_string_new_utf16 (domain
, (gunichar2
*) mono_array_addr(value
, gunichar2
, sindex
), length
);
182 ves_icall_System_String_ctor_encoding (gpointer dummy
, gint8
*value
, gint32 sindex
,
183 gint32 length
, MonoObject
*enc
)
189 MonoDomain
*domain
= mono_domain_get ();
190 MonoMethod
*get_string
;
193 if ((value
== NULL
) || (length
== 0))
194 return mono_string_new_size (mono_domain_get (), 0);
196 mono_raise_exception (mono_get_exception_argument_null ("enc"));
198 mono_raise_exception (mono_get_exception_argument_out_of_range ("startIndex"));
200 mono_raise_exception (mono_get_exception_argument_out_of_range ("length"));
202 arr
= mono_array_new (domain
, mono_defaults
.byte_class
, length
);
203 memcpy (mono_array_addr (arr
, guint8
*, 0), value
+ sindex
, length
);
205 get_string
= mono_find_method_by_name (enc
->vtable
->klass
, "GetString", 1);
207 s
= (MonoString
*)mono_runtime_invoke (get_string
, enc
, args
, &exc
);
209 mono_raise_exception (mono_get_exception_argument ("", "Unable to decode the array into a valid string."));
215 ves_icall_System_String_InternalJoin (MonoString
*separator
, MonoArray
* value
, gint32 sindex
, gint32 count
)
230 insert
= mono_string_chars(separator
);
231 insertlen
= mono_string_length(separator
);
234 for (pos
= sindex
; pos
!= sindex
+ count
; pos
++) {
235 current
= mono_array_get (value
, MonoString
*, pos
);
237 length
+= mono_string_length (current
);
239 if (pos
< sindex
+ count
- 1)
243 ret
= mono_string_new_size( mono_domain_get (), length
);
244 dest
= mono_string_chars(ret
);
247 for (pos
= sindex
; pos
!= sindex
+ count
; pos
++) {
248 current
= mono_array_get (value
, MonoString
*, pos
);
249 if (current
!= NULL
) {
250 src
= mono_string_chars (current
);
251 srclen
= mono_string_length (current
);
253 memcpy (dest
+ destpos
, src
, srclen
* sizeof(gunichar2
));
257 if (pos
< sindex
+ count
- 1) {
258 memcpy(dest
+ destpos
, insert
, insertlen
* sizeof(gunichar2
));
259 destpos
+= insertlen
;
267 ves_icall_System_String_InternalInsert (MonoString
*me
, gint32 sindex
, MonoString
*value
)
271 gunichar2
*insertsrc
;
278 src
= mono_string_chars(me
);
279 srclen
= mono_string_length(me
);
281 insertsrc
= mono_string_chars(value
);
282 insertlen
= mono_string_length(value
);
284 ret
= mono_string_new_size( mono_domain_get (), srclen
+ insertlen
);
285 dest
= mono_string_chars(ret
);
287 memcpy(dest
, src
, sindex
* sizeof(gunichar2
));
288 memcpy(dest
+ sindex
, insertsrc
, insertlen
* sizeof(gunichar2
));
289 memcpy(dest
+ sindex
+ insertlen
, src
+ sindex
, (srclen
- sindex
) * sizeof(gunichar2
));
295 ves_icall_System_String_InternalReplace_Char (MonoString
*me
, gunichar2 oldChar
, gunichar2 newChar
)
304 src
= mono_string_chars(me
);
305 srclen
= mono_string_length(me
);
307 ret
= mono_string_new_size( mono_domain_get (), srclen
);
308 dest
= mono_string_chars(ret
);
310 for (i
= 0; i
!= srclen
; i
++) {
311 if (src
[i
] == oldChar
)
321 ves_icall_System_String_InternalRemove (MonoString
*me
, gint32 sindex
, gint32 count
)
330 srclen
= mono_string_length(me
);
331 ret
= mono_string_new_size( mono_domain_get (), srclen
- count
);
333 src
= mono_string_chars(me
);
334 dest
= mono_string_chars(ret
);
336 memcpy(dest
, src
, sindex
* sizeof(gunichar2
));
337 memcpy(dest
+ sindex
, src
+ sindex
+ count
, (srclen
- count
- sindex
) * sizeof(gunichar2
));
343 ves_icall_System_String_InternalCopyTo (MonoString
*me
, gint32 sindex
, MonoArray
*dest
, gint32 dindex
, gint32 count
)
345 gunichar2
*destptr
= (gunichar2
*) mono_array_addr(dest
, gunichar2
, dindex
);
346 gunichar2
*src
= mono_string_chars(me
);
350 memcpy(destptr
, src
+ sindex
, sizeof(gunichar2
) * count
);
354 ves_icall_System_String_InternalSplit (MonoString
*me
, MonoArray
*separator
, gint32 count
)
359 gint32 arrsize
, srcsize
, splitsize
;
360 gint32 i
, lastpos
, arrpos
;
362 gunichar2
*tmpstrptr
;
368 src
= mono_string_chars(me
);
369 srcsize
= mono_string_length(me
);
370 arrsize
= mono_array_length(separator
);
372 cmpchar
= mono_array_get(separator
, gunichar2
, 0);
375 for (i
= 0; i
!= srcsize
&& splitsize
< count
; i
++) {
376 if (string_icall_is_in_array(separator
, arrsize
, src
[i
]))
383 /* if no split chars found return the string */
384 if (splitsize
== 0) {
385 retarr
= mono_array_new(mono_domain_get(), mono_get_string_class (), 1);
386 mono_array_set(retarr
, MonoString
*, 0, me
);
391 if (splitsize
!= count
)
394 retarr
= mono_array_new(mono_domain_get(), mono_get_string_class (), splitsize
);
395 for (i
= 0; i
!= srcsize
&& arrpos
!= count
; i
++) {
396 if (string_icall_is_in_array(separator
, arrsize
, src
[i
])) {
397 if (arrpos
== count
- 1)
398 tmpstrsize
= srcsize
- lastpos
;
400 tmpstrsize
= i
- lastpos
;
402 tmpstr
= mono_string_new_size( mono_domain_get (), tmpstrsize
);
403 tmpstrptr
= mono_string_chars(tmpstr
);
405 memcpy(tmpstrptr
, src
+ lastpos
, tmpstrsize
* sizeof(gunichar2
));
406 mono_array_set(retarr
, MonoString
*, arrpos
, tmpstr
);
412 if (arrpos
< count
) {
413 tmpstrsize
= srcsize
- lastpos
;
414 tmpstr
= mono_string_new_size( mono_domain_get (), tmpstrsize
);
415 tmpstrptr
= mono_string_chars(tmpstr
);
417 memcpy(tmpstrptr
, src
+ lastpos
, tmpstrsize
* sizeof(gunichar2
));
418 mono_array_set(retarr
, MonoString
*, arrpos
, tmpstr
);
425 string_icall_is_in_array (MonoArray
*chars
, gint32 arraylength
, gunichar2 chr
)
430 for (arrpos
= 0; arrpos
!= arraylength
; arrpos
++) {
431 cmpchar
= mono_array_get(chars
, gunichar2
, arrpos
);
440 ves_icall_System_String_InternalTrim (MonoString
*me
, MonoArray
*chars
, gint32 typ
)
443 gunichar2
*src
, *dest
;
444 gint32 srclen
, newlen
, arrlen
;
445 gint32 i
, lenfirst
, lenlast
;
449 srclen
= mono_string_length(me
);
450 src
= mono_string_chars(me
);
451 arrlen
= mono_array_length(chars
);
456 if (0 == typ
|| 1 == typ
) {
457 for (i
= 0; i
!= srclen
; i
++) {
458 if (string_icall_is_in_array(chars
, arrlen
, src
[i
]))
465 if (0 == typ
|| 2 == typ
) {
466 for (i
= srclen
- 1; i
> lenfirst
- 1; i
--) {
467 if (string_icall_is_in_array(chars
, arrlen
, src
[i
]))
474 newlen
= srclen
- lenfirst
- lenlast
;
475 if (newlen
== srclen
)
478 ret
= mono_string_new_size( mono_domain_get (), newlen
);
479 dest
= mono_string_chars(ret
);
481 memcpy(dest
, src
+ lenfirst
, newlen
*sizeof(gunichar2
));
487 ves_icall_System_String_InternalIndexOfAny (MonoString
*me
, MonoArray
*arr
, gint32 sindex
, gint32 count
)
496 arraysize
= mono_array_length(arr
);
497 src
= mono_string_chars(me
);
499 for (pos
= sindex
; pos
!= count
+ sindex
; pos
++) {
500 for (loop
= 0; loop
!= arraysize
; loop
++)
501 if ( src
[pos
] == mono_array_get(arr
, gunichar2
, loop
) )
509 ves_icall_System_String_InternalLastIndexOf_Char (MonoString
*me
, gunichar2 value
, gint32 sindex
, gint32 count
)
516 src
= mono_string_chars(me
);
517 for (pos
= sindex
; pos
> sindex
- count
; pos
--) {
518 if (src
[pos
] == value
)
526 ves_icall_System_String_InternalLastIndexOf_Str (MonoString
*me
, MonoString
*value
, gint32 sindex
, gint32 count
)
535 lencmpstr
= mono_string_length(value
);
537 src
= mono_string_chars(me
);
538 cmpstr
= mono_string_chars(value
);
540 for (pos
= sindex
- lencmpstr
+ 1; pos
> sindex
- count
; pos
--) {
541 if (0 == memcmp(src
+ pos
, cmpstr
, lencmpstr
* sizeof(gunichar2
)))
549 ves_icall_System_String_InternalLastIndexOfAny (MonoString
*me
, MonoArray
*anyOf
, gint32 sindex
, gint32 count
)
558 arraysize
= mono_array_length(anyOf
);
559 src
= mono_string_chars(me
);
561 for (pos
= sindex
; pos
> sindex
- count
; pos
--) {
562 for (loop
= 0; loop
!= arraysize
; loop
++)
563 if ( src
[pos
] == mono_array_get(anyOf
, gunichar2
, loop
) )
571 ves_icall_System_String_InternalPad (MonoString
*me
, gint32 width
, gunichar2 chr
, MonoBoolean right
)
582 srclen
= mono_string_length(me
);
583 src
= mono_string_chars(me
);
585 ret
= mono_string_new_size( mono_domain_get (), width
);
586 dest
= mono_string_chars(ret
);
587 fillcount
= width
- srclen
;
590 memcpy(dest
, src
, srclen
* sizeof(gunichar2
));
591 for (i
= srclen
; i
!= width
; i
++)
598 for (i
= 0; i
!= fillcount
; i
++)
601 memcpy(dest
+ fillcount
, src
, srclen
* sizeof(gunichar2
));
607 ves_icall_System_String_InternalAllocateStr (gint32 length
)
611 return mono_string_new_size(mono_domain_get (), length
);
615 ves_icall_System_String_InternalStrcpy_Str (MonoString
*dest
, gint32 destPos
, MonoString
*src
)
622 srcptr
= mono_string_chars (src
);
623 destptr
= mono_string_chars (dest
);
625 g_memmove (destptr
+ destPos
, srcptr
, mono_string_length(src
) * sizeof(gunichar2
));
629 ves_icall_System_String_InternalStrcpy_StrN (MonoString
*dest
, gint32 destPos
, MonoString
*src
, gint32 startPos
, gint32 count
)
636 srcptr
= mono_string_chars (src
);
637 destptr
= mono_string_chars (dest
);
638 g_memmove (destptr
+ destPos
, srcptr
+ startPos
, count
* sizeof(gunichar2
));
642 ves_icall_System_String_InternalStrcpy_Chars (MonoString
*dest
, gint32 destPos
, MonoArray
*src
)
649 srcptr
= mono_array_addr (src
, gunichar2
, 0);
650 destptr
= mono_string_chars (dest
);
652 g_memmove (destptr
+ destPos
, srcptr
, mono_array_length (src
) * sizeof(gunichar2
));
656 ves_icall_System_String_InternalStrcpy_CharsN (MonoString
*dest
, gint32 destPos
, MonoArray
*src
, gint32 startPos
, gint32 count
)
663 srcptr
= mono_array_addr (src
, gunichar2
, 0);
664 destptr
= mono_string_chars (dest
);
666 g_memmove (destptr
+ destPos
, srcptr
+ startPos
, count
* sizeof(gunichar2
));
670 ves_icall_System_String_InternalIntern (MonoString
*str
)
674 return mono_string_intern(str
);
678 ves_icall_System_String_InternalIsInterned (MonoString
*str
)
682 return mono_string_is_interned(str
);
686 ves_icall_System_String_GetHashCode (MonoString
*me
)
689 gunichar2
*data
= mono_string_chars (me
);
693 for (i
= 0; i
< mono_string_length (me
); ++i
)
694 h
= (h
<< 5) - h
+ data
[i
];
700 ves_icall_System_String_get_Chars (MonoString
*me
, gint32 idx
)
704 if ((idx
< 0) || (idx
>= mono_string_length (me
)))
705 mono_raise_exception (mono_get_exception_index_out_of_range ());
706 return mono_string_chars(me
)[idx
];
710 ves_icall_System_String_InternalCharCopy (gunichar2
*src
, gunichar2
*dest
, gint32 count
)
714 memcpy (dest
, src
, sizeof (gunichar2
) * count
);