Coverage Report

Created: 2026-01-10 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupd/fwupd-json-object.c
Line
Count
Source
1
/*
2
 * Copyright 2025 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-error.h"
10
#include "fwupd-json-array-private.h"
11
#include "fwupd-json-common-private.h"
12
#include "fwupd-json-node-private.h"
13
#include "fwupd-json-object-private.h"
14
15
/**
16
 * FwupdJsonObject:
17
 *
18
 * A JSON object.
19
 *
20
 * See also: [struct@FwupdJsonArray] [struct@FwupdJsonNode]
21
 */
22
23
typedef struct {
24
  GRefString *key;
25
  FwupdJsonNode *json_node;
26
} FwupdJsonObjectEntry;
27
28
struct FwupdJsonObject {
29
  grefcount refcount;
30
  GPtrArray *items; /* element-type FwupdJsonObjectEntry */
31
};
32
33
static void
34
fwupd_json_object_entry_free(FwupdJsonObjectEntry *entry)
35
9.52k
{
36
9.52k
  g_ref_string_release(entry->key);
37
9.52k
  fwupd_json_node_unref(entry->json_node);
38
9.52k
  g_free(entry);
39
9.52k
}
40
41
/**
42
 * fwupd_json_object_new: (skip):
43
 *
44
 * Creates a new JSON object.
45
 *
46
 * Returns: (transfer full): a #FwupdJsonObject
47
 *
48
 * Since: 2.1.1
49
 **/
50
FwupdJsonObject *
51
fwupd_json_object_new(void)
52
10.1k
{
53
10.1k
  FwupdJsonObject *self = g_new0(FwupdJsonObject, 1);
54
10.1k
  g_ref_count_init(&self->refcount);
55
10.1k
  self->items = g_ptr_array_new_with_free_func((GDestroyNotify)fwupd_json_object_entry_free);
56
10.1k
  return self;
57
10.1k
}
58
59
/**
60
 * fwupd_json_object_ref: (skip):
61
 * @self: a #FwupdJsonObject
62
 *
63
 * Increases the reference count of a JSON object.
64
 *
65
 * Returns: (transfer full): a #FwupdJsonObject
66
 *
67
 * Since: 2.1.1
68
 **/
69
FwupdJsonObject *
70
fwupd_json_object_ref(FwupdJsonObject *self)
71
13.7k
{
72
13.7k
  g_return_val_if_fail(self != NULL, NULL);
73
13.7k
  g_ref_count_inc(&self->refcount);
74
13.7k
  return self;
75
13.7k
}
76
77
/**
78
 * fwupd_json_object_unref: (skip):
79
 * @self: a #FwupdJsonObject
80
 *
81
 * Decreases the reference count of a JSON object.
82
 *
83
 * Returns: (transfer none): a #FwupdJsonObject, or %NULL
84
 *
85
 * Since: 2.1.1
86
 **/
87
FwupdJsonObject *
88
fwupd_json_object_unref(FwupdJsonObject *self)
89
23.9k
{
90
23.9k
  g_return_val_if_fail(self != NULL, NULL);
91
23.9k
  if (!g_ref_count_dec(&self->refcount))
92
13.7k
    return self;
93
10.1k
  g_ptr_array_unref(self->items);
94
10.1k
  g_free(self);
95
10.1k
  return NULL;
96
23.9k
}
97
98
/**
99
 * fwupd_json_object_clear:
100
 * @self: a #FwupdJsonObject
101
 *
102
 * Clears the member data for the JSON object, but does not affect the refcount.
103
 *
104
 * Since: 2.1.1
105
 **/
106
void
107
fwupd_json_object_clear(FwupdJsonObject *self)
108
0
{
109
0
  g_return_if_fail(self != NULL);
110
0
  g_ptr_array_set_size(self->items, 0);
111
0
}
112
113
/**
114
 * fwupd_json_object_get_size:
115
 * @self: a #FwupdJsonObject
116
 *
117
 * Gets the size of the JSON object.
118
 *
119
 * Returns: number of key-values added
120
 *
121
 * Since: 2.1.1
122
 **/
123
guint
124
fwupd_json_object_get_size(FwupdJsonObject *self)
125
12.5k
{
126
12.5k
  g_return_val_if_fail(self != NULL, G_MAXUINT);
127
12.5k
  return self->items->len;
128
12.5k
}
129
130
/**
131
 * fwupd_json_object_get_key_for_index: (skip):
132
 * @self: a #FwupdJsonObject
133
 * @idx: index
134
 * @error: (nullable): optional return location for an error
135
 *
136
 * Gets the key for a given index position.
137
 *
138
 * Returns: a #GRefString, or %NULL on error
139
 *
140
 * Since: 2.1.1
141
 **/
