mono_array_to_byvalarray (native_arr, arr, mono_defaults.byte_class, elnum);
}
-void
-mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
-{
- GError *error = NULL;
- guint16 *ut;
- glong items_written;
- int l;
-
- if (!sb || !text)
- return;
-
- l = strlen (text);
-
- ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
-
- if (items_written > mono_stringbuilder_capacity (sb))
- items_written = mono_stringbuilder_capacity (sb);
-
- if (!error) {
- if (! sb->str || sb->str == sb->cached_str)
- MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), items_written));
-
- memcpy (mono_string_chars (sb->str), ut, items_written * 2);
- sb->length = items_written;
- sb->cached_str = NULL;
- } else
- g_error_free (error);
-
- g_free (ut);
-}
-
-MonoStringBuilder *
-mono_string_utf8_to_builder2 (char *text)
+static MonoStringBuilder *
+mono_string_builder_new (int starting_string_length)
{
- int l;
- MonoStringBuilder *sb;
static MonoClass *string_builder_class;
static MonoMethod *sb_ctor;
- void *args [1];
- MonoObject *exc;
+ static void *args [1];
+ int initial_len = starting_string_length;
- if (!text)
- return NULL;
+ if (initial_len < 0)
+ initial_len = 0;
if (!string_builder_class) {
MonoMethodDesc *desc;
sb_ctor = mono_method_desc_search_in_class (desc, string_builder_class);
g_assert (sb_ctor);
mono_method_desc_free (desc);
- }
- l = strlen (text);
+ // We make a new array in the _to_builder function, so this
+ // array will always be garbage collected.
+ args [0] = &initial_len;
+ }
- sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
+ MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
+ MonoObject *exc;
g_assert (sb);
- args [0] = &l;
+
mono_runtime_invoke (sb_ctor, sb, args, &exc);
+
+ g_assert (sb->chunkChars->max_length >= initial_len);
g_assert (!exc);
- mono_string_utf8_to_builder (sb, text);
+ return sb;
+}
+
+static void
+mono_string_utf16_to_builder_copy (MonoStringBuilder *sb, gunichar2 *text, size_t string_len)
+{
+ gunichar2 *charDst = (gunichar2 *)sb->chunkChars->vector;
+ gunichar2 *charSrc = (gunichar2 *)text;
+ memcpy (charDst, charSrc, sizeof (gunichar2) * string_len);
+
+ sb->chunkLength = string_len;
+
+ return;
+}
+
+MonoStringBuilder *
+mono_string_utf16_to_builder2 (gunichar2 *text)
+{
+ if (!text)
+ return NULL;
+
+ int len;
+ for (len = 0; text [len] != 0; ++len);
+
+ MonoStringBuilder *sb = mono_string_builder_new (len);
+ mono_string_utf16_to_builder (sb, text);
return sb;
}
-/*
- * FIXME: This routine does not seem to do what it seems to do
- * the @text is never copied into the string builder
- */
void
-mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
+mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
{
- guint32 len;
-
if (!sb || !text)
return;
- g_assert (mono_string_chars (sb->str) == text);
+ int len = strlen (text);
+ if (len > mono_string_builder_capacity (sb))
+ len = mono_string_builder_capacity (sb);
- for (len = 0; text [len] != 0; ++len)
- ;
+ GError *error = NULL;
+ glong copied;
+ gunichar2* ut = g_utf8_to_utf16 (text, len, NULL, &copied, &error);
- sb->length = len;
+ if (!error) {
+ MONO_OBJECT_SETREF (sb, chunkPrevious, NULL);
+ mono_string_utf16_to_builder_copy (sb, ut, copied);
+ } else
+ g_error_free (error);
+
+ g_free (ut);
}
MonoStringBuilder *
-mono_string_utf16_to_builder2 (gunichar2 *text)
+mono_string_utf8_to_builder2 (char *text)
{
- int len;
- MonoStringBuilder *sb;
- static MonoClass *string_builder_class;
- static MonoMethod *sb_ctor;
- void *args [1];
- MonoObject *exc;
-
if (!text)
return NULL;
- if (!string_builder_class) {
- MonoMethodDesc *desc;
+ int len = strlen (text);
+ MonoStringBuilder *sb = mono_string_builder_new (len);
+ mono_string_utf8_to_builder (sb, text);
- string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder");
- g_assert (string_builder_class);
- desc = mono_method_desc_new (":.ctor(int)", FALSE);
- sb_ctor = mono_method_desc_search_in_class (desc, string_builder_class);
- g_assert (sb_ctor);
- mono_method_desc_free (desc);
- }
+ return sb;
+}
- for (len = 0; text [len] != 0; ++len)
- ;
- sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
- g_assert (sb);
- args [0] = &len;
- mono_runtime_invoke (sb_ctor, sb, args, &exc);
- g_assert (!exc);
+void
+mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
+{
+ if (!sb || !text)
+ return;
- sb->length = len;
- memcpy (mono_string_chars (sb->str), text, len * 2);
+ guint32 len;
+ for (len = 0; text [len] != 0; ++len);
+
+ if (len > mono_string_builder_capacity (sb))
+ len = mono_string_builder_capacity (sb);
- return sb;
+ mono_string_utf16_to_builder_copy (sb, text, len);
}
/**
*
* The return value must be released with g_free.
*/
-gpointer
+gchar*
mono_string_builder_to_utf8 (MonoStringBuilder *sb)
{
GError *error = NULL;
- gchar *tmp, *res = NULL;
if (!sb)
return NULL;
- if ((sb->str == sb->cached_str) && (sb->str->length == 0)) {
- /*
- * The sb could have been allocated with the default capacity and be empty.
- * we need to alloc a buffer of the default capacity in this case.
- */
- MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), 16));
- sb->cached_str = NULL;
- }
- tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, NULL, &error);
+ gunichar2 *str_utf16 = mono_string_builder_to_utf16 (sb);
+
+ guint str_len = mono_string_builder_string_length (sb);
+
+ gchar *tmp = g_utf16_to_utf8 (str_utf16, str_len, NULL, NULL, &error);
+
if (error) {
g_error_free (error);
+ g_free (str_utf16);
mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
+ return NULL;
} else {
- res = mono_marshal_alloc (mono_stringbuilder_capacity (sb) + 1);
- memcpy (res, tmp, sb->length + 1);
+ guint len = mono_string_builder_capacity (sb) + 1;
+ gchar *res = mono_marshal_alloc (len * sizeof (gchar));
+ g_assert (str_len < len);
+ memcpy (res, tmp, str_len * sizeof (gchar));
+ res[str_len] = '\0';
+
+
+ g_free (str_utf16);
g_free (tmp);
+ return res;
}
-
- return res;
}
/**
*
* The return value must not be freed.
*/
-gpointer
+gunichar2*
mono_string_builder_to_utf16 (MonoStringBuilder *sb)
{
if (!sb)
return NULL;
- g_assert (sb->str);
+ g_assert (sb->chunkChars);
- /*
- * The stringbuilder might not have ownership of this string. If this is
- * the case, we must duplicate the string, so that we don't munge immutable
- * strings
- */
- if (sb->str == sb->cached_str) {
- /*
- * The sb could have been allocated with the default capacity and be empty.
- * we need to alloc a buffer of the default capacity in this case.
- */
- if (sb->str->length == 0)
- MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), 16));
- else
- MONO_OBJECT_SETREF (sb, str, mono_string_new_utf16 (mono_domain_get (), mono_string_chars (sb->str), mono_stringbuilder_capacity (sb)));
- sb->cached_str = NULL;
- }
-
- if (sb->length == 0)
- *(mono_string_chars (sb->str)) = '\0';
+ guint len = mono_string_builder_capacity (sb);
+
+ if (len == 0)
+ len = 1;
+
+ gunichar2 *str = mono_marshal_alloc ((len + 1) * sizeof (gunichar2));
+ str[len] = '\0';
+
+ if (len == 0)
+ return str;
+
+ MonoStringBuilder* chunk = sb;
+ do {
+ if (chunk->chunkLength > 0) {
+ // Check that we will not overrun our boundaries.
+ gunichar2 *source = (gunichar2 *)chunk->chunkChars->vector;
+
+ if (chunk->chunkLength <= len) {
+ memcpy (str + chunk->chunkOffset, source, chunk->chunkLength * sizeof(gunichar2));
+ } else {
+ g_error ("A chunk in the StringBuilder had a length longer than expected from the offset.");
+ }
+
+ len -= chunk->chunkLength;
+ }
+ chunk = chunk->chunkPrevious;
+ } while (chunk != NULL);
- return mono_string_chars (sb->str);
+ return str;
}
static gpointer
{
int pos_noabort, pos_noex;
- mono_mb_emit_ptr (mb, (gpointer) mono_thread_interruption_request_flag ());
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_LDPTR_INT_REQ_FLAG);
mono_mb_emit_byte (mb, CEE_LDIND_U4);
pos_noabort = mono_mb_emit_branch (mb, CEE_BRFALSE);
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_byte (mb, CEE_LDC_I4);
mono_mb_emit_i4 (mb, ~0x1);
- mono_mb_emit_byte (mb, CEE_CONV_U);
+ mono_mb_emit_byte (mb, CEE_CONV_I);
mono_mb_emit_byte (mb, CEE_AND);
mono_mb_emit_ldloc (mb, 0);
/*if ((cached_vtable & ~0x1)== obj_vtable)*/
void*
ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
{
+ void *res;
+
#ifdef HOST_WIN32
- return CoTaskMemAlloc (size);
+ res = CoTaskMemAlloc (size);
#else
- return g_try_malloc ((gulong)size);
+ if ((gulong)size == 0)
+ /* This returns a valid pointer for size 0 on MS.NET */
+ size = 4;
+
+ res = g_try_malloc ((gulong)size);
#endif
+ if (!res)
+ mono_gc_out_of_memory ((gulong)size);
+ return res;
}
void
gpointer
ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, int size)
{
+ void *res;
+
#ifdef HOST_WIN32
- return CoTaskMemRealloc (ptr, size);
+ res = CoTaskMemRealloc (ptr, size);
#else
- return g_try_realloc (ptr, (gulong)size);
+ res = g_try_realloc (ptr, (gulong)size);
#endif
+ if (!res)
+ mono_gc_out_of_memory ((gulong)size);
+ return res;
}
void*