/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 | } |