#include "msgpack.h" #include // endianness #include // memcpy #define EXPAND_CALL(c, ...) c(__VA_ARGS__) #define CAR(a, b) a #define CDR(a, b) b #define INT int #define UINT uint #define htobe8(i) (i) #define be8toh(i) (i) #define _HTOI(bits, i) htobe##bits(i) #define _ITOH(bits, i) be##bits##toh(i) #define CONV_ALL(...) __VA_ARGS__ #define CONV_TYPE(t, b) t##b##_t #define CONV_BITS(t, b) b #define ITOH(c, i) ((CONV_TYPE c)EXPAND_CALL(_ITOH, CONV_BITS c, i)) #define HTOI(c, h) ((CONV_TYPE c)EXPAND_CALL(_HTOI, CONV_BITS c, i)) #define PTOH(c, p) ((CONV_TYPE c)EXPAND_CALL(_ITOH, CONV_BITS c, (*(CONV_TYPE c*)(p)))) #define HTOP2(c, h, p) (((*(CONV_TYPE c *)(p)) = EXPAND_CALL(_HTOI, CONV_BITS c, h))) #define ITOF(bits, v) (((union {uint32_t u32; float f32; uint64_t u64; double f64;}){.u##bits = v}).f##bits) #define FTOI(bits, v) (((union {uint32_t u32; float f32; uint64_t u64; double f64;}){.f##bits = v}).u##bits) #define PTOH_F(c, p) EXPAND_CALL(ITOF, CONV_ALL c, PTOH((UINT, CONV_ALL c), p)) // possibly remove #define HTOP2_F(c, f, p) HTOP2((UINT, CONV_ALL c), EXPAND_CALL(FTOI, CONV_ALL c, f), p) // possibly remove // range low, range high #define RANGES(X) \ X(0x00, 0x7F) \ X(0x80, 0x8F) \ X(0x90, 0x9F) \ X(0xA0, 0xBF) \ X(0xE0, 0xFF) // byte, format, type #define FORMAT_NIL(X) \ X(0xC0, FMT_NIL, MSGPACK_NIL) #define FORMAT_UNKNOWN(X) \ X(0xC1, FMT_UNKNOWN, MSGPACK_UNKNOWN) // byte, format, type, data #define FORMAT_BOOL(X) \ X(0xC2, FMT_BOOL_TRUE, MSGPACK_BOOL, true) \ X(0xC3, FMT_BOOL_FALSE, MSGPACK_BOOL, false) // byte, format, type, subtype, offset, lengh, field, conv, range #define FORMAT_INT(X) \ X(0x00, FMT_FIX_UINT, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 0, 1, u, (UINT, 8), (0, 127)) \ X(0XE0, FMT_FIX_INT, MSGPACK_INT, MSGPACK_INT_SIGNED, 0, 1, i, (INT, 8), (-32, -1)) \ X(0xCC, FMT_U8, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 1, u, (UINT, 8), (0, UINT8_MAX)) \ X(0xCD, FMT_U16, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 2, u, (UINT, 16), (0, UINT16_MAX)) \ X(0xCE, FMT_U32, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 4, u, (UINT, 32), (0, UINT32_MAX)) \ X(0xCF, FMT_U64, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 8, u, (UINT, 64), (0, UINT64_MAX)) \ X(0xD0, FMT_I8, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 1, i, (INT, 8), (INT8_MIN, INT8_MAX)) \ X(0xD1, FMT_I16, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 2, i, (INT, 16), (INT16_MIN, INT16_MAX)) \ X(0xD2, FMT_I32, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 4, i, (INT, 32), (INT32_MIN, INT32_MAX)) \ X(0xD3, FMT_I64, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 8, i, (INT, 64), (INT64_MIN, INT64_MAX)) // byte, format, type, subtype, offset, length, field, conv #define FORMAT_FLOAT(X) \ X(0xCA, FMT_FLOAT, MSGPACK_FLOAT, MSGPACK_FLOAT_32, 1, 4, f, (32)) \ X(0xCB, FMT_DOUBLE, MSGPACK_FLOAT, MSGPACK_FLOAT_64, 1, 8, d, (64)) // byte, fmt, type, subtype, offset, conv, max #define FORMAT_RAW(X) \ X(0xA0, FMT_FIX_STR, MSGPACK_RAW, MSGPACK_RAW_STRING, 1, (UINT, 8), 31) \ X(0xC4, FMT_BIN8, MSGPACK_RAW, MSGPACK_RAW_BIN, 2, (UINT, 8), UINT8_MAX) \ X(0xC5, FMT_BIN16, MSGPACK_RAW, MSGPACK_RAW_BIN, 3, (UINT, 16), UINT16_MAX) \ X(0xC6, FMT_BIN32, MSGPACK_RAW, MSGPACK_RAW_BIN, 5, (UINT, 32), UINT32_MAX) \ X(0xD9, FMT_STR8, MSGPACK_RAW, MSGPACK_RAW_STRING, 2, (UINT, 8), UINT8_MAX) \ X(0xDA, FMT_STR16, MSGPACK_RAW, MSGPACK_RAW_STRING, 3, (UINT, 16), UINT16_MAX) \ X(0xDB, FMT_STR32, MSGPACK_RAW, MSGPACK_RAW_STRING, 5, (UINT, 32), UINT32_MAX) // // byte, fmt, type, elements, offset, lenght // #define FORMAT_ARRAY(X) \ // X(0x90, FMT_FIX_ARRAY, MSGPACK_ARRAY, pack->bin[0] & 0x0F, 1, elements_length(pack, fmt)) \ // X(0xDC, FMT_ARRAY16, MSGPACK_ARRAY, UINT16_H(pack->bin+1), 3, elements_length(pack, fmt)) \ // X(0xDD, FMT_ARRAY32, MSGPACK_ARRAY, UINT32_H(pack->bin+1), 5, elements_length(pack, fmt)) // #define FORMAT_MAP(X) \ // X(0x80, FMT_FIX_MAP, MSGPACK_MAP, 2 * (pack->bin[0] & 0x0F), 1, elements_length(pack, fmt)) \ // X(0xDE, FMT_MAP16, MSGPACK_MAP, 2 * (UINT16_H(pack->bin+1)), 3, elements_length(pack, fmt)) \ // X(0xDF, FMT_MAP32, MSGPACK_MAP, 2 * (UINT32_H(pack->bin+1)), 5, elements_length(pack, fmt)) // #define FORMAT_EXT(X) #define FORMATS(X) \ FORMAT_NIL (X) \ FORMAT_UNKNOWN(X) \ FORMAT_BOOL (X) \ FORMAT_INT (X) \ FORMAT_FLOAT (X) \ FORMAT_RAW (X) \ // FORMAT_ARRAY (X) \ // FORMAT_MAP (X) \ // FORMAT_EXT (X) #define X_FMT_ENUM(_byte, fmt, ...) fmt, #define X_FMT_TYPE(_byte, fmt, type, ...) [fmt] = type, #define X_BYTE_FMT( byte, fmt, ...) [byte] = fmt, enum msgpack_fmt { FORMATS(X_FMT_ENUM) }; static const enum msgpack_type fmt_to_type[] = { FORMATS(X_FMT_TYPE) }; static const enum msgpack_fmt byte_to_fmt[] = { FORMATS(X_BYTE_FMT) }; // --- helper macros --- // #define SUCCESS(type) SUCCESS2(type, 0) #define SUCCESS2(type, rest) \ (((rest) << 6) | (type)) #define ERROR(type, err) ERROR2(type, err, 0) #define ERROR2(type, err, rest) \ ((1 << (sizeof(int)*8-1))| ((rest) << 6) | ((err) << 3) | (type)) #define ENOUGH_BYTES(pack, n, on_fail) \ if((pack)->size < (n)) { on_fail; } #define MOVE_PACK(pack, sz) \ do { \ (pack)->bin += (sz); \ (pack)->size -= (sz); \ } while(0) static enum msgpack_fmt pack_fmt(msgpack_t *pack); static enum msgpack_fmt data_fmt(enum msgpack_type type, enum msgpack_type subtype, const void *m); #define FMT_FOR_READ(pack, type, subtype, m) pack_fmt(pack) #define FMT_FOR_WRITE(pack, type, subtype, m) data_fmt(type, subtype, m) // --- function composition --- // // these will be shadowed unless missing in parameters const void * const m = (void *)1; const enum msgpack_type subtype; #define COMPOSE_FUNCTION(op, type) \ { \ if(!pack || !pack->bin || pack->size == 0) \ return ERROR(MSGPACK_##type, MSGPACK_ERROR_INVALID_PACK); \ if(!m) \ return ERROR(MSGPACK_##type, MSGPACK_ERROR_INVALID_ARGUMENT); \ \ const enum msgpack_fmt fmt = \ FMT_FOR_##op(pack, MSGPACK_##type, subtype, m); \ \ switch(fmt) { \ FORMAT_##type(X_##type##_##op) \ default: \ return ERROR2(MSGPACK_##type, MSGPACK_ERROR_WRONG_TYPE, \ fmt_to_type[fmt]); \ } \ } // TODO: refactor these things, they are hard to read #define OP_BOOL_READ(x_byte, pack, m, x_data) \ *m = x_data #define OP_BOOL_WRITE(x_byte, pack, m, x_data) \ pack->bin[0] = x_byte #define MAKE_X_BOOL(op, x_byte, x_fmt, x_type, x_data) \ case x_fmt: \ OP_BOOL_##op(x_byte, pack, m, x_data); \ MOVE_PACK(pack, 1); \ return SUCCESS(x_type); #define OP_INT_READ(_byte, ptr, value, x_conv) \ value = PTOH(x_conv, ptr) #define OP_INT_WRITE(x_byte, ptr, value, x_conv) \ (ptr-1)[0] = x_byte; /* temp fix*/ \ HTOP2(x_conv, value, ptr) #define OP_FLOAT_READ(_byte, ptr, value, x_conv) \ value = PTOH_F(x_conv, ptr) #define OP_FLOAT_WRITE(x_byte, ptr, value, x_conv) \ (ptr-1)[0] = x_byte; /* temp fix*/ \ HTOP2_F(x_conv, value, ptr) #define MAKE_X_INTORFLOAT(type, op, x_byte, x_fmt, x_type, x_subtype, x_offset, x_length, x_field, x_conv, ...) \ case x_fmt: \ ENOUGH_BYTES(pack, (x_offset) + (x_length), \ return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \ OP_##type##_##op(x_byte, pack->bin + (x_offset), m->x_field, x_conv); \ \ MOVE_PACK(pack, (x_offset) + (x_length)); \ return SUCCESS2(x_type, x_subtype); #define OP_RAW_LENGTH_READ(x_fmt, x_conv) \ (x_fmt == FMT_FIX_STR) ? PTOH(x_conv, pack->bin) & 0x1F \ : PTOH(x_conv, pack->bin + 1); #define OP_RAW_LENGTH_WRITE(x_fmt, x_conv) m->size #define OP_RAW_READ(x_byte, x_offset, x_conv) \ m->size = length; \ m->bin = pack->bin + (x_offset); #define OP_RAW_WRITE(x_byte, x_offset, x_conv) \ pack->bin[0] = x_byte; \ if (fmt == FMT_FIX_STR) pack->bin[0] |= (uint8_t)length; \ else HTOP2(x_conv, length, pack->bin+1); \ memcpy(pack->bin+(x_offset), m->bin, m->size); #define MAKE_X_RAW(op, x_byte, x_fmt, x_type, x_subtype, x_offset, x_conv, ...) \ case x_fmt: { \ ENOUGH_BYTES(pack, (x_offset), \ return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \ size_t length = OP_RAW_LENGTH_##op(x_fmt, x_conv); \ \ ENOUGH_BYTES(pack, (x_offset) + length, \ return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \ OP_RAW_##op(x_byte, x_offset, x_conv); \ \ MOVE_PACK(pack, (x_offset) + length); \ return SUCCESS2(x_type, x_subtype); \ } // --- api implemention --- // #define X_BOOL_READ(...) MAKE_X_BOOL(READ, __VA_ARGS__) #define X_INT_READ(...) MAKE_X_INTORFLOAT(INT, READ, __VA_ARGS__) #define X_FLOAT_READ(...) MAKE_X_INTORFLOAT(FLOAT, READ, __VA_ARGS__) #define X_RAW_READ(...) MAKE_X_RAW(READ, __VA_ARGS__) #define X_BOOL_WRITE(...) MAKE_X_BOOL(WRITE, __VA_ARGS__) #define X_INT_WRITE(...) MAKE_X_INTORFLOAT(INT, WRITE, __VA_ARGS__) #define X_FLOAT_WRITE(...) MAKE_X_INTORFLOAT(FLOAT, WRITE, __VA_ARGS__) #define X_RAW_WRITE(...) MAKE_X_RAW(WRITE, __VA_ARGS__) // int msgpack_read_nil (msgpack_t *pack); int msgpack_read_bool (msgpack_t *pack, bool *m) COMPOSE_FUNCTION(READ, BOOL) int msgpack_read_int (msgpack_t *pack, union mp_int *m) COMPOSE_FUNCTION(READ, INT) int msgpack_read_float (msgpack_t *pack, union mp_float *m) COMPOSE_FUNCTION(READ, FLOAT) int msgpack_read_raw (msgpack_t *pack, struct mp_bin *m) COMPOSE_FUNCTION(READ, RAW) // int msgpack_read_raw_cpy (msgpack_t *pack, struct mp_bin *m); // int msgpack_read_ext (msgpack_t *pack, struct mp_bin *m) COMPOSE_FUNCTION(READ, EXT) // int msgpack_read_ext_cpy (msgpack_t *pack, struct mp_bin *m); // int msgpack_read_array (msgpack_t *pack, size_t *m) COMPOSE_FUNCTION(READ, ARRAY) // int msgpack_read_map (msgpack_t *pack, size_t *m) COMPOSE_FUNCTION(READ, MAP) // int msgpack_read_array2 (const msgpack_t *pack, struct mp_array *m); // int msgpack_read_map2 (const msgpack_t *pack, struct mp_map *m); // int msgpack_write_nil (msgpack_t *pack); int msgpack_write_bool (msgpack_t *pack, const bool *m) COMPOSE_FUNCTION(WRITE, BOOL) int msgpack_write_int (msgpack_t *pack, const union mp_int *m, enum msgpack_type subtype) COMPOSE_FUNCTION(WRITE, INT) int msgpack_write_float (msgpack_t *pack, const union mp_float *m, enum msgpack_type subtype) COMPOSE_FUNCTION(WRITE, FLOAT) int msgpack_write_raw (msgpack_t *pack, const struct mp_bin *m, enum msgpack_type subtype) COMPOSE_FUNCTION(WRITE, RAW) // int msgpack_write_ext (msgpack_t *pack, const struct mp_bin *m, enum msgpack_type subtype); // int msgpack_write_array (msgpack_t *pack, const size_t *m); // int msgpack_write_map (msgpack_t *pack, const size_t *m); // --- helpers --- // #define X_MASK_RANGE(range_low, range_high) \ if(byte >= range_low && byte <= range_high) \ byte &= ~(uint8_t)(range_high-range_low); \ else \ static enum msgpack_fmt pack_fmt(msgpack_t *pack) { uint8_t byte = pack->bin[0]; RANGES(X_MASK_RANGE); return byte_to_fmt[byte]; } #define WRAP_FMT_BOOL(e) \ case MSGPACK_BOOL: switch((int)*(bool *)m) {e; default: break; } break; #define X_FMT_BOOL(_byte, x_fmt, x_type, x_data) \ case x_data: return x_fmt; #define WRAP_FMT_INT(e) \ case MSGPACK_INT: e; break; #define X_FMT_INT(_byte, x_fmt, x_type, x_subtype, _offset, _length, x_field, _conv, x_range) \ if((x_subtype == subtype) && \ (((union mp_int *)m)->x_field >= CAR x_range) && \ (((union mp_int *)m)->x_field <= CDR x_range)) \ return x_fmt; \ else #define WRAP_FMT_FLOAT(e) \ case MSGPACK_FLOAT: switch(subtype) {e; default: break; } break; #define X_FMT_FLOAT(_byte, x_fmt, _type, x_subtype, _offset, _length, _field, _conv) \ case x_subtype: return x_fmt; #define WRAP_FMT_RAW(e) \ case MSGPACK_RAW: e; break; #define X_FMT_RAW(_byte, x_fmt, x_type, x_subtype, _offset, _conv, x_range_max) \ if((x_subtype == subtype) && \ ((struct mp_bin *)m)->size <= x_range_max) return x_fmt; \ else static enum msgpack_fmt data_fmt(enum msgpack_type type, enum msgpack_type subtype, const void *m) { switch(type) { WRAP_FMT_BOOL(FORMAT_BOOL(X_FMT_BOOL)) WRAP_FMT_INT(FORMAT_INT(X_FMT_INT)) WRAP_FMT_FLOAT(FORMAT_FLOAT(X_FMT_FLOAT)) WRAP_FMT_RAW(FORMAT_RAW(X_FMT_RAW)) default: return FMT_UNKNOWN; } return FMT_UNKNOWN; }