Esempio n. 1
0
static gint32 string_invariant_compare (MonoString *str1, gint32 off1,
					gint32 len1, MonoString *str2,
					gint32 off2, gint32 len2,
					gint32 options)
{
	/* c translation of C# code from old string.cs.. :) */
	gint32 length;
	gint32 charcmp;
	gunichar2 *ustr1;
	gunichar2 *ustr2;
	gint32 pos;

	if(len1 >= len2) {
		length=len1;
	} else {
		length=len2;
	}

	ustr1 = mono_string_chars(str1)+off1;
	ustr2 = mono_string_chars(str2)+off2;

	pos = 0;

	for (pos = 0; pos != length; pos++) {
		if (pos >= len1 || pos >= len2)
			break;

		charcmp = string_invariant_compare_char(ustr1[pos], ustr2[pos],
							options);
		if (charcmp != 0) {
			return(charcmp);
		}
	}

	/* the lesser wins, so if we have looped until length we just
	 * need to check the last char
	 */
	if (pos == length) {
		return(string_invariant_compare_char(ustr1[pos - 1],
						     ustr2[pos - 1], options));
	}

	/* Test if one of the strings has been compared to the end */
	if (pos >= len1) {
		if (pos >= len2) {
			return(0);
		} else {
			return(-1);
		}
	} else if (pos >= len2) {
		return(1);
	}

	/* if not, check our last char only.. (can this happen?) */
	return(string_invariant_compare_char(ustr1[pos], ustr2[pos], options));
}
Esempio n. 2
0
gpointer
ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
{
	gpointer handle;
	gchar *utf8_name;

	*error = ERROR_SUCCESS;

	/* w32 seems to guarantee that opening named objects can't race each other */
	mono_w32handle_namespace_lock ();

	utf8_name = g_utf16_to_utf8 (mono_string_chars (name), -1, NULL, NULL, NULL);

	mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named sem [%s]", __func__, utf8_name);

	handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDSEM, utf8_name);
	if (handle == INVALID_HANDLE_VALUE) {
		/* The name has already been used for a different object. */
		*error = ERROR_INVALID_HANDLE;
		goto cleanup;
	} else if (!handle) {
		/* This name doesn't exist */
		*error = ERROR_FILE_NOT_FOUND;
		goto cleanup;
	}

	mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named sem handle %p", __func__, handle);

