Coverage Report

Created: 2025-11-09 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-fdt-image.c
Line
Count
Source
1
/*
2
 * Copyright 2022 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
0
#define G_LOG_DOMAIN "FuFirmware"
8
9
#include "config.h"
10
11
#include "fu-byte-array.h"
12
#include "fu-fdt-image.h"
13
#include "fu-mem.h"
14
#include "fu-string.h"
15
16
/**
17
 * FuFdtImage:
18
 *
19
 * A Flattened DeviceTree firmware image.
20
 *
21
 * See also: [class@FuFdtFirmware]
22
 */
23
24
typedef struct {
25
  GHashTable *hash_attrs;
26
  GHashTable *hash_attrs_format;
27
} FuFdtImagePrivate;
28
29
252k
G_DEFINE_TYPE_WITH_PRIVATE(FuFdtImage, fu_fdt_image, FU_TYPE_FIRMWARE)
30
252k
#define GET_PRIVATE(o) (fu_fdt_image_get_instance_private(o))
31
32
0
#define FU_FDT_IMAGE_FORMAT_STR     "str"
33
0
#define FU_FDT_IMAGE_FORMAT_STRLIST "strlist"
34
0
#define FU_FDT_IMAGE_FORMAT_UINT32  "uint32"
35
0
#define FU_FDT_IMAGE_FORMAT_UINT64  "uint64"
36
0
#define FU_FDT_IMAGE_FORMAT_DATA    "data"
37
38
static const gchar *
39
fu_fdt_image_guess_format_from_key(const gchar *key)
40
0
{
41
0
  struct {
42
0
    const gchar *key;
43
0
    const gchar *format;
44
0
  } key_format_map[] = {{"#address-cells", FU_FDT_IMAGE_FORMAT_UINT32},
45
0
            {"algo", FU_FDT_IMAGE_FORMAT_STR},
46
0
            {"arch", FU_FDT_IMAGE_FORMAT_STR},
47
0
            {"compatible", FU_FDT_IMAGE_FORMAT_STRLIST},
48
0
            {"compression", FU_FDT_IMAGE_FORMAT_STR},
49
0
            {"creator", FU_FDT_IMAGE_FORMAT_STR},
50
0
            {"data-offset", FU_FDT_IMAGE_FORMAT_UINT32},
51
0
            {"data-size", FU_FDT_IMAGE_FORMAT_UINT32},
52
0
            {"default", FU_FDT_IMAGE_FORMAT_STR},
53
0
            {"description", FU_FDT_IMAGE_FORMAT_STR},
54
0
            {"entry", FU_FDT_IMAGE_FORMAT_STR},
55
0
            {"firmware", FU_FDT_IMAGE_FORMAT_STR},
56
0
            {"load", FU_FDT_IMAGE_FORMAT_UINT32},
57
0
            {"os", FU_FDT_IMAGE_FORMAT_STR},
58
0
            {"timestamp", FU_FDT_IMAGE_FORMAT_UINT32},
59
0
            {"type", FU_FDT_IMAGE_FORMAT_STR},
60
0
            {"version", FU_FDT_IMAGE_FORMAT_STR},
61
0
            {NULL, NULL}};
62
0
  for (guint i = 0; key_format_map[i].key != NULL; i++) {
63
0
    if (g_strcmp0(key, key_format_map[i].key) == 0)
64
0
      return key_format_map[i].format;
65
0
  }
66
0
  return NULL;
67
0
}
68
69
static gchar **
70
fu_fdt_image_strlist_from_blob(GBytes *blob)
71
0
{
72
0
  gchar **val;
73
0
  gsize bufsz = 0;
74
0
  const guint8 *buf = g_bytes_get_data(blob, &bufsz);
75
0
  g_autoptr(GPtrArray) strs = g_ptr_array_new();
76
77
  /* delimit by NUL */
78
0
  for (gsize i = 0; i < bufsz; i++) {
79
0
    const gchar *tmp = (const gchar *)buf + i;
80
0
    g_ptr_array_add(strs, (gpointer)tmp);
81
0
    i += strlen(tmp);
82
0
  }
83
84
  /* copy to GStrv */
85
0
  val = g_new0(gchar *, strs->len + 1);
86
0
  for (guint i = 0; i < strs->len; i++)
87
0
    val[i] = g_strdup(g_ptr_array_index(strs, i));
88
0
  return val;
89
0
}
90
91
static void
92
fu_fdt_image_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn)
93
0
{
94
0
  FuFdtImage *self = FU_FDT_IMAGE(firmware);
95
0
  FuFdtImagePrivate *priv = GET_PRIVATE(self);
96
0
  GHashTableIter iter;
97
0
  gpointer key, value;
98
99
0
  g_hash_table_iter_init(&iter, priv->hash_attrs);
100
0
  while (g_hash_table_iter_next(&iter, &key, &value)) {
101
0
    gsize bufsz = 0;
102
0
    const guint8 *buf = g_bytes_get_data(value, &bufsz);
103
0
    const gchar *format = g_hash_table_lookup(priv->hash_attrs_format, key);
104
0
    g_autofree gchar *str = NULL;
105
0
    g_autoptr(XbBuilderNode) bc = NULL;
106
107
    /* guess format based on key name to improve debugging experience */
108
0
    if (format == NULL)
109
0
      format = fu_fdt_image_guess_format_from_key(key);
110
0
    if (g_strcmp0(format, FU_FDT_IMAGE_FORMAT_UINT32) == 0 && bufsz == 4) {
111
0
      guint64 tmp = fu_memread_uint32(buf, G_BIG_ENDIAN);
112
0
      str = g_strdup_printf("0x%x", (guint)tmp);
113
0
    } else if (g_strcmp0(format, FU_FDT_IMAGE_FORMAT_UINT64) == 0 && bufsz == 8) {
114
0
      guint64 tmp = fu_memread_uint64(buf, G_BIG_ENDIAN);
115
0
      str = g_strdup_printf("0x%x", (guint)tmp);
116
0
    } else if (g_strcmp0(format, FU_FDT_IMAGE_FORMAT_STR) == 0 && bufsz > 0) {
117
0
      str = g_strndup((const gchar *)buf, bufsz);
118
0
    } else if (g_strcmp0(format, FU_FDT_IMAGE_FORMAT_STRLIST) == 0 && bufsz > 0) {
119
0
      g_auto(GStrv) tmp = fu_fdt_image_strlist_from_blob(value);
120
0
      str = g_strjoinv(":", tmp);
121
0
    } else {
122
0
      str = g_base64_encode(buf, bufsz);
123
0
    }
124
0
    bc = xb_builder_node_insert(bn, "metadata", "key", key, NULL);
125
0
    if (str != NULL)
126
0
      xb_builder_node_set_text(bc, str, -1);
127
0
    if (format != NULL)
128
0
      xb_builder_node_set_attr(bc, "format", format);
129
0
  }
130
0
}
131
132
/**
133
 * fu_fdt_image_get_attrs:
134
 * @self: a #FuFdtImage
135
 *
136
 * Gets all the attributes stored on the image.
137
 *
138
 * Returns: (transfer container) (element-type utf8): keys
139
 *
140
 * Since: 1.8.2
141
 **/
