mirror of
				https://github.com/msgpack/msgpack-python.git
				synced 2025-10-31 09:30:53 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			423 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			423 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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 USE_CASE_RANGE
 | |
| #if !defined(_MSC_VER)
 | |
| #define USE_CASE_RANGE
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| typedef struct unpack_stack {
 | |
|     PyObject* obj;
 | |
|     Py_ssize_t size;
 | |
|     Py_ssize_t count;
 | |
|     unsigned int ct;
 | |
|     PyObject* map_key;
 | |
| } unpack_stack;
 | |
| 
 | |
| struct unpack_context {
 | |
|     unpack_user user;
 | |
|     unsigned int cs;
 | |
|     unsigned int trail;
 | |
|     unsigned int top;
 | |
|     /*
 | |
|     unpack_stack* stack;
 | |
|     unsigned int stack_size;
 | |
|     unpack_stack embed_stack[MSGPACK_EMBED_STACK_SIZE];
 | |
|     */
 | |
|     unpack_stack stack[MSGPACK_EMBED_STACK_SIZE];
 | |
| };
 | |
| 
 | |
| 
 | |
| static inline void unpack_init(unpack_context* ctx)
 | |
| {
 | |
|     ctx->cs = CS_HEADER;
 | |
|     ctx->trail = 0;
 | |
|     ctx->top = 0;
 | |
|     /*
 | |
|     ctx->stack = ctx->embed_stack;
 | |
|     ctx->stack_size = MSGPACK_EMBED_STACK_SIZE;
 | |
|     */
 | |
|     ctx->stack[0].obj = unpack_callback_root(&ctx->user);
 | |
| }
 | |
| 
 | |
| /*
 | |
| static inline void unpack_destroy(unpack_context* ctx)
 | |
| {
 | |
|     if(ctx->stack_size != MSGPACK_EMBED_STACK_SIZE) {
 | |
|         free(ctx->stack);
 | |
|     }
 | |
| }
 | |
| */
 | |
| 
 | |
| static inline PyObject* unpack_data(unpack_context* ctx)
 | |
| {
 | |
|     return (ctx)->stack[0].obj;
 | |
| }
 | |
| 
 | |
| static inline void unpack_clear(unpack_context *ctx)
 | |
| {
 | |
|     Py_CLEAR(ctx->stack[0].obj);
 | |
| }
 | |
| 
 | |
