Coverage Report

Created: 2026-03-11 07:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupd/fwupd-common.c
Line
Count
Source
1
/*
2
 * Copyright 2017 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
#include "config.h"
8
9
#include "fwupd-common-private.h"
10
#include "fwupd-error.h"
11
12
#ifdef HAVE_GIO_UNIX
13
#include <errno.h>
14
#include <fcntl.h>
15
#include <glib/gstdio.h>
16
#include <unistd.h>
17
#endif
18
19
#ifdef HAVE_MEMFD_CREATE
20
#include <sys/mman.h>
21
#endif
22
23
#include <string.h>
24
25
/**
26
 * fwupd_checksum_guess_kind:
27
 * @checksum: (nullable): a checksum
28
 *
29
 * Guesses the checksum kind based on the length of the hash.
30
 *
31
 * Returns: a checksum type, e.g. %G_CHECKSUM_SHA1
32
 *
33
 * Since: 0.9.3
34
 **/
35
GChecksumType
36
fwupd_checksum_guess_kind(const gchar *checksum)
37
0
{
38
0
  guint len;
39
0
  g_return_val_if_fail(checksum != NULL, G_CHECKSUM_SHA1);
40
0
  len = strlen(checksum);
41
0
  if (len == 32)
42
0
    return G_CHECKSUM_MD5;
43
0
  if (len == 40)
44
0
    return G_CHECKSUM_SHA1;
45
0
  if (len == 64)
46
0
    return G_CHECKSUM_SHA256;
47
0
  if (len == 96)
48
0
    return G_CHECKSUM_SHA384;
49
0
  if (len == 128)
50
0
    return G_CHECKSUM_SHA512;
51
0
  return G_CHECKSUM_SHA1;
52
0
}
53
54
/**
55
 * fwupd_checksum_type_to_string_display:
56
 * @checksum_type: a #GChecksumType, e.g. %G_CHECKSUM_SHA1
57
 *
58
 * Formats a checksum type for display.
59
 *
60
 * Returns: text, or %NULL for invalid
61
 *
62
 * Since: 1.9.6
63
 **/
64
const gchar *
65
fwupd_checksum_type_to_string_display(GChecksumType checksum_type)
66
0
{
67
0
  if (checksum_type == G_CHECKSUM_MD5)
68
0
    return "MD5";
69
0
  if (checksum_type == G_CHECKSUM_SHA1)
70
0
    return "SHA1";
71
0
  if (checksum_type == G_CHECKSUM_SHA256)
72
0
    return "SHA256";
73
0
  if (checksum_type == G_CHECKSUM_SHA384)
74
0
    return "SHA384";
75
0
  if (checksum_type == G_CHECKSUM_SHA512)
76
0
    return "SHA512";
77
0
  return NULL;
78
0
}
79
80
/**
81
 * fwupd_checksum_format_for_display:
82
 * @checksum: (nullable): a checksum
83
 *
84
 * Formats a checksum for display.
85
 *
86
 * Returns: text, or %NULL for invalid
87
 *
88
 * Since: 0.9.3
89
 **/
90
gchar *
91
fwupd_checksum_format_for_display(const gchar *checksum)
92
0
{
93
0
  GChecksumType kind = fwupd_checksum_guess_kind(checksum);
94
0
  return g_strdup_printf("%s(%s)", fwupd_checksum_type_to_string_display(kind), checksum);
95
0
}
96
97
/**
98
 * fwupd_checksum_get_by_kind:
99
 * @checksums: (element-type utf8): checksums
100
 * @kind: a checksum type, e.g. %G_CHECKSUM_SHA512
101
 *
102
 * Gets a specific checksum kind.
103
 *
104
 * Returns: a checksum from the array, or %NULL if not found
105
 *
106
 * Since: 0.9.4
107
 **/
108
const gchar *
109
fwupd_checksum_get_by_kind(GPtrArray *checksums, GChecksumType kind)
110
0
{
111
0
  g_return_val_if_fail(checksums != NULL, NULL);
112
0
  for (guint i = 0; i < checksums->len; i++) {
113
0
    const gchar *checksum = g_ptr_array_index(checksums, i);
114
0
    if (fwupd_checksum_guess_kind(checksum) == kind)
115
0
      return checksum;
116
0
  }
117
0
  return NULL;
118
0
}
119
120
/**
121
 * fwupd_checksum_get_best:
122
 * @checksums: (element-type utf8): checksums
123
 *
124
 * Gets a the best possible checksum kind.
125
 *
126
 * Returns: a checksum from the array, or %NULL if nothing was suitable
127
 *
128
 * Since: 0.9.4
129
 **/
