Coverage Report

Created: 2025-10-10 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupd/fwupd-codec.c
Line
Count
Source
1
/*
2
 * Copyright 2024 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-codec.h"
10
#include "fwupd-error.h"
11
12
/**
13
 * FwupdCodec:
14
 *
15
 * A codec that can serialize and deserialize objects to formats such as text, JSON or #GVariant.
16
 */
17
18
61
G_DEFINE_INTERFACE(FwupdCodec, fwupd_codec, G_TYPE_OBJECT)
19
61
20
61
static void
21
61
fwupd_codec_default_init(FwupdCodecInterface *iface)
22
61
{
23
27
}
24
25
static void
26
fwupd_codec_add_string_from_json_node(FwupdCodec *self,
27
              const gchar *member_name,
28
              JsonNode *json_node,
29
              guint idt,
30
              GString *str)
31
0
{
32
0
  JsonNodeType node_type = json_node_get_node_type(json_node);
33
0
  if (node_type == JSON_NODE_VALUE) {
34
0
    GType gtype = json_node_get_value_type(json_node);
35
0
    if (gtype == G_TYPE_STRING) {
36
0
      fwupd_codec_string_append(str,
37
0
              idt,
38
0
              member_name,
39
0
              json_node_get_string(json_node));
40
0
    } else if (gtype == G_TYPE_INT64) {
41
0
      fwupd_codec_string_append_hex(str,
42
0
                  idt,
43
0
                  member_name,
44
0
                  json_node_get_int(json_node));
45
0
    } else if (gtype == G_TYPE_BOOLEAN) {
46
0
      fwupd_codec_string_append_bool(str,
47
0
                   idt,
48
0
                   member_name,
49
0
                   json_node_get_boolean(json_node));
50
0
    } else {
51
0
      fwupd_codec_string_append(str, idt, member_name, "GType value unknown");
52
0
    }
53
0
  } else if (node_type == JSON_NODE_ARRAY) {
54
0
    JsonArray *json_array = json_node_get_array(json_node);
55
0
    g_autoptr(GList) json_nodes = json_array_get_elements(json_array);
56
0
    if (g_strcmp0(member_name, "") != 0)
57
0
      fwupd_codec_string_append(str, idt, member_name, "");
58
0
    for (GList *l = json_nodes; l != NULL; l = l->next)
59
0
      fwupd_codec_add_string_from_json_node(self, "", l->data, idt + 1, str);
60
0
  } else if (node_type == JSON_NODE_OBJECT) {
61
0
    JsonObjectIter iter;
62
0
    json_object_iter_init(&iter, json_node_get_object(json_node));
63
0
    if (g_strcmp0(member_name, "") != 0)
64
0
      fwupd_codec_string_append(str, idt, member_name, "");
65
0
    while (json_object_iter_next(&iter, &member_name, &json_node)) {
66
0
      fwupd_codec_add_string_from_json_node(self,
67
0
                    member_name,
68
0
                    json_node,
69
0
                    idt + 1,
70
0
                    str);
71
0
    }
72
0
  }
73
0
}
74
75
/**
76
 * fwupd_codec_add_string:
77
 * @self: a #FwupdCodec
78
 * @idt: the indent
79
 * @str: (not nullable): a string to append to
80
 *
81
 * Converts an object that implements #FwupdCodec to a debug string, appending it to @str.
82
 *
83
 * Since: 2.0.0
84
 */
85
void
86
fwupd_codec_add_string(FwupdCodec *self, guint idt, GString *str)
87
0
{
88
0
  FwupdCodecInterface *iface;
89
90
0
  g_return_if_fail(FWUPD_IS_CODEC(self));
91
0
  g_return_if_fail(str != NULL);
92
93
0
  fwupd_codec_string_append(str, idt, G_OBJECT_TYPE_NAME(self), "");
94
0
  iface = FWUPD_CODEC_GET_IFACE(self);
95
0
  if (iface->add_string != NULL) {
96
0
    iface->add_string(self, idt + 1, str);
97
0
    return;
98
0
  }
99
0
  if (iface->add_json != NULL) {
100
0
    g_autoptr(JsonBuilder) builder = json_builder_new();
101
0
    g_autoptr(JsonNode) root_node = NULL;
102
0
    json_builder_begin_object(builder);
103
0
    iface->add_json(self, builder, FWUPD_CODEC_FLAG_TRUSTED);
104
0
    json_builder_end_object(builder);
105
0
    root_node = json_builder_get_root(builder);
106
0
    fwupd_codec_add_string_from_json_node(self, "", root_node, idt + 1, str);
107
0
    return;
108
0
  }
109
0
  g_critical("FwupdCodec->add_string or iface->add_json not implemented");
110
0
}
111
112
/**
113
 * fwupd_codec_to_string:
114
 * @self: a #FwupdCodec
115
 *
116
 * Converts an object that implements #FwupdCodec to a debug string.
117
 *
118
 * Returns: (transfer full): a string
119
 *
120
 * Since: 2.0.0
121
 */
