[libgxps/wip/nacho/resources: 1/2] Add support for resource dictionaries
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgxps/wip/nacho/resources: 1/2] Add support for resource dictionaries
- Date: Thu, 26 Jan 2017 15:49:45 +0000 (UTC)
commit 042a633840290bce3708dd93a96984dd5a9c264d
Author: Ignacio Casal Quinteiro <ignacio casal nice-software com>
Date: Thu Jan 26 12:57:47 2017 +0100
Add support for resource dictionaries
It parses the resources and keeps a cache in the form of xml.
Once we are parsing the real xml if we find a resource we
get the cached xml resource and we parse it to properly handle it.
For now only Path Data resources are supported.
Based in a patch from Jason Crain.
https://bugzilla.gnome.org/show_bug.cgi?id=777731
libgxps/Makefile.am | 2 +-
libgxps/Makefile.sources | 2 +
libgxps/gxps-page-private.h | 3 +
libgxps/gxps-page.c | 106 ++++++++++-
libgxps/gxps-resources.c | 445 +++++++++++++++++++++++++++++++++++++++++++
libgxps/gxps-resources.h | 47 +++++
6 files changed, 603 insertions(+), 2 deletions(-)
---
diff --git a/libgxps/Makefile.am b/libgxps/Makefile.am
index 57cc9c8..f8ac4f8 100644
--- a/libgxps/Makefile.am
+++ b/libgxps/Makefile.am
@@ -55,7 +55,7 @@ INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) --warn-all --identifie
INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
if HAVE_INTROSPECTION
-introspection_sources = $(filter-out $(NOINST_H_FILES) gxps-archive.c gxps-fonts.c gxps-images.c
gxps-parse-utils.c gxps-version.h, $(libgxps_la_SOURCES))
+introspection_sources = $(filter-out $(GXPS_BASE_NOINST_H_FILES) gxps-resources.c gxps-color.c gxps-path.c
gxps-brush.c gxps-matrix.c gxps-glyphs.c gxps-archive.c gxps-fonts.c gxps-images.c gxps-parse-utils.c
gxps-version.h, $(libgxps_la_SOURCES))
GXPS-0.1.gir: libgxps.la
GXPS_0_1_gir_INCLUDES = GObject-2.0 Gio-2.0 cairo-1.0
diff --git a/libgxps/Makefile.sources b/libgxps/Makefile.sources
index 9d6a24a..c9adc55 100644
--- a/libgxps/Makefile.sources
+++ b/libgxps/Makefile.sources
@@ -13,6 +13,7 @@ GXPS_BASE_NOINST_H_FILES = \
gxps-parse-utils.h \
gxps-path.h \
gxps-private.h \
+ gxps-resources.h \
$(NULL)
GXPS_BASE_INST_H_FILES = \
@@ -45,4 +46,5 @@ GXPS_BASE_SOURCES = \
gxps-page.c \
gxps-parse-utils.c \
gxps-path.c \
+ gxps-resources.c \
$(NULL)
diff --git a/libgxps/gxps-page-private.h b/libgxps/gxps-page-private.h
index f4d299c..072dcaa 100644
--- a/libgxps/gxps-page-private.h
+++ b/libgxps/gxps-page-private.h
@@ -26,6 +26,7 @@
#include "gxps-page.h"
#include "gxps-archive.h"
#include "gxps-images.h"
+#include "gxps-resources.h"
G_BEGIN_DECLS
@@ -50,6 +51,8 @@ struct _GXPSPagePrivate {
/* Anchors */
gboolean has_anchors;
GHashTable *anchors;
+
+ GXPSResources *resources;
};
struct _GXPSRenderContext {
diff --git a/libgxps/gxps-page.c b/libgxps/gxps-page.c
index dc43f6e..18ecf45 100644
--- a/libgxps/gxps-page.c
+++ b/libgxps/gxps-page.c
@@ -276,6 +276,7 @@ typedef struct {
gdouble opacity;
cairo_pattern_t *opacity_mask;
+ gboolean pop_resource;
} GXPSCanvas;
static GXPSCanvas *
@@ -288,6 +289,7 @@ gxps_canvas_new (GXPSRenderContext *ctx)
/* Default values */
canvas->opacity = 1.0;
+ canvas->pop_resource = FALSE;
return canvas;
}
@@ -322,6 +324,18 @@ canvas_start_element (GMarkupParseContext *context,
brush = gxps_brush_new (canvas->ctx);
gxps_brush_parser_push (context, brush);
+ } else if (strcmp (element_name, "Canvas.Resources") == 0) {
+ if (canvas->pop_resource) {
+ gxps_parse_error (context,
+ canvas->ctx->page->priv->source,
+ G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ element_name, NULL, NULL, error);
+ return;
+ }
+
+ gxps_resources_push_dict (canvas->ctx->page->priv->resources);
+ canvas->pop_resource = TRUE;
+ gxps_resources_parser_push (context, canvas->ctx->page->priv->resources);
} else {
render_start_element (context,
element_name,
@@ -359,6 +373,8 @@ canvas_end_element (GMarkupParseContext *context,
cairo_push_group (canvas->ctx->cr);
}
gxps_brush_free (brush);
+ } else if (strcmp (element_name, "Canvas.Resources") == 0) {
+ g_markup_parse_context_pop (context);
} else {
render_end_element (context,
element_name,
@@ -385,6 +401,69 @@ static GMarkupParser canvas_parser = {
};
static void
+resource_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ if (strcmp (element_name, "Resource.PathGeometry") == 0) {
+ GXPSPath *path = (GXPSPath *)user_data;
+
+ gxps_path_parser_push (context, path);
+ }
+}
+
+static void
+resource_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ if (strcmp (element_name, "Resource.PathGeometry") == 0) {
+ g_markup_parse_context_pop (context);
+ }
+}
+
+static GMarkupParser resource_parser = {
+ resource_start_element,
+ resource_end_element,
+ NULL,
+ NULL,
+ NULL
+};
+
+static gboolean
+expand_resource (GXPSPage *page,
+ const gchar *data,
+ gpointer user_data)
+{
+ gchar *resource_key = NULL;
+ const gchar *resource;
+ GMarkupParseContext *context;
+ gboolean ret = TRUE;
+
+ if (sscanf (data, "{StaticResource %m[^}]}", &resource_key) != 1)
+ return FALSE;
+
+ if (!resource_key || *resource_key == '\0')
+ return FALSE;
+
+ resource = gxps_resources_get_resource (page->priv->resources, resource_key);
+ if (!resource)
+ return FALSE;
+
+ context = g_markup_parse_context_new (&resource_parser, 0, user_data, NULL);
+
+ ret = g_markup_parse_context_parse (context, resource, strlen (resource), NULL) &&
+ g_markup_parse_context_end_parse (context, NULL);
+ g_markup_parse_context_free (context);
+
+ return ret;
+}
+
+static void
render_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **names,
@@ -405,7 +484,9 @@ render_start_element (GMarkupParseContext *context,
for (i = 0; names[i] != NULL; i++) {
if (strcmp (names[i], "Data") == 0) {
- path->data = g_strdup (values[i]);
+ if (!expand_resource (ctx->page, values[i], path)) {
+ path->data = g_strdup (values[i]);
+ }
} else if (strcmp (names[i], "RenderTransform") == 0) {
cairo_matrix_t matrix;
@@ -713,6 +794,8 @@ render_start_element (GMarkupParseContext *context,
if (canvas->opacity != 1.0)
cairo_push_group (canvas->ctx->cr);
g_markup_parse_context_push (context, &canvas_parser, canvas);
+ } else if (strcmp (element_name, "FixedPage.Resources") == 0) {
+ gxps_resources_parser_push (context, ctx->page->priv->resources);
} else if (strcmp (element_name, "FixedPage") == 0) {
/* Do Nothing */
} else {
@@ -956,7 +1039,11 @@ render_end_element (GMarkupParseContext *context,
}
cairo_restore (ctx->cr);
GXPS_DEBUG (g_message ("restore"));
+ if (canvas->pop_resource)
+ gxps_resources_pop_dict (ctx->page->priv->resources);
gxps_canvas_free (canvas);
+ } else if (strcmp (element_name, "FixedPage.Resources") == 0) {
+ g_markup_parse_context_pop (context);
} else if (strcmp (element_name, "FixedPage") == 0) {
/* Do Nothing */
} else {
@@ -1553,10 +1640,26 @@ gxps_page_finalize (GObject *object)
page->priv->has_anchors = FALSE;
}
+ if (page->priv->resources) {
+ g_object_unref (page->priv->resources);
+ page->priv->resources = NULL;
+ }
+
G_OBJECT_CLASS (gxps_page_parent_class)->finalize (object);
}
static void
+gxps_page_constructed (GObject *object)
+{
+ GXPSPage *page = GXPS_PAGE (object);
+
+ page->priv->resources = gxps_resources_new (page->priv->zip,
+ page->priv->source);
+
+ G_OBJECT_CLASS (gxps_page_parent_class)->constructed (object);
+}
+
+static void
gxps_page_init (GXPSPage *page)
{
page->priv = G_TYPE_INSTANCE_GET_PRIVATE (page,
@@ -1593,6 +1696,7 @@ gxps_page_class_init (GXPSPageClass *klass)
object_class->set_property = gxps_page_set_property;
object_class->finalize = gxps_page_finalize;
+ object_class->constructed = gxps_page_constructed;
g_object_class_install_property (object_class,
PROP_ARCHIVE,
diff --git a/libgxps/gxps-resources.c b/libgxps/gxps-resources.c
new file mode 100644
index 0000000..640ca2d
--- /dev/null
+++ b/libgxps/gxps-resources.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2015 Jason Crain <jason aquaticape us>
+ * Copyright (C) 2017 Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "gxps-resources.h"
+#include "gxps-parse-utils.h"
+#include "gxps-error.h"
+
+#include <string.h>
+
+struct _GXPSResources
+{
+ GObject parent_instance;
+
+ GXPSArchive *zip;
+ gchar *source;
+
+ gboolean remote;
+ GQueue *queue;
+};
+
+enum {
+ PROP_0,
+ PROP_ARCHIVE,
+ PROP_SOURCE,
+ LAST_PROP
+};
+
+static GParamSpec *props[LAST_PROP];
+
+G_DEFINE_TYPE (GXPSResources, gxps_resources, G_TYPE_OBJECT)
+
+static void
+gxps_resources_finalize (GObject *object)
+{
+ GXPSResources *resources = GXPS_RESOURCES (object);
+
+ g_queue_free_full (resources->queue, (GDestroyNotify)g_hash_table_destroy);
+ g_object_unref (resources->zip);
+ g_free (resources->source);
+
+ G_OBJECT_CLASS (gxps_resources_parent_class)->finalize (object);
+}
+
+static void
+gxps_resources_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GXPSResources *resources = GXPS_RESOURCES (object);
+
+ switch (prop_id) {
+ case PROP_ARCHIVE:
+ resources->zip = g_value_dup_object (value);
+ break;
+ case PROP_SOURCE:
+ resources->source = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gxps_resources_class_init (GXPSResourcesClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gxps_resources_finalize;
+ object_class->set_property = gxps_resources_set_property;
+
+ props[PROP_ARCHIVE] =
+ g_param_spec_object ("archive",
+ "Archive",
+ "The document archive",
+ GXPS_TYPE_ARCHIVE,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY);
+
+ props[PROP_SOURCE] =
+ g_param_spec_string ("source",
+ "Source",
+ "The Page Source File",
+ NULL,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+}
+
+static void
+gxps_resources_init (GXPSResources *resources)
+{
+ resources->queue = g_queue_new ();
+}
+
+GXPSResources *
+gxps_resources_new (GXPSArchive *zip,
+ const gchar *source)
+{
+ return g_object_new (GXPS_TYPE_RESOURCES,
+ "archive", zip,
+ "source", source,
+ NULL);
+}
+
+void
+gxps_resources_push_dict (GXPSResources *resources)
+{
+ GHashTable *ht;
+
+ g_return_if_fail (GXPS_IS_RESOURCES (resources));
+
+ ht = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)g_free);
+ g_queue_push_head (resources->queue, ht);
+}
+
+void
+gxps_resources_pop_dict (GXPSResources *resources)
+{
+ GHashTable *ht;
+
+ g_return_if_fail (GXPS_IS_RESOURCES (resources));
+
+ ht = g_queue_pop_head (resources->queue);
+ g_hash_table_destroy (ht);
+}
+
+const gchar *
+gxps_resources_get_resource (GXPSResources *resources,
+ const gchar *key)
+{
+ GList *node;
+
+ g_return_val_if_fail (GXPS_IS_RESOURCES (resources), NULL);
+
+ for (node = resources->queue->head; node != NULL; node = node->next) {
+ GHashTable *ht;
+ gpointer data;
+
+ ht = node->data;
+ data = g_hash_table_lookup (ht, key);
+ if (data)
+ return data;
+ }
+
+ return NULL;
+}
+
+static gboolean
+gxps_resources_set (GXPSResources *resources,
+ gchar *key,
+ gchar *value)
+{
+ GHashTable *ht;
+
+ if (g_queue_get_length (resources->queue) == 0)
+ gxps_resources_push_dict (resources);
+
+ ht = g_queue_peek_head (resources->queue);
+ if (g_hash_table_contains (ht, key))
+ return FALSE;
+
+ g_hash_table_insert (ht, key, value);
+
+ return TRUE;
+}
+
+typedef struct {
+ GXPSResources *resources;
+
+ gchar *key;
+ gchar *first_element_name;
+ GString *xml;
+} GXPSResourceDictContext;
+
+static GXPSResourceDictContext *
+gxps_resource_dict_context_new (GXPSResources *resources)
+{
+ GXPSResourceDictContext *resource_dict;
+
+ resource_dict = g_slice_new0 (GXPSResourceDictContext);
+ resource_dict->resources = g_object_ref (resources);
+
+ return resource_dict;
+}
+
+static void
+gxps_resource_dict_context_free (GXPSResourceDictContext *resource_dict)
+{
+ if (G_UNLIKELY (!resource_dict))
+ return;
+
+ g_free (resource_dict->key);
+ g_free (resource_dict->first_element_name);
+ if (resource_dict->xml)
+ g_string_free (resource_dict->xml, TRUE);
+ g_object_unref (resource_dict->resources);
+ g_slice_free (GXPSResourceDictContext, resource_dict);
+}
+
+static void
+resource_dict_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ GXPSResourceDictContext *resource_dict_ctx = (GXPSResourceDictContext *)user_data;
+ gint i;
+
+ for (i = 0; names[i] != NULL; i++) {
+ if (strcmp (names[i], "x:Key") == 0) {
+ resource_dict_ctx->key = g_strdup (values[i]);
+ break;
+ }
+ }
+
+ if (!resource_dict_ctx->key) {
+ gxps_parse_error (context,
+ resource_dict_ctx->resources->source,
+ G_MARKUP_ERROR_MISSING_ATTRIBUTE,
+ element_name, "x:Key",
+ NULL, error);
+ return;
+ }
+
+ if (!resource_dict_ctx->xml) {
+ resource_dict_ctx->first_element_name = g_strdup (element_name);
+ resource_dict_ctx->xml = g_string_new (NULL);
+ g_string_append_printf (resource_dict_ctx->xml, "<Resource.%s>\n",
+ element_name);
+ }
+
+ g_string_append_printf (resource_dict_ctx->xml, "<%s",
+ element_name);
+ for (i = 0; names[i] != NULL; i++) {
+ /* Skip key */
+ if (strcmp (names[i], "x:Key") != 0) {
+ g_string_append_printf (resource_dict_ctx->xml,
+ " %s=\"%s\"",
+ names[i], values[i]);
+ }
+ }
+
+ g_string_append (resource_dict_ctx->xml, ">\n");
+}
+
+static void
+resource_dict_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ GXPSResourceDictContext *resource_dict_ctx = (GXPSResourceDictContext *)user_data;
+
+ if (strcmp (element_name, resource_dict_ctx->first_element_name) == 0) {
+ g_string_append_printf (resource_dict_ctx->xml, "</%s>\n</Resource.%s>",
+ element_name, element_name);
+ gxps_resources_set (resource_dict_ctx->resources,
+ resource_dict_ctx->key,
+ g_string_free (resource_dict_ctx->xml, FALSE));
+ g_clear_pointer (&resource_dict_ctx->first_element_name, g_free);
+ resource_dict_ctx->key = NULL;
+ resource_dict_ctx->xml = NULL;
+ } else {
+ g_string_append_printf (resource_dict_ctx->xml, "</%s>\n",
+ element_name);
+ }
+}
+
+static void
+resource_dict_error (GMarkupParseContext *context,
+ GError *error,
+ gpointer user_data)
+{
+ GXPSResourceDictContext *resource_dict_ctx = (GXPSResourceDictContext *)user_data;
+ gxps_resource_dict_context_free (resource_dict_ctx);
+}
+
+static GMarkupParser resource_dict_parser = {
+ resource_dict_start_element,
+ resource_dict_end_element,
+ NULL,
+ NULL,
+ resource_dict_error
+};
+
+static void
+remote_resource_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ GXPSResources *resources = GXPS_RESOURCES (user_data);
+
+ if (strcmp (element_name, "ResourceDictionary") == 0) {
+ GXPSResourceDictContext *resource_dict_ctx;
+
+ resource_dict_ctx = gxps_resource_dict_context_new (resources);
+ g_markup_parse_context_push (context, &resource_dict_parser, resource_dict_ctx);
+ } else {
+ gxps_parse_error (context,
+ resources->source,
+ G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ element_name, NULL, NULL, error);
+ }
+}
+
+static void
+remote_resource_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ if (strcmp (element_name, "ResourceDictionary") == 0) {
+ GXPSResourceDictContext *resource_dict;
+
+ resource_dict = g_markup_parse_context_pop (context);
+ gxps_resource_dict_context_free (resource_dict);
+ }
+}
+
+static GMarkupParser remote_resource_parser = {
+ remote_resource_start_element,
+ remote_resource_end_element,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void
+resources_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ gpointer user_data,
+ GError **error)
+{
+ GXPSResources *resources = GXPS_RESOURCES (user_data);
+ const gchar *source = NULL;
+ gint i;
+
+ if (strcmp (element_name, "ResourceDictionary") == 0) {
+ for (i = 0; names[i] != NULL; i++) {
+ if (strcmp (names[i], "Source") == 0)
+ source = values[i];
+ }
+
+ resources->remote = source != NULL;
+ if (resources->remote) {
+ GInputStream *stream;
+ gchar *abs_source;
+ GMarkupParseContext *parse_ctx;
+
+ abs_source = gxps_resolve_relative_path (resources->source,
+ source);
+ stream = gxps_archive_open (resources->zip, abs_source);
+ if (!stream) {
+ g_set_error (error,
+ GXPS_ERROR,
+ GXPS_ERROR_SOURCE_NOT_FOUND,
+ "Source %s not found in archive",
+ abs_source);
+ g_free (abs_source);
+ return;
+ }
+
+ parse_ctx = g_markup_parse_context_new (&remote_resource_parser,
+ 0, resources, NULL);
+ gxps_parse_stream (parse_ctx, stream, error);
+ g_object_unref (stream);
+ g_markup_parse_context_free (parse_ctx);
+ g_free (abs_source);
+ } else {
+ GXPSResourceDictContext *resource_dict;
+
+ resource_dict = gxps_resource_dict_context_new (resources);
+ g_markup_parse_context_push (context, &resource_dict_parser, resource_dict);
+ }
+ } else {
+ gxps_parse_error (context,
+ resources->source,
+ G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ element_name, NULL, NULL, error);
+ }
+}
+
+static void
+resources_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ GXPSResources *resources = GXPS_RESOURCES (user_data);
+
+ if (strcmp (element_name, "ResourceDictionary") == 0) {
+ GXPSResourceDictContext *resource_dict;
+
+ if (!resources->remote) {
+ resource_dict = g_markup_parse_context_pop (context);
+ gxps_resource_dict_context_free (resource_dict);
+ } else {
+ resources->remote = FALSE;
+ }
+ }
+}
+
+static GMarkupParser resources_parser = {
+ resources_start_element,
+ resources_end_element,
+ NULL,
+ NULL,
+ NULL
+};
+
+void
+gxps_resources_parser_push (GMarkupParseContext *context,
+ GXPSResources *resources)
+{
+ g_markup_parse_context_push (context, &resources_parser, resources);
+}
diff --git a/libgxps/gxps-resources.h b/libgxps/gxps-resources.h
new file mode 100644
index 0000000..8a75bfb
--- /dev/null
+++ b/libgxps/gxps-resources.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Jason Crain <jason aquaticape us>
+ * Copyright (C) 2017 Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef GXPS_RESOURCES_H
+#define GXPS_RESOURCES_H
+
+#include <glib-object.h>
+
+#include "gxps-archive.h"
+
+G_BEGIN_DECLS
+
+#define GXPS_TYPE_RESOURCES (gxps_resources_get_type ())
+G_DECLARE_FINAL_TYPE (GXPSResources, gxps_resources, GXPS, RESOURCES, GObject)
+
+GXPSResources *gxps_resources_new (GXPSArchive *zip,
+ const gchar *source);
+
+void gxps_resources_push_dict (GXPSResources *resources);
+
+void gxps_resources_pop_dict (GXPSResources *resources);
+
+const gchar *gxps_resources_get_resource (GXPSResources *resources,
+ const gchar *key);
+
+void gxps_resources_parser_push (GMarkupParseContext *context,
+ GXPSResources *resources);
+
+G_END_DECLS
+
+#endif /* GXPS_RESOURCES_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]