130
const gchar *
131
fwupd_checksum_get_best(GPtrArray *checksums)
132
0
{
133
0
  GChecksumType checksum_types[] = {
134
0
      G_CHECKSUM_SHA512,
135
0
      G_CHECKSUM_SHA256,
136
0
      G_CHECKSUM_SHA384,
137
0
      G_CHECKSUM_SHA1,
138
0
  };
139
0
  g_return_val_if_fail(checksums != NULL, NULL);
140
0
  for (guint i = 0; i < G_N_ELEMENTS(checksum_types); i++) {
141
0
    for (guint j = 0; j < checksums->len; j++) {
142
0
      const gchar *checksum = g_ptr_array_index(checksums, j);
143
0
      if (fwupd_checksum_guess_kind(checksum) == checksum_types[i])
144
0
        return checksum;
145
0
    }
146
0
  }
147
0
  return NULL;
148
0
}
149
150
#define FWUPD_GUID_NAMESPACE_DEFAULT   "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
151
#define FWUPD_GUID_NAMESPACE_MICROSOFT "70ffd812-4c7f-4c7d-0000-000000000000"
152
153
typedef struct __attribute__((packed)) { /* nocheck:blocked */
154
  guint32 a;
155
  guint16 b;
156
  guint16 c;
157
  guint16 d;
158
  guint8 e[6];
159
} fwupd_guid_native_t;
160
161
/**
162
 * fwupd_guid_to_string:
163
 * @guid: a #fwupd_guid_t to read
164
 * @flags: GUID flags, e.g. %FWUPD_GUID_FLAG_MIXED_ENDIAN
165
 *
166
 * Returns a text GUID of mixed or BE endian for a packed buffer.
167
 *
168
 * Returns: a new GUID string
169
 *
170
 * Since: 1.2.5
171
 **/
172
gchar *
173
fwupd_guid_to_string(const fwupd_guid_t *guid, FwupdGuidFlags flags)
174
50.4k
{
175
50.4k
  fwupd_guid_native_t gnat;
176
177
50.4k
  g_return_val_if_fail(guid != NULL, NULL);
178
179
  /* copy to avoid issues with aligning */
180
50.4k
  memcpy(&gnat, guid, sizeof(gnat)); /* nocheck:blocked */
181
182
  /* mixed is bizaar, but specified as the DCE encoding */
183
50.4k
  if (flags & FWUPD_GUID_FLAG_MIXED_ENDIAN) {
184
48.2k
    return g_strdup_printf("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
185
48.2k
               (guint)GUINT32_FROM_LE(gnat.a), /* nocheck:blocked */
186
48.2k
               (guint)GUINT16_FROM_LE(gnat.b), /* nocheck:blocked */
187
48.2k
               (guint)GUINT16_FROM_LE(gnat.c), /* nocheck:blocked */
188
48.2k
               (guint)GUINT16_FROM_BE(gnat.d), /* nocheck:blocked */
189
48.2k
               gnat.e[0],
190
48.2k
               gnat.e[1],
191
48.2k
               gnat.e[2],
192
48.2k
               gnat.e[3],
193
48.2k
               gnat.e[4],
194
48.2k
               gnat.e[5]);
195
48.2k
  }
196
2.21k
  return g_strdup_printf("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
197
2.21k
             (guint)GUINT32_FROM_BE(gnat.a), /* nocheck:blocked */
198
2.21k
             (guint)GUINT16_FROM_BE(gnat.b), /* nocheck:blocked */
199
2.21k
             (guint)GUINT16_FROM_BE(gnat.c), /* nocheck:blocked */
200
2.21k
             (guint)GUINT16_FROM_BE(gnat.d), /* nocheck:blocked */
201
2.21k
             gnat.e[0],
202
2.21k
             gnat.e[1],
203
2.21k
             gnat.e[2],
204
2.21k
             gnat.e[3],
205
2.21k
             gnat.e[4],
206
2.21k
             gnat.e[5]);
207
50.4k
}
208
209
/**
210
 * fwupd_guid_from_string:
211
 * @guidstr: (not nullable): a GUID, e.g. `00112233-4455-6677-8899-aabbccddeeff`
212
 * @guid: (nullable): a #fwupd_guid_t, or NULL to just check the GUID
213
 * @flags: GUID flags, e.g. %FWUPD_GUID_FLAG_MIXED_ENDIAN
214
 * @error: (nullable): optional return location for an error
215
 *
216
 * Converts a string GUID into its binary encoding. All string GUIDs are
217
 * formatted as big endian but on-disk can be encoded in different ways.
218
 *
219
 * Returns: %TRUE for success
220
 *
221
 * Since: 1.2.5
222
 **/
