From 0d86b25f91aeff168474280f4f5e03df779afc6d Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 18 Nov 2009 13:14:13 +0100 Subject: [PATCH] Add GConverter interface This is an interface for stateful conversions of data. Its a generic interface suitable for things like IConv, compression, decompression, and regexp replacement. --- gio/Makefile.am | 2 + gio/gconverter.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++ gio/gconverter.h | 94 +++++++++++++++++++ gio/gio.h | 1 + gio/gioenums.h | 34 +++++++ gio/giotypes.h | 1 + 6 files changed, 366 insertions(+) create mode 100644 gio/gconverter.c create mode 100644 gio/gconverter.h diff --git a/gio/Makefile.am b/gio/Makefile.am index 6df1c2a9..d0b6935e 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -187,6 +187,7 @@ libgio_2_0_la_SOURCES = \ gcancellable.c \ gcontenttype.c \ gcontenttypeprivate.h \ + gconverter.c \ gdatainputstream.c \ gdataoutputstream.c \ gdrive.c \ @@ -324,6 +325,7 @@ gio_headers = \ gbufferedoutputstream.h \ gcancellable.h \ gcontenttype.h \ + gconverter.h \ gdatainputstream.h \ gdataoutputstream.h \ gdrive.h \ diff --git a/gio/gconverter.c b/gio/gconverter.c new file mode 100644 index 00000000..49bca44c --- /dev/null +++ b/gio/gconverter.c @@ -0,0 +1,234 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + */ + +#include "config.h" +#include "gconverter.h" +#include "glibintl.h" + +#include "gioalias.h" + +/** + * SECTION:gconverter + * @short_description: Data conversion interface + * @include: gio/gio.h + * @see_also: #GInputStream, #GOutputStream + * + * #GConverter is implemented by objects that convert + * binary data in various ways. The conversion can be + * stateful and may fail at any place. + * + * Some example conversions are: character set conversion, + * compression, decompression and regular expression + * replace. + * + * Since: 2.24 + **/ + +static void g_converter_base_init (gpointer g_class); + +GType +g_converter_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + const GTypeInfo converter_info = + { + sizeof (GConverterIface), /* class_size */ + g_converter_base_init, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + GType g_define_type_id = + g_type_register_static (G_TYPE_INTERFACE, I_("GConverter"), + &converter_info, 0); + + g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT); + + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + +static void +g_converter_base_init (gpointer g_class) +{ +} + +/** + * g_converter_convert: + * @converter: a #GConverter. + * @inbuf: the buffer containing the data to convert. + * @inbuf_size: the number of bytes in @inbuf + * @outbuf: a buffer to write converted data in. + * @outbuf_size: the number of bytes in @outbuf, must be at least one + * @flags: a #GConvertFlags controlling the conversion details + * @bytes_read: will be set to the number of bytes read from @inbuf on success + * @bytes_written: will be set to the number of bytes written to @outbuf on success + * @error: location to store the error occuring, or %NULL to ignore + * + * This is the main operation used when converting data. It is to be called + * multiple times in a loop, and each time it will do some work, i.e. + * producing some output (in @outbuf) or consuming some input (from @inbuf) or + * both. If its not possible to do any work an error is returned. + * + * Note that a single call may not consume all input (or any input at all). + * Also a call may produce output even if given no input, due to state stored + * in the converter producing output. + * + * If any data was either produced or consumed, and then an error happens, then + * only the successful conversion is reported and the error is returned on the + * next call. + * + * A full conversion loop involves calling this method repeatedly, each time + * giving it new input and space output space. When there is no more input + * data after the data in @inbuf, the flag %G_CONVERTER_INPUT_AT_END must be set. + * The loop will be (unless some error happens) returning %G_CONVERTER_CONVERTED + * each time until all data is consumed and all output is produced, then + * %G_CONVERTER_FINISHED is returned instead. Note, that %G_CONVERTER_FINISHED + * may be returned even if %G_CONVERTER_INPUT_AT_END is not set, for instance + * in a decompression converter where the end of data is detectable from the + * data (and there might even be other data after the end of the compressed data). + * + * When some data has successfully been converted @bytes_read and is set to + * the number of bytes read from @inbuf, and @bytes_written is set to indicate + * how many bytes was written to @outbuf. If there are more data to output + * or consume (i.e. unless the G_CONVERTER_INPUT_AT_END is specified) then + * G_CONVERTER_CONVERTED is returned, and if no more data is to be output + * then G_CONVERTER_FINISHED is returned. + * + * On error %G_CONVERTER_ERROR is returned and @error is set accordingly. + * Some errors need special handling: + * + * %G_IO_ERROR_NO_SPACE is returned if there is not enough space + * to write the resulting converted data, the application should + * call the function again with a larger @outbuf to continue. + * + * %G_IO_ERROR_PARTIAL_INPUT is returned if there is not enough + * input to fully determine what the conversion should produce, + * and the %G_CONVERTER_INPUT_AT_END flag is not set. This happens for + * example with an incomplete multibyte sequence when converting text, + * or when a regexp matches up to the end of the input (and may match + * further input). It may also happen when @inbuf_size is zero and + * there is no more data to produce. + * + * When this happens the application should read more input and then + * call the function again. If further input shows that there is no + * more data call the function again with the same data but with + * the %G_CONVERTER_INPUT_AT_END flag set. This may cause the conversion + * to finish as e.g. in the regexp match case (or, to fail again with + * %G_IO_ERROR_PARTIAL_INPUT in e.g. a charset conversion where the + * input is actually partial). + * + * After g_converter_convert() has returned %G_CONVERTER_FINISHED the + * converter object is in an invalid state where its not allowed + * to call g_converter_convert() anymore. At this time you can only + * free the object or call g_converter_reset() to reset it to the + * initial state. + * + * If the flag %G_CONVERTER_FLUSH is set then conversion is modified + * to try to write out all internal state to the output. The application + * has to call the function multiple times with the flag set, and when + * the availible input has been consumed and all internal state has + * been produced then %G_CONVERTER_FLUSHED (or %G_CONVERTER_FINISHED if + * really at the end) is returned instead of %G_CONVERTER_CONVERTED. + * This is somewhat similar to what happens at the end of the input stream, + * but done in the middle of the data. + * + * This has different meanings for different conversions. For instance + * in a compression converter it would mean that we flush all the + * compression state into output such that if you uncompress the + * compressed data you get back all the input data. Doing this may + * make the final file larger due to padding though. Another example + * is a regexp conversion, where if you at the end of the flushed data + * have a match, but there is also a potential longer match. In the + * non-flushed case we would ask for more input, but when flushing we + * treat this as the end of input and do the match. + * + * Flushing is not always possible (like if a charset converter flushes + * at a partial multibyte sequence). Converters are supposed to try + * to produce as much output as possible and then return an error + * (typically %G_IO_ERROR_PARTIAL_INPUT). + * + * Returns: a #GConverterResult, %G_CONVERTER_ERROR on error. + * + * Since: 2.24 + **/ +GConverterResult +g_converter_convert (GConverter *converter, + const void *inbuf, + gsize inbuf_size, + void *outbuf, + gsize outbuf_size, + GConverterFlags flags, + gsize *bytes_read, + gsize *bytes_written, + GError **error) +{ + GConverterIface *iface; + + g_return_val_if_fail (G_IS_CONVERTER (converter), G_CONVERTER_ERROR); + g_return_val_if_fail (outbuf_size > 0, G_CONVERTER_ERROR); + + *bytes_read = 0; + *bytes_written = 0; + + iface = G_CONVERTER_GET_IFACE (converter); + + return (* iface->convert) (converter, + inbuf, inbuf_size, + outbuf, outbuf_size, + flags, + bytes_read, bytes_written, error); +} + +/** + * g_converter_reset: + * @converter: a #GConverter. + * + * Resets all internal state in the converter, making it behave + * as if it was just created. If the converter has any internal + * state that would produce output then that output is lost. + * + * Since: 2.24 + **/ +void +g_converter_reset (GConverter *converter) +{ + GConverterIface *iface; + + g_return_if_fail (G_IS_CONVERTER (converter)); + + iface = G_CONVERTER_GET_IFACE (converter); + + return (* iface->reset) (converter); +} + +#define __G_CONVERTER_C__ +#include "gioaliasdef.c" diff --git a/gio/gconverter.h b/gio/gconverter.h new file mode 100644 index 00000000..8892ee28 --- /dev/null +++ b/gio/gconverter.h @@ -0,0 +1,94 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + */ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __G_CONVERTER_H__ +#define __G_CONVERTER_H__ + +#include + +G_BEGIN_DECLS + +#define G_TYPE_CONVERTER (g_converter_get_type ()) +#define G_CONVERTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_CONVERTER, GConverter)) +#define G_IS_CONVERTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_CONVERTER)) +#define G_CONVERTER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_CONVERTER, GConverterIface)) + +/** + * GConverter: + * + * Seek object for streaming operations. + * + * Since: 2.24 + **/ +typedef struct _GConverterIface GConverterIface; + +/** + * GConverterIface: + * @g_iface: The parent interface. + * @convert: Converts data. + * + * Provides an interface for converting data from one type + * to another type. The conversion can be stateful + * and may fail at any place. + * + * Since: 2.24 + **/ +struct _GConverterIface +{ + GTypeInterface g_iface; + + /* Virtual Table */ + + GConverterResult (* convert) (GConverter *converter, + const void *inbuf, + gsize inbuf_size, + void *outbuf, + gsize outbuf_size, + GConverterFlags flags, + gsize *bytes_read, + gsize *bytes_written, + GError **error); + void (* reset) (GConverter *converter); +}; + +GType g_converter_get_type (void) G_GNUC_CONST; + +GConverterResult g_converter_convert (GConverter *converter, + const void *inbuf, + gsize inbuf_size, + void *outbuf, + gsize outbuf_size, + GConverterFlags flags, + gsize *bytes_read, + gsize *bytes_written, + GError **error); +void g_converter_reset (GConverter *converter); + + +G_END_DECLS + + +#endif /* __G_CONVERTER_H__ */ diff --git a/gio/gio.h b/gio/gio.h index ad175030..d2e168ea 100644 --- a/gio/gio.h +++ b/gio/gio.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/gio/gioenums.h b/gio/gioenums.h index fea7d4e3..808e223e 100644 --- a/gio/gioenums.h +++ b/gio/gioenums.h @@ -46,6 +46,40 @@ typedef enum { G_APP_INFO_CREATE_SUPPORTS_URIS = (1 << 1) /*< nick=supports-uris >*/ } GAppInfoCreateFlags; +/** + * GConverterFlags: + * @G_CONVERTER_NO_FLAGS: No flags. + * @G_CONVERTER_INPUT_AT_END: At end of input data + * @G_CONVERTER_FLUSH: Flush data + * + * Flags used when calling a g_converter_convert(). + * + * Since: 2.24 + */ +typedef enum { + G_CONVERTER_NO_FLAGS = 0, /*< nick=none >*/ + G_CONVERTER_INPUT_AT_END = (1 << 0), /*< nick=input-at-end >*/ + G_CONVERTER_FLUSH = (1 << 1), /*< nick=flush >*/ +} GConverterFlags; + +/** + * GConverterResult: + * @G_CONVERTER_ERROR: There was an error during conversion. + * @G_CONVERTER_CONVERTED: Some data was consumed or produced + * @G_CONVERTER_FINISHED: The conversion is finished + * @G_CONVERTER_FLUSHED: Flushing is finished + * + * Results returned from g_converter_convert(). + * + * Since: 2.24 + */ +typedef enum { + G_CONVERTER_ERROR = 0, /*< nick=error >*/ + G_CONVERTER_CONVERTED = 1, /*< nick=converted >*/ + G_CONVERTER_FINISHED = 2, /*< nick=finished >*/ + G_CONVERTER_FLUSHED = 3, /*< nick=flushed >*/ +} GConverterResult; + /** * GDataStreamByteOrder: diff --git a/gio/giotypes.h b/gio/giotypes.h index 9ee099c7..adb6341d 100644 --- a/gio/giotypes.h +++ b/gio/giotypes.h @@ -38,6 +38,7 @@ typedef struct _GAsyncInitable GAsyncInitable; typedef struct _GBufferedInputStream GBufferedInputStream; typedef struct _GBufferedOutputStream GBufferedOutputStream; typedef struct _GCancellable GCancellable; +typedef struct _GConverter GConverter; typedef struct _GDataInputStream GDataInputStream; /** -- 2.34.1