142
GPtrArray *
143
fu_fdt_image_get_attrs(FuFdtImage *self)
144
8.07k
{
145
8.07k
  FuFdtImagePrivate *priv = GET_PRIVATE(self);
146
8.07k
  GPtrArray *array = g_ptr_array_new_with_free_func(g_free);
147
8.07k
  g_autoptr(GList) keys = NULL;
148
149
8.07k
  g_return_val_if_fail(FU_IS_FDT_IMAGE(self), NULL);
150
151
8.07k
  keys = g_hash_table_get_keys(priv->hash_attrs);
152
21.4k
  for (GList *l = keys; l != NULL; l = l->next) {
153
13.4k
    const gchar *key = l->data;
154
13.4k
    g_ptr_array_add(array, g_strdup(key));
155
13.4k
  }
156
8.07k
  return array;
157
8.07k
}
158
159
/**
160
 * fu_fdt_image_get_attr:
161
 * @self: a #FuFdtImage
162
 * @key: string, e.g. `creator`
163
 * @error: (nullable): optional return location for an error
164
 *
165
 * Gets a attribute from the image.
166
 *
167
 * Returns: (transfer full): blob
168
 *
169
 * Since: 1.8.2
170
 **/
171
GBytes *
172
fu_fdt_image_get_attr(FuFdtImage *self, const gchar *key, GError **error)
173
15.7k
{
174
15.7k
  FuFdtImagePrivate *priv = GET_PRIVATE(self);
175
15.7k
  GBytes *blob;
176
177
15.7k
  g_return_val_if_fail(FU_IS_FDT_IMAGE(self), NULL);
178
15.7k
  g_return_val_if_fail(key != NULL, NULL);
179
15.7k
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
180
181
15.7k
  blob = g_hash_table_lookup(priv->hash_attrs, key);
182
15.7k
  if (blob == NULL) {
183
288
    g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no data for %s", key);
184
288
    return NULL;
185
288
  }
186
187
  /* success */
188
15.4k
  return g_bytes_ref(blob);
189
15.7k
}
190
191
/**
192
 * fu_fdt_image_get_attr_u32:
193
 * @self: a #FuFdtImage
194
 * @key: string, e.g. `creator`
195
 * @val: (out) (nullable): value
196
 * @error: (nullable): optional return location for an error
197
 *
198
 * Gets a uint32 attribute from the image.
199
 *
200
 * Returns: %TRUE if @val was set.
201
 *
202
 * Since: 1.8.2
203
 **/
204
gboolean
205
fu_fdt_image_get_attr_u32(FuFdtImage *self, const gchar *key, guint32 *val, GError **error)
206
1.25k
{
207
1.25k
  g_autoptr(GBytes) blob = NULL;
208
209
1.25k
  g_return_val_if_fail(FU_IS_FDT_IMAGE(self), FALSE);
210
1.25k
  g_return_val_if_fail(key != NULL, FALSE);
211
1.25k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
212
213
1.25k
  blob = fu_fdt_image_get_attr(self, key, error);
214
1.25k
  if (blob == NULL)
215
249
    return FALSE;
216
1.00k
  if (g_bytes_get_size(blob) != sizeof(guint32)) {
217
9
    g_set_error(error,
218
9
          FWUPD_ERROR,
219
9
          FWUPD_ERROR_INVALID_DATA,
220
9
          "invalid data size for %s, got 0x%x, expected 0x%x",
221
9
          key,
222
9
          (guint)g_bytes_get_size(blob),
223
9
          (guint)sizeof(guint32));
224
9
    return FALSE;
225
9
  }
226
995
  if (val != NULL)
227
115
    *val = fu_memread_uint32(g_bytes_get_data(blob, NULL), G_BIG_ENDIAN);
228
995
  return TRUE;
229
1.00k
}
230
231
/**
232
 * fu_fdt_image_get_attr_u64:
233
 * @self: a #FuFdtImage
234
 * @key: string, e.g. `creator`
235
 * @val: (out) (nullable): value
236
 * @error: (nullable): optional return location for an error
237
 *
238
 * Gets a uint64 attribute from the image.
239
 *
240
 * Returns: %TRUE if @val was set.
241
 *
242
 * Since: 1.8.2
243
 **/
244
gboolean
245
fu_fdt_image_get_attr_u64(FuFdtImage *self, const gchar *key, guint64 *val, GError **error)
246
0
{
247
0
  g_autoptr(GBytes) blob = NULL;
248
249
0
  g_return_val_if_fail(FU_IS_FDT_IMAGE(self), FALSE);
250
0
  g_return_val_if_fail(key != NULL, FALSE);
251
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
252
253
0
  blob = fu_fdt_image_get_attr(self, key, error);
254
0
  if (blob == NULL)
255
0
    return FALSE;
256
0
  if (g_bytes_get_size(blob) != sizeof(guint64)) {
257
0
    g_set_error(error,
258
0
          FWUPD_ERROR,
259
0
          FWUPD_ERROR_INVALID_DATA,
260
0
          "invalid data size for %s, got 0x%x, expected 0x%x",
261
0
          key,
262
0
          (guint)g_bytes_get_size(blob),
263
0
          (guint)sizeof(guint64));
264
0
    return FALSE;
265
0
  }
266
0
  if (val != NULL)
267
0
    *val = fu_memread_uint64(g_bytes_get_data(blob, NULL), G_BIG_ENDIAN);
268
0
  return TRUE;
269
0
}
270
271
/**
272
 * fu_fdt_image_get_attr_strlist:
273
 * @self: a #FuFdtImage
274
 * @key: string, e.g. `compatible`
275
 * @val: (out) (nullable) (transfer full): values
276
 * @error: (nullable): optional return location for an error
277
 *
278
 * Gets a stringlist attribute from the image. @val is always `NUL` terminated.
279
 *
280
 * Returns: %TRUE if @val was set.
281
 *
282
 * Since: 1.8.2
283
 **/