| static inline int unpack_execute(bool construct, unpack_context* ctx, const char* data, Py_ssize_t len, Py_ssize_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 = p;
 | |
| 
 | |
|     unsigned int trail = ctx->trail;
 | |
|     unsigned int cs = ctx->cs;
 | |
|     unsigned int top = ctx->top;
 | |
|     unpack_stack* stack = ctx->stack;
 | |
|     /*
 | |
|     unsigned int stack_size = ctx->stack_size;
 | |
|     */
 | |
|     unpack_user* user = &ctx->user;
 | |
| 
 | |
|     PyObject* obj = NULL;
 | |
|     unpack_stack* c = NULL;
 | |
| 
 | |
|     int ret;
 | |
| 
 | |
| #define construct_cb(name) \
 | |
|     construct && unpack_callback ## name
 | |
| 
 | |
| #define push_simple_value(func) \
 | |
|     if(construct_cb(func)(user, &obj) < 0) { goto _failed; } \
 | |
|     goto _push
 | |
| #define push_fixed_value(func, arg) \
 | |
|     if(construct_cb(func)(user, arg, &obj) < 0) { goto _failed; } \
 | |
|     goto _push
 | |
| #define push_variable_value(func, base, pos, len) \
 | |
|     if(construct_cb(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) { ret = -3; goto _end; } \
 | |
|     if(construct_cb(func)(user, count_, &stack[top].obj) < 0) { goto _failed; } \
 | |
|     if((count_) == 0) { obj = stack[top].obj; \
 | |
|         if (construct_cb(func##_end)(user, &obj) < 0) { goto _failed; } \
 | |
|         goto _push; } \
 | |
|     stack[top].ct = ct_; \
 | |
|     stack[top].size  = count_; \
 | |
|     stack[top].count = 0; \
 | |
|     ++top; \
 | |
|     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 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:  // never used
 | |
|                 case 0xc2:  // false
 | |
|                     push_simple_value(_false);
 | |
|                 case 0xc3:  // true
 | |
|                     push_simple_value(_true);
 | |
|                 case 0xc4:  // bin 8
 | |
|                     again_fixed_trail(NEXT_CS(p), 1);
 | |
|                 case 0xc5:  // bin 16
 | |
|                     again_fixed_trail(NEXT_CS(p), 2);
 | |
|                 case 0xc6:  // bin 32
 | |
|                     again_fixed_trail(NEXT_CS(p), 4);
 | |
|                 case 0xc7:  // ext 8
 | |
|                     again_fixed_trail(NEXT_CS(p), 1);
 | |
|                 case 0xc8:  // ext 16
 | |
|                     again_fixed_trail(NEXT_CS(p), 2);
 | |
|                 case 0xc9:  // ext 32
 | |
|                     again_fixed_trail(NEXT_CS(p), 4);
 | |
|                 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(ACS_EXT_VALUE, 
 | |
|                                               (1 << (((unsigned int)*p) & 0x03))+1,
 | |
|                                               _ext_zero);
 | |
|                 case 0xd8:  // fixext 16
 | |
|                     again_fixed_trail_if_zero(ACS_EXT_VALUE, 16+1, _ext_zero);
 | |
|                 case 0xd9:  // str 8
 | |
|                     again_fixed_trail(NEXT_CS(p), 1);
 | |
|                 case 0xda:  // raw 16
 | |
|                 case 0xdb:  // raw 32
 | |
|                 case 0xdc:  // array 16
 | |
|                 case 0xdd:  // array 32
 | |
|                 case 0xde:  // map 16
 | |
|                 case 0xdf:  // map 32
 | |
|                     again_fixed_trail(NEXT_CS(p), 2 << (((unsigned int)*p) & 0x01));
 | |
|                 default:
 | |
|                     ret = -2;
 | |
|                     goto _end;
 | |
|                 }
 | |
|             SWITCH_RANGE(0xa0, 0xbf)  // FixRaw
 | |
|                 again_fixed_trail_if_zero(ACS_RAW_VALUE, ((unsigned int)*p & 0x1f), _raw_zero);
 | |
|             SWITCH_RANGE(0x90, 0x9f)  // FixArray
 | |
|                 start_container(_array, ((unsigned int)*p) & 0x0f, CT_ARRAY_ITEM);
 | |
|             SWITCH_RANGE(0x80, 0x8f)  // FixMap
 | |
|                 start_container(_map, ((unsigned int)*p) & 0x0f, CT_MAP_KEY);
 | |
| 
 | |
|             SWITCH_RANGE_DEFAULT
 | |
|                 ret = -2;
 | |
|                 goto _end;
 | |
|             SWITCH_RANGE_END
 | |
|             // end CS_HEADER
 | |
| 
 | |
| 
 | |
|         _fixed_trail_again:
 | |
|             ++p;
 | |
| 
 | |
|         default:
 | |
|             if((size_t)(pe - p) < trail) { goto _out; }
 | |
|             n = p;  p += trail - 1;
 | |
|             switch(cs) {
 | |
|             case CS_EXT_8:
 | |
|                 again_fixed_trail_if_zero(ACS_EXT_VALUE, *(uint8_t*)n+1, _ext_zero);
 | |
|             case CS_EXT_16:
 | |
|                 again_fixed_trail_if_zero(ACS_EXT_VALUE,
 | |
|                                           _msgpack_load16(uint16_t,n)+1,
 | |
|                                           _ext_zero);
 | |
|             case CS_EXT_32:
 | |
|                 again_fixed_trail_if_zero(ACS_EXT_VALUE,
 | |
|                                           _msgpack_load32(uint32_t,n)+1,
 | |
|                                           _ext_zero);
 | |
|             case CS_FLOAT: {
 | |
|                     double f;
 | |
| #if PY_VERSION_HEX >= 0x030B00A7
 | |
|                     f = PyFloat_Unpack4((const char*)n, 0);
 | |
| #else
 | |
|                     f = _PyFloat_Unpack4((unsigned char*)n, 0);
 | |
| #endif
 | |
|                     push_fixed_value(_float, f); }
 | |
|             case CS_DOUBLE: {
 | |
|                     double f;
 | |
| #if PY_VERSION_HEX >= 0x030B00A7
 | |
|                     f = PyFloat_Unpack8((const char*)n, 0);
 | |
| #else
 | |
|                     f = _PyFloat_Unpack8((unsigned char*)n, 0);
 | |
| #endif
 | |
|                     push_fixed_value(_double, f); }
 | |
|             case CS_UINT_8:
 | |
|                 push_fixed_value(_uint8, *(uint8_t*)n);
 | |
|             case CS_UINT_16:
 | |
|                 push_fixed_value(_uint16, _msgpack_load16(uint16_t,n));
 | |
|             case CS_UINT_32:
 | |
|                 push_fixed_value(_uint32, _msgpack_load32(uint32_t,n));
 | |
|             case CS_UINT_64:
 | |
|                 push_fixed_value(_uint64, _msgpack_load64(uint64_t,n));
 | |
| 
 | |
|             case CS_INT_8:
 | |
|                 push_fixed_value(_int8, *(int8_t*)n);
 | |
|             case CS_INT_16:
 | |
|                 push_fixed_value(_int16, _msgpack_load16(int16_t,n));
 | |
|             case CS_INT_32:
 | |
|                 push_fixed_value(_int32, _msgpack_load32(int32_t,n));
 | |
|             case CS_INT_64:
 | |
|                 push_fixed_value(_int64, _msgpack_load64(int64_t,n));
 | |
| 
 | |
|             case CS_BIN_8:
 | |
|                 again_fixed_trail_if_zero(ACS_BIN_VALUE, *(uint8_t*)n, _bin_zero);
 | |
|             case CS_BIN_16:
 | |
|                 again_fixed_trail_if_zero(ACS_BIN_VALUE, _msgpack_load16(uint16_t,n), _bin_zero);
 | |
|             case CS_BIN_32:
 | |
|                 again_fixed_trail_if_zero(ACS_BIN_VALUE, _msgpack_load32(uint32_t,n), _bin_zero);
 | |
|             case ACS_BIN_VALUE:
 | |
|             _bin_zero:
 | |
|                 push_variable_value(_bin, data, n, trail);
 | |
| 
 | |
|             case CS_RAW_8:
 | |
|                 again_fixed_trail_if_zero(ACS_RAW_VALUE, *(uint8_t*)n, _raw_zero);
 | |
|             case CS_RAW_16:
 | |
|                 again_fixed_trail_if_zero(ACS_RAW_VALUE, _msgpack_load16(uint16_t,n), _raw_zero);
 | |
|             case CS_RAW_32:
 | |
|                 again_fixed_trail_if_zero(ACS_RAW_VALUE, _msgpack_load32(uint32_t,n), _raw_zero);
 | |
|             case ACS_RAW_VALUE:
 | |
|             _raw_zero:
 | |
|                 push_variable_value(_raw, data, n, trail);
 | |
| 
 | |
|             case ACS_EXT_VALUE:
 | |
|             _ext_zero:
 | |
|                 push_variable_value(_ext, data, n, trail);
 | |
| 
 | |
|             case CS_ARRAY_16:
 | |
|                 start_container(_array, _msgpack_load16(uint16_t,n), CT_ARRAY_ITEM);
 | |
|             case CS_ARRAY_32:
 | |
|                 /* FIXME security guard */
 | |
|                 start_container(_array, _msgpack_load32(uint32_t,n), CT_ARRAY_ITEM);
 | |
| 
 | |
|             case CS_MAP_16:
 | |
|                 start_container(_map, _msgpack_load16(uint16_t,n), CT_MAP_KEY);
 | |
|             case CS_MAP_32:
 | |
|                 /* FIXME security guard */
 | |
|                 start_container(_map, _msgpack_load32(uint32_t,n), CT_MAP_KEY);
 | |
| 
 | |
|             default:
 | |
|                 goto _failed;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| _push:
 | |
|     if(top == 0) { goto _finish; }
 | |
|     c = &stack[top-1];
 | |
|     switch(c->ct) {
 | |
|     case CT_ARRAY_ITEM:
 | |
|         if(construct_cb(_array_item)(user, c->count, &c->obj, obj) < 0) { goto _failed; }
 | |
|         if(++c->count == c->size) {
 | |
|             obj = c->obj;
 | |
|             if (construct_cb(_array_end)(user, &obj) < 0) { goto _failed; }
 | |
|             --top;
 | |
|             /*printf("stack pop %d\n", top);*/
 | |
|             goto _push;
 | |
|         }
 | |
|         goto _header_again;
 | |
|     case CT_MAP_KEY:
 | |
|         c->map_key = obj;
 | |
|         c->ct = CT_MAP_VALUE;
 | |
|         goto _header_again;
 | |
|     case CT_MAP_VALUE:
 | |
|         if(construct_cb(_map_item)(user, c->count, &c->obj, c->map_key, obj) < 0) { goto _failed; }
 | |
|         if(++c->count == c->size) {
 | |
|             obj = c->obj;
 | |
|             if (construct_cb(_map_end)(user, &obj) < 0) { goto _failed; }
 | |
|             --top;
 | |
|             /*printf("stack pop %d\n", top);*/
 | |
|             goto _push;
 | |
|         }
 | |
|         c->ct = CT_MAP_KEY;
 | |
|         goto _header_again;
 | |
| 
 | |
|     default:
 | |
|         goto _failed;
 | |
|     }
 | |
| 
 | |
| _header_again:
 | |
|         cs = CS_HEADER;
 | |
|         ++p;
 | |
|     } while(p != pe);
 | |
|     goto _out;
 | |
| 
 | |
| 
 | |
| _finish:
 | |
|     if (!construct)
 | |
|         unpack_callback_nil(user, &obj);
 | |
|     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 = p - (const unsigned char*)data;
 | |
| 
 | |
|     return ret;
 | |
| #undef construct_cb
 | |
| }
 | |
| 
 | |
| #undef NEXT_CS
 | |
| #undef SWITCH_RANGE_BEGIN
 | |
| #undef SWITCH_RANGE
 | |
| #undef SWITCH_RANGE_DEFAULT
 | |
| #undef SWITCH_RANGE_END
 | |
| #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
 | |
| 
 | |
| static int unpack_construct(unpack_context *ctx, const char *data, Py_ssize_t len, Py_ssize_t *off) {
 | |
|     return unpack_execute(1, ctx, data, len, off);
 | |
| }
 | |
| static int unpack_skip(unpack_context *ctx, const char *data, Py_ssize_t len, Py_ssize_t *off) {
 | |
|     return unpack_execute(0, ctx, data, len, off);
 | |
| }
 | |
| 
 | |
| #define unpack_container_header read_array_header
 | |
| #define fixed_offset 0x90
 | |
| #define var_offset 0xdc
 | |
| #include "unpack_container_header.h"
 | |
| #undef unpack_container_header
 | |
| #undef fixed_offset
 | |
| #undef var_offset
 | |
| 
 | |
| #define unpack_container_header read_map_header
 | |
| #define fixed_offset 0x80
 | |
| #define var_offset 0xde
 | |
| #include "unpack_container_header.h"
 | |
| #undef unpack_container_header
 | |
| #undef fixed_offset
 | |
| #undef var_offset
 | |
| 
 | |
| /* vim: set ts=4 sw=4 sts=4 expandtab  */
 | 