122
gchar *
123
fwupd_codec_to_string(FwupdCodec *self)
124
0
{
125
0
  FwupdCodecInterface *iface;
126
127
0
  g_return_val_if_fail(FWUPD_IS_CODEC(self), NULL);
128
129
0
  iface = FWUPD_CODEC_GET_IFACE(self);
130
0
  if (iface->to_string != NULL)
131
0
    return iface->to_string(self);
132
0
  if (iface->add_string != NULL || iface->add_json != NULL) {
133
0
    GString *str = g_string_new(NULL);
134
0
    fwupd_codec_add_string(self, 0, str);
135
0
    return g_string_free(str, FALSE);
136
0
  }
137
0
  g_critical("FwupdCodec->to_string and iface->add_string not implemented");
138
0
  return NULL;
139
0
}
140
141
/**
142
 * fwupd_codec_from_json:
143
 * @self: a #FwupdCodec
144
 * @json_node: (not nullable): a JSON node
145
 * @error: (nullable): optional return location for an error
146
 *
147
 * Converts an object that implements #FwupdCodec from a JSON object.
148
 *
149
 * Returns: %TRUE on success
150
 *
151
 * Since: 2.0.0
152
 */
153
gboolean
154
fwupd_codec_from_json(FwupdCodec *self, JsonNode *json_node, GError **error)
155
0
{
156
0
  FwupdCodecInterface *iface;
157
158
0
  g_return_val_if_fail(FWUPD_IS_CODEC(self), FALSE);
159
0
  g_return_val_if_fail(json_node != NULL, FALSE);
160
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
161
162
0
  iface = FWUPD_CODEC_GET_IFACE(self);
163
0
  if (iface->from_json == NULL) {
164
0
    g_set_error_literal(error,
165
0
            FWUPD_ERROR,
166
0
            FWUPD_ERROR_NOT_SUPPORTED,
167
0
            "FwupdCodec->from_json not implemented");
168
0
    return FALSE;
169
0
  }
170
0
  return (*iface->from_json)(self, json_node, error);
171
0
}
172
173
/**
174
 * fwupd_codec_from_json_string:
175
 * @self: a #FwupdCodec
176
 * @json: (not nullable): JSON text
177
 * @error: (nullable): optional return location for an error
178
 *
179
 * Converts an object that implements #FwupdCodec from a JSON string.
180
 *
181
 * Returns: %TRUE on success
182
 *
183
 * Since: 2.0.0
184
 */
185
gboolean
186
fwupd_codec_from_json_string(FwupdCodec *self, const gchar *json, GError **error)
187
0
{
188
0
  g_autoptr(JsonParser) parser = json_parser_new();
189
190
0
  g_return_val_if_fail(FWUPD_IS_CODEC(self), FALSE);
191
0
  g_return_val_if_fail(json != NULL, FALSE);
192
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
193
194
0
  if (!json_parser_load_from_data(parser, json, -1, error)) {
195
0
    g_prefix_error(error, "failed to load '%s': ", json);
196
0
    return FALSE;
197
0
  }
198
0
  return fwupd_codec_from_json(self, json_parser_get_root(parser), error);
199
0
}
200
201
/**
202
 * fwupd_codec_to_json:
203
 * @self: a #FwupdCodec
204
 * @builder: (not nullable): a JSON builder
205
 * @flags: a #FwupdCodecFlags, e.g. %FWUPD_CODEC_FLAG_TRUSTED
206
 *
207
 * Converts an object that implements #FwupdCodec to a JSON builder object.
208
 *
209
 * Since: 2.0.0
210
 */
