/src/fwupd/libfwupdplugin/fu-sum.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-mem-private.h" |
12 | | #include "fu-sum.h" |
13 | | |
14 | | /** |
15 | | * fu_sum8: |
16 | | * @buf: memory buffer |
17 | | * @bufsz: size of @buf |
18 | | * |
19 | | * Returns the arithmetic sum of all bytes in @buf. |
20 | | * |
21 | | * Returns: sum value |
22 | | * |
23 | | * Since: 1.8.2 |
24 | | **/ |
25 | | guint8 |
26 | | fu_sum8(const guint8 *buf, gsize bufsz) |
27 | 2.20M | { |
28 | 2.20M | guint8 checksum = 0; |
29 | 2.20M | g_return_val_if_fail(buf != NULL || bufsz == 0, G_MAXUINT8); |
30 | 59.4M | for (gsize i = 0; i < bufsz; i++) |
31 | 57.2M | checksum += buf[i]; |
32 | 2.20M | return checksum; |
33 | 2.20M | } |
34 | | |
35 | | /** |
36 | | * fu_sum8_safe: |
37 | | * @buf: source buffer |
38 | | * @bufsz: maximum size of @buf, typically `sizeof(buf)` |
39 | | * @offset: offset in bytes into @buf where sum should start |
40 | | * @n: number of bytes to sum from @buf |
41 | | * @value: (out) (nullable): the result |
42 | | * @error: (nullable): optional return location for an error |
43 | | * |
44 | | * Returns the arithmetic sum of all bytes in @buf. |
45 | | * |
46 | | * You don't need to use this function in "obviously correct" cases, nor should |
47 | | * you use it when performance is a concern. Only use it when you're not sure if |
48 | | * malicious data from a device or firmware could cause memory corruption. |
49 | | * |
50 | | * Returns: %TRUE on success, %FALSE otherwise |
51 | | * |
52 | | * Since: 2.1.2 |
53 | | **/ |
54 | | gboolean |
55 | | fu_sum8_safe(const guint8 *buf, gsize bufsz, gsize offset, gsize n, guint8 *value, GError **error) |
56 | 0 | { |
57 | 0 | g_return_val_if_fail(buf != NULL || bufsz == 0, FALSE); |
58 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, FALSE); |
59 | | |
60 | 0 | if (!fu_memchk_read(bufsz, offset, n, error)) |
61 | 0 | return FALSE; |
62 | 0 | if (value != NULL) |
63 | 0 | *value = fu_sum8(buf + offset, n); |
64 | 0 | return TRUE; |
65 | 0 | } |
66 | | |
67 | | /** |
68 | | * fu_sum8_bytes: |
69 | | * @blob: a #GBytes |
70 | | * |
71 | | * Returns the arithmetic sum of all bytes in @blob. |
72 | | * |
73 | | * Returns: sum value |
74 | | * |
75 | | * Since: 1.8.2 |
76 | | **/ |
77 | | guint8 |
78 | | fu_sum8_bytes(GBytes *blob) |
79 | 350k | { |
80 | 350k | g_return_val_if_fail(blob != NULL, G_MAXUINT8); |
81 | 350k | if (g_bytes_get_size(blob) == 0) |
82 | 346k | return 0; |
83 | 3.74k | return fu_sum8(g_bytes_get_data(blob, NULL), g_bytes_get_size(blob)); |
84 | 350k | } |
85 | | |
86 | | /** |
87 | | * fu_sum16: |
88 | | * @buf: memory buffer |
89 | | * @bufsz: size of @buf |
90 | | * |
91 | | * Returns the arithmetic sum of all bytes in @buf, adding them one byte at a time. |
92 | | * |
93 | | * Returns: sum value |
94 | | * |
95 | | * Since: 1.8.2 |
96 | | **/ |
97 | | guint16 |
98 | | fu_sum16(const guint8 *buf, gsize bufsz) |
99 | 89 | { |
100 | 89 | guint16 checksum = 0; |
101 | 89 | g_return_val_if_fail(buf != NULL || bufsz == 0, G_MAXUINT16); |
102 | 2.18M | for (gsize i = 0; i < bufsz; i++) |
103 | 2.18M | checksum += buf[i]; |
104 | 89 | return checksum; |
105 | 89 | } |
106 | | |
107 | | /** |
108 | | * fu_sum16_safe: |
109 | | * @buf: source buffer |
110 | | * @bufsz: maximum size of @buf, typically `sizeof(buf)` |
111 | | * @offset: offset in bytes into @buf where sum should start |
112 | | * @n: number of bytes to sum from @buf |
113 | | * @value: (out) (nullable): the result |
114 | | * @error: (nullable): optional return location for an error |
115 | | * |
116 | | * Returns the arithmetic sum of all bytes in @buf, adding them one byte at a time. |
117 | | * |
118 | | * You don't need to use this function in "obviously correct" cases, nor should |
119 | | * you use it when performance is a concern. Only use it when you're not sure if |
120 | | * malicious data from a device or firmware could cause memory corruption. |
121 | | * |
122 | | * Returns: %TRUE on success, %FALSE otherwise |
123 | | * |
124 | | * Since: 2.1.2 |
125 | | **/ |
126 | | gboolean |
127 | | fu_sum16_safe(const guint8 *buf, gsize bufsz, gsize offset, gsize n, guint16 *value, GError **error) |
128 | 0 | { |
129 | 0 | g_return_val_if_fail(buf != NULL || bufsz == 0, FALSE); |
130 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, FALSE); |
131 | | |
132 | 0 | if (!fu_memchk_read(bufsz, offset, n, error)) |
133 | 0 | return FALSE; |
134 | 0 | if (value != NULL) |
135 | 0 | *value = fu_sum16(buf + offset, n); |
136 | 0 | return TRUE; |
137 | 0 | } |
138 | | |
139 | | /** |
140 | | * fu_sum16_bytes: |
141 | | * @blob: a #GBytes |
142 | | * |
143 | | * Returns the arithmetic sum of all bytes in @blob, adding them one byte at a time. |
144 | | * |
145 | | * Returns: sum value |
146 | | * |
147 | | * Since: 1.8.2 |
148 | | **/ |
149 | | guint16 |
150 | | fu_sum16_bytes(GBytes *blob) |
151 | 0 | { |
152 | 0 | g_return_val_if_fail(blob != NULL, G_MAXUINT16); |
153 | 0 | return fu_sum16(g_bytes_get_data(blob, NULL), g_bytes_get_size(blob)); |
154 | 0 | } |
155 | | |
156 | | /** |
157 | | * fu_sum16w: |
158 | | * @buf: memory buffer |
159 | | * @bufsz: size of @buf |
160 | | * @endian: an endian type, e.g. %G_LITTLE_ENDIAN |
161 | | * |
162 | | * Returns the arithmetic sum of all bytes in @buf, adding them one word at a time. |
163 | | * The caller must ensure that @bufsz is a multiple of 2. |
164 | | * |
165 | | * Returns: sum value |
166 | | * |
167 | | * Since: 1.8.2 |
168 | | **/ |
169 | | guint16 |
170 | | fu_sum16w(const guint8 *buf, gsize bufsz, FuEndianType endian) |
171 | 3.24k | { |
172 | 3.24k | guint16 checksum = 0; |
173 | 3.24k | g_return_val_if_fail(buf != NULL || bufsz == 0, G_MAXUINT16); |
174 | 3.24k | g_return_val_if_fail(bufsz % 2 == 0, G_MAXUINT16); |
175 | 119k | for (gsize i = 0; i < bufsz; i += 2) |
176 | 116k | checksum += fu_memread_uint16(&buf[i], endian); |
177 | 3.24k | return checksum; |
178 | 3.24k | } |
179 | | |
180 | | /** |
181 | | * fu_sum16w_bytes: |
182 | | * @blob: a #GBytes |
183 | | * @endian: an endian type, e.g. %G_LITTLE_ENDIAN |
184 | | * |
185 | | * Returns the arithmetic sum of all bytes in @blob, adding them one word at a time. |
186 | | * The caller must ensure that the size of @blob is a multiple of 2. |
187 | | * |
188 | | * Returns: sum value |
189 | | * |
190 | | * Since: 1.8.2 |
191 | | **/ |
192 | | guint16 |
193 | | fu_sum16w_bytes(GBytes *blob, FuEndianType endian) |
194 | 0 | { |
195 | 0 | g_return_val_if_fail(blob != NULL, G_MAXUINT16); |
196 | 0 | return fu_sum16w(g_bytes_get_data(blob, NULL), g_bytes_get_size(blob), endian); |
197 | 0 | } |
198 | | |
199 | | /** |
200 | | * fu_sum32: |
201 | | * @buf: memory buffer |
202 | | * @bufsz: size of @buf |
203 | | * |
204 | | * Returns the arithmetic sum of all bytes in @buf, adding them one byte at a time. |
205 | | * |
206 | | * Returns: sum value |
207 | | * |
208 | | * Since: 1.8.2 |
209 | | **/ |
210 | | guint32 |
211 | | fu_sum32(const guint8 *buf, gsize bufsz) |
212 | 0 | { |
213 | 0 | guint32 checksum = 0; |
214 | 0 | g_return_val_if_fail(buf != NULL || bufsz == 0, G_MAXUINT32); |
215 | 0 | for (gsize i = 0; i < bufsz; i++) |
216 | 0 | checksum += buf[i]; |
217 | 0 | return checksum; |
218 | 0 | } |
219 | | |
220 | | /** |
221 | | * fu_sum32_bytes: |
222 | | * @blob: a #GBytes |
223 | | * |
224 | | * Returns the arithmetic sum of all bytes in @blob, adding them one byte at a time. |
225 | | * |
226 | | * Returns: sum value |
227 | | * |
228 | | * Since: 1.8.2 |
229 | | **/ |
230 | | guint32 |
231 | | fu_sum32_bytes(GBytes *blob) |
232 | 0 | { |
233 | 0 | g_return_val_if_fail(blob != NULL, G_MAXUINT32); |
234 | 0 | return fu_sum32(g_bytes_get_data(blob, NULL), g_bytes_get_size(blob)); |
235 | 0 | } |
236 | | |
237 | | /** |
238 | | * fu_sum32w: |
239 | | * @buf: memory buffer |
240 | | * @bufsz: size of @buf |
241 | | * @endian: an endian type, e.g. %G_LITTLE_ENDIAN |
242 | | * |
243 | | * Returns the arithmetic sum of all bytes in @buf, adding them one dword at a time. |
244 | | * The caller must ensure that @bufsz is a multiple of 4. |
245 | | * |
246 | | * Returns: sum value |
247 | | * |
248 | | * Since: 1.8.2 |
249 | | **/ |
250 | | guint32 |
251 | | fu_sum32w(const guint8 *buf, gsize bufsz, FuEndianType endian) |
252 | 0 | { |
253 | 0 | guint32 checksum = 0; |
254 | 0 | g_return_val_if_fail(buf != NULL || bufsz == 0, G_MAXUINT32); |
255 | 0 | g_return_val_if_fail(bufsz % 4 == 0, G_MAXUINT32); |
256 | 0 | for (gsize i = 0; i < bufsz; i += 4) |
257 | 0 | checksum += fu_memread_uint32(&buf[i], endian); |
258 | 0 | return checksum; |
259 | 0 | } |
260 | | |
261 | | /** |
262 | | * fu_sum32w_bytes: |
263 | | * @blob: a #GBytes |
264 | | * @endian: an endian type, e.g. %G_LITTLE_ENDIAN |
265 | | * |
266 | | * Returns the arithmetic sum of all bytes in @blob, adding them one dword at a time. |
267 | | * The caller must ensure that the size of @blob is a multiple of 4. |
268 | | * |
269 | | * Returns: sum value |
270 | | * |
271 | | * Since: 1.8.2 |
272 | | **/ |
273 | | guint32 |
274 | | fu_sum32w_bytes(GBytes *blob, FuEndianType endian) |
275 | 0 | { |
276 | 0 | g_return_val_if_fail(blob != NULL, G_MAXUINT32); |
277 | 0 | return fu_sum32w(g_bytes_get_data(blob, NULL), g_bytes_get_size(blob), endian); |
278 | 0 | } |