1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * gsf-output-iconv.c: wrapper to convert character sets.
5 * Copyright (C) 2005-2006 Morten Welinder (terra@gnome.org)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2.1 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 #include <gsf-config.h>
23 #include <gsf/gsf-output-iconv.h>
24 #include <gsf/gsf-output-impl.h>
25 #include <gsf/gsf-impl-utils.h>
26 #include <gsf/gsf-utils.h>
30 #define BUF_SIZE 0x400
32 static GObjectClass *parent_class;
34 struct _GsfOutputIconv {
55 * gsf_output_iconv_new :
56 * @sink : The underlying data source.
57 * @dst : The target character set.
58 * @src : The source character set.
60 * Adds a reference to @sink.
62 * Returns: a new GsfOutput object or %NULL.
65 gsf_output_iconv_new (GsfOutput *sink, char const *dst, char const *src)
68 g_return_val_if_fail (GSF_IS_OUTPUT (sink), NULL);
70 if (!dst) dst = "UTF-8";
71 if (!src) src = "UTF-8";
72 g_free (g_convert ("", 0, dst, src, NULL, NULL, &error));
79 return g_object_new (GSF_OUTPUT_ICONV_TYPE,
82 "output-charset", dst,
87 gsf_output_iconv_finalize (GObject *obj)
89 GsfOutputIconv *ic = (GsfOutputIconv *)obj;
92 g_object_unref (G_OBJECT (ic->sink));
93 g_free (ic->input_charset);
94 g_free (ic->output_charset);
97 parent_class->finalize (obj);
101 iconv_flush (GsfOutputIconv *ic, gboolean must_empty)
103 if (gsf_output_error (GSF_OUTPUT (ic)))
106 if (ic->buf_len > 0) {
107 gsize bytes_read, bytes_written;
109 char *data = g_convert_with_fallback (ic->buf, ic->buf_len,
116 if (data == NULL || bytes_read <= 0) {
117 gsf_output_set_error (GSF_OUTPUT (ic),
119 "Failed to convert string");
122 ic->buf_len -= bytes_read;
123 g_memmove (ic->buf, ic->buf + bytes_read, ic->buf_len);
125 ok = gsf_output_write (ic->sink, bytes_written, data);
127 gsf_output_set_error (GSF_OUTPUT (ic),
134 return ok && (!must_empty || ic->buf_len == 0);
140 gsf_output_iconv_write (GsfOutput *output,
141 size_t num_bytes, guint8 const *data)
143 GsfOutputIconv *ic = GSF_OUTPUT_ICONV (output);
145 g_return_val_if_fail (data, FALSE);
147 while (num_bytes > 0) {
148 if (gsf_output_error (output))
150 if (ic->buf_len == BUF_SIZE)
151 iconv_flush (ic, FALSE);
153 size_t count = MIN (BUF_SIZE - ic->buf_len, num_bytes);
154 memcpy (ic->buf + ic->buf_len, data, count);
155 ic->buf_len += count;
165 gsf_output_iconv_seek (G_GNUC_UNUSED GsfOutput *output,
166 G_GNUC_UNUSED gsf_off_t offset,
167 G_GNUC_UNUSED GSeekType whence)
173 gsf_output_iconv_close (GsfOutput *output)
175 if (!gsf_output_error (output)) {
176 GsfOutputIconv *ic = GSF_OUTPUT_ICONV (output);
178 if (!iconv_flush (ic, TRUE))
186 gsf_output_iconv_init (GObject *obj)
188 GsfOutputIconv *ic = GSF_OUTPUT_ICONV (obj);
190 ic->buf = g_malloc (BUF_SIZE);
195 gsf_output_iconv_get_property (GObject *object,
200 GsfOutputIconv *ic = (GsfOutputIconv *)object;
202 switch (property_id) {
204 g_value_set_object (value, ic->sink);
206 case PROP_INPUT_CHARSET:
207 g_value_set_string (value, ic->input_charset);
209 case PROP_OUTPUT_CHARSET:
210 g_value_set_string (value, ic->output_charset);
213 g_value_set_string (value, ic->fallback);
216 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
222 gsf_output_iconv_set_sink (GsfOutputIconv *ic, GsfOutput *sink)
224 g_return_if_fail (GSF_IS_OUTPUT (sink));
227 g_object_unref (ic->sink);
232 gsf_output_iconv_set_property (GObject *object,
237 GsfOutputIconv *ic = (GsfOutputIconv *)object;
240 switch (property_id) {
242 gsf_output_iconv_set_sink (ic, g_value_get_object (value));
244 case PROP_INPUT_CHARSET:
245 ic->input_charset = g_strdup (g_value_get_string (value));
247 case PROP_OUTPUT_CHARSET:
248 ic->output_charset = g_strdup (g_value_get_string (value));
251 scopy = g_strdup (g_value_get_string (value));
252 g_free (ic->fallback);
253 ic->fallback = scopy;
256 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
262 gsf_output_iconv_class_init (GObjectClass *gobject_class)
264 GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
266 gobject_class->finalize = gsf_output_iconv_finalize;
267 gobject_class->set_property = gsf_output_iconv_set_property;
268 gobject_class->get_property = gsf_output_iconv_get_property;
269 output_class->Write = gsf_output_iconv_write;
270 output_class->Seek = gsf_output_iconv_seek;
271 output_class->Close = gsf_output_iconv_close;
273 g_object_class_install_property
276 g_param_spec_object ("sink", "Sink",
277 "Where the converted data is written.",
281 G_PARAM_CONSTRUCT_ONLY));
282 g_object_class_install_property
285 g_param_spec_string ("input-charset", "Input Charset",
286 "The character set to convert from.",
290 G_PARAM_CONSTRUCT_ONLY));
291 g_object_class_install_property
294 g_param_spec_string ("output-charset", "Output Charset",
295 "The character set to convert to.",
299 G_PARAM_CONSTRUCT_ONLY));
301 * GsfOutputIconv:fallback:
303 * Either NULL or a UTF-8 string (representable in the target encoding)
304 * to convert and output in place of characters that cannot be represented
305 * in the target encoding. NULL means use \u1234 or \U12345678 format.
307 g_object_class_install_property
310 g_param_spec_string ("fallback", "Fallback",
311 "The string to use for invalid characters.",
316 parent_class = g_type_class_peek_parent (gobject_class);
319 GSF_CLASS (GsfOutputIconv, gsf_output_iconv,
320 gsf_output_iconv_class_init, gsf_output_iconv_init,