211
void
212
fwupd_codec_to_json(FwupdCodec *self, JsonBuilder *builder, FwupdCodecFlags flags)
213
0
{
214
0
  FwupdCodecInterface *iface;
215
216
0
  g_return_if_fail(FWUPD_IS_CODEC(self));
217
0
  g_return_if_fail(builder != NULL);
218
219
0
  iface = FWUPD_CODEC_GET_IFACE(self);
220
0
  if (iface->add_json == NULL) {
221
0
    g_critical("FwupdCodec->add_json not implemented");
222
0
    return;
223
0
  }
224
0
  iface->add_json(self, builder, flags);
225
0
}
226
227
/**
228
 * fwupd_codec_to_json_string:
229
 * @self: a #FwupdCodec
230
 * @flags: a #FwupdCodecFlags, e.g. %FWUPD_CODEC_FLAG_TRUSTED
231
 * @error: (nullable): optional return location for an error
232
 *
233
 * Converts an object that implements #FwupdCodec to a JSON string.
234
 *
235
 * Returns: (transfer full): a string
236
 *
237
 * Since: 2.0.0
238
 */
239
gchar *
240
fwupd_codec_to_json_string(FwupdCodec *self, FwupdCodecFlags flags, GError **error)
241
0
{
242
0
  g_autofree gchar *data = NULL;
243
0
  g_autoptr(JsonGenerator) json_generator = NULL;
244
0
  g_autoptr(JsonBuilder) builder = json_builder_new();
245
0
  g_autoptr(JsonNode) json_root = NULL;
246
247
0
  g_return_val_if_fail(FWUPD_IS_CODEC(self), NULL);
248
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
249
250
0
  json_builder_begin_object(builder);
251
0
  fwupd_codec_to_json(self, builder, flags);
252
0
  json_builder_end_object(builder);
253
0
  json_root = json_builder_get_root(builder);
254
0
  json_generator = json_generator_new();
255
0
  json_generator_set_pretty(json_generator, TRUE);
256
0
  json_generator_set_root(json_generator, json_root);
257
0
  data = json_generator_to_data(json_generator, NULL);
258
0
  if (data == NULL) {
259
0
    g_set_error_literal(error,
260
0
            FWUPD_ERROR,
261
0
            FWUPD_ERROR_INTERNAL,
262
0
            "failed to convert to json");
263
0
    return NULL;
264
0
  }
265
0
  return g_steal_pointer(&data);
266
0
}
267
268
/**
269
 * fwupd_codec_from_variant:
270
 * @self: a #FwupdCodec
271
 * @value: (not nullable): a JSON node
272
 * @error: (nullable): optional return location for an error
273
 *
274
 * Converts an object that implements #FwupdCodec from a #GVariant value.
275
 *
276
 * Returns: %TRUE on success
277
 *
278
 * Since: 2.0.0
279
 */
280
gboolean
281
fwupd_codec_from_variant(FwupdCodec *self, GVariant *value, GError **error)
282
0
{
283
0
  FwupdCodecInterface *iface;
284
285
0
  g_return_val_if_fail(FWUPD_IS_CODEC(self), FALSE);
286
0
  g_return_val_if_fail(value != NULL, FALSE);
287
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
288
289
0
  iface = FWUPD_CODEC_GET_IFACE(self);
290
0
  if (iface->from_variant != NULL)
291
0
    return (*iface->from_variant)(self, value, error);
292
0
  if (iface->from_variant_iter != NULL) {
293
0
    const gchar *type_string;
294
0
    type_string = g_variant_get_type_string(value);
295
0
    if (g_strcmp0(type_string, "(a{sv})") == 0) {
296
0
      g_autoptr(GVariantIter) iter = NULL;
297
0
      g_variant_get(value, "(a{sv})", &iter);
298
0
      iface->from_variant_iter(self, iter);
299
0
    } else if (g_strcmp0(type_string, "a{sv}") == 0) {
300
0
      g_autoptr(GVariantIter) iter = NULL;
301
0
      g_variant_get(value, "a{sv}", &iter);
302
0
      iface->from_variant_iter(self, iter);
303
0
    } else {
304
0
      g_set_error(error,
305
0
            FWUPD_ERROR,
306
0
            FWUPD_ERROR_NOT_SUPPORTED,
307
0
            "GVariant type %s not known",
308
0
            type_string);
309
0
      return FALSE;
310
0
    }
311
0
    return TRUE;
312
0
  }
313
0
  g_set_error_literal(error,
314
0
          FWUPD_ERROR,
315
0
          FWUPD_ERROR_NOT_SUPPORTED,
316
0
          "FwupdCodec->from_variant not implemented");
317
0
  return FALSE;
318
0
}
319
320
/**
321
 * fwupd_codec_array_from_variant:
322
 * @value: a JSON node
323
 * @gtype: a #GType that implements `FwupdCodec`
324
 * @error: (nullable): optional return location for an error
325
 *
326
 * Converts an array of objects, each deserialized from a #GVariant value.
327
 *
328
 * Returns: (element-type GObject) (transfer container): %TRUE on success
329
 *
330
 * Since: 2.0.0
331
 */