142
GRefString *
143
fwupd_json_object_get_key_for_index(FwupdJsonObject *self, guint idx, GError **error)
144
0
{
145
0
  FwupdJsonObjectEntry *entry;
146
147
0
  g_return_val_if_fail(self != NULL, NULL);
148
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
149
150
  /* sanity check */
151
0
  if (idx >= self->items->len) {
152
0
    g_set_error(error,
153
0
          FWUPD_ERROR,
154
0
          FWUPD_ERROR_NOT_FOUND,
155
0
          "index %u is larger than object size",
156
0
          idx);
157
0
    return NULL;
158
0
  }
159
160
  /* success */
161
0
  entry = g_ptr_array_index(self->items, idx);
162
0
  return entry->key;
163
0
}
164
165
/**
166
 * fwupd_json_object_get_node_for_index: (skip):
167
 * @self: a #FwupdJsonObject
168
 * @idx: index
169
 * @error: (nullable): optional return location for an error
170
 *
171
 * Gets the node for a given index position.
172
 *
173
 * Returns: (transfer full): a #FwupdJsonNode, or %NULL on error
174
 *
175
 * Since: 2.1.1
176
 **/
177
FwupdJsonNode *
178
fwupd_json_object_get_node_for_index(FwupdJsonObject *self, guint idx, GError **error)
179
0
{
180
0
  FwupdJsonObjectEntry *entry;
181
182
0
  g_return_val_if_fail(self != NULL, NULL);
183
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
184
185
  /* sanity check */
186
0
  if (idx >= self->items->len) {
187
0
    g_set_error(error,
188
0
          FWUPD_ERROR,
189
0
          FWUPD_ERROR_NOT_FOUND,
190
0
          "index %u is larger than object size",
191
0
          idx);
192
0
    return NULL;
193
0
  }
194
195
  /* success */
196
0
  entry = g_ptr_array_index(self->items, idx);
197
0
  return fwupd_json_node_ref(entry->json_node);
198
0
}
199
200
static FwupdJsonObjectEntry *
201
fwupd_json_object_get_entry(FwupdJsonObject *self, const gchar *key, GError **error)
202
12.5k
{
203
26.0k
  for (guint i = 0; i < self->items->len; i++) {
204
16.5k
    FwupdJsonObjectEntry *entry = g_ptr_array_index(self->items, i);
205
16.5k
    if (g_strcmp0(key, entry->key) == 0)
206
3.06k
      return entry;
207
16.5k
  }
208
9.52k
  g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no json_node for key %s", key);
209
9.52k
  return NULL;
210
12.5k
}
211
212
/**
213
 * fwupd_json_object_get_string: (skip):
214
 * @self: a #FwupdJsonObject
215
 * @key: (not nullable): dictionary key
216
 * @error: (nullable): optional return location for an error
217
 *
218
 * Gets a string from a JSON object. An error is returned if @key is not the correct type.
219
 *
220
 * Returns: a #GRefString, or %NULL on error
221
 *
222
 * Since: 2.1.1
223
 **/
224
GRefString *
225
fwupd_json_object_get_string(FwupdJsonObject *self, const gchar *key, GError **error)
226
0
{
227
0
  FwupdJsonObjectEntry *entry;
228
229
0
  g_return_val_if_fail(self != NULL, NULL);
230
0
  g_return_val_if_fail(key != NULL, NULL);
231
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
232
233
0
  entry = fwupd_json_object_get_entry(self, key, error);
234
0
  if (entry == NULL)
235
0
    return NULL;
236
0
  return fwupd_json_node_get_string(entry->json_node, error);
237
0
}
238
239
/**
240
 * fwupd_json_object_get_string_with_default:
241
 * @self: a #FwupdJsonObject
242
 * @key: (not nullable): dictionary key
243
 * @value_default: (not nullable): value to return if @key is not found
244
 * @error: (nullable): optional return location for an error
245
 *
246
 * Gets a string from a JSON object. An error is returned if @key is not the correct type.
247
 *
248
 * Returns: a string, or %NULL on error
249
 *
250
 * Since: 2.1.1
251
 **/
252
const gchar *
253
fwupd_json_object_get_string_with_default(FwupdJsonObject *self,
254
            const gchar *key,
255
            const gchar *value_default,
256
            GError **error)
257
0
{
258
0
  FwupdJsonObjectEntry *entry;
259
260
0
  g_return_val_if_fail(self != NULL, NULL);
261
0
  g_return_val_if_fail(key != NULL, NULL);
262
0
  g_return_val_if_fail(value_default != NULL, NULL);
263
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
264
265
0
  entry = fwupd_json_object_get_entry(self, key, NULL);
266
0
  if (entry == NULL)
267
0
    return value_default;
268
0
  return fwupd_json_node_get_string(entry->json_node, error);
269
0
}
270
271
/**
272
 * fwupd_json_object_get_integer:
273
 * @self: a #FwupdJsonObject
274
 * @key: (not nullable): dictionary key
275
 * @value: (out) (nullable): integer value
276
 * @error: (nullable): optional return location for an error
277
 *
278
 * Gets an integer from a JSON object. An error is returned if @key is not the correct type.
279
 *
280
 * Returns: %TRUE if @value was parsed as an integer
281
 *
282
 * Since: 2.1.1
283
 **/
284
gboolean
285
fwupd_json_object_get_integer(FwupdJsonObject *self,
286
            const gchar *key,
287
            gint64 *value,
288
            GError **error)
289
0
{
290
0
  FwupdJsonObjectEntry *entry;
291
0
  const gchar *str;
292
0
  gchar *endptr = NULL;
293
0
  gint64 value_tmp;
294
295
0
  g_return_val_if_fail(self != NULL, FALSE);
296
0
  g_return_val_if_fail(key != NULL, FALSE);
297
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
298
299
0
  entry = fwupd_json_object_get_entry(self, key, error);
300
0
  if (entry == NULL)
301
0
    return FALSE;
302
0
  str = fwupd_json_node_get_raw(entry->json_node, error);
303
0
  if (str == NULL)
304
0
    return FALSE;
305
306
  /* convert */
307
0
  value_tmp = g_ascii_strtoll(str, &endptr, 10); /* nocheck:blocked */
308
0
  if ((gsize)(endptr - str) != strlen(str)) {
309
0
    g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_DATA, "cannot parse %s", str);
310
0
    return FALSE;
311
0
  }
312
313
  /* overflow check */
314
0
  if (value_tmp == G_MAXINT64) {
315
0
    g_set_error(error,
316
0
          FWUPD_ERROR,
317
0
          FWUPD_ERROR_INVALID_DATA,
318
0
          "cannot parse %s due to overflow",
319
0
          str);
320
0
    return FALSE;
321
0
  }
322
323
  /* success */
324
0
  if (value != NULL)
325
0
    *value = value_tmp;
326
0
  return TRUE;
327
0
}
328
329
/**
330
 * fwupd_json_object_get_integer_with_default:
331
 * @self: a #FwupdJsonObject
332
 * @key: (not nullable): dictionary key
333
 * @value: (out) (nullable): integer value
334
 * @value_default: value to return if @key is not found, typically 0 or %G_MAXINT64
335
 * @error: (nullable): optional return location for an error
336
 *
337
 * Gets an integer from a JSON object. An error is returned if @key is not the correct type.
338
 *
339
 * Returns: %TRUE if @value was parsed as an integer
340
 *
341
 * Since: 2.1.1
342
 **/
343
gboolean
344
fwupd_json_object_get_integer_with_default(FwupdJsonObject *self,
345
             const gchar *key,
346
             gint64 *value,
347
             gint64 value_default,
348
             GError **error)
349
0
{
350
0
  FwupdJsonObjectEntry *entry;
351
0
  const gchar *str;
352
0
  gchar *endptr = NULL;
353
0
  gint64 value_tmp;
354
355
0
  g_return_val_if_fail(self != NULL, FALSE);
356
0
  g_return_val_if_fail(key != NULL, FALSE);
357
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
358
359
0
  entry = fwupd_json_object_get_entry(self, key, NULL);
360
0
  if (entry == NULL) {
361
0
    if (value != NULL)
362
0
      *value = value_default;
363
0
    return TRUE;
364
0
  }
365
0
  str = fwupd_json_node_get_raw(entry->json_node, error);
366
0
  if (str == NULL)
367
0
    return FALSE;
368
369
  /* convert */
370
0
  value_tmp = g_ascii_strtoll(str, &endptr, 10); /* nocheck:blocked */
371
0
  if ((gsize)(endptr - str) != strlen(str)) {
372
0
    g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_DATA, "cannot parse %s", str);
373
0
    return FALSE;
374
0
  }
375
376
  /* overflow check */
377
0
  if (value_tmp == G_MAXINT64) {
378
0
    g_set_error(error,
379
0
          FWUPD_ERROR,
380
0
          FWUPD_ERROR_INVALID_DATA,
381
0
          "cannot parse %s due to overflow",
382
0
          str);
383
0
    return FALSE;
384
0
  }
385
386
  /* success */
387
0
  if (value != NULL)
388
0
    *value = value_tmp;
389
0
  return TRUE;
390
0
}
391
392
/**
393
 * fwupd_json_object_get_boolean:
394
 * @self: a #FwupdJsonObject
395
 * @key: (not nullable): dictionary key
396
 * @value: (out) (nullable): boolean value
397
 * @error: (nullable): optional return location for an error
398
 *
399
 * Gets a boolean from a JSON object. An error is returned if @key is not the correct type.
400
 *
401
 * Returns: %TRUE if @value was parsed as an integer
402
 *
403
 * Since: 2.1.1
404
 **/
405
gboolean
406
fwupd_json_object_get_boolean(FwupdJsonObject *self,
407
            const gchar *key,
408
            gboolean *value,
409
            GError **error)
410
0
{
411
0
  FwupdJsonObjectEntry *entry;
412
0
  const gchar *str;
413
414
0
  g_return_val_if_fail(self != NULL, FALSE);
415
0
  g_return_val_if_fail(key != NULL, FALSE);
416
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
417
418
0
  entry = fwupd_json_object_get_entry(self, key, error);
419
0
  if (entry == NULL)
420
0
    return FALSE;
421
0
  str = fwupd_json_node_get_raw(entry->json_node, error);
422
0
  if (str == NULL)
423
0
    return FALSE;
424
425
  /* convert */
426
0
  if (g_ascii_strcasecmp(str, "false") == 0) {
427
0
    if (value != NULL)
428
0
      *value = FALSE;
429
0
    return TRUE;
430
0
  }
431
0
  if (g_ascii_strcasecmp(str, "true") == 0) {
432
0
    if (value != NULL)
433
0
      *value = TRUE;
434
0
    return TRUE;
435
0
  }
436
437
  /* failed */
438
0
  g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_DATA, "cannot parse %s", str);
