2 * MessagePack unpacking routine template
4 * Copyright (C) 2008-2010 FURUHASHI Sadayuki
6 * Distributed under the Boost Software License, Version 1.0.
7 * (See accompanying file LICENSE_1_0.txt or copy at
8 * http://www.boost.org/LICENSE_1_0.txt)
11 #ifndef msgpack_unpack_func
12 #error msgpack_unpack_func template is not defined
15 #ifndef msgpack_unpack_callback
16 #error msgpack_unpack_callback template is not defined
19 #ifndef msgpack_unpack_struct
20 #error msgpack_unpack_struct template is not defined
23 #ifndef msgpack_unpack_struct_decl
24 #define msgpack_unpack_struct_decl(name) msgpack_unpack_struct(name)
27 #ifndef msgpack_unpack_object
28 #error msgpack_unpack_object type is not defined
31 #ifndef msgpack_unpack_user
32 #error msgpack_unpack_user type is not defined
35 #ifndef USE_CASE_RANGE
36 #if !defined(_MSC_VER)
37 #define USE_CASE_RANGE
41 #if defined(_KERNEL_MODE)
43 #define assert NT_ASSERT
46 msgpack_unpack_struct_decl(_stack
) {
47 msgpack_unpack_object obj
;
50 msgpack_unpack_object map_key
;
53 msgpack_unpack_struct_decl(_context
) {
54 msgpack_unpack_user user
;
59 msgpack_unpack_struct(_stack)* stack;
60 unsigned int stack_size;
61 msgpack_unpack_struct(_stack) embed_stack[MSGPACK_EMBED_STACK_SIZE];
63 msgpack_unpack_struct(_stack
) stack
[MSGPACK_EMBED_STACK_SIZE
];
67 msgpack_unpack_func(void, _init
)(msgpack_unpack_struct(_context
)* ctx
)
69 ctx
->cs
= MSGPACK_CS_HEADER
;
73 ctx->stack = ctx->embed_stack;
74 ctx->stack_size = MSGPACK_EMBED_STACK_SIZE;
76 ctx
->stack
[0].obj
= msgpack_unpack_callback(_root
)(&ctx
->user
);
80 msgpack_unpack_func(void, _destroy)(msgpack_unpack_struct(_context)* ctx)
82 if(ctx->stack_size != MSGPACK_EMBED_STACK_SIZE) {
88 msgpack_unpack_func(msgpack_unpack_object
, _data
)(msgpack_unpack_struct(_context
)* ctx
)
90 return (ctx
)->stack
[0].obj
;
94 msgpack_unpack_func(int, _execute
)(msgpack_unpack_struct(_context
)* ctx
, const char* data
, size_t len
, size_t* off
)
98 const unsigned char* p
= (unsigned char*)data
+ *off
;
99 const unsigned char* const pe
= (unsigned char*)data
+ len
;
100 const void* n
= NULL
;
102 unsigned int trail
= ctx
->trail
;
103 unsigned int cs
= ctx
->cs
;
104 unsigned int top
= ctx
->top
;
105 msgpack_unpack_struct(_stack
)* stack
= ctx
->stack
;
107 unsigned int stack_size = ctx->stack_size;
109 msgpack_unpack_user
* user
= &ctx
->user
;
111 msgpack_unpack_object obj
;
112 msgpack_unpack_struct(_stack
)* c
= NULL
;
116 #define push_simple_value(func) \
117 ret = msgpack_unpack_callback(func)(user, &obj); \
118 if(ret < 0) { goto _failed; } \
120 #define push_fixed_value(func, arg) \
121 ret = msgpack_unpack_callback(func)(user, arg, &obj); \
122 if(ret < 0) { goto _failed; } \
124 #define push_variable_value(func, base, pos, len) \
125 ret = msgpack_unpack_callback(func)(user, \
126 (const char*)base, (const char*)pos, len, &obj); \
127 if(ret < 0) { goto _failed; } \
130 #define again_fixed_trail(_cs, trail_len) \
133 goto _fixed_trail_again
134 #define again_fixed_trail_if_zero(_cs, trail_len, ifzero) \
136 if(trail == 0) { goto ifzero; } \
138 goto _fixed_trail_again
140 #define start_container(func, count_, ct_) \
141 if(top >= MSGPACK_EMBED_STACK_SIZE) { \
142 ret = MSGPACK_UNPACK_NOMEM_ERROR; \
145 ret = msgpack_unpack_callback(func)(user, count_, &stack[top].obj); \
146 if(ret < 0) { goto _failed; } \
147 if((count_) == 0) { obj = stack[top].obj; goto _push; } \
148 stack[top].ct = ct_; \
149 stack[top].count = count_; \
154 ((unsigned int)*p & 0x1f)
156 #ifdef USE_CASE_RANGE
157 #define SWITCH_RANGE_BEGIN switch(*p) {
158 #define SWITCH_RANGE(FROM, TO) case FROM ... TO:
159 #define SWITCH_RANGE_DEFAULT default:
160 #define SWITCH_RANGE_END }
162 #define SWITCH_RANGE_BEGIN { if(0) {
163 #define SWITCH_RANGE(FROM, TO) } else if(FROM <= *p && *p <= TO) {
164 #define SWITCH_RANGE_DEFAULT } else {
165 #define SWITCH_RANGE_END } }
168 if(p
== pe
) { goto _out
; }
171 case MSGPACK_CS_HEADER
:
173 SWITCH_RANGE(0x00, 0x7f) // Positive Fixnum
174 push_fixed_value(_uint8
, *(uint8_t*)p
);
175 SWITCH_RANGE(0xe0, 0xff) // Negative Fixnum
176 push_fixed_value(_int8
, *(int8_t*)p
);
177 SWITCH_RANGE(0xc0, 0xdf) // Variable
180 push_simple_value(_nil
);
181 //case 0xc1: // string
182 // again_terminal_trail(NEXT_CS(p), p+1);
184 push_simple_value(_false
);
186 push_simple_value(_true
);
190 again_fixed_trail(NEXT_CS(p
), 1 << (((unsigned int)*p
) & 0x03));
194 again_fixed_trail(NEXT_CS(p
), 1 << ((((unsigned int)*p
) + 1) & 0x03));
197 case 0xcc: // unsigned int 8
198 case 0xcd: // unsigned int 16
199 case 0xce: // unsigned int 32
200 case 0xcf: // unsigned int 64
201 case 0xd0: // signed int 8
202 case 0xd1: // signed int 16
203 case 0xd2: // signed int 32
204 case 0xd3: // signed int 64
205 again_fixed_trail(NEXT_CS(p
), 1 << (((unsigned int)*p
) & 0x03));
206 case 0xd4: // fixext 1
207 case 0xd5: // fixext 2
208 case 0xd6: // fixext 4
209 case 0xd7: // fixext 8
210 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE
,
211 (1 << (((unsigned int)*p
) & 0x03)) + 1, _ext_zero
);
212 case 0xd8: // fixext 16
213 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE
, 16+1, _ext_zero
);
218 again_fixed_trail(NEXT_CS(p
), 1 << ((((unsigned int)*p
) & 0x03) - 1));
219 case 0xdc: // array 16
220 case 0xdd: // array 32
223 again_fixed_trail(NEXT_CS(p
), 2u << (((unsigned int)*p
) & 0x01));
225 ret
= MSGPACK_UNPACK_PARSE_ERROR
;
228 SWITCH_RANGE(0xa0, 0xbf) // FixStr
229 again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE
, ((unsigned int)*p
& 0x1f), _str_zero
);
230 SWITCH_RANGE(0x90, 0x9f) // FixArray
231 start_container(_array
, ((unsigned int)*p
) & 0x0f, MSGPACK_CT_ARRAY_ITEM
);
232 SWITCH_RANGE(0x80, 0x8f) // FixMap
233 start_container(_map
, ((unsigned int)*p
) & 0x0f, MSGPACK_CT_MAP_KEY
);
236 ret
= MSGPACK_UNPACK_PARSE_ERROR
;
239 // end MSGPACK_CS_HEADER
247 if((size_t)(pe
- p
) < trail
) { goto _out
; }
248 n
= p
; p
+= trail
- 1;
252 case MSGPACK_CS_FLOAT
: {
253 union { uint32_t i
; float f
; } mem
;
254 _msgpack_load32(uint32_t, n
, &mem
.i
);
255 push_fixed_value(_float
, mem
.f
); }
256 case MSGPACK_CS_DOUBLE
: {
257 union { uint64_t i
; double f
; } mem
;
258 _msgpack_load64(uint64_t, n
, &mem
.i
);
259 #if defined(TARGET_OS_IPHONE)
261 #elif defined(__arm__) && !(__ARM_EABI__) // arm-oabi
262 // https://github.com/msgpack/msgpack-perl/pull/1
263 mem
.i
= (mem
.i
& 0xFFFFFFFFUL
) << 32UL | (mem
.i
>> 32UL);
265 push_fixed_value(_double
, mem
.f
); }
266 case MSGPACK_CS_UINT_8
:
267 push_fixed_value(_uint8
, *(uint8_t*)n
);
268 case MSGPACK_CS_UINT_16
:{
270 _msgpack_load16(uint16_t,n
,&tmp
);
271 push_fixed_value(_uint16
, tmp
);
273 case MSGPACK_CS_UINT_32
:{
275 _msgpack_load32(uint32_t,n
,&tmp
);
276 push_fixed_value(_uint32
, tmp
);
278 case MSGPACK_CS_UINT_64
:{
280 _msgpack_load64(uint64_t,n
,&tmp
);
281 push_fixed_value(_uint64
, tmp
);
283 case MSGPACK_CS_INT_8
:
284 push_fixed_value(_int8
, *(int8_t*)n
);
285 case MSGPACK_CS_INT_16
:{
287 _msgpack_load16(int16_t,n
,&tmp
);
288 push_fixed_value(_int16
, tmp
);
290 case MSGPACK_CS_INT_32
:{
292 _msgpack_load32(int32_t,n
,&tmp
);
293 push_fixed_value(_int32
, tmp
);
295 case MSGPACK_CS_INT_64
:{
297 _msgpack_load64(int64_t,n
,&tmp
);
298 push_fixed_value(_int64
, tmp
);
300 case MSGPACK_CS_FIXEXT_1
:
301 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE
, 1+1, _ext_zero
);
302 case MSGPACK_CS_FIXEXT_2
:
303 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE
, 2+1, _ext_zero
);
304 case MSGPACK_CS_FIXEXT_4
:
305 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE
, 4+1, _ext_zero
);
306 case MSGPACK_CS_FIXEXT_8
:
307 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE
, 8+1, _ext_zero
);
308 case MSGPACK_CS_FIXEXT_16
:
309 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE
, 16+1, _ext_zero
);
310 case MSGPACK_CS_STR_8
:
311 again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE
, *(uint8_t*)n
, _str_zero
);
312 case MSGPACK_CS_BIN_8
:
313 again_fixed_trail_if_zero(MSGPACK_ACS_BIN_VALUE
, *(uint8_t*)n
, _bin_zero
);
314 case MSGPACK_CS_EXT_8
:
315 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE
, (*(uint8_t*)n
) + 1, _ext_zero
);
316 case MSGPACK_CS_STR_16
:{
318 _msgpack_load16(uint16_t,n
,&tmp
);
319 again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE
, tmp
, _str_zero
);
321 case MSGPACK_CS_BIN_16
:{
323 _msgpack_load16(uint16_t,n
,&tmp
);
324 again_fixed_trail_if_zero(MSGPACK_ACS_BIN_VALUE
, tmp
, _bin_zero
);
326 case MSGPACK_CS_EXT_16
:{
328 _msgpack_load16(uint16_t,n
,&tmp
);
329 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE
, tmp
+ 1, _ext_zero
);
331 case MSGPACK_CS_STR_32
:{
333 _msgpack_load32(uint32_t,n
,&tmp
);
334 again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE
, tmp
, _str_zero
);
336 case MSGPACK_CS_BIN_32
:{
338 _msgpack_load32(uint32_t,n
,&tmp
);
339 again_fixed_trail_if_zero(MSGPACK_ACS_BIN_VALUE
, tmp
, _bin_zero
);
341 case MSGPACK_CS_EXT_32
:{
343 _msgpack_load32(uint32_t,n
,&tmp
);
344 again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE
, tmp
+ 1, _ext_zero
);
346 case MSGPACK_ACS_STR_VALUE
:
348 push_variable_value(_str
, data
, n
, trail
);
349 case MSGPACK_ACS_BIN_VALUE
:
351 push_variable_value(_bin
, data
, n
, trail
);
352 case MSGPACK_ACS_EXT_VALUE
:
354 push_variable_value(_ext
, data
, n
, trail
);
356 case MSGPACK_CS_ARRAY_16
:{
358 _msgpack_load16(uint16_t,n
,&tmp
);
359 start_container(_array
, tmp
, MSGPACK_CT_ARRAY_ITEM
);
361 case MSGPACK_CS_ARRAY_32
:{
362 /* FIXME security guard */
364 _msgpack_load32(uint32_t,n
,&tmp
);
365 start_container(_array
, tmp
, MSGPACK_CT_ARRAY_ITEM
);
368 case MSGPACK_CS_MAP_16
:{
370 _msgpack_load16(uint16_t,n
,&tmp
);
371 start_container(_map
, tmp
, MSGPACK_CT_MAP_KEY
);
373 case MSGPACK_CS_MAP_32
:{
374 /* FIXME security guard */
376 _msgpack_load32(uint32_t,n
,&tmp
);
377 start_container(_map
, tmp
, MSGPACK_CT_MAP_KEY
);
381 ret
= MSGPACK_UNPACK_PARSE_ERROR
;
387 if(top
== 0) { goto _finish
; }
390 case MSGPACK_CT_ARRAY_ITEM
:
391 ret
= msgpack_unpack_callback(_array_item
)(user
, &c
->obj
, obj
); \
392 if(ret
< 0) { goto _failed
; }
393 if(--c
->count
== 0) {
396 /*printf("stack pop %d\n", top);*/
400 case MSGPACK_CT_MAP_KEY
:
402 c
->ct
= MSGPACK_CT_MAP_VALUE
;
404 case MSGPACK_CT_MAP_VALUE
:
405 ret
= msgpack_unpack_callback(_map_item
)(user
, &c
->obj
, c
->map_key
, obj
); \
406 if(ret
< 0) { goto _failed
; }
407 if(--c
->count
== 0) {
410 /*printf("stack pop %d\n", top);*/
413 c
->ct
= MSGPACK_CT_MAP_KEY
;
417 ret
= MSGPACK_UNPACK_PARSE_ERROR
;
422 cs
= MSGPACK_CS_HEADER
;
432 /*printf("-- finish --\n"); */
436 /*printf("** FAILED **\n"); */
447 *off
= (size_t)(p
- (const unsigned char*)data
);
453 #undef msgpack_unpack_func
454 #undef msgpack_unpack_callback
455 #undef msgpack_unpack_struct
456 #undef msgpack_unpack_object
457 #undef msgpack_unpack_user
459 #undef push_simple_value
460 #undef push_fixed_value
461 #undef push_variable_value
462 #undef again_fixed_trail
463 #undef again_fixed_trail_if_zero
464 #undef start_container
468 #undef SWITCH_RANGE_BEGIN
470 #undef SWITCH_RANGE_DEFAULT
471 #undef SWITCH_RANGE_END