diff options
Diffstat (limited to 'src/helper/crc32.c')
-rw-r--r-- | src/helper/crc32.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/src/helper/crc32.c b/src/helper/crc32.c new file mode 100644 index 0000000..441a46c --- /dev/null +++ b/src/helper/crc32.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2013-2014 by Franck Jullien * + * elec4fun@gmail.com * + * * + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg * + * marian.buschsieweke@ovgu.de * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "crc32.h" +#include <stdint.h> +#include <stddef.h> + +static uint32_t crc_le_step(uint32_t poly, uint32_t crc, uint32_t data_in, + unsigned int data_bits) +{ + for (unsigned int i = 0; i < data_bits; i++) { + uint32_t d, c; + d = ((data_in >> i) & 0x1) ? 0xffffffff : 0; + c = (crc & 0x1) ? 0xffffffff : 0; + crc = crc >> 1; + crc = crc ^ ((d ^ c) & poly); + } + + return crc; +} + +uint32_t crc32_le(uint32_t poly, uint32_t seed, const void *_data, + size_t data_len) +{ + if (((uintptr_t)_data & 0x3) || (data_len & 0x3)) { + /* data is unaligned, processing data one byte at a time */ + const uint8_t *data = _data; + for (size_t i = 0; i < data_len; i++) + seed = crc_le_step(poly, seed, data[i], 8); + } else { + /* data is aligned, processing 32 bit at a time */ + data_len >>= 2; + const uint32_t *data = _data; + for (size_t i = 0; i < data_len; i++) + seed = crc_le_step(poly, seed, data[i], 32); + } + + return seed; +} |