284
gboolean
285
fu_fdt_image_get_attr_strlist(FuFdtImage *self, const gchar *key, gchar ***val, GError **error)
286
36
{
287
36
  g_autoptr(GBytes) blob = NULL;
288
36
  const guint8 *buf;
289
36
  gsize bufsz = 0;
290
291
36
  g_return_val_if_fail(FU_IS_FDT_IMAGE(self), FALSE);
292
36
  g_return_val_if_fail(key != NULL, FALSE);
293
36
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
294
295
36
  blob = fu_fdt_image_get_attr(self, key, error);
296
36
  if (blob == NULL)
297
5
    return FALSE;
298
31
  if (g_bytes_get_size(blob) == 0) {
299
3
    g_set_error(error,
300
3
          FWUPD_ERROR,
301
3
          FWUPD_ERROR_INVALID_DATA,
302
3
          "invalid data size for %s, got 0x%x",
303
3
          key,
304
3
          (guint)g_bytes_get_size(blob));
305
3
    return FALSE;
306
3
  }
307
308
  /* sanity check */
309
28
  buf = g_bytes_get_data(blob, &bufsz);
310
766
  for (gsize i = 0; i < bufsz; i++) {
311
754
    if (buf[i] != 0x0 && !g_ascii_isprint((gchar)buf[i])) {
312
16
      g_set_error(error,
313
16
            FWUPD_ERROR,
314
16
            FWUPD_ERROR_INVALID_DATA,
315
16
            "nonprintable character 0x%02x at offset 0x%x in %s",
316
16
            buf[i],
317
16
            (guint)i,
318
16
            key);
319
16
      return FALSE;
320
16
    }
321
754
  }
322
323
  /* success */
324
12
  if (val != NULL)
325
0
    *val = fu_fdt_image_strlist_from_blob(blob);
326
12
  return TRUE;
327
28
}
328
329
/**
330
 * fu_fdt_image_get_attr_str:
331
 * @self: a #FuFdtImage
332
 * @key: string, e.g. `creator`
333
 * @val: (out) (nullable) (transfer full): value
334
 * @error: (nullable): optional return location for an error
335
 *
336
 * Gets a string attribute from the image. @val is always `NUL` terminated.
337
 *
338
 * Returns: %TRUE if @val was set.
339
 *
340
 * Since: 1.8.2
341
 **/
342
gboolean
343
fu_fdt_image_get_attr_str(FuFdtImage *self, const gchar *key, gchar **val, GError **error)
344
786
{
345
786
  g_autoptr(GBytes) blob = NULL;
346
786
  const guint8 *buf;
347
786
  gsize bufsz = 0;
348
349
786
  g_return_val_if_fail(FU_IS_FDT_IMAGE(self), FALSE);
350
786
  g_return_val_if_fail(key != NULL, FALSE);
351
786
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
352
353
786
  blob = fu_fdt_image_get_attr(self, key, error);
354
786
  if (blob == NULL)
355
25
    return FALSE;
356
761
  if (g_bytes_get_size(blob) == 0) {
357
3
    g_set_error(error,
358
3
          FWUPD_ERROR,
359
3
          FWUPD_ERROR_INVALID_DATA,
360
3
          "invalid data size for %s, got 0x%x",
361
3
          key,
362
3
          (guint)g_bytes_get_size(blob));
363
3
    return FALSE;
364
3
  }
365
366
  /* sanity check */
367
758
  buf = g_bytes_get_data(blob, &bufsz);
368
6.73k
  for (gsize i = 0; i < bufsz; i++) {
369
5.99k
    if (buf[i] != 0x0 && !g_ascii_isprint((gchar)buf[i])) {
370
23
      g_set_error(error,
371
23
            FWUPD_ERROR,
372
23
            FWUPD_ERROR_INVALID_DATA,
373
23
            "nonprintable character 0x%02x at offset 0x%x in %s",
374
23
            buf[i],
375
23
            (guint)i,
376
23
            key);
377
23
      return FALSE;
378
23
    }
379
5.99k
  }
380
381
  /* success */
382
735
  if (val != NULL)
383
237
    *val = g_strndup(g_bytes_get_data(blob, NULL), g_bytes_get_size(blob));
384
735
  return TRUE;
385
758
}
386
387
/**
388
 * fu_fdt_image_set_attr:
389
 * @self: a #FuFdtImage
390
 * @key: string, e.g. `creator`
391
 * @blob: a #GBytes
392
 *
393
 * Sets a attribute for the image.
394
 *
395
 * Since: 1.8.2
396
 **/
