Coverage Report

Created: 2026-09-03 07:14

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