#include "msgpack.h" #include // endianness #include // memcpy // TODO: fix all these #define PINT8_H(p) (*(int8_t*)(p)) #define PINT16_H(p) ((int16_t)be16toh(*(uint16_t *)(p))) #define PINT32_H(p) ((int32_t)be32toh(*(uint32_t *)(p))) #define PINT64_H(p) ((int64_t)be64toh(*(uint64_t *)(p))) #define PUINT8_H(p) (*(uint8_t*)(p)) #define PUINT16_H(p) (be16toh(*(uint16_t *)(p))) #define PUINT32_H(p) (be32toh(*(uint32_t *)(p))) #define PUINT64_H(p) (be64toh(*(uint64_t *)(p))) #define H_PINT8(b) (*(int8_t*)(b)) #define H_PINT16(b) ((int16_t)htobe16((int16_t)(b))) #define H_PINT32(b) ((int32_t)htobe32((int32_t)(b))) #define H_PINT64(b) ((int64_t)htobe64((int64_t)(b))) #define F32_H(b) (*(float *) &be32toh(*(uint32_t *)(b))) #define F64_H(b) (*(double *)&be64toh(*(uint64_t *)(b))) #define H_F32(b) (*(float *) &htobe32(*(uint32_t *)(b))) #define H_F64(b) (*(double *)&htobe64(*(uint64_t *)(b))) // 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 high, range low #define FORMAT_INT(X) \ X(0x00, FMT_FIX_UINT, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 0, 1, u, UINT8, 0, 127) \ X(0XE0, FMT_FIX_INT, MSGPACK_INT, MSGPACK_INT_SIGNED, 0, 1, i, INT8, -32, -1) \ X(0xCC, FMT_U8, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 1, u, UINT8, 0, UINT8_MAX) \ X(0xCD, FMT_U16, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 2, u, UINT16, 0, UINT16_MAX) \ X(0xCE, FMT_U32, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 4, u, UINT32, 0, UINT32_MAX) \ X(0xCF, FMT_U64, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 8, u, UINT64, 0, UINT64_MAX) \ X(0xD0, FMT_I8, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 1, i, INT8, INT8_MIN, INT8_MAX) \ X(0xD1, FMT_I16, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 2, i, INT16, INT16_MIN, INT16_MAX) \ X(0xD2, FMT_I32, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 4, i, INT32, INT32_MIN, INT32_MAX) \ X(0xD3, FMT_I64, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 8, i, INT64, 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, F32) \ X(0xCB, FMT_DOUBLE, MSGPACK_FLOAT, MSGPACK_FLOAT_64, 1, 8, d, F64) // // byte, fmt, type, subtype, offset, length, data // #define FORMAT_RAW(X) \ // X(0xA0, FMT_FIX_STR, MSGPACK_RAW, MSGPACK_RAW_STRING, 1, pack->bin[0] & 0x0F) \ // X(0xC4, FMT_BIN8, MSGPACK_RAW, MSGPACK_RAW_BIN, 1, pack->bin[1]) \ // X(0xC5, FMT_BIN16, MSGPACK_RAW, MSGPACK_RAW_BIN, 3, UINT16_H(pack->bin+1)) \ // X(0xC6, FMT_BIN32, MSGPACK_RAW, MSGPACK_RAW_BIN, 5, UINT32_H(pack->bin+1)) \ // X(0xD9, FMT_STR8, MSGPACK_RAW, MSGPACK_RAW_STRING, 1, pack->bin[1]) \ // X(0xDA, FMT_STR16, MSGPACK_RAW, MSGPACK_RAW_STRING, 3, UINT16_H(pack->bin+1)) \ // X(0xDB, FMT_STR32, MSGPACK_RAW, MSGPACK_RAW_STRING, 5, UINT32_H(pack->bin+1)) // // 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) }; // static size_t elements_length(msgpack_t *pack, enum msgpack_fmt fmt); // static size_t pack_size(msgpack_t *pack); // --- 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, 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); \ \ 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]); \ } \ } #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 = P##x_conv##_H(ptr) #define OP_INT_WRITE(x_byte, ptr, value, x_conv) #define MAKE_X_INT(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_INT_##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); // --- api implemention --- // #define X_BOOL_READ(...) MAKE_X_BOOL(READ, __VA_ARGS__) #define X_INT_READ(...) MAKE_X_INT(READ, __VA_ARGS__) int msgpack_read_nil (msgpack_t *pack);// COMPOSE_FUNCTION(READ, NIL) 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); #define X_BOOL_WRITE(...) MAKE_X_BOOL(WRITE, __VA_ARGS__) #define X_INT_WRITE(...) MAKE_X_INT(WRITE, __VA_ARGS__) 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); int msgpack_write_float (msgpack_t *pack, const union mp_float *m, enum msgpack_type subtype); // int msgpack_write_raw (msgpack_t *pack, const struct mp_bin *m, enum msgpack_type subtype); // 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(*(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_high, x_range_low) \ if((x_subtype == subtype) && \ (((union mp_int *)m)->x_field >= x_range_low) && \ (((union mp_int *)m)->x_field <= x_range_high)) \ return x_fmt; \ else static enum msgpack_fmt data_fmt(enum msgpack_type type, enum msgpack_type subtype, void *m) { switch(type) { WRAP_FMT_BOOL(FORMAT_BOOL(X_FMT_BOOL)) WRAP_FMT_INT(FORMAT_INT(X_FMT_INT)) default: return FMT_UNKNOWN; } return FMT_UNKNOWN; } // #define X_FLOAT(...) X_INT(__VA_ARGS__) // #define OP_RAW_READ(x_byte, pack, m, x_offset, x_length) \ // m->bin = pack->bin + (x_offset); \ // m->size = (x_length); \ // #define X_READ_RAW(op, x_byte, x_fmt, x_type, x_subtype, x_offset, x_length_expr) \ // case x_fmt: \ // ENOUGH_BYTES(pack, (x_offset), \ // return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \ // size_t length = x_length_expr; \ // ENOUGH_BYTES(pack, (size_t)(x_offset) + (x_length), \ // return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \ // OP_RAW_##op(x_byte, pack, m, (x_offset), (x_length)); \ // \ // MOVE_PACK(pack, (x_offset) + (x_length)); \ // return SUCCESS2(x_type, x_subtype); // #define X_READ_EXT(...) //X_READ_RAW(__VA_ARGS__) // #define X_READ_ARRAY(_byte, x_fmt, x_type, x_elements, x_offset, _length) \ // case x_fmt: \ // ENOUGH_BYTES(pack, (x_offset), \ // return ERROR(x_type, MSGPACK_ERROR_UNEXPECTED_END)); \ // *m = x_elements; \ // \ // MOVE_PACK(pack, (x_offset)); \ // return SUCCESS(x_type); // #define X_READ_MAP(...) X_READ_ARRAY(__VA_ARGS__) // #define X_COMPLEX_LENGTH(_byte, x_fmt, _type, x_elements, x_offset, x_length) \ // case x_fmt: { \ // ENOUGH_BYTES(pack, (x_offset), return 0); \ // offset = (x_offset); \ // elements = (x_elements); \ // } break; // static size_t elements_length(msgpack_t *pack, enum msgpack_fmt fmt) // { // size_t offset = 0; // size_t elements = 0; // switch(fmt) { // FORMAT_ARRAY(X_COMPLEX_LENGTH) // FORMAT_MAP(X_COMPLEX_LENGTH) // default: return 0; // } // for(size_t i = 0; i < elements; i++) { // msgpack_t new_pack = {pack->bin + offset, // pack->size - offset};//, pack->membuf}; // size_t len = pack_size(&new_pack); // if(len == 0) return 0; // offset += len; // ENOUGH_BYTES(pack, offset, return 0); // } // return offset; // } // #define X_PACK_SIZE(_byte, x_fmt, _type, _, x_offset, x_length, ...) \ // case x_fmt: { \ // ENOUGH_BYTES(pack, (x_offset), return 0); \ // offset = (x_offset); \ // length = (x_length); \ // } break; // static size_t pack_size(msgpack_t *pack) // { // enum msgpack_fmt fmt = pack_fmt(pack); // size_t offset = 0; // size_t length = 0; // switch(fmt) { // FORMATS(X_PACK_SIZE) // default: return 0; // } // if(fmt_to_type[fmt] == MSGPACK_ARRAY || fmt_to_type[fmt] == MSGPACK_MAP) // if(length == 0) return 0; // return offset + length; // }