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>
25 #include "gcharsetconverter.h"
29 #include "gcontenttypeprivate.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;
259 conv = G_CHARSET_CONVERTER (converter);
261 if (conv->iconv == NULL)
263 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED,
264 _("Invalid object, not initialized"));
265 return G_CONVERTER_ERROR;
268 inbufp = (char *)inbuf;
269 outbufp = (char *)outbuf;
270 in_left = inbuf_size;
271 out_left = outbuf_size;
274 /* if there is not input try to flush the data */
277 if (flags & G_CONVERTER_INPUT_AT_END ||
278 flags & G_CONVERTER_FLUSH)
284 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
285 _("Incomplete multibyte sequence in input"));
286 return G_CONVERTER_ERROR;
291 /* call g_iconv with NULL inbuf to cleanup shift state */
292 res = g_iconv (conv->iconv,
294 &outbufp, &out_left);
296 res = g_iconv (conv->iconv,
298 &outbufp, &out_left);
300 *bytes_read = inbufp - (char *)inbuf;
301 *bytes_written = outbufp - (char *)outbuf;
303 /* Don't report error if we converted anything */
304 if (res == (gsize) -1 && *bytes_read == 0)
311 /* Incomplete input text */
312 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
313 _("Incomplete multibyte sequence in input"));
317 /* Not enough destination space */
318 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
319 _("Not enough space in destination"));
323 /* Invalid code sequence */
324 if (conv->use_fallback)
327 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
328 _("Not enough space in destination"));
331 const char hex[] = "0123456789ABCDEF";
332 guint8 v = *(guint8 *)inbuf;
333 guint8 *out = (guint8 *)outbuf;
335 out[1] = hex[(v & 0xf0) >> 4];
336 out[2] = hex[(v & 0x0f) >> 0];
340 conv->n_fallback_errors++;
345 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
346 _("Invalid byte sequence in conversion input"));
350 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
351 _("Error during conversion: %s"),
355 ret = G_CONVERTER_ERROR;
360 ret = G_CONVERTER_CONVERTED;
363 (flags & G_CONVERTER_INPUT_AT_END))
364 ret = G_CONVERTER_FINISHED;
366 (flags & G_CONVERTER_FLUSH))
367 ret = G_CONVERTER_FLUSHED;
374 * g_charset_converter_set_use_fallback:
375 * @converter: a #GCharsetConverter
376 * @use_fallback: %TRUE to use fallbacks
378 * Sets the #GCharsetConverter:use-fallback property.
383 g_charset_converter_set_use_fallback (GCharsetConverter *converter,
384 gboolean use_fallback)
386 use_fallback = !!use_fallback;
388 if (converter->use_fallback != use_fallback)
390 converter->use_fallback = use_fallback;
391 g_object_notify (G_OBJECT (converter), "use-fallback");
396 * g_charset_converter_get_use_fallback:
397 * @converter: a #GCharsetConverter
399 * Gets the #GCharsetConverter:use-fallback property.
401 * Returns: %TRUE if fallbacks are used by @converter
406 g_charset_converter_get_use_fallback (GCharsetConverter *converter)
408 return converter->use_fallback;
412 * g_charset_converter_get_num_fallbacks:
413 * @converter: a #GCharsetConverter
415 * Gets the number of fallbacks that @converter has applied so far.
417 * Returns: the number of fallbacks that @converter has applied
422 g_charset_converter_get_num_fallbacks (GCharsetConverter *converter)
424 return converter->n_fallback_errors;
428 g_charset_converter_iface_init (GConverterIface *iface)
430 iface->convert = g_charset_converter_convert;
431 iface->reset = g_charset_converter_reset;
435 g_charset_converter_initable_init (GInitable *initable,
436 GCancellable *cancellable,
439 GCharsetConverter *conv;
441 g_return_val_if_fail (G_IS_CHARSET_CONVERTER (initable), FALSE);
443 conv = G_CHARSET_CONVERTER (initable);
445 if (cancellable != NULL)
447 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
448 _("Cancellable initialization not supported"));
453 g_iconv_open (conv->to, conv->from);
455 if (conv->iconv == NULL)
458 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
459 _("Conversion from character set '%s' to '%s' is not supported"),
460 conv->from, conv->to);
462 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
463 _("Could not open converter from '%s' to '%s'"),
464 conv->from, conv->to);
472 g_charset_converter_initable_iface_init (GInitableIface *iface)
474 iface->init = g_charset_converter_initable_init;
477 #define __G_CHARSET_CONVERTER_C__
478 #include "gioaliasdef.c"