cleanup:
	g_free (utf8_name);

	mono_w32handle_namespace_unlock ();

	return handle;
}
Esempio n. 3
0
static gint32 string_invariant_indexof_char (MonoString *source, gint32 sindex,
					     gint32 count, gunichar2 value,
					     MonoBoolean first)
{
	gint32 pos;
	gunichar2 *src;

	src = mono_string_chars(source);
	if(first) {
		for (pos = sindex; pos != count + sindex; pos++) {
			if (src [pos] == value) {
				return(pos);
			}
		}

		return(-1);
	} else {
		for (pos = sindex; pos > sindex - count; pos--) {
			if (src [pos] == value)
				return(pos);
		}

		return(-1);
	}
}
Esempio n. 4
0
gboolean
mono_process_get_shell_arguments (MonoProcessStartInfo *proc_start_info, gunichar2 **shell_path, MonoString **cmd)
{
	gchar		*spath = NULL;
	gchar		*new_cmd, *cmd_utf8;
	MonoError	mono_error;

	*shell_path = NULL;
	*cmd = proc_start_info->arguments;

	mono_process_complete_path (mono_string_chars (proc_start_info->filename), &spath);
	if (spath != NULL) {
		/* Seems like our CreateProcess does not work as the windows one.
		 * This hack is needed to deal with paths containing spaces */
		if (*cmd) {
			cmd_utf8 = mono_string_to_utf8_checked (*cmd, &mono_error);
			if (!mono_error_set_pending_exception (&mono_error)) {
				new_cmd = g_strdup_printf ("%s %s", spath, cmd_utf8);
				*cmd = mono_string_new_wrapper (new_cmd);
				g_free (cmd_utf8);
				g_free (new_cmd);
			} else {
				*cmd = NULL;
			}
		}
		else {
			*cmd = mono_string_new_wrapper (spath);
		}

		g_free (spath);
	}

	return (*cmd != NULL) ? TRUE : FALSE;
}
Esempio n. 5
0
gpointer
ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, gint32 *error)
{ 
	gpointer sem;

	if (maximumCount <= 0) {
		mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: maximumCount <= 0", __func__);

		*error = ERROR_INVALID_PARAMETER;
		return NULL;
	}

	if (initialCount > maximumCount || initialCount < 0) {
		mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: initialCount > maximumCount or < 0", __func__);

		*error = ERROR_INVALID_PARAMETER;
		return NULL;
	}

	/* Need to blow away any old errors here, because code tests
	 * for ERROR_ALREADY_EXISTS on success (!) to see if a
	 * semaphore was freshly created
	 */
	SetLastError (ERROR_SUCCESS);

	if (!name)
		sem = sem_create (initialCount, maximumCount);
	else
		sem = namedsem_create (initialCount, maximumCount, mono_string_chars (name));

	*error = GetLastError ();

	return sem;
}
Esempio n. 6
0
gunichar2*
mono_string_handle_pin_chars (MonoStringHandle handle, uint32_t *gchandle)
{
	g_assert (gchandle != NULL);
	*gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, handle), TRUE);
	MonoString *raw = MONO_HANDLE_RAW (handle);
	return mono_string_chars (raw);
}
Esempio n. 7
0
gpointer
ves_icall_System_Security_Principal_WindowsIdentity_GetUserToken (MonoString *username)
{
#ifdef HOST_WIN32
    gpointer token = NULL;

    MONO_ARCH_SAVE_REGS;

    /* TODO: MS has something like this working in Windows 2003 (client and
     * server) but works only for domain accounts (so it's quite limiting).
     * http://www.develop.com/kbrown/book/html/howto_logonuser.html
     */
    g_warning ("Unsupported on Win32 (anyway requires W2K3 minimum)");

#else /* HOST_WIN32*/

#ifdef HAVE_GETPWNAM_R
    struct passwd pwd;
    size_t fbufsize;
    gchar *fbuf;
    gint32 retval;
#endif
    gpointer token = (gpointer) -2;
    struct passwd *p;
    gchar *utf8_name;
    gboolean result;

    MONO_ARCH_SAVE_REGS;

    utf8_name = mono_unicode_to_external (mono_string_chars (username));

#ifdef HAVE_GETPWNAM_R
#ifdef _SC_GETPW_R_SIZE_MAX
    fbufsize = mono_sysconf (_SC_GETPW_R_SIZE_MAX);
#else
    fbufsize = MONO_SYSCONF_DEFAULT_SIZE;
#endif

    fbuf = g_malloc0 (fbufsize);
    retval = getpwnam_r (utf8_name, &pwd, fbuf, fbufsize, &p);
    result = ((retval == 0) && (p == &pwd));
#else
    /* default to non thread-safe but posix compliant function */
    p = getpwnam (utf8_name);
    result = (p != NULL);
#endif

    if (result) {
        token = GINT_TO_POINTER (p->pw_uid);
    }

#ifdef HAVE_GETPWNAM_R
    g_free (fbuf);
#endif
    g_free (utf8_name);
#endif
    return token;
}
gpointer
ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
{
	HANDLE sem;

	sem = OpenSemaphore (rights, FALSE, mono_string_chars (name));

	*error = GetLastError ();

	return sem;
}
gpointer
ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, gint32 *error)
{ 
	HANDLE sem;

	sem = CreateSemaphore (NULL, initialCount, maximumCount, name ? mono_string_chars (name) : NULL);

	*error = GetLastError ();

	return sem;
}
Esempio n. 10
0
gpointer
ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, gint32 *error)
{
	gpointer event;

	event = CreateEvent (NULL, manual, initial, name ? mono_string_chars (name) : NULL);

	*error = GetLastError ();

	return event;
}
Esempio n. 11
0
MonoBoolean
ves_icall_Mono_Security_Cryptography_KeyPairPersistence_IsUserProtected (MonoString *path)
{
	gboolean ret = FALSE;

	/* no one, but the user, should have access to the directory */
#ifdef HOST_WIN32
	ret = IsUserProtected (mono_string_chars (path));
#else
	ret = IsProtected (path, (S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH));
#endif
	return ret;
}
Esempio n. 12
0
gpointer
ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name, gint32 rights, gint32 *error)
{
	gpointer handle;

	*error = ERROR_SUCCESS;

	handle = OpenEvent (rights, FALSE, mono_string_chars (name));
	if (!handle)
		*error = GetLastError ();

	return handle;
}
Esempio n. 13
0
MonoBoolean
ves_icall_Mono_Security_Cryptography_KeyPairPersistence_ProtectMachine (MonoString *path)
{
	gboolean ret = FALSE;

	/* read/write to owner, read to everyone else */
#ifdef HOST_WIN32
	ret = ProtectMachine (mono_string_chars (path));
#else
	ret = Protect (path, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), (S_IXUSR | S_IXGRP | S_IXOTH));
