[glib] Add GConverter interface



commit 0d86b25f91aeff168474280f4f5e03df779afc6d
Author: Alexander Larsson <alexl redhat com>
Date:   Wed Nov 18 13:14:13 2009 +0100

    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(+), 0 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index 6df1c2a..d0b6935 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 0000000..49bca44
--- /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 <alexl redhat com>
+ */
+
+#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 0000000..8892ee2
--- /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 <alexl redhat com>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_CONVERTER_H__
+#define __G_CONVERTER_H__
+
+#include <gio/giotypes.h>
+
+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 ad17503..d2e168e 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -34,6 +34,7 @@
 #include <gio/gbufferedoutputstream.h>
 #include <gio/gcancellable.h>
 #include <gio/gcontenttype.h>
+#include <gio/gconverter.h>
 #include <gio/gdatainputstream.h>
 #include <gio/gdataoutputstream.h>
 #include <gio/gdrive.h>
diff --git a/gio/gioenums.h b/gio/gioenums.h
index fea7d4e..808e223 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 9ee099c..adb6341 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;
 
 /**



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]