File Coverage

include/msgpack/unpack_template.h
Criterion Covered Total %
statement 92 104 88.4
branch 57 92 61.9
condition n/a
subroutine n/a
pod n/a
total 149 196 76.0


line stmt bran cond sub pod time code
1             /*
2             * MessagePack unpacking routine template
3             *
4             * Copyright (C) 2008-2010 FURUHASHI Sadayuki
5             *
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)
9             */
10              
11             #ifndef msgpack_unpack_func
12             #error msgpack_unpack_func template is not defined
13             #endif
14              
15             #ifndef msgpack_unpack_callback
16             #error msgpack_unpack_callback template is not defined
17             #endif
18              
19             #ifndef msgpack_unpack_struct
20             #error msgpack_unpack_struct template is not defined
21             #endif
22              
23             #ifndef msgpack_unpack_struct_decl
24             #define msgpack_unpack_struct_decl(name) msgpack_unpack_struct(name)
25             #endif
26              
27             #ifndef msgpack_unpack_object
28             #error msgpack_unpack_object type is not defined
29             #endif
30              
31             #ifndef msgpack_unpack_user
32             #error msgpack_unpack_user type is not defined
33             #endif
34              
35             #ifndef USE_CASE_RANGE
36             #if !defined(_MSC_VER)
37             #define USE_CASE_RANGE
38             #endif
39             #endif
40              
41             msgpack_unpack_struct_decl(_stack) {
42             msgpack_unpack_object obj;
43             size_t count;
44             unsigned int ct;
45             msgpack_unpack_object map_key;
46             };
47              
48             msgpack_unpack_struct_decl(_context) {
49             msgpack_unpack_user user;
50             unsigned int cs;
51             unsigned int trail;
52             unsigned int top;
53             /*
54             msgpack_unpack_struct(_stack)* stack;
55             unsigned int stack_size;
56             msgpack_unpack_struct(_stack) embed_stack[MSGPACK_EMBED_STACK_SIZE];
57             */
58             msgpack_unpack_struct(_stack) stack[MSGPACK_EMBED_STACK_SIZE];
59             };
60              
61              
62             msgpack_unpack_func(void, _init)(msgpack_unpack_struct(_context)* ctx)
63             {
64 1869           ctx->cs = MSGPACK_CS_HEADER;
65 1869           ctx->trail = 0;
66 1869           ctx->top = 0;
67             /*
68             ctx->stack = ctx->embed_stack;
69             ctx->stack_size = MSGPACK_EMBED_STACK_SIZE;
70             */
71 1869           ctx->stack[0].obj = msgpack_unpack_callback(_root)(&ctx->user);
72             }
73              
74             /*
75             msgpack_unpack_func(void, _destroy)(msgpack_unpack_struct(_context)* ctx)
76             {
77             if(ctx->stack_size != MSGPACK_EMBED_STACK_SIZE) {
78             free(ctx->stack);
79             }
80             }
81             */
82              
83             msgpack_unpack_func(msgpack_unpack_object, _data)(msgpack_unpack_struct(_context)* ctx)
84             {
85             return (ctx)->stack[0].obj;
86             }
87              
88              
89 1863           msgpack_unpack_func(int, _execute)(msgpack_unpack_struct(_context)* ctx, const char* data, size_t len, size_t* off)
90             {
91             assert(len >= *off);
92             {
93 1863           const unsigned char* p = (unsigned char*)data + *off;
94 1863           const unsigned char* const pe = (unsigned char*)data + len;
95             const void* n = NULL;
96              
97 1863           unsigned int trail = ctx->trail;
98 1863           unsigned int cs = ctx->cs;
99 1863           unsigned int top = ctx->top;
100 1863           msgpack_unpack_struct(_stack)* stack = ctx->stack;
101             /*
102             unsigned int stack_size = ctx->stack_size;
103             */
104             msgpack_unpack_user* user = &ctx->user;
105              
106             msgpack_unpack_object obj;
107             msgpack_unpack_struct(_stack)* c = NULL;
108              
109             int ret;
110              
111             #define push_simple_value(func) \
112             if(msgpack_unpack_callback(func)(user, &obj) < 0) { goto _failed; } \
113             goto _push
114             #define push_fixed_value(func, arg) \
115             if(msgpack_unpack_callback(func)(user, arg, &obj) < 0) { goto _failed; } \
116             goto _push
117             #define push_variable_value(func, base, pos, len) \
118             if(msgpack_unpack_callback(func)(user, \
119             (const char*)base, (const char*)pos, len, &obj) < 0) { goto _failed; } \
120             goto _push
121              
122             #define again_fixed_trail(_cs, trail_len) \
123             trail = trail_len; \
124             cs = _cs; \
125             goto _fixed_trail_again
126             #define again_fixed_trail_if_zero(_cs, trail_len, ifzero) \
127             trail = trail_len; \
128             if(trail == 0) { goto ifzero; } \
129             cs = _cs; \
130             goto _fixed_trail_again
131              
132             #define start_container(func, count_, ct_) \
133             if(top >= MSGPACK_EMBED_STACK_SIZE) { goto _failed; } /* FIXME */ \
134             if(msgpack_unpack_callback(func)(user, count_, &stack[top].obj) < 0) { goto _failed; } \
135             if((count_) == 0) { obj = stack[top].obj; goto _push; } \
136             stack[top].ct = ct_; \
137             stack[top].count = count_; \
138             ++top; \
139             /*printf("container %d count %d stack %d\n",stack[top].obj,count_,top);*/ \
140             /*printf("stack push %d\n", top);*/ \
141             /* FIXME \
142             if(top >= stack_size) { \
143             if(stack_size == MSGPACK_EMBED_STACK_SIZE) { \
144             size_t csize = sizeof(msgpack_unpack_struct(_stack)) * MSGPACK_EMBED_STACK_SIZE; \
145             size_t nsize = csize * 2; \
146             msgpack_unpack_struct(_stack)* tmp = (msgpack_unpack_struct(_stack)*)malloc(nsize); \
147             if(tmp == NULL) { goto _failed; } \
148             memcpy(tmp, ctx->stack, csize); \
149             ctx->stack = stack = tmp; \
150             ctx->stack_size = stack_size = MSGPACK_EMBED_STACK_SIZE * 2; \
151             } else { \
152             size_t nsize = sizeof(msgpack_unpack_struct(_stack)) * ctx->stack_size * 2; \
153             msgpack_unpack_struct(_stack)* tmp = (msgpack_unpack_struct(_stack)*)realloc(ctx->stack, nsize); \
154             if(tmp == NULL) { goto _failed; } \
155             ctx->stack = stack = tmp; \
156             ctx->stack_size = stack_size = stack_size * 2; \
157             } \
158             } \
159             */ \
160             goto _header_again
161              
162             #define NEXT_CS(p) \
163             ((unsigned int)*p & 0x1f)
164              
165             #ifdef USE_CASE_RANGE
166             #define SWITCH_RANGE_BEGIN switch(*p) {
167             #define SWITCH_RANGE(FROM, TO) case FROM ... TO:
168             #define SWITCH_RANGE_DEFAULT default:
169             #define SWITCH_RANGE_END }
170             #else
171             #define SWITCH_RANGE_BEGIN { if(0) {
172             #define SWITCH_RANGE(FROM, TO) } else if(FROM <= *p && *p <= TO) {
173             #define SWITCH_RANGE_DEFAULT } else {
174             #define SWITCH_RANGE_END } }
175             #endif
176              
177 1863 50         if(p == pe) { goto _out; }
178             do {
179 21462 100         switch(cs) {
180             case MSGPACK_CS_HEADER:
181 21461           SWITCH_RANGE_BEGIN
182             SWITCH_RANGE(0x00, 0x7f) // Positive Fixnum
183 5223           push_fixed_value(_uint8, *(uint8_t*)p);
184             SWITCH_RANGE(0xe0, 0xff) // Negative Fixnum
185 2702           push_fixed_value(_int8, *(int8_t*)p);
186             SWITCH_RANGE(0xc0, 0xdf) // Variable
187 10188           switch(*p) {
188             case 0xc0: // nil
189             push_simple_value(_nil);
190             //case 0xc1: // string
191             // again_terminal_trail(NEXT_CS(p), p+1);
192             case 0xc2: // false
193             push_simple_value(_false);
194             case 0xc3: // true
195             push_simple_value(_true);
196             case 0xc4: // bin 8
197             case 0xc5: // bin 16
198             case 0xc6: // bin 32
199 3823           again_fixed_trail(NEXT_CS(p), 1 << (((unsigned int)*p) & 0x03));
200             case 0xc7: // ext 8
201             case 0xc8: // ext 16
202             case 0xc9: // ext 32
203 0           again_fixed_trail(NEXT_CS(p), 1 << ((((unsigned int)*p) + 1) & 0x03));
204             case 0xca: // float
205             case 0xcb: // double
206             case 0xcc: // unsigned int 8
207             case 0xcd: // unsigned int 16
208             case 0xce: // unsigned int 32
209             case 0xcf: // unsigned int 64
210             case 0xd0: // signed int 8
211             case 0xd1: // signed int 16
212             case 0xd2: // signed int 32
213             case 0xd3: // signed int 64
214 3329           again_fixed_trail(NEXT_CS(p), 1 << (((unsigned int)*p) & 0x03));
215             case 0xd4: // fixext 1
216             case 0xd5: // fixext 2
217             case 0xd6: // fixext 4
218             case 0xd7: // fixext 8
219 0 0         again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE,
220             (1 << (((unsigned int)*p) & 0x03)) + 1, _ext_zero);
221             case 0xd8: // fixext 16
222             again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 16+1, _ext_zero);
223              
224             case 0xd9: // str 8
225             case 0xda: // str 16
226             case 0xdb: // str 32
227 23           again_fixed_trail(NEXT_CS(p), 1 << ((((unsigned int)*p) & 0x03) - 1));
228             case 0xdc: // array 16
229             case 0xdd: // array 32
230             case 0xde: // map 16
231             case 0xdf: // map 32
232 489           again_fixed_trail(NEXT_CS(p), 2u << (((unsigned int)*p) & 0x01));
233             default:
234             goto _failed;
235             }
236             SWITCH_RANGE(0xa0, 0xbf) // FixStr
237 32 100         again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE, ((unsigned int)*p & 0x1f), _str_zero);
238             SWITCH_RANGE(0x90, 0x9f) // FixArray
239 2043 50         start_container(_array, ((unsigned int)*p) & 0x0f, MSGPACK_CT_ARRAY_ITEM);
    50          
    100          
240             SWITCH_RANGE(0x80, 0x8f) // FixMap
241 1273 50         start_container(_map, ((unsigned int)*p) & 0x0f, MSGPACK_CT_MAP_KEY);
    50          
    100          
242              
243             SWITCH_RANGE_DEFAULT
244             goto _failed;
245             SWITCH_RANGE_END
246             // end MSGPACK_CS_HEADER
247              
248              
249             _fixed_trail_again:
250 11015           ++p;
251              
252             default:
253 11016 100         if((size_t)(pe - p) < trail) { goto _out; }
254 9761           n = p; p += trail - 1;
255 9761           switch(cs) {
256             //case MSGPACK_CS_
257             //case MSGPACK_CS_
258             case MSGPACK_CS_FLOAT: {
259             union { uint32_t i; float f; } mem;
260 4           _msgpack_load32(uint32_t, n, &mem.i);
261 4           push_fixed_value(_float, mem.f); }
262             case MSGPACK_CS_DOUBLE: {
263             union { uint64_t i; double f; } mem;
264 960           _msgpack_load64(uint64_t, n, &mem.i);
265             #if defined(TARGET_OS_IPHONE)
266             // ok
267             #elif defined(__arm__) && !(__ARM_EABI__) // arm-oabi
268             // https://github.com/msgpack/msgpack-perl/pull/1
269             mem.i = (mem.i & 0xFFFFFFFFUL) << 32UL | (mem.i >> 32UL);
270             #endif
271 960           push_fixed_value(_double, mem.f); }
272             case MSGPACK_CS_UINT_8:
273 393           push_fixed_value(_uint8, *(uint8_t*)n);
274             case MSGPACK_CS_UINT_16:{
275             uint16_t tmp;
276 382 50         _msgpack_load16(uint16_t,n,&tmp);
277 382           push_fixed_value(_uint16, tmp);
278             }
279             case MSGPACK_CS_UINT_32:{
280             uint32_t tmp;
281 375           _msgpack_load32(uint32_t,n,&tmp);
282 375           push_fixed_value(_uint32, tmp);
283             }
284             case MSGPACK_CS_UINT_64:{
285             uint64_t tmp;
286 8           _msgpack_load64(uint64_t,n,&tmp);
287 8           push_fixed_value(_uint64, tmp);
288             }
289             case MSGPACK_CS_INT_8:
290 362           push_fixed_value(_int8, *(int8_t*)n);
291             case MSGPACK_CS_INT_16:{
292             int16_t tmp;
293 340 50         _msgpack_load16(int16_t,n,&tmp);
294 340           push_fixed_value(_int16, tmp);
295             }
296             case MSGPACK_CS_INT_32:{
297             int32_t tmp;
298 327           _msgpack_load32(int32_t,n,&tmp);
299 327           push_fixed_value(_int32, tmp);
300             }
301             case MSGPACK_CS_INT_64:{
302             int64_t tmp;
303 21           _msgpack_load64(int64_t,n,&tmp);
304 21           push_fixed_value(_int64, tmp);
305             }
306             case MSGPACK_CS_FIXEXT_1:
307             again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 1+1, _ext_zero);
308             case MSGPACK_CS_FIXEXT_2:
309 0           again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 2+1, _ext_zero);
310             case MSGPACK_CS_FIXEXT_4:
311 0           again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 4+1, _ext_zero);
312             case MSGPACK_CS_FIXEXT_8:
313 0           again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 8+1, _ext_zero);
314             case MSGPACK_CS_FIXEXT_16:
315 0           again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, 16+1, _ext_zero);
316             case MSGPACK_CS_STR_8:
317 3 50         again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE, *(uint8_t*)n, _str_zero);
318             case MSGPACK_CS_BIN_8:
319 2751 100         again_fixed_trail_if_zero(MSGPACK_ACS_BIN_VALUE, *(uint8_t*)n, _bin_zero);
320             case MSGPACK_CS_EXT_8:
321 0 0         again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, (*(uint8_t*)n) + 1, _ext_zero);
322             case MSGPACK_CS_STR_16:{
323             uint16_t tmp;
324 10 50         _msgpack_load16(uint16_t,n,&tmp);
325 10 100         again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE, tmp, _str_zero);
326             }
327             case MSGPACK_CS_BIN_16:{
328             uint16_t tmp;
329 1027 50         _msgpack_load16(uint16_t,n,&tmp);
330 1027 50         again_fixed_trail_if_zero(MSGPACK_ACS_BIN_VALUE, tmp, _bin_zero);
331             }
332             case MSGPACK_CS_EXT_16:{
333             uint16_t tmp;
334 0 0         _msgpack_load16(uint16_t,n,&tmp);
335 0 0         again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, tmp + 1, _ext_zero);
336             }
337             case MSGPACK_CS_STR_32:{
338             uint32_t tmp;
339 10           _msgpack_load32(uint32_t,n,&tmp);
340 10 100         again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE, tmp, _str_zero);
341             }
342             case MSGPACK_CS_BIN_32:{
343             uint32_t tmp;
344 8           _msgpack_load32(uint32_t,n,&tmp);
345 8 50         again_fixed_trail_if_zero(MSGPACK_ACS_BIN_VALUE, tmp, _bin_zero);
346             }
347             case MSGPACK_CS_EXT_32:{
348             uint32_t tmp;
349 0           _msgpack_load32(uint32_t,n,&tmp);
350 0 0         again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, tmp + 1, _ext_zero);
351             }
352             case MSGPACK_ACS_STR_VALUE:
353             _str_zero:
354 55 50         push_variable_value(_str, data, n, trail);
355             case MSGPACK_ACS_BIN_VALUE:
356             _bin_zero:
357 2729 50         push_variable_value(_bin, data, n, trail);
358             case MSGPACK_ACS_EXT_VALUE:
359             _ext_zero:
360 0           push_variable_value(_ext, data, n, trail);
361              
362             case MSGPACK_CS_ARRAY_16:{
363             uint16_t tmp;
364 458 50         _msgpack_load16(uint16_t,n,&tmp);
365 458 50         start_container(_array, tmp, MSGPACK_CT_ARRAY_ITEM);
    50          
    100          
366             }
367             case MSGPACK_CS_ARRAY_32:{
368             /* FIXME security guard */
369             uint32_t tmp;
370 8           _msgpack_load32(uint32_t,n,&tmp);
371 8 50         start_container(_array, tmp, MSGPACK_CT_ARRAY_ITEM);
    50          
    100          
372             }
373              
374             case MSGPACK_CS_MAP_16:{
375             uint16_t tmp;
376 10 50         _msgpack_load16(uint16_t,n,&tmp);
377 10 50         start_container(_map, tmp, MSGPACK_CT_MAP_KEY);
    50          
    100          
378             }
379             case MSGPACK_CS_MAP_32:{
380             /* FIXME security guard */
381             uint32_t tmp;
382 10           _msgpack_load32(uint32_t,n,&tmp);
383 1548 50         start_container(_map, tmp, MSGPACK_CT_MAP_KEY);
    50          
    100          
384             }
385              
386             default:
387             goto _failed;
388             }
389             }
390              
391             _push:
392 18658 100         if(top == 0) { goto _finish; }
393 18263           c = &stack[top-1];
394 18263           switch(c->ct) {
395             case MSGPACK_CT_ARRAY_ITEM:
396 16278           if(msgpack_unpack_callback(_array_item)(user, &c->obj, obj) < 0) { goto _failed; }
397 16278 100         if(--c->count == 0) {
398 605           obj = c->obj;
399             --top;
400             /*printf("stack pop %d\n", top);*/
401 605           goto _push;
402             }
403             goto _header_again;
404             case MSGPACK_CT_MAP_KEY:
405 996           c->map_key = obj;
406 996           c->ct = MSGPACK_CT_MAP_VALUE;
407 996           goto _header_again;
408             case MSGPACK_CT_MAP_VALUE:
409 989 50         if(msgpack_unpack_callback(_map_item)(user, &c->obj, c->map_key, obj) < 0) { goto _failed; }
410 989 100         if(--c->count == 0) {
411 933           obj = c->obj;
412             --top;
413             /*printf("stack pop %d\n", top);*/
414 933           goto _push;
415             }
416 56           c->ct = MSGPACK_CT_MAP_KEY;
417 56           goto _header_again;
418              
419             default:
420             goto _failed;
421             }
422              
423             _header_again:
424             cs = MSGPACK_CS_HEADER;
425 19812           ++p;
426 19812 100         } while(p != pe);
427             goto _out;
428              
429              
430             _finish:
431 395           stack[0].obj = obj;
432 395           ++p;
433             ret = 1;
434             /*printf("-- finish --\n"); */
435 395           goto _end;
436              
437             _failed:
438             /*printf("** FAILED **\n"); */
439             ret = -1;
440             goto _end;
441              
442             _out:
443             ret = 0;
444             goto _end;
445              
446             _end:
447 1863           ctx->cs = cs;
448 1863           ctx->trail = trail;
449 1863           ctx->top = top;
450 1863           *off = (size_t)(p - (const unsigned char*)data);
451              
452 1863           return ret;
453             }
454             }
455              
456             #undef msgpack_unpack_func
457             #undef msgpack_unpack_callback
458             #undef msgpack_unpack_struct
459             #undef msgpack_unpack_object
460             #undef msgpack_unpack_user
461              
462             #undef push_simple_value
463             #undef push_fixed_value
464             #undef push_variable_value
465             #undef again_fixed_trail
466             #undef again_fixed_trail_if_zero
467             #undef start_container
468              
469             #undef NEXT_CS
470              
471             #undef SWITCH_RANGE_BEGIN
472             #undef SWITCH_RANGE
473             #undef SWITCH_RANGE_DEFAULT
474             #undef SWITCH_RANGE_END