439
0
  return FALSE;
440
0
}
441
442
/**
443
 * fwupd_json_object_get_boolean_with_default:
444
 * @self: a #FwupdJsonObject
445
 * @key: (not nullable): dictionary key
446
 * @value: (out) (nullable): boolean value
447
 * @value_default: value to return if @key is not found, typically %FALSE
448
 * @error: (nullable): optional return location for an error
449
 *
450
 * Gets a boolean from a JSON object. An error is returned if @key is not the correct type.
451
 *
452
 * Returns: %TRUE if @value was parsed as an integer
453
 *
454
 * Since: 2.1.1
455
 **/
456
gboolean
457
fwupd_json_object_get_boolean_with_default(FwupdJsonObject *self,
458
             const gchar *key,
459
             gboolean *value,
460
             gboolean value_default,
461
             GError **error)
462
0
{
463
0
  FwupdJsonObjectEntry *entry;
464
0
  const gchar *str;
465
466
0
  g_return_val_if_fail(self != NULL, FALSE);
467
0
  g_return_val_if_fail(key != NULL, FALSE);
468
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
469
470
0
  entry = fwupd_json_object_get_entry(self, key, NULL);
471
0
  if (entry == NULL) {
472
0
    if (value != NULL)
473
0
      *value = value_default;
474
0
    return TRUE;
475
0
  }
476
0
  str = fwupd_json_node_get_raw(entry->json_node, error);
477
0
  if (str == NULL)
478
0
    return FALSE;
479
480
  /* convert */
481
0
  if (g_ascii_strcasecmp(str, "false") == 0) {
482
0
    if (value != NULL)
483
0
      *value = FALSE;
484
0
    return TRUE;
485
0
  }
486
0
  if (g_ascii_strcasecmp(str, "true") == 0) {
487
0
    if (value != NULL)
488
0
      *value = TRUE;
489
0
    return TRUE;
490
0
  }
491
492
  /* failed */
493
0
  g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_DATA, "cannot parse %s", str);
494
0
  return FALSE;
495
0
}
496
497
/**
498
 * fwupd_json_object_has_node: (skip):
499
 * @self: a #FwupdJsonObject
500
 * @key: (not nullable): dictionary key
501
 *
502
 * Finds if a node exists in a JSON object.
503
 *
504
 * In general, it's nearly always better to call the type-specific method directly e.g.
505
 * fwupd_json_object_get_string() and handle the error.
506
 *
507
 * Returns: %TRUE if a node exists with the key.
508
 *
509
 * Since: 2.1.1
510
 **/
511
gboolean
512
fwupd_json_object_has_node(FwupdJsonObject *self, const gchar *key)
513
0
{
514
0
  g_return_val_if_fail(self != NULL, FALSE);
515
0
  g_return_val_if_fail(key != NULL, FALSE);
516
0
  return fwupd_json_object_get_entry(self, key, NULL) != NULL;
517
0
}
518
519
/**
520
 * fwupd_json_object_get_node: (skip):
521
 * @self: a #FwupdJsonObject
522
 * @key: (not nullable): dictionary key
523
 * @error: (nullable): optional return location for an error
524
 *
525
 * Gets a node from a JSON object.
526
 *
527
 * Returns: (transfer full): a #FwupdJsonObject, or %NULL on error
528
 *
529
 * Since: 2.1.1
530
 **/
531
FwupdJsonNode *
532
fwupd_json_object_get_node(FwupdJsonObject *self, const gchar *key, GError **error)
533
0
{
534
0
  FwupdJsonObjectEntry *entry;
535
536
0
  g_return_val_if_fail(self != NULL, NULL);
537
0
  g_return_val_if_fail(key != NULL, NULL);
538
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
539
540
0
  entry = fwupd_json_object_get_entry(self, key, error);
541
0
  if (entry == NULL)
542
0
    return NULL;
543
0
  return fwupd_json_node_ref(entry->json_node);
544
0
}
545
546
/**
547
 * fwupd_json_object_get_nodes: (skip):
548
 * @self: a #FwupdJsonObject
549
 *
550
 * Gets all the nodes from a JSON object.
551
 *
552
 * Returns: (transfer container) (element-type FwupdJsonNode): an array of nodes
553
 *
554
 * Since: 2.1.1
555
 **/