397
void
398
fu_fdt_image_set_attr(FuFdtImage *self, const gchar *key, GBytes *blob)
399
31.7k
{
400
31.7k
  FuFdtImagePrivate *priv = GET_PRIVATE(self);
401
31.7k
  g_return_if_fail(FU_IS_FDT_IMAGE(self));
402
31.7k
  g_return_if_fail(key != NULL);
403
31.7k
  g_hash_table_insert(priv->hash_attrs, g_strdup(key), g_bytes_ref(blob));
404
31.7k
}
405
406
static void
407
fu_fdt_image_set_attr_format(FuFdtImage *self, const gchar *key, const gchar *format)
408
0
{
409
0
  FuFdtImagePrivate *priv = GET_PRIVATE(self);
410
0
  g_return_if_fail(FU_IS_FDT_IMAGE(self));
411
0
  g_return_if_fail(format != NULL);
412
0
  g_hash_table_insert(priv->hash_attrs_format, g_strdup(key), strdup(format));
413
0
}
414
415
/**
416
 * fu_fdt_image_set_attr_uint32:
417
 * @self: a #FuFdtImage
418
 * @key: string, e.g. `creator`
419
 * @value: value to store
420
 *
421
 * Sets a uint32 attribute for the image.
422
 *
423
 * Since: 1.8.2
424
 **/
425
void
426
fu_fdt_image_set_attr_uint32(FuFdtImage *self, const gchar *key, guint32 value)
427
0
{
428
0
  guint8 buf[4] = {0x0};
429
0
  g_autoptr(GBytes) blob = NULL;
430
431
0
  g_return_if_fail(FU_IS_FDT_IMAGE(self));
432
0
  g_return_if_fail(key != NULL);
433
434
0
  fu_memwrite_uint32(buf, value, G_BIG_ENDIAN);
435
0
  blob = g_bytes_new(buf, sizeof(buf));
436
0
  fu_fdt_image_set_attr(self, key, blob);
437
0
  fu_fdt_image_set_attr_format(self, key, FU_FDT_IMAGE_FORMAT_UINT32);
438
0
}
439
440
/**
441
 * fu_fdt_image_set_attr_uint64:
442
 * @self: a #FuFdtImage
443
 * @key: string, e.g. `creator`
444
 * @value: value to store
445
 *
446
 * Sets a uint64 attribute for the image.
447
 *
448
 * Since: 1.8.2
449
 **/
450
void
451
fu_fdt_image_set_attr_uint64(FuFdtImage *self, const gchar *key, guint64 value)
452
0
{
453
0
  guint8 buf[8] = {0x0};
454
0
  g_autoptr(GBytes) blob = NULL;
455
456
0
  g_return_if_fail(FU_IS_FDT_IMAGE(self));
457
0
  g_return_if_fail(key != NULL);
458
459
0
  fu_memwrite_uint64(buf, value, G_BIG_ENDIAN);
460
0
  blob = g_bytes_new(buf, sizeof(buf));
461
0
  fu_fdt_image_set_attr(self, key, blob);
462
0
  fu_fdt_image_set_attr_format(self, key, FU_FDT_IMAGE_FORMAT_UINT64);
463
0
}
464
465
/**
466
 * fu_fdt_image_set_attr_str:
467
 * @self: a #FuFdtImage
468
 * @key: string, e.g. `creator`
469
 * @value: value to store
470
 *
471
 * Sets a string attribute for the image.
472
 *
473
 * Since: 1.8.2
474
 **/
