/src/fwupd/libfwupdplugin/fu-device-event.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 | 0 | #define G_LOG_DOMAIN "FuDeviceEvent" |
8 | | |
9 | | #include "config.h" |
10 | | |
11 | | #include "fu-device-event-private.h" |
12 | | #include "fu-mem.h" |
13 | | #include "fu-string.h" |
14 | | |
15 | | /** |
16 | | * FuDeviceEvent: |
17 | | * |
18 | | * A device event, used to enumulate hardware. |
19 | | * |
20 | | * See also: [class@FuDevice] |
21 | | */ |
22 | | |
23 | | typedef struct { |
24 | | GType gtype; |
25 | | GRefString *key; |
26 | | gpointer data; |
27 | | GDestroyNotify data_destroy; |
28 | | } FuDeviceEventBlob; |
29 | | |
30 | | struct _FuDeviceEvent { |
31 | | GObject parent_instance; |
32 | | gchar *id; |
33 | | gchar *id_uncompressed; |
34 | | GPtrArray *values; /* element-type FuDeviceEventBlob */ |
35 | | }; |
36 | | |
37 | | static void |
38 | | fu_device_event_codec_iface_init(FwupdCodecInterface *iface); |
39 | | |
40 | 0 | G_DEFINE_TYPE_WITH_CODE(FuDeviceEvent, |
41 | 0 | fu_device_event, |
42 | 0 | G_TYPE_OBJECT, |
43 | 0 | G_IMPLEMENT_INTERFACE(FWUPD_TYPE_CODEC, fu_device_event_codec_iface_init)) |
44 | 0 |
|
45 | 0 | /* |
46 | 0 | * NOTE: We use an event *counter* that gets the next event in the emulation, and this ID is only |
47 | 0 | * used as a sanity check in case we have to skip an entry. |
48 | 0 | */ |
49 | 0 | #define FU_DEVICE_EVENT_KEY_HASH_PREFIX_SIZE 8 |
50 | | |
51 | | static void |
52 | | fu_device_event_blob_free(FuDeviceEventBlob *blob) |
53 | 0 | { |
54 | 0 | g_ref_string_release(blob->key); |
55 | 0 | if (blob->data_destroy != NULL) |
56 | 0 | blob->data_destroy(blob->data); |
57 | 0 | g_free(blob); |
58 | 0 | } |
59 | | |
60 | | static FuDeviceEventBlob * |
61 | | fu_device_event_blob_new_internal(GType gtype, |
62 | | GRefString *key, |
63 | | gpointer data, |
64 | | GDestroyNotify data_destroy) |
65 | 0 | { |
66 | 0 | FuDeviceEventBlob *blob = g_new0(FuDeviceEventBlob, 1); |
67 | 0 | blob->key = g_ref_string_acquire(key); |
68 | 0 | blob->gtype = gtype; |
69 | 0 | blob->data = data; |
70 | 0 | blob->data_destroy = data_destroy; |
71 | 0 | return blob; |
72 | 0 | } |
73 | | |
74 | | static FuDeviceEventBlob * |
75 | | fu_device_event_blob_new(GType gtype, const gchar *key, gpointer data, GDestroyNotify data_destroy) |
76 | 0 | { |
77 | 0 | g_autoptr(GRefString) key_ref = NULL; |
78 | 0 | const gchar *known_keys[] = { |
79 | 0 | "Data", |
80 | 0 | "DataOut", |
81 | 0 | "Error", |
82 | 0 | "ErrorMsg", |
83 | 0 | "Rc", |
84 | 0 | NULL, |
85 | 0 | }; |
86 | 0 | key_ref = g_strv_contains(known_keys, key) ? g_ref_string_new_intern(key) |
87 | 0 | : g_ref_string_new(key); |
88 | 0 | return fu_device_event_blob_new_internal(gtype, key_ref, data, data_destroy); |
89 | 0 | } |
90 | | |
91 | | /** |
92 | | * fu_device_event_build_id: |
93 | | * @id: a string |
94 | | * |
95 | | * Return the hash of the event ID. |
96 | | * |
97 | | * Returns: string hash prefix |
98 | | * |
99 | | * Since: 2.0.3 |
100 | | **/ |
101 | | gchar * |
102 | | fu_device_event_build_id(const gchar *id) |
103 | 0 | { |
104 | 0 | guint8 buf[20] = {0}; |
105 | 0 | gsize bufsz = sizeof(buf); |
106 | 0 | g_autoptr(GChecksum) csum = g_checksum_new(G_CHECKSUM_SHA1); |
107 | 0 | g_autoptr(GString) id_hash = g_string_sized_new(FU_DEVICE_EVENT_KEY_HASH_PREFIX_SIZE + 1); |
108 | |
|
109 | 0 | g_return_val_if_fail(id != NULL, NULL); |
110 | | |
111 | | /* IMPORTANT: if you're reading this we're not using the SHA1 prefix for any kind of secure |
112 | | * hash, just because it is a tiny string that takes up less memory than the full ID. */ |
113 | 0 | g_checksum_update(csum, (const guchar *)id, strlen(id)); |
114 | 0 | g_checksum_get_digest(csum, buf, &bufsz); |
115 | 0 | g_string_append_c(id_hash, '#'); |
116 | 0 | for (guint i = 0; i < FU_DEVICE_EVENT_KEY_HASH_PREFIX_SIZE / 2; i++) |
117 | 0 | g_string_append_printf(id_hash, "%02x", buf[i]); |
118 | 0 | return g_string_free(g_steal_pointer(&id_hash), FALSE); |
119 | 0 | } |
120 | | |
121 | | /** |
122 | | * fu_device_event_get_id: |
123 | | * @self: a #FuDeviceEvent |
124 | | * |
125 | | * Return the truncated SHA1 of the #FuDeviceEvent key, which is normally set when creating the |
126 | | * object. |
127 | | * |
128 | | * Returns: (nullable): string |
129 | | * |
130 | | * Since: 2.0.0 |
131 | | **/ |
132 | | const gchar * |
133 | | fu_device_event_get_id(FuDeviceEvent *self) |
134 | 0 | { |
135 | 0 | g_return_val_if_fail(FU_IS_DEVICE_EVENT(self), NULL); |
136 | 0 | return self->id; |
137 | 0 | } |
138 | | |
139 | | /** |
140 | | * fu_device_event_set_str: |
141 | | * @self: a #FuDeviceEvent |
142 | | * @key: (not nullable): a unique key, e.g. `Name` |
143 | | * @value: (nullable): a string |
144 | | * |
145 | | * Sets a string value on the event. |
146 | | * |
147 | | * Since: 2.0.0 |
148 | | **/ |
149 | | void |
150 | | fu_device_event_set_str(FuDeviceEvent *self, const gchar *key, const gchar *value) |
151 | 0 | { |
152 | 0 | g_return_if_fail(FU_IS_DEVICE_EVENT(self)); |
153 | 0 | g_return_if_fail(key != NULL); |
154 | 0 | g_ptr_array_add(self->values, |
155 | 0 | fu_device_event_blob_new(G_TYPE_STRING, key, g_strdup(value), g_free)); |
156 | 0 | } |
157 | | |
158 | | /** |
159 | | * fu_device_event_set_i64: |
160 | | * @self: a #FuDeviceEvent |
161 | | * @key: (not nullable): a unique key, e.g. `Name` |
162 | | * @value: a string |
163 | | * |
164 | | * Sets an integer value on the string. |
165 | | * |
166 | | * Since: 2.0.0 |
167 | | **/ |
168 | | void |
169 | | fu_device_event_set_i64(FuDeviceEvent *self, const gchar *key, gint64 value) |
170 | 0 | { |
171 | 0 | g_return_if_fail(FU_IS_DEVICE_EVENT(self)); |
172 | 0 | g_return_if_fail(key != NULL); |
173 | | |
174 | 0 | g_ptr_array_add( |
175 | 0 | self->values, |
176 | 0 | fu_device_event_blob_new(G_TYPE_INT, key, g_memdup2(&value, sizeof(value)), g_free)); |
177 | 0 | } |
178 | | |
179 | | /** |
180 | | * fu_device_event_set_bytes: |
181 | | * @self: a #FuDeviceEvent |
182 | | * @key: (not nullable): a unique key, e.g. `Name` |
183 | | * @value: (not nullable): a #GBytes |
184 | | * |
185 | | * Sets a blob on the event. Note: blobs are stored internally as BASE-64 strings. |
186 | | * |
187 | | * Since: 2.0.0 |
188 | | **/ |
189 | | void |
190 | | fu_device_event_set_bytes(FuDeviceEvent *self, const gchar *key, GBytes *value) |
191 | 0 | { |
192 | 0 | g_return_if_fail(FU_IS_DEVICE_EVENT(self)); |
193 | 0 | g_return_if_fail(key != NULL); |
194 | 0 | g_return_if_fail(value != NULL); |
195 | 0 | g_ptr_array_add(self->values, |
196 | 0 | fu_device_event_blob_new( |
197 | 0 | G_TYPE_STRING, |
198 | 0 | key, |
199 | 0 | g_base64_encode(g_bytes_get_data(value, NULL), g_bytes_get_size(value)), |
200 | 0 | g_free)); |
201 | 0 | } |
202 | | |
203 | | /** |
204 | | * fu_device_event_set_data: |
205 | | * @self: a #FuDeviceEvent |
206 | | * @key: (not nullable): a unique key, e.g. `Name` |
207 | | * @buf: (nullable): a buffer |
208 | | * @bufsz: size of @buf |
209 | | * |
210 | | * Sets a memory buffer on the event. Note: memory buffers are stored internally as BASE-64 strings. |
211 | | * |
212 | | * Since: 2.0.0 |
213 | | **/ |
214 | | void |
215 | | fu_device_event_set_data(FuDeviceEvent *self, const gchar *key, const guint8 *buf, gsize bufsz) |
216 | 0 | { |
217 | 0 | g_return_if_fail(FU_IS_DEVICE_EVENT(self)); |
218 | 0 | g_return_if_fail(key != NULL); |
219 | 0 | g_ptr_array_add( |
220 | 0 | self->values, |
221 | 0 | fu_device_event_blob_new(G_TYPE_STRING, key, g_base64_encode(buf, bufsz), g_free)); |
222 | 0 | } |
223 | | |
224 | | /** |
225 | | * fu_device_event_set_error: |
226 | | * @self: a #FuDeviceEvent |
227 | | * @error: (not nullable): a #GError with domain #FwupdError |
228 | | * |
229 | | * Sets an error on the event. |
230 | | * |
231 | | * Since: 2.0.6 |
232 | | **/ |
233 | | void |
234 | | fu_device_event_set_error(FuDeviceEvent *self, const GError *error) |
235 | 0 | { |
236 | 0 | g_return_if_fail(FU_IS_DEVICE_EVENT(self)); |
237 | 0 | g_return_if_fail(error != NULL); |
238 | 0 | g_return_if_fail(error->domain == FWUPD_ERROR); |
239 | 0 | fu_device_event_set_i64(self, "Error", error->code); |
240 | 0 | fu_device_event_set_str(self, "ErrorMsg", error->message); |
241 | 0 | } |
242 | | |
243 | | /** |
244 | | * fu_device_event_check_error: |
245 | | * @self: a #FuDeviceEvent |
246 | | * @error: (nullable): optional return location for an error |
247 | | * |
248 | | * Sets an error from the event if possible. |
249 | | * |
250 | | * Returns: %FALSE if @error was set |
251 | | * |
252 | | * Since: 2.0.6 |
253 | | **/ |
254 | | gboolean |
255 | | fu_device_event_check_error(FuDeviceEvent *self, GError **error) |
256 | 0 | { |
257 | 0 | gint64 code; |
258 | 0 | const gchar *message; |
259 | |
|
260 | 0 | g_return_val_if_fail(FU_IS_DEVICE_EVENT(self), FALSE); |
261 | | |
262 | | /* nothing to do */ |
263 | 0 | if (error == NULL) |
264 | 0 | return TRUE; |
265 | | |
266 | | /* anything set */ |
267 | 0 | code = fu_device_event_get_i64(self, "Error", NULL); |
268 | 0 | if (code == G_MAXINT64) |
269 | 0 | return TRUE; |
270 | 0 | message = fu_device_event_get_str(self, "ErrorMsg", NULL); |
271 | 0 | if (message == NULL) |
272 | 0 | message = fwupd_error_to_string(code); |
273 | | |
274 | | /* success, in a way */ |
275 | 0 | g_set_error_literal(error, FWUPD_ERROR, code, message); |
276 | 0 | return FALSE; |
277 | 0 | } |
278 | | |
279 | | static gpointer |
280 | | fu_device_event_lookup(FuDeviceEvent *self, const gchar *key, GType gtype, GError **error) |
281 | 0 | { |
282 | 0 | FuDeviceEventBlob *blob = NULL; |
283 | |
|
284 | 0 | for (guint i = 0; i < self->values->len; i++) { |
285 | 0 | FuDeviceEventBlob *blob_tmp = g_ptr_array_index(self->values, i); |
286 | 0 | if (g_strcmp0(blob_tmp->key, key) == 0) { |
287 | 0 | blob = blob_tmp; |
288 | 0 | break; |
289 | 0 | } |
290 | 0 | } |
291 | 0 | if (blob == NULL) { |
292 | 0 | g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no event for key %s", key); |
293 | 0 | return NULL; |
294 | 0 | } |
295 | 0 | if (blob->gtype != gtype) { |
296 | 0 | g_set_error(error, |
297 | 0 | FWUPD_ERROR, |
298 | 0 | FWUPD_ERROR_INVALID_DATA, |
299 | 0 | "invalid event type for key %s", |
300 | 0 | key); |
301 | 0 | return NULL; |
302 | 0 | } |
303 | 0 | return blob->data; |
304 | 0 | } |
305 | | |
306 | | /** |
307 | | * fu_device_event_get_str: |
308 | | * @self: a #FuDeviceEvent |
309 | | * @key: (not nullable): a unique key, e.g. `Name` |
310 | | * @error: (nullable): optional return location for an error |
311 | | * |
312 | | * Gets a string value from the event. |
313 | | * |
314 | | * Returns: (nullable): string, or %NULL on error |
315 | | * |
316 | | * Since: 2.0.0 |
317 | | **/ |
318 | | const gchar * |
319 | | fu_device_event_get_str(FuDeviceEvent *self, const gchar *key, GError **error) |
320 | 0 | { |
321 | 0 | g_return_val_if_fail(FU_IS_DEVICE_EVENT(self), NULL); |
322 | 0 | g_return_val_if_fail(key != NULL, NULL); |
323 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, NULL); |
324 | 0 | return (const gchar *)fu_device_event_lookup(self, key, G_TYPE_STRING, error); |
325 | 0 | } |
326 | | |
327 | | /** |
328 | | * fu_device_event_get_i64: |
329 | | * @self: a #FuDeviceEvent |
330 | | * @key: (not nullable): a unique key, e.g. `Name` |
331 | | * @error: (nullable): optional return location for an error |
332 | | * |
333 | | * Gets an integer value from the event. |
334 | | * |
335 | | * Returns: integer, or %G_MAXINT64 on error |
336 | | * |
337 | | * Since: 2.0.0 |
338 | | **/ |
339 | | gint64 |
340 | | fu_device_event_get_i64(FuDeviceEvent *self, const gchar *key, GError **error) |
341 | 0 | { |
342 | 0 | gint64 *val; |
343 | 0 | g_return_val_if_fail(FU_IS_DEVICE_EVENT(self), G_MAXINT64); |
344 | 0 | g_return_val_if_fail(key != NULL, G_MAXINT64); |
345 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, G_MAXINT64); |
346 | 0 | val = fu_device_event_lookup(self, key, G_TYPE_INT, error); |
347 | 0 | if (val == NULL) |
348 | 0 | return G_MAXINT64; |
349 | 0 | return *val; |
350 | 0 | } |
351 | | |
352 | | /** |
353 | | * fu_device_event_get_bytes: |
354 | | * @self: a #FuDeviceEvent |
355 | | * @key: (not nullable): a unique key, e.g. `Name` |
356 | | * @error: (nullable): optional return location for an error |
357 | | * |
358 | | * Gets a memory blob from the event. |
359 | | * |
360 | | * Returns: (transfer full) (nullable): byes data, or %NULL on error |
361 | | * |
362 | | * Since: 2.0.0 |
363 | | **/ |
364 | | GBytes * |
365 | | fu_device_event_get_bytes(FuDeviceEvent *self, const gchar *key, GError **error) |
366 | 0 | { |
367 | 0 | const gchar *blobstr; |
368 | 0 | gsize bufsz = 0; |
369 | 0 | g_autofree guchar *buf = NULL; |
370 | |
|
371 | 0 | g_return_val_if_fail(FU_IS_DEVICE_EVENT(self), NULL); |
372 | 0 | g_return_val_if_fail(key != NULL, NULL); |
373 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, NULL); |
374 | | |
375 | 0 | blobstr = fu_device_event_lookup(self, key, G_TYPE_STRING, error); |
376 | 0 | if (blobstr == NULL) |
377 | 0 | return NULL; |
378 | 0 | if (blobstr[0] == '\0') |
379 | 0 | return g_bytes_new(NULL, 0); |
380 | 0 | buf = g_base64_decode(blobstr, &bufsz); |
381 | 0 | return g_bytes_new_take(g_steal_pointer(&buf), bufsz); |
382 | 0 | } |
383 | | |
384 | | /** |
385 | | * fu_device_event_copy_data: |
386 | | * @self: a #FuDeviceEvent |
387 | | * @key: (not nullable): a unique key, e.g. `Name` |
388 | | * @buf: (nullable): a buffer |
389 | | * @bufsz: size of @buf |
390 | | * @actual_length: (out) (optional): the actual number of bytes sent, or %NULL |
391 | | * @error: (nullable): optional return location for an error |
392 | | * |
393 | | * Copies memory from the event. |
394 | | * |
395 | | * Returns: %TRUE if the buffer was copied |
396 | | * |
397 | | * Since: 2.0.0 |
398 | | **/ |
399 | | gboolean |
400 | | fu_device_event_copy_data(FuDeviceEvent *self, |
401 | | const gchar *key, |
402 | | guint8 *buf, |
403 | | gsize bufsz, |
404 | | gsize *actual_length, |
405 | | GError **error) |
406 | 0 | { |
407 | 0 | const gchar *blobstr; |
408 | 0 | gsize bufsz_src = 0; |
409 | 0 | g_autofree guchar *buf_src = NULL; |
410 | |
|
411 | 0 | g_return_val_if_fail(FU_IS_DEVICE_EVENT(self), FALSE); |
412 | 0 | g_return_val_if_fail(key != NULL, FALSE); |
413 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, FALSE); |
414 | | |
415 | 0 | blobstr = fu_device_event_lookup(self, key, G_TYPE_STRING, error); |
416 | 0 | if (blobstr == NULL) |
417 | 0 | return FALSE; |
418 | 0 | buf_src = g_base64_decode(blobstr, &bufsz_src); |
419 | 0 | if (actual_length != NULL) |
420 | 0 | *actual_length = bufsz_src; |
421 | 0 | if (buf != NULL) |
422 | 0 | return fu_memcpy_safe(buf, bufsz, 0x0, buf_src, bufsz_src, 0x0, bufsz_src, error); |
423 | 0 | return TRUE; |
424 | 0 | } |
425 | | |
426 | | static void |
427 | | fu_device_event_add_json(FwupdCodec *codec, FwupdJsonObject *json_obj, FwupdCodecFlags flags) |
428 | 0 | { |
429 | 0 | FuDeviceEvent *self = FU_DEVICE_EVENT(codec); |
430 | |
|
431 | 0 | if (self->id_uncompressed != NULL && (flags & FWUPD_CODEC_FLAG_COMPRESSED) == 0) { |
432 | 0 | fwupd_json_object_add_string(json_obj, "Id", self->id_uncompressed); |
433 | 0 | } else if (self->id != NULL) { |
434 | 0 | fwupd_json_object_add_string(json_obj, "Id", self->id); |
435 | 0 | } |
436 | |
|
437 | 0 | for (guint i = 0; i < self->values->len; i++) { |
438 | 0 | FuDeviceEventBlob *blob = g_ptr_array_index(self->values, i); |
439 | 0 | if (blob->gtype == G_TYPE_INT) { |
440 | 0 | fwupd_json_object_add_integer(json_obj, blob->key, *((gint64 *)blob->data)); |
441 | 0 | } else if (blob->gtype == G_TYPE_BYTES || blob->gtype == G_TYPE_STRING) { |
442 | 0 | fwupd_json_object_add_string(json_obj, |
443 | 0 | blob->key, |
444 | 0 | (const gchar *)blob->data); |
445 | 0 | } else { |
446 | 0 | g_warning("invalid GType %s, ignoring", g_type_name(blob->gtype)); |
447 | 0 | } |
448 | 0 | } |
449 | 0 | } |
450 | | |
451 | | static void |
452 | | fu_device_event_set_id(FuDeviceEvent *self, const gchar *id) |
453 | 0 | { |
454 | 0 | g_return_if_fail(FU_IS_DEVICE_EVENT(self)); |
455 | 0 | g_return_if_fail(id != NULL); |
456 | | |
457 | 0 | g_clear_pointer(&self->id, g_free); |
458 | 0 | g_clear_pointer(&self->id_uncompressed, g_free); |
459 | | |
460 | | /* already a truncated SHA1 hash? */ |
461 | 0 | if (g_str_has_prefix(id, "#")) { |
462 | 0 | self->id = g_strdup(id); |
463 | 0 | } else { |
464 | 0 | self->id_uncompressed = g_strdup(id); |
465 | 0 | self->id = fu_device_event_build_id(id); |
466 | 0 | } |
467 | 0 | } |
468 | | |
469 | | static gboolean |
470 | | fu_device_event_from_json(FwupdCodec *codec, FwupdJsonObject *json_obj, GError **error) |
471 | 0 | { |
472 | 0 | FuDeviceEvent *self = FU_DEVICE_EVENT(codec); |
473 | 0 | for (guint i = 0; i < fwupd_json_object_get_size(json_obj); i++) { |
474 | 0 | GRefString *key = fwupd_json_object_get_key_for_index(json_obj, i, NULL); |
475 | 0 | g_autoptr(FwupdJsonNode) json_node = NULL; |
476 | |
|
477 | 0 | json_node = fwupd_json_object_get_node_for_index(json_obj, i, error); |
478 | 0 | if (json_node == NULL) |
479 | 0 | return FALSE; |
480 | 0 | if (fwupd_json_node_get_kind(json_node) == FWUPD_JSON_NODE_KIND_STRING) { |
481 | 0 | GRefString *str = fwupd_json_node_get_string(json_node, NULL); |
482 | 0 | if (g_strcmp0(key, "Id") == 0) { |
483 | 0 | fu_device_event_set_id(self, str); |
484 | 0 | } else if (str != NULL) { |
485 | 0 | g_ptr_array_add(self->values, |
486 | 0 | fu_device_event_blob_new_internal( |
487 | 0 | G_TYPE_STRING, |
488 | 0 | key, |
489 | 0 | g_ref_string_acquire(str), |
490 | 0 | (GDestroyNotify)g_ref_string_release)); |
491 | 0 | } else { |
492 | 0 | g_ptr_array_add(self->values, |
493 | 0 | fu_device_event_blob_new_internal(G_TYPE_STRING, |
494 | 0 | key, |
495 | 0 | NULL, |
496 | 0 | NULL)); |
497 | 0 | } |
498 | 0 | } else if (fwupd_json_node_get_kind(json_node) == FWUPD_JSON_NODE_KIND_RAW) { |
499 | 0 | GRefString *str; |
500 | 0 | gint64 value = 0; |
501 | |
|
502 | 0 | str = fwupd_json_node_get_raw(json_node, error); |
503 | 0 | if (str == NULL) |
504 | 0 | return FALSE; |
505 | 0 | if (!fu_strtoll(str, |
506 | 0 | &value, |
507 | 0 | G_MININT64, |
508 | 0 | G_MAXINT64, |
509 | 0 | FU_INTEGER_BASE_AUTO, |
510 | 0 | error)) |
511 | 0 | return FALSE; |
512 | 0 | g_ptr_array_add( |
513 | 0 | self->values, |
514 | 0 | fu_device_event_blob_new_internal(G_TYPE_INT, |
515 | 0 | key, |
516 | 0 | g_memdup2(&value, sizeof(value)), |
517 | 0 | g_free)); |
518 | 0 | } |
519 | 0 | } |
520 | | |
521 | | /* we do not need this again, so avoid keeping all the tree data in memory */ |
522 | 0 | fwupd_json_object_clear(json_obj); |
523 | | |
524 | | /* success */ |
525 | 0 | return TRUE; |
526 | 0 | } |
527 | | |
528 | | static void |
529 | | fu_device_event_init(FuDeviceEvent *self) |
530 | 0 | { |
531 | 0 | self->values = g_ptr_array_new_with_free_func((GDestroyNotify)fu_device_event_blob_free); |
532 | 0 | } |
533 | | |
534 | | static void |
535 | | fu_device_event_finalize(GObject *object) |
536 | 0 | { |
537 | 0 | FuDeviceEvent *self = FU_DEVICE_EVENT(object); |
538 | 0 | g_free(self->id); |
539 | 0 | g_free(self->id_uncompressed); |
540 | 0 | g_ptr_array_unref(self->values); |
541 | 0 | G_OBJECT_CLASS(fu_device_event_parent_class)->finalize(object); |
542 | 0 | } |
543 | | |
544 | | static void |
545 | | fu_device_event_class_init(FuDeviceEventClass *klass) |
546 | 0 | { |
547 | 0 | GObjectClass *object_class = G_OBJECT_CLASS(klass); |
548 | 0 | object_class->finalize = fu_device_event_finalize; |
549 | 0 | } |
550 | | |
551 | | static void |
552 | | fu_device_event_codec_iface_init(FwupdCodecInterface *iface) |
553 | 0 | { |
554 | 0 | iface->add_json = fu_device_event_add_json; |
555 | 0 | iface->from_json = fu_device_event_from_json; |
556 | 0 | } |
557 | | |
558 | | /** |
559 | | * fu_device_event_new: |
560 | | * @id: a cache key, which is converted to a truncated SHA1 hash if required |
561 | | * |
562 | | * Return value: (transfer full): a new #FuDeviceEvent object. |
563 | | * |
564 | | * Since: 2.0.0 |
565 | | **/ |
566 | | FuDeviceEvent * |
567 | | fu_device_event_new(const gchar *id) |
568 | 0 | { |
569 | 0 | FuDeviceEvent *self = g_object_new(FU_TYPE_DEVICE_EVENT, NULL); |
570 | 0 | if (id != NULL) |
571 | 0 | fu_device_event_set_id(self, id); |
572 | 0 | return FU_DEVICE_EVENT(self); |
573 | 0 | } |