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"
43 * SECTION:gcharsetconverter
44 * @short_description: Convert between charsets
47 * #GCharsetConverter is an implementation of #GConverter based on
51 static void g_charset_converter_iface_init (GConverterIface
*iface
);
52 static void g_charset_converter_initable_iface_init (GInitableIface
*iface
);
57 * Conversions between character sets.
59 struct _GCharsetConverter
61 GObject parent_instance
;
66 gboolean use_fallback
;
67 guint n_fallback_errors
;
70 G_DEFINE_TYPE_WITH_CODE (GCharsetConverter
, g_charset_converter
, G_TYPE_OBJECT
,
71 G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER
,
72 g_charset_converter_iface_init
);
73 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE
,
74 g_charset_converter_initable_iface_init
))
77 g_charset_converter_finalize (GObject
*object
)
79 GCharsetConverter
*conv
;
81 conv
= G_CHARSET_CONVERTER (object
);
86 g_iconv_close (conv
->iconv
);
88 G_OBJECT_CLASS (g_charset_converter_parent_class
)->finalize (object
);
92 g_charset_converter_set_property (GObject
*object
,
97 GCharsetConverter
*conv
;
99 conv
= G_CHARSET_CONVERTER (object
);
103 case PROP_TO_CHARSET
:
105 conv
->to
= g_value_dup_string (value
);
108 case PROP_FROM_CHARSET
:
110 conv
->from
= g_value_dup_string (value
);
113 case PROP_USE_FALLBACK
:
114 conv
->use_fallback
= g_value_get_boolean (value
);
118 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
125 g_charset_converter_get_property (GObject
*object
,
130 GCharsetConverter
*conv
;
132 conv
= G_CHARSET_CONVERTER (object
);
136 case PROP_TO_CHARSET
:
137 g_value_set_string (value
, conv
->to
);
140 case PROP_FROM_CHARSET
:
141 g_value_set_string (value
, conv
->from
);
144 case PROP_USE_FALLBACK
:
145 g_value_set_boolean (value
, conv
->use_fallback
);
149 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
155 g_charset_converter_class_init (GCharsetConverterClass
*klass
)
157 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
159 gobject_class
->finalize
= g_charset_converter_finalize
;
160 gobject_class
->get_property
= g_charset_converter_get_property
;
161 gobject_class
->set_property
= g_charset_converter_set_property
;
163 g_object_class_install_property (gobject_class
,
165 g_param_spec_string ("to-charset",
167 P_("The character encoding to convert to"),
169 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
170 G_PARAM_STATIC_STRINGS
));
171 g_object_class_install_property (gobject_class
,
173 g_param_spec_string ("from-charset",
175 P_("The character encoding to convert from"),
177 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
178 G_PARAM_STATIC_STRINGS
));
179 g_object_class_install_property (gobject_class
,
181 g_param_spec_boolean ("use-fallback",
182 P_("Fallback enabled"),
183 P_("Use fallback (of form \\<hexval>) for invalid bytes"),
187 G_PARAM_STATIC_STRINGS
));
191 g_charset_converter_init (GCharsetConverter
*local
)
197 * g_charset_converter_new:
198 * @to_charset: destination charset
199 * @from_charset: source charset
200 * @error: #GError for error reporting, or %NULL to ignore.
202 * Creates a new #GCharsetConverter.
204 * Returns: a new #GCharsetConverter or %NULL on error.
209 g_charset_converter_new (const gchar
*to_charset
,
210 const gchar
*from_charset
,
213 GCharsetConverter
*conv
;
215 conv
= g_initable_new (G_TYPE_CHARSET_CONVERTER
,
217 "to-charset", to_charset
,
218 "from-charset", from_charset
,
225 g_charset_converter_reset (GConverter
*converter
)
227 GCharsetConverter
*conv
= G_CHARSET_CONVERTER (converter
);
229 if (conv
->iconv
== NULL
)
231 g_warning ("Invalid object, not initialized");
235 g_iconv (conv
->iconv
, NULL
, NULL
, NULL
, NULL
);
236 conv
->n_fallback_errors
= 0;
239 static GConverterResult
240 g_charset_converter_convert (GConverter
*converter
,
245 GConverterFlags flags
,
247 gsize
*bytes_written
,
250 GCharsetConverter
*conv
;
252 GConverterResult ret
;
253 gchar
*inbufp
, *outbufp
;
254 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 inbufp
= (char *)inbuf
;
268 outbufp
= (char *)outbuf
;
269 in_left
= inbuf_size
;
270 out_left
= outbuf_size
;
273 /* if there is not input try to flush the data */
276 if (flags
& G_CONVERTER_INPUT_AT_END
||
277 flags
& G_CONVERTER_FLUSH
)
283 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_PARTIAL_INPUT
,
284 _("Incomplete multibyte sequence in input"));
285 return G_CONVERTER_ERROR
;
290 /* call g_iconv with NULL inbuf to cleanup shift state */
291 res
= g_iconv (conv
->iconv
,
293 &outbufp
, &out_left
);
295 res
= g_iconv (conv
->iconv
,
297 &outbufp
, &out_left
);
299 *bytes_read
= inbufp
- (char *)inbuf
;
300 *bytes_written
= outbufp
- (char *)outbuf
;
302 /* Don't report error if we converted anything */
303 if (res
== (gsize
) -1 && *bytes_read
== 0)
310 /* Incomplete input text */
311 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_PARTIAL_INPUT
,
312 _("Incomplete multibyte sequence in input"));
316 /* Not enough destination space */
317 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_NO_SPACE
,
318 _("Not enough space in destination"));
322 /* Invalid code sequence */
323 if (conv
->use_fallback
)
326 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_NO_SPACE
,
327 _("Not enough space in destination"));
330 const char hex
[] = "0123456789ABCDEF";
331 guint8 v
= *(guint8
*)inbuf
;
332 guint8
*out
= (guint8
*)outbuf
;
334 out
[1] = hex
[(v
& 0xf0) >> 4];
335 out
[2] = hex
[(v
& 0x0f) >> 0];
339 conv
->n_fallback_errors
++;
344 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_INVALID_DATA
,
345 _("Invalid byte sequence in conversion input"));
349 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
350 _("Error during conversion: %s"),
354 ret
= G_CONVERTER_ERROR
;
359 ret
= G_CONVERTER_CONVERTED
;
362 (flags
& G_CONVERTER_INPUT_AT_END
))
363 ret
= G_CONVERTER_FINISHED
;
365 (flags
& G_CONVERTER_FLUSH
))
366 ret
= G_CONVERTER_FLUSHED
;
373 * g_charset_converter_set_use_fallback:
374 * @converter: a #GCharsetConverter
375 * @use_fallback: %TRUE to use fallbacks
377 * Sets the #GCharsetConverter:use-fallback property.
382 g_charset_converter_set_use_fallback (GCharsetConverter
*converter
,
383 gboolean use_fallback
)
385 use_fallback
= !!use_fallback
;
387 if (converter
->use_fallback
!= use_fallback
)
389 converter
->use_fallback
= use_fallback
;
390 g_object_notify (G_OBJECT (converter
), "use-fallback");
395 * g_charset_converter_get_use_fallback:
396 * @converter: a #GCharsetConverter
398 * Gets the #GCharsetConverter:use-fallback property.
400 * Returns: %TRUE if fallbacks are used by @converter
405 g_charset_converter_get_use_fallback (GCharsetConverter
*converter
)
407 return converter
->use_fallback
;
411 * g_charset_converter_get_num_fallbacks:
412 * @converter: a #GCharsetConverter
414 * Gets the number of fallbacks that @converter has applied so far.
416 * Returns: the number of fallbacks that @converter has applied
421 g_charset_converter_get_num_fallbacks (GCharsetConverter
*converter
)
423 return converter
->n_fallback_errors
;
427 g_charset_converter_iface_init (GConverterIface
*iface
)
429 iface
->convert
= g_charset_converter_convert
;
430 iface
->reset
= g_charset_converter_reset
;
434 g_charset_converter_initable_init (GInitable
*initable
,
435 GCancellable
*cancellable
,
438 GCharsetConverter
*conv
;
440 g_return_val_if_fail (G_IS_CHARSET_CONVERTER (initable
), FALSE
);
442 conv
= G_CHARSET_CONVERTER (initable
);
444 if (cancellable
!= NULL
)
446 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_NOT_SUPPORTED
,
447 _("Cancellable initialization not supported"));
452 g_iconv_open (conv
->to
, conv
->from
);
454 if (conv
->iconv
== (GIConv
)-1)
457 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_NOT_SUPPORTED
,
458 _("Conversion from character set '%s' to '%s' is not supported"),
459 conv
->from
, conv
->to
);
461 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
462 _("Could not open converter from '%s' to '%s'"),
463 conv
->from
, conv
->to
);
471 g_charset_converter_initable_iface_init (GInitableIface
*iface
)
473 iface
->init
= g_charset_converter_initable_init
;