Coverage Report

Created: 2025-07-01 07:09

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