332
GPtrArray *
333
fwupd_codec_array_from_variant(GVariant *value, GType gtype, GError **error)
334
0
{
335
0
  gsize sz;
336
0
  g_autoptr(GPtrArray) array = NULL;
337
0
  g_autoptr(GVariant) untuple = NULL;
338
339
0
  g_return_val_if_fail(value != NULL, NULL);
340
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
341
342
0
  array = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
343
0
  untuple = g_variant_get_child_value(value, 0);
344
0
  sz = g_variant_n_children(untuple);
345
0
  for (guint i = 0; i < sz; i++) {
346
0
    g_autoptr(GObject) gobj = g_object_new(gtype, NULL);
347
0
    g_autoptr(GVariant) data = g_variant_get_child_value(untuple, i);
348
0
    if (!fwupd_codec_from_variant(FWUPD_CODEC(gobj), data, error))
349
0
      return NULL;
350
0
    g_ptr_array_add(array, g_steal_pointer(&gobj));
351
0
  }
352
0
  return g_steal_pointer(&array);
353
0
}
354
355
/**
356
 * fwupd_codec_array_to_json:
357
 * @array: (element-type GObject): (not nullable): array of objects that much implement `FwupdCodec`
358
 * @member_name: (not nullable): member name of the array
359
 * @builder: (not nullable): a #JsonBuilder
360
 * @flags: a #FwupdCodecFlags, e.g. %FWUPD_CODEC_FLAG_TRUSTED
361
 *
362
 * Converts an array of objects into a #GVariant value.
363
 *
364
 * Since: 2.0.0
365
 */
366
void
367
fwupd_codec_array_to_json(GPtrArray *array,
368
        const gchar *member_name,
369
        JsonBuilder *builder,
370
        FwupdCodecFlags flags)
371
0
{
372
0
  g_return_if_fail(array != NULL);
373
0
  g_return_if_fail(member_name != NULL);
374
0
  g_return_if_fail(JSON_IS_BUILDER(builder));
375
376
0
  json_builder_set_member_name(builder, member_name);
377
0
  json_builder_begin_array(builder);
378
0
  for (guint i = 0; i < array->len; i++) {
379
0
    FwupdCodec *codec = FWUPD_CODEC(g_ptr_array_index(array, i));
380
0
    json_builder_begin_object(builder);
381
0
    fwupd_codec_to_json(codec, builder, flags);
382
0
    json_builder_end_object(builder);
383
0
  }
384
0
  json_builder_end_array(builder);
385
0
}
386
387
/**
388
 * fwupd_codec_array_to_variant:
389
 * @array: (element-type GObject): (not nullable): array of objects that much implement `FwupdCodec`
390
 * @flags: a #FwupdCodecFlags, e.g. %FWUPD_CODEC_FLAG_TRUSTED
391
 *
392
 * Converts an array of objects into a #GVariant value.
393
 *
394
 * Returns: (transfer full): a #GVariant
395
 *
396
 * Since: 2.0.0
397
 */
398
GVariant *
399
fwupd_codec_array_to_variant(GPtrArray *array, FwupdCodecFlags flags)
400
0
{
401
0
  GVariantBuilder builder;
402
403
0
  g_return_val_if_fail(array != NULL, NULL);
404
405
0
  g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}"));