#endif
	return ret;
}
Esempio n. 14
0
char *monostring_to_string(MonoString *string_obj)
{
    mono_unichar2 *uni_buffer = mono_string_chars(string_obj);
    int len = mono_string_length(string_obj);

    char *buffer = new char[len + 1];
    for (int i = 0; i < len; i++) {
        buffer[i] = get_char_from_unicode(uni_buffer[i]);
    }
    buffer[len] = '\0';

    return buffer;
}
Esempio n. 15
0
MonoBoolean
ves_icall_Mono_Security_Cryptography_KeyPairPersistence_ProtectUser (MonoString *path)
{
	gboolean ret = FALSE;
	
	/* read/write to user, no access to everyone else */
#ifdef HOST_WIN32
	ret = ProtectUser (mono_string_chars (path));
#else
	ret = Protect (path, (S_IRUSR | S_IWUSR), S_IXUSR);
#endif
	return ret;
}
Esempio n. 16
0
gboolean
ves_icall_System_Security_Principal_WindowsPrincipal_IsMemberOfGroupName (gpointer user, MonoString *group)
{
    gboolean result = FALSE;

#ifdef HOST_WIN32

    MONO_ARCH_SAVE_REGS;

    /* Windows version use a cache built using WindowsIdentity._GetRoles */
    g_warning ("IsMemberOfGroupName should never be called on Win32");

#else /* HOST_WIN32 */
    gchar *utf8_groupname;

    MONO_ARCH_SAVE_REGS;

    utf8_groupname = mono_unicode_to_external (mono_string_chars (group));
    if (utf8_groupname) {
        struct group *g = NULL;
#ifdef HAVE_GETGRNAM_R
        struct group grp;
        gchar *fbuf;
        gint32 retval;
#ifdef _SC_GETGR_R_SIZE_MAX
        size_t fbufsize = mono_sysconf (_SC_GETGR_R_SIZE_MAX);
#else
        size_t fbufsize = MONO_SYSCONF_DEFAULT_SIZE;
#endif
        fbuf = g_malloc0 (fbufsize);
        retval = getgrnam_r (utf8_groupname, &grp, fbuf, fbufsize, &g);
        result = ((retval == 0) && (g == &grp));
#else
        /* default to non thread-safe but posix compliant function */
        g = getgrnam (utf8_groupname);
        result = (g != NULL);
#endif

        if (result) {
            result = IsMemberOf ((uid_t) GPOINTER_TO_INT (user), g);
        }

#ifdef HAVE_GETGRNAM_R
        g_free (fbuf);
#endif
        g_free (utf8_groupname);
    }
#endif /* HOST_WIN32 */

    return result;
}
Esempio n. 17
0
static gboolean
IsProtected (MonoString *path, gint32 protection)
{
    gboolean result = FALSE;
    gchar *utf8_name = mono_unicode_to_external (mono_string_chars (path));
    if (utf8_name) {
        struct stat st;
        if (stat (utf8_name, &st) == 0) {
            result = (((st.st_mode & 0777) & protection) == 0);
        }
        g_free (utf8_name);
    }
    return result;
}
Esempio n. 18
0
MonoBoolean
ves_icall_Mono_Security_Cryptography_KeyPairPersistence_IsMachineProtected (MonoString *path)
{
    gboolean ret = FALSE;

    MONO_ARCH_SAVE_REGS;

    /* no one, but the owner, should have write access to the directory */
#ifdef HOST_WIN32
    ret = IsMachineProtected (mono_string_chars (path));
#else
    ret = IsProtected (path, (S_IWGRP | S_IWOTH));
#endif
    return ret;
}
Esempio n. 19
0
static gint32 string_invariant_indexof (MonoString *source, gint32 sindex,
					gint32 count, MonoString *value,
					MonoBoolean first)
{
	gint32 lencmpstr;
	gunichar2 *src;
	gunichar2 *cmpstr;
	gint32 pos,i;
	
	lencmpstr = mono_string_length(value);
	
	src = mono_string_chars(source);
	cmpstr = mono_string_chars(value);

	if(first) {
		count -= lencmpstr;
		for(pos=sindex;pos <= sindex+count;pos++) {
			for(i=0;src[pos+i]==cmpstr[i];) {
				if(++i==lencmpstr) {
					return(pos);
				}
			}
		}
		
		return(-1);
	} else {
		for(pos=sindex-lencmpstr+1;pos>sindex-count;pos--) {
			if(memcmp (src+pos, cmpstr,
				   lencmpstr*sizeof(gunichar2))==0) {
				return(pos);
			}
		}
		
		return(-1);
	}
}
Esempio n. 20
0
MonoBoolean
ves_icall_Mono_Security_Cryptography_KeyPairPersistence_CanSecure (MonoString *root)
{
#if HOST_WIN32
	gint32 flags;

	/* ACL are nice... unless you have FAT or other uncivilized filesystem */
	if (!GetVolumeInformation (mono_string_chars (root), NULL, 0, NULL, NULL, (LPDWORD)&flags, NULL, 0))
		return FALSE;
	return ((flags & FS_PERSISTENT_ACLS) == FS_PERSISTENT_ACLS);
#else
	/* we assume some kind of security is applicable outside Windows */
	return TRUE;
#endif
}
Esempio n. 21
0
void ves_icall_System_Globalization_CompareInfo_assign_sortkey (MonoCompareInfo *this_obj, MonoSortKey *key, MonoString *source, gint32 options)
{
	MonoArray *arr;
	gint32 keylen, i;

	keylen=mono_string_length (source);
	
	arr=mono_array_new (mono_domain_get (), mono_get_byte_class (),
			    keylen);
	for(i=0; i<keylen; i++) {
		mono_array_set (arr, guint8, i, mono_string_chars (source)[i]);
	}
	
	MONO_OBJECT_SETREF (key, key, arr);
}
Esempio n. 22
0
static gboolean
Protect (MonoString *path, gint32 file_mode, gint32 add_dir_mode)
{
    gboolean result = FALSE;
    gchar *utf8_name = mono_unicode_to_external (mono_string_chars (path));
    if (utf8_name) {
        struct stat st;
        if (stat (utf8_name, &st) == 0) {
            int mode = file_mode;
            if (st.st_mode & S_IFDIR)
                mode |= add_dir_mode;
            result = (chmod (utf8_name, mode) == 0);
        }
        g_free (utf8_name);
    }
    return result;
}
Esempio n. 23
0
String mono_to_utf16_string(MonoString *p_mono_string) {
	int len = mono_string_length(p_mono_string);
	String ret;

	if (len == 0)
		return ret;

	ret.resize(len + 1);
	ret.set(len, 0);

	CharType *src = (CharType *)mono_string_chars(p_mono_string);
	CharType *dst = &(ret.operator[](0));

	for (int i = 0; i < len; i++) {
		dst[i] = src[i];
	}

	return ret;
}
Esempio n. 24
0
static char *
string_to_utf8 (MonoString *s)
{
	char *as;
	GError *error = NULL;

	g_assert (s);

	if (!s->length)
		return g_strdup ("");

	as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
	if (error) {
		/* Happens with StringBuilders */
		g_error_free (error);
		return g_strdup ("<INVALID UTF8>");
	}
	else
		return as;
}
Esempio n. 25
0
gpointer
ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
{
	MonoObject *obj;

	if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
		return (gpointer)-2;
	obj = mono_gchandle_get_target (handle);
	if (obj) {
		MonoClass *klass = mono_object_class (obj);
		if (klass == mono_defaults.string_class) {
			return mono_string_chars ((MonoString*)obj);
		} else if (klass->rank) {
			return mono_array_addr ((MonoArray*)obj, char, 0);
		} else {
			/* the C# code will check and throw the exception */
			/* FIXME: missing !klass->blittable test, see bug #61134 */
			if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
				return (gpointer)-1;
			return (char*)obj + sizeof (MonoObject);
		}
	}
Esempio n. 26
0
gpointer
ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
{
	gpointer mutex;

	*created = TRUE;

	/* Need to blow away any old errors here, because code tests
	 * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
	 * was freshly created */
	mono_w32error_set_last (ERROR_SUCCESS);

	if (!name) {
		mutex = mutex_create (owned);
	} else {
		mutex = namedmutex_create (owned, mono_string_chars (name));

		if (mono_w32error_get_last () == ERROR_ALREADY_EXISTS)
			*created = FALSE;
	}

	return mutex;
}
Esempio n. 27
0
static MonoString *string_invariant_replace (MonoString *me,
					     MonoString *oldValue,
					     MonoString *newValue)
{
	MonoString *ret;
	gunichar2 *src;
	gunichar2 *dest=NULL; /* shut gcc up */
	gunichar2 *oldstr;
	gunichar2 *newstr=NULL; /* shut gcc up here too */
	gint32 i, destpos;
	gint32 occurr;
	gint32 newsize;
	gint32 oldstrlen;
	gint32 newstrlen;
	gint32 srclen;

	occurr = 0;
	destpos = 0;

	oldstr = mono_string_chars(oldValue);
	oldstrlen = mono_string_length(oldValue);

	if (NULL != newValue) {
		newstr = mono_string_chars(newValue);
		newstrlen = mono_string_length(newValue);
	} else
		newstrlen = 0;

	src = mono_string_chars(me);
	srclen = mono_string_length(me);

	if (oldstrlen != newstrlen) {
		i = 0;
		while (i <= srclen - oldstrlen) {
			if (0 == memcmp(src + i, oldstr, oldstrlen * sizeof(gunichar2))) {
				occurr++;
				i += oldstrlen;
			}
			else
				i ++;
		}
		if (occurr == 0)
			return me;
		newsize = srclen + ((newstrlen - oldstrlen) * occurr);
	} else
		newsize = srclen;

	ret = NULL;
	i = 0;
	while (i < srclen) {
		if (0 == memcmp(src + i, oldstr, oldstrlen * sizeof(gunichar2))) {
			if (ret == NULL) {
				ret = mono_string_new_size( mono_domain_get (), newsize);
				dest = mono_string_chars(ret);
				memcpy (dest, src, i * sizeof(gunichar2));
			}
			if (newstrlen > 0) {
				memcpy(dest + destpos, newstr, newstrlen * sizeof(gunichar2));
				destpos += newstrlen;
			}
			i += oldstrlen;
			continue;
		} else if (ret != NULL) {
			dest[destpos] = src[i];
		}
		destpos++;
		i++;
	}
	
	if (ret == NULL)
		return me;

	return ret;
}
Esempio n. 28
0
MonoArray * 
ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count, gint32 options)
{
	static MonoClass *String_array;
	MonoString * tmpstr;
	MonoArray * retarr;
	gunichar2 *src;
	gint32 arrsize, srcsize, splitsize;
	gint32 i, lastpos, arrpos;
	gint32 tmpstrsize;
	gint32 remempty;
	gint32 flag;
	gunichar2 *tmpstrptr;

	remempty = options & STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES;
	src = mono_string_chars (me);
	srcsize = mono_string_length (me);
	arrsize = mono_array_length (separator);

	if (!String_array) {
		MonoClass *klass = mono_array_class_get (mono_get_string_class (), 1);
		mono_memory_barrier ();
		String_array = klass;
	}

	splitsize = 1;
	/* Count the number of elements we will return. Note that this operation
	 * guarantees that we will return exactly splitsize elements, and we will
	 * have enough data to fill each. This allows us to skip some checks later on.
	 */
	if (remempty == 0) {
		for (i = 0; i != srcsize && splitsize < count; i++) {
			if (string_icall_is_in_array (separator, arrsize, src [i]))
				splitsize++;
		}
	} else if (count > 1) {
		/* Require pattern "Nondelim + Delim + Nondelim" to increment counter.
		 * Lastpos != 0 means first nondelim found.
		 * Flag = 0 means last char was delim.
		 * Efficient, though perhaps confusing.
		 */
		lastpos = 0;
		flag = 0;
		for (i = 0; i != srcsize && splitsize < count; i++) {
			if (string_icall_is_in_array (separator, arrsize, src [i])) {
				flag = 0;
			} else if (flag == 0) {
				if (lastpos == 1)
					splitsize++;
				flag = 1;
				lastpos = 1;
			}
		}

		/* Nothing but separators */
		if (lastpos == 0) {
			retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 0);
			return retarr;
		}
	}

	/* if no split chars found return the string */
	if (splitsize == 1) {
		if (remempty == 0 || count == 1) {
			/* Copy the whole string */
			retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 1);
			mono_array_setref (retarr, 0, me);
		} else {
			/* otherwise we have to filter out leading & trailing delims */

			/* find first non-delim char */
			for (; srcsize != 0; srcsize--, src++) {
				if (!string_icall_is_in_array (separator, arrsize, src [0]))
					break;
			}
			/* find last non-delim char */
			for (; srcsize != 0; srcsize--) {
				if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
					break;
			}
			tmpstr = mono_string_new_size (mono_domain_get (), srcsize);
			tmpstrptr = mono_string_chars (tmpstr);

			memcpy (tmpstrptr, src, srcsize * sizeof (gunichar2));
			retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 1);
			mono_array_setref (retarr, 0, tmpstr);
		}
		return retarr;
	}

	lastpos = 0;
	arrpos = 0;
	
	retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), splitsize);

	for (i = 0; i != srcsize && arrpos != splitsize; i++) {
		if (string_icall_is_in_array (separator, arrsize, src [i])) {
			
			if (lastpos != i || remempty == 0) {
				tmpstrsize = i - lastpos;
				tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
				tmpstrptr = mono_string_chars (tmpstr);

				memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
				mono_array_setref (retarr, arrpos, tmpstr);
				arrpos++;

				if (arrpos == splitsize - 1) {
					/* Shortcut the last array element */

					lastpos = i + 1;
					if (remempty != 0) {
						/* Search for non-delim starting char (guaranteed to find one) Note that loop
						 * condition is only there for safety. It will never actually terminate the loop. */
						for (; lastpos != srcsize ; lastpos++) {
							if (!string_icall_is_in_array (separator, arrsize, src [lastpos])) 
								break;
						}
						if (count > splitsize) {
							/* Since we have fewer results than our limit, we must remove
							 * trailing delimiters as well. 
							 */
							for (; srcsize != lastpos + 1 ; srcsize--) {
								if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1])) 
									break;
							}
						}
					}

					tmpstrsize = srcsize - lastpos;
					tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
					tmpstrptr = mono_string_chars (tmpstr);

					memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
					mono_array_setref (retarr, arrpos, tmpstr);

					/* Loop will ALWAYS end here. Test criteria in the FOR loop is technically unnecessary. */
					break;
				}
			}
			lastpos = i + 1;
		}
	}

	return retarr;
}