2007-03-09 Martin Baulig <martin@ximian.com>
[mono.git] / mono / utils / strenc.c
index c719914f80ebbf651f1b1c2db983deabb7036ae9..c37bb3d20168ffb6c93473b33ce7558b4da2ffb7 100644 (file)
@@ -9,44 +9,44 @@
 
 #include <config.h>
 #include <glib.h>
+#include <string.h>
 
 #include "strenc.h"
 
 #undef DEBUG
 
-/* Tries to turn a NULL-terminated string into UTF16LE.
+/**
+ * mono_unicode_from_external:
+ * @in: pointers to the buffer.
+ * @bytes: number of bytes in the string.
+ *
+ * Tries to turn a NULL-terminated string into UTF16.
  *
  * First, see if it's valid UTF8, in which case just turn it directly
- * into UTF16LE.  Next, run through the colon-separated encodings in
+ * into UTF16.  Next, run through the colon-separated encodings in
  * MONO_EXTERNAL_ENCODINGS and do an iconv conversion on each,
- * returning the first successful conversion to utf16.  If no
+ * returning the first successful conversion to UTF16.  If no
  * conversion succeeds, return NULL.
  *
  * Callers must free the returned string if not NULL. bytes holds the number
  * of bytes in the returned string, not including the terminator.
  */
-gunichar2 *mono_unicode_from_external (const gchar *in, gsize *bytes)
+gunichar2 *
+mono_unicode_from_external (const gchar *in, gsize *bytes)
 {
        gchar *res=NULL;
        gchar **encodings;
        const gchar *encoding_list;
        int i;
+       glong lbytes;
        
        if(in==NULL) {
                return(NULL);
        }
        
-       if(g_utf8_validate (in, -1, NULL)) {
-               /* Use g_convert not g_utf8_to_utf16 because we need
-                * to specify LE
-                */
-               res=g_convert (in, -1, "UTF16LE", "UTF8", NULL, bytes, NULL);
-               return((gunichar2 *)res);
-       }
-
        encoding_list=g_getenv ("MONO_EXTERNAL_ENCODINGS");
        if(encoding_list==NULL) {
-               return(NULL);
+               encoding_list = "";
        }
        
        encodings=g_strsplit (encoding_list, ":", 0);
@@ -55,34 +55,48 @@ gunichar2 *mono_unicode_from_external (const gchar *in, gsize *bytes)
                g_message (G_GNUC_PRETTY_FUNCTION ": Trying encoding [%s]",
                           encodings[i]);
 #endif
-               
                /* "default_locale" is a special case encoding */
                if(!strcmp (encodings[i], "default_locale")) {
-                       gchar *utf8=g_locale_to_utf8 (in, -1, NULL, NULL,
-                                                     NULL);
-                       if(utf8!=NULL && g_utf8_validate (utf8, -1, NULL)) {
-                               res=g_convert (utf8, -1, "UTF16LE",
-                                              encodings[i], NULL, bytes,
-                                              NULL);
+                       gchar *utf8=g_locale_to_utf8 (in, -1, NULL, NULL, NULL);
+                       if(utf8!=NULL) {
+                               res=(gchar *) g_utf8_to_utf16 (utf8, -1, NULL, &lbytes, NULL);
+                               *bytes = (gsize) lbytes;
                        }
                        g_free (utf8);
                } else {
-                       res=g_convert (in, -1, "UTF16LE", encodings[i], NULL,
-                                      bytes, NULL);
+                       /* Don't use UTF16 here. It returns the <FF FE> prepended to the string */
+                       res = g_convert (in, strlen (in), "UTF8", encodings[i], NULL, bytes, NULL);
+                       if (res != NULL) {
+                               gchar *ptr = res;
+                               res = (gchar *) g_utf8_to_utf16 (res, -1, NULL, &lbytes, NULL);
+                               *bytes = (gsize) lbytes;
+                               g_free (ptr);
+                       }
                }
 
                if(res!=NULL) {
                        g_strfreev (encodings);
+                       *bytes *= 2;
                        return((gunichar2 *)res);
                }
        }
        
        g_strfreev (encodings);
        
+       if(g_utf8_validate (in, -1, NULL)) {
+               gunichar2 *unires=g_utf8_to_utf16 (in, -1, NULL, (glong *)bytes, NULL);
+               *bytes *= 2;
+               return(unires);
+       }
+
        return(NULL);
 }
 
-/* Tries to turn a NULL-terminated string into UTF8.
+/**
+ * mono_utf8_from_external:
+ * @in: pointer to the string buffer.
+ *
+ * Tries to turn a NULL-terminated string into UTF8.
  *
  * First, see if it's valid UTF8, in which case there's nothing more
  * to be done.  Next, run through the colon-separated encodings in
@@ -107,13 +121,9 @@ gchar *mono_utf8_from_external (const gchar *in)
                return(NULL);
        }
        
-       if(g_utf8_validate (in, -1, NULL)) {
-               return(g_strdup (in));
-       }
-
        encoding_list=g_getenv ("MONO_EXTERNAL_ENCODINGS");
        if(encoding_list==NULL) {
-               return(NULL);
+               encoding_list = "";
        }
        
        encodings=g_strsplit (encoding_list, ":", 0);
@@ -143,10 +153,18 @@ gchar *mono_utf8_from_external (const gchar *in)
        
        g_strfreev (encodings);
        
+       if(g_utf8_validate (in, -1, NULL)) {
+               return(g_strdup (in));
+       }
+
        return(NULL);
 }
 
-/* Turns NULL-terminated UTF16LE into either UTF8, or the first
+/**
+ * mono_unicode_to_external:
+ * @uni: an UTF16 string to conver to an external representation.
+ *
+ * Turns NULL-terminated UTF16 into either UTF8, or the first
  * working item in MONO_EXTERNAL_ENCODINGS if set.  If no conversions
  * work, then UTF8 is returned.
  *