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:
parent
71a3db14a5
commit
9e183ec0a6
24
README.md
24
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 <serializer.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -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.
|
||||
|
|
124
serializer.c
124
serializer.c
|
@ -20,6 +20,10 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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;
|
||||
|
|
|
@ -19,10 +19,6 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
#if __STDC_VERSION__ < 199901L
|
||||
#error C99 support is mandatory for serializer
|
||||
#endif /* __STDC_VERSION < 199901L */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue