[glib/wip/gmarkupreader: 2/4] GMarkupReader: new GIO stream-based markup parser
- From: Ryan Lortie <desrt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/gmarkupreader: 2/4] GMarkupReader: new GIO stream-based markup parser
- Date: Mon, 28 Jul 2014 09:18:53 +0000 (UTC)
commit 2f6982bba0a79d7881b5c1349a233d4518c9e6ed
Author: Ryan Lortie <desrt desrt ca>
Date: Mon Jul 28 11:12:53 2014 +0200
GMarkupReader: new GIO stream-based markup parser
Add GMarkupReader which is a new GMarkup-style parser that reads from a
GInputStream and operates as a sort of iterator that gets advanced to
each token in sequence and then inspected.
The API makes it quite nice to write parsers where the function nesting
(in C) follows the nesting of the elements in the file being parsed.
It's also possible to use this new class to write async or
partially-async parsers in which the stream is advanced until reading
would block (via GPollableInputStream) and only then is an async call
made.
gio/Makefile.am | 2 +
gio/gio.h | 1 +
gio/gmarkupreader.c | 738 +++++++++++++++++++++++++++++++++++++++++++++++++++
gio/gmarkupreader.h | 136 ++++++++++
4 files changed, 877 insertions(+), 0 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index e993e2f..82ff872 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -395,6 +395,7 @@ libgio_2_0_la_SOURCES = \
gioprivate.h \
giowin32-priv.h \
gloadableicon.c \
+ gmarkupreader.c \
gmount.c \
gmemoryinputstream.c \
gmemoryoutputstream.c \
@@ -570,6 +571,7 @@ gio_headers = \
gioscheduler.h \
giostream.h \
gloadableicon.h \
+ gmarkupreader.h \
gmount.h \
gmemoryinputstream.h \
gmemoryoutputstream.h \
diff --git a/gio/gio.h b/gio/gio.h
index 3cc4af3..b92ab1e 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -85,6 +85,7 @@
#include <gio/gioscheduler.h>
#include <gio/giostream.h>
#include <gio/gloadableicon.h>
+#include <gio/gmarkupreader.h>
#include <gio/gmemoryinputstream.h>
#include <gio/gmemoryoutputstream.h>
#include <gio/gmount.h>
diff --git a/gio/gmarkupreader.c b/gio/gmarkupreader.c
new file mode 100644
index 0000000..d6be4ee
--- /dev/null
+++ b/gio/gmarkupreader.c
@@ -0,0 +1,738 @@
+/*
+ * Copyright © 2013 Canonical Limited
+ *
+ * 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 licence, 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: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "config.h"
+
+#include "gmarkupreader.h"
+
+#include "glib/gmarkup-private.h"
+#include "glib/glib-private.h"
+
+#include <gio.h>
+
+typedef enum
+{
+ READER_STATE_NONE,
+ READER_STATE_EOF,
+ READER_STATE_PENDING,
+ READER_STATE_START_ELEMENT,
+ READER_STATE_END_ELEMENT,
+ READER_STATE_TEXT,
+ READER_STATE_PASSTHROUGH,
+ READER_STATE_ERROR
+} GMarkupReaderState;
+
+struct _GMarkupReader
+{
+ GObject parent_instance;
+
+ GMarkupParseContext *context;
+ GInputStream *stream;
+ GPollableInputStream *pollable;
+ GMarkupParser parser;
+
+ gchar *buffer;
+
+ GMarkupReaderState state;
+ gchar *element_name;
+ gchar **attribute_names;
+ gchar **attribute_values;
+ GBytes *content;
+};
+
+typedef GObjectClass GMarkupReaderClass;
+
+G_DEFINE_TYPE (GMarkupReader, g_markup_reader, G_TYPE_OBJECT)
+
+enum
+{
+ PROP_0,
+ PROP_STREAM,
+ PROP_FLAGS
+};
+
+static void
+g_markup_reader_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ GMarkupReader *reader = user_data;
+
+ g_assert (reader->state == READER_STATE_PENDING);
+
+ reader->element_name = g_strdup (element_name);
+ reader->attribute_names = g_strdupv ((gchar **) attribute_names);
+ reader->attribute_values = g_strdupv ((gchar **) attribute_values);
+ reader->state = READER_STATE_START_ELEMENT;
+}
+
+static void
+g_markup_reader_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ GMarkupReader *reader = user_data;
+
+ g_assert (reader->state == READER_STATE_PENDING);
+
+ reader->element_name = g_strdup (element_name);
+ reader->state = READER_STATE_END_ELEMENT;
+}
+
+static void
+g_markup_reader_text (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_length,
+ gpointer user_data,
+ GError **error)
+{
+ GMarkupReader *reader = user_data;
+
+ g_assert (reader->state == READER_STATE_PENDING);
+
+ reader->content = g_bytes_new (text, text_length);
+ reader->state = READER_STATE_TEXT;
+}
+
+static void
+g_markup_reader_passthrough (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_length,
+ gpointer user_data,
+ GError **error)
+{
+ GMarkupReader *reader = user_data;
+
+ g_assert (reader->state == READER_STATE_PENDING);
+
+ reader->content = g_bytes_new (text, text_length);
+ reader->state = READER_STATE_PASSTHROUGH;
+}
+
+static void
+g_markup_reader_set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GMarkupReader *reader = G_MARKUP_READER (object);
+
+ switch (prop_id)
+ {
+ case PROP_STREAM:
+ reader->stream = g_value_dup_object (value);
+
+ if (reader->stream != NULL && G_IS_POLLABLE_INPUT_STREAM (reader->stream) &&
+ g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (reader->stream)))
+ reader->pollable = G_POLLABLE_INPUT_STREAM (reader->stream);
+ else
+ reader->pollable = NULL;
+
+ break;
+
+ case PROP_FLAGS:
+ reader->context->flags = g_value_get_uint (value);
+ if (reader->context->flags & G_MARKUP_IGNORE_PASSTHROUGH)
+ reader->parser.passthrough = NULL;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+g_markup_reader_finalize (GObject *object)
+{
+ GMarkupReader *reader = G_MARKUP_READER (object);
+
+ g_markup_parse_context_free (reader->context);
+ g_object_unref (reader->stream);
+ g_free (reader->element_name);
+ g_strfreev (reader->attribute_names);
+ g_strfreev (reader->attribute_values);
+ g_free (reader->buffer);
+ if (reader->content)
+ g_bytes_unref (reader->content);
+
+ G_OBJECT_CLASS (g_markup_reader_parent_class)->finalize (object);
+}
+
+static void
+g_markup_reader_init (GMarkupReader *reader)
+{
+ reader->parser.start_element = g_markup_reader_start_element;
+ reader->parser.end_element = g_markup_reader_end_element;
+ reader->parser.text = g_markup_reader_text;
+ reader->parser.passthrough = g_markup_reader_passthrough;
+
+ reader->context = g_markup_parse_context_new (&reader->parser, 0, reader, NULL);
+}
+
+static void
+g_markup_reader_class_init (GMarkupReaderClass *class)
+{
+ class->set_property = g_markup_reader_set_property;
+ class->finalize = g_markup_reader_finalize;
+
+ g_object_class_install_property (class, PROP_STREAM,
+ g_param_spec_object ("stream", "stream", "input stream",
+ G_TYPE_INPUT_STREAM, G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (class, PROP_FLAGS,
+ g_param_spec_uint ("flags", "flags", "flags",
+ 0, G_MAXUINT, 0, G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+}
+
+GMarkupReader *
+g_markup_reader_new (GInputStream *stream,
+ GMarkupParseFlags flags)
+{
+ return g_object_new (G_TYPE_MARKUP_READER,
+ "stream", stream,
+ "flags", flags,
+ NULL);
+}
+
+static gboolean
+g_markup_reader_handle_read_result (GMarkupReader *reader,
+ gssize result,
+ GError **error)
+{
+ if (result < 0)
+ {
+ g_assert (error == NULL || *error != NULL);
+ reader->state = READER_STATE_ERROR;
+ return FALSE;
+ }
+
+ else if (result == 0)
+ {
+ if (g_markup_parse_context_end_parse (reader->context, error))
+ {
+ reader->state = READER_STATE_EOF;
+ return TRUE;
+ }
+ else
+ {
+ reader->state = READER_STATE_ERROR;
+ return FALSE;
+ }
+ }
+
+ else
+ {
+ reader->context->current_text = reader->buffer;
+ reader->context->current_text_end = reader->buffer + result;
+ reader->context->iter = reader->context->current_text;
+ reader->context->start = reader->context->iter;
+
+ return TRUE;
+ }
+}
+
+static gboolean
+g_markup_reader_ensure_data (GMarkupReader *reader,
+ gboolean non_blocking,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const guint size = 1024 * 1024;
+ gssize result;
+
+ g_assert (reader->state == READER_STATE_PENDING);
+
+ if (reader->context->iter != reader->context->current_text_end)
+ return TRUE;
+
+ if (!reader->buffer)
+ reader->buffer = g_malloc (size);
+
+ if (non_blocking)
+ {
+ if (reader->pollable)
+ {
+ GError *local_error = NULL;
+
+ result = g_pollable_input_stream_read_nonblocking (reader->pollable, reader->buffer,
+ size, cancellable, &local_error);
+
+ if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+ {
+ reader->state = READER_STATE_NONE;
+ g_propagate_error (error, local_error);
+ return FALSE;
+ }
+ }
+ else
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
+ "Buffer is empty and underlying stream is not pollable");
+ reader->state = READER_STATE_NONE;
+ return FALSE;
+ }
+ }
+ else
+ result = g_input_stream_read (reader->stream, reader->buffer, size, cancellable, error);
+
+ return g_markup_reader_handle_read_result (reader, result, error);
+}
+
+static void
+g_markup_reader_clear (GMarkupReader *reader)
+{
+ g_free (reader->element_name);
+ reader->element_name = NULL;
+ g_strfreev (reader->attribute_names);
+ reader->attribute_names = NULL;
+ g_strfreev (reader->attribute_values);
+ reader->attribute_values = NULL;
+
+ if (reader->content)
+ {
+ g_bytes_unref (reader->content);
+ reader->content = NULL;
+ }
+
+ reader->state = READER_STATE_PENDING;
+}
+
+gboolean
+g_markup_reader_advance (GMarkupReader *reader,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (G_IS_MARKUP_READER (reader), FALSE);
+ g_return_val_if_fail (reader->state != READER_STATE_ERROR &&
+ reader->state != READER_STATE_PENDING &&
+ reader->state != READER_STATE_EOF, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ g_markup_reader_clear (reader);
+
+ while (reader->state == READER_STATE_PENDING)
+ {
+ if (!g_markup_reader_ensure_data (reader, FALSE, cancellable, error))
+ return FALSE;
+
+ if (!GLIB_PRIVATE_CALL (g_markup_parse_context_parse_slightly) (reader->context, error))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+g_markup_reader_advance_nonblocking (GMarkupReader *reader,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (G_IS_MARKUP_READER (reader), FALSE);
+ g_return_val_if_fail (reader->state != READER_STATE_ERROR &&
+ reader->state != READER_STATE_PENDING &&
+ reader->state != READER_STATE_EOF, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ g_markup_reader_clear (reader);
+
+ while (reader->state == READER_STATE_PENDING)
+ {
+ if (!g_markup_reader_ensure_data (reader, TRUE, cancellable, error))
+ return FALSE;
+
+ if (!GLIB_PRIVATE_CALL (g_markup_parse_context_parse_slightly) (reader->context, error))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+g_markup_reader_has_data (GMarkupReader *reader)
+{
+ return reader->context->iter != reader->context->current_text_end;
+}
+
+static void
+g_markup_reader_stream_read_async_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+ GMarkupReader *reader;
+ GError *error = NULL;
+ gssize bytes;
+
+ reader = g_task_get_source_object (task);
+
+ g_assert (reader->state == READER_STATE_PENDING);
+
+ if (result)
+ {
+ g_assert (reader->stream == (gpointer) source);
+ bytes = g_input_stream_read_finish (reader->stream, result, &error);
+
+ if (!g_markup_reader_handle_read_result (reader, bytes, &error))
+ {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+ }
+
+ while (reader->state == READER_STATE_PENDING)
+ {
+ if (!g_markup_reader_has_data (reader))
+ {
+ g_input_stream_read_async (reader->stream, reader->buffer, 1024 * 1024, 0,
+ g_task_get_cancellable (task),
+ g_markup_reader_stream_read_async_complete, task);
+ return;
+ }
+
+ if (!GLIB_PRIVATE_CALL (g_markup_parse_context_parse_slightly) (reader->context, &error))
+ {
+ reader->state = READER_STATE_ERROR;
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+void
+g_markup_reader_advance_async (GMarkupReader *reader,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ g_return_val_if_fail (G_IS_MARKUP_READER (reader), FALSE);
+ g_return_val_if_fail (reader->state != READER_STATE_ERROR &&
+ reader->state != READER_STATE_PENDING &&
+ reader->state != READER_STATE_EOF, FALSE);
+
+ task = g_task_new (reader, cancellable, callback, user_data);
+ g_markup_reader_clear (reader);
+ g_markup_reader_stream_read_async_complete (NULL, NULL, task);
+}
+
+gboolean
+g_markup_reader_advance_finish (GMarkupReader *reader,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, reader), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+gboolean
+g_markup_reader_is_start_element (GMarkupReader *reader,
+ const gchar *element_name)
+{
+ g_return_val_if_fail (G_IS_MARKUP_READER (reader), FALSE);
+
+ return reader->state == READER_STATE_START_ELEMENT &&
+ (!element_name || g_str_equal (reader->element_name, element_name));
+}
+
+gboolean
+g_markup_reader_is_end_element (GMarkupReader *reader)
+{
+ g_return_val_if_fail (G_IS_MARKUP_READER (reader), FALSE);
+
+ return reader->state == READER_STATE_END_ELEMENT;
+}
+
+gboolean
+g_markup_reader_is_passthrough (GMarkupReader *reader)
+{
+ g_return_val_if_fail (G_IS_MARKUP_READER (reader), FALSE);
+
+ return reader->state == READER_STATE_PASSTHROUGH;
+}
+
+gboolean
+g_markup_reader_is_text (GMarkupReader *reader)
+{
+ g_return_val_if_fail (G_IS_MARKUP_READER (reader), FALSE);
+
+ return reader->state == READER_STATE_TEXT;
+}
+
+gboolean
+g_markup_reader_is_whitespace (GMarkupReader *reader)
+{
+ const gchar *data;
+ gsize length;
+ gsize i;
+
+ g_return_val_if_fail (G_IS_MARKUP_READER (reader), FALSE);
+
+ if (reader->state != READER_STATE_TEXT)
+ return FALSE;
+
+
+ data = g_bytes_get_data (reader->content, &length);
+ for (i = 0; i < length; i++)
+ if (!g_ascii_isspace (data[i]))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
+g_markup_reader_is_eof (GMarkupReader *reader)
+{
+ g_return_val_if_fail (G_IS_MARKUP_READER (reader), FALSE);
+
+ return reader->state == READER_STATE_EOF;
+}
+
+const gchar *
+g_markup_reader_get_element_name (GMarkupReader *reader)
+{
+ g_return_val_if_fail (G_IS_MARKUP_READER (reader), NULL);
+ g_return_val_if_fail (reader->state == READER_STATE_START_ELEMENT ||
+ reader->state == READER_STATE_END_ELEMENT, NULL);
+
+ return reader->element_name;
+}
+
+void
+g_markup_reader_get_attributes (GMarkupReader *reader,
+ const gchar * const **attribute_names,
+ const gchar * const **attribute_values)
+{
+ g_return_if_fail (G_IS_MARKUP_READER (reader));
+ g_return_if_fail (reader->state == READER_STATE_START_ELEMENT);
+
+ if (attribute_names)
+ *attribute_names = (const gchar * const *) reader->attribute_names;
+
+ if (attribute_values)
+ *attribute_values = (const gchar * const *) reader->attribute_values;
+}
+
+gboolean
+g_markup_reader_collect_attributes (GMarkupReader *reader,
+ GError **error,
+ GMarkupCollectType first_type,
+ const gchar *first_name,
+ ...)
+{
+ gboolean ok;
+ va_list ap;
+
+ g_return_if_fail (G_IS_MARKUP_READER (reader));
+ g_return_if_fail (reader->state == READER_STATE_START_ELEMENT);
+
+ va_start (ap, first_name);
+ ok = GLIB_PRIVATE_CALL (g_markup_collect_attributesv) (reader->element_name,
+ (const gchar **) reader->attribute_names,
+ (const gchar **) reader->attribute_values,
+ error, first_type, first_name, ap);
+ va_end (ap);
+
+ return ok;
+}
+
+GBytes *
+g_markup_reader_get_content (GMarkupReader *reader)
+{
+ g_return_val_if_fail (G_IS_MARKUP_READER (reader), NULL);
+ g_return_val_if_fail (reader->state == READER_STATE_TEXT || reader->state == READER_STATE_PASSTHROUGH,
NULL);
+
+ return reader->content;
+}
+
+gboolean
+g_markup_reader_unexpected (GMarkupReader *reader,
+ GError **error)
+{
+ const GSList *stack;
+
+ g_return_val_if_fail (reader->state == READER_STATE_START_ELEMENT ||
+ reader->state == READER_STATE_TEXT, FALSE);
+
+ stack = g_markup_parse_context_get_element_stack (reader->context);
+
+ if (reader->state == READER_STATE_START_ELEMENT)
+ {
+ if (stack->next)
+ g_markup_reader_set_error (reader, error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Element <%s> is not valid inside of <%s>",
+ reader->element_name, (gchar *) stack->next->data);
+ else
+ g_markup_reader_set_error (reader, error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Element <%s> is not valid at the document toplevel",
+ reader->element_name);
+ }
+ else /* TEXT */
+ {
+ g_assert (stack->next);
+
+ g_markup_reader_set_error (reader, error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Text content is not valid inside of <%s>",
+ (gchar *) stack->next->data);
+ }
+
+ /* always 'fail' */
+ return FALSE;
+}
+
+gboolean
+g_markup_reader_expect_end (GMarkupReader *reader,
+ GCancellable *cancellable,
+ GError **error)
+{
+ /* Expect either EOF or end tag */
+ while (g_markup_reader_advance (reader, cancellable, error))
+ {
+ if (g_markup_reader_is_end_element (reader))
+ return TRUE;
+
+ if (g_markup_reader_is_eof (reader))
+ return TRUE;
+
+ if (g_markup_reader_is_passthrough (reader))
+ continue; /* XXX: fixme? */
+
+ if (!g_markup_reader_is_whitespace (reader))
+ return g_markup_reader_unexpected (reader, error);
+ }
+
+ return TRUE;
+}
+
+void
+g_markup_reader_set_error (GMarkupReader *reader,
+ GError **error,
+ GQuark domain,
+ gint code,
+ const gchar *format,
+ ...)
+{
+ va_list ap;
+
+ g_return_if_fail (error == NULL || *error == NULL);
+
+ if (!error)
+ return;
+
+
+ va_start (ap, format);
+ *error = g_error_new_valist (domain, code, format, ap);
+ va_end (ap);
+
+ if (reader->context->flags & G_MARKUP_PREFIX_ERROR_POSITION)
+ g_prefix_error (error, "line %d, column %d: ", reader->context->line_number,
reader->context->char_number);
+}
+
+gboolean
+g_markup_reader_collect_elements (GMarkupReader *reader,
+ GCancellable *cancellable,
+ gpointer user_data,
+ GError **error,
+ const gchar *first_name,
+ ...)
+{
+ va_list ap;
+
+ while (g_markup_reader_advance (reader, cancellable, error))
+ {
+ if (g_markup_reader_is_end_element (reader) || g_markup_reader_is_eof (reader))
+ return TRUE;
+
+ if (g_markup_reader_is_start_element (reader, NULL))
+ {
+ const gchar *name = g_markup_reader_get_element_name (reader);
+ const gchar *n;
+
+ va_start (ap, first_name);
+ for (n = first_name; n; n = va_arg (ap, const gchar *))
+ {
+ typedef gboolean (* cb_t) (GMarkupReader *, GCancellable *, gpointer, GError **);
+ cb_t cb = va_arg (ap, cb_t);
+
+ if (g_str_equal (n, name))
+ {
+ if (!(* cb) (reader, cancellable, user_data, error))
+ {
+ va_end (ap);
+ return FALSE;
+ }
+ break;
+ }
+ }
+ va_end (ap);
+ }
+
+ else if (!g_markup_reader_is_whitespace (reader))
+ {
+ g_markup_reader_unexpected (reader, error);
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+gchar *
+g_markup_reader_collect_text (GMarkupReader *reader,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GString *string;
+
+ string = g_string_new (NULL);
+
+ while (g_markup_reader_advance (reader, cancellable, error))
+ {
+ if (g_markup_reader_is_end_element (reader))
+ return g_string_free (string, FALSE);
+
+ if (g_markup_reader_is_text (reader))
+ {
+ GBytes *bytes;
+
+ bytes = g_markup_reader_get_content (reader);
+ g_string_append_len (string, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes));
+ }
+ else
+ {
+ g_markup_reader_unexpected (reader, error);
+ break;
+ }
+ }
+
+ g_string_free (string, TRUE);
+
+ return NULL;
+}
diff --git a/gio/gmarkupreader.h b/gio/gmarkupreader.h
new file mode 100644
index 0000000..021274b
--- /dev/null
+++ b/gio/gmarkupreader.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright © 2013 Canonical Limited
+ *
+ * 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 licence, 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: Ryan Lortie <desrt desrt ca>
+ */
+
+#ifndef __G_MARKUP_READER_H__
+#define __G_MARKUP_READER_H__
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_MARKUP_READER (g_markup_reader_get_type ())
+#define G_MARKUP_READER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst),
\
+ G_TYPE_MARKUP_READER, GMarkupReader))
+#define G_IS_MARKUP_READER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst),
\
+ G_TYPE_MARKUP_READER))
+
+typedef struct _GMarkupReader GMarkupReader;
+
+GLIB_AVAILABLE_IN_2_42
+GType g_markup_reader_get_type (void);
+
+GLIB_AVAILABLE_IN_2_42
+GMarkupReader * g_markup_reader_new (GInputStream *stream,
+ GMarkupParseFlags flags);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_advance (GMarkupReader *reader,
+ GCancellable *cancellable,
+ GError **error);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_advance_nonblocking (GMarkupReader *reader,
+ GCancellable *cancellable,
+ GError **error);
+
+GLIB_AVAILABLE_IN_2_42
+void g_markup_reader_advance_async (GMarkupReader *reader,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_advance_finish (GMarkupReader *reader,
+ GAsyncResult *result,
+ GError **error);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_is_eof (GMarkupReader *reader);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_is_start_element (GMarkupReader *reader,
+ const gchar *element_name);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_is_end_element (GMarkupReader *reader);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_is_passthrough (GMarkupReader *reader);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_is_text (GMarkupReader *reader);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_is_whitespace (GMarkupReader *reader);
+
+GLIB_AVAILABLE_IN_2_42
+const gchar * g_markup_reader_get_element_name (GMarkupReader *reader);
+
+GLIB_AVAILABLE_IN_2_42
+void g_markup_reader_get_attributes (GMarkupReader *reader,
+ const gchar * const
**attribute_names,
+ const gchar * const
**attribute_values);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_collect_attributes (GMarkupReader *reader,
+ GError **error,
+ GMarkupCollectType first_type,
+ const gchar *first_name,
+ ...);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_collect_elements (GMarkupReader *reader,
+ GCancellable *cancellable,
+ gpointer user_data,
+ GError **error,
+ const gchar *first_name,
+ ...) G_GNUC_NULL_TERMINATED;
+
+GLIB_AVAILABLE_IN_2_42
+GBytes * g_markup_reader_get_content (GMarkupReader *reader);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_unexpected (GMarkupReader *reader,
+ GError **error);
+
+GLIB_AVAILABLE_IN_2_42
+gboolean g_markup_reader_expect_end (GMarkupReader *reader,
+ GCancellable *cancellable,
+ GError **error);
+GLIB_AVAILABLE_IN_2_42
+void g_markup_reader_set_error (GMarkupReader *reader,
+ GError **error,
+ GQuark domain,
+ gint code,
+ const gchar *format,
+ ...);
+GLIB_AVAILABLE_IN_2_42
+gchar * g_markup_reader_collect_text (GMarkupReader *reader,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __G_MARKUP_READER_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]