[gnome-software] Move the AppStream cache functionality to it's own file
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Move the AppStream cache functionality to it's own file
- Date: Wed, 4 Sep 2013 16:15:11 +0000 (UTC)
commit 43014ca4fd57376737a4afc2cc00de7bb8537973
Author: Richard Hughes <richard hughsie com>
Date: Wed Sep 4 16:34:55 2013 +0100
Move the AppStream cache functionality to it's own file
Additionally support .xml and .xml.gz AppStream files. This gets us some degree
of Ubuntu compatibility.
src/plugins/Makefile.am | 7 +-
src/plugins/appstream-app.c | 255 ++++++++++++++++
src/plugins/appstream-app.h | 81 +++++
src/plugins/appstream-cache.c | 594 +++++++++++++++++++++++++++++++++++++
src/plugins/appstream-cache.h | 75 +++++
src/plugins/gs-appstream-item.c | 256 ----------------
src/plugins/gs-appstream-item.h | 81 -----
src/plugins/gs-plugin-appstream.c | 474 +++---------------------------
8 files changed, 1053 insertions(+), 770 deletions(-)
---
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index c9f7ad4..2ca58e4 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -54,7 +54,12 @@ libgs_plugin_self_test_la_LIBADD = $(GS_PLUGIN_LIBS)
libgs_plugin_self_test_la_LDFLAGS = -module -avoid-version
libgs_plugin_self_test_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARNINGFLAGS_C)
-libgs_plugin_appstream_la_SOURCES = gs-plugin-appstream.c gs-appstream-item.c gs-appstream-item.h
+libgs_plugin_appstream_la_SOURCES = \
+ gs-plugin-appstream.c \
+ appstream-app.c \
+ appstream-app.h \
+ appstream-cache.c \
+ appstream-cache.h
libgs_plugin_appstream_la_LIBADD = $(GS_PLUGIN_LIBS)
libgs_plugin_appstream_la_LDFLAGS = -module -avoid-version
libgs_plugin_appstream_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARNINGFLAGS_C)
diff --git a/src/plugins/appstream-app.c b/src/plugins/appstream-app.c
new file mode 100644
index 0000000..932f8ab
--- /dev/null
+++ b/src/plugins/appstream-app.c
@@ -0,0 +1,255 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include "appstream-app.h"
+
+struct AppstreamApp
+{
+ gchar *id;
+ gchar *pkgname;
+ gchar *name;
+ gchar *summary;
+ gchar *url;
+ gchar *description;
+ gchar *icon;
+ AppstreamAppIconKind icon_kind;
+ GPtrArray *appcategories;
+};
+
+/**
+ * appstream_app_free:
+ */
+void
+appstream_app_free (AppstreamApp *app)
+{
+ g_free (app->id);
+ g_free (app->pkgname);
+ g_free (app->name);
+ g_free (app->summary);
+ g_free (app->url);
+ g_free (app->description);
+ g_free (app->icon);
+ g_ptr_array_unref (app->appcategories);
+ g_slice_free (AppstreamApp, app);
+}
+
+/**
+ * appstream_app_new:
+ */
+AppstreamApp *
+appstream_app_new (void)
+{
+ AppstreamApp *app;
+ app = g_slice_new0 (AppstreamApp);
+ app->appcategories = g_ptr_array_new_with_free_func (g_free);
+ app->icon_kind = APPSTREAM_APP_ICON_KIND_UNKNOWN;
+ return app;
+}
+
+/**
+ * appstream_app_get_id:
+ */
+const gchar *
+appstream_app_get_id (AppstreamApp *app)
+{
+ return app->id;
+}
+
+/**
+ * appstream_app_get_pkgname:
+ */
+const gchar *
+appstream_app_get_pkgname (AppstreamApp *app)
+{
+ return app->pkgname;
+}
+
+/**
+ * appstream_app_get_name:
+ */
+const gchar *
+appstream_app_get_name (AppstreamApp *app)
+{
+ return app->name;
+}
+
+/**
+ * appstream_app_get_summary:
+ */
+const gchar *
+appstream_app_get_summary (AppstreamApp *app)
+{
+ return app->summary;
+}
+
+/**
+ * appstream_app_get_url:
+ */
+const gchar *
+appstream_app_get_url (AppstreamApp *app)
+{
+ return app->url;
+}
+
+/**
+ * appstream_app_get_description:
+ */
+const gchar *
+appstream_app_get_description (AppstreamApp *app)
+{
+ return app->description;
+}
+
+/**
+ * appstream_app_get_icon:
+ */
+const gchar *
+appstream_app_get_icon (AppstreamApp *app)
+{
+ return app->icon;
+}
+
+/**
+ * appstream_app_get_icon_kind:
+ */
+AppstreamAppIconKind
+appstream_app_get_icon_kind (AppstreamApp *app)
+{
+ return app->icon_kind;
+}
+
+/**
+ * appstream_app_has_category:
+ */
+gboolean
+appstream_app_has_category (AppstreamApp *app, const gchar *category)
+{
+ const gchar *tmp;
+ guint i;
+
+ for (i = 0; i < app->appcategories->len; i++) {
+ tmp = g_ptr_array_index (app->appcategories, i);
+ if (g_strcmp0 (tmp, category) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * appstream_app_set_id:
+ */
+void
+appstream_app_set_id (AppstreamApp *app,
+ const gchar *id,
+ gsize length)
+{
+ app->id = g_strndup (id, length);
+}
+
+/**
+ * appstream_app_set_pkgname:
+ */
+void
+appstream_app_set_pkgname (AppstreamApp *app,
+ const gchar *pkgname,
+ gsize length)
+{
+ app->pkgname = g_strndup (pkgname, length);
+}
+
+/**
+ * appstream_app_set_name:
+ */
+void
+appstream_app_set_name (AppstreamApp *app,
+ const gchar *name,
+ gsize length)
+{
+ app->name = g_strndup (name, length);
+}
+
+/**
+ * appstream_app_set_summary:
+ */
+void
+appstream_app_set_summary (AppstreamApp *app,
+ const gchar *summary,
+ gsize length)
+{
+ app->summary = g_strndup (summary, length);
+}
+
+/**
+ * appstream_app_set_url:
+ */
+void
+appstream_app_set_url (AppstreamApp *app,
+ const gchar *url,
+ gsize length)
+{
+ app->url = g_strndup (url, length);
+}
+
+/**
+ * appstream_app_set_description:
+ */
+void
+appstream_app_set_description (AppstreamApp *app,
+ const gchar *description,
+ gsize length)
+{
+ app->description = g_strndup (description, length);
+}
+
+/**
+ * appstream_app_set_icon:
+ */
+void
+appstream_app_set_icon (AppstreamApp *app,
+ const gchar *icon,
+ gsize length)
+{
+ app->icon = g_strndup (icon, length);
+}
+
+/**
+ * appstream_app_add_category:
+ */
+void
+appstream_app_add_category (AppstreamApp *app,
+ const gchar *category,
+ gsize length)
+{
+ g_ptr_array_add (app->appcategories,
+ g_strndup (category, length));
+}
+
+/**
+ * appstream_app_set_icon_kind:
+ */
+void
+appstream_app_set_icon_kind (AppstreamApp *app,
+ AppstreamAppIconKind icon_kind)
+{
+ app->icon_kind = icon_kind;
+}
diff --git a/src/plugins/appstream-app.h b/src/plugins/appstream-app.h
new file mode 100644
index 0000000..fcd4d29
--- /dev/null
+++ b/src/plugins/appstream-app.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __APPSTREAM_APP_H
+#define __APPSTREAM_APP_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ APPSTREAM_APP_ICON_KIND_STOCK,
+ APPSTREAM_APP_ICON_KIND_CACHED,
+ APPSTREAM_APP_ICON_KIND_UNKNOWN,
+ APPSTREAM_APP_ICON_KIND_LAST
+} AppstreamAppIconKind;
+
+typedef struct AppstreamApp AppstreamApp;
+
+void appstream_app_free (AppstreamApp *app);
+AppstreamApp *appstream_app_new (void);
+
+const gchar *appstream_app_get_id (AppstreamApp *app);
+const gchar *appstream_app_get_pkgname (AppstreamApp *app);
+const gchar *appstream_app_get_name (AppstreamApp *app);
+const gchar *appstream_app_get_summary (AppstreamApp *app);
+const gchar *appstream_app_get_url (AppstreamApp *app);
+const gchar *appstream_app_get_description (AppstreamApp *app);
+const gchar *appstream_app_get_icon (AppstreamApp *app);
+gboolean appstream_app_has_category (AppstreamApp *app,
+ const gchar *category);
+AppstreamAppIconKind appstream_app_get_icon_kind (AppstreamApp *app);
+
+void appstream_app_set_id (AppstreamApp *app,
+ const gchar *id,
+ gsize length);
+void appstream_app_set_pkgname (AppstreamApp *app,
+ const gchar *pkgname,
+ gsize length);
+void appstream_app_set_name (AppstreamApp *app,
+ const gchar *name,
+ gsize length);
+void appstream_app_set_summary (AppstreamApp *app,
+ const gchar *summary,
+ gsize length);
+void appstream_app_set_url (AppstreamApp *app,
+ const gchar *summary,
+ gsize length);
+void appstream_app_set_description (AppstreamApp *app,
+ const gchar *description,
+ gsize length);
+void appstream_app_set_icon (AppstreamApp *app,
+ const gchar *icon,
+ gsize length);
+void appstream_app_add_category (AppstreamApp *app,
+ const gchar *category,
+ gsize length);
+void appstream_app_set_icon_kind (AppstreamApp *app,
+ AppstreamAppIconKind icon_kind);
+
+G_END_DECLS
+
+#endif /* __APPSTREAM_APP_H */
diff --git a/src/plugins/appstream-cache.c b/src/plugins/appstream-cache.c
new file mode 100644
index 0000000..6daeb24
--- /dev/null
+++ b/src/plugins/appstream-cache.c
@@ -0,0 +1,594 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include "appstream-cache.h"
+
+static void appstream_cache_finalize (GObject *object);
+
+#define APPSTREAM_CACHE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APPSTREAM_TYPE_CACHE,
AppstreamCachePrivate))
+
+typedef enum {
+ APPSTREAM_CACHE_SECTION_UNKNOWN,
+ APPSTREAM_CACHE_SECTION_APPLICATIONS,
+ APPSTREAM_CACHE_SECTION_APPLICATION,
+ APPSTREAM_CACHE_SECTION_ID,
+ APPSTREAM_CACHE_SECTION_PKGNAME,
+ APPSTREAM_CACHE_SECTION_NAME,
+ APPSTREAM_CACHE_SECTION_SUMMARY,
+ APPSTREAM_CACHE_SECTION_DESCRIPTION,
+ APPSTREAM_CACHE_SECTION_URL,
+ APPSTREAM_CACHE_SECTION_ICON,
+ APPSTREAM_CACHE_SECTION_APPCATEGORIES,
+ APPSTREAM_CACHE_SECTION_APPCATEGORY,
+ APPSTREAM_CACHE_SECTION_LAST
+} AppstreamCacheSection;
+
+struct AppstreamCachePrivate
+{
+ GPtrArray *array; /* of AppstreamApp */
+ GHashTable *hash_id; /* of AppstreamApp{id} */
+ GHashTable *hash_pkgname; /* of AppstreamApp{pkgname} */
+};
+
+G_DEFINE_TYPE (AppstreamCache, appstream_cache, G_TYPE_OBJECT)
+
+/**
+ * appstream_cache_error_quark:
+ **/
+GQuark
+appstream_cache_error_quark (void)
+{
+ static GQuark quark = 0;
+ if (!quark)
+ quark = g_quark_from_static_string ("appstream_cache_error");
+ return quark;
+}
+
+/**
+ * appstream_cache_get_size:
+ */
+guint
+appstream_cache_get_size (AppstreamCache *cache)
+{
+ g_return_val_if_fail (APPSTREAM_IS_CACHE (cache), 0);
+ return cache->priv->array->len;
+}
+
+/**
+ * appstream_cache_get_items:
+ */
+GPtrArray *
+appstream_cache_get_items (AppstreamCache *cache)
+{
+ g_return_val_if_fail (APPSTREAM_IS_CACHE (cache), NULL);
+ return cache->priv->array;
+}
+
+/**
+ * appstream_cache_get_item_by_id:
+ */
+AppstreamApp *
+appstream_cache_get_item_by_id (AppstreamCache *cache, const gchar *id)
+{
+ g_return_val_if_fail (APPSTREAM_IS_CACHE (cache), NULL);
+ return g_hash_table_lookup (cache->priv->hash_id, id);
+}
+
+/**
+ * appstream_cache_get_item_by_pkgname:
+ */
+AppstreamApp *
+appstream_cache_get_item_by_pkgname (AppstreamCache *cache, const gchar *pkgname)
+{
+ g_return_val_if_fail (APPSTREAM_IS_CACHE (cache), NULL);
+ return g_hash_table_lookup (cache->priv->hash_pkgname, pkgname);
+}
+
+/**
+ * appstream_cache_selection_from_string:
+ */
+static AppstreamCacheSection
+appstream_cache_selection_from_string (const gchar *element_name)
+{
+ if (g_strcmp0 (element_name, "applications") == 0)
+ return APPSTREAM_CACHE_SECTION_APPLICATIONS;
+ if (g_strcmp0 (element_name, "application") == 0)
+ return APPSTREAM_CACHE_SECTION_APPLICATION;
+ if (g_strcmp0 (element_name, "id") == 0)
+ return APPSTREAM_CACHE_SECTION_ID;
+ if (g_strcmp0 (element_name, "pkgname") == 0)
+ return APPSTREAM_CACHE_SECTION_PKGNAME;
+ if (g_strcmp0 (element_name, "name") == 0)
+ return APPSTREAM_CACHE_SECTION_NAME;
+ if (g_strcmp0 (element_name, "summary") == 0)
+ return APPSTREAM_CACHE_SECTION_SUMMARY;
+ if (g_strcmp0 (element_name, "url") == 0)
+ return APPSTREAM_CACHE_SECTION_URL;
+ if (g_strcmp0 (element_name, "description") == 0)
+ return APPSTREAM_CACHE_SECTION_DESCRIPTION;
+ if (g_strcmp0 (element_name, "icon") == 0)
+ return APPSTREAM_CACHE_SECTION_ICON;
+ if (g_strcmp0 (element_name, "appcategories") == 0)
+ return APPSTREAM_CACHE_SECTION_APPCATEGORIES;
+ if (g_strcmp0 (element_name, "appcategory") == 0)
+ return APPSTREAM_CACHE_SECTION_APPCATEGORY;
+ return APPSTREAM_CACHE_SECTION_UNKNOWN;
+}
+
+/**
+ * appstream_cache_selection_to_string:
+ */
+static const gchar *
+appstream_cache_selection_to_string (AppstreamCacheSection section)
+{
+ if (section == APPSTREAM_CACHE_SECTION_APPLICATIONS)
+ return "applications";
+ if (section == APPSTREAM_CACHE_SECTION_APPLICATION)
+ return "application";
+ if (section == APPSTREAM_CACHE_SECTION_ID)
+ return "id";
+ if (section == APPSTREAM_CACHE_SECTION_PKGNAME)
+ return "pkgname";
+ if (section == APPSTREAM_CACHE_SECTION_NAME)
+ return "name";
+ if (section == APPSTREAM_CACHE_SECTION_SUMMARY)
+ return "summary";
+ if (section == APPSTREAM_CACHE_SECTION_URL)
+ return "url";
+ if (section == APPSTREAM_CACHE_SECTION_DESCRIPTION)
+ return "description";
+ if (section == APPSTREAM_CACHE_SECTION_ICON)
+ return "icon";
+ if (section == APPSTREAM_CACHE_SECTION_APPCATEGORIES)
+ return "appcategories";
+ if (section == APPSTREAM_CACHE_SECTION_APPCATEGORY)
+ return "appcategory";
+ return NULL;
+}
+
+/**
+ * appstream_cache_icon_kind_from_string:
+ */
+static AppstreamAppIconKind
+appstream_cache_icon_kind_from_string (const gchar *kind_str)
+{
+ if (g_strcmp0 (kind_str, "stock") == 0)
+ return APPSTREAM_APP_ICON_KIND_STOCK;
+ if (g_strcmp0 (kind_str, "local") == 0 ||
+ g_strcmp0 (kind_str, "cached") == 0)
+ return APPSTREAM_APP_ICON_KIND_CACHED;
+ return APPSTREAM_APP_ICON_KIND_UNKNOWN;
+}
+
+typedef struct {
+ AppstreamApp *item_temp;
+ AppstreamCache *cache;
+ AppstreamCacheSection section;
+} AppstreamCacheHelper;
+
+/**
+ * appstream_cache_start_element_cb:
+ */
+static void
+appstream_cache_start_element_cb (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ AppstreamCacheHelper *helper = (AppstreamCacheHelper *) user_data;
+ AppstreamCacheSection section_new;
+ guint i;
+
+ /* process tag start */
+ section_new = appstream_cache_selection_from_string (element_name);
+ switch (section_new) {
+ case APPSTREAM_CACHE_SECTION_APPLICATIONS:
+ case APPSTREAM_CACHE_SECTION_APPCATEGORIES:
+ case APPSTREAM_CACHE_SECTION_APPCATEGORY:
+ /* ignore */
+ break;
+ case APPSTREAM_CACHE_SECTION_APPLICATION:
+ if (helper->item_temp != NULL ||
+ helper->section != APPSTREAM_CACHE_SECTION_APPLICATIONS) {
+ g_set_error (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "XML start %s invalid, section %s",
+ element_name,
+ appstream_cache_selection_to_string (helper->section));
+ return;
+ }
+ helper->item_temp = appstream_app_new ();
+ break;
+
+ case APPSTREAM_CACHE_SECTION_ICON:
+ /* get the icon kind */
+ for (i = 0; attribute_names[i] != NULL; i++) {
+ if (g_strcmp0 (attribute_names[i], "type") == 0) {
+ appstream_app_set_icon_kind (helper->item_temp,
+ appstream_cache_icon_kind_from_string
(attribute_values[i]));
+ break;
+ }
+ }
+ if (appstream_app_get_icon_kind (helper->item_temp) == APPSTREAM_APP_ICON_KIND_UNKNOWN) {
+ g_set_error_literal (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "icon type not set");
+ }
+ break;
+ case APPSTREAM_CACHE_SECTION_ID:
+ case APPSTREAM_CACHE_SECTION_PKGNAME:
+ case APPSTREAM_CACHE_SECTION_NAME:
+ case APPSTREAM_CACHE_SECTION_SUMMARY:
+ case APPSTREAM_CACHE_SECTION_URL:
+ case APPSTREAM_CACHE_SECTION_DESCRIPTION:
+ if (helper->item_temp == NULL ||
+ helper->section != APPSTREAM_CACHE_SECTION_APPLICATION) {
+ g_set_error (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "XML start %s invalid, section %s",
+ element_name,
+ appstream_cache_selection_to_string (helper->section));
+ return;
+ }
+ break;
+ default:
+ /* ignore unknown entries */
+ break;
+ }
+
+ /* save */
+ helper->section = section_new;
+}
+
+/**
+ * appstream_cache_end_element_cb:
+ */
+static void
+appstream_cache_end_element_cb (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ const gchar *id;
+ AppstreamCacheHelper *helper = (AppstreamCacheHelper *) user_data;
+ AppstreamCachePrivate *priv = helper->cache->priv;
+ AppstreamCacheSection section_new;
+ AppstreamApp *item;
+
+ section_new = appstream_cache_selection_from_string (element_name);
+ switch (section_new) {
+ case APPSTREAM_CACHE_SECTION_APPLICATIONS:
+ case APPSTREAM_CACHE_SECTION_APPCATEGORY:
+ /* ignore */
+ break;
+ case APPSTREAM_CACHE_SECTION_APPLICATION:
+
+ /* have we recorded this before? */
+ id = appstream_app_get_id (helper->item_temp);
+ item = g_hash_table_lookup (priv->hash_id, id);
+ if (item != NULL) {
+ g_set_error (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "duplicate AppStream entry: %s", id);
+ appstream_app_free (helper->item_temp);
+ } else {
+ g_ptr_array_add (priv->array, helper->item_temp);
+ g_hash_table_insert (priv->hash_id,
+ (gpointer) appstream_app_get_id (helper->item_temp),
+ helper->item_temp);
+ g_hash_table_insert (priv->hash_pkgname,
+ (gpointer) appstream_app_get_pkgname (helper->item_temp),
+ helper->item_temp);
+ }
+ helper->item_temp = NULL;
+ helper->section = APPSTREAM_CACHE_SECTION_APPLICATIONS;
+ break;
+ case APPSTREAM_CACHE_SECTION_ID:
+ case APPSTREAM_CACHE_SECTION_PKGNAME:
+ case APPSTREAM_CACHE_SECTION_APPCATEGORIES:
+ case APPSTREAM_CACHE_SECTION_NAME:
+ case APPSTREAM_CACHE_SECTION_ICON:
+ case APPSTREAM_CACHE_SECTION_SUMMARY:
+ case APPSTREAM_CACHE_SECTION_URL:
+ case APPSTREAM_CACHE_SECTION_DESCRIPTION:
+ helper->section = APPSTREAM_CACHE_SECTION_APPLICATION;
+ break;
+ default:
+ /* ignore unknown entries */
+ helper->section = APPSTREAM_CACHE_SECTION_APPLICATION;
+ break;
+ }
+}
+
+/**
+ * appstream_cache_text_cb:
+ */
+static void
+appstream_cache_text_cb (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ AppstreamCacheHelper *helper = (AppstreamCacheHelper *) user_data;
+
+ switch (helper->section) {
+ case APPSTREAM_CACHE_SECTION_UNKNOWN:
+ case APPSTREAM_CACHE_SECTION_APPLICATIONS:
+ case APPSTREAM_CACHE_SECTION_APPLICATION:
+ case APPSTREAM_CACHE_SECTION_APPCATEGORIES:
+ /* ignore */
+ break;
+ case APPSTREAM_CACHE_SECTION_APPCATEGORY:
+ if (helper->item_temp == NULL) {
+ g_set_error_literal (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "item_temp category invalid");
+ return;
+ }
+ appstream_app_add_category (helper->item_temp, text, text_len);
+ break;
+ case APPSTREAM_CACHE_SECTION_ID:
+ if (helper->item_temp == NULL ||
+ appstream_app_get_id (helper->item_temp) != NULL) {
+ g_set_error_literal (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "item_temp id invalid");
+ return;
+ }
+ if (text_len < 9) {
+ g_set_error_literal (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "desktop id invalid");
+ return;
+ }
+ appstream_app_set_id (helper->item_temp, text, text_len - 8);
+ break;
+ case APPSTREAM_CACHE_SECTION_PKGNAME:
+ if (helper->item_temp == NULL ||
+ appstream_app_get_pkgname (helper->item_temp) != NULL) {
+ g_set_error_literal (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "item_temp pkgname invalid");
+ return;
+ }
+ appstream_app_set_pkgname (helper->item_temp, text, text_len);
+ break;
+ case APPSTREAM_CACHE_SECTION_NAME:
+ if (helper->item_temp == NULL ||
+ appstream_app_get_name (helper->item_temp) != NULL) {
+ g_set_error_literal (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "item_temp name invalid");
+ return;
+ }
+ appstream_app_set_name (helper->item_temp, text, text_len);
+ break;
+ case APPSTREAM_CACHE_SECTION_SUMMARY:
+ if (helper->item_temp == NULL ||
+ appstream_app_get_summary (helper->item_temp) != NULL) {
+ g_set_error_literal (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "item_temp summary invalid");
+ return;
+ }
+ appstream_app_set_summary (helper->item_temp, text, text_len);
+ break;
+ case APPSTREAM_CACHE_SECTION_URL:
+ if (helper->item_temp == NULL ||
+ appstream_app_get_url (helper->item_temp) != NULL) {
+ g_set_error_literal (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "item_temp url invalid");
+ return;
+ }
+ appstream_app_set_url (helper->item_temp, text, text_len);
+ break;
+ case APPSTREAM_CACHE_SECTION_DESCRIPTION:
+ if (helper->item_temp == NULL ||
+ appstream_app_get_description (helper->item_temp) != NULL) {
+ g_set_error_literal (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "item_temp description invalid");
+ return;
+ }
+ appstream_app_set_description (helper->item_temp, text, text_len);
+ break;
+ case APPSTREAM_CACHE_SECTION_ICON:
+ if (helper->item_temp == NULL ||
+ appstream_app_get_icon (helper->item_temp) != NULL) {
+ g_set_error_literal (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "item_temp icon invalid");
+ return;
+ }
+ appstream_app_set_icon (helper->item_temp, text, text_len);
+ break;
+ default:
+ /* ignore unknown entries */
+ break;
+ }
+}
+
+/**
+ * appstream_cache_parse_file:
+ */
+gboolean
+appstream_cache_parse_file (AppstreamCache *cache,
+ GFile *file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const gchar *content_type = NULL;
+ gboolean ret = TRUE;
+ gchar *data = NULL;
+ GConverter *converter = NULL;
+ GFileInfo *info = NULL;
+ GInputStream *file_stream;
+ GInputStream *stream_data = NULL;
+ GMarkupParseContext *ctx = NULL;
+ AppstreamCacheHelper *helper = NULL;
+ gssize len;
+ const GMarkupParser parser = {
+ appstream_cache_start_element_cb,
+ appstream_cache_end_element_cb,
+ appstream_cache_text_cb,
+ NULL /* passthrough */,
+ NULL /* error */ };
+
+ g_return_val_if_fail (APPSTREAM_IS_CACHE (cache), FALSE);
+
+ file_stream = G_INPUT_STREAM (g_file_read (file, cancellable, error));
+ if (file_stream == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+
+ /* what kind of file is this */
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ cancellable,
+ error);
+ if (info == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+
+ /* decompress if required */
+ content_type = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
+ if (g_strcmp0 (content_type, "application/gzip") == 0) {
+ converter = G_CONVERTER (g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP));
+ stream_data = g_converter_input_stream_new (file_stream, converter);
+ } else if (g_strcmp0 (content_type, "application/xml") == 0) {
+ stream_data = g_object_ref (file_stream);
+ } else {
+ ret = FALSE;
+ g_set_error (error,
+ APPSTREAM_CACHE_ERROR,
+ APPSTREAM_CACHE_ERROR_FAILED,
+ "cannot process file of type %s",
+ content_type);
+ }
+ helper = g_new0 (AppstreamCacheHelper, 1);
+ helper->cache = cache;
+ ctx = g_markup_parse_context_new (&parser,
+ G_MARKUP_PREFIX_ERROR_POSITION,
+ helper,
+ NULL);
+ data = g_malloc (32 * 1024);
+ while ((len = g_input_stream_read (stream_data, data, 32 * 1024, NULL, error)) > 0) {
+ ret = g_markup_parse_context_parse (ctx, data, len, error);
+ if (!ret)
+ goto out;
+ }
+ if (len < 0)
+ ret = FALSE;
+out:
+ if (helper->item_temp)
+ appstream_app_free (helper->item_temp);
+ if (info != NULL)
+ g_object_unref (info);
+ g_free (helper);
+ g_free (data);
+ if (ctx != NULL)
+ g_markup_parse_context_free (ctx);
+ if (stream_data != NULL)
+ g_object_unref (stream_data);
+ if (converter != NULL)
+ g_object_unref (converter);
+ g_object_unref (file_stream);
+ return ret;
+}
+
+/**
+ * appstream_cache_class_init:
+ **/
+static void
+appstream_cache_class_init (AppstreamCacheClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = appstream_cache_finalize;
+ g_type_class_add_private (klass, sizeof (AppstreamCachePrivate));
+}
+
+/**
+ * appstream_cache_init:
+ **/
+static void
+appstream_cache_init (AppstreamCache *cache)
+{
+ AppstreamCachePrivate *priv;
+ priv = cache->priv = APPSTREAM_CACHE_GET_PRIVATE (cache);
+ priv->array = g_ptr_array_new_with_free_func ((GDestroyNotify) appstream_app_free);
+ priv->hash_id = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ NULL,
+ NULL);
+ priv->hash_pkgname = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ NULL,
+ NULL);
+}
+
+/**
+ * appstream_cache_finalize:
+ **/
+static void
+appstream_cache_finalize (GObject *object)
+{
+ AppstreamCache *cache = APPSTREAM_CACHE (object);
+ AppstreamCachePrivate *priv = cache->priv;
+
+ g_ptr_array_unref (priv->array);
+ g_hash_table_unref (priv->hash_id);
+ g_hash_table_unref (priv->hash_pkgname);
+
+ G_OBJECT_CLASS (appstream_cache_parent_class)->finalize (object);
+}
+
+/**
+ * appstream_cache_new:
+ **/
+AppstreamCache *
+appstream_cache_new (void)
+{
+ AppstreamCache *cache;
+ cache = g_object_new (APPSTREAM_TYPE_CACHE, NULL);
+ return APPSTREAM_CACHE (cache);
+}
diff --git a/src/plugins/appstream-cache.h b/src/plugins/appstream-cache.h
new file mode 100644
index 0000000..e079707
--- /dev/null
+++ b/src/plugins/appstream-cache.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __APPSTREAM_CACHE_H
+#define __APPSTREAM_CACHE_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "appstream-app.h"
+
+G_BEGIN_DECLS
+
+#define APPSTREAM_TYPE_CACHE (appstream_cache_get_type ())
+#define APPSTREAM_CACHE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), APPSTREAM_TYPE_CACHE,
AppstreamCache))
+#define APPSTREAM_CACHE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), APPSTREAM_TYPE_CACHE,
AppstreamCacheClass))
+#define APPSTREAM_IS_CACHE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), APPSTREAM_TYPE_CACHE))
+#define APPSTREAM_IS_CACHE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), APPSTREAM_TYPE_CACHE))
+#define APPSTREAM_CACHE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), APPSTREAM_TYPE_CACHE,
AppstreamCacheClass))
+#define APPSTREAM_CACHE_ERROR (appstream_cache_error_quark ())
+
+typedef struct AppstreamCachePrivate AppstreamCachePrivate;
+
+typedef struct
+{
+ GObject parent;
+ AppstreamCachePrivate *priv;
+} AppstreamCache;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} AppstreamCacheClass;
+
+typedef enum {
+ APPSTREAM_CACHE_ERROR_FAILED,
+ APPSTREAM_CACHE_ERROR_LAST
+} AppstreamCacheError;
+
+GQuark appstream_cache_error_quark (void);
+GType appstream_cache_get_type (void);
+
+AppstreamCache *appstream_cache_new (void);
+gboolean appstream_cache_parse_file (AppstreamCache *cache,
+ GFile *file,
+ GCancellable *cancellable,
+ GError **error);
+guint appstream_cache_get_size (AppstreamCache *cache);
+GPtrArray *appstream_cache_get_items (AppstreamCache *cache);
+AppstreamApp *appstream_cache_get_item_by_id (AppstreamCache *cache,
+ const gchar *id);
+AppstreamApp *appstream_cache_get_item_by_pkgname (AppstreamCache *cache,
+ const gchar *pkgname);
+
+G_END_DECLS
+
+#endif /* __APPSTREAM_CACHE_H */
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
index 7b3d6e4..093bf1d 100644
--- a/src/plugins/gs-plugin-appstream.c
+++ b/src/plugins/gs-plugin-appstream.c
@@ -23,34 +23,15 @@
#include <gs-plugin.h>
-#include "gs-appstream-item.h"
+#include "appstream-app.h"
+#include "appstream-cache.h"
#define GS_PLUGIN_APPSTREAM_ICONS_HASH "81f92592ce464df3baf4c480c4a4cc6e18efee52"
-typedef enum {
- GS_APPSTREAM_XML_SECTION_UNKNOWN,
- GS_APPSTREAM_XML_SECTION_APPLICATIONS,
- GS_APPSTREAM_XML_SECTION_APPLICATION,
- GS_APPSTREAM_XML_SECTION_ID,
- GS_APPSTREAM_XML_SECTION_PKGNAME,
- GS_APPSTREAM_XML_SECTION_NAME,
- GS_APPSTREAM_XML_SECTION_SUMMARY,
- GS_APPSTREAM_XML_SECTION_DESCRIPTION,
- GS_APPSTREAM_XML_SECTION_URL,
- GS_APPSTREAM_XML_SECTION_ICON,
- GS_APPSTREAM_XML_SECTION_APPCATEGORIES,
- GS_APPSTREAM_XML_SECTION_APPCATEGORY,
- GS_APPSTREAM_XML_SECTION_LAST
-} GsAppstreamXmlSection;
-
struct GsPluginPrivate {
+ AppstreamCache *cache;
gchar *cachedir;
- GsAppstreamXmlSection section;
- GsAppstreamItem *item_temp;
- GPtrArray *array; /* of GsAppstreamItem */
- GHashTable *hash_id; /* of GsAppstreamItem{id} */
- GHashTable *hash_pkgname; /* of GsAppstreamItem{pkgname} */
- gsize done_init;
+ gsize done_init;
};
/**
@@ -135,328 +116,6 @@ out:
}
/**
- * gs_appstream_selection_from_text:
- */
-static GsAppstreamXmlSection
-gs_appstream_selection_from_text (const gchar *element_name)
-{
- if (g_strcmp0 (element_name, "applications") == 0)
- return GS_APPSTREAM_XML_SECTION_APPLICATIONS;
- if (g_strcmp0 (element_name, "application") == 0)
- return GS_APPSTREAM_XML_SECTION_APPLICATION;
- if (g_strcmp0 (element_name, "id") == 0)
- return GS_APPSTREAM_XML_SECTION_ID;
- if (g_strcmp0 (element_name, "pkgname") == 0)
- return GS_APPSTREAM_XML_SECTION_PKGNAME;
- if (g_strcmp0 (element_name, "name") == 0)
- return GS_APPSTREAM_XML_SECTION_NAME;
- if (g_strcmp0 (element_name, "summary") == 0)
- return GS_APPSTREAM_XML_SECTION_SUMMARY;
- if (g_strcmp0 (element_name, "url") == 0)
- return GS_APPSTREAM_XML_SECTION_URL;
- if (g_strcmp0 (element_name, "description") == 0)
- return GS_APPSTREAM_XML_SECTION_DESCRIPTION;
- if (g_strcmp0 (element_name, "icon") == 0)
- return GS_APPSTREAM_XML_SECTION_ICON;
- if (g_strcmp0 (element_name, "appcategories") == 0)
- return GS_APPSTREAM_XML_SECTION_APPCATEGORIES;
- if (g_strcmp0 (element_name, "appcategory") == 0)
- return GS_APPSTREAM_XML_SECTION_APPCATEGORY;
- return GS_APPSTREAM_XML_SECTION_UNKNOWN;
-}
-
-/**
- * gs_appstream_selection_to_text:
- */
-static const gchar *
-gs_appstream_selection_to_text (GsAppstreamXmlSection section)
-{
- if (section == GS_APPSTREAM_XML_SECTION_APPLICATIONS)
- return "applications";
- if (section == GS_APPSTREAM_XML_SECTION_APPLICATION)
- return "application";
- if (section == GS_APPSTREAM_XML_SECTION_ID)
- return "id";
- if (section == GS_APPSTREAM_XML_SECTION_PKGNAME)
- return "pkgname";
- if (section == GS_APPSTREAM_XML_SECTION_NAME)
- return "name";
- if (section == GS_APPSTREAM_XML_SECTION_SUMMARY)
- return "summary";
- if (section == GS_APPSTREAM_XML_SECTION_URL)
- return "url";
- if (section == GS_APPSTREAM_XML_SECTION_DESCRIPTION)
- return "description";
- if (section == GS_APPSTREAM_XML_SECTION_ICON)
- return "icon";
- if (section == GS_APPSTREAM_XML_SECTION_APPCATEGORIES)
- return "appcategories";
- if (section == GS_APPSTREAM_XML_SECTION_APPCATEGORY)
- return "appcategory";
- return NULL;
-}
-
-/**
- * gs_appstream_icon_kind_from_text:
- */
-static GsAppstreamItemIconKind
-gs_appstream_icon_kind_from_text (const gchar *kind_str)
-{
- if (g_strcmp0 (kind_str, "stock") == 0)
- return GS_APPSTREAM_ITEM_ICON_KIND_STOCK;
- if (g_strcmp0 (kind_str, "local") == 0 ||
- g_strcmp0 (kind_str, "cached") == 0)
- return GS_APPSTREAM_ITEM_ICON_KIND_CACHED;
- g_warning ("icon type %s not recognised", kind_str);
- return GS_APPSTREAM_ITEM_ICON_KIND_UNKNOWN;
-}
-
-/**
- * gs_appstream_start_element_cb:
- */
-static void
-gs_appstream_start_element_cb (GMarkupParseContext *context,
- const gchar *element_name,
- const gchar **attribute_names,
- const gchar **attribute_values,
- gpointer user_data,
- GError **error)
-{
- GsPlugin *plugin = (GsPlugin *) user_data;
- GsAppstreamXmlSection section_new;
- guint i;
-
- /* process tag start */
- section_new = gs_appstream_selection_from_text (element_name);
- switch (section_new) {
- case GS_APPSTREAM_XML_SECTION_APPLICATIONS:
- case GS_APPSTREAM_XML_SECTION_APPCATEGORIES:
- case GS_APPSTREAM_XML_SECTION_APPCATEGORY:
- /* ignore */
- break;
- case GS_APPSTREAM_XML_SECTION_APPLICATION:
- if (plugin->priv->item_temp != NULL ||
- plugin->priv->section != GS_APPSTREAM_XML_SECTION_APPLICATIONS) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "XML start %s invalid, section %s",
- element_name,
- gs_appstream_selection_to_text (plugin->priv->section));
- return;
- }
- plugin->priv->item_temp = gs_appstream_item_new ();
- break;
-
- case GS_APPSTREAM_XML_SECTION_ICON:
- /* get the icon kind */
- for (i = 0; attribute_names[i] != NULL; i++) {
- if (g_strcmp0 (attribute_names[i], "type") == 0) {
- gs_appstream_item_set_icon_kind (plugin->priv->item_temp,
- gs_appstream_icon_kind_from_text
(attribute_values[i]));
- break;
- }
- }
- if (gs_appstream_item_get_icon_kind (plugin->priv->item_temp) ==
GS_APPSTREAM_ITEM_ICON_KIND_UNKNOWN) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "icon type not set");
- }
- break;
- case GS_APPSTREAM_XML_SECTION_ID:
- case GS_APPSTREAM_XML_SECTION_PKGNAME:
- case GS_APPSTREAM_XML_SECTION_NAME:
- case GS_APPSTREAM_XML_SECTION_SUMMARY:
- case GS_APPSTREAM_XML_SECTION_URL:
- case GS_APPSTREAM_XML_SECTION_DESCRIPTION:
- if (plugin->priv->item_temp == NULL ||
- plugin->priv->section != GS_APPSTREAM_XML_SECTION_APPLICATION) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "XML start %s invalid, section %s",
- element_name,
- gs_appstream_selection_to_text (plugin->priv->section));
- return;
- }
- break;
- default:
- /* ignore unknown entries */
- break;
- }
-
- /* save */
- plugin->priv->section = section_new;
-}
-
-/**
- * gs_appstream_end_element_cb:
- */
-static void
-gs_appstream_end_element_cb (GMarkupParseContext *context,
- const gchar *element_name,
- gpointer user_data,
- GError **error)
-{
- GsPlugin *plugin = (GsPlugin *) user_data;
- GsAppstreamXmlSection section_new;
-
- section_new = gs_appstream_selection_from_text (element_name);
- switch (section_new) {
- case GS_APPSTREAM_XML_SECTION_APPLICATIONS:
- case GS_APPSTREAM_XML_SECTION_APPCATEGORY:
- /* ignore */
- break;
- case GS_APPSTREAM_XML_SECTION_APPLICATION:
- /* save */
- g_ptr_array_add (plugin->priv->array, plugin->priv->item_temp);
- g_hash_table_insert (plugin->priv->hash_id,
- (gpointer) gs_appstream_item_get_id (plugin->priv->item_temp),
- plugin->priv->item_temp);
- g_hash_table_insert (plugin->priv->hash_pkgname,
- (gpointer) gs_appstream_item_get_pkgname (plugin->priv->item_temp),
- plugin->priv->item_temp);
- plugin->priv->item_temp = NULL;
- plugin->priv->section = GS_APPSTREAM_XML_SECTION_APPLICATIONS;
- break;
- case GS_APPSTREAM_XML_SECTION_ID:
- case GS_APPSTREAM_XML_SECTION_PKGNAME:
- case GS_APPSTREAM_XML_SECTION_APPCATEGORIES:
- case GS_APPSTREAM_XML_SECTION_NAME:
- case GS_APPSTREAM_XML_SECTION_ICON:
- case GS_APPSTREAM_XML_SECTION_SUMMARY:
- case GS_APPSTREAM_XML_SECTION_URL:
- case GS_APPSTREAM_XML_SECTION_DESCRIPTION:
- plugin->priv->section = GS_APPSTREAM_XML_SECTION_APPLICATION;
- break;
- default:
- /* ignore unknown entries */
- plugin->priv->section = GS_APPSTREAM_XML_SECTION_APPLICATION;
- break;
- }
-}
-
-/**
- * gs_appstream_text_cb:
- */
-static void
-gs_appstream_text_cb (GMarkupParseContext *context,
- const gchar *text,
- gsize text_len,
- gpointer user_data,
- GError **error)
-{
- GsPlugin *plugin = (GsPlugin *) user_data;
-
- switch (plugin->priv->section) {
- case GS_APPSTREAM_XML_SECTION_UNKNOWN:
- case GS_APPSTREAM_XML_SECTION_APPLICATIONS:
- case GS_APPSTREAM_XML_SECTION_APPLICATION:
- case GS_APPSTREAM_XML_SECTION_APPCATEGORIES:
- /* ignore */
- break;
- case GS_APPSTREAM_XML_SECTION_APPCATEGORY:
- if (plugin->priv->item_temp == NULL) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "item_temp category invalid");
- return;
- }
- gs_appstream_item_add_category (plugin->priv->item_temp, text, text_len);
- break;
- case GS_APPSTREAM_XML_SECTION_ID:
- if (plugin->priv->item_temp == NULL ||
- gs_appstream_item_get_id (plugin->priv->item_temp) != NULL) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "item_temp id invalid");
- return;
- }
- if (text_len < 9) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "desktop id invalid");
- return;
- }
- gs_appstream_item_set_id (plugin->priv->item_temp, text, text_len - 8);
- break;
- case GS_APPSTREAM_XML_SECTION_PKGNAME:
- if (plugin->priv->item_temp == NULL ||
- gs_appstream_item_get_pkgname (plugin->priv->item_temp) != NULL) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "item_temp pkgname invalid");
- return;
- }
- gs_appstream_item_set_pkgname (plugin->priv->item_temp, text, text_len);
- break;
- case GS_APPSTREAM_XML_SECTION_NAME:
- if (plugin->priv->item_temp == NULL ||
- gs_appstream_item_get_name (plugin->priv->item_temp) != NULL) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "item_temp name invalid");
- return;
- }
- gs_appstream_item_set_name (plugin->priv->item_temp, text, text_len);
- break;
- case GS_APPSTREAM_XML_SECTION_SUMMARY:
- if (plugin->priv->item_temp == NULL ||
- gs_appstream_item_get_summary (plugin->priv->item_temp) != NULL) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "item_temp summary invalid");
- return;
- }
- gs_appstream_item_set_summary (plugin->priv->item_temp, text, text_len);
- break;
- case GS_APPSTREAM_XML_SECTION_URL:
- if (plugin->priv->item_temp == NULL ||
- gs_appstream_item_get_url (plugin->priv->item_temp) != NULL) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "item_temp url invalid");
- return;
- }
- gs_appstream_item_set_url (plugin->priv->item_temp, text, text_len);
- break;
- case GS_APPSTREAM_XML_SECTION_DESCRIPTION:
- if (plugin->priv->item_temp == NULL ||
- gs_appstream_item_get_description (plugin->priv->item_temp) != NULL) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "item_temp description invalid");
- return;
- }
- gs_appstream_item_set_description (plugin->priv->item_temp, text, text_len);
- break;
- case GS_APPSTREAM_XML_SECTION_ICON:
- if (plugin->priv->item_temp == NULL ||
- gs_appstream_item_get_icon (plugin->priv->item_temp) != NULL) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "item_temp icon invalid");
- return;
- }
- gs_appstream_item_set_icon (plugin->priv->item_temp, text, text_len);
- break;
- default:
- /* ignore unknown entries */
- break;
- }
-}
-
-/**
* gs_plugin_parse_xml_file:
*/
static gboolean
@@ -465,60 +124,19 @@ gs_plugin_parse_xml_file (GsPlugin *plugin,
const gchar *filename,
GError **error)
{
- gboolean ret = TRUE;
- gchar *data = NULL;
+ gboolean ret;
gchar *path;
- GConverter *converter = NULL;
GFile *file;
- GInputStream *converter_stream = NULL;
- GInputStream *file_stream;
- GMarkupParseContext *ctx = NULL;
- gssize len;
- const GMarkupParser parser = {
- gs_appstream_start_element_cb,
- gs_appstream_end_element_cb,
- gs_appstream_text_cb,
- NULL /* passthrough */,
- NULL /* error */ };
+ /* load this specific file */
path = g_build_filename (parent_dir, filename, NULL);
file = g_file_new_for_path (path);
- file_stream = G_INPUT_STREAM (g_file_read (file, NULL, error));
- if (file_stream == NULL) {
- ret = FALSE;
+ ret = appstream_cache_parse_file (plugin->priv->cache, file, NULL, error);
+ if (!ret)
goto out;
- }
- converter = G_CONVERTER (g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP));
- converter_stream = g_converter_input_stream_new (file_stream, converter);
- ctx = g_markup_parse_context_new (&parser,
- G_MARKUP_PREFIX_ERROR_POSITION,
- plugin,
- NULL);
- data = g_malloc (32 * 1024);
- while ((len = g_input_stream_read (converter_stream, data, 32 * 1024, NULL, error)) > 0) {
- ret = g_markup_parse_context_parse (ctx, data, len, error);
- if (!ret)
- goto out;
- }
- if (len < 0)
- ret = FALSE;
out:
- /* reset in case we failed parsing */
- if (plugin->priv->item_temp) {
- gs_appstream_item_free (plugin->priv->item_temp);
- plugin->priv->item_temp = NULL;
- }
-
- g_free (data);
g_free (path);
- if (ctx != NULL)
- g_markup_parse_context_free (ctx);
- if (converter_stream != NULL)
- g_object_unref (converter_stream);
- if (converter != NULL)
- g_object_unref (converter);
g_object_unref (file);
- g_object_unref (file_stream);
return ret;
}
@@ -560,15 +178,7 @@ gs_plugin_initialize (GsPlugin *plugin)
{
/* create private area */
plugin->priv = GS_PLUGIN_GET_PRIVATE (GsPluginPrivate);
- plugin->priv->array = g_ptr_array_new_with_free_func ((GDestroyNotify) gs_appstream_item_free);
- plugin->priv->hash_id = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- NULL,
- NULL);
- plugin->priv->hash_pkgname = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- NULL,
- NULL);
+ plugin->priv->cache = appstream_cache_new ();
/* this is per-user */
plugin->priv->cachedir = g_build_filename (g_get_user_cache_dir(),
@@ -592,9 +202,7 @@ void
gs_plugin_destroy (GsPlugin *plugin)
{
g_free (plugin->priv->cachedir);
- g_ptr_array_unref (plugin->priv->array);
- g_hash_table_unref (plugin->priv->hash_id);
- g_hash_table_unref (plugin->priv->hash_pkgname);
+ g_object_unref (plugin->priv->cache);
}
/**
@@ -619,7 +227,7 @@ gs_plugin_startup (GsPlugin *plugin, GError **error)
if (!ret)
goto out;
g_debug ("Parsed %i entries of XML\t:%.1fms",
- plugin->priv->array->len,
+ appstream_cache_get_size (plugin->priv->cache),
g_timer_elapsed (timer, NULL) * 1000);
out:
@@ -634,7 +242,7 @@ out:
static gboolean
gs_plugin_refine_item (GsPlugin *plugin,
GsApp *app,
- GsAppstreamItem *item,
+ AppstreamApp *item,
GError **error)
{
gboolean ret = TRUE;
@@ -649,38 +257,38 @@ gs_plugin_refine_item (GsPlugin *plugin,
gs_app_set_kind (app, GS_APP_KIND_NORMAL);
/* set id */
- if (gs_appstream_item_get_id (item) != NULL && gs_app_get_id (app) == NULL)
- gs_app_set_id (app, gs_appstream_item_get_id (item));
+ if (appstream_app_get_id (item) != NULL && gs_app_get_id (app) == NULL)
+ gs_app_set_id (app, appstream_app_get_id (item));
/* set name */
- if (gs_appstream_item_get_name (item) != NULL && gs_app_get_name (app) == NULL)
- gs_app_set_name (app, gs_appstream_item_get_name (item));
+ if (appstream_app_get_name (item) != NULL && gs_app_get_name (app) == NULL)
+ gs_app_set_name (app, appstream_app_get_name (item));
/* set summary */
- if (gs_appstream_item_get_summary (item) != NULL && gs_app_get_summary (app) == NULL)
- gs_app_set_summary (app, gs_appstream_item_get_summary (item));
+ if (appstream_app_get_summary (item) != NULL && gs_app_get_summary (app) == NULL)
+ gs_app_set_summary (app, appstream_app_get_summary (item));
/* set url */
- if (gs_appstream_item_get_url (item) != NULL && gs_app_get_url (app) == NULL)
- gs_app_set_url (app, gs_appstream_item_get_url (item));
+ if (appstream_app_get_url (item) != NULL && gs_app_get_url (app) == NULL)
+ gs_app_set_url (app, appstream_app_get_url (item));
/* set description */
- if (gs_appstream_item_get_description (item) != NULL && gs_app_get_description (app) == NULL)
- gs_app_set_description (app, gs_appstream_item_get_description (item));
+ if (appstream_app_get_description (item) != NULL && gs_app_get_description (app) == NULL)
+ gs_app_set_description (app, appstream_app_get_description (item));
/* set icon */
- if (gs_appstream_item_get_icon (item) != NULL && gs_app_get_pixbuf (app) == NULL) {
- if (gs_appstream_item_get_icon_kind (item) == GS_APPSTREAM_ITEM_ICON_KIND_STOCK) {
+ if (appstream_app_get_icon (item) != NULL && gs_app_get_pixbuf (app) == NULL) {
+ if (appstream_app_get_icon_kind (item) == APPSTREAM_APP_ICON_KIND_STOCK) {
pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
- gs_appstream_item_get_icon (item),
+ appstream_app_get_icon (item),
plugin->pixbuf_size,
GTK_ICON_LOOKUP_USE_BUILTIN |
GTK_ICON_LOOKUP_FORCE_SIZE,
error);
- } else if (gs_appstream_item_get_icon_kind (item) == GS_APPSTREAM_ITEM_ICON_KIND_CACHED) {
+ } else if (appstream_app_get_icon_kind (item) == APPSTREAM_APP_ICON_KIND_CACHED) {
icon_path = g_strdup_printf ("%s/%s.png",
plugin->priv->cachedir,
- gs_appstream_item_get_icon (item));
+ appstream_app_get_icon (item));
pixbuf = gdk_pixbuf_new_from_file_at_size (icon_path,
plugin->pixbuf_size,
plugin->pixbuf_size,
@@ -696,8 +304,8 @@ gs_plugin_refine_item (GsPlugin *plugin,
}
/* set package name */
- if (gs_appstream_item_get_pkgname (item) != NULL && gs_app_get_metadata_item (app, "package-name") ==
NULL)
- gs_app_set_metadata (app, "package-name", gs_appstream_item_get_pkgname (item));
+ if (appstream_app_get_pkgname (item) != NULL && gs_app_get_metadata_item (app, "package-name") ==
NULL)
+ gs_app_set_metadata (app, "package-name", appstream_app_get_pkgname (item));
out:
g_free (icon_path);
if (pixbuf != NULL)
@@ -715,13 +323,13 @@ gs_plugin_refine_from_id (GsPlugin *plugin,
{
const gchar *id;
gboolean ret = TRUE;
- GsAppstreamItem *item;
+ AppstreamApp *item;
/* find anything that matches the ID */
id = gs_app_get_id (app);
if (id == NULL)
goto out;
- item = g_hash_table_lookup (plugin->priv->hash_id, id);
+ item = appstream_cache_get_item_by_id (plugin->priv->cache, id);
if (item == NULL) {
g_debug ("no AppStream match for [id] %s", id);
goto out;
@@ -745,13 +353,13 @@ gs_plugin_refine_from_pkgname (GsPlugin *plugin,
{
const gchar *pkgname;
gboolean ret = TRUE;
- GsAppstreamItem *item;
+ AppstreamApp *item;
/* find anything that matches the ID */
pkgname = gs_app_get_metadata_item (app, "package-name");
if (pkgname == NULL)
goto out;
- item = g_hash_table_lookup (plugin->priv->hash_pkgname, pkgname);
+ item = appstream_cache_get_item_by_pkgname (plugin->priv->cache, pkgname);
if (item == NULL) {
g_debug ("no AppStream match for {pkgname} %s", pkgname);
goto out;
@@ -817,8 +425,9 @@ gs_plugin_add_category_apps (GsPlugin *plugin,
const gchar *search_id2 = NULL;
gboolean ret = TRUE;
GsApp *app;
- GsAppstreamItem *item;
+ AppstreamApp *item;
GsCategory *parent;
+ GPtrArray *array;
guint i;
/* load XML files */
@@ -842,17 +451,18 @@ gs_plugin_add_category_apps (GsPlugin *plugin,
}
/* just look at each app in turn */
- for (i = 0; i < plugin->priv->array->len; i++) {
- item = g_ptr_array_index (plugin->priv->array, i);
- if (gs_appstream_item_get_id (item) == NULL)
+ array = appstream_cache_get_items (plugin->priv->cache);
+ for (i = 0; i < array->len; i++) {
+ item = g_ptr_array_index (array, i);
+ if (appstream_app_get_id (item) == NULL)
continue;
- if (!gs_appstream_item_has_category (item, search_id1))
+ if (!appstream_app_has_category (item, search_id1))
continue;
- if (search_id2 != NULL && !gs_appstream_item_has_category (item, search_id2))
+ if (search_id2 != NULL && !appstream_app_has_category (item, search_id2))
continue;
/* got a search match, so add all the data we can */
- app = gs_app_new (gs_appstream_item_get_id (item));
+ app = gs_app_new (appstream_app_get_id (item));
ret = gs_plugin_refine_item (plugin, app, item, error);
if (!ret)
goto out;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]