123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- #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_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
|