1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2009 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Alexander Larsson <alexl@redhat.com>
27 #include "gcontenttypeprivate.h"
28 #include "gcharsetconverter.h"
30 #include "ginitable.h"
44 * SECTION:gcharsetconverter
45 * @short_description: Convert between charsets
48 * #GCharsetConverter is an implementation of #GConverter based on
52 static void g_charset_converter_iface_init (GConverterIface *iface);
53 static void g_charset_converter_initable_iface_init (GInitableIface *iface);
58 * Conversions between character sets.
60 struct _GCharsetConverter
62 GObject parent_instance;
67 gboolean use_fallback;
68 guint n_fallback_errors;
71 G_DEFINE_TYPE_WITH_CODE (GCharsetConverter, g_charset_converter, G_TYPE_OBJECT,
72 G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
73 g_charset_converter_iface_init);
74 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
75 g_charset_converter_initable_iface_init))
78 g_charset_converter_finalize (GObject *object)
80 GCharsetConverter *conv;
82 conv = G_CHARSET_CONVERTER (object);
87 g_iconv_close (conv->iconv);
89 G_OBJECT_CLASS (g_charset_converter_parent_class)->finalize (object);
93 g_charset_converter_set_property (GObject *object,
98 GCharsetConverter *conv;
100 conv = G_CHARSET_CONVERTER (object);
104 case PROP_TO_CHARSET:
106 conv->to = g_value_dup_string (value);
109 case PROP_FROM_CHARSET:
111 conv->from = g_value_dup_string (value);
114 case PROP_USE_FALLBACK:
115 conv->use_fallback = g_value_get_boolean (value);
119 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
126 g_charset_converter_get_property (GObject *object,
131 GCharsetConverter *conv;
133 conv = G_CHARSET_CONVERTER (object);
137 case PROP_TO_CHARSET:
138 g_value_set_string (value, conv->to);
141 case PROP_FROM_CHARSET:
142 g_value_set_string (value, conv->from);
145 case PROP_USE_FALLBACK:
146 g_value_set_boolean (value, conv->use_fallback);
150 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
156 g_charset_converter_class_init (GCharsetConverterClass *klass)
158 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
160 gobject_class->finalize = g_charset_converter_finalize;
161 gobject_class->get_property = g_charset_converter_get_property;
162 gobject_class->set_property = g_charset_converter_set_property;
164 g_object_class_install_property (gobject_class,
166 g_param_spec_string ("to-charset",
168 P_("The character encoding to convert to"),
170 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
171 G_PARAM_STATIC_STRINGS));
172 g_object_class_install_property (gobject_class,
174 g_param_spec_string ("from-charset",
176 P_("The character encoding to convert from"),
178 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
179 G_PARAM_STATIC_STRINGS));
180 g_object_class_install_property (gobject_class,
182 g_param_spec_boolean ("use-fallback",
183 P_("Fallback enabled"),
184 P_("Use fallback (of form \\<hexval>) for invalid bytes"),
188 G_PARAM_STATIC_STRINGS));
192 g_charset_converter_init (GCharsetConverter *local)
198 * g_charset_converter_new:
199 * @to_charset: destination charset
200 * @from_charset: source charset
201 * @error: #GError for error reporting, or %NULL to ignore.
203 * Creates a new #GCharsetConverter.
205 * Returns: a new #GCharsetConverter or %NULL on error.
210 g_charset_converter_new (const gchar *to_charset,
211 const gchar *from_charset,
214 GCharsetConverter *conv;
216 conv = g_initable_new (G_TYPE_CHARSET_CONVERTER,
218 "to-charset", to_charset,
219 "from-charset", from_charset,
226 g_charset_converter_reset (GConverter *converter)
228 GCharsetConverter *conv = G_CHARSET_CONVERTER (converter);
230 if (conv->iconv == NULL)
232 g_warning ("Invalid object, not initialized");
236 g_iconv (conv->iconv, NULL, NULL, NULL, NULL);
237 conv->n_fallback_errors = 0;
240 static GConverterResult
241 g_charset_converter_convert (GConverter *converter,
246 GConverterFlags flags,
248 gsize *bytes_written,
251 GCharsetConverter *conv;
253 GConverterResult ret;
254 gchar *inbufp, *outbufp;
255 gsize in_left, out_left;
258 conv = G_CHARSET_CONVERTER (converter);
260 if (conv->iconv == NULL)
262 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED,
263 _("Invalid object, not initialized"));
264 return G_CONVERTER_ERROR;
267 /* Iconv never produces output with no input, so handle this
271 if (flags & G_CONVERTER_INPUT_AT_END)
272 return G_CONVERTER_FINISHED;
274 if (flags & G_CONVERTER_FLUSH)
275 return G_CONVERTER_FLUSHED;
277 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
278 _("Incomplete multibyte sequence in input"));
279 return G_CONVERTER_ERROR;
282 inbufp = (char *)inbuf;
283 outbufp = (char *)outbuf;
284 in_left = inbuf_size;
285 out_left = outbuf_size;
287 res = g_iconv (conv->iconv,
289 &outbufp, &out_left);
291 *bytes_read = inbufp - (char *)inbuf;
292 *bytes_written = outbufp - (char *)outbuf;
294 /* Don't report error if we converted anything */
295 if (res == (gsize) -1 && *bytes_read == 0)
302 /* Incomplete input text */
303 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
304 _("Incomplete multibyte sequence in input"));
308 /* Not enough destination space */
309 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
310 _("Not enough space in destination"));
314 /* Invalid code sequence */
315 if (conv->use_fallback)
318 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
319 _("Not enough space in destination"));
322 const char hex[] = "0123456789ABCDEF";
323 guint8 v = *(guint8 *)inbuf;
324 guint8 *out = (guint8 *)outbuf;
326 out[1] = hex[(v & 0xf0) >> 4];
327 out[2] = hex[(v & 0x0f) >> 0];
331 conv->n_fallback_errors++;
336 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
337 _("Invalid byte sequence in conversion input"));
341 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
342 _("Error during conversion: %s"),
346 ret = G_CONVERTER_ERROR;
351 ret = G_CONVERTER_CONVERTED;
354 (flags & G_CONVERTER_INPUT_AT_END))
355 ret = G_CONVERTER_FINISHED;
356 else if (in_left == 0 &&
357 (flags & G_CONVERTER_FLUSH))
358 ret = G_CONVERTER_FLUSHED;
365 g_charset_converter_set_use_fallback (GCharsetConverter *converter,
366 gboolean use_fallback)
368 use_fallback = !!use_fallback;
370 if (converter->use_fallback != use_fallback)
372 converter->use_fallback = use_fallback;
373 g_object_notify (G_OBJECT (converter), "use-fallback");
378 g_charset_converter_get_use_fallback (GCharsetConverter *converter)
380 return converter->use_fallback;
384 g_charset_converter_get_num_fallbacks (GCharsetConverter *converter)
386 return converter->n_fallback_errors;
390 g_charset_converter_iface_init (GConverterIface *iface)
392 iface->convert = g_charset_converter_convert;
393 iface->reset = g_charset_converter_reset;
397 g_charset_converter_initable_init (GInitable *initable,
398 GCancellable *cancellable,
401 GCharsetConverter *conv;
403 g_return_val_if_fail (G_IS_CHARSET_CONVERTER (initable), FALSE);
405 conv = G_CHARSET_CONVERTER (initable);
407 if (cancellable != NULL)
409 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
410 _("Cancellable initialization not supported"));
415 g_iconv_open (conv->to, conv->from);
417 if (conv->iconv == NULL)
420 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
421 _("Conversion from character set '%s' to '%s' is not supported"),
422 conv->from, conv->to);
424 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
425 _("Could not open converter from '%s' to '%s'"),
426 conv->from, conv->to);
434 g_charset_converter_initable_iface_init (GInitableIface *iface)
436 iface->init = g_charset_converter_initable_init;
439 #define __G_CHARSET_CONVERTER_C__
440 #include "gioaliasdef.c"