Don't use AppStream-glib for version helpers

Refactor the imported version format code now we now longer need to stick to
the API mistakes of libappstream-glib.
This commit is contained in:
Richard Hughes 2018-10-10 20:20:39 +01:00
parent d3d2c2c39f
commit 05cbb7245c
15 changed files with 533 additions and 49 deletions

View File

@ -232,7 +232,7 @@ fu_plugin_dell_inject_fake_data (FuPlugin *plugin,
data->can_switch_modes = TRUE;
}
static AsVersionParseFlag
static FuVersionFormat
fu_plugin_dell_get_version_format (FuPlugin *plugin)
{
const gchar *content;
@ -241,17 +241,15 @@ fu_plugin_dell_get_version_format (FuPlugin *plugin)
content = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER);
if (content == NULL)
return AS_VERSION_PARSE_FLAG_USE_TRIPLET;
return FU_VERSION_FORMAT_TRIPLET;
/* any quirks match */
group = g_strdup_printf ("SmbiosManufacturer=%s", content);
quirk = fu_plugin_lookup_quirk_by_id (plugin, group,
FU_QUIRKS_UEFI_VERSION_FORMAT);
if (g_strcmp0 (quirk, "quad") == 0)
return AS_VERSION_PARSE_FLAG_NONE;
/* fall back */
return AS_VERSION_PARSE_FLAG_USE_TRIPLET;
if (quirk == NULL)
return FU_VERSION_FORMAT_TRIPLET;
return fu_common_version_format_from_string (quirk);
}
static gboolean
@ -319,7 +317,7 @@ fu_plugin_usb_device_added (FuPlugin *plugin,
GError **error)
{
FuPluginData *data = fu_plugin_get_data (plugin);
AsVersionParseFlag parse_flags;
FuVersionFormat version_format;
guint16 pid;
guint16 vid;
const gchar *query_str;
@ -372,7 +370,7 @@ fu_plugin_usb_device_added (FuPlugin *plugin,
g_debug ("Dock cable type: %" G_GUINT32_FORMAT, dock_info->cable_type);
g_debug ("Dock location: %d", dock_info->location);
g_debug ("Dock component count: %d", dock_info->component_count);
parse_flags = fu_plugin_dell_get_version_format (plugin);
version_format = fu_plugin_dell_get_version_format (plugin);
for (guint i = 0; i < dock_info->component_count; i++) {
g_autofree gchar *fw_str = NULL;
@ -411,8 +409,8 @@ fu_plugin_usb_device_added (FuPlugin *plugin,
continue;
}
fw_str = as_utils_version_from_uint32 (dock_info->components[i].fw_version,
parse_flags);
fw_str = fu_common_version_from_uint32 (dock_info->components[i].fw_version,
version_format);
if (!fu_plugin_dock_node (plugin,
platform,
buf.record->dock_info_header.dock_type,
@ -427,8 +425,8 @@ fu_plugin_usb_device_added (FuPlugin *plugin,
/* if an old EC or invalid EC version found, create updatable parent */
if (old_ec)
flash_ver_str = as_utils_version_from_uint32 (dock_info->flash_pkg_version,
parse_flags);
flash_ver_str = fu_common_version_from_uint32 (dock_info->flash_pkg_version,
version_format);
if (!fu_plugin_dock_node (plugin,
platform,
buf.record->dock_info_header.dock_type,
@ -607,8 +605,8 @@ fu_plugin_dell_detect_tpm (FuPlugin *plugin, GError **error)
g_debug ("Creating primary TPM GUID %s and secondary TPM GUID %s",
tpm_guid_raw, tpm_guid_raw_alt);
version_str = as_utils_version_from_uint32 (out->fw_version,
AS_VERSION_PARSE_FLAG_NONE);
version_str = fu_common_version_from_uint32 (out->fw_version,
FU_VERSION_FORMAT_QUAD);
/* make it clear that the TPM is a discrete device of the product */
if (!data->smi_obj->fake_smbios) {

View File

@ -21,7 +21,8 @@
#include <string.h>
#include <stdio.h>
#include <appstream-glib.h>
#include "fu-common-version.h"
#include "dfu-common.h"
#include "dfu-firmware.h"
@ -642,8 +643,8 @@ dfu_firmware_to_string (DfuFirmware *firmware)
g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL);
release_str = as_utils_version_from_uint16 (priv->release,
AS_VERSION_PARSE_FLAG_USE_BCD);
release_str = fu_common_version_from_uint16 (priv->release,
FU_VERSION_FORMAT_BCD);
str = g_string_new ("");
g_string_append_printf (str, "vid: 0x%04x\n", priv->vid);
g_string_append_printf (str, "pid: 0x%04x\n", priv->pid);

View File

@ -11,7 +11,6 @@
#include <stdlib.h>
#include <glib/gi18n.h>
#include <glib-unix.h>
#include <appstream-glib.h>
#include "dfu-cipher-xtea.h"
#include "dfu-device-private.h"
@ -2036,8 +2035,8 @@ dfu_tool_list (DfuToolPrivate *priv, gchar **values, GError **error)
dfu_device_set_usb_context (device, usb_context);
if (!fu_device_probe (FU_DEVICE (device), NULL))
continue;
version = as_utils_version_from_uint16 (g_usb_device_get_release (usb_device),
AS_VERSION_PARSE_FLAG_USE_BCD);
version = fu_common_version_from_uint16 (g_usb_device_get_release (usb_device),
FU_VERSION_FORMAT_BCD);
g_print ("%s %04x:%04x [v%s]:\n",
/* TRANSLATORS: detected a DFU device */
_("Found"),

View File

@ -6,8 +6,6 @@
#include "config.h"
#include <appstream-glib.h>
#include "fu-plugin-vfuncs.h"
#include "dfu-device.h"

View File

@ -203,7 +203,7 @@ fu_nvme_device_set_version (FuNvmeDevice *self, const gchar *version, GError **e
version);
return FALSE;
}
version_new = as_utils_version_from_uint32 (tmp, AS_VERSION_PARSE_FLAG_NONE);
version_new = as_utils_version_from_uint32 (tmp, FU_VERSION_FORMAT_QUAD);
fu_device_set_version (FU_DEVICE (self), version_new);
return TRUE;
}

View File

@ -412,7 +412,7 @@ fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device)
}
}
static AsVersionParseFlag
static FuVersionFormat
fu_plugin_uefi_get_version_format_for_type (FuPlugin *plugin, FuUefiDeviceKind device_kind)
{
const gchar *content;
@ -421,21 +421,19 @@ fu_plugin_uefi_get_version_format_for_type (FuPlugin *plugin, FuUefiDeviceKind d
/* we have no information for devices */
if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE)
return AS_VERSION_PARSE_FLAG_USE_TRIPLET;
return FU_VERSION_FORMAT_TRIPLET;
content = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER);
if (content == NULL)
return AS_VERSION_PARSE_FLAG_USE_TRIPLET;
return FU_VERSION_FORMAT_TRIPLET;
/* any quirks match */
group = g_strdup_printf ("SmbiosManufacturer=%s", content);
quirk = fu_plugin_lookup_quirk_by_id (plugin, group,
FU_QUIRKS_UEFI_VERSION_FORMAT);
if (g_strcmp0 (quirk, "quad") == 0)
return AS_VERSION_PARSE_FLAG_NONE;
/* fall back */
return AS_VERSION_PARSE_FLAG_USE_TRIPLET;
if (quirk == NULL)
return FU_VERSION_FORMAT_TRIPLET;
return fu_common_version_format_from_string (quirk);
}
static const gchar *
@ -478,7 +476,7 @@ static gboolean
fu_plugin_uefi_coldplug_device (FuPlugin *plugin, FuUefiDevice *dev, GError **error)
{
FuUefiDeviceKind device_kind;
AsVersionParseFlag parse_flags;
FuVersionFormat version_format;
guint32 version_raw;
g_autofree gchar *name = NULL;
g_autofree gchar *version_lowest = NULL;
@ -486,17 +484,17 @@ fu_plugin_uefi_coldplug_device (FuPlugin *plugin, FuUefiDevice *dev, GError **er
/* add details to the device */
device_kind = fu_uefi_device_get_kind (dev);
parse_flags = fu_plugin_uefi_get_version_format_for_type (plugin, device_kind);
version_format = fu_plugin_uefi_get_version_format_for_type (plugin, device_kind);
version_raw = fu_uefi_device_get_version (dev);
version = as_utils_version_from_uint32 (version_raw, parse_flags);
version = fu_common_version_from_uint32 (version_raw, version_format);
fu_device_set_version (dev, version);
name = fu_plugin_uefi_get_name_for_type (plugin, fu_uefi_device_get_kind (dev));
if (name != NULL)
fu_device_set_name (FU_DEVICE (dev), name);
version_raw = fu_uefi_device_get_version_lowest (dev);
if (version_raw != 0) {
version_lowest = as_utils_version_from_uint32 (version_raw,
parse_flags);
version_lowest = fu_common_version_from_uint32 (version_raw,
version_format);
fu_device_set_version_lowest (FU_DEVICE (dev), version_lowest);
}
fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_INTERNAL);

307
src/fu-common-version.c Normal file
View File

@ -0,0 +1,307 @@
/*
* Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#define G_LOG_DOMAIN "FuCommon"
#include <config.h>
#include <string.h>
#include "fwupd-error.h"
#include "fu-common-version.h"
#define FU_COMMON_VERSION_DECODE_BCD(val) ((((val) >> 4) & 0x0f) * 10 + ((val) & 0x0f))
/**
* fu_common_version_format_from_string:
* @str: A string, e.g. `quad`
*
* Converts text to a display version type.
*
* Returns: A #FuVersionFormat, e.g. %FU_VERSION_FORMAT_TRIPLET
*
* Since: 1.2.0
**/
FuVersionFormat
fu_common_version_format_from_string (const gchar *str)
{
if (g_strcmp0 (str, "triplet") == 0)
return FU_VERSION_FORMAT_TRIPLET;
if (g_strcmp0 (str, "quad") == 0)
return FU_VERSION_FORMAT_QUAD;
if (g_strcmp0 (str, "bcd") == 0)
return FU_VERSION_FORMAT_BCD;
if (g_strcmp0 (str, "plain") == 0)
return FU_VERSION_FORMAT_PLAIN;
return FU_VERSION_FORMAT_QUAD;
}
/**
* fu_common_version_format_to_string:
* @str: A #FuVersionFormat, e.g. %FU_VERSION_FORMAT_TRIPLET
*
* Converts a display version type to text.
*
* Returns: A string, e.g. `quad`, or %NULL if not known
*
* Since: 1.2.0
**/
const gchar *
fu_common_version_format_to_string (FuVersionFormat kind)
{
if (kind == FU_VERSION_FORMAT_TRIPLET)
return "triplet";
if (kind == FU_VERSION_FORMAT_QUAD)
return "quad";
if (kind == FU_VERSION_FORMAT_BCD)
return "bcd";
if (kind == FU_VERSION_FORMAT_PLAIN)
return "plain";
return NULL;
}
/**
* fu_common_version_from_uint32:
* @val: A uint32le version number
* @kind: version kind used for formatting, e.g. %FU_VERSION_FORMAT_TRIPLET
*
* Returns a dotted decimal version string from a 32 bit number.
*
* Returns: A version number, e.g. "1.0.3", or %NULL if not supported
*
* Since: 1.2.0
**/
gchar *
fu_common_version_from_uint32 (guint32 val, FuVersionFormat kind)
{
if (kind == FU_VERSION_FORMAT_QUAD) {
/* AA.BB.CC.DD */
return g_strdup_printf ("%u.%u.%u.%u",
(val >> 24) & 0xff,
(val >> 16) & 0xff,
(val >> 8) & 0xff,
val & 0xff);
}
if (kind == FU_VERSION_FORMAT_TRIPLET) {
/* AA.BB.CCDD */
return g_strdup_printf ("%u.%u.%u",
(val >> 24) & 0xff,
(val >> 16) & 0xff,
val & 0xffff);
}
if (kind == FU_VERSION_FORMAT_PAIR) {
/* AABB.CCDD */
return g_strdup_printf ("%u.%u",
(val >> 16) & 0xffff,
val & 0xffff);
}
if (kind == FU_VERSION_FORMAT_PLAIN) {
/* AABBCCDD */
return g_strdup_printf ("%" G_GUINT32_FORMAT, val);
}
if (kind == FU_VERSION_FORMAT_BCD) {
/* AA.BB.CC.DD, but BCD */
return g_strdup_printf ("%u.%u.%u.%u",
FU_COMMON_VERSION_DECODE_BCD(val >> 24),
FU_COMMON_VERSION_DECODE_BCD(val >> 16),
FU_COMMON_VERSION_DECODE_BCD(val >> 8),
FU_COMMON_VERSION_DECODE_BCD(val));
}
return NULL;
}
/**
* fu_common_version_from_uint16:
* @val: A uint16le version number
* @kind: version kind used for formatting, e.g. %FU_VERSION_FORMAT_TRIPLET
*
* Returns a dotted decimal version string from a 16 bit number.
*
* Returns: A version number, e.g. "1.3", or %NULL if not supported
*
* Since: 1.2.0
**/
gchar *
fu_common_version_from_uint16 (guint16 val, FuVersionFormat kind)
{
if (kind == FU_VERSION_FORMAT_BCD) {
return g_strdup_printf ("%i.%i",
FU_COMMON_VERSION_DECODE_BCD(val >> 8),
FU_COMMON_VERSION_DECODE_BCD(val));
}
if (kind == FU_VERSION_FORMAT_PAIR) {
return g_strdup_printf ("%u.%u",
(guint) (val >> 8) & 0xff,
(guint) val & 0xff);
}
if (kind == FU_VERSION_FORMAT_PLAIN) {
return g_strdup_printf ("%" G_GUINT16_FORMAT, val);
}
return NULL;
}
static gint
fu_common_vercmp_char (gchar chr1, gchar chr2)
{
if (chr1 == chr2)
return 0;
if (chr1 == '~')
return -1;
if (chr2 == '~')
return 1;
return chr1 < chr2 ? -1 : 1;
}
static gint
fu_common_vercmp_chunk (const gchar *str1, const gchar *str2)
{
guint i;
/* trivial */
if (g_strcmp0 (str1, str2) == 0)
return 0;
if (str1 == NULL)
return 1;
if (str2 == NULL)
return -1;
/* check each char of the chunk */
for (i = 0; str1[i] != '\0' && str2[i] != '\0'; i++) {
gint rc = fu_common_vercmp_char (str1[i], str2[i]);
if (rc != 0)
return rc;
}
return fu_common_vercmp_char (str1[i], str2[i]);
}
/**
* fu_common_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"
* - Date in YYYYMMDD format, e.g. 20150915
*
* 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: 1.2.0
*/
gchar *
fu_common_version_parse (const gchar *version)
{
const gchar *version_noprefix = version;
gchar *endptr = NULL;
guint64 tmp;
guint base;
guint i;
/* already dotted decimal */
if (g_strstr_len (version, -1, ".") != NULL)
return g_strdup (version);
/* is a date */
if (g_str_has_prefix (version, "20") &&
strlen (version) == 8)
return g_strdup (version);
/* convert 0x prefixed strings to dotted decimal */
if (g_str_has_prefix (version, "0x")) {
version_noprefix += 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_noprefix, &endptr, base);
if (endptr != NULL && endptr[0] != '\0')
return g_strdup (version);
if (tmp == 0)
return g_strdup (version);
return fu_common_version_from_uint32 ((guint32) tmp, FU_VERSION_FORMAT_TRIPLET);
}
/**
* fu_common_vercmp:
* @version_a: the release version, e.g. 1.2.3
* @version_b: the release version, e.g. 1.2.3.1
*
* Compares version numbers for sorting.
*
* Returns: -1 if a < b, +1 if a > b, 0 if they are equal, and %G_MAXINT on error
*
* Since: 0.3.5
*/
gint
fu_common_vercmp (const gchar *version_a, const gchar *version_b)
{
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;
/* sanity check */
if (version_a == NULL || version_b == NULL)
return G_MAXINT;
/* optimisation */
if (g_strcmp0 (version_a, version_b) == 0)
return 0;
/* split into sections, and try to parse */
str_a = fu_common_version_parse (version_a);
str_b = fu_common_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 (guint i = 0; i < longest_split; i++) {
gchar *endptr_a = NULL;
gchar *endptr_b = NULL;
gint64 ver_a;
gint64 ver_b;
/* we lost or gained a dot */
if (split_a[i] == NULL)
return -1;
if (split_b[i] == NULL)
return 1;
/* compare integers */
ver_a = g_ascii_strtoll (split_a[i], &endptr_a, 10);
ver_b = g_ascii_strtoll (split_b[i], &endptr_b, 10);
if (ver_a < ver_b)
return -1;
if (ver_a > ver_b)
return 1;
/* compare strings */
if ((endptr_a != NULL && endptr_a[0] != '\0') ||
(endptr_b != NULL && endptr_b[0] != '\0')) {
gint rc = fu_common_vercmp_chunk (endptr_a, endptr_b);
if (rc < 0)
return -1;
if (rc > 0)
return 1;
}
}
/* we really shouldn't get here */
return 0;
}

45
src/fu-common-version.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef __FU_COMMON_VERSION_H__
#define __FU_COMMON_VERSION_H__
#include <gio/gio.h>
/**
* FuVersionFormat:
* @FU_VERSION_FORMAT_UNKNOWN: Unknown version format
* @FU_VERSION_FORMAT_PLAIN: Use plain integer version numbers
* @FU_VERSION_FORMAT_QUAD: Use Dell-style AA.BB.CC.DD version numbers
* @FU_VERSION_FORMAT_TRIPLET: Use Microsoft-style AA.BB.CCDD version numbers
* @FU_VERSION_FORMAT_PAIR: Use two AABB.CCDD version numbers
* @FU_VERSION_FORMAT_BCD: Use binary coded decimal notation
*
* The flags used when parsing version numbers.
**/
typedef enum {
FU_VERSION_FORMAT_UNKNOWN, /* Since: 1.2.0 */
FU_VERSION_FORMAT_PLAIN, /* Since: 1.2.0 */
FU_VERSION_FORMAT_QUAD, /* Since: 1.2.0 */
FU_VERSION_FORMAT_TRIPLET, /* Since: 1.2.0 */
FU_VERSION_FORMAT_PAIR, /* Since: 1.2.0 */
FU_VERSION_FORMAT_BCD, /* Since: 1.2.0 */
/*< private >*/
FU_VERSION_FORMAT_LAST
} FuVersionFormat;
FuVersionFormat fu_common_version_format_from_string (const gchar *str);
const gchar *fu_common_version_format_to_string (FuVersionFormat kind);
gint fu_common_vercmp (const gchar *version_a,
const gchar *version_b);
gchar *fu_common_version_from_uint32 (guint32 val,
FuVersionFormat flags);
gchar *fu_common_version_from_uint16 (guint16 val,
FuVersionFormat flags);
gchar *fu_common_version_parse (const gchar *version);
#endif /* __FU_COMMON_VERSION_H__ */

View File

@ -1007,7 +1007,7 @@ fu_engine_vendor_fixup_provide_value (AsApp *app)
static void
fu_engine_vendor_quirk_release_version (FuEngine *self, AsApp *app)
{
AsVersionParseFlag flags = AS_VERSION_PARSE_FLAG_USE_TRIPLET;
FuVersionFormat flags = FU_VERSION_FORMAT_TRIPLET;
GPtrArray *releases;
const gchar *quirk;
const gchar *version_format;
@ -1024,7 +1024,7 @@ fu_engine_vendor_quirk_release_version (FuEngine *self, AsApp *app)
g_auto(GStrv) globs = g_strsplit (quirk, ",", -1);
for (guint i = 0; globs[i] != NULL; i++) {
if (fnmatch (globs[i], as_app_get_id (app), 0) == 0) {
flags = AS_VERSION_PARSE_FLAG_NONE;
flags = FU_VERSION_FORMAT_QUAD;
break;
}
}
@ -1033,7 +1033,7 @@ fu_engine_vendor_quirk_release_version (FuEngine *self, AsApp *app)
/* specified in metadata */
version_format = as_app_get_metadata_item (app, "LVFS::VersionFormat");
if (g_strcmp0 (version_format, "quad") == 0)
flags = AS_VERSION_PARSE_FLAG_NONE;
flags = FU_VERSION_FORMAT_QUAD;
/* fix each release */
releases = as_app_get_releases (app);
@ -1056,7 +1056,7 @@ fu_engine_vendor_quirk_release_version (FuEngine *self, AsApp *app)
continue;
/* convert to dotted decimal */
version_new = as_utils_version_from_uint32 ((guint32) ver_uint32, flags);
version_new = fu_common_version_from_uint32 ((guint32) ver_uint32, flags);
as_release_set_version (rel, version_new);
}
}

View File

@ -10,6 +10,7 @@
#include <fwupd.h>
#include "fu-common-version.h"
#include "fu-device-private.h"
#include "fu-install-task.h"
#include "fu-keyring-utils.h"
@ -210,7 +211,7 @@ fu_install_task_check_requirements (FuInstallTask *self,
/* compare to the lowest supported version, if it exists */
version_lowest = fu_device_get_version_lowest (self->device);
if (version_lowest != NULL &&
as_utils_vercmp (version_lowest, version) > 0 &&
fu_common_vercmp (version_lowest, version) > 0 &&
(flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
g_set_error (error,
FWUPD_ERROR,
@ -221,7 +222,7 @@ fu_install_task_check_requirements (FuInstallTask *self,
}
/* check semver */
vercmp = as_utils_vercmp (version, version_release);
vercmp = fu_common_vercmp (version, version_release);
if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) {
g_set_error (error,
FWUPD_ERROR,

View File

@ -13,6 +13,8 @@
#include <gudev/gudev.h>
#include "fu-common.h"
#include "fu-common-guid.h"
#include "fu-common-version.h"
#include "fu-device.h"
#include "fu-device-locker.h"
#include "fu-quirks.h"

View File

@ -17,6 +17,7 @@
#include "fu-common-cab.h"
#include "fu-common-guid.h"
#include "fu-common-version.h"
#include "fu-chunk.h"
#include "fu-config.h"
#include "fu-device-list.h"
@ -2862,6 +2863,134 @@ fu_common_guid_func (void)
g_assert_cmpstr (guid2, ==, "1fbd1f2c-80f4-5d7c-a6ad-35c7b9bd5486");
}
static void
fu_common_version_func (void)
{
guint i;
struct {
guint32 val;
const gchar *ver;
FuVersionFormat flags;
} version_from_uint32[] = {
{ 0x0, "0.0.0.0", FU_VERSION_FORMAT_QUAD },
{ 0xff, "0.0.0.255", FU_VERSION_FORMAT_QUAD },
{ 0xff01, "0.0.255.1", FU_VERSION_FORMAT_QUAD },
{ 0xff0001, "0.255.0.1", FU_VERSION_FORMAT_QUAD },
{ 0xff000100, "255.0.1.0", FU_VERSION_FORMAT_QUAD },
{ 0x0, "0.0.0", FU_VERSION_FORMAT_TRIPLET },
{ 0xff, "0.0.255", FU_VERSION_FORMAT_TRIPLET },
{ 0xff01, "0.0.65281", FU_VERSION_FORMAT_TRIPLET },
{ 0xff0001, "0.255.1", FU_VERSION_FORMAT_TRIPLET },
{ 0xff000100, "255.0.256", FU_VERSION_FORMAT_TRIPLET },
{ 0x0, "0", FU_VERSION_FORMAT_PLAIN },
{ 0xff000100, "4278190336", FU_VERSION_FORMAT_PLAIN },
{ 0, NULL }
};
struct {
guint16 val;
const gchar *ver;
FuVersionFormat flags;
} version_from_uint16[] = {
{ 0x0, "0.0", FU_VERSION_FORMAT_PAIR },
{ 0xff, "0.255", FU_VERSION_FORMAT_PAIR },
{ 0xff01, "255.1", FU_VERSION_FORMAT_PAIR },
{ 0x0, "0.0", FU_VERSION_FORMAT_BCD },
{ 0x0110, "1.10", FU_VERSION_FORMAT_BCD },
{ 0x9999, "99.99", FU_VERSION_FORMAT_BCD },
{ 0x0, "0", FU_VERSION_FORMAT_PLAIN },
{ 0x1234, "4660", FU_VERSION_FORMAT_PLAIN },
{ 0, NULL }
};
struct {
const gchar *old;
const gchar *new;
} version_parse[] = {
{ "0", "0" },
{ "0x1a", "0.0.26" },
{ "257", "0.0.257" },
{ "1.2.3", "1.2.3" },
{ "0xff0001", "0.255.1" },
{ "16711681", "0.255.1" },
{ "20150915", "20150915" },
{ "dave", "dave" },
{ "0x1x", "0x1x" },
{ NULL, NULL }
};
/* check version conversion */
for (i = 0; version_from_uint32[i].ver != NULL; i++) {
g_autofree gchar *ver = NULL;
ver = fu_common_version_from_uint32 (version_from_uint32[i].val,
version_from_uint32[i].flags);
g_assert_cmpstr (ver, ==, version_from_uint32[i].ver);
}
for (i = 0; version_from_uint16[i].ver != NULL; i++) {
g_autofree gchar *ver = NULL;
ver = fu_common_version_from_uint16 (version_from_uint16[i].val,
version_from_uint16[i].flags);
g_assert_cmpstr (ver, ==, version_from_uint16[i].ver);
}
/* check version parsing */
for (i = 0; version_parse[i].old != NULL; i++) {
g_autofree gchar *ver = NULL;
ver = fu_common_version_parse (version_parse[i].old);
g_assert_cmpstr (ver, ==, version_parse[i].new);
}
}
static void
fu_common_vercmp_func (void)
{
/* same */
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("001.002.003", "001.002.003"), ==, 0);
/* same, not dotted decimal */
g_assert_cmpint (fu_common_vercmp ("1.2.3", "0x1020003"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("0x10203", "0x10203"), ==, 0);
/* upgrade and downgrade */
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.4"), <, 0);
g_assert_cmpint (fu_common_vercmp ("001.002.000", "001.002.009"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.2"), >, 0);
g_assert_cmpint (fu_common_vercmp ("001.002.009", "001.002.000"), >, 0);
/* unequal depth */
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3.1"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3.1", "1.2.4"), <, 0);
/* mixed-alpha-numeric */
g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3a"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3b"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3b", "1.2.3a"), >, 0);
/* alpha version append */
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3a"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3"), >, 0);
/* alpha only */
g_assert_cmpint (fu_common_vercmp ("alpha", "alpha"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("alpha", "beta"), <, 0);
g_assert_cmpint (fu_common_vercmp ("beta", "alpha"), >, 0);
/* alpha-compare */
g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2a.3"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2b.3"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2b.3", "1.2a.3"), >, 0);
/* tilde is all-powerful */
g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3~rc1"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3~rc1"), >, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3~rc2", "1.2.3~rc1"), >, 0);
/* invalid */
g_assert_cmpint (fu_common_vercmp ("1", NULL), ==, G_MAXINT);
g_assert_cmpint (fu_common_vercmp (NULL, "1"), ==, G_MAXINT);
g_assert_cmpint (fu_common_vercmp (NULL, NULL), ==, G_MAXINT);
}
int
main (int argc, char **argv)
{
@ -2924,6 +3053,8 @@ main (int argc, char **argv)
g_test_add_func ("/fwupd/keyring{pkcs7}", fu_keyring_pkcs7_func);
g_test_add_func ("/fwupd/chunk", fu_chunk_func);
g_test_add_func ("/fwupd/common{guid}", fu_common_guid_func);
g_test_add_func ("/fwupd/common{version}", fu_common_version_func);
g_test_add_func ("/fwupd/common{vercmp}", fu_common_vercmp_func);
g_test_add_func ("/fwupd/common{strstrip}", fu_common_strstrip_func);
g_test_add_func ("/fwupd/common{endian}", fu_common_endian_func);
g_test_add_func ("/fwupd/common{cab-success}", fu_common_store_cab_func);

View File

@ -8,8 +8,6 @@
#include "config.h"
#include <appstream-glib.h>
#include "fu-usb-device-private.h"
/**
@ -238,8 +236,8 @@ fu_usb_device_probe (FuDevice *device, GError **error)
/* set the version if the release has been set */
release = g_usb_device_get_release (priv->usb_device);
if (release != 0x0) {
g_autofree gchar *version = as_utils_version_from_uint16 (release,
AS_VERSION_PARSE_FLAG_USE_BCD);
g_autofree gchar *version = NULL;
version = fu_common_version_from_uint16 (release, FU_VERSION_FORMAT_BCD);
fu_device_set_version (device, version);
}

View File

@ -742,8 +742,8 @@ fu_util_install_prepared (FuUtilPrivate *priv, gchar **values, GError **error)
continue;
/* tell the user what's going to happen */
vercmp = as_utils_vercmp (fwupd_device_get_version (dev),
fwupd_release_get_version (rel));
vercmp = fu_common_vercmp (fwupd_device_get_version (dev),
fwupd_release_get_version (rel));
if (vercmp == 0) {
/* TRANSLATORS: the first replacement is a display name
* e.g. "ColorHugALS" and the second is a version number

View File

@ -27,6 +27,7 @@ libfwupdprivate = static_library(
sources : [
'fu-common.c',
'fu-common-guid.c',
'fu-common-version.c',
'fu-chunk.c',
'fu-device.c',
'fu-device-locker.c',
@ -111,6 +112,7 @@ fwupdtool = executable(
'fu-common.c',
'fu-common-cab.c',
'fu-common-guid.c',
'fu-common-version.c',
'fu-config.c',
'fu-keyring.c',
'fu-keyring-result.c',
@ -189,6 +191,7 @@ executable(
'fu-common.c',
'fu-common-cab.c',
'fu-common-guid.c',
'fu-common-version.c',
'fu-config.c',
'fu-keyring.c',
'fu-keyring-result.c',
@ -258,6 +261,7 @@ if get_option('tests')
'fu-common.c',
'fu-common-cab.c',
'fu-common-guid.c',
'fu-common-version.c',
'fu-config.c',
'fu-engine.c',
'fu-keyring.c',
@ -322,6 +326,8 @@ if get_option('introspection')
'fu-common.c',
'fu-common-guid.c',
'fu-common-guid.h',
'fu-common-version.c',
'fu-common-version.h',
'fu-common.h',
'fu-device.c',
'fu-device.h',