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