summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2014-03-13 13:03:58 +0000
committerRichard Hughes <richard@hughsie.com>2014-03-13 14:02:32 +0000
commita4f0fa55a790b07f62e2dac0c98fe9755f95e239 (patch)
tree9a5fc56f3bbebb735d0097df29dae39491ff4f6d
parent5701b1d5be00cda2e98d6c9df858e86db86b93a8 (diff)
downloadappstream-glib-a4f0fa55a790b07f62e2dac0c98fe9755f95e239.tar.gz
Add functions to parse from and to insert a GNode
This allows us to trivially serialize objects to XML and back. NOTE: as this uses a DOM parser, it's certainly not quick. Use something manual like expat or GMarkupParser to do this more efficiently and with less memory.
-rw-r--r--libappstream-glib/as-app.c410
-rw-r--r--libappstream-glib/as-app.h19
-rw-r--r--libappstream-glib/as-image.c57
-rw-r--r--libappstream-glib/as-image.h10
-rw-r--r--libappstream-glib/as-release.c43
-rw-r--r--libappstream-glib/as-release.h9
-rw-r--r--libappstream-glib/as-screenshot.c82
-rw-r--r--libappstream-glib/as-screenshot.h14
-rw-r--r--libappstream-glib/as-self-test.c207
9 files changed, 813 insertions, 38 deletions
diff --git a/libappstream-glib/as-app.c b/libappstream-glib/as-app.c
index 111d9bc..01e4e4c 100644
--- a/libappstream-glib/as-app.c
+++ b/libappstream-glib/as-app.c
@@ -22,12 +22,14 @@
#include "config.h"
#include "as-app.h"
+#include "as-node.h"
+#include "as-tag.h"
typedef struct _AsAppPrivate AsAppPrivate;
struct _AsAppPrivate
{
- AsAppIconKind icon_type;
- AsAppIdKind kind;
+ AsAppIconKind icon_kind;
+ AsAppIdKind id_kind;
GHashTable *comments; /* of locale:string */
GHashTable *descriptions; /* of locale:string */
GHashTable *languages; /* of locale:string */
@@ -120,19 +122,19 @@ as_app_class_init (AsAppClass *klass)
* as_app_id_kind_to_string:
**/
const gchar *
-as_app_id_kind_to_string (AsAppIdKind kind)
+as_app_id_kind_to_string (AsAppIdKind id_kind)
{
- if (kind == AS_APP_ID_KIND_DESKTOP)
+ if (id_kind == AS_APP_ID_KIND_DESKTOP)
return "desktop";
- if (kind == AS_APP_ID_KIND_CODEC)
+ if (id_kind == AS_APP_ID_KIND_CODEC)
return "codec";
- if (kind == AS_APP_ID_KIND_FONT)
+ if (id_kind == AS_APP_ID_KIND_FONT)
return "font";
- if (kind == AS_APP_ID_KIND_INPUT_METHOD)
+ if (id_kind == AS_APP_ID_KIND_INPUT_METHOD)
return "inputmethod";
- if (kind == AS_APP_ID_KIND_WEB_APP)
+ if (id_kind == AS_APP_ID_KIND_WEB_APP)
return "webapp";
- if (kind == AS_APP_ID_KIND_SOURCE)
+ if (id_kind == AS_APP_ID_KIND_SOURCE)
return "source";
return "unknown";
}
@@ -141,35 +143,34 @@ as_app_id_kind_to_string (AsAppIdKind kind)
* as_app_id_kind_from_string:
**/
AsAppIdKind
-as_app_id_kind_from_string (const gchar *kind)
+as_app_id_kind_from_string (const gchar *id_kind)
{
- if (g_strcmp0 (kind, "desktop") == 0)
+ if (g_strcmp0 (id_kind, "desktop") == 0)
return AS_APP_ID_KIND_DESKTOP;
- if (g_strcmp0 (kind, "codec") == 0)
+ if (g_strcmp0 (id_kind, "codec") == 0)
return AS_APP_ID_KIND_CODEC;
- if (g_strcmp0 (kind, "font") == 0)
+ if (g_strcmp0 (id_kind, "font") == 0)
return AS_APP_ID_KIND_FONT;
- if (g_strcmp0 (kind, "inputmethod") == 0)
+ if (g_strcmp0 (id_kind, "inputmethod") == 0)
return AS_APP_ID_KIND_INPUT_METHOD;
- if (g_strcmp0 (kind, "webapp") == 0)
+ if (g_strcmp0 (id_kind, "webapp") == 0)
return AS_APP_ID_KIND_WEB_APP;
- if (g_strcmp0 (kind, "source") == 0)
+ if (g_strcmp0 (id_kind, "source") == 0)
return AS_APP_ID_KIND_SOURCE;
return AS_APP_ID_KIND_UNKNOWN;
}
-
/**
* as_app_icon_kind_to_string:
**/
const gchar *
-as_app_icon_kind_to_string (AsAppIconKind icon_type)
+as_app_icon_kind_to_string (AsAppIconKind icon_kind)
{
- if (icon_type == AS_APP_ICON_KIND_CACHED)
+ if (icon_kind == AS_APP_ICON_KIND_CACHED)
return "cached";
- if (icon_type == AS_APP_ICON_KIND_STOCK)
+ if (icon_kind == AS_APP_ICON_KIND_STOCK)
return "stock";
- if (icon_type == AS_APP_ICON_KIND_REMOTE)
+ if (icon_kind == AS_APP_ICON_KIND_REMOTE)
return "remote";
return "unknown";
}
@@ -178,13 +179,13 @@ as_app_icon_kind_to_string (AsAppIconKind icon_type)
* as_app_icon_kind_from_string:
**/
AsAppIconKind
-as_app_icon_kind_from_string (const gchar *icon_type)
+as_app_icon_kind_from_string (const gchar *icon_kind)
{
- if (g_strcmp0 (icon_type, "cached") == 0)
+ if (g_strcmp0 (icon_kind, "cached") == 0)
return AS_APP_ICON_KIND_CACHED;
- if (g_strcmp0 (icon_type, "stock") == 0)
+ if (g_strcmp0 (icon_kind, "stock") == 0)
return AS_APP_ICON_KIND_STOCK;
- if (g_strcmp0 (icon_type, "remote") == 0)
+ if (g_strcmp0 (icon_kind, "remote") == 0)
return AS_APP_ICON_KIND_REMOTE;
return AS_APP_ICON_KIND_UNKNOWN;
}
@@ -279,7 +280,17 @@ AsAppIdKind
as_app_get_id_kind (AsApp *app)
{
AsAppPrivate *priv = GET_PRIVATE (app);
- return priv->kind;
+ return priv->id_kind;
+}
+
+/**
+ * as_app_get_icon_kind:
+ **/
+AsAppIconKind
+as_app_get_icon_kind (AsApp *app)
+{
+ AsAppPrivate *priv = GET_PRIVATE (app);
+ return priv->icon_kind;
}
/**
@@ -299,6 +310,8 @@ const gchar *
as_app_get_name (AsApp *app, const gchar *locale)
{
AsAppPrivate *priv = GET_PRIVATE (app);
+ if (locale == NULL)
+ locale = "C";
return g_hash_table_lookup (priv->names, locale);
}
@@ -309,6 +322,8 @@ const gchar *
as_app_get_comment (AsApp *app, const gchar *locale)
{
AsAppPrivate *priv = GET_PRIVATE (app);
+ if (locale == NULL)
+ locale = "C";
return g_hash_table_lookup (priv->comments, locale);
}
@@ -319,6 +334,8 @@ const gchar *
as_app_get_language (AsApp *app, const gchar *locale)
{
AsAppPrivate *priv = GET_PRIVATE (app);
+ if (locale == NULL)
+ locale = "C";
return g_hash_table_lookup (priv->languages, locale);
}
@@ -362,6 +379,16 @@ as_app_get_project_group (AsApp *app)
return priv->project_group;
}
+/**
+ * as_app_get_project_license:
+ **/
+const gchar *
+as_app_get_project_license (AsApp *app)
+{
+ AsAppPrivate *priv = GET_PRIVATE (app);
+ return priv->project_license;
+}
+
/******************************************************************************/
/**
@@ -385,10 +412,10 @@ as_app_set_id_full (AsApp *app, const gchar *id_full)
* as_app_set_id_kind:
**/
void
-as_app_set_id_kind (AsApp *app, AsAppIdKind kind)
+as_app_set_id_kind (AsApp *app, AsAppIdKind id_kind)
{
AsAppPrivate *priv = GET_PRIVATE (app);
- priv->kind = kind;
+ priv->id_kind = id_kind;
}
/**
@@ -428,10 +455,10 @@ as_app_set_icon (AsApp *app, const gchar *icon)
* as_app_set_icon_kind:
**/
void
-as_app_set_icon_kind (AsApp *app, AsAppIconKind icon_type)
+as_app_set_icon_kind (AsApp *app, AsAppIconKind icon_kind)
{
AsAppPrivate *priv = GET_PRIVATE (app);
- priv->icon_type = icon_type;
+ priv->icon_kind = icon_kind;
}
/**
@@ -610,6 +637,9 @@ void
as_app_add_metadata (AsApp *app, const gchar *key, const gchar *value)
{
AsAppPrivate *priv = GET_PRIVATE (app);
+ g_return_if_fail (key != NULL);
+ if (value == NULL)
+ value = "";
g_hash_table_insert (priv->metadata, g_strdup (key), g_strdup (value));
}
@@ -668,6 +698,326 @@ as_app_subsume (AsApp *app, AsApp *donor)
}
/**
+ * as_app_node_insert:
+ **/
+GNode *
+as_app_node_insert (AsApp *app, GNode *parent)
+{
+ AsAppPrivate *priv = GET_PRIVATE (app);
+ AsRelease *rel;
+ AsScreenshot *ss;
+ GNode *node_app;
+ GNode *node_tmp;
+ const gchar *tmp;
+ guint i;
+
+ node_app = as_node_insert (parent, "application", NULL, 0, NULL);
+
+ /* <id> */
+ as_node_insert (node_app, "id", priv->id_full, 0,
+ "type", as_app_id_kind_to_string (priv->id_kind),
+ NULL);
+
+ /* <pkgname> */
+ for (i = 0; i < priv->pkgnames->len; i++) {
+ tmp = g_ptr_array_index (priv->pkgnames, i);
+ as_node_insert (node_app, "pkgname", tmp, 0, NULL);
+ }
+
+ /* <name> */
+ as_node_insert_localized (node_app, "name", priv->names, 0);
+
+ /* <summary> */
+ as_node_insert_localized (node_app, "summary", priv->comments, 0);
+
+ /* <description> */
+ as_node_insert_localized (node_app, "description", priv->descriptions,
+ AS_NODE_INSERT_FLAG_PRE_ESCAPED);
+
+ /* <icon> */
+ if (priv->icon != NULL) {
+ as_node_insert (node_app, "icon", priv->icon, 0,
+ "type", as_app_icon_kind_to_string (priv->icon_kind),
+ NULL);
+ }
+
+ /* <categories> */
+ if (priv->categories->len > 0) {
+ node_tmp = as_node_insert (node_app, "appcategories", NULL, 0, NULL);
+ for (i = 0; i < priv->categories->len; i++) {
+ tmp = g_ptr_array_index (priv->categories, i);
+ as_node_insert (node_tmp, "appcategory", tmp, 0, NULL);
+ }
+ }
+
+ /* <keywords> */
+ if (priv->keywords->len > 0) {
+ node_tmp = as_node_insert (node_app, "keywords", NULL, 0, NULL);
+ for (i = 0; i < priv->keywords->len; i++) {
+ tmp = g_ptr_array_index (priv->keywords, i);
+ as_node_insert (node_tmp, "keyword", tmp, 0, NULL);
+ }
+ }
+
+ /* <mimetypes> */
+ if (priv->mimetypes->len > 0) {
+ node_tmp = as_node_insert (node_app, "mimetypes", NULL, 0, NULL);
+ for (i = 0; i < priv->mimetypes->len; i++) {
+ tmp = g_ptr_array_index (priv->mimetypes, i);
+ as_node_insert (node_tmp, "mimetype", tmp, 0, NULL);
+ }
+ }
+
+ /* <project_license> */
+ if (priv->project_license != NULL) {
+ as_node_insert (node_app, "project_license",
+ priv->project_license, 0, NULL);
+ }
+
+ /* <url> */
+// as_node_insert (node_app, "url", priv->homepage_url, 0,
+// "type", "homepage",
+// NULL);
+ as_node_insert_hash (node_app, "url", "type", priv->urls, 0);
+
+ /* <project_group> */
+ if (priv->project_group != NULL) {
+ as_node_insert (node_app, "project_group",
+ priv->project_group, 0, NULL);
+ }
+
+ /* <compulsory_for_desktop> */
+ if (priv->compulsory_for_desktop != NULL) {
+ for (i = 0; i < priv->compulsory_for_desktop->len; i++) {
+ tmp = g_ptr_array_index (priv->compulsory_for_desktop, i);
+ as_node_insert (node_app, "compulsory_for_desktop",
+ tmp, 0, NULL);
+ }
+ }
+
+ /* <screenshots> */
+ if (priv->screenshots->len > 0) {
+ node_tmp = as_node_insert (node_app, "screenshots", NULL, 0, NULL);
+ for (i = 0; i < priv->screenshots->len; i++) {
+ ss = g_ptr_array_index (priv->screenshots, i);
+ as_screenshot_node_insert (ss, node_tmp);
+ }
+ }
+
+ /* <releases> */
+ if (priv->releases->len > 0) {
+ node_tmp = as_node_insert (node_app, "releases", NULL, 0, NULL);
+ for (i = 0; i < priv->releases->len && i < 3; i++) {
+ rel = g_ptr_array_index (priv->releases, i);
+ as_release_node_insert (rel, node_tmp);
+ }
+ }
+
+ /* <languages> */
+ if (g_hash_table_size (priv->languages) > 0) {
+ node_tmp = as_node_insert (node_app, "languages", NULL, 0, NULL);
+ as_node_insert_hash (node_tmp, "lang", "percentage", priv->languages, TRUE);
+ }
+
+ /* <metadata> */
+ if (g_hash_table_size (priv->metadata) > 0) {
+ node_tmp = as_node_insert (node_app, "metadata", NULL, 0, NULL);
+ as_node_insert_hash (node_tmp, "value", "key", priv->metadata, FALSE);
+ }
+
+ return node_app;
+}
+
+/**
+ * as_app_node_parse_child:
+ **/
+static gboolean
+as_app_node_parse_child (AsApp *app, GNode *n, GError **error)
+{
+ AsTag tag;
+ GNode *c;
+ GString *xml;
+ const gchar *tmp;
+ gboolean ret = TRUE;
+
+ /* <id> */
+ tag = as_tag_from_string (as_node_get_name (n));
+ if (tag == AS_TAG_ID) {
+ tmp = as_node_get_attribute (n, "type");
+ as_app_set_id_kind (app, as_app_id_kind_from_string (tmp));
+ as_app_set_id_full (app, as_node_get_data (n));
+ goto out;
+ }
+
+ /* <pkgname> */
+ if (tag == AS_TAG_PKGNAME) {
+ as_app_add_pkgname (app, as_node_get_data (n));
+ goto out;
+ }
+
+ /* <name> */
+ if (tag == AS_TAG_NAME) {
+ as_app_set_name (app,
+ as_node_get_attribute (n, "xml:lang"),
+ as_node_get_data (n));
+ }
+
+ /* <summary> */
+ if (tag == AS_TAG_SUMMARY) {
+ as_app_set_comment (app,
+ as_node_get_attribute (n, "xml:lang"),
+ as_node_get_data (n));
+ }
+
+ /* <description> */
+ if (tag == AS_TAG_DESCRIPTION) {
+ xml = as_node_to_xml (n->children, AS_NODE_TO_XML_FLAG_NONE);
+ as_app_set_description (app,
+ as_node_get_attribute (n, "xml:lang"),
+ xml->str);
+ g_string_free (xml, TRUE);
+ }
+
+ /* <icon> */
+ if (tag == AS_TAG_ICON) {
+ tmp = as_node_get_attribute (n, "type");
+ as_app_set_icon_kind (app, as_app_icon_kind_from_string (tmp));
+ as_app_set_icon (app, as_node_get_data (n));
+ goto out;
+ }
+
+ /* <categories> */
+ if (tag == AS_TAG_APPCATEGORIES) {
+ for (c = n->children; c != NULL; c = c->next) {
+ if (g_strcmp0 (as_node_get_name (c),
+ "appcategory") != 0)
+ continue;
+ as_app_add_category (app, as_node_get_data (c));
+ }
+ }
+
+ /* <keywords> */
+ if (tag == AS_TAG_KEYWORDS) {
+ for (c = n->children; c != NULL; c = c->next) {
+ if (g_strcmp0 (as_node_get_name (c),
+ "keyword") != 0)
+ continue;
+ as_app_add_keyword (app, as_node_get_data (c));
+ }
+ }
+
+ /* <mimetypes> */
+ if (tag == AS_TAG_MIMETYPES) {
+ for (c = n->children; c != NULL; c = c->next) {
+ if (g_strcmp0 (as_node_get_name (c),
+ "mimetype") != 0)
+ continue;
+ as_app_add_mimetype (app, as_node_get_data (c));
+ }
+ }
+
+ /* <project_license> */
+ if (tag == AS_TAG_PROJECT_LICENSE) {
+ as_app_set_project_license (app, as_node_get_data (n));
+ goto out;
+ }
+
+ /* <url> */
+ if (tag == AS_TAG_URL) {
+ tmp = as_node_get_attribute (n, "type");
+ as_app_add_url (app, tmp, as_node_get_data (n));
+ goto out;
+ }
+
+ /* <project_group> */
+ if (tag == AS_TAG_PROJECT_GROUP) {
+ as_app_set_project_group (app, as_node_get_data (n));
+ goto out;
+ }
+
+ /* <compulsory_for_desktop> */
+ if (tag == AS_TAG_COMPULSORY_FOR_DESKTOP) {
+ as_app_add_compulsory_for_desktop (app, as_node_get_data (n));
+ goto out;
+ }
+
+ /* <screenshots> */
+ if (tag == AS_TAG_SCREENSHOTS) {
+ AsScreenshot *ss;
+ for (c = n->children; c != NULL; c = c->next) {
+ if (g_strcmp0 (as_node_get_name (c), "screenshot") != 0)
+ continue;
+ ss = as_screenshot_new ();
+ ret = as_screenshot_node_parse (ss, c, error);
+ if (!ret) {
+ g_object_unref (ss);
+ goto out;
+ }
+ as_app_add_screenshot (app, ss);
+ g_object_unref (ss);
+ }
+ }
+
+ /* <releases> */
+ if (tag == AS_TAG_RELEASES) {
+ AsRelease *r;
+ for (c = n->children; c != NULL; c = c->next) {
+ if (g_strcmp0 (as_node_get_name (c), "release") != 0)
+ continue;
+ r = as_release_new ();
+ ret = as_release_node_parse (r, c, error);
+ if (!ret) {
+ g_object_unref (r);
+ goto out;
+ }
+ as_app_add_release (app, r);
+ g_object_unref (r);
+ }
+ }
+
+ /* <languages> */
+ if (tag == AS_TAG_LANGUAGES) {
+ for (c = n->children; c != NULL; c = c->next) {
+ if (g_strcmp0 (as_node_get_name (c), "lang") != 0)
+ continue;
+ tmp = as_node_get_attribute (c, "percentage");
+ as_app_add_language (app, as_node_get_data (c), tmp);
+ }
+ }
+
+ /* <metadata> */
+ if (tag == AS_TAG_METADATA) {
+ for (c = n->children; c != NULL; c = c->next) {
+ if (g_strcmp0 (as_node_get_name (c), "value") != 0)
+ continue;
+ tmp = as_node_get_attribute (c, "key");
+ as_app_add_metadata (app, tmp, as_node_get_data (c));
+ }
+ }
+out:
+ return ret;
+}
+
+/**
+ * as_app_node_parse:
+ **/
+gboolean
+as_app_node_parse (AsApp *app, GNode *node, GError **error)
+{
+ GNode *n;
+ gboolean ret = TRUE;
+
+ /* parse each node */
+ for (n = node->children; n != NULL; n = n->next) {
+ ret = as_app_node_parse_child (app, n, error);
+ if (!ret)
+ goto out;
+ }
+out:
+ return ret;
+}
+
+/**
* as_app_new:
**/
AsApp *
diff --git a/libappstream-glib/as-app.h b/libappstream-glib/as-app.h
index b734821..f5bcfc1 100644
--- a/libappstream-glib/as-app.h
+++ b/libappstream-glib/as-app.h
@@ -76,12 +76,13 @@ GType as_app_get_type (void);
AsApp *as_app_new (void);
/* helpers */
-const gchar *as_app_id_kind_to_string (AsAppIdKind kind);
-AsAppIdKind as_app_id_kind_from_string (const gchar *kind);
-const gchar *as_app_icon_kind_to_string (AsAppIconKind icon_type);
-AsAppIconKind as_app_icon_kind_from_string (const gchar *icon_type);
+const gchar *as_app_id_kind_to_string (AsAppIdKind id_kind);
+AsAppIdKind as_app_id_kind_from_string (const gchar *id_kind);
+const gchar *as_app_icon_kind_to_string (AsAppIconKind icon_kind);
+AsAppIconKind as_app_icon_kind_from_string (const gchar *icon_kind);
/* getters */
+AsAppIconKind as_app_get_icon_kind (AsApp *app);
AsAppIdKind as_app_get_id_kind (AsApp *app);
GList *as_app_get_languages (AsApp *app);
GPtrArray *as_app_get_categories (AsApp *app);
@@ -94,6 +95,7 @@ const gchar *as_app_get_icon (AsApp *app);
const gchar *as_app_get_id (AsApp *app);
const gchar *as_app_get_id_full (AsApp *app);
const gchar *as_app_get_project_group (AsApp *app);
+const gchar *as_app_get_project_license (AsApp *app);
const gchar *as_app_get_name (AsApp *app,
const gchar *locale);
const gchar *as_app_get_comment (AsApp *app,
@@ -109,7 +111,7 @@ const gchar *as_app_get_url_item (AsApp *app,
void as_app_set_id_full (AsApp *app,
const gchar *id_full);
void as_app_set_id_kind (AsApp *app,
- AsAppIdKind kind);
+ AsAppIdKind id_kind);
void as_app_set_project_group (AsApp *app,
const gchar *project_group);
void as_app_set_project_license (AsApp *app,
@@ -117,7 +119,7 @@ void as_app_set_project_license (AsApp *app,
void as_app_set_icon (AsApp *app,
const gchar *icon);
void as_app_set_icon_kind (AsApp *app,
- AsAppIconKind icon_type);
+ AsAppIconKind icon_kind);
void as_app_set_name (AsApp *app,
const gchar *locale,
const gchar *name);
@@ -154,6 +156,11 @@ void as_app_remove_metadata (AsApp *app,
const gchar *key);
/* object methods */
+GNode *as_app_node_insert (AsApp *app,
+ GNode *parent);
+gboolean as_app_node_parse (AsApp *app,
+ GNode *node,
+ GError **error);
void as_app_subsume (AsApp *app,
AsApp *donor);
diff --git a/libappstream-glib/as-image.c b/libappstream-glib/as-image.c
index 177a332..8b17294 100644
--- a/libappstream-glib/as-image.c
+++ b/libappstream-glib/as-image.c
@@ -21,7 +21,11 @@
#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+
#include "as-image.h"
+#include "as-node.h"
typedef struct _AsImagePrivate AsImagePrivate;
struct _AsImagePrivate
@@ -143,6 +147,8 @@ as_image_set_url (AsImage *image, const gchar *url, gsize url_len)
{
AsImagePrivate *priv = GET_PRIVATE (image);
g_free (priv->url);
+ if (url_len == (gsize) -1)
+ url_len = strlen (url);
priv->url = g_strndup (url, url_len);
}
@@ -177,6 +183,57 @@ as_image_set_kind (AsImage *image, AsImageKind kind)
}
/**
+ * as_image_node_insert:
+ **/
+GNode *
+as_image_node_insert (AsImage *image, GNode *parent)
+{
+ AsImagePrivate *priv = GET_PRIVATE (image);
+ GNode *n;
+ gchar tmp_height[6];
+ gchar tmp_width[6];
+
+ if (priv->width > 0 && priv->height > 0) {
+ g_snprintf (tmp_width, sizeof (tmp_width), "%u", priv->width);
+ g_snprintf (tmp_height, sizeof (tmp_height), "%u", priv->height);
+ n = as_node_insert (parent, "image", priv->url,
+ AS_NODE_INSERT_FLAG_NONE,
+ "width", tmp_width,
+ "height", tmp_height,
+ "type", as_image_kind_to_string (priv->kind),
+ NULL);
+ } else {
+ n = as_node_insert (parent, "image", priv->url,
+ AS_NODE_INSERT_FLAG_NONE,
+ "type", as_image_kind_to_string (priv->kind),
+ NULL);
+ }
+ return n;
+}
+
+/**
+ * as_image_node_parse:
+ **/
+gboolean
+as_image_node_parse (AsImage *image, GNode *node, GError **error)
+{
+ const gchar *tmp;
+ tmp = as_node_get_attribute (node, "width");
+ if (tmp != NULL)
+ as_image_set_width (image, atoi (tmp));
+ tmp = as_node_get_attribute (node, "height");
+ if (tmp != NULL)
+ as_image_set_height (image, atoi (tmp));
+ tmp = as_node_get_attribute (node, "type");
+ if (tmp != NULL)
+ as_image_set_kind (image, as_image_kind_from_string (tmp));
+ tmp = as_node_get_data (node);
+ if (tmp != NULL)
+ as_image_set_url (image, tmp, -1);
+ return TRUE;
+}
+
+/**
* as_image_new:
**/
AsImage *
diff --git a/libappstream-glib/as-image.h b/libappstream-glib/as-image.h
index 0c1f870..2e90c73 100644
--- a/libappstream-glib/as-image.h
+++ b/libappstream-glib/as-image.h
@@ -60,14 +60,17 @@ typedef enum {
GType as_image_get_type (void);
AsImage *as_image_new (void);
+/* helpers */
AsImageKind as_image_kind_from_string (const gchar *kind);
const gchar *as_image_kind_to_string (AsImageKind kind);
+/* getters */
const gchar *as_image_get_url (AsImage *image);
guint as_image_get_width (AsImage *image);
guint as_image_get_height (AsImage *image);
AsImageKind as_image_get_kind (AsImage *image);
+/* setters */
void as_image_set_url (AsImage *image,
const gchar *url,
gsize url_len);
@@ -78,6 +81,13 @@ void as_image_set_height (AsImage *image,
void as_image_set_kind (AsImage *image,
AsImageKind kind);
+/* object methods */
+GNode *as_image_node_insert (AsImage *image,
+ GNode *parent);
+gboolean as_image_node_parse (AsImage *image,
+ GNode *node,
+ GError **error);
+
G_END_DECLS
#endif /* AS_IMAGE_H */
diff --git a/libappstream-glib/as-release.c b/libappstream-glib/as-release.c
index 9d1fe17..b4ab2a2 100644
--- a/libappstream-glib/as-release.c
+++ b/libappstream-glib/as-release.c
@@ -21,6 +21,9 @@
#include "config.h"
+#include <stdlib.h>
+
+#include "as-node.h"
#include "as-release.h"
typedef struct _AsReleasePrivate AsReleasePrivate;
@@ -129,6 +132,46 @@ as_release_set_description (AsRelease *release, const gchar *description)
}
/**
+ * as_release_node_insert:
+ **/
+GNode *
+as_release_node_insert (AsRelease *release, GNode *parent)
+{
+ AsReleasePrivate *priv = GET_PRIVATE (release);
+ GNode *n;
+ gchar *timestamp_str;
+
+ timestamp_str = g_strdup_printf ("%" G_GUINT64_FORMAT,
+ priv->timestamp);
+ n = as_node_insert (parent, "release", priv->description,
+ AS_NODE_INSERT_FLAG_NONE,
+ "timestamp", timestamp_str,
+ "version", priv->version,
+ NULL);
+ g_free (timestamp_str);
+ return n;
+}
+
+/**
+ * as_release_node_parse:
+ **/
+gboolean
+as_release_node_parse (AsRelease *release, GNode *node, GError **error)
+{
+ const gchar *tmp;
+ tmp = as_node_get_attribute (node, "timestamp");
+ if (tmp != NULL)
+ as_release_set_timestamp (release, atol (tmp));
+ tmp = as_node_get_attribute (node, "version");
+ if (tmp != NULL)
+ as_release_set_version (release, tmp);
+ tmp = as_node_get_data (node);
+ if (tmp != NULL)
+ as_release_set_description (release, tmp);
+ return TRUE;
+}
+
+/**
* as_release_new:
**/
AsRelease *
diff --git a/libappstream-glib/as-release.h b/libappstream-glib/as-release.h
index 9e09566..0c3b3f6 100644
--- a/libappstream-glib/as-release.h
+++ b/libappstream-glib/as-release.h
@@ -53,10 +53,12 @@ struct _AsReleaseClass
GType as_release_get_type (void);
AsRelease *as_release_new (void);
+/* getters */
const gchar *as_release_get_version (AsRelease *release);
guint64 as_release_get_timestamp (AsRelease *release);
const gchar *as_release_get_description (AsRelease *release);
+/* setters */
void as_release_set_version (AsRelease *release,
const gchar *version);
void as_release_set_timestamp (AsRelease *release,
@@ -64,6 +66,13 @@ void as_release_set_timestamp (AsRelease *release,
void as_release_set_description (AsRelease *release,
const gchar *description);
+/* object methods */
+GNode *as_release_node_insert (AsRelease *release,
+ GNode *parent);
+gboolean as_release_node_parse (AsRelease *release,
+ GNode *node,
+ GError **error);
+
G_END_DECLS
#endif /* AS_RELEASE_H */
diff --git a/libappstream-glib/as-screenshot.c b/libappstream-glib/as-screenshot.c
index 1e0ff4b..ab213d9 100644
--- a/libappstream-glib/as-screenshot.c
+++ b/libappstream-glib/as-screenshot.c
@@ -21,7 +21,11 @@
#include "config.h"
+#include <string.h>
+
+#include "as-node.h"
#include "as-screenshot.h"
+#include "as-tag.h"
typedef struct _AsScreenshotPrivate AsScreenshotPrivate;
struct _AsScreenshotPrivate
@@ -162,12 +166,90 @@ as_screenshot_set_caption (AsScreenshot *screenshot,
AsScreenshotPrivate *priv = GET_PRIVATE (screenshot);
if (locale == NULL)
locale = "C";
+ if (caption_length == (gsize) -1)
+ caption_length = strlen (caption);
g_hash_table_insert (priv->captions,
g_strdup (locale),
g_strndup (caption, caption_length));
}
/**
+ * as_screenshot_node_insert:
+ **/
+GNode *
+as_screenshot_node_insert (AsScreenshot *screenshot, GNode *parent)
+{
+ AsImage *image;
+ AsScreenshotPrivate *priv = GET_PRIVATE (screenshot);
+ GNode *n;
+ guint i;
+
+ n = as_node_insert (parent, "screenshot", NULL,
+ AS_NODE_INSERT_FLAG_NONE,
+ "type", as_screenshot_kind_to_string (priv->kind),
+ NULL);
+ as_node_insert_localized (n, "caption", priv->captions, 0);
+ for (i = 0; i < priv->images->len; i++) {
+ image = g_ptr_array_index (priv->images, i);
+ as_image_node_insert (image, n);
+ }
+ return n;
+}
+
+/**
+ * as_screenshot_node_parse:
+ **/
+gboolean
+as_screenshot_node_parse (AsScreenshot *screenshot, GNode *node, GError **error)
+{
+ AsImage *image;
+ AsScreenshotPrivate *priv = GET_PRIVATE (screenshot);
+ GHashTable *captions = NULL;
+ GList *keys;
+ GList *l;
+ GNode *c;
+ const gchar *tmp;
+ gboolean ret = TRUE;
+
+ tmp = as_node_get_attribute (node, "type");
+ if (tmp != NULL) {
+ as_screenshot_set_kind (screenshot,
+ as_screenshot_kind_from_string (tmp));
+ }
+
+ /* add captions */
+ captions = as_node_get_localized (node, "caption");
+ if (captions != NULL) {
+ keys = g_hash_table_get_keys (captions);
+ for (l = keys; l != NULL; l = l->next) {
+ tmp = l->data;
+ as_screenshot_set_caption (screenshot,
+ tmp,
+ g_hash_table_lookup (captions, tmp),
+ -1);
+ }
+ g_list_free (keys);
+ }
+
+ /* add images */
+ for (c = node->children; c != NULL; c = c->next) {
+ if (as_tag_from_string (as_node_get_name (c)) != AS_TAG_IMAGE)
+ continue;
+ image = as_image_new ();
+ ret = as_image_node_parse (image, c, error);
+ if (!ret) {
+ g_object_unref (image);
+ goto out;
+ }
+ g_ptr_array_add (priv->images, image);
+ }
+out:
+ if (captions != NULL)
+ g_hash_table_unref (captions);
+ return ret;
+}
+
+/**
* as_screenshot_new:
**/
AsScreenshot *
diff --git a/libappstream-glib/as-screenshot.h b/libappstream-glib/as-screenshot.h
index ba603dc..c820d01 100644
--- a/libappstream-glib/as-screenshot.h
+++ b/libappstream-glib/as-screenshot.h
@@ -62,23 +62,33 @@ typedef enum {
GType as_screenshot_get_type (void);
AsScreenshot *as_screenshot_new (void);
+/* helpers */
AsScreenshotKind as_screenshot_kind_from_string (const gchar *kind);
const gchar *as_screenshot_kind_to_string (AsScreenshotKind kind);
+/* getters */
AsScreenshotKind as_screenshot_get_kind (AsScreenshot *screenshot);
-const gchar *as_screenshot_get_caption (AsScreenshot *app,
+const gchar *as_screenshot_get_caption (AsScreenshot *screenshot,
const gchar *locale);
GPtrArray *as_screenshot_get_images (AsScreenshot *screenshot);
+/* setters */
void as_screenshot_set_kind (AsScreenshot *screenshot,
AsScreenshotKind kind);
-void as_screenshot_set_caption (AsScreenshot *app,
+void as_screenshot_set_caption (AsScreenshot *screenshot,
const gchar *locale,
const gchar *caption,
gsize caption_length);
void as_screenshot_add_image (AsScreenshot *screenshot,
AsImage *image);
+/* object methods */
+GNode *as_screenshot_node_insert (AsScreenshot *screenshot,
+ GNode *parent);
+gboolean as_screenshot_node_parse (AsScreenshot *screenshot,
+ GNode *node,
+ GError **error);
+
G_END_DECLS
#endif /* AS_SCREENSHOT_H */
diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c
index d8947f1..623c67f 100644
--- a/libappstream-glib/as-self-test.c
+++ b/libappstream-glib/as-self-test.c
@@ -24,13 +24,217 @@
#include <glib.h>
#include "as-app.h"
+#include "as-image.h"
#include "as-node.h"
+#include "as-release.h"
+#include "as-screenshot.h"
+
+static void
+ch_test_release_func (void)
+{
+ AsRelease *release;
+ GError *error = NULL;
+ GNode *n;
+ GNode *root;
+ GString *xml;
+ const gchar *src = "<release version=\"0.1.2\" timestamp=\"123\"/>";
+ gboolean ret;
+
+ release = as_release_new ();
+
+ /* to object */
+ root = as_node_from_xml (src, -1, &error);
+ g_assert_no_error (error);
+ g_assert (root != NULL);
+ n = as_node_find (root, "release");
+ g_assert (n != NULL);
+ ret = as_release_node_parse (release, n, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ as_node_unref (root);
+
+ /* verify */
+ g_assert_cmpint (as_release_get_timestamp (release), ==, 123);
+ g_assert_cmpstr (as_release_get_version (release), ==, "0.1.2");
+
+ /* back to node */
+ root = as_node_new ();
+ n = as_release_node_insert (release, root);
+ xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
+ g_assert_cmpstr (xml->str, ==, src);
+ g_string_free (xml, TRUE);
+ as_node_unref (root);
+
+ g_object_unref (release);
+}
+
+static void
+ch_test_image_func (void)
+{
+ AsImage *image;
+ GError *error = NULL;
+ GNode *n;
+ GNode *root;
+ GString *xml;
+ const gchar *src =
+ "<image type=\"thumbnail\" height=\"12\" width=\"34\">"
+ "http://www.hughsie.com/a.jpg</image>";
+ gboolean ret;
+
+ image = as_image_new ();
+
+ /* to object */
+ root = as_node_from_xml (src, -1, &error);
+ g_assert_no_error (error);
+ g_assert (root != NULL);
+ n = as_node_find (root, "image");
+ g_assert (n != NULL);
+ ret = as_image_node_parse (image, n, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ as_node_unref (root);
+
+ /* verify */
+ g_assert_cmpint (as_image_get_kind (image), ==, AS_IMAGE_KIND_THUMBNAIL);
+ g_assert_cmpint (as_image_get_height (image), ==, 12);
+ g_assert_cmpint (as_image_get_width (image), ==, 34);
+ g_assert_cmpstr (as_image_get_url (image), ==, "http://www.hughsie.com/a.jpg");
+
+ /* back to node */
+ root = as_node_new ();
+ n = as_image_node_insert (image, root);
+ xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
+ g_assert_cmpstr (xml->str, ==, src);
+ g_string_free (xml, TRUE);
+ as_node_unref (root);
+
+ g_object_unref (image);
+}
+
+static void
+ch_test_screenshot_func (void)
+{
+ GPtrArray *images;
+ AsScreenshot *screenshot;
+ GError *error = NULL;
+ GNode *n;
+ GNode *root;
+ GString *xml;
+ const gchar *src =
+ "<screenshot type=\"normal\">"
+ "<caption>Hello</caption>"
+ "<image type=\"source\">http://1.png</image>"
+ "<image type=\"thumbnail\">http://2.png</image>"
+ "</screenshot>";
+ gboolean ret;
+
+ screenshot = as_screenshot_new ();
+
+ /* to object */
+ root = as_node_from_xml (src, -1, &error);
+ g_assert_no_error (error);
+ g_assert (root != NULL);
+ n = as_node_find (root, "screenshot");
+ g_assert (n != NULL);
+ ret = as_screenshot_node_parse (screenshot, n, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ /* verify */
+ g_assert_cmpint (as_screenshot_get_kind (screenshot), ==, AS_SCREENSHOT_KIND_NORMAL);
+ g_assert_cmpstr (as_screenshot_get_caption (screenshot, "C"), ==, "Hello");
+ images = as_screenshot_get_images (screenshot);
+ g_assert_cmpint (images->len, ==, 2);
+ as_node_unref (root);
+
+ /* back to node */
+ root = as_node_new ();
+ n = as_screenshot_node_insert (screenshot, root);
+ xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
+ g_assert_cmpstr (xml->str, ==, src);
+ g_string_free (xml, TRUE);
+ as_node_unref (root);
+
+ g_object_unref (screenshot);
+}
static void
ch_test_app_func (void)
{
AsApp *app;
+ GError *error = NULL;
+ GNode *n;
+ GNode *root;
+ GString *xml;
+ gboolean ret;
+ const gchar *src =
+ "<application>"
+ "<id type=\"desktop\">org.gnome.Software.desktop</id>"
+ "<pkgname>gnome-software</pkgname>"
+ "<name>Software</name>"
+ "<name xml:lang=\"pl\">Oprogramowanie</name>"
+ "<summary>Application manager</summary>"
+ "<description><p>Software allows you to find stuff</p></description>"
+ "<description xml:lang=\"pt_BR\"><p>O aplicativo Software.</p></description>"
+ "<icon type=\"cached\">org.gnome.Software.png</icon>"
+ "<appcategories>"
+ "<appcategory>System</appcategory>"
+ "</appcategories>"
+ "<project_license>GPLv2+</project_license>"
+ "<url type=\"homepage\">https://wiki.gnome.org/Design/Apps/Software</url>"
+ "<project_group>GNOME</project_group>"
+ "<compulsory_for_desktop>GNOME</compulsory_for_desktop>"
+ "<screenshots>"
+ "<screenshot type=\"default\">"
+ "<image type=\"thumbnail\" height=\"351\" width=\"624\">http://a.png</image>"
+ "</screenshot>"
+ "<screenshot type=\"normal\">"
+ "<image type=\"thumbnail\">http://b.png</image>"
+ "</screenshot>"
+ "</screenshots>"
+ "<releases>"
+ "<release version=\"3.11.90\" timestamp=\"1392724800\"/>"
+ "</releases>"
+ "<metadata>"
+ "<value key=\"X-Kudo-GTK3\"/>"
+ "</metadata>"
+ "</application>";
+
app = as_app_new ();
+
+ /* to object */
+ root = as_node_from_xml (src, -1, &error);
+ g_assert_no_error (error);
+ g_assert (root != NULL);
+ n = as_node_find (root, "application");
+ g_assert (n != NULL);
+ ret = as_app_node_parse (app, n, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ /* verify */
+ g_assert_cmpstr (as_app_get_id_full (app), ==, "org.gnome.Software.desktop");
+ g_assert_cmpstr (as_app_get_id (app), ==, "org.gnome.Software");
+ g_assert_cmpstr (as_app_get_name (app, "pl"), ==, "Oprogramowanie");
+ g_assert_cmpstr (as_app_get_comment (app, NULL), ==, "Application manager");
+ g_assert_cmpstr (as_app_get_icon (app), ==, "org.gnome.Software.png");
+ g_assert_cmpint (as_app_get_icon_kind (app), ==, AS_APP_ICON_KIND_CACHED);
+ g_assert_cmpstr (as_app_get_project_group (app), ==, "GNOME");
+ g_assert_cmpstr (as_app_get_project_license (app), ==, "GPLv2+");
+ g_assert_cmpint (as_app_get_categories(app)->len, ==, 1);
+ g_assert_cmpint (as_app_get_screenshots(app)->len, ==, 2);
+ g_assert_cmpint (as_app_get_releases(app)->len, ==, 1);
+ g_assert_cmpstr (as_app_get_metadata_item (app, "X-Kudo-GTK3"), ==, "");
+ as_node_unref (root);
+
+ /* back to node */
+ root = as_node_new ();
+ n = as_app_node_insert (app, root);
+ xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
+ g_assert_cmpstr (xml->str, ==, src);
+ g_string_free (xml, TRUE);
+ as_node_unref (root);
+
g_object_unref (app);
}
@@ -252,6 +456,9 @@ main (int argc, char **argv)
g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
/* tests go here */
+ g_test_add_func ("/AppStream/release", ch_test_release_func);
+ g_test_add_func ("/AppStream/image", ch_test_image_func);
+ g_test_add_func ("/AppStream/screenshot", ch_test_screenshot_func);
g_test_add_func ("/AppStream/app", ch_test_app_func);
g_test_add_func ("/AppStream/node", ch_test_node_func);
g_test_add_func ("/AppStream/node{xml}", ch_test_node_xml_func);