Add this for backwards compatibility
[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 #include <string.h>
13
14 #include "strenc.h"
15
16 #undef DEBUG
17
18 /* Tries to turn a NULL-terminated string into UTF16.
19  *
20  * First, see if it's valid UTF8, in which case just turn it directly
21  * into UTF16.  Next, run through the colon-separated encodings in
22  * MONO_EXTERNAL_ENCODINGS and do an iconv conversion on each,
23  * returning the first successful conversion to UTF16.  If no
24  * conversion succeeds, return NULL.
25  *
26  * Callers must free the returned string if not NULL. bytes holds the number
27  * of bytes in the returned string, not including the terminator.
28  */
29 gunichar2 *mono_unicode_from_external (const gchar *in, gsize *bytes)
30 {
31         gchar *res=NULL;
32         gchar **encodings;
33         const gchar *encoding_list;
34         int i;
35         glong lbytes;
36         
37         if(in==NULL) {
38                 return(NULL);
39         }
40         
41         encoding_list=g_getenv ("MONO_EXTERNAL_ENCODINGS");
42         if(encoding_list==NULL) {
43                 encoding_list = "";
44         }
45         
46         encodings=g_strsplit (encoding_list, ":", 0);
47         for(i=0;encodings[i]!=NULL; i++) {
48 #ifdef DEBUG
49                 g_message (G_GNUC_PRETTY_FUNCTION ": Trying encoding [%s]",
50                            encodings[i]);
51 #endif
52                 /* "default_locale" is a special case encoding */
53                 if(!strcmp (encodings[i], "default_locale")) {
54                         gchar *utf8=g_locale_to_utf8 (in, -1, NULL, NULL, NULL);
55                         if(utf8!=NULL) {
56                                 res=(gchar *) g_utf8_to_utf16 (utf8, -1, NULL, &lbytes, NULL);
57                                 *bytes = (gsize) lbytes;
58                         }
59                         g_free (utf8);
60                 } else {
61                         /* Don't use UTF16 here. It returns the <FF FE> prepended to the string */
62                         res = g_convert (in, strlen (in), "UTF8", encodings[i], NULL, bytes, NULL);
63                         if (res != NULL) {
64                                 gchar *ptr = res;
65                                 res = (gchar *) g_utf8_to_utf16 (res, -1, NULL, &lbytes, NULL);
66                                 *bytes = (gsize) lbytes;
67                                 g_free (ptr);
68                         }
69                 }
70
71                 if(res!=NULL) {
72                         g_strfreev (encodings);
73                         *bytes *= 2;
74                         return((gunichar2 *)res);
75                 }
76         }
77         
78         g_strfreev (encodings);
79         
80         if(g_utf8_validate (in, -1, NULL)) {
81                 gunichar2 *unires=g_utf8_to_utf16 (in, -1, NULL, (glong *)bytes, NULL);
82                 *bytes *= 2;
83                 return(unires);
84         }
85
86         return(NULL);
87 }
88
89 /* Tries to turn a NULL-terminated string into UTF8.
90  *
91  * First, see if it's valid UTF8, in which case there's nothing more
92  * to be done.  Next, run through the colon-separated encodings in
93  * MONO_EXTERNAL_ENCODINGS and do an iconv conversion on each,
94  * returning the first successful conversion to utf8.  If no
95  * conversion succeeds, return NULL.
96  *
97  * Callers must free the returned string if not NULL.
98  *
99  * This function is identical to mono_unicode_from_external, apart
100  * from returning utf8 not utf16; it's handy in a few places to work
101  * in utf8.
102  */
103 gchar *mono_utf8_from_external (const gchar *in)
104 {
105         gchar *res=NULL;
106         gchar **encodings;
107         const gchar *encoding_list;
108         int i;
109         
110         if(in==NULL) {
111                 return(NULL);
112         }
113         
114         encoding_list=g_getenv ("MONO_EXTERNAL_ENCODINGS");
115         if(encoding_list==NULL) {
116                 encoding_list = "";
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         if(g_utf8_validate (in, -1, NULL)) {
147                 return(g_strdup (in));
148         }
149
150         return(NULL);
151 }
152
153 /* Turns NULL-terminated UTF16 into either UTF8, or the first
154  * working item in MONO_EXTERNAL_ENCODINGS if set.  If no conversions
155  * work, then UTF8 is returned.
156  *
157  * Callers must free the returned string.
158  */
159 gchar *mono_unicode_to_external (const gunichar2 *uni)
160 {
161         gchar *utf8;
162         const gchar *encoding_list;
163         
164         /* Turn the unicode into utf8 to start with, because its
165          * easier to work with gchar * than gunichar2 *
166          */
167         utf8=g_utf16_to_utf8 (uni, -1, NULL, NULL, NULL);
168         g_assert (utf8!=NULL);
169         
170         encoding_list=g_getenv ("MONO_EXTERNAL_ENCODINGS");
171         if(encoding_list==NULL) {
172                 /* Do UTF8 */
173                 return(utf8);
174         } else {
175                 gchar *res, **encodings;
176                 int i;
177                 
178                 encodings=g_strsplit (encoding_list, ":", 0);
179                 for(i=0; encodings[i]!=NULL; i++) {
180                         if(!strcmp (encodings[i], "default_locale")) {
181                                 res=g_locale_from_utf8 (utf8, -1, NULL, NULL,
182                                                         NULL);
183                         } else {
184                                 res=g_convert (utf8, -1, encodings[i], "UTF8",
185                                                NULL, NULL, NULL);
186                         }
187
188                         if(res!=NULL) {
189                                 g_free (utf8);
190                                 g_strfreev (encodings);
191                                 
192                                 return(res);
193                         }
194                 }
195         
196                 g_strfreev (encodings);
197         }
198         
199         /* Nothing else worked, so just return the utf8 */
200         return(utf8);
201 }
202