/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.19k | { |
36 | 9.19k | g_ref_string_release(entry->key); |
37 | 9.19k | fwupd_json_node_unref(entry->json_node); |
38 | 9.19k | g_free(entry); |
39 | 9.19k | } |
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 | 9.74k | { |
53 | 9.74k | FwupdJsonObject *self = g_new0(FwupdJsonObject, 1); |
54 | 9.74k | g_ref_count_init(&self->refcount); |
55 | 9.74k | self->items = g_ptr_array_new_with_free_func((GDestroyNotify)fwupd_json_object_entry_free); |
56 | 9.74k | return self; |
57 | 9.74k | } |
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 | 12.9k | { |
72 | 12.9k | g_return_val_if_fail(self != NULL, NULL); |
73 | 12.9k | g_ref_count_inc(&self->refcount); |
74 | 12.9k | return self; |
75 | 12.9k | } |
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 | 22.7k | { |
90 | 22.7k | g_return_val_if_fail(self != NULL, NULL); |
91 | 22.7k | if (!g_ref_count_dec(&self->refcount)) |
92 | 12.9k | return self; |
93 | 9.74k | g_ptr_array_unref(self->items); |
94 | 9.74k | g_free(self); |
95 | 9.74k | return NULL; |
96 | 22.7k | } |
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.2k | { |
126 | 12.2k | g_return_val_if_fail(self != NULL, G_MAXUINT); |
127 | 12.2k | return self->items->len; |
128 | 12.2k | } |
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.2k | { |
203 | 26.0k | for (guint i = 0; i < self->items->len; i++) { |
204 | 16.8k | FwupdJsonObjectEntry *entry = g_ptr_array_index(self->items, i); |
205 | 16.8k | if (g_strcmp0(key, entry->key) == 0) |
206 | 3.08k | return entry; |
207 | 16.8k | } |
208 | 9.19k | g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no json_node for key %s", key); |
209 | 9.19k | return NULL; |
210 | 12.2k | } |
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.26k | { |
656 | 4.26k | FwupdJsonObjectEntry *entry = NULL; |
657 | | |
658 | 4.26k | if ((flags & FWUPD_JSON_LOAD_FLAG_TRUSTED) == 0) |
659 | 4.26k | entry = fwupd_json_object_get_entry(self, key, NULL); |
660 | 4.26k | if (entry != NULL) { |
661 | 459 | fwupd_json_node_unref(entry->json_node); |
662 | 3.80k | } else { |
663 | 3.80k | entry = g_new0(FwupdJsonObjectEntry, 1); |
664 | 3.80k | entry->key = (flags & FWUPD_JSON_LOAD_FLAG_STATIC_KEYS) > 0 |
665 | 3.80k | ? g_ref_string_new_intern(key) |
666 | 3.80k | : g_ref_string_acquire(key); |
667 | 3.80k | g_ptr_array_add(self->items, entry); |
668 | 3.80k | } |
669 | 4.26k | entry->json_node = fwupd_json_node_new_raw_internal(value); |
670 | 4.26k | } |
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.20k | { |
731 | 2.20k | FwupdJsonObjectEntry *entry = NULL; |
732 | | |
733 | 2.20k | if ((flags & FWUPD_JSON_LOAD_FLAG_TRUSTED) == 0) |
734 | 2.20k | entry = fwupd_json_object_get_entry(self, key, NULL); |
735 | 2.20k | if (entry != NULL) { |
736 | 828 | 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.20k | entry->json_node = fwupd_json_node_new_string_internal(value); |
745 | 2.20k | } |
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.58k | { |
845 | 3.58k | FwupdJsonObjectEntry *entry = fwupd_json_object_get_entry(self, key, NULL); |
846 | 3.58k | if (entry != NULL) { |
847 | 1.17k | fwupd_json_node_unref(entry->json_node); |
848 | 2.41k | } else { |
849 | 2.41k | entry = g_new0(FwupdJsonObjectEntry, 1); |
850 | 2.41k | entry->key = g_ref_string_acquire(key); |
851 | 2.41k | g_ptr_array_add(self->items, entry); |
852 | 2.41k | } |
853 | 3.58k | entry->json_node = fwupd_json_node_new_object(json_obj); |
854 | 3.58k | } |
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.23k | { |
915 | 2.23k | FwupdJsonObjectEntry *entry = fwupd_json_object_get_entry(self, key, NULL); |
916 | 2.23k | if (entry != NULL) { |
917 | 626 | fwupd_json_node_unref(entry->json_node); |
918 | 1.60k | } else { |
919 | 1.60k | entry = g_new0(FwupdJsonObjectEntry, 1); |
920 | 1.60k | entry->key = g_ref_string_acquire(key); |
921 | 1.60k | g_ptr_array_add(self->items, entry); |
922 | 1.60k | } |
923 | 2.23k | entry->json_node = fwupd_json_node_new_array(json_arr); |
924 | 2.23k | } |
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.12k | { |
966 | 4.12k | g_return_if_fail(self != NULL); |
967 | 4.12k | g_return_if_fail(str != NULL); |
968 | | |
969 | | /* start */ |
970 | 4.12k | g_string_append_c(str, '{'); |
971 | 4.12k | if (flags & FWUPD_JSON_EXPORT_FLAG_INDENT) |
972 | 0 | g_string_append_c(str, '\n'); |
973 | | |
974 | 7.14k | for (guint i = 0; i < self->items->len; i++) { |
975 | 3.02k | FwupdJsonObjectEntry *entry = g_ptr_array_index(self->items, i); |
976 | | |
977 | 3.02k | if (flags & FWUPD_JSON_EXPORT_FLAG_INDENT) |
978 | 0 | fwupd_json_indent(str, depth + 1); |
979 | 3.02k | g_string_append_printf(str, "\"%s\": ", entry->key); |
980 | 3.02k | fwupd_json_node_append_string(entry->json_node, str, depth + 1, flags); |
981 | 3.02k | 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.02k | } else { |
986 | 3.02k | if (i != self->items->len - 1) |
987 | 1.08k | g_string_append(str, ", "); |
988 | 3.02k | } |
989 | 3.02k | } |
990 | | |
991 | | /* end */ |
992 | 4.12k | if (flags & FWUPD_JSON_EXPORT_FLAG_INDENT) |
993 | 0 | fwupd_json_indent(str, depth); |
994 | 4.12k | g_string_append_c(str, '}'); |
995 | 4.12k | } |
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 | } |