2003-10-28 Dick Porter <dick@ximian.com>
[mono.git] / mono / utils / strenc.c
1 /*
2  * strenc.c: string encoding conversions
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2003 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12
13 #include "strenc.h"
14
15 #undef DEBUG
16
17 /* Tries to turn a NULL-terminated string into UTF16LE.
18  *
19  * First, see if it's valid UTF8, in which case just turn it directly
20  * into UTF16LE.  Next, run through the colon-separated encodings in
21  * MONO_EXTERNAL_ENCODINGS and do an iconv conversion on each,
22  * returning the first successful conversion to utf16.  If no
23  * conversion succeeds, return NULL.
24  *
25  * Callers must free the returned string if not NULL. bytes holds the number
26  * of bytes in the returned string, not including the terminator.
27  */
28 gunichar2 *mono_unicode_from_external (const gchar *in, gsize *bytes)
29 {
30         gchar *res=NULL;
31         gchar **encodings;
32         const gchar *encoding_list;
33         int i;
34         
35         if(in==NULL) {
36                 return(NULL);
37         }
38         
39         if(g_utf8_validate (in, -1, NULL)) {
40                 /* Use g_convert not g_utf8_to_utf16 because we need
41                  * to specify LE
42                  */
43                 res=g_convert (in, -1, "UTF16LE", "UTF8", NULL, bytes, NULL);
44                 return((gunichar2 *)res);
45         }
46
47         encoding_list=g_getenv ("MONO_EXTERNAL_ENCODINGS");
48         if(encoding_list==NULL) {
49                 return(NULL);
50         }
51         
52         encodings=g_strsplit (encoding_list, ":", 0);
53         for(i=0;encodings[i]!=NULL; i++) {
54 #ifdef DEBUG
55                 g_message (G_GNUC_PRETTY_FUNCTION ": Trying encoding [%s]",
56                            encodings[i]);
57 #endif
58                 
59                 /* "default_locale" is a special case encoding */
60                 if(!strcmp (encodings[i], "default_locale")) {
61                         gchar *utf8=g_locale_to_utf8 (in, -1, NULL, NULL,
62                                                       NULL);
63                         if(utf8!=NULL && g_utf8_validate (utf8, -1, NULL)) {
64                                 res=g_convert (utf8, -1, "UTF16LE",
65                                                encodings[i], NULL, bytes,
66                                                NULL);
67                         }
68                         g_free (utf8);
69                 } else {
70                         res=g_convert (in, -1, "UTF16LE", encodings[i], NULL,
71                                        bytes, NULL);
72                 }
73
74                 if(res!=NULL) {
75                         g_strfreev (encodings);
76                         return((gunichar2 *)res);
77                 }
78         }
79         
80         g_strfreev (encodings);
81         
82         return(NULL);
83 }
84
85 /* Tries to turn a NULL-terminated string into UTF8.
86  *
87  * First, see if it's valid UTF8, in which case there's nothing more
88  * to be done.  Next, run through the colon-separated encodings in
89  * MONO_EXTERNAL_ENCODINGS and do an iconv conversion on each,
90  * returning the first successful conversion to utf8.  If no
91  * conversion succeeds, return NULL.
92  *
93  * Callers must free the returned string if not NULL.
94  *
95  * This function is identical to mono_unicode_from_external, apart
96  * from returning utf8 not utf16; it's handy in a few places to work
97  * in utf8.
98  */
99 gchar *mono_utf8_from_external (const gchar *in)
100 {
101         gchar *res=NULL;
102         gchar **encodings;
103         const gchar *encoding_list;
104         int i;
105         
106         if(in==NULL) {
107                 return(NULL);
108         }
109         
110         if(g_utf8_validate (in, -1, NULL)) {
111                 return(g_strdup (in));
112         }
113
114         encoding_list=g_getenv ("MONO_EXTERNAL_ENCODINGS");
115         if(encoding_list==NULL) {
116                 return(NULL);
117         }
118         
119         encodings=g_strsplit (encoding_list, ":", 0);
120         for(i=0;encodings[i]!=NULL; i++) {
121 #ifdef DEBUG
122                 g_message (G_GNUC_PRETTY_FUNCTION ": Trying encoding [%s]",
123                            encodings[i]);
124 #endif
125                 
126                 /* "default_locale" is a special case encoding */
127                 if(!strcmp (encodings[i], "default_locale")) {
128                         res=g_locale_to_utf8 (in, -1, NULL, NULL, NULL);
129                         if(res!=NULL && !g_utf8_validate (res, -1, NULL)) {
130                                 g_free (res);
131                                 res=NULL;
132                         }
133                 } else {
134                         res=g_convert (in, -1, "UTF8", encodings[i], NULL,
135                                        NULL, NULL);
136                 }
137
138                 if(res!=NULL) {
139                         g_strfreev (encodings);
140                         return(res);
141                 }
142         }
143         
144         g_strfreev (encodings);
145         
146         return(NULL);
147 }
148
149 /* Turns NULL-terminated UTF16LE into either UTF8, or the first
150  * working item in MONO_EXTERNAL_ENCODINGS if set.  If no conversions
151  * work, then UTF8 is returned.
152  *
153  * Callers must free the returned string.
154  */
155 gchar *mono_unicode_to_external (const gunichar2 *uni)
156 {
157         gchar *utf8;
158         const gchar *encoding_list;
159         
160         /* Turn the unicode into utf8 to start with, because its
161          * easier to work with gchar * than gunichar2 *
162          */
163         utf8=g_utf16_to_utf8 (uni, -1, NULL, NULL, NULL);
164         g_assert (utf8!=NULL);
165         
166         encoding_list=g_getenv ("MONO_EXTERNAL_ENCODINGS");
167         if(encoding_list==NULL) {
168                 /* Do UTF8 */
169                 return(utf8);
170         } else {
171                 gchar *res, **encodings;
172                 int i;
173                 
174                 encodings=g_strsplit (encoding_list, ":", 0);
175                 for(i=0; encodings[i]!=NULL; i++) {
176                         if(!strcmp (encodings[i], "default_locale")) {
177                                 res=g_locale_from_utf8 (utf8, -1, NULL, NULL,
178                                                         NULL);
179                         } else {
180                                 res=g_convert (utf8, -1, encodings[i], "UTF8",
181                                                NULL, NULL, NULL);
182                         }
183
184                         if(res!=NULL) {
185                                 g_free (utf8);
186                                 g_strfreev (encodings);
187                                 
188                                 return(res);
189                         }
190                 }
191         
192                 g_strfreev (encodings);
193         }
194         
195         /* Nothing else worked, so just return the utf8 */
196         return(utf8);
197 }
198