556
GPtrArray *
557
fwupd_json_object_get_nodes(FwupdJsonObject *self)
558
0
{
559
0
  g_autoptr(GPtrArray) json_nodes =
560
0
      g_ptr_array_new_with_free_func((GDestroyNotify)fwupd_json_node_unref);
561
562
0
  g_return_val_if_fail(self != NULL, NULL);
563
564
0
  for (guint i = 0; i < self->items->len; i++) {
565
0
    FwupdJsonObjectEntry *entry = g_ptr_array_index(self->items, i);
566
0
    g_ptr_array_add(json_nodes, fwupd_json_node_ref(entry->json_node));
567
0
  }
568
0
  return g_steal_pointer(&json_nodes);
569
0
}
570
571
/**
572
 * fwupd_json_object_get_keys: (skip):
573
 * @self: a #FwupdJsonObject
574
 *
575
 * Gets all the keys from a JSON object.
576
 *
577
 * Returns: (transfer container) (element-type GRefString): an array of keys
578
 *
579
 * Since: 2.1.1
580
 **/
581
GPtrArray *
582
fwupd_json_object_get_keys(FwupdJsonObject *self)
583
0
{
584
0
  g_autoptr(GPtrArray) json_keys =
585
0
      g_ptr_array_new_with_free_func((GDestroyNotify)g_ref_string_release);
586
587
0
  g_return_val_if_fail(self != NULL, NULL);
588
589
0
  for (guint i = 0; i < self->items->len; i++) {
590
0
    FwupdJsonObjectEntry *entry = g_ptr_array_index(self->items, i);
591
0
    g_ptr_array_add(json_keys, g_ref_string_acquire(entry->key));
592
0
  }
593
0
  return g_steal_pointer(&json_keys);
594
0
}
595
596
/**
597
 * fwupd_json_object_get_object: (skip):
598
 * @self: a #FwupdJsonObject
599
 * @key: (not nullable): dictionary key
600
 * @error: (nullable): optional return location for an error
601
 *
602
 * Gets a different object from a JSON object. An error is returned if @key is not the correct type.
603
 *
604
 * Returns: (transfer full): a #FwupdJsonObject, or %NULL on error
605
 *
606
 * Since: 2.1.1
607
 **/
608
FwupdJsonObject *
609
fwupd_json_object_get_object(FwupdJsonObject *self, const gchar *key, GError **error)
610
0
{
611
0
  FwupdJsonObjectEntry *entry;
612
613
0
  g_return_val_if_fail(self != NULL, NULL);
614
0
  g_return_val_if_fail(key != NULL, NULL);
615
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
616
617
0
  entry = fwupd_json_object_get_entry(self, key, error);
618
0
  if (entry == NULL)
619
0
    return NULL;
620
0
  return fwupd_json_node_get_object(entry->json_node, error);
621
0
}
622
623
/**
624
 * fwupd_json_object_get_array: (skip):
625
 * @self: a #FwupdJsonObject
626
 * @key: (not nullable): dictionary key
627
 * @error: (nullable): optional return location for an error
628
 *
629
 * Gets an array from a JSON object. An error is returned if @key is not the correct type.
630
 *
631
 * Returns: (transfer full): a #FwupdJsonArray, or %NULL on error
632
 *
633
 * Since: 2.1.1
634
 **/
635
FwupdJsonArray *
636
fwupd_json_object_get_array(FwupdJsonObject *self, const gchar *key, GError **error)
637
0
{
638
0
  FwupdJsonObjectEntry *entry;
639
640
0
  g_return_val_if_fail(self != NULL, NULL);
641
0
  g_return_val_if_fail(key != NULL, NULL);
642
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
643
644
0
  entry = fwupd_json_object_get_entry(self, key, error);
645
0
  if (entry == NULL)
646
0
    return NULL;
647
0
  return fwupd_json_node_get_array(entry->json_node, error);
648
0
}
649
650
void
651
fwupd_json_object_add_raw_internal(FwupdJsonObject *self,
652
           GRefString *key,
653
           GRefString *value,
654
           FwupdJsonLoadFlags flags)
655
4.56k
{
656
4.56k
  FwupdJsonObjectEntry *entry = NULL;
657
658
4.56k
  if ((flags & FWUPD_JSON_LOAD_FLAG_TRUSTED) == 0)
659
4.56k
    entry = fwupd_json_object_get_entry(self, key, NULL);
660
4.56k
  if (entry != NULL) {
661
455
    fwupd_json_node_unref(entry->json_node);
662
4.11k
  } else {
663
4.11k
    entry = g_new0(FwupdJsonObjectEntry, 1);
664
4.11k
    entry->key = (flags & FWUPD_JSON_LOAD_FLAG_STATIC_KEYS) > 0
665
4.11k
         ? g_ref_string_new_intern(key)
666
4.11k
         : g_ref_string_acquire(key);
667
4.11k
    g_ptr_array_add(self->items, entry);
668
4.11k
  }
669
4.56k
  entry->json_node = fwupd_json_node_new_raw_internal(value);
670
4.56k
}
671
672
/**
673
 * fwupd_json_object_add_node:
674
 * @self: a #FwupdJsonObject
675
 * @key: (not nullable): dictionary key
676
 * @json_node: (not nullable): a #FwupdJsonNode
677
 *
678
 * Adds a node to the JSON object. If the node already exists the old one is replaced.
679
 *
680
 * Since: 2.1.1
681
 **/
682
void
683
fwupd_json_object_add_node(FwupdJsonObject *self, const gchar *key, FwupdJsonNode *json_node)
684
0
{
685
0
  FwupdJsonObjectEntry *entry;
686
687
0
  g_return_if_fail(self != NULL);
688
0
  g_return_if_fail(key != NULL);
689
0
  g_return_if_fail(json_node != NULL);
690
691
0
  entry = fwupd_json_object_get_entry(self, key, NULL);
692
0
  if (entry != NULL) {
693
0
    fwupd_json_node_unref(entry->json_node);
694
0
  } else {
695
0
    entry = g_new0(FwupdJsonObjectEntry, 1);
696
0
    entry->key = g_ref_string_new(key);
697
0
    g_ptr_array_add(self->items, entry);
698
0
  }
699
0
  entry->json_node = fwupd_json_node_ref(json_node);
700
0
}
701
702
/**
703
 * fwupd_json_object_add_raw:
704
 * @self: a #FwupdJsonObject
705
 * @key: (not nullable): dictionary key
706
 * @value: (not nullable): value
707
 *
708
 * Adds a raw value to the JSON object. If the node already exists the old one is replaced.
709
 *
710
 * Since: 2.1.1
711
 **/
712
void
713
fwupd_json_object_add_raw(FwupdJsonObject *self, const gchar *key, const gchar *value)
714
0
{
715
0
  g_autoptr(FwupdJsonNode) json_node = NULL;
716
717
0
  g_return_if_fail(self != NULL);
718
0
  g_return_if_fail(key != NULL);
719
0
  g_return_if_fail(value != NULL);
720
721
0
  json_node = fwupd_json_node_new_raw(value);
722
0
  fwupd_json_object_add_node(self, key, json_node);
723
0
}
724
725
void
726
fwupd_json_object_add_string_internal(FwupdJsonObject *self,
727
              GRefString *key,
728
              GRefString *value,
729
              FwupdJsonLoadFlags flags)
730
2.19k
{
731
2.19k
  FwupdJsonObjectEntry *entry = NULL;
732
733
2.19k
  if ((flags & FWUPD_JSON_LOAD_FLAG_TRUSTED) == 0)
734
2.19k
    entry = fwupd_json_object_get_entry(self, key, NULL);
735
2.19k
  if (entry != NULL) {
736
826
    fwupd_json_node_unref(entry->json_node);
737
1.37k
  } else {
738
1.37k
    entry = g_new0(FwupdJsonObjectEntry, 1);
739
1.37k
    entry->key = (flags & FWUPD_JSON_LOAD_FLAG_STATIC_KEYS) > 0
740
1.37k
         ? g_ref_string_new_intern(key)
741
1.37k
         : g_ref_string_acquire(key);
742
1.37k
    g_ptr_array_add(self->items, entry);
743
1.37k
  }
744
2.19k
  entry->json_node = fwupd_json_node_new_string_internal(value);
745
2.19k
}
746
747
/**
748
 * fwupd_json_object_add_string:
749
 * @self: a #FwupdJsonObject
750
 * @key: (not nullable): dictionary key
751
 * @value: (nullable): value, or %NULL
752
 *
753
 * Adds a string value to the JSON object. If the node already exists the old one is replaced.
754
 *
755
 * Since: 2.1.1
756
 **/
757
void
758
fwupd_json_object_add_string(FwupdJsonObject *self, const gchar *key, const gchar *value)
759
0
{
760
0
  g_autoptr(FwupdJsonNode) json_node = NULL;
761
762
0
  g_return_if_fail(self != NULL);
763
0
  g_return_if_fail(key != NULL);
764
765
0
  json_node = fwupd_json_node_new_string(value);
766
0
  fwupd_json_object_add_node(self, key, json_node);
767
0
}
768
769
/**
770
 * fwupd_json_object_add_array_strv:
771
 * @self: a #FwupdJsonObject
772
 * @key: (not nullable): dictionary key
773
 * @value: (not nullable): value
774
 *
775
 * Adds a string array to the JSON object. If the node already exists the old one is replaced.
776
 *
777
 * Since: 2.1.1
778
 **/
779
void
780
fwupd_json_object_add_array_strv(FwupdJsonObject *self, const gchar *key, gchar **value)
781
0
{
782
0
  g_autoptr(FwupdJsonArray) json_arr = fwupd_json_array_new();
783
784
0
  g_return_if_fail(self != NULL);
785
0
  g_return_if_fail(key != NULL);
786
0
  g_return_if_fail(value != NULL);
787
788
0
  for (guint i = 0; value[i] != NULL; i++)
789
0
    fwupd_json_array_add_string(json_arr, value[i]);
790
0
  fwupd_json_object_add_array(self, key, json_arr);
791
0
}
792
793
/**
794
 * fwupd_json_object_add_integer:
795
 * @self: a #FwupdJsonObject
796
 * @key: (not nullable): dictionary key
797
 * @value: integer
798
 *
799
 * Adds an integer value to the JSON object.
800
 *
801
 * Since: 2.1.1
802
 **/
803
void
804
fwupd_json_object_add_integer(FwupdJsonObject *self, const gchar *key, gint64 value)
805
0
{
806
0
  g_autoptr(FwupdJsonNode) json_node = NULL;
807
0
  g_autofree gchar *str = NULL;
808
809
0
  g_return_if_fail(self != NULL);
810
0
  g_return_if_fail(key != NULL);
811
0
  g_return_if_fail(value != G_MAXINT64);
812
813
0
  str = g_strdup_printf("%" G_GINT64_FORMAT, value);
814
0
  json_node = fwupd_json_node_new_raw(str);
815
0
  fwupd_json_object_add_node(self, key, json_node);
816
0
}
817
818
/**
819
 * fwupd_json_object_add_boolean:
820
 * @self: a #FwupdJsonObject
821
 * @key: (not nullable): dictionary key
822
 * @value: boolean
823
 *
824
 * Adds a boolean value to the JSON object.
825
 *
826
 * Since: 2.1.1
827
 **/
828
void
829
fwupd_json_object_add_boolean(FwupdJsonObject *self, const gchar *key, gboolean value)
830
0
{
831
0
  g_autoptr(FwupdJsonNode) json_node = NULL;
832
833
0
  g_return_if_fail(self != NULL);
834
0
  g_return_if_fail(key != NULL);
835
836
0
  json_node = fwupd_json_node_new_raw(value ? "true" : "false");
837
0
  fwupd_json_object_add_node(self, key, json_node);
838
0
}
839
840
void
841
fwupd_json_object_add_object_internal(FwupdJsonObject *self,
842
              GRefString *key,
843
              FwupdJsonObject *json_obj)
844
3.64k
{
845
3.64k
  FwupdJsonObjectEntry *entry = fwupd_json_object_get_entry(self, key, NULL);
846
3.64k
  if (entry != NULL) {
847
1.16k
    fwupd_json_node_unref(entry->json_node);
848
2.47k
  } else {
849
2.47k
    entry = g_new0(FwupdJsonObjectEntry, 1);
850
2.47k
    entry->key = g_ref_string_acquire(key);
851
2.47k
    g_ptr_array_add(self->items, entry);
852
2.47k
  }
853
3.64k
  entry->json_node = fwupd_json_node_new_object(json_obj);
854
3.64k
}
855
856
/**
857
 * fwupd_json_object_add_object:
858
 * @self: a #FwupdJsonObject
859
 * @key: (not nullable): dictionary key
860
 * @json_obj: a #FwupdJsonObject
861
 *
862
 * Adds a different object to the JSON object.
863
 *
864
 * Since: 2.1.1
865
 **/
866
void
867
fwupd_json_object_add_object(FwupdJsonObject *self, const gchar *key, FwupdJsonObject *json_obj)
868
0
{
869
0
  g_autoptr(FwupdJsonNode) json_node = NULL;
870
871
0
  g_return_if_fail(self != NULL);
872
0
  g_return_if_fail(key != NULL);
873
0
  g_return_if_fail(json_obj != NULL);
874
0
  g_return_if_fail(self != json_obj);
875
876
0
  json_node = fwupd_json_node_new_object(json_obj);
877
0
  fwupd_json_object_add_node(self, key, json_node);
878
0
}
879
880
/**
881
 * fwupd_json_object_add_object_map:
882
 * @self: a #FwupdJsonObject
883
 * @key: (not nullable): dictionary key
884
 * @value: (element-type utf8 utf8): a hash table
885
 *
886
 * Adds a  object to the JSON object.
887
 *
888
 * Since: 2.1.1
889
 **/
890
void
891
fwupd_json_object_add_object_map(FwupdJsonObject *self, const gchar *key, GHashTable *value)
892
0
{
893
0
  GHashTableIter iter;
894
0
  gpointer hash_key, hash_value;
895
0
  g_autoptr(FwupdJsonObject) json_obj = fwupd_json_object_new();
896
897
0
  g_return_if_fail(self != NULL);
898
0
  g_return_if_fail(key != NULL);
899
0
  g_return_if_fail(value != NULL);
900
901
0
  g_hash_table_iter_init(&iter, value);
902
0
  while (g_hash_table_iter_next(&iter, &hash_key, &hash_value)) {
903
0
    fwupd_json_object_add_string(json_obj,
904
0
               (const gchar *)hash_key,
905
0
               (const gchar *)hash_value);
906
0
  }
907
0
  fwupd_json_object_add_object(self, key, json_obj);
908
0
}
909
910
void
911
fwupd_json_object_add_array_internal(FwupdJsonObject *self,
912
             GRefString *key,
913
             FwupdJsonArray *json_arr)
914
2.19k
{
915
2.19k
  FwupdJsonObjectEntry *entry = fwupd_json_object_get_entry(self, key, NULL);
916
2.19k
  if (entry != NULL) {
917
621
    fwupd_json_node_unref(entry->json_node);
918
1.57k
  } else {
919
1.57k
    entry = g_new0(FwupdJsonObjectEntry, 1);
920
1.57k
    entry->key = g_ref_string_acquire(key);
921
1.57k
    g_ptr_array_add(self->items, entry);
922
1.57k
  }
923
2.19k
  entry->json_node = fwupd_json_node_new_array(json_arr);
924
2.19k
}
925
926
/**
927
 * fwupd_json_object_add_array:
928
 * @self: a #FwupdJsonObject
929
 * @key: (not nullable): dictionary key
930
 * @json_arr: a #FwupdJsonArray
931
 *
932
 * Adds an array to the JSON object.
933
 *
934
 * Since: 2.1.1
935
 **/