406
0
  for (guint i = 0; i < array->len; i++) {
407
0
    FwupdCodec *codec = FWUPD_CODEC(g_ptr_array_index(array, i));
408
0
    g_variant_builder_add_value(&builder, fwupd_codec_to_variant(codec, flags));
409
0
  }
410
0
  return g_variant_new("(aa{sv})", &builder);
411
0
}
412
413
/**
414
 * fwupd_codec_to_variant:
415
 * @self: a #FwupdCodec
416
 * @flags: a #FwupdCodecFlags, e.g. %FWUPD_CODEC_FLAG_TRUSTED
417
 *
418
 * Converts an object that implements #FwupdCodec to a #GVariant.
419
 *
420
 * Returns: (transfer full): a #GVariant
421
 *
422
 * Since: 2.0.0
423
 */
424
GVariant *
425
fwupd_codec_to_variant(FwupdCodec *self, FwupdCodecFlags flags)
426
0
{
427
0
  FwupdCodecInterface *iface;
428
429
0
  g_return_val_if_fail(FWUPD_IS_CODEC(self), NULL);
430
431
0
  iface = FWUPD_CODEC_GET_IFACE(self);
432
0
  if (iface->to_variant != NULL)
433
0
    return iface->to_variant(self, flags);
434
0
  if (iface->add_variant != NULL) {
435
0
    GVariantBuilder builder;
436
0
    g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
437
0
    iface->add_variant(self, &builder, flags);
438
0
    return g_variant_new("a{sv}", &builder);
439
0
  }
440
441
0
  g_critical("FwupdCodec->add_variant and iface->add_variant not implemented");
442
0
  return NULL;
443
0
}
444
445
static gsize
446
_fu_strwidth(const gchar *text)
447
0
{
448
0
  const gchar *p = text;
449
0
  gsize width = 0;
450
451
0
  g_return_val_if_fail(text != NULL, 0);
452
453
0
  while (*p) {
454
0
    gunichar c = g_utf8_get_char(p);
455
0
    if (g_unichar_iswide(c))
456
0
      width += 2;
457
0
    else if (!g_unichar_iszerowidth(c))
458
0
      width += 1;
459
0
    p = g_utf8_next_char(p);
460
0
  }
461
0
  return width;
462
0
}
463
464
/**
465
 * fwupd_codec_string_append:
466
 * @str: (not nullable): a #GString
467
 * @idt: the indent
468
 * @key: (not nullable): a string to append
469
 * @value: a string to append
470
 *
471
 * Appends a key and value to a string.
472
 *
473
 * Since: 2.0.0
474
 */
475
void
476
fwupd_codec_string_append(GString *str, guint idt, const gchar *key, const gchar *value)
477
0
{
478
0
  const guint align = 24;
479
0
  gsize keysz;
480
481
0
  g_return_if_fail(str != NULL);
482
0
  g_return_if_fail(key != NULL);
483
0
  g_return_if_fail(idt * 2 < align);
484
485
  /* ignore */
486
0
  if (value == NULL)
487
0
    return;
488
0
  for (gsize i = 0; i < idt; i++)
489
0
    g_string_append(str, "  ");
490
0
  if (key[0] != '\0') {
491
0
    g_string_append_printf(str, "%s:", key);
492
0
    keysz = (idt * 2) + _fu_strwidth(key) + 1;
493
0
  } else {
494
0
    keysz = idt * 2;
495
0
  }
496
0
  if (value != NULL) {
497
0
    g_auto(GStrv) split = NULL;
498
0
    split = g_strsplit(value, "\n", -1);
499
0
    for (guint i = 0; split[i] != NULL; i++) {
500
0
      if (i == 0) {
501
0
        g_string_append(str, " ");
502
0
        for (gsize j = keysz + 1; j < align; j++)
503
0
          g_string_append(str, " ");
504
0
      } else {
505
0
        g_string_append(str, "\n");
506
0
        for (gsize j = 0; j < idt; j++)
507
0
          g_string_append(str, "  ");
508
0
      }
509
0
      g_string_append(str, split[i]);
510
0
    }
511
0
  }
512
0
  g_string_append(str, "\n");
513
0
}
514
515
/**
516
 * fwupd_codec_string_append_int:
517
 * @str: (not nullable): a #GString
518
 * @idt: the indent
519
 * @key: (not nullable): a string to append
520
 * @value: guint64
521
 *
522
 * Appends a key and unsigned integer to a string.
523
 *
524
 * Since: 2.0.0
525
 */
