Coverage Report

Created: 2026-09-03 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-byte-array.c
Line
Count
Source
1
/*
2
 * Copyright 2017 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
0
#define G_LOG_DOMAIN "FuCommon"
8
9
#include "config.h"
10
11
#include "fu-byte-array.h"
12
#include "fu-common.h"
13
#include "fu-firmware-common.h"
14
#include "fu-mem-private.h"
15
16
/**
17
 * fu_byte_array_to_string:
18
 * @array: a #GByteArray
19
 *
20
 * Converts the byte array to a lowercase hex string.
21
 *
22
 * Returns: (transfer full): a string, which may be zero length
23
 *
24
 * Since: 1.8.9
25
 **/
26
gchar *
27
fu_byte_array_to_string(GByteArray *array)
28
0
{
29
0
  g_autoptr(GString) str = g_string_new(NULL);
30
0
  g_return_val_if_fail(array != NULL, NULL);
31
0
  for (guint i = 0; i < array->len; i++)
32
0
    g_string_append_printf(str, "%02x", array->data[i]);
33
0
  return g_string_free_and_steal(g_steal_pointer(&str));
34
0
}
35
36
/**
37
 * fu_byte_array_from_string:
38
 * @str: a hex string
39
 * @error: (nullable): optional return location for an error
40
 *
41
 * Converts a lowercase hex string to a byte array.
42
 *
43
 * Returns: (transfer full): a #GByteArray, or %NULL on error
44
 *
45
 * Since: 1.9.6
46
 **/
47
GByteArray *
48
fu_byte_array_from_string(const gchar *str, GError **error)
49
0
{
50
0
  gsize strsz;
51
0
  g_autoptr(GByteArray) buf = g_byte_array_new();
52
53
0
  g_return_val_if_fail(str != NULL, NULL);
54
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
55
56
0
  strsz = strlen(str);
57
0
  for (guint i = 0; i < strsz; i += 2) {
58
0
    guint8 value = 0;
59
0
    if (!fu_firmware_strparse_uint8_safe(str, strsz, i, &value, error))
60
0
      return NULL;
61
0
    fu_byte_array_append_uint8(buf, value);
62
0
  }
63
0
  return g_steal_pointer(&buf);
64
0
}
65
66
/**
67
 * fu_byte_array_append_uint8:
68
 * @array: a #GByteArray
69
 * @data: value
70
 *
71
 * Adds a 8 bit integer to a byte array.
72
 *
73
 * Since: 1.3.1
74
 **/
75
void
76
fu_byte_array_append_uint8(GByteArray *array, guint8 data)
77
161M
{
78
161M
  g_byte_array_append(array, &data, sizeof(data));
79
161M
}
80
81
/**
82
 * fu_byte_array_append_uint16:
83
 * @array: a #GByteArray
84
 * @data: value
85
 * @endian: endian type, e.g. #G_LITTLE_ENDIAN
86
 *
87
 * Adds a 16 bit integer to a byte array.
88
 *
89
 * Since: 1.3.1
90
 **/
91
void
92
fu_byte_array_append_uint16(GByteArray *array, guint16 data, FuEndianType endian)
93
810k
{
94
810k
  guint8 buf[2]; /* nocheck:zero-init */
95
810k
  fu_memwrite_uint16(buf, data, endian);
96
810k
  g_byte_array_append(array, buf, sizeof(buf));
97
810k
}
98
99
/**
100
 * fu_byte_array_append_uint24:
101
 * @array: a #GByteArray
102
 * @data: value
103
 * @endian: endian type, e.g. #G_LITTLE_ENDIAN
104
 *
105
 * Adds a 24 bit integer to a byte array.
106
 *
107
 * Since: 1.8.13
108
 **/
109
void
110
fu_byte_array_append_uint24(GByteArray *array, guint32 data, FuEndianType endian)
111
0
{
112
0
  guint8 buf[3]; /* nocheck:zero-init */
113
0
  fu_memwrite_uint24(buf, data, endian);
114
0
  g_byte_array_append(array, buf, sizeof(buf));
115
0
}
116
117
/**
118
 * fu_byte_array_append_uint32:
119
 * @array: a #GByteArray
120
 * @data: value
121
 * @endian: endian type, e.g. #G_LITTLE_ENDIAN
122
 *
123
 * Adds a 32 bit integer to a byte array.
124
 *
125
 * Since: 1.3.1
126
 **/
127
void
128
fu_byte_array_append_uint32(GByteArray *array, guint32 data, FuEndianType endian)
129
238k
{
130
238k
  guint8 buf[4]; /* nocheck:zero-init */
131
238k
  fu_memwrite_uint32(buf, data, endian);
132
238k
  g_byte_array_append(array, buf, sizeof(buf));
133
238k
}
134
135
/**
136
 * fu_byte_array_append_uint64:
137
 * @array: a #GByteArray
138
 * @data: value
139
 * @endian: endian type, e.g. #G_LITTLE_ENDIAN
140
 *
141
 * Adds a 64 bit integer to a byte array.
142
 *
143
 * Since: 1.5.8
144
 **/