936
void
937
fwupd_json_object_add_array(FwupdJsonObject *self, const gchar *key, FwupdJsonArray *json_arr)
938
0
{
939
0
  g_autoptr(FwupdJsonNode) json_node = NULL;
940
941
0
  g_return_if_fail(self != NULL);
942
0
  g_return_if_fail(key != NULL);
943
0
  g_return_if_fail(json_arr != NULL);
944
945
0
  json_node = fwupd_json_node_new_array(json_arr);
946
0
  fwupd_json_object_add_node(self, key, json_node);
947
0
}
948
949
/**
950
 * fwupd_json_object_append_string:
951
 * @self: a #FwupdJsonObject
952
 * @str: a #GString
953
 * @depth: depth, where 0 is the root node
954
 * @flags: some #FwupdJsonExportFlags e.g. #FWUPD_JSON_EXPORT_FLAG_INDENT
955
 *
956
 * Appends the JSON object to existing string.
957
 *
958
 * Since: 2.1.1
959
 **/
960
void
961
fwupd_json_object_append_string(FwupdJsonObject *self,
962
        GString *str,
963
        guint depth,
964
        FwupdJsonExportFlags flags)
965
4.46k
{
966
4.46k
  g_return_if_fail(self != NULL);
967
4.46k
  g_return_if_fail(str != NULL);
968
969
  /* start */
970
4.46k
  g_string_append_c(str, '{');
971
4.46k
  if (flags & FWUPD_JSON_EXPORT_FLAG_INDENT)
972
0
    g_string_append_c(str, '\n');
973
974
7.73k
  for (guint i = 0; i < self->items->len; i++) {
975
3.26k
    FwupdJsonObjectEntry *entry = g_ptr_array_index(self->items, i);
976
977
3.26k
    if (flags & FWUPD_JSON_EXPORT_FLAG_INDENT)
978
0
      fwupd_json_indent(str, depth + 1);
979
3.26k
    g_string_append_printf(str, "\"%s\": ", entry->key);
980
3.26k
    fwupd_json_node_append_string(entry->json_node, str, depth + 1, flags);
981
3.26k
    if (flags & FWUPD_JSON_EXPORT_FLAG_INDENT) {
982
0
      if (i != self->items->len - 1)
983
0
        g_string_append_c(str, ',');
984
0
      g_string_append_c(str, '\n');
985
3.26k
    } else {
986
3.26k
      if (i != self->items->len - 1)
987
1.05k
        g_string_append(str, ", ");
988
3.26k
    }
989
3.26k
  }
990
991
  /* end */
992
4.46k
  if (flags & FWUPD_JSON_EXPORT_FLAG_INDENT)
993
0
    fwupd_json_indent(str, depth);
994
4.46k
  g_string_append_c(str, '}');
995
4.46k
}
996
997
/**
998
 * fwupd_json_object_to_string:
999
 * @self: a #FwupdJsonObject
1000
 * @flags: some #FwupdJsonExportFlags e.g. #FWUPD_JSON_EXPORT_FLAG_INDENT
1001
 *
1002
 * Converts the JSON object to a string representation.
1003
 *
1004
 * Returns: (transfer full): a #GString
1005
 *
1006
 * Since: 2.1.1
1007
 **/
1008
GString *
1009
fwupd_json_object_to_string(FwupdJsonObject *self, FwupdJsonExportFlags flags)
1010
0
{
1011
0
  GString *str = g_string_new(NULL);
1012
0
  fwupd_json_object_append_string(self, str, 0, flags);
1013
0
  if (flags & FWUPD_JSON_EXPORT_FLAG_TRAILING_NEWLINE)
1014
0
    g_string_append_c(str, '\n');
1015
0
  return str;
1016
0
}
1017
1018
/**
1019
 * fwupd_json_object_to_bytes:
1020
 * @self: a #FwupdJsonObject
1021
 * @flags: some #FwupdJsonExportFlags e.g. #FWUPD_JSON_EXPORT_FLAG_INDENT
1022
 *
1023
 * Converts the JSON object to UTF-8 bytes.
1024
 *
1025
 * Returns: (transfer full): a #GBytes
1026
 *
1027
 * Since: 2.1.1
1028
 **/
1029
GBytes *
1030
fwupd_json_object_to_bytes(FwupdJsonObject *self, FwupdJsonExportFlags flags)
1031
0
{
1032
0
  GString *str = g_string_new(NULL);
1033
0
  fwupd_json_object_append_string(self, str, 0, flags);
1034
0
  if (flags & FWUPD_JSON_EXPORT_FLAG_TRAILING_NEWLINE)
1035
0
    g_string_append_c(str, '\n');
1036
0
  return g_string_free_to_bytes(str);
1037
0
}