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 "ginitable.h"
42 * SECTION:gcharsetconverter
43 * @short_description: Convert between charsets
46 * #GCharsetConverter is an implementation of #GConverter based on
50 static void g_charset_converter_iface_init (GConverterIface
*iface
);
51 static void g_charset_converter_initable_iface_init (GInitableIface
*iface
);
56 * Conversions between character sets.
58 struct _GCharsetConverter
60 GObject parent_instance
;
65 gboolean use_fallback
;
66 guint n_fallback_errors
;
69 G_DEFINE_TYPE_WITH_CODE (GCharsetConverter
, g_charset_converter
, G_TYPE_OBJECT
,
70 G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER
,
71 g_charset_converter_iface_init
);
72 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE
,
73 g_charset_converter_initable_iface_init
))
76 g_charset_converter_finalize (GObject
*object
)
78 GCharsetConverter
*conv
;
80 conv
= G_CHARSET_CONVERTER (object
);
85 g_iconv_close (conv
->iconv
);
87 G_OBJECT_CLASS (g_charset_converter_parent_class
)->finalize (object
);
91 g_charset_converter_set_property (GObject
*object
,
96 GCharsetConverter
*conv
;
98 conv
= G_CHARSET_CONVERTER (object
);
102 case PROP_TO_CHARSET
:
104 conv
->to
= g_value_dup_string (value
);
107 case PROP_FROM_CHARSET
:
109 conv
->from
= g_value_dup_string (value
);
112 case PROP_USE_FALLBACK
:
113 conv
->use_fallback
= g_value_get_boolean (value
);
117 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
124 g_charset_converter_get_property (GObject
*object
,
129 GCharsetConverter
*conv
;
131 conv
= G_CHARSET_CONVERTER (object
);
135 case PROP_TO_CHARSET
:
136 g_value_set_string (value
, conv
->to
);
139 case PROP_FROM_CHARSET
:
140 g_value_set_string (value
, conv
->from
);
143 case PROP_USE_FALLBACK
:
144 g_value_set_boolean (value
, conv
->use_fallback
);
148 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
154 g_charset_converter_class_init (GCharsetConverterClass
*klass
)
156 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
158 gobject_class
->finalize
= g_charset_converter_finalize
;
159 gobject_class
->get_property
= g_charset_converter_get_property
;
160 gobject_class
->set_property
= g_charset_converter_set_property
;
162 g_object_class_install_property (gobject_class
,
164 g_param_spec_string ("to-charset",
166 P_("The character encoding to convert to"),
168 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
169 G_PARAM_STATIC_STRINGS
));
170 g_object_class_install_property (gobject_class
,
172 g_param_spec_string ("from-charset",
174 P_("The character encoding to convert from"),
176 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
177 G_PARAM_STATIC_STRINGS
));
178 g_object_class_install_property (gobject_class
,
180 g_param_spec_boolean ("use-fallback",
181 P_("Fallback enabled"),
182 P_("Use fallback (of form \\<hexval>) for invalid bytes"),
186 G_PARAM_STATIC_STRINGS
));
190 g_charset_converter_init (GCharsetConverter
*local
)
196 * g_charset_converter_new:
197 * @to_charset: destination charset
198 * @from_charset: source charset
199 * @error: #GError for error reporting, or %NULL to ignore.
201 * Creates a new #GCharsetConverter.
203 * Returns: a new #GCharsetConverter or %NULL on error.
208 g_charset_converter_new (const gchar
*to_charset
,
209 const gchar
*from_charset
,
212 GCharsetConverter
*conv
;
214 conv
= g_initable_new (G_TYPE_CHARSET_CONVERTER
,
216 "to-charset", to_charset
,
217 "from-charset", from_charset
,
224 g_charset_converter_reset (GConverter
*converter
)
226 GCharsetConverter
*conv
= G_CHARSET_CONVERTER (converter
);
228 if (conv
->iconv
== NULL
)
230 g_warning ("Invalid object, not initialized");
234 g_iconv (conv
->iconv
, NULL
, NULL
, NULL
, NULL
);
235 conv
->n_fallback_errors
= 0;
238 static GConverterResult
239 g_charset_converter_convert (GConverter
*converter
,
244 GConverterFlags flags
,
246 gsize
*bytes_written
,
249 GCharsetConverter
*conv
;
251 GConverterResult ret
;
252 gchar
*inbufp
, *outbufp
;
253 gsize in_left
, out_left
;
257 conv
= G_CHARSET_CONVERTER (converter
);
259 if (conv
->iconv
== NULL
)
261 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_NOT_INITIALIZED
,
262 _("Invalid object, not initialized"));
263 return G_CONVERTER_ERROR
;
266 inbufp
= (char *)inbuf
;
267 outbufp
= (char *)outbuf
;
268 in_left
= inbuf_size
;
269 out_left
= outbuf_size
;
272 /* if there is not input try to flush the data */
275 if (flags
& G_CONVERTER_INPUT_AT_END
||
276 flags
& G_CONVERTER_FLUSH
)
282 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_PARTIAL_INPUT
,
283 _("Incomplete multibyte sequence in input"));
284 return G_CONVERTER_ERROR
;
289 /* call g_iconv with NULL inbuf to cleanup shift state */
290 res
= g_iconv (conv
->iconv
,
292 &outbufp
, &out_left
);
294 res
= g_iconv (conv
->iconv
,
296 &outbufp
, &out_left
);
298 *bytes_read
= inbufp
- (char *)inbuf
;
299 *bytes_written
= outbufp
- (char *)outbuf
;
301 /* Don't report error if we converted anything */
302 if (res
== (gsize
) -1 && *bytes_read
== 0)
309 /* Incomplete input text */
310 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_PARTIAL_INPUT
,
311 _("Incomplete multibyte sequence in input"));
315 /* Not enough destination space */
316 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_NO_SPACE
,
317 _("Not enough space in destination"));
321 /* Invalid code sequence */
322 if (conv
->use_fallback
)
325 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_NO_SPACE
,
326 _("Not enough space in destination"));
329 const char hex
[] = "0123456789ABCDEF";
330 guint8 v
= *(guint8
*)inbuf
;
331 guint8
*out
= (guint8
*)outbuf
;
333 out
[1] = hex
[(v
& 0xf0) >> 4];
334 out
[2] = hex
[(v
& 0x0f) >> 0];
338 conv
->n_fallback_errors
++;
343 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_INVALID_DATA
,
344 _("Invalid byte sequence in conversion input"));
348 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
349 _("Error during conversion: %s"),
353 ret
= G_CONVERTER_ERROR
;
358 ret
= G_CONVERTER_CONVERTED
;
361 (flags
& G_CONVERTER_INPUT_AT_END
))
362 ret
= G_CONVERTER_FINISHED
;
364 (flags
& G_CONVERTER_FLUSH
))
365 ret
= G_CONVERTER_FLUSHED
;
372 * g_charset_converter_set_use_fallback:
373 * @converter: a #GCharsetConverter
374 * @use_fallback: %TRUE to use fallbacks
376 * Sets the #GCharsetConverter:use-fallback property.
381 g_charset_converter_set_use_fallback (GCharsetConverter
*converter
,
382 gboolean use_fallback
)
384 use_fallback
= !!use_fallback
;
386 if (converter
->use_fallback
!= use_fallback
)
388 converter
->use_fallback
= use_fallback
;
389 g_object_notify (G_OBJECT (converter
), "use-fallback");
394 * g_charset_converter_get_use_fallback:
395 * @converter: a #GCharsetConverter
397 * Gets the #GCharsetConverter:use-fallback property.
399 * Returns: %TRUE if fallbacks are used by @converter
404 g_charset_converter_get_use_fallback (GCharsetConverter
*converter
)
406 return converter
->use_fallback
;
410 * g_charset_converter_get_num_fallbacks:
411 * @converter: a #GCharsetConverter
413 * Gets the number of fallbacks that @converter has applied so far.
415 * Returns: the number of fallbacks that @converter has applied
420 g_charset_converter_get_num_fallbacks (GCharsetConverter
*converter
)
422 return converter
->n_fallback_errors
;
426 g_charset_converter_iface_init (GConverterIface
*iface
)
428 iface
->convert
= g_charset_converter_convert
;
429 iface
->reset
= g_charset_converter_reset
;
433 g_charset_converter_initable_init (GInitable
*initable
,
434 GCancellable
*cancellable
,
437 GCharsetConverter
*conv
;
439 g_return_val_if_fail (G_IS_CHARSET_CONVERTER (initable
), FALSE
);
441 conv
= G_CHARSET_CONVERTER (initable
);
443 if (cancellable
!= NULL
)
445 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_NOT_SUPPORTED
,
446 _("Cancellable initialization not supported"));
451 g_iconv_open (conv
->to
, conv
->from
);
453 if (conv
->iconv
== (GIConv
)-1)
456 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_NOT_SUPPORTED
,
457 _("Conversion from character set '%s' to '%s' is not supported"),
458 conv
->from
, conv
->to
);
460 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
461 _("Could not open converter from '%s' to '%s'"),
462 conv
->from
, conv
->to
);
470 g_charset_converter_initable_iface_init (GInitableIface
*iface
)
472 iface
->init
= g_charset_converter_initable_init
;