145
void
146
fu_byte_array_append_uint64(GByteArray *array, guint64 data, FuEndianType endian)
147
62
{
148
62
  guint8 buf[8]; /* nocheck:zero-init */
149
62
  fu_memwrite_uint64(buf, data, endian);
150
62
  g_byte_array_append(array, buf, sizeof(buf));
151
62
}
152
153
/**
154
 * fu_byte_array_append_bytes:
155
 * @array: a #GByteArray
156
 * @bytes: data blob
157
 *
158
 * Adds the contents of a GBytes to a byte array.
159
 *
160
 * Since: 1.5.8
161
 **/
162
void
163
fu_byte_array_append_bytes(GByteArray *array, GBytes *bytes)
164
247k
{
165
247k
  g_byte_array_append(array, g_bytes_get_data(bytes, NULL), g_bytes_get_size(bytes));
166
247k
}
167
168
/**
169
 * fu_byte_array_append_array:
170
 * @array: a #GByteArray
171
 * @array2: another #GByteArray
172
 *
173
 * Adds the content of @array2 to @array.
174
 *
175
 * Since: 2.0.17
176
 **/
177
void
178
fu_byte_array_append_array(GByteArray *array, GByteArray *array2)
179
794k
{
180
794k
  g_return_if_fail(array != NULL);
181
794k
  g_return_if_fail(array2 != NULL);
182
794k
  g_byte_array_append(array, array2->data, array2->len);
183
794k
}
184
185
/**
186
 * fu_byte_array_append_safe:
187
 * @array: a #GByteArray
188
 * @buf: a raw byte buffer
189
 * @bufsz: size of @buf
190
 * @offset: offset in bytes
191
 * @n: number of bytes
192
 * @error: (nullable): optional return location for an error
193
 *
194
 * Adds the content of @buf at @offset to @array.
195
 *
196
 * Returns: %TRUE if the access is safe, %FALSE otherwise
197
 *
198
 * Since: 2.1.1
199
 **/
200
gboolean
201
fu_byte_array_append_safe(GByteArray *array,
202
        const guint8 *buf,
203
        gsize bufsz,
204
        gsize offset,
205
        gsize n,
206
        GError **error)
207
0
{
208
0
  g_return_val_if_fail(array != NULL, FALSE);
209
0
  g_return_val_if_fail(buf != NULL, FALSE);
210
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
211
212
0
  if (!fu_memchk_read(bufsz, offset, n, error))
213
0
    return FALSE;
214
0
  g_byte_array_append(array, buf + offset, n);
215
0
  return TRUE;
216
0
}
217
218
/**
219
 * fu_byte_array_set_size:
220
 * @array: a #GByteArray
221
 * @length:  the new size of the GByteArray
222
 * @data: the byte used to pad the array
223
 *
224
 * Sets the size of the GByteArray, expanding with @data as required.
225
 *
226
 * Since: 1.8.2
227
 **/
228
void
229
fu_byte_array_set_size(GByteArray *array, gsize length, guint8 data)
230
909k
{
231
909k
  guint oldlength = array->len;
232
909k
  g_return_if_fail(array != NULL);
233
909k
  g_return_if_fail(length < G_MAXUINT);
234
909k
  g_byte_array_set_size(array, length);
235
909k
  if (length > oldlength)
236
881k
    memset(array->data + oldlength, data, length - oldlength);
237
909k
}
238
239
/**
240
 * fu_byte_array_align_up:
241
 * @array: a #GByteArray
242
 * @alignment: align to this power of 2
243
 * @data: the byte used to pad the array
244
 *
245
 * Align a byte array length to a power of 2 boundary, where @alignment is the
246
 * bit position to align to. If @alignment is zero then @array is unchanged.
247
 *
248
 * Since: 1.6.0
249
 **/
250
void
251
fu_byte_array_align_up(GByteArray *array, guint8 alignment, guint8 data)
252
46.9k
{
253
46.9k
  fu_byte_array_set_size(array, fu_common_align_up(array->len, alignment), data);
254
46.9k
}
255
256
/**
257
 * fu_byte_array_compare:
258
 * @buf1: a data blob
259
 * @buf2: another #GByteArray
260
 * @error: (nullable): optional return location for an error
261
 *
262
 * Compares two buffers for equality.
263
 *
264
 * Returns: %TRUE if @buf1 and @buf2 are identical
265
 *
266
 * Since: 1.8.0
267
 **/
268
gboolean
269
fu_byte_array_compare(GByteArray *buf1, GByteArray *buf2, GError **error)
270
0
{
271
0
  g_return_val_if_fail(buf1 != NULL, FALSE);
272
0
  g_return_val_if_fail(buf2 != NULL, FALSE);
273
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
274
0
  return fu_memcmp_safe(buf1->data,
275
0
            buf1->len,
276
0
            0x0,
277
0
            buf2->data,
278
0
            buf2->len,
279
0
            0x0,
280
0
            MAX(buf1->len, buf2->len),
281
0
            error);
282
0
}