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