/src/fwupd/libfwupdplugin/fu-crc.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-common.h" |
12 | | #include "fu-crc-private.h" |
13 | | #include "fu-mem.h" |
14 | | |
15 | | const struct { |
16 | | FuCrcKind kind; |
17 | | guint bitwidth; |
18 | | guint32 poly; |
19 | | guint32 init; |
20 | | gboolean reflected; |
21 | | guint32 xorout; |
22 | | } crc_map[] = { |
23 | | {FU_CRC_KIND_UNKNOWN, 32, 0x00000000, 0x00000000, TRUE, 0xFFFFFFFF}, |
24 | | {FU_CRC_KIND_B32_STANDARD, 32, 0x04C11DB7, 0xFFFFFFFF, TRUE, 0xFFFFFFFF}, |
25 | | {FU_CRC_KIND_B32_BZIP2, 32, 0x04C11DB7, 0xFFFFFFFF, FALSE, 0xFFFFFFFF}, |
26 | | {FU_CRC_KIND_B32_JAMCRC, 32, 0x04C11DB7, 0xFFFFFFFF, TRUE, 0x00000000}, |
27 | | {FU_CRC_KIND_B32_MPEG2, 32, 0x04C11DB7, 0xFFFFFFFF, FALSE, 0x00000000}, |
28 | | {FU_CRC_KIND_B32_POSIX, 32, 0x04C11DB7, 0x00000000, FALSE, 0xFFFFFFFF}, |
29 | | {FU_CRC_KIND_B32_SATA, 32, 0x04C11DB7, 0x52325032, FALSE, 0x00000000}, |
30 | | {FU_CRC_KIND_B32_XFER, 32, 0x000000AF, 0x00000000, FALSE, 0x00000000}, |
31 | | {FU_CRC_KIND_B32_C, 32, 0x1EDC6F41, 0xFFFFFFFF, TRUE, 0xFFFFFFFF}, |
32 | | {FU_CRC_KIND_B32_D, 32, 0xA833982B, 0xFFFFFFFF, TRUE, 0xFFFFFFFF}, |
33 | | {FU_CRC_KIND_B32_Q, 32, 0x814141AB, 0x00000000, FALSE, 0x00000000}, |
34 | | {FU_CRC_KIND_B16_XMODEM, 16, 0x1021, 0x0000, FALSE, 0x0000}, |
35 | | {FU_CRC_KIND_B16_KERMIT, 16, 0x1021, 0x0000, TRUE, 0x0000}, |
36 | | {FU_CRC_KIND_B16_USB, 16, 0x8005, 0xFFFF, TRUE, 0xFFFF}, |
37 | | {FU_CRC_KIND_B16_UMTS, 16, 0x8005, 0x0000, FALSE, 0x0000}, |
38 | | {FU_CRC_KIND_B16_TMS37157, 16, 0x1021, 0x89ec, TRUE, 0x0000}, |
39 | | {FU_CRC_KIND_B16_BNR, 16, 0x8005, 0xFFFF, FALSE, 0x0000}, |
40 | | {FU_CRC_KIND_B8_WCDMA, 8, 0x9B, 0x00, TRUE, 0x00}, |
41 | | {FU_CRC_KIND_B8_TECH_3250, 8, 0x1D, 0xFF, TRUE, 0x00}, |
42 | | {FU_CRC_KIND_B8_STANDARD, 8, 0x07, 0x00, FALSE, 0x00}, |
43 | | {FU_CRC_KIND_B8_SAE_J1850, 8, 0x1D, 0xFF, FALSE, 0xFF}, |
44 | | {FU_CRC_KIND_B8_ROHC, 8, 0x07, 0xFF, TRUE, 0x00}, |
45 | | {FU_CRC_KIND_B8_OPENSAFETY, 8, 0x2F, 0x00, FALSE, 0x00}, |
46 | | {FU_CRC_KIND_B8_NRSC_5, 8, 0x31, 0xFF, FALSE, 0x00}, |
47 | | {FU_CRC_KIND_B8_MIFARE_MAD, 8, 0x1D, 0xC7, FALSE, 0x00}, |
48 | | {FU_CRC_KIND_B8_MAXIM_DOW, 8, 0x31, 0x00, TRUE, 0x00}, |
49 | | {FU_CRC_KIND_B8_LTE, 8, 0x9B, 0x00, FALSE, 0x00}, |
50 | | {FU_CRC_KIND_B8_I_CODE, 8, 0x1D, 0xFD, FALSE, 0x00}, |
51 | | {FU_CRC_KIND_B8_ITU, 8, 0x07, 0x00, FALSE, 0x55}, |
52 | | {FU_CRC_KIND_B8_HITAG, 8, 0x1D, 0xFF, FALSE, 0x00}, |
53 | | {FU_CRC_KIND_B8_GSM_B, 8, 0x49, 0x00, FALSE, 0xFF}, |
54 | | {FU_CRC_KIND_B8_GSM_A, 8, 0x1D, 0x00, FALSE, 0x00}, |
55 | | {FU_CRC_KIND_B8_DVB_S2, 8, 0xD5, 0x00, FALSE, 0x00}, |
56 | | {FU_CRC_KIND_B8_DARC, 8, 0x39, 0x00, TRUE, 0x00}, |
57 | | {FU_CRC_KIND_B8_CDMA2000, 8, 0x9B, 0xFF, FALSE, 0x00}, |
58 | | {FU_CRC_KIND_B8_BLUETOOTH, 8, 0xA7, 0x00, TRUE, 0x00}, |
59 | | {FU_CRC_KIND_B8_AUTOSAR, 8, 0x2F, 0xFF, FALSE, 0xFF}, |
60 | | }; |
61 | | |
62 | | static guint8 |
63 | | fu_crc_reflect8(guint8 data) |
64 | 105M | { |
65 | 105M | guint8 val = 0; |
66 | 950M | for (guint8 bit = 0; bit < 8; bit++) { |
67 | 844M | if (data & 0x01) |
68 | 283M | FU_BIT_SET(val, 7 - bit); |
69 | 844M | data = (data >> 1); |
70 | 844M | } |
71 | 105M | return val; |
72 | 105M | } |
73 | | |
74 | | static guint32 |
75 | | fu_crc_reflect(guint32 data, guint bitwidth) |
76 | 4.82k | { |
77 | 4.82k | guint32 val = 0; |
78 | 159k | for (guint bit = 0; bit < bitwidth; bit++) { |
79 | 154k | if (data & 0x01) |
80 | 78.8k | val |= 1ul << ((bitwidth - 1) - bit); |
81 | 154k | data = (data >> 1); |
82 | 154k | } |
83 | 4.82k | return val; |
84 | 4.82k | } |
85 | | |
86 | | /** |
87 | | * fu_crc8_step: |
88 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B8_MAXIM_DOW |
89 | | * @buf: memory buffer |
90 | | * @bufsz: size of @buf |
91 | | * @crc: initial CRC value |
92 | | * |
93 | | * Computes the cyclic redundancy check section value for the given memory buffer. |
94 | | * |
95 | | * NOTE: When all data has been added, you should call fu_crc8_done() to return the final value. |
96 | | * |
97 | | * Returns: CRC value |
98 | | * |
99 | | * Since: 2.0.0 |
100 | | **/ |
101 | | guint8 |
102 | | fu_crc8_step(FuCrcKind kind, const guint8 *buf, gsize bufsz, guint8 crc) |
103 | 0 | { |
104 | 0 | const guint bitwidth = sizeof(crc) * 8; |
105 | |
|
106 | 0 | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
107 | 0 | g_return_val_if_fail(crc_map[kind].bitwidth == 8, 0x0); |
108 | | |
109 | 0 | for (gsize i = 0; i < bufsz; ++i) { |
110 | 0 | crc ^= crc_map[kind].reflected ? fu_crc_reflect8(buf[i]) : buf[i]; |
111 | 0 | for (guint8 bit = 0; bit < 8; bit++) { |
112 | 0 | if (crc & (1ul << (bitwidth - 1))) { |
113 | 0 | crc = (crc << 1) ^ crc_map[kind].poly; |
114 | 0 | } else { |
115 | 0 | crc = (crc << 1); |
116 | 0 | } |
117 | 0 | } |
118 | 0 | } |
119 | 0 | return crc; |
120 | 0 | } |
121 | | |
122 | | /** |
123 | | * fu_crc8_done: |
124 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B8_MAXIM_DOW |
125 | | * @crc: initial CRC value |
126 | | * |
127 | | * Returns the finished cyclic redundancy check value. |
128 | | * |
129 | | * Returns: CRC value |
130 | | * |
131 | | * Since: 2.0.0 |
132 | | **/ |
133 | | guint8 |
134 | | fu_crc8_done(FuCrcKind kind, guint8 crc) |
135 | 0 | { |
136 | 0 | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
137 | 0 | g_return_val_if_fail(crc_map[kind].bitwidth == 8, 0x0); |
138 | 0 | crc = crc_map[kind].reflected ? fu_crc_reflect(crc, crc_map[kind].bitwidth) : crc; |
139 | 0 | return crc ^ crc_map[kind].xorout; |
140 | 0 | } |
141 | | |
142 | | /** |
143 | | * fu_crc8: |
144 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B8_MAXIM_DOW |
145 | | * @buf: memory buffer |
146 | | * @bufsz: size of @buf |
147 | | * |
148 | | * Returns the cyclic redundancy check value for the given memory buffer. |
149 | | * |
150 | | * Returns: CRC value |
151 | | * |
152 | | * Since: 2.0.0 |
153 | | **/ |
154 | | guint8 |
155 | | fu_crc8(FuCrcKind kind, const guint8 *buf, gsize bufsz) |
156 | 0 | { |
157 | 0 | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
158 | 0 | g_return_val_if_fail(crc_map[kind].bitwidth == 8, 0x0); |
159 | 0 | return fu_crc8_done(kind, fu_crc8_step(kind, buf, bufsz, crc_map[kind].init)); |
160 | 0 | } |
161 | | |
162 | | /** |
163 | | * fu_crc8_bytes: |
164 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B8_MAXIM_DOW |
165 | | * @blob: a #GBytes |
166 | | * |
167 | | * Returns the cyclic redundancy check value for the given memory buffer. |
168 | | * |
169 | | * Returns: CRC value |
170 | | * |
171 | | * Since: 2.0.2 |
172 | | **/ |
173 | | guint8 |
174 | | fu_crc8_bytes(FuCrcKind kind, GBytes *blob) |
175 | 0 | { |
176 | 0 | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
177 | 0 | g_return_val_if_fail(blob != NULL, 0x0); |
178 | 0 | return fu_crc8(kind, g_bytes_get_data(blob, NULL), g_bytes_get_size(blob)); |
179 | 0 | } |
180 | | |
181 | | /** |
182 | | * fu_crc16_step: |
183 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B16_XMODEM |
184 | | * @buf: memory buffer |
185 | | * @bufsz: size of @buf |
186 | | * @crc: initial CRC value |
187 | | * |
188 | | * Computes the cyclic redundancy check section value for the given memory buffer. |
189 | | * |
190 | | * NOTE: When all data has been added, you should call fu_crc16_done() to return the final value. |
191 | | * |
192 | | * Returns: CRC value |
193 | | * |
194 | | * Since: 2.0.0 |
195 | | **/ |
196 | | guint16 |
197 | | fu_crc16_step(FuCrcKind kind, const guint8 *buf, gsize bufsz, guint16 crc) |
198 | 0 | { |
199 | 0 | const guint bitwidth = sizeof(crc) * 8; |
200 | |
|
201 | 0 | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
202 | 0 | g_return_val_if_fail(crc_map[kind].bitwidth == 16, 0x0); |
203 | | |
204 | 0 | for (gsize i = 0; i < bufsz; ++i) { |
205 | 0 | guint16 tmp = crc_map[kind].reflected ? fu_crc_reflect8(buf[i]) : buf[i]; |
206 | 0 | crc ^= tmp << (bitwidth - 8); |
207 | 0 | for (guint8 bit = 0; bit < 8; bit++) { |
208 | 0 | if (crc & (1ul << (bitwidth - 1))) { |
209 | 0 | crc = (crc << 1) ^ crc_map[kind].poly; |
210 | 0 | } else { |
211 | 0 | crc = (crc << 1); |
212 | 0 | } |
213 | 0 | } |
214 | 0 | } |
215 | 0 | return crc; |
216 | 0 | } |
217 | | |
218 | | /** |
219 | | * fu_crc16_done: |
220 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B16_XMODEM |
221 | | * @crc: initial CRC value |
222 | | * |
223 | | * Returns the finished cyclic redundancy check value. |
224 | | * |
225 | | * Returns: CRC value |
226 | | * |
227 | | * Since: 2.0.0 |
228 | | **/ |
229 | | guint16 |
230 | | fu_crc16_done(FuCrcKind kind, guint16 crc) |
231 | 0 | { |
232 | 0 | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
233 | 0 | g_return_val_if_fail(crc_map[kind].bitwidth == 16, 0x0); |
234 | 0 | crc = crc_map[kind].reflected ? fu_crc_reflect(crc, crc_map[kind].bitwidth) : crc; |
235 | 0 | return crc ^ crc_map[kind].xorout; |
236 | 0 | } |
237 | | |
238 | | /** |
239 | | * fu_crc16: |
240 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B16_XMODEM |
241 | | * @buf: memory buffer |
242 | | * @bufsz: size of @buf |
243 | | * |
244 | | * Returns the cyclic redundancy check value for the given memory buffer. |
245 | | * |
246 | | * Returns: CRC value |
247 | | * |
248 | | * Since: 2.0.0 |
249 | | **/ |
250 | | guint16 |
251 | | fu_crc16(FuCrcKind kind, const guint8 *buf, gsize bufsz) |
252 | 0 | { |
253 | 0 | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
254 | 0 | g_return_val_if_fail(crc_map[kind].bitwidth == 16, 0x0); |
255 | 0 | return fu_crc16_done(kind, fu_crc16_step(kind, buf, bufsz, crc_map[kind].init)); |
256 | 0 | } |
257 | | |
258 | | /** |
259 | | * fu_crc16_bytes: |
260 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B16_XMODEM |
261 | | * @blob: a #GBytes |
262 | | * |
263 | | * Returns the cyclic redundancy check value for the given memory buffer. |
264 | | * |
265 | | * Returns: CRC value |
266 | | * |
267 | | * Since: 2.0.2 |
268 | | **/ |
269 | | guint16 |
270 | | fu_crc16_bytes(FuCrcKind kind, GBytes *blob) |
271 | 0 | { |
272 | 0 | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
273 | 0 | g_return_val_if_fail(blob != NULL, 0x0); |
274 | 0 | return fu_crc16(kind, g_bytes_get_data(blob, NULL), g_bytes_get_size(blob)); |
275 | 0 | } |
276 | | |
277 | | /** |
278 | | * fu_crc32_step: |
279 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B32_STANDARD |
280 | | * @buf: memory buffer |
281 | | * @bufsz: size of @buf |
282 | | * @crc: initial CRC value |
283 | | * |
284 | | * Computes the cyclic redundancy check section value for the given memory buffer. |
285 | | * |
286 | | * NOTE: When all data has been added, you should call fu_crc32_done() to return the final value. |
287 | | * |
288 | | * Returns: CRC value |
289 | | * |
290 | | * Since: 2.0.0 |
291 | | **/ |
292 | | guint32 |
293 | | fu_crc32_step(FuCrcKind kind, const guint8 *buf, gsize bufsz, guint32 crc) |
294 | 5.13k | { |
295 | 5.13k | const guint bitwidth = sizeof(crc) * 8; |
296 | | |
297 | 5.13k | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
298 | 5.13k | g_return_val_if_fail(crc_map[kind].bitwidth == 32, 0x0); |
299 | | |
300 | 105M | for (gsize i = 0; i < bufsz; ++i) { |
301 | 105M | guint32 tmp = crc_map[kind].reflected ? fu_crc_reflect8(buf[i]) : buf[i]; |
302 | 105M | crc ^= tmp << (bitwidth - 8); |
303 | 950M | for (guint8 bit = 0; bit < 8; bit++) { |
304 | 844M | if (crc & (1ul << (bitwidth - 1))) { |
305 | 405M | crc = (crc << 1) ^ crc_map[kind].poly; |
306 | 438M | } else { |
307 | 438M | crc = (crc << 1); |
308 | 438M | } |
309 | 844M | } |
310 | 105M | } |
311 | 5.13k | return crc; |
312 | 5.13k | } |
313 | | |
314 | | /** |
315 | | * fu_crc32_done: |
316 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B32_STANDARD |
317 | | * @crc: initial CRC value |
318 | | * |
319 | | * Returns the finished cyclic redundancy check value. |
320 | | * |
321 | | * Returns: CRC value |
322 | | * |
323 | | * Since: 2.0.0 |
324 | | **/ |
325 | | guint32 |
326 | | fu_crc32_done(FuCrcKind kind, guint32 crc) |
327 | 4.82k | { |
328 | 4.82k | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
329 | 4.82k | g_return_val_if_fail(crc_map[kind].bitwidth == 32, 0x0); |
330 | 4.82k | crc = crc_map[kind].reflected ? fu_crc_reflect(crc, crc_map[kind].bitwidth) : crc; |
331 | 4.82k | return crc ^ crc_map[kind].xorout; |
332 | 4.82k | } |
333 | | |
334 | | /** |
335 | | * fu_crc32: |
336 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B32_STANDARD |
337 | | * @buf: memory buffer |
338 | | * @bufsz: size of @buf |
339 | | * |
340 | | * Returns the cyclic redundancy check value for the given memory buffer. |
341 | | * |
342 | | * Returns: CRC value |
343 | | * |
344 | | * Since: 2.0.0 |
345 | | **/ |
346 | | guint32 |
347 | | fu_crc32(FuCrcKind kind, const guint8 *buf, gsize bufsz) |
348 | 1.99k | { |
349 | 1.99k | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
350 | 1.99k | g_return_val_if_fail(crc_map[kind].bitwidth == 32, 0x0); |
351 | 1.99k | return fu_crc32_done(kind, fu_crc32_step(kind, buf, bufsz, crc_map[kind].init)); |
352 | 1.99k | } |
353 | | |
354 | | /** |
355 | | * fu_crc32_bytes: |
356 | | * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B32_STANDARD |
357 | | * @blob: a #GBytes |
358 | | * |
359 | | * Returns the cyclic redundancy check value for the given memory buffer. |
360 | | * |
361 | | * Returns: CRC value |
362 | | * |
363 | | * Since: 2.0.2 |
364 | | **/ |
365 | | guint32 |
366 | | fu_crc32_bytes(FuCrcKind kind, GBytes *blob) |
367 | 696 | { |
368 | 696 | g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0); |
369 | 696 | g_return_val_if_fail(blob != NULL, 0x0); |
370 | 696 | return fu_crc32(kind, g_bytes_get_data(blob, NULL), g_bytes_get_size(blob)); |
371 | 696 | } |
372 | | |
373 | | /** |
374 | | * fu_crc_find: |
375 | | * @buf: memory buffer |
376 | | * @bufsz: size of @buf |
377 | | * @crc_target: "correct" CRC value |
378 | | * |
379 | | * Returns the cyclic redundancy kind for the given memory buffer and target CRC. |
380 | | * |
381 | | * You can use a very simple buffer to discover most types of standard CRC-32: |
382 | | * |
383 | | * guint8 buf[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; |
384 | | * g_info("CRC:%u", fu_crc_find(buf, sizeof(buf), _custom_crc(buf, sizeof(buf)))); |
385 | | * |
386 | | * Returns: a #FuCrcKind, or %FU_CRC_KIND_UNKNOWN on error |
387 | | * |
388 | | * Since: 2.0.0 |
389 | | **/ |
390 | | FuCrcKind |
391 | | fu_crc_find(const guint8 *buf, gsize bufsz, guint32 crc_target) |
392 | 0 | { |
393 | 0 | for (guint i = 0; i < G_N_ELEMENTS(crc_map); i++) { |
394 | 0 | if (crc_map[i].bitwidth == 32) { |
395 | 0 | if (crc_target == fu_crc32(crc_map[i].kind, buf, bufsz)) |
396 | 0 | return crc_map[i].kind; |
397 | 0 | } |
398 | 0 | if (crc_map[i].bitwidth == 16) { |
399 | 0 | if ((guint16)crc_target == fu_crc16(crc_map[i].kind, buf, bufsz)) |
400 | 0 | return crc_map[i].kind; |
401 | 0 | } |
402 | 0 | if (crc_map[i].bitwidth == 8) { |
403 | 0 | if ((guint8)crc_target == fu_crc8(crc_map[i].kind, buf, bufsz)) |
404 | 0 | return crc_map[i].kind; |
405 | 0 | } |
406 | 0 | } |
407 | 0 | return FU_CRC_KIND_UNKNOWN; |
408 | 0 | } |
409 | | |
410 | | static guint16 |
411 | | fu_crc_misr16_step(guint16 cur, guint16 new) |
412 | 0 | { |
413 | 0 | guint16 bit0; |
414 | 0 | guint16 res; |
415 | |
|
416 | 0 | bit0 = cur ^ (new & 1); |
417 | 0 | bit0 ^= cur >> 1; |
418 | 0 | bit0 ^= cur >> 2; |
419 | 0 | bit0 ^= cur >> 4; |
420 | 0 | bit0 ^= cur >> 5; |
421 | 0 | bit0 ^= cur >> 7; |
422 | 0 | bit0 ^= cur >> 11; |
423 | 0 | bit0 ^= cur >> 15; |
424 | 0 | res = (cur << 1) ^ new; |
425 | 0 | res = (res & ~1) | (bit0 & 1); |
426 | 0 | return res; |
427 | 0 | } |
428 | | |
429 | | /** |
430 | | * fu_crc_misr16: |
431 | | * @buf: memory buffer |
432 | | * @bufsz: size of @buf |
433 | | * @init: initial value, typically 0x0 |
434 | | * |
435 | | * Returns the MISR check value for the given memory buffer. |
436 | | * |
437 | | * Returns: value |
438 | | * |
439 | | * Since: 1.9.17 |
440 | | **/ |
441 | | guint16 |
442 | | fu_crc_misr16(guint16 init, const guint8 *buf, gsize bufsz) |
443 | 0 | { |
444 | 0 | g_return_val_if_fail(buf != NULL, G_MAXUINT16); |
445 | 0 | g_return_val_if_fail(bufsz % 2 == 0, G_MAXUINT16); |
446 | | |
447 | 0 | for (gsize i = 0; i < bufsz; i += 2) |
448 | 0 | init = fu_crc_misr16_step(init, fu_memread_uint16(buf + i, G_LITTLE_ENDIAN)); |
449 | 0 | return init; |
450 | 0 | } |