223
gboolean
224
fwupd_guid_from_string(const gchar *guidstr,
225
           fwupd_guid_t *guid,
226
           FwupdGuidFlags flags,
227
           GError **error)
228
18.2k
{
229
18.2k
  fwupd_guid_native_t gu = {0x0};
230
18.2k
  gboolean mixed_endian = flags & FWUPD_GUID_FLAG_MIXED_ENDIAN;
231
18.2k
  guint64 tmp;
232
18.2k
  g_auto(GStrv) split = NULL;
233
234
18.2k
  g_return_val_if_fail(guidstr != NULL, FALSE);
235
18.2k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
236
237
  /* split into sections */
238
18.2k
  if (strlen(guidstr) != 36) {
239
5.23k
    g_set_error_literal(error,
240
5.23k
            FWUPD_ERROR,
241
5.23k
            FWUPD_ERROR_INVALID_DATA,
242
5.23k
            "GUID is not valid format");
243
5.23k
    return FALSE;
244
5.23k
  }
245
12.9k
  split = g_strsplit(guidstr, "-", 5);
246
12.9k
  if (g_strv_length(split) != 5) {
247
225
    g_set_error_literal(error,
248
225
            FWUPD_ERROR,
249
225
            FWUPD_ERROR_INVALID_DATA,
250
225
            "GUID is not valid format, no dashes");
251
225
    return FALSE;
252
225
  }
253
12.7k
  if (strlen(split[0]) != 8 || strlen(split[1]) != 4 || strlen(split[2]) != 4 ||
254
12.3k
      strlen(split[3]) != 4 || strlen(split[4]) != 12) {
255
661
    g_set_error_literal(error,
256
661
            FWUPD_ERROR,
257
661
            FWUPD_ERROR_INVALID_DATA,
258
661
            "GUID is not valid format, not GUID");
259
661
    return FALSE;
260
661
  }
261
262
  /* parse */
263
12.1k
  if (!g_ascii_string_to_unsigned(split[0], 16, 0, 0xffffffff, &tmp, error))
264
82
    return FALSE;
265
12.0k
  gu.a = mixed_endian ? GUINT32_TO_LE(tmp) : GUINT32_TO_BE(tmp); /* nocheck:blocked */
266
12.0k
  if (!g_ascii_string_to_unsigned(split[1], 16, 0, 0xffff, &tmp, error))
267
74
    return FALSE;
268
11.9k
  gu.b = mixed_endian ? GUINT16_TO_LE(tmp) : GUINT16_TO_BE(tmp); /* nocheck:blocked */
269
11.9k
  if (!g_ascii_string_to_unsigned(split[2], 16, 0, 0xffff, &tmp, error))
270
104
    return FALSE;
271
11.8k
  gu.c = mixed_endian ? GUINT16_TO_LE(tmp) : GUINT16_TO_BE(tmp); /* nocheck:blocked */
272
11.8k
  if (!g_ascii_string_to_unsigned(split[3], 16, 0, 0xffff, &tmp, error))
273
27
    return FALSE;
274
11.8k
  gu.d = GUINT16_TO_BE(tmp); /* nocheck:blocked */
275
81.1k
  for (guint i = 0; i < 6; i++) {
276
69.7k
    gchar buffer[3] = {0x0};
277
69.7k
    memcpy(buffer, split[4] + (i * 2), 2); /* nocheck:blocked */
278
69.7k
    if (!g_ascii_string_to_unsigned(buffer, 16, 0, 0xff, &tmp, error))
279
405
      return FALSE;
280
69.3k
    gu.e[i] = tmp;
281
69.3k
  }
282
11.4k
  if (guid != NULL)
283
11.4k
    memcpy(guid, &gu, sizeof(gu)); /* nocheck:blocked */
284
285
  /* success */
286
11.4k
  return TRUE;
287
11.8k
}
288
289
/**
290
 * fwupd_guid_hash_data:
291
 * @data: data to hash
292
 * @datasz: length of @data
293
 * @flags: GUID flags, e.g. %FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT
294
 *
295
 * Returns a GUID for some data. This uses a hash and so even small
296
 * differences in the @data will produce radically different return values.
297
 *
298
 * The implementation is taken from RFC4122, Section 4.1.3; specifically
299
 * using a type-5 SHA-1 hash.
300
 *
301
 * Returns: a new GUID, or %NULL for internal error
302
 *
303
 * Since: 1.2.5
304
 **/
305
gchar *
306
fwupd_guid_hash_data(const guint8 *data, gsize datasz, FwupdGuidFlags flags)
307
0
{
308
0
  gsize digestlen = 20;
309
0
  guint8 hash[20] = {0};
310
0
  fwupd_guid_t uu_new;
311
0
  g_autoptr(GChecksum) csum = NULL;
312
0
  const fwupd_guid_t uu_default = {0x6b,
313
0
           0xa7,
314
0
           0xb8,
315
0
           0x10,
316
0
           0x9d,
317
0
           0xad,
318
0
           0x11,
319
0
           0xd1,
320
0
           0x80,
321
0
           0xb4,
322
0
           0x00,
323
0
           0xc0,
324
0
           0x4f,
325
0
           0xd4,
326
0
           0x30,
327
0
           0xc8};
328
0
  const fwupd_guid_t uu_microso = {0x70, 0xff, 0xd8, 0x12, 0x4c, 0x7f, 0x4c, 0x7d};
329
0
  const fwupd_guid_t *uu_namespace = &uu_default;
330
331
0
  g_return_val_if_fail(data != NULL, NULL);
332
0
  g_return_val_if_fail(datasz != 0, NULL);
333
334
  /* old MS GUID */
335
0
  if (flags & FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT)
336
0
    uu_namespace = &uu_microso;
337
338
  /* hash the namespace and then the string */
339
0
  csum = g_checksum_new(G_CHECKSUM_SHA1);
340
0
  g_checksum_update(csum, (guchar *)uu_namespace, sizeof(*uu_namespace));
341
0
  g_checksum_update(csum, (guchar *)data, (gssize)datasz);
342
0
  g_checksum_get_digest(csum, hash, &digestlen);
343
344
  /* copy most parts of the hash 1:1 */
345
0
  memcpy(uu_new, hash, sizeof(uu_new)); /* nocheck:blocked */
346
347
  /* set specific bits according to Section 4.1.3 */
348
0
  uu_new[6] = (guint8)((uu_new[6] & 0x0f) | (5 << 4));
349
0
  uu_new[8] = (guint8)((uu_new[8] & 0x3f) | 0x80);
350
0
  return fwupd_guid_to_string((const fwupd_guid_t *)&uu_new, flags);
351
0
}
352
353
/**
354
 * fwupd_device_id_is_valid:
355
 * @device_id: string to check, e.g. `d3fae86d95e5d56626129d00e332c4b8dac95442`
356
 *
357
 * Checks the string is a valid non-partial device ID. It is important to note
358
 * that the wildcard ID of `*` is not considered a valid ID in this function and
359
 * the client must check for this manually if this should be allowed.
360
 *
361
 * Returns: %TRUE if @guid was a fwupd device ID, %FALSE otherwise
362
 *
363
 * Since: 1.4.1
364
 **/
365
gboolean
366
fwupd_device_id_is_valid(const gchar *device_id)
367
0
{
368
0
  if (device_id == NULL)
369
0
    return FALSE;
370
0
  if (strlen(device_id) != 40)
371
0
    return FALSE;
372
0
  for (guint i = 0; device_id[i] != '\0'; i++) {
373
0
    gchar tmp = device_id[i];
374
    /* isalnum isn't case specific */
375
0
    if ((tmp < 'a' || tmp > 'f') && (tmp < '0' || tmp > '9'))
376
0
      return FALSE;
377
0
  }
378
0
  return TRUE;
379
0
}
380
381
/**
382
 * fwupd_guid_is_valid:
383
 * @guid: string to check, e.g. `00112233-4455-6677-8899-aabbccddeeff`
384
 *
385
 * Checks the string is a valid GUID.
386
 *
387
 * Returns: %TRUE if @guid was a valid GUID, %FALSE otherwise
388
 *
389
 * Since: 1.2.5
390
 **/
391
gboolean
392
fwupd_guid_is_valid(const gchar *guid)
393
0
{
394
0
  const gchar zeroguid[] = {"00000000-0000-0000-0000-000000000000"};
395
396
  /* sanity check */
397
0
  if (guid == NULL)
398
0
    return FALSE;
399
400
  /* check for dashes and hexdigits in the right place */
401
0
  for (guint i = 0; i < sizeof(zeroguid) - 1; i++) {
402
0
    if (guid[i] == '\0')
403
0
      return FALSE;
404
0
    if (zeroguid[i] == '-') {
405
0
      if (guid[i] != '-')
406
0
        return FALSE;
407
0
      continue;
408
0
    }
409
0
    if (!g_ascii_isxdigit(guid[i]))
410
0
      return FALSE;
411
0
  }
412
413
  /* longer than required */
414
0
  if (guid[sizeof(zeroguid) - 1] != '\0')
415
0
    return FALSE;
416
417
  /* not valid */
418
0
  return g_strcmp0(guid, zeroguid) != 0;
419
0
}
420
421
/**
422
 * fwupd_guid_hash_string:
423
 * @str: (nullable): a source string to use as a key
424
 *
425
 * Returns a GUID for a given string. This uses a hash and so even small
426
 * differences in the @str will produce radically different return values.
427
 *
428
 * The default implementation is taken from RFC4122, Section 4.1.3; specifically
429
 * using a type-5 SHA-1 hash with a DNS namespace.
430
 * The same result can be obtained with this simple python program:
431
 *
432
 *    #!/usr/bin/python
433
 *    import uuid
434
 *    print uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
435
 *
436
 * Returns: a new GUID, or %NULL if the string was invalid
437
 *
438
 * Since: 1.2.5
439
 **/
440
gchar *
441
fwupd_guid_hash_string(const gchar *str)
442
0
{
443
0
  if (str == NULL || str[0] == '\0')
444
0
    return NULL;
445
0
  return fwupd_guid_hash_data((const guint8 *)str, strlen(str), FWUPD_GUID_FLAG_NONE);
446
0
}
447
448
/**
449
 * fwupd_hash_kv_to_variant: (skip):
450
 **/
451
GVariant *
452
fwupd_hash_kv_to_variant(GHashTable *hash)
453
0
{
454
0
  GVariantBuilder builder;
455
0
  g_autoptr(GList) keys = g_hash_table_get_keys(hash);
456
0
  g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
457
0
  for (GList *l = keys; l != NULL; l = l->next) {
458
0
    const gchar *key = l->data;
459
0
    const gchar *value = g_hash_table_lookup(hash, key);
460
0
    g_variant_builder_add(&builder, "{ss}", key, value);
461
0
  }
462
0
  return g_variant_builder_end(&builder);
463
0
}
464
465
/**
466
 * fwupd_variant_to_hash_kv: (skip):
467
 **/
468
GHashTable *
469
fwupd_variant_to_hash_kv(GVariant *dict)
470
0
{
471
0
  GHashTable *hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
472
0
  GVariantIter iter;
473
0
  const gchar *key;
474
0
  const gchar *value;
475
0
  g_variant_iter_init(&iter, dict);
476
0
  while (g_variant_iter_loop(&iter, "{&s&s}", &key, &value))
477
0
    g_hash_table_insert(hash, g_strdup(key), g_strdup(value));
478
0
  return hash;
479
0
}
480
481
#ifdef HAVE_GIO_UNIX
482
/**
483
 * fwupd_unix_input_stream_from_bytes: (skip):
484
 **/
485
GUnixInputStream *
486
fwupd_unix_input_stream_from_bytes(GBytes *bytes, GError **error)
487
{
488
  gint fd;
489
  gssize rc;
490
#ifndef HAVE_MEMFD_CREATE
491
  gchar tmp_file[] = "/tmp/fwupd.XXXXXX";
492
#endif
493
494
#ifdef HAVE_MEMFD_CREATE
495
  fd = memfd_create("fwupd", MFD_CLOEXEC);
496
#else
497
  /* emulate in-memory file by an unlinked temporary file */
498
  fd = g_mkstemp(tmp_file);
499
  if (fd != -1) {
500
    rc = g_unlink(tmp_file);
501
    if (rc != 0) {
502
      if (!g_close(fd, error)) {
503
        g_prefix_error_literal(error, "failed to close temporary file: ");
504
        return NULL;
505
      }
506
      g_set_error_literal(error,
507
              FWUPD_ERROR,
508
              FWUPD_ERROR_INVALID_FILE,
509
              "failed to unlink temporary file");
510
      return NULL;
511
    }
512
  }
513
#endif
514
515
  if (fd < 0) {
516
    g_set_error_literal(error,
517
            FWUPD_ERROR,
518
            FWUPD_ERROR_INVALID_FILE,
519
            "failed to create memfd");
520
    return NULL;
521
  }
522
  rc = write(fd, g_bytes_get_data(bytes, NULL), g_bytes_get_size(bytes));
523
  if (rc < 0) {
524
    g_set_error(error,
525
          FWUPD_ERROR,
526
          FWUPD_ERROR_INVALID_FILE,
527
          "failed to write %" G_GSSIZE_FORMAT,
528
          rc);
529
    return NULL;
530
  }
531
  if (lseek(fd, 0, SEEK_SET) < 0) {
532
    g_set_error(error,
533
          FWUPD_ERROR,
534
          FWUPD_ERROR_INVALID_FILE,
535
          "failed to seek: %s",
536
          fwupd_strerror(errno));
537
    return NULL;
538
  }
539
  return G_UNIX_INPUT_STREAM(g_unix_input_stream_new(fd, TRUE));
540
}
541
542
/**
543
 * fwupd_unix_input_stream_from_fn: (skip):
544
 **/
545
GUnixInputStream *
546
fwupd_unix_input_stream_from_fn(const gchar *fn, GError **error)
547
{
548
  gint fd = open(fn, O_RDONLY);
549
  if (fd < 0) {
550
    g_set_error(error,
551
          FWUPD_ERROR,
552
          FWUPD_ERROR_INVALID_FILE,
553
          "failed to open %s: %s",
554
          fn,
555
          fwupd_strerror(errno));
556
    return NULL;
557
  }
558
  return G_UNIX_INPUT_STREAM(g_unix_input_stream_new(fd, TRUE));
559
}
560
561
/**
562
 * fwupd_unix_output_stream_from_fn: (skip):
563
 **/
564
GUnixOutputStream *
565
fwupd_unix_output_stream_from_fn(const gchar *fn, GError **error)
566
{
567
  gint fd = g_open(fn, O_RDWR | O_CREAT, S_IRWXU);
568
  if (fd < 0) {
569
    g_set_error(error,
570
          FWUPD_ERROR,
571
          FWUPD_ERROR_INVALID_FILE,
572
          "failed to open %s: %s",
573
          fn,
574
          fwupd_strerror(errno));
575
    return NULL;
576
  }
577
  return G_UNIX_OUTPUT_STREAM(g_unix_output_stream_new(fd, TRUE));
578
}
579
#endif
580
581
/**
582
 * fwupd_variant_get_uint32: (skip):
583
 * @value: a #GVariant
584
 *
585
 * Gets an unsigned integer from a variant, handling both 'u' and 'i' types.
586
 **/
587
guint32
588
fwupd_variant_get_uint32(GVariant *value)
589
0
{
590
0
  g_return_val_if_fail(value != NULL, 0);
591
0
  if (g_variant_is_of_type(value, G_VARIANT_TYPE_INT32))
592
0
    return (guint32)g_variant_get_int32(value);
593
0
  return g_variant_get_uint32(value);
594
0
}
595
596
/**
597
 * fwupd_variant_get_uint64: (skip):
598
 * @value: a #GVariant
599
 *
600
 * Gets an unsigned integer from a variant, handling both 't' and 'x' types.
601
 **/
602
guint64
603
fwupd_variant_get_uint64(GVariant *value)
604
0
{
605
0
  g_return_val_if_fail(value != NULL, 0);
606
0
  if (g_variant_is_of_type(value, G_VARIANT_TYPE_INT64))
607
0
    return (guint64)g_variant_get_int64(value);
608
0
  return g_variant_get_uint64(value);
609
0
}