Coverage Report

Created: 2025-12-14 06:56

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