475
void
476
fu_fdt_image_set_attr_str(FuFdtImage *self, const gchar *key, const gchar *value)
477
0
{
478
0
  g_autoptr(GBytes) blob = NULL;
479
480
0
  g_return_if_fail(FU_IS_FDT_IMAGE(self));
481
0
  g_return_if_fail(key != NULL);
482
0
  g_return_if_fail(value != NULL);
483
484
0
  blob = g_bytes_new((const guint8 *)value, strlen(value) + 1);
485
0
  fu_fdt_image_set_attr(self, key, blob);
486
0
  fu_fdt_image_set_attr_format(self, key, FU_FDT_IMAGE_FORMAT_STR);
487
0
}
488
489
/**
490
 * fu_fdt_image_set_attr_strlist:
491
 * @self: a #FuFdtImage
492
 * @key: string, e.g. `compatible`
493
 * @value: values to store
494
 *
495
 * Sets a stringlist attribute for the image.
496
 *
497
 * Since: 1.8.2
498
 **/
499
void
500
fu_fdt_image_set_attr_strlist(FuFdtImage *self, const gchar *key, gchar **value)
501
0
{
502
0
  g_autoptr(GByteArray) buf = g_byte_array_new();
503
0
  g_autoptr(GBytes) blob = NULL;
504
505
0
  g_return_if_fail(FU_IS_FDT_IMAGE(self));
506
0
  g_return_if_fail(key != NULL);
507
0
  g_return_if_fail(value != NULL);
508
0
  g_return_if_fail(value[0] != NULL);
509
510
0
  for (guint i = 0; value[i] != NULL; i++) {
511
0
    g_byte_array_append(buf, (const guint8 *)value[i], strlen(value[i]));
512
0
    fu_byte_array_append_uint8(buf, 0x0);
513
0
  }
514
0
  blob = g_bytes_new(buf->data, buf->len);
515
0
  fu_fdt_image_set_attr(self, key, blob);
516
0
  fu_fdt_image_set_attr_format(self, key, FU_FDT_IMAGE_FORMAT_STRLIST);
517
0
}
518
519
static gboolean
520
fu_fdt_image_build_metadata_node(FuFdtImage *self, XbNode *n, GError **error)
521
0
{
522
0
  const gchar *key;
523
0
  const gchar *format;
524
0
  const gchar *value = xb_node_get_text(n);
525
526
0
  key = xb_node_get_attr(n, "key");
527
0
  if (key == NULL) {
528
0
    g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_DATA, "key invalid");
529
0
    return FALSE;
530
0
  }
531
0
  format = xb_node_get_attr(n, "format");
532
0
  if (format == NULL) {
533
0
    g_set_error(error,
534
0
          FWUPD_ERROR,
535
0
          FWUPD_ERROR_INVALID_DATA,
536
0
          "format unspecified for %s, expected uint64|uint32|str|strlist|data",
537
0
          key);
538
0
    return FALSE;
539
0
  }
540
0
  fu_fdt_image_set_attr_format(self, key, format);
541
542
  /* actually parse values */
543
0
  if (g_strcmp0(format, FU_FDT_IMAGE_FORMAT_UINT32) == 0) {
544
0
    guint64 tmp = 0;
545
0
    if (value != NULL) {
546
0
      if (!fu_strtoull(value,
547
0
           &tmp,
548
0
           0x0,
549
0
           G_MAXUINT32,
550
0
           FU_INTEGER_BASE_AUTO,
551
0
           error))
552
0
        return FALSE;
553
0
    }
554
0
    fu_fdt_image_set_attr_uint32(self, key, tmp);
555
0
    return TRUE;
556
0
  }
557
0
  if (g_strcmp0(format, FU_FDT_IMAGE_FORMAT_UINT64) == 0) {
558
0
    guint64 tmp = 0;
559
0
    if (value != NULL) {
560
0
      if (!fu_strtoull(value,
561
0
           &tmp,
562
0
           0x0,
563
0
           G_MAXUINT64,
564
0
           FU_INTEGER_BASE_AUTO,
565
0
           error))
566
0
        return FALSE;
567
0
    }
568
0
    fu_fdt_image_set_attr_uint64(self, key, tmp);
569
0
    return TRUE;
570
0
  }
571
0
  if (g_strcmp0(format, FU_FDT_IMAGE_FORMAT_STR) == 0) {
572
0
    if (value != NULL) {
573
0
      fu_fdt_image_set_attr_str(self, key, value);
574
0
    } else {
575
0
      g_autoptr(GBytes) blob = g_bytes_new(NULL, 0);
576
0
      fu_fdt_image_set_attr(self, key, blob);
577
0
    }
578
0
    return TRUE;
579
0
  }
580
0
  if (g_strcmp0(format, FU_FDT_IMAGE_FORMAT_STRLIST) == 0) {
581
0
    if (value != NULL) {
582
0
      g_auto(GStrv) split = g_strsplit(value, ":", -1);
583
0
      fu_fdt_image_set_attr_strlist(self, key, split);
584
0
    } else {
585
0
      g_autoptr(GBytes) blob = g_bytes_new(NULL, 0);
586
0
      fu_fdt_image_set_attr(self, key, blob);
587
0
    }
588
0
    return TRUE;
589
0
  }
590
0
  if (g_strcmp0(format, FU_FDT_IMAGE_FORMAT_DATA) == 0) {
591
0
    g_autoptr(GBytes) blob = NULL;
592
0
    if (value != NULL) {
593
0
      gsize bufsz = 0;
594
0
      g_autofree guchar *buf = g_base64_decode(value, &bufsz);
595
0
      blob = g_bytes_new(buf, bufsz);
596
0
    } else {
597
0
      blob = g_bytes_new(NULL, 0);
598
0
    }
599
0
    fu_fdt_image_set_attr(self, key, blob);
600
0
    return TRUE;
601
0
  }
602
603
  /* failed */
604
0
  g_set_error(error,
605
0
        FWUPD_ERROR,
606
0
        FWUPD_ERROR_INVALID_DATA,
607
0
        "format for %s invalid, expected uint64|uint32|str|strlist|data",
608
0
        key);
609
0
  return FALSE;
610
0
}
611
612
static gboolean
613
fu_fdt_image_build(FuFirmware *firmware, XbNode *n, GError **error)
614
0
{
615
0
  FuFdtImage *self = FU_FDT_IMAGE(firmware);
616
0
  g_autoptr(GPtrArray) metadata = NULL;
617
618
0
  metadata = xb_node_query(n, "metadata", 0, NULL);
619
0
  if (metadata != NULL) {
620
0
    for (guint i = 0; i < metadata->len; i++) {
621
0
      XbNode *c = g_ptr_array_index(metadata, i);
622
0
      if (!fu_fdt_image_build_metadata_node(self, c, error))
623
0
        return FALSE;
624
0
    }
625
0
  }
626
627
  /* success */
628
0
  return TRUE;
629
0
}
630
631
static void
632
fu_fdt_image_init(FuFdtImage *self)
633
77.6k
{
634
77.6k
  FuFdtImagePrivate *priv = GET_PRIVATE(self);
635
77.6k
  priv->hash_attrs =
636
77.6k
      g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_bytes_unref);
637
77.6k
  priv->hash_attrs_format = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
638
77.6k
  fu_firmware_set_images_max(FU_FIRMWARE(self), 10000);
639
77.6k
}
640
641
static void
642
fu_fdt_image_finalize(GObject *object)
643
77.6k
{
644
77.6k
  FuFdtImage *self = FU_FDT_IMAGE(object);
645
77.6k
  FuFdtImagePrivate *priv = GET_PRIVATE(self);
646
77.6k
  g_hash_table_unref(priv->hash_attrs);
647
77.6k
  g_hash_table_unref(priv->hash_attrs_format);
648
77.6k
  G_OBJECT_CLASS(fu_fdt_image_parent_class)->finalize(object);
649
77.6k
}
650
651
static void
652
fu_fdt_image_class_init(FuFdtImageClass *klass)
653
2
{
654
2
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
655
2
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
656
2
  object_class->finalize = fu_fdt_image_finalize;
657
2
  firmware_class->export = fu_fdt_image_export;
658
2
  firmware_class->build = fu_fdt_image_build;
659
2
}
660
661
/**
662
 * fu_fdt_image_new:
663
 *
664
 * Creates a new #FuFirmware of sub type FDT image
665
 *
666
 * Since: 1.8.2
667
 **/
668
FuFirmware *
669
fu_fdt_image_new(void)
670
77.6k
{
671
77.6k
  return FU_FIRMWARE(g_object_new(FU_TYPE_FDT_IMAGE, NULL));
672
77.6k
}