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
|
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.
|
|
||||||
|
|
124
serializer.c
124
serializer.c
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue