From 9e183ec0a6951723a80e8719525ccdbaecd62e17 Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Wed, 20 May 2020 14:35:59 +0200 Subject: [PATCH] 64-bit support, C11 as requirement and other improvements - C11 support is required (although only on serializer.c, so the check has been moved there) since _Alignof is needed. - Added support for little/big endian 64-bit integers. - swap16, swap32 and swap64 now cast pointers to (uint8_t *) and (const uint8_t *) from the argument list so the explicit casts are no longer needed. --- README.md | 24 +++++----- serializer.c | 124 ++++++++++++++++++++++++++++++++++----------------- serializer.h | 4 -- 3 files changed, 97 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index f3b35ed..1ddfffe 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -Serializer/deserializer library for C99 +Serializer/deserializer library for C11 ======================================= This library hopes to be useful under certain circumstances where a portable implementation is desired to read/write data streams yet endianness and alignment requirements need to be taken into account e.g.: network protocols, -file formats, etc. As the title specifies, only a C99-compliant compiler is +file formats, etc. As the title specifies, only a C11-compliant compiler is required. -Only 8-bit and 16/32-bit little-endian and big-endian values are supported. +Only 8-bit and 16/32/64-bit little-endian and big-endian values are supported. This means no support for bit fields, as some aspects of bit fields are implementation-defined. @@ -15,7 +15,7 @@ Usage ------ ```{c} -#include "serializer.h" +#include #include #include @@ -27,25 +27,27 @@ int main() uint16_t b; uint32_t c; uint16_t d; + uint64_t e; + uint64_t f; } ex; static const uint8_t data[] = { - 0x01, 0x33, 0xFF, 0xAC, 0xBB, 0xFA, 0xFA, 0xDE, 0xDE + 0x01, 0x33, 0xFF, 0xAC, 0xBB, 0xFA, 0xFA, 0xDE, 0xDD, + 0x12, 0x33, 0xFF, 0xAC, 0xBB, 0xFA, 0xFA, 0xDE, + 0x12, 0x33, 0xFF, 0xAC, 0xBB, 0xFA, 0xFA, 0xDE, }; - deserialize("1/le2/be4/be2", &ex, sizeof ex, data, sizeof data); - printf("a=%X, b=%X, c=%X, d=%X\n", - ex.a, ex.b, ex.c, ex.d); + deserialize("1/le2/be4/be2/be8/le8", &ex, sizeof ex, data, sizeof data); + printf("a=%X, b=%X, c=%X, d=%X, e=%lX, f=%lX\n", + ex.a, ex.b, ex.c, ex.d, ex.e, ex.f); return 0; } ``` Output ------ -`a=1, b=FF33, c=ACBBFAFA, d=DEDE` +`a=1, b=FF33, c=ACBBFAFA, d=DEDD, e=1233FFACBBFAFADE, f=DEFAFABBACFF3312` TODO ---- Only deserialization is implemented. Serialization will be implemented in the future. - -64-bit support. diff --git a/serializer.c b/serializer.c index e094bc0..d108254 100644 --- a/serializer.c +++ b/serializer.c @@ -20,6 +20,10 @@ #include #include +#if __STDC_VERSION__ < 201112L +#error C11 support is mandatory for serializer +#endif + static bool little_endian(void) { return (const union {char c; int b;}){.c = 1}.b; @@ -42,6 +46,8 @@ enum token TOKEN_BE16BIT, TOKEN_LE32BIT, TOKEN_BE32BIT, + TOKEN_LE64BIT, + TOKEN_BE64BIT, TOKEN_NOT_READY, TOKEN_ERROR }; @@ -134,6 +140,22 @@ static enum token get_multibyte(const char c, enum state *const state, enum endi break; + case '8': + + switch (*endianness) + { + case LITTLE_ENDIAN: + return TOKEN_LE64BIT; + + case BIG_ENDIAN: + return TOKEN_BE64BIT; + + default: + break; + } + + break; + default: break; } @@ -153,46 +175,72 @@ static enum token get_token(const char c, enum state *const state, enum endianne return get[*state](c, state, endianness); } -static void read8(void *const dst, const void *const src) +static void read8(void *const dst, const void *const src, const size_t sz) { *(uint8_t *)dst = *(const uint8_t *)src; } -static void swap32(void *dst, const void *const src) +static void swap64(uint8_t *dst, const uint8_t *const src) { - *(uint8_t *)dst++ = *((const uint8_t *)src + 3); - *(uint8_t *)dst++ = *((const uint8_t *)src + 2); - *(uint8_t *)dst++ = *((const uint8_t *)src + 1); - *(uint8_t *)dst = *(const uint8_t *)src; + *dst++ = *(src + 7); + *dst++ = *(src + 6); + *dst++ = *(src + 5); + *dst++ = *(src + 4); + *dst++ = *(src + 3); + *dst++ = *(src + 2); + *dst++ = *(src + 1); + *dst = *src; } -static void readbe32(void *const dst, const void *const src) +static void readbe64(void *const dst, const void *const src, const size_t sz) { - enum + if (little_endian()) { - SZ = sizeof (uint32_t) - }; + swap64(dst, src); + } + else + { + memmove(dst, src, sz); + } +} +static void readle64(void *const dst, const void *const src, const size_t sz) +{ + if (little_endian()) + { + memmove(dst, src, sz); + } + else + { + swap64(dst, src); + } +} + +static void swap32(uint8_t *dst, const uint8_t *const src) +{ + *dst++ = *(src + 3); + *dst++ = *(src + 2); + *dst++ = *(src + 1); + *dst = *src; +} + +static void readbe32(void *const dst, const void *const src, const size_t sz) +{ if (little_endian()) { swap32(dst, src); } else { - memmove(dst, src, SZ); + memmove(dst, src, sz); } } -static void readle32(void *const dst, const void *const src) +static void readle32(void *const dst, const void *const src, const size_t sz) { - enum - { - SZ = sizeof (uint32_t) - }; - if (little_endian()) { - memmove(dst, src, SZ); + memmove(dst, src, sz); } else { @@ -200,39 +248,29 @@ static void readle32(void *const dst, const void *const src) } } -static void swap16(void *dst, const void *const src) +static void swap16(uint8_t *dst, const uint8_t *const src) { - *(uint8_t *)dst++ = *((const uint8_t *)src + 1); - *(uint8_t *)dst = *(const uint8_t *)src; + *dst++ = *(src + 1); + *dst = *src; } -static void readbe16(void *const dst, const void *const src) +static void readbe16(void *const dst, const void *const src, const size_t sz) { - enum - { - SZ = sizeof (uint16_t) - }; - if (little_endian()) { swap16(dst, src); } else { - memmove(dst, src, SZ); + memmove(dst, src, sz); } } -static void readle16(void *const dst, const void *const src) +static void readle16(void *const dst, const void *const src, const size_t sz) { - enum - { - SZ = sizeof (uint16_t) - }; - if (little_endian()) { - memmove(dst, src, SZ); + memmove(dst, src, sz); } else { @@ -271,7 +309,9 @@ enum serializer_err deserialize(const char *format, [TOKEN_LE16BIT] = sizeof (uint16_t), [TOKEN_BE16BIT] = sizeof (uint16_t), [TOKEN_LE32BIT] = sizeof (uint32_t), - [TOKEN_BE32BIT] = sizeof (uint32_t) + [TOKEN_BE32BIT] = sizeof (uint32_t), + [TOKEN_LE64BIT] = sizeof (uint64_t), + [TOKEN_BE64BIT] = sizeof (uint64_t) }; static const size_t aligns[] = @@ -280,16 +320,20 @@ enum serializer_err deserialize(const char *format, [TOKEN_LE16BIT] = _Alignof (uint16_t), [TOKEN_BE16BIT] = _Alignof (uint16_t), [TOKEN_LE32BIT] = _Alignof (uint32_t), - [TOKEN_BE32BIT] = _Alignof (uint32_t) + [TOKEN_BE32BIT] = _Alignof (uint32_t), + [TOKEN_LE64BIT] = _Alignof (uint64_t), + [TOKEN_BE64BIT] = _Alignof (uint64_t) }; - static void (*const read[])(void *dst, const void *src) = + static void (*const read[])(void *dst, const void *src, size_t sz) = { [TOKEN_8BIT] = read8, [TOKEN_LE16BIT] = readle16, [TOKEN_BE16BIT] = readbe16, [TOKEN_LE32BIT] = readle32, - [TOKEN_BE32BIT] = readbe32 + [TOKEN_BE32BIT] = readbe32, + [TOKEN_LE64BIT] = readle64, + [TOKEN_BE64BIT] = readbe64 }; const size_t st = sizes[token]; @@ -304,7 +348,7 @@ enum serializer_err deserialize(const char *format, return SERIALIZER_ERR_IN_OVERFLOW; else if (out_sz + st <= sz) { - read[token]((uint8_t *)dst + out_sz, (const uint8_t *)src + in_sz); + read[token]((uint8_t *)dst + out_sz, (const uint8_t *)src + in_sz, st); in_sz += st; out_sz += st; state = 0; diff --git a/serializer.h b/serializer.h index 091e0e8..2e16a7d 100644 --- a/serializer.h +++ b/serializer.h @@ -19,10 +19,6 @@ #include -#if __STDC_VERSION__ < 199901L -#error C99 support is mandatory for serializer -#endif /* __STDC_VERSION < 199901L */ - #ifdef __cplusplus extern "C" {