/* * MessagePack unpacking routine template * * Copyright (C) 2008-2010 FURUHASHI Sadayuki * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef msgpack_unpack_func #error msgpack_unpack_func template is not defined #endif #ifndef msgpack_unpack_callback #error msgpack_unpack_callback template is not defined #endif #ifndef msgpack_unpack_struct #error msgpack_unpack_struct template is not defined #endif #ifndef msgpack_unpack_struct_decl #define msgpack_unpack_struct_decl(name) msgpack_unpack_struct(name) #endif #ifndef msgpack_unpack_object #error msgpack_unpack_object type is not defined #endif #ifndef msgpack_unpack_user #error msgpack_unpack_user type is not defined #endif #ifndef USE_CASE_RANGE #if !defined(_MSC_VER) #define USE_CASE_RANGE #endif #endif msgpack_unpack_struct_decl(_stack) { msgpack_unpack_object obj; size_t count; unsigned int ct; msgpack_unpack_object map_key; }; msgpack_unpack_struct_decl(_context) { msgpack_unpack_user user; unsigned int cs; unsigned int trail; unsigned int top; /* msgpack_unpack_struct(_stack)* stack; unsigned int stack_size; msgpack_unpack_struct(_stack) embed_stack[MSGPACK_EMBED_STACK_SIZE]; */ msgpack_unpack_struct(_stack) stack[MSGPACK_EMBED_STACK_SIZE]; }; msgpack_unpack_func(void, _init)(msgpack_unpack_struct(_context)* ctx) { ctx->cs = MSGPACK_CS_HEADER; ctx->trail = 0; ctx->top = 0; /* ctx->stack = ctx->embed_stack; ctx->stack_size = MSGPACK_EMBED_STACK_SIZE; */ ctx->stack[0].obj = msgpack_unpack_callback(_root)(&ctx->user); } /* msgpack_unpack_func(void, _destroy)(msgpack_unpack_struct(_context)* ctx) { if(ctx->stack_size != MSGPACK_EMBED_STACK_SIZE) { free(ctx->stack); } } */ msgpack_unpack_func(msgpack_unpack_object, _data)(msgpack_unpack_struct(_context)* ctx) { return (ctx)->stack[0].obj; } msgpack_unpack_func(int, _execute)(msgpack_unpack_struct(_context)* ctx, const char* data, size_t len, size_t* off) { assert(len >= *off); const unsigned char* p = (unsigned char*)data + *off; const unsigned char* const pe = (unsigned char*)data + len; const void* n = NULL; unsigned int trail = ctx->trail; unsigned int cs = ctx->cs; unsigned int top = ctx->top; msgpack_unpack_struct(_stack)* stack = ctx->stack; /* unsigned int stack_size = ctx->stack_size; */ msgpack_unpack_user* user = &ctx->user; msgpack_unpack_object obj; msgpack_unpack_struct(_stack)* c = NULL; int ret; #define push_simple_value(func) \ if(msgpack_unpack_callback(func)(user, &obj) < 0) { goto _failed; } \ goto _push #define push_fixed_value(func, arg) \ if(msgpack_unpack_callback(func)(user, arg, &obj) < 0) { goto _failed; } \ goto _push #define push_variable_value(func, base, pos, len) \ if(msgpack_unpack_callback(func)(user, \ (const char*)base, (const char*)pos, len, &obj) < 0) { goto _failed; } \ goto _push #define again_fixed_trail(_cs, trail_len) \ trail = trail_len; \ cs = _cs; \ goto _fixed_trail_again #define again_fixed_trail_if_zero(_cs, trail_len, ifzero) \ trail = trail_len; \ if(trail == 0) { goto ifzero; } \ cs = _cs; \ goto _fixed_trail_again #define start_container(func, count_, ct_) \ if(top >= MSGPACK_EMBED_STACK_SIZE) { goto _failed; } /* FIXME */ \ if(msgpack_unpack_callback(func)(user, count_, &stack[top].obj) < 0) { goto _failed; } \ if((count_) == 0) { obj = stack[top].obj; goto _push; } \ stack[top].ct = ct_; \ stack[top].count = count_; \ ++top; \ /*printf("container %d count %d stack %d\n",stack[top].obj,count_,top);*/ \ /*printf("stack push %d\n", top);*/ \ /* FIXME \ if(top >= stack_size) { \ if(stack_size == MSGPACK_EMBED_STACK_SIZE) { \ size_t csize = sizeof(msgpack_unpack_struct(_stack)) * MSGPACK_EMBED_STACK_SIZE; \ size_t nsize = csize * 2; \ msgpack_unpack_struct(_stack)* tmp = (msgpack_unpack_struct(_stack)*)malloc(nsize); \ if(tmp == NULL) { goto _failed; } \ memcpy(tmp, ctx->stack, csize); \ ctx->stack = stack = tmp; \ ctx->stack_size = stack_size = MSGPACK_EMBED_STACK_SIZE * 2; \ } else { \ size_t nsize = sizeof(msgpack_unpack_struct(_stack)) * ctx->stack_size * 2; \ msgpack_unpack_struct(_stack)* tmp = (msgpack_unpack_struct(_stack)*)realloc(ctx->stack, nsize); \ if(tmp == NULL) { goto _failed; } \ ctx->stack = stack = tmp; \ ctx->stack_size = stack_size = stack_size * 2; \ } \ } \ */ \ goto _header_again #define NEXT_CS(p) \ ((unsigned int)*p & 0x1f) #ifdef USE_CASE_RANGE #define SWITCH_RANGE_BEGIN switch(*p) { #define SWITCH_RANGE(FROM, TO) case FROM ... TO: #define SWITCH_RANGE_DEFAULT default: #define SWITCH_RANGE_END } #else #define SWITCH_RANGE_BEGIN { if(0) { #define SWITCH_RANGE(FROM, TO) } else if(FROM <= *p && *p <= TO) { #define SWITCH_RANGE_DEFAULT } else { #define SWITCH_RANGE_END } } #endif if(p == pe) { goto _out; } do { switch(cs) { case MSGPACK_CS_HEADER: SWITCH_RANGE_BEGIN SWITCH_RANGE(0x00, 0x7f) // Positive Fixnum push_fixed_value(_uint8, *(uint8_t*)p); SWITCH_RANGE(0xe0, 0xff) // Negative Fixnum push_fixed_value(_int8, *(int8_t*)p); SWITCH_RANGE(0xc0, 0xdf) // Variable switch(*p) { case 0xc0: // nil push_simple_value(_nil); //case 0xc1: // string // again_terminal_trail(NEXT_CS(p), p+1); case 0xc2: // false push_simple_value(_false); case 0xc3: // true push_simple_value(_true); case 0xc4: // bin 8 case 0xc5: // bin 16 case 0xc6: // bin 32 again_fixed_trail(NEXT_CS(p), 1 << (((unsigned int)*p) & 0x03)); case 0xc7: // ext 8 case 0xc8: // ext 16 case 0xc9: // ext 32 again_fixed_trail(NEXT_CS(p), 1 << ((((unsigned int)*p) + 1) & 0x03)); case 0xca: // float case 0xcb: // double case 0xcc: // unsigned int 8 case 0xcd: // unsigned int 16 case 0xce: // unsigned int 32 case 0xcf: // unsigned int 64 case 0xd0: // signed int 8 case 0xd1: // signed int 16 case 0xd2: // signed int 32 case 0xd3: // signed int 64 again_fixed_trail(NEXT_CS(p), 1 << (((unsigned int)*p) & 0x03)); case 0xd4: // fixext 1 case 0xd5: // fixext 2 case 0xd6: // fixext 4 case 0xd7: // fixext 8 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, (1 << (((unsigned int)*p) & 0x03)) + 1, _ext_zero); case 0xd8: // fixext 16 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 16+1, _ext_zero); case 0xd9: // str 8 case 0xda: // str 16 case 0xdb: // str 32 again_fixed_trail(NEXT_CS(p), 1 << ((((unsigned int)*p) & 0x03) - 1)); case 0xdc: // array 16 case 0xdd: // array 32 case 0xde: // map 16 case 0xdf: // map 32 again_fixed_trail(NEXT_CS(p), 2u << (((unsigned int)*p) & 0x01)); default: goto _failed; } SWITCH_RANGE(0xa0, 0xbf) // FixStr again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE, ((unsigned int)*p & 0x1f), _str_zero); SWITCH_RANGE(0x90, 0x9f) // FixArray start_container(_array, ((unsigned int)*p) & 0x0f, MSGPACK_CT_ARRAY_ITEM); SWITCH_RANGE(0x80, 0x8f) // FixMap start_container(_map, ((unsigned int)*p) & 0x0f, MSGPACK_CT_MAP_KEY); SWITCH_RANGE_DEFAULT goto _failed; SWITCH_RANGE_END // end MSGPACK_CS_HEADER _fixed_trail_again: ++p; default: if((size_t)(pe - p) < trail) { goto _out; } n = p; p += trail - 1; switch(cs) { //case MSGPACK_CS_ //case MSGPACK_CS_ case MSGPACK_CS_FLOAT: { union { uint32_t i; float f; } mem; _msgpack_load32(uint32_t, n, &mem.i); push_fixed_value(_float, mem.f); } case MSGPACK_CS_DOUBLE: { union { uint64_t i; double f; } mem; _msgpack_load64(uint64_t, n, &mem.i); #if defined(__arm__) && !(__ARM_EABI__) // arm-oabi // https://github.com/msgpack/msgpack-perl/pull/1 mem.i = (mem.i & 0xFFFFFFFFUL) << 32UL | (mem.i >> 32UL); #endif push_fixed_value(_double, mem.f); } case MSGPACK_CS_UINT_8: push_fixed_value(_uint8, *(uint8_t*)n); case MSGPACK_CS_UINT_16:{ uint16_t tmp; _msgpack_load16(uint16_t,n,&tmp); push_fixed_value(_uint16, tmp); } case MSGPACK_CS_UINT_32:{ uint32_t tmp; _msgpack_load32(uint32_t,n,&tmp); push_fixed_value(_uint32, tmp); } case MSGPACK_CS_UINT_64:{ uint64_t tmp; _msgpack_load64(uint64_t,n,&tmp); push_fixed_value(_uint64, tmp); } case MSGPACK_CS_INT_8: push_fixed_value(_int8, *(int8_t*)n); case MSGPACK_CS_INT_16:{ int16_t tmp; _msgpack_load16(int16_t,n,&tmp); push_fixed_value(_int16, tmp); } case MSGPACK_CS_INT_32:{ int32_t tmp; _msgpack_load32(int32_t,n,&tmp); push_fixed_value(_int32, tmp); } case MSGPACK_CS_INT_64:{ int64_t tmp; _msgpack_load64(int64_t,n,&tmp); push_fixed_value(_int64, tmp); } case MSGPACK_CS_FIXEXT_1: again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 1+1, _ext_zero); case MSGPACK_CS_FIXEXT_2: again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 2+1, _ext_zero); case MSGPACK_CS_FIXEXT_4: again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 4+1, _ext_zero); case MSGPACK_CS_FIXEXT_8: again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 8+1, _ext_zero); case MSGPACK_CS_FIXEXT_16: again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 16+1, _ext_zero); case MSGPACK_CS_STR_8: again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE, *(uint8_t*)n, _str_zero); case MSGPACK_CS_BIN_8: again_fixed_trail_if_zero(MSGPACK_ACS_BIN_VALUE, *(uint8_t*)n, _bin_zero); case MSGPACK_CS_EXT_8: again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, (*(uint8_t*)n) + 1, _ext_zero); case MSGPACK_CS_STR_16:{ uint16_t tmp; _msgpack_load16(uint16_t,n,&tmp); again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE, tmp, _str_zero); } case MSGPACK_CS_BIN_16:{ uint16_t tmp; _msgpack_load16(uint16_t,n,&tmp); again_fixed_trail_if_zero(MSGPACK_ACS_BIN_VALUE, tmp, _bin_zero); } case MSGPACK_CS_EXT_16:{ uint16_t tmp; _msgpack_load16(uint16_t,n,&tmp); again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, tmp + 1, _ext_zero); } case MSGPACK_CS_STR_32:{ uint32_t tmp; _msgpack_load32(uint32_t,n,&tmp); again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE, tmp, _str_zero); } case MSGPACK_CS_BIN_32:{ uint32_t tmp; _msgpack_load32(uint32_t,n,&tmp); again_fixed_trail_if_zero(MSGPACK_ACS_BIN_VALUE, tmp, _bin_zero); } case MSGPACK_CS_EXT_32:{ uint32_t tmp; _msgpack_load32(uint32_t,n,&tmp); again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, tmp + 1, _ext_zero); } case MSGPACK_ACS_STR_VALUE: _str_zero: push_variable_value(_str, data, n, trail); case MSGPACK_ACS_BIN_VALUE: _bin_zero: push_variable_value(_bin, data, n, trail); case MSGPACK_ACS_EXT_VALUE: _ext_zero: push_variable_value(_ext, data, n, trail); case MSGPACK_CS_ARRAY_16:{ uint16_t tmp; _msgpack_load16(uint16_t,n,&tmp); start_container(_array, tmp, MSGPACK_CT_ARRAY_ITEM); } case MSGPACK_CS_ARRAY_32:{ /* FIXME security guard */ uint32_t tmp; _msgpack_load32(uint32_t,n,&tmp); start_container(_array, tmp, MSGPACK_CT_ARRAY_ITEM); } case MSGPACK_CS_MAP_16:{ uint16_t tmp; _msgpack_load16(uint16_t,n,&tmp); start_container(_map, tmp, MSGPACK_CT_MAP_KEY); } case MSGPACK_CS_MAP_32:{ /* FIXME security guard */ uint32_t tmp; _msgpack_load32(uint32_t,n,&tmp); start_container(_map, tmp, MSGPACK_CT_MAP_KEY); } default: goto _failed; } } _push: if(top == 0) { goto _finish; } c = &stack[top-1]; switch(c->ct) { case MSGPACK_CT_ARRAY_ITEM: if(msgpack_unpack_callback(_array_item)(user, &c->obj, obj) < 0) { goto _failed; } if(--c->count == 0) { obj = c->obj; --top; /*printf("stack pop %d\n", top);*/ goto _push; } goto _header_again; case MSGPACK_CT_MAP_KEY: c->map_key = obj; c->ct = MSGPACK_CT_MAP_VALUE; goto _header_again; case MSGPACK_CT_MAP_VALUE: if(msgpack_unpack_callback(_map_item)(user, &c->obj, c->map_key, obj) < 0) { goto _failed; } if(--c->count == 0) { obj = c->obj; --top; /*printf("stack pop %d\n", top);*/ goto _push; } c->ct = MSGPACK_CT_MAP_KEY; goto _header_again; default: goto _failed; } _header_again: cs = MSGPACK_CS_HEADER; ++p; } while(p != pe); goto _out; _finish: stack[0].obj = obj; ++p; ret = 1; /*printf("-- finish --\n"); */ goto _end; _failed: /*printf("** FAILED **\n"); */ ret = -1; goto _end; _out: ret = 0; goto _end; _end: ctx->cs = cs; ctx->trail = trail; ctx->top = top; *off = (size_t)(p - (const unsigned char*)data); return ret; } #undef msgpack_unpack_func #undef msgpack_unpack_callback #undef msgpack_unpack_struct #undef msgpack_unpack_object #undef msgpack_unpack_user #undef push_simple_value #undef push_fixed_value #undef push_variable_value #undef again_fixed_trail #undef again_fixed_trail_if_zero #undef start_container #undef NEXT_CS #undef SWITCH_RANGE_BEGIN #undef SWITCH_RANGE #undef SWITCH_RANGE_DEFAULT #undef SWITCH_RANGE_END