Fri Feb 22 18:55:57 CET 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / unicode.c
index ba57a96d9d7bdd628913db5896a1df2880182e3d..e162e65d4033c42ed50d76fa5a9b02eea6388e2b 100644 (file)
@@ -154,14 +154,19 @@ ves_icall_iconv_new_encoder (MonoString *name, MonoBoolean big_endian)
        iconv_t cd;
        char *n;
 
-       // fixme: add support big_endian
+       // fixme: don't enforce big endian, support old iconv
 
        g_assert (name);
 
        n = mono_string_to_utf8 (name);
 
+       /* force big endian before class libraries are fixed */
+#if G_BYTE_ORDER != G_LITTLE_ENDIAN
+       big_endian = 1;
+#endif 
+
 #ifdef HAVE_NEW_ICONV
-       cd = iconv_open (n, "UTF-16le");
+       cd = iconv_open (n, big_endian ? "UTF-16be" : "UTF-16le");
 #else
        cd = iconv_open (n, "UTF-16");
 #endif
@@ -176,14 +181,19 @@ ves_icall_iconv_new_decoder (MonoString *name, MonoBoolean big_endian)
        iconv_t cd;
        char *n;
 
-       // fixme: add support big_endian
+       // fixme: don't enforce big endian, support old iconv
 
        g_assert (name);
 
        n = mono_string_to_utf8 (name);
 
+       /* force big endian before class libraries are fixed */
+#if G_BYTE_ORDER != G_LITTLE_ENDIAN
+       big_endian = 1;
+#endif 
+
 #ifdef HAVE_NEW_ICONV
-       cd = iconv_open ("UTF-16le", n);
+       cd = iconv_open (big_endian ? "UTF-16be" : "UTF-16le", n);
 #else
        cd = iconv_open ("UTF-16", n);
 #endif
@@ -203,10 +213,10 @@ ves_icall_iconv_reset (gpointer converter)
 }
 
 static int
-iconv_get_length (iconv_t cd, guchar *src, int len)
+iconv_get_length (iconv_t cd, guchar *src, int len, gboolean encode)
 {
        guchar buf [512];
-       int i, res;
+       int res;
        guchar *outp;
        guchar *p;
        guint inbytes_remaining;
@@ -214,12 +224,14 @@ iconv_get_length (iconv_t cd, guchar *src, int len)
        guint outbuf_size;
        gboolean have_error = FALSE;
        size_t err;
-
+       
        g_assert (cd);
        g_assert (src);
 
 #ifndef HAVE_NEW_ICONV
-       if (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
+       if (G_BYTE_ORDER == G_LITTLE_ENDIAN && encode) {
+               int i;
+               
                src = g_memdup (src, len);
                for (i = 0; i < len; i += 2) {
                        char t = src [i];
@@ -268,7 +280,7 @@ again:
        }
 
 #ifndef HAVE_NEW_ICONV
-       if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
+       if (G_BYTE_ORDER == G_LITTLE_ENDIAN && encode)
                g_free (src);
 #endif
 
@@ -297,13 +309,12 @@ ves_icall_iconv_get_byte_count (gpointer converter, MonoArray *chars, gint32 ind
 
        src =  mono_array_addr (chars, guint16, index);
 
-       return iconv_get_length (cd, src, len);
+       return iconv_get_length (cd, src, len, TRUE);
 }
 
 static int
-iconv_convert (iconv_t cd, guchar *src, int len, guchar *dest, int max_len)
+iconv_convert (iconv_t cd, guchar *src, int len, guchar *dest, int max_len, gboolean encode)
 {
-       int i;
        guchar *p, *outp;
        guint inbytes_remaining;
        guint outbytes_remaining;
@@ -316,7 +327,9 @@ iconv_convert (iconv_t cd, guchar *src, int len, guchar *dest, int max_len)
        g_assert (dest);
 
 #ifndef HAVE_NEW_ICONV
-       if (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
+       if (G_BYTE_ORDER == G_LITTLE_ENDIAN && encode) {
+               int i;
+               
                src = g_memdup (src, len);
                for (i = 0; i < len; i += 2) {
                        char t = src [i];
@@ -350,8 +363,19 @@ iconv_convert (iconv_t cd, guchar *src, int len, guchar *dest, int max_len)
        }
 
 #ifndef HAVE_NEW_ICONV
-       if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
-               g_free (src);
+       if (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
+               if (encode) {
+                       g_free (src);
+               } else {
+                       int mb = max_len - outbytes_remaining;
+                       int i;
+                       for (i = 0; i < mb; i+=2) {
+                               char t = dest [i];
+                               dest [i] = dest [i + 1];
+                               dest [i + 1] = t;
+                       }
+               }
+}
 #endif
        if (have_error) {
                g_assert_not_reached ();
@@ -389,7 +413,7 @@ ves_icall_iconv_get_bytes (gpointer converter, MonoArray *chars, gint32 charInde
 
        max_len = mono_array_length (bytes) - byteIndex;
 
-       return iconv_convert (cd, src, len, dest, max_len);
+       return iconv_convert (cd, src, len, dest, max_len, TRUE);
 }
 
 int
@@ -409,7 +433,7 @@ ves_icall_iconv_get_char_count (gpointer converter, MonoArray *bytes, gint32 ind
 
        src =  mono_array_addr (bytes, char, index);
 
-       return iconv_get_length (cd, src, len);
+       return iconv_get_length (cd, src, len, FALSE);
 }
 
 int
@@ -436,5 +460,5 @@ ves_icall_iconv_get_chars (gpointer converter, MonoArray *bytes, gint32 byteInde
        max_len = (mono_array_length (chars) - charIndex) * 2;
 
        /* iconv_convert () returns the number of bytes */
-       return iconv_convert (cd, src, len, dest, max_len) / 2;
+       return iconv_convert (cd, src, len, dest, max_len, FALSE) / 2;
 }