526
void
527
fwupd_codec_string_append_int(GString *str, guint idt, const gchar *key, guint64 value)
528
0
{
529
0
  g_autofree gchar *tmp = NULL;
530
531
0
  g_return_if_fail(str != NULL);
532
0
  g_return_if_fail(key != NULL);
533
534
  /* ignore */
535
0
  if (value == 0)
536
0
    return;
537
0
  tmp = g_strdup_printf("%" G_GUINT64_FORMAT, value);
538
0
  fwupd_codec_string_append(str, idt, key, tmp);
539
0
}
540
541
/**
542
 * fwupd_codec_string_append_hex:
543
 * @str: (not nullable): a #GString
544
 * @idt: the indent
545
 * @key: (not nullable): a string to append
546
 * @value: guint64
547
 *
548
 * Appends a key and hex integer to a string.
549
 *
550
 * Since: 2.0.0
551
 */
552
void
553
fwupd_codec_string_append_hex(GString *str, guint idt, const gchar *key, guint64 value)
554
0
{
555
0
  g_autofree gchar *tmp = NULL;
556
557
0
  g_return_if_fail(str != NULL);
558
0
  g_return_if_fail(key != NULL);
559
560
  /* ignore */
561
0
  if (value == 0)
562
0
    return;
563
0
  tmp = g_strdup_printf("0x%x", (guint)value);
564
0
  fwupd_codec_string_append(str, idt, key, tmp);
565
0
}
566
567
/**
568
 * fwupd_codec_string_append_bool:
569
 * @str: (not nullable): a #GString
570
 * @idt: the indent
571
 * @key: (not nullable): a string to append
572
 * @value: Boolean
573
 *
574
 * Appends a key and boolean value to a string.
575
 *
576
 * Since: 2.0.0
577
 */
578
void
579
fwupd_codec_string_append_bool(GString *str, guint idt, const gchar *key, gboolean value)
580
0
{
581
0
  g_return_if_fail(str != NULL);
582
0
  g_return_if_fail(key != NULL);
583
0
  fwupd_codec_string_append(str, idt, key, value ? "true" : "false");
584
0
}
585
586
/**
587
 * fwupd_codec_string_append_time:
588
 * @str: (not nullable): a #GString
589
 * @idt: the indent
590
 * @key: (not nullable): a string to append
591
 * @value: guint64 UNIX time
592
 *
593
 * Appends a key and time value to a string.
594
 *
595
 * Since: 2.0.0
596
 */
597
void
598
fwupd_codec_string_append_time(GString *str, guint idt, const gchar *key, guint64 value)
599
0
{
600
0
  g_autofree gchar *tmp = NULL;
601
0
  g_autoptr(GDateTime) date = NULL;
602
603
0
  g_return_if_fail(str != NULL);
604
0
  g_return_if_fail(key != NULL);
605
606
  /* ignore */
607
0
  if (value == 0)
608
0
    return;
609
610
0
  date = g_date_time_new_from_unix_utc((gint64)value);
611
0
  tmp = g_date_time_format(date, "%F %T");
612
0
  fwupd_codec_string_append(str, idt, key, tmp);
613
0
}
614
615
/**
616
 * fwupd_codec_string_append_size:
617
 * @str: (not nullable): a #GString
618
 * @idt: the indent
619
 * @key: (not nullable): a string to append
620
 * @value: guint64
621
 *
622
 * Appends a key and size in bytes to a string.
623
 *
624
 * Since: 2.0.0
625
 */
626
void
627
fwupd_codec_string_append_size(GString *str, guint idt, const gchar *key, guint64 value)
628
0
{
629
0
  g_autofree gchar *tmp = NULL;
630
631
0
  g_return_if_fail(str != NULL);
632
0
  g_return_if_fail(key != NULL);
633
634
  /* ignore */
635
0
  if (value == 0)
636
0
    return;
637
0
  tmp = g_format_size(value);
638
0
  fwupd_codec_string_append(str, idt, key, tmp);
639
0
}
640
641
/**
642
 * fwupd_codec_json_append:
643
 * @builder: (not nullable): a #JsonBuilder
644
 * @key: (not nullable): a string
645
 * @value: a string to append
646
 *
647
 * Appends a key and value to a JSON builder.
648
 *
649
 * Since: 2.0.0
650
 */
