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.
This commit is contained in:
Xavier Del Campo Romero 2020-05-20 14:35:59 +02:00
parent 71a3db14a5
commit 9e183ec0a6
3 changed files with 97 additions and 55 deletions

View File

@ -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 This library hopes to be useful under certain circumstances where a portable
implementation is desired to read/write data streams yet endianness and implementation is desired to read/write data streams yet endianness and
alignment requirements need to be taken into account e.g.: network protocols, 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. 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 This means no support for bit fields, as some aspects of bit fields are
implementation-defined. implementation-defined.
@ -15,7 +15,7 @@ Usage
------ ------
```{c} ```{c}
#include "serializer.h" #include <serializer.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -27,25 +27,27 @@ int main()
uint16_t b; uint16_t b;
uint32_t c; uint32_t c;
uint16_t d; uint16_t d;
uint64_t e;
uint64_t f;
} ex; } ex;
static const uint8_t data[] = 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); deserialize("1/le2/be4/be2/be8/le8", &ex, sizeof ex, data, sizeof data);
printf("a=%X, b=%X, c=%X, d=%X\n", printf("a=%X, b=%X, c=%X, d=%X, e=%lX, f=%lX\n",
ex.a, ex.b, ex.c, ex.d); ex.a, ex.b, ex.c, ex.d, ex.e, ex.f);
return 0; return 0;
} }
``` ```
Output Output
------ ------
`a=1, b=FF33, c=ACBBFAFA, d=DEDE` `a=1, b=FF33, c=ACBBFAFA, d=DEDD, e=1233FFACBBFAFADE, f=DEFAFABBACFF3312`
TODO TODO
---- ----
Only deserialization is implemented. Serialization will be implemented in the future. Only deserialization is implemented. Serialization will be implemented in the future.
64-bit support.

View File

@ -20,6 +20,10 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#if __STDC_VERSION__ < 201112L
#error C11 support is mandatory for serializer
#endif
static bool little_endian(void) static bool little_endian(void)
{ {
return (const union {char c; int b;}){.c = 1}.b; return (const union {char c; int b;}){.c = 1}.b;
@ -42,6 +46,8 @@ enum token
TOKEN_BE16BIT, TOKEN_BE16BIT,
TOKEN_LE32BIT, TOKEN_LE32BIT,
TOKEN_BE32BIT, TOKEN_BE32BIT,
TOKEN_LE64BIT,
TOKEN_BE64BIT,
TOKEN_NOT_READY, TOKEN_NOT_READY,
TOKEN_ERROR TOKEN_ERROR
}; };
@ -134,6 +140,22 @@ static enum token get_multibyte(const char c, enum state *const state, enum endi
break; break;
case '8':
switch (*endianness)
{
case LITTLE_ENDIAN:
return TOKEN_LE64BIT;
case BIG_ENDIAN:
return TOKEN_BE64BIT;
default:
break;
}
break;
default: default:
break; 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); 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; *(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); *dst++ = *(src + 7);
*(uint8_t *)dst++ = *((const uint8_t *)src + 2); *dst++ = *(src + 6);
*(uint8_t *)dst++ = *((const uint8_t *)src + 1); *dst++ = *(src + 5);
*(uint8_t *)dst = *(const uint8_t *)src; *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()) if (little_endian())
{ {
swap32(dst, src); swap32(dst, src);
} }
else 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()) if (little_endian())
{ {
memmove(dst, src, SZ); memmove(dst, src, sz);
} }
else 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); *dst++ = *(src + 1);
*(uint8_t *)dst = *(const uint8_t *)src; *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()) if (little_endian())
{ {
swap16(dst, src); swap16(dst, src);
} }
else 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()) if (little_endian())
{ {
memmove(dst, src, SZ); memmove(dst, src, sz);
} }
else else
{ {
@ -271,7 +309,9 @@ enum serializer_err deserialize(const char *format,
[TOKEN_LE16BIT] = sizeof (uint16_t), [TOKEN_LE16BIT] = sizeof (uint16_t),
[TOKEN_BE16BIT] = sizeof (uint16_t), [TOKEN_BE16BIT] = sizeof (uint16_t),
[TOKEN_LE32BIT] = sizeof (uint32_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[] = static const size_t aligns[] =
@ -280,16 +320,20 @@ enum serializer_err deserialize(const char *format,
[TOKEN_LE16BIT] = _Alignof (uint16_t), [TOKEN_LE16BIT] = _Alignof (uint16_t),
[TOKEN_BE16BIT] = _Alignof (uint16_t), [TOKEN_BE16BIT] = _Alignof (uint16_t),
[TOKEN_LE32BIT] = _Alignof (uint32_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_8BIT] = read8,
[TOKEN_LE16BIT] = readle16, [TOKEN_LE16BIT] = readle16,
[TOKEN_BE16BIT] = readbe16, [TOKEN_BE16BIT] = readbe16,
[TOKEN_LE32BIT] = readle32, [TOKEN_LE32BIT] = readle32,
[TOKEN_BE32BIT] = readbe32 [TOKEN_BE32BIT] = readbe32,
[TOKEN_LE64BIT] = readle64,
[TOKEN_BE64BIT] = readbe64
}; };
const size_t st = sizes[token]; const size_t st = sizes[token];
@ -304,7 +348,7 @@ enum serializer_err deserialize(const char *format,
return SERIALIZER_ERR_IN_OVERFLOW; return SERIALIZER_ERR_IN_OVERFLOW;
else if (out_sz + st <= sz) 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; in_sz += st;
out_sz += st; out_sz += st;
state = 0; state = 0;

View File

@ -19,10 +19,6 @@
#include <stddef.h> #include <stddef.h>
#if __STDC_VERSION__ < 199901L
#error C99 support is mandatory for serializer
#endif /* __STDC_VERSION < 199901L */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {