r1188: Fix compile problem if iconv.h is missing (reported by Jim Knoble).
[rox-filer.git] / ROX-Filer / src / gconvert.c
blob6424cf36b6f37bde0ae9c54a4c25744a1c89cec5
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place, Suite 330, Boston, MA 02111-1307 USA
21 /* This code is taken from glib2 and has been converted to the GPL, as allowed
22 * under the terms of the LGPL. Removed lots of stuff! When we move fully to
23 * glib2, this file will disappear.
25 * gconvert.c: Convert between character sets using iconv
26 * Copyright Red Hat Inc., 2000
27 * Authors: Havoc Pennington <hp@redhat.com>, Owen Taylor <otaylor@redhat.com
30 #include "config.h"
32 #ifndef GTK2
34 #include "gunicode.h"
36 #ifdef HAVE_ICONV_H
37 # include <iconv.h>
38 #endif
40 #include <errno.h>
41 #include <string.h>
42 #include <stdlib.h>
44 #include <stdlib.h>
45 #include <string.h>
47 #include "global.h"
49 #include "gconvert.h"
51 #ifdef HAVE_ICONV_H
52 static gboolean
53 g_utf8_get_charset_internal (const char **a)
55 const char *charset = getenv("CHARSET");
56 iconv_t cd;
58 if (charset && *charset)
60 *a = charset;
62 if (charset && strstr (charset, "UTF-8"))
63 return TRUE;
64 else
65 return FALSE;
68 /* Try to find a sensible default... */
69 *a = "ISO8859-1";
70 cd = iconv_open (*a, "UTF-8");
71 if (cd == (iconv_t) -1)
73 *a = "iso-8859-1";
74 cd = (GIConv) iconv_open (*a, "UTF-8");
76 if (cd == (iconv_t) -1)
77 *a = "UTF-8";
78 else
79 iconv_close (cd);
81 return FALSE;
84 static int utf8_locale_cache = -1;
85 static const char *utf8_charset_cache = NULL;
87 #endif
89 gboolean
90 g_get_charset (const char **charset)
92 #ifdef HAVE_ICONV_H
93 if (utf8_locale_cache != -1)
95 if (charset)
96 *charset = utf8_charset_cache;
97 return utf8_locale_cache;
99 utf8_locale_cache = g_utf8_get_charset_internal (&utf8_charset_cache);
100 if (charset)
101 *charset = utf8_charset_cache;
102 return utf8_locale_cache;
103 #else
104 *charset = "UTF-8";
105 return 1;
106 #endif
109 #ifdef HAVE_ICONV_H
110 size_t
111 g_iconv (GIConv converter,
112 gchar **inbuf,
113 gsize *inbytes_left,
114 gchar **outbuf,
115 gsize *outbytes_left)
117 iconv_t cd = (iconv_t)converter;
119 return iconv (cd, inbuf, inbytes_left, outbuf, outbytes_left);
122 gint
123 g_iconv_close (GIConv converter)
125 iconv_t cd = (iconv_t)converter;
127 return iconv_close (cd);
130 static GIConv
131 open_converter (const gchar *to_codeset,
132 const gchar *from_codeset,
133 GError **error)
135 GIConv cd = (GIConv) iconv_open (to_codeset, from_codeset);
137 if (cd == (iconv_t) -1)
139 /* Something went wrong. */
140 if (errno == EINVAL)
141 g_warning("Conversion from character set '%s' to '%s' is not supported",
142 from_codeset, to_codeset);
143 else
144 g_warning("Could not open converter from '%s' to '%s': %s",
145 from_codeset, to_codeset, strerror (errno));
148 return cd;
151 #endif
153 gchar*
154 g_convert (const gchar *str,
155 gssize len,
156 const gchar *to_codeset,
157 const gchar *from_codeset,
158 gsize *bytes_read,
159 gsize *bytes_written,
160 GError **error)
162 gchar *res;
163 #ifdef HAVE_ICONV_H
164 GIConv cd;
166 g_return_val_if_fail (str != NULL, NULL);
167 g_return_val_if_fail (to_codeset != NULL, NULL);
168 g_return_val_if_fail (from_codeset != NULL, NULL);
170 cd = open_converter (to_codeset, from_codeset, error);
172 if (cd == (GIConv) -1)
174 if (bytes_read)
175 *bytes_read = 0;
177 if (bytes_written)
178 *bytes_written = 0;
180 return NULL;
183 res = g_convert_with_iconv (str, len, cd,
184 bytes_read, bytes_written,
185 error);
187 g_iconv_close (cd);
188 #else
189 res = g_strdup(str);
190 #endif
192 return res;
195 #ifdef HAVE_ICONV_H
196 gchar*
197 g_convert_with_iconv (const gchar *str,
198 gssize len,
199 GIConv converter,
200 gsize *bytes_read,
201 gsize *bytes_written,
202 GError **error)
204 gchar *dest;
205 gchar *outp;
206 const gchar *p;
207 gsize inbytes_remaining;
208 gsize outbytes_remaining;
209 gsize err;
210 gsize outbuf_size;
211 gboolean have_error = FALSE;
213 g_return_val_if_fail (str != NULL, NULL);
214 g_return_val_if_fail (converter != (GIConv) -1, NULL);
216 if (len < 0)
217 len = strlen (str);
219 p = str;
220 inbytes_remaining = len;
221 outbuf_size = len + 1; /* + 1 for nul in case len == 1 */
223 outbytes_remaining = outbuf_size - 1; /* -1 for nul */
224 outp = dest = g_malloc (outbuf_size);
226 again:
228 err = g_iconv (converter, (char **)&p, &inbytes_remaining, &outp, &outbytes_remaining);
230 if (err == (size_t) -1)
232 switch (errno)
234 case EINVAL:
235 /* Incomplete text, do not report an error */
236 break;
237 case E2BIG:
239 size_t used = outp - dest;
241 outbuf_size *= 2;
242 dest = g_realloc (dest, outbuf_size);
244 outp = dest + used;
245 outbytes_remaining = outbuf_size - used - 1; /* -1 for nul */
247 goto again;
249 case EILSEQ:
250 g_warning("Invalid byte sequence in conversion input");
251 have_error = TRUE;
252 break;
253 default:
254 g_warning("Error during conversion: %s", strerror (errno));
255 have_error = TRUE;
256 break;
260 *outp = '\0';
262 if (bytes_read)
263 *bytes_read = p - str;
264 else
266 if ((p - str) != len)
268 if (!have_error)
270 g_warning("Partial character sequence at end of input");
271 have_error = TRUE;
276 if (bytes_written)
277 *bytes_written = outp - dest; /* Doesn't include '\0' */
279 if (have_error)
281 g_free (dest);
282 return NULL;
284 else
285 return dest;
287 #endif
289 gchar *
290 g_locale_to_utf8 (const gchar *opsysstring,
291 gssize len,
292 gsize *bytes_read,
293 gsize *bytes_written,
294 GError **error)
296 const char *charset;
298 if (g_get_charset (&charset))
299 return g_strdup (opsysstring);
300 else
301 return g_convert (opsysstring, len,
302 "UTF-8", charset, bytes_read, bytes_written, error);
305 gchar *
306 g_locale_from_utf8 (const gchar *utf8string,
307 gssize len,
308 gsize *bytes_read,
309 gsize *bytes_written,
310 GError **error)
312 const gchar *charset;
314 if (g_get_charset (&charset))
315 return g_strdup (utf8string);
316 else
317 return g_convert (utf8string, len,
318 charset, "UTF-8", bytes_read, bytes_written, error);
321 #endif /* GTK2 */