diff options
author | Richard Hughes <richard@hughsie.com> | 2014-03-13 13:03:58 +0000 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2014-03-13 14:02:32 +0000 |
commit | a4f0fa55a790b07f62e2dac0c98fe9755f95e239 (patch) | |
tree | 9a5fc56f3bbebb735d0097df29dae39491ff4f6d | |
parent | 5701b1d5be00cda2e98d6c9df858e86db86b93a8 (diff) | |
download | appstream-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.c | 410 | ||||
-rw-r--r-- | libappstream-glib/as-app.h | 19 | ||||
-rw-r--r-- | libappstream-glib/as-image.c | 57 | ||||
-rw-r--r-- | libappstream-glib/as-image.h | 10 | ||||
-rw-r--r-- | libappstream-glib/as-release.c | 43 | ||||
-rw-r--r-- | libappstream-glib/as-release.h | 9 | ||||
-rw-r--r-- | libappstream-glib/as-screenshot.c | 82 | ||||
-rw-r--r-- | libappstream-glib/as-screenshot.h | 14 | ||||
-rw-r--r-- | libappstream-glib/as-self-test.c | 207 |
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); |