/src/fwupd/libfwupdplugin/fu-cfu-payload.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2021 Richard Hughes <richard@hughsie.com> |
3 | | * |
4 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | | */ |
6 | | |
7 | | #define G_LOG_DOMAIN "FuFirmware" |
8 | | |
9 | | #include "config.h" |
10 | | |
11 | | #include "fu-cfu-firmware-struct.h" |
12 | | #include "fu-cfu-payload.h" |
13 | | #include "fu-input-stream.h" |
14 | | |
15 | | /** |
16 | | * FuCfuPayload: |
17 | | * |
18 | | * A CFU payload. This contains of a variable number of blocks, each containing the address, size |
19 | | * and the chunk data. The chunks do not have to be the same size, and the address ranges do not |
20 | | * have to be continuous. |
21 | | * |
22 | | * Documented: https://docs.microsoft.com/en-us/windows-hardware/drivers/cfu/cfu-specification |
23 | | * |
24 | | * See also: [class@FuFirmware] |
25 | | */ |
26 | | |
27 | | G_DEFINE_TYPE(FuCfuPayload, fu_cfu_payload, FU_TYPE_FIRMWARE) |
28 | | |
29 | | static gboolean |
30 | | fu_cfu_payload_parse(FuFirmware *firmware, |
31 | | GInputStream *stream, |
32 | | FuFirmwareParseFlags flags, |
33 | | GError **error) |
34 | 552 | { |
35 | 552 | gsize offset = 0; |
36 | 552 | gsize streamsz = 0; |
37 | | |
38 | | /* process into chunks */ |
39 | 552 | if (!fu_input_stream_size(stream, &streamsz, error)) |
40 | 0 | return FALSE; |
41 | 441k | while (offset < streamsz) { |
42 | 441k | guint8 chunk_size = 0; |
43 | 441k | g_autoptr(FuChunk) chk = NULL; |
44 | 441k | g_autoptr(GBytes) blob = NULL; |
45 | 441k | g_autoptr(GByteArray) st = NULL; |
46 | | |
47 | 441k | st = fu_struct_cfu_payload_parse_stream(stream, offset, error); |
48 | 441k | if (st == NULL) |
49 | 32 | return FALSE; |
50 | 441k | offset += st->len; |
51 | 441k | chunk_size = fu_struct_cfu_payload_get_size(st); |
52 | 441k | if (chunk_size == 0) { |
53 | 20 | g_set_error_literal(error, |
54 | 20 | FWUPD_ERROR, |
55 | 20 | FWUPD_ERROR_INVALID_DATA, |
56 | 20 | "payload size was invalid"); |
57 | 20 | return FALSE; |
58 | 20 | } |
59 | 441k | blob = fu_input_stream_read_bytes(stream, offset, chunk_size, NULL, error); |
60 | 441k | if (blob == NULL) |
61 | 3 | return FALSE; |
62 | 441k | chk = fu_chunk_bytes_new(blob); |
63 | 441k | fu_chunk_set_address(chk, fu_struct_cfu_payload_get_addr(st)); |
64 | 441k | fu_firmware_add_chunk(firmware, chk); |
65 | | |
66 | | /* next! */ |
67 | 441k | offset += chunk_size; |
68 | 441k | } |
69 | | |
70 | | /* success */ |
71 | 497 | return TRUE; |
72 | 552 | } |
73 | | |
74 | | static GByteArray * |
75 | | fu_cfu_payload_write(FuFirmware *firmware, GError **error) |
76 | 358 | { |
77 | 358 | g_autoptr(GByteArray) buf = g_byte_array_new(); |
78 | 358 | g_autoptr(GPtrArray) chunks = NULL; |
79 | | |
80 | 358 | chunks = fu_firmware_get_chunks(firmware, error); |
81 | 358 | if (chunks == NULL) |
82 | 0 | return NULL; |
83 | 48.3k | for (guint i = 0; i < chunks->len; i++) { |
84 | 47.9k | FuChunk *chk = g_ptr_array_index(chunks, i); |
85 | 47.9k | g_autoptr(GByteArray) st = fu_struct_cfu_payload_new(); |
86 | 47.9k | fu_struct_cfu_payload_set_addr(st, fu_chunk_get_address(chk)); |
87 | 47.9k | fu_struct_cfu_payload_set_size(st, fu_chunk_get_data_sz(chk)); |
88 | 47.9k | g_byte_array_append(buf, st->data, st->len); |
89 | 47.9k | g_byte_array_append(buf, fu_chunk_get_data(chk), fu_chunk_get_data_sz(chk)); |
90 | 47.9k | } |
91 | 358 | return g_steal_pointer(&buf); |
92 | 358 | } |
93 | | |
94 | | static void |
95 | | fu_cfu_payload_init(FuCfuPayload *self) |
96 | 569 | { |
97 | 569 | } |
98 | | |
99 | | static void |
100 | | fu_cfu_payload_class_init(FuCfuPayloadClass *klass) |
101 | 1 | { |
102 | 1 | FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass); |
103 | 1 | firmware_class->parse = fu_cfu_payload_parse; |
104 | 1 | firmware_class->write = fu_cfu_payload_write; |
105 | 1 | } |
106 | | |
107 | | /** |
108 | | * fu_cfu_payload_new: |
109 | | * |
110 | | * Creates a new #FuFirmware for a CFU payload |
111 | | * |
112 | | * Since: 1.7.0 |
113 | | **/ |
114 | | FuFirmware * |
115 | | fu_cfu_payload_new(void) |
116 | 569 | { |
117 | 569 | return FU_FIRMWARE(g_object_new(FU_TYPE_CFU_PAYLOAD, NULL)); |
118 | 569 | } |