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