651
void
652
fwupd_codec_json_append(JsonBuilder *builder, const gchar *key, const gchar *value)
653
0
{
654
0
  g_return_if_fail(JSON_IS_BUILDER(builder));
655
0
  g_return_if_fail(key != NULL);
656
0
  if (value == NULL)
657
0
    return;
658
0
  json_builder_set_member_name(builder, key);
659
0
  json_builder_add_string_value(builder, value);
660
0
}
661
662
/**
663
 * fwupd_codec_json_append_int:
664
 * @builder: (not nullable): a #JsonBuilder
665
 * @key: (not nullable): a string
666
 * @value: guint64
667
 *
668
 * Appends a key and unsigned integer to a JSON builder.
669
 *
670
 * Since: 2.0.0
671
 */
672
void
673
fwupd_codec_json_append_int(JsonBuilder *builder, const gchar *key, guint64 value)
674
0
{
675
0
  g_return_if_fail(JSON_IS_BUILDER(builder));
676
0
  g_return_if_fail(key != NULL);
677
0
  json_builder_set_member_name(builder, key);
678
0
  json_builder_add_int_value(builder, value);
679
0
}
680
681
/**
682
 * fwupd_codec_json_append_bool:
683
 * @builder: (not nullable): a #JsonBuilder
684
 * @key: (not nullable): a string
685
 * @value: boolean
686
 *
687
 * Appends a key and boolean value to a JSON builder.
688
 *
689
 * Since: 2.0.0
690
 */
691
void
692
fwupd_codec_json_append_bool(JsonBuilder *builder, const gchar *key, gboolean value)
693
0
{
694
0
  g_return_if_fail(JSON_IS_BUILDER(builder));
695
0
  g_return_if_fail(key != NULL);
696
0
  json_builder_set_member_name(builder, key);
697
0
  json_builder_add_boolean_value(builder, value);
698
0
}
699
700
/**
701
 * fwupd_codec_json_append_strv:
702
 * @builder: (not nullable): a #JsonBuilder
703
 * @key: (not nullable): a string
704
 * @value: a #GStrv
705
 *
706
 * Appends a key and string array to a JSON builder.
707
 *
708
 * Since: 2.0.0
709
 */
710
void
711
fwupd_codec_json_append_strv(JsonBuilder *builder, const gchar *key, gchar **value)
712
0
{
713
0
  g_return_if_fail(JSON_IS_BUILDER(builder));
714
0
  g_return_if_fail(key != NULL);
715
0
  if (value == NULL)
716
0
    return;
717
0
  json_builder_set_member_name(builder, key);
718
0
  json_builder_begin_array(builder);
719
0
  for (guint i = 0; value[i] != NULL; i++)
720
0
    json_builder_add_string_value(builder, value[i]);
721
0
  json_builder_end_array(builder);
722
0
}
723
724
/**
725
 * fwupd_codec_json_append_map:
726
 * @builder: (not nullable): a #JsonBuilder
727
 * @key: (not nullable): a string
728
 * @value: (element-type utf8 utf8): a hash table
729
 *
730
 * Appends a key and string hash map to a JSON builder.
731
 *
732
 * Since: 2.0.10
733
 */
734
void
735
fwupd_codec_json_append_map(JsonBuilder *builder, const gchar *key, GHashTable *value)
736
0
{
737
0
  GHashTableIter iter;
738
0
  gpointer hash_key, hash_value;
739
740
0
  g_return_if_fail(JSON_IS_BUILDER(builder));
741
0
  g_return_if_fail(key != NULL);
742
743
0
  if (value == NULL)
744
0
    return;
745
0
  json_builder_set_member_name(builder, key);
746
0
  json_builder_begin_object(builder);
747
0
  g_hash_table_iter_init(&iter, value);
748
0
  while (g_hash_table_iter_next(&iter, &hash_key, &hash_value)) {
749
0
    fwupd_codec_json_append(builder,
750
0
          (const gchar *)hash_key,
751
0
          (const gchar *)hash_value);
752
0
  }
753
0
  json_builder_end_object(builder);
754
0
}