ipdbot/node_modules/erlpack/cpp/encoder.h
2022-04-18 15:32:07 +02:00

237 lines
5.8 KiB
C

#include <stddef.h>
#include <stdlib.h>
#include "sysdep.h"
#include "constants.h"
#include <limits.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct erlpack_buffer {
char *buf;
size_t length;
size_t allocated_size;
} erlpack_buffer;
static inline int erlpack_buffer_write(erlpack_buffer *pk, const char *bytes,
size_t l) {
char *buf = pk->buf;
size_t allocated_size = pk->allocated_size;
size_t length = pk->length;
if (length + l > allocated_size) {
// Grow buffer 2x to avoid excessive re-allocations.
allocated_size = (length + l) * 2;
buf = (char *)realloc(buf, allocated_size);
if (!buf)
return -1;
}
memcpy(buf + length, bytes, l);
length += l;
pk->buf = buf;
pk->allocated_size = allocated_size;
pk->length = length;
return 0;
}
#define erlpack_append(pk, buf, len) \
return erlpack_buffer_write(pk, (const char *)buf, len)
static inline int erlpack_append_version(erlpack_buffer *b) {
static unsigned char buf[1] = {FORMAT_VERSION};
erlpack_append(b, buf, 1);
}
static inline int erlpack_append_nil(erlpack_buffer *b) {
static unsigned char buf[5] = {SMALL_ATOM_EXT, 3, 'n', 'i', 'l'};
erlpack_append(b, buf, 5);
}
static inline int erlpack_append_false(erlpack_buffer *b) {
static unsigned char buf[7] = {SMALL_ATOM_EXT, 5, 'f', 'a', 'l', 's', 'e'};
erlpack_append(b, buf, 7);
}
static inline int erlpack_append_true(erlpack_buffer *b) {
static unsigned char buf[6] = {SMALL_ATOM_EXT, 4, 't', 'r', 'u', 'e'};
erlpack_append(b, buf, 6);
}
static inline int erlpack_append_small_integer(erlpack_buffer *b,
unsigned char d) {
unsigned char buf[2] = {SMALL_INTEGER_EXT, d};
erlpack_append(b, buf, 2);
}
static inline int erlpack_append_integer(erlpack_buffer *b, int32_t d) {
unsigned char buf[5];
buf[0] = INTEGER_EXT;
_erlpack_store32(buf + 1, d);
erlpack_append(b, buf, 5);
}
static inline int erlpack_append_unsigned_long_long(erlpack_buffer *b,
unsigned long long d) {
unsigned char buf[1 + 2 + sizeof(unsigned long long)];
buf[0] = SMALL_BIG_EXT;
unsigned char bytes_enc = 0;
while (d > 0) {
buf[3 + bytes_enc] = d & 0xFF;
d >>= 8;
bytes_enc++;
}
buf[1] = bytes_enc;
buf[2] = 0;
erlpack_append(b, buf, 1 + 2 + bytes_enc);
}
static inline int erlpack_append_long_long(erlpack_buffer *b, long long d) {
unsigned char buf[1 + 2 + sizeof(unsigned long long)];
buf[0] = SMALL_BIG_EXT;
buf[2] = d < 0 ? 1 : 0;
unsigned long long ull = d < 0 ? -d : d;
unsigned char bytes_enc = 0;
while (ull > 0) {
buf[3 + bytes_enc] = ull & 0xFF;
ull >>= 8;
bytes_enc++;
}
buf[1] = bytes_enc;
erlpack_append(b, buf, 1 + 2 + bytes_enc);
}
typedef union {
uint64_t ui64;
double df;
} typePunner;
static inline int erlpack_append_double(erlpack_buffer *b, double f) {
unsigned char buf[1 + 8] = {0};
buf[0] = NEW_FLOAT_EXT;
typePunner p;
p.df = f;
_erlpack_store64(buf + 1, p.ui64);
erlpack_append(b, buf, 1 + 8);
}
static inline int erlpack_append_atom(erlpack_buffer *b, const char *bytes, size_t size) {
if (size < 255) {
unsigned char buf[2] = {SMALL_ATOM_EXT, (unsigned char)size};
int ret = erlpack_buffer_write(b, (const char *)buf, 2);
if (ret < 0)
return ret;
erlpack_append(b, bytes, size);
} else {
unsigned char buf[3];
buf[0] = ATOM_EXT;
if (size > 0xFFFF) {
return 1;
}
_erlpack_store16(buf + 1, size);
int ret = erlpack_buffer_write(b, (const char *)buf, 3);
if (ret < 0)
return ret;
erlpack_append(b, bytes, size);
}
}
static inline int erlpack_append_atom_utf8(erlpack_buffer *b, const char *bytes, size_t size) {
if (size < 255) {
unsigned char buf[2] = {SMALL_ATOM_UTF8_EXT, (unsigned char)size};
int ret = erlpack_buffer_write(b, (const char *)buf, 2);
if (ret < 0)
return ret;
erlpack_append(b, bytes, size);
} else {
unsigned char buf[3];
buf[0] = ATOM_UTF8_EXT;
if (size > 0xFFFF) {
return 1;
}
_erlpack_store16(buf + 1, size);
int ret = erlpack_buffer_write(b, (const char *)buf, 3);
if (ret < 0)
return ret;
erlpack_append(b, bytes, size);
}
}
static inline int erlpack_append_binary(erlpack_buffer *b, const char *bytes, size_t size) {
unsigned char buf[5];
buf[0] = BINARY_EXT;
_erlpack_store32(buf + 1, size);
int ret = erlpack_buffer_write(b, (const char *)buf, 5);
if (ret < 0)
return ret;
erlpack_append(b, bytes, size);
}
static inline int erlpack_append_string(erlpack_buffer *b, const char *bytes, size_t size) {
unsigned char buf[3];
buf[0] = STRING_EXT;
_erlpack_store16(buf + 1, size);
int ret = erlpack_buffer_write(b, (const char *)buf, 3);
if (ret < 0)
return ret;
erlpack_append(b, bytes, size);
}
static inline int erlpack_append_tuple_header(erlpack_buffer *b, size_t size) {
if (size < 256) {
unsigned char buf[2];
buf[0] = SMALL_TUPLE_EXT;
buf[1] = (unsigned char)size;
erlpack_append(b, buf, 2);
} else {
unsigned char buf[5];
buf[0] = LARGE_TUPLE_EXT;
_erlpack_store32(buf + 1, size);
erlpack_append(b, buf, 5);
}
}
static inline int erlpack_append_nil_ext(erlpack_buffer *b) {
static unsigned char buf[1] = {NIL_EXT};
erlpack_append(b, buf, 1);
}
static inline int erlpack_append_list_header(erlpack_buffer *b, size_t size) {
unsigned char buf[5];
buf[0] = LIST_EXT;
_erlpack_store32(buf + 1, size);
erlpack_append(b, buf, 5);
}
static inline int erlpack_append_map_header(erlpack_buffer *b, size_t size) {
unsigned char buf[5];
buf[0] = MAP_EXT;
_erlpack_store32(buf + 1, size);
erlpack_append(b, buf, 5);
}
#ifdef __cplusplus
}
#endif