summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2015-09-24 09:47:33 +0100
committerRichard Hughes <richard@hughsie.com>2015-09-24 09:52:02 +0100
commitdaefcf13d36963bc77b09d7824d38f13dc5ba49b (patch)
treef2509e3f915951a4db7fb323972b8d9d723ee8e3
parentc14ea9def41aa41c2b6fd5f2eaf943dc3b5d459d (diff)
downloadappstream-glib-daefcf13d36963bc77b09d7824d38f13dc5ba49b.tar.gz
Always use a dotted-decimal representation of the version
This helps a lot for UEFI versions that just specify a uint32le number.
-rw-r--r--libappstream-glib/as-release.c12
-rw-r--r--libappstream-glib/as-self-test.c50
-rw-r--r--libappstream-glib/as-utils.c94
-rw-r--r--libappstream-glib/as-utils.h2
4 files changed, 144 insertions, 14 deletions
diff --git a/libappstream-glib/as-release.c b/libappstream-glib/as-release.c
index 7946deb..bcb00f1 100644
--- a/libappstream-glib/as-release.c
+++ b/libappstream-glib/as-release.c
@@ -320,17 +320,7 @@ as_release_set_version (AsRelease *release, const gchar *version)
{
AsReleasePrivate *priv = GET_PRIVATE (release);
g_free (priv->version);
-
- /* convert 0x prefixed strings to base 10 */
- if (g_str_has_prefix (version, "0x")) {
- guint64 tmp;
- tmp = g_ascii_strtoull (version + 2, NULL, 16);
- priv->version = g_strdup_printf ("%" G_GUINT64_FORMAT, tmp);
- return;
- }
-
- /* no special rule */
- priv->version = g_strdup (version);
+ priv->version = as_utils_version_parse (version);
}
/**
diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c
index 0d8e695..920cc12 100644
--- a/libappstream-glib/as-self-test.c
+++ b/libappstream-glib/as-self-test.c
@@ -378,7 +378,7 @@ as_test_release_func (void)
/* verify converting hex prefix */
as_release_set_version (release, "0x600100");
- g_assert_cmpstr (as_release_get_version (release), ==, "6291712");
+ g_assert_cmpstr (as_release_get_version (release), ==, "96.1.0");
}
static void
@@ -3522,6 +3522,49 @@ as_test_utils_func (void)
}
static void
+as_test_utils_version_func (void)
+{
+ guint i;
+ struct {
+ guint32 val;
+ const gchar *ver;
+ } version_from_uint32[] = {
+ { 0x0, "0" },
+ { 0xff, "255" },
+ { 0xff01, "255.1" },
+ { 0xff0001, "255.0.1" },
+ { 0xff000100, "255.0.1.0" },
+ { NULL, NULL }
+ };
+ struct {
+ const gchar *old;
+ const gchar *new;
+ } version_parse[] = {
+ { "0", "0" },
+ { "257", "1.1" },
+ { "1.2.3", "1.2.3" },
+ { "0xff0001", "255.0.1" },
+ { "16711681", "255.0.1" },
+ { "dave", "dave" },
+ { NULL, NULL }
+ };
+
+ /* check version conversion */
+ for (i = 0; version_from_uint32[i].ver != NULL; i++) {
+ g_autofree gchar *ver = NULL;
+ ver = as_utils_version_from_uint32 (version_from_uint32[i].val);
+ g_assert_cmpstr (ver, ==, version_from_uint32[i].ver);
+ }
+
+ /* check version parsing */
+ for (i = 0; version_parse[i].old != NULL; i++) {
+ g_autofree gchar *ver = NULL;
+ ver = as_utils_version_parse (version_parse[i].old);
+ g_assert_cmpstr (ver, ==, version_parse[i].new);
+ }
+}
+
+static void
as_test_store_app_install_func (void)
{
GError *error = NULL;
@@ -3819,6 +3862,10 @@ as_test_utils_vercmp_func (void)
/* same */
g_assert_cmpint (as_utils_vercmp ("1.2.3", "1.2.3"), ==, 0);
+ /* same, not dotted decimal */
+ g_assert_cmpint (as_utils_vercmp ("1.2.3", "0x10203"), ==, 0);
+ g_assert_cmpint (as_utils_vercmp ("0x10203", "0x10203"), ==, 0);
+
/* upgrade and downgrade */
g_assert_cmpint (as_utils_vercmp ("1.2.3", "1.2.4"), <, 0);
g_assert_cmpint (as_utils_vercmp ("1.2.3", "1.2.2"), >, 0);
@@ -4253,6 +4300,7 @@ main (int argc, char **argv)
g_test_add_func ("/AppStream/node{intltool}", as_test_node_intltool_func);
g_test_add_func ("/AppStream/node{sort}", as_test_node_sort_func);
g_test_add_func ("/AppStream/utils", as_test_utils_func);
+ g_test_add_func ("/AppStream/utils{version}", as_test_utils_version_func);
g_test_add_func ("/AppStream/utils{guid}", as_test_utils_guid_func);
g_test_add_func ("/AppStream/utils{icons}", as_test_utils_icons_func);
g_test_add_func ("/AppStream/utils{spdx-token}", as_test_utils_spdx_token_func);
diff --git a/libappstream-glib/as-utils.c b/libappstream-glib/as-utils.c
index ed25219..9180ba9 100644
--- a/libappstream-glib/as-utils.c
+++ b/libappstream-glib/as-utils.c
@@ -1393,6 +1393,8 @@ as_utils_vercmp (const gchar *version_a, const gchar *version_b)
gint64 ver_b;
guint i;
guint longest_split;
+ g_autofree gchar *str_a = NULL;
+ g_autofree gchar *str_b = NULL;
g_auto(GStrv) split_a = NULL;
g_auto(GStrv) split_b = NULL;
@@ -1405,8 +1407,10 @@ as_utils_vercmp (const gchar *version_a, const gchar *version_b)
return 0;
/* split into sections, and try to parse */
- split_a = g_strsplit (version_a, ".", -1);
- split_b = g_strsplit (version_b, ".", -1);
+ str_a = as_utils_version_parse (version_a);
+ str_b = as_utils_version_parse (version_b);
+ split_a = g_strsplit (str_a, ".", -1);
+ split_b = g_strsplit (str_b, ".", -1);
longest_split = MAX (g_strv_length (split_a), g_strv_length (split_b));
for (i = 0; i < longest_split; i++) {
@@ -1530,3 +1534,89 @@ as_utils_guid_from_string (const gchar *str)
g_assert (as_utils_guid_is_valid (tmp));
return tmp;
}
+
+/**
+ * as_utils_version_from_uint32:
+ * @val: A uint32le version number
+ *
+ * Returns a dotted decimal version string from a 32 bit number.
+ *
+ * Returns: A version number, e.g. "1.0.3"
+ *
+ * Since: 0.5.2
+ **/
+gchar *
+as_utils_version_from_uint32 (guint32 val)
+{
+ GString *str;
+ gboolean valid = FALSE;
+ guint i;
+ guint8 *tmp = (guint8 *) &val;
+
+ /* create version string */
+ str = g_string_sized_new (13);
+ for (i = 0; i < 4; i++) {
+ if (tmp[3 - i] > 0 || i == 3)
+ valid = TRUE;
+ if (valid)
+ g_string_append_printf (str, "%i.", tmp[3 - i]);
+ }
+
+ /* delete trailing dot */
+ if (str->len > 0)
+ g_string_truncate (str, str->len - 1);
+
+ return g_string_free (str, FALSE);
+}
+
+/**
+ * as_utils_version_parse:
+ * @version: A version number
+ *
+ * Returns a dotted decimal version string from a version string. The supported
+ * formats are:
+ *
+ * - Dotted decimal, e.g. "1.2.3"
+ * - Base 16, a hex number *with* a 0x prefix, e.g. "0x10203"
+ * - Base 10, a string containing just [0-9], e.g. "66051"
+ *
+ * Anything with a '.' or that doesn't match [0-9] or 0x[a-f,0-9] is considered
+ * a string and returned without modification.
+ *
+ * Returns: A version number, e.g. "1.0.3"
+ *
+ * Since: 0.5.2
+ */
+gchar *
+as_utils_version_parse (const gchar *version)
+{
+ gchar *endptr = NULL;
+ guint64 tmp;
+ guint base;
+ guint i;
+
+ /* already dotted decimal */
+ if (g_strstr_len (version, -1, ".") != NULL)
+ return g_strdup (version);
+
+ /* convert 0x prefixed strings to dotted decimal */
+ if (g_str_has_prefix (version, "0x")) {
+ version += 2;
+ base = 16;
+ } else {
+ /* for non-numeric content, just return the string */
+ for (i = 0; version[i] != '\0'; i++) {
+ if (!g_ascii_isdigit (version[i]))
+ return g_strdup (version);
+ }
+ base = 10;
+ }
+
+ /* convert */
+ tmp = g_ascii_strtoull (version, &endptr, base);
+ if (endptr != NULL && endptr[0] != '\0')
+ return g_strdup (version);
+ if (tmp == 0 || tmp < 0xff)
+ return g_strdup (version);
+ return as_utils_version_from_uint32 (tmp);
+}
diff --git a/libappstream-glib/as-utils.h b/libappstream-glib/as-utils.h
index aa0baf4..8e8d5b3 100644
--- a/libappstream-glib/as-utils.h
+++ b/libappstream-glib/as-utils.h
@@ -125,6 +125,8 @@ gint as_utils_vercmp (const gchar *version_a,
const gchar *version_b);
gboolean as_utils_guid_is_valid (const gchar *guid);
gchar *as_utils_guid_from_string (const gchar *str);
+gchar *as_utils_version_from_uint32 (guint32 val);
+gchar *as_utils_version_parse (const gchar *version);
G_END_DECLS