Commit | Line | Data |
---|---|---|
116a02e3 JG |
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 | #if defined(_KERNEL_MODE) | |
42 | #undef assert | |
43 | #define assert NT_ASSERT | |
44 | #endif | |
45 | ||
46 | msgpack_unpack_struct_decl(_stack) { | |
47 | msgpack_unpack_object obj; | |
48 | size_t count; | |
49 | unsigned int ct; | |
50 | msgpack_unpack_object map_key; | |
51 | }; | |
52 | ||
53 | msgpack_unpack_struct_decl(_context) { | |
54 | msgpack_unpack_user user; | |
55 | unsigned int cs; | |
56 | unsigned int trail; | |
57 | unsigned int top; | |
58 | /* | |
59 | msgpack_unpack_struct(_stack)* stack; | |
60 | unsigned int stack_size; | |
61 | msgpack_unpack_struct(_stack) embed_stack[MSGPACK_EMBED_STACK_SIZE]; | |
62 | */ | |
63 | msgpack_unpack_struct(_stack) stack[MSGPACK_EMBED_STACK_SIZE]; | |
64 | }; | |
65 | ||
66 | ||
67 | msgpack_unpack_func(void, _init)(msgpack_unpack_struct(_context)* ctx) | |
68 | { | |
69 | ctx->cs = MSGPACK_CS_HEADER; | |
70 | ctx->trail = 0; | |
71 | ctx->top = 0; | |
72 | /* | |
73 | ctx->stack = ctx->embed_stack; | |
74 | ctx->stack_size = MSGPACK_EMBED_STACK_SIZE; | |
75 | */ | |
76 | ctx->stack[0].obj = msgpack_unpack_callback(_root)(&ctx->user); | |
77 | } | |
78 | ||
79 | /* | |
80 | msgpack_unpack_func(void, _destroy)(msgpack_unpack_struct(_context)* ctx) | |
81 | { | |
82 | if(ctx->stack_size != MSGPACK_EMBED_STACK_SIZE) { | |
83 | free(ctx->stack); | |
84 | } | |
85 | } | |
86 | */ | |
87 | ||
88 | msgpack_unpack_func(msgpack_unpack_object, _data)(msgpack_unpack_struct(_context)* ctx) | |
89 | { | |
90 | return (ctx)->stack[0].obj; | |
91 | } | |
92 | ||
93 | ||
94 | msgpack_unpack_func(int, _execute)(msgpack_unpack_struct(_context)* ctx, const char* data, size_t len, size_t* off) | |
95 | { | |
96 | assert(len >= *off); | |
97 | { | |
98 | const unsigned char* p = (unsigned char*)data + *off; | |
99 | const unsigned char* const pe = (unsigned char*)data + len; | |
100 | const void* n = NULL; | |
101 | ||
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; | |
106 | /* | |
107 | unsigned int stack_size = ctx->stack_size; | |
108 | */ | |
109 | msgpack_unpack_user* user = &ctx->user; | |
110 | ||
111 | msgpack_unpack_object obj; | |
112 | msgpack_unpack_struct(_stack)* c = NULL; | |
113 | ||
114 | int ret; | |
115 | ||
116 | #define push_simple_value(func) \ | |
117 | ret = msgpack_unpack_callback(func)(user, &obj); \ | |
118 | if(ret < 0) { goto _failed; } \ | |
119 | goto _push | |
120 | #define push_fixed_value(func, arg) \ | |
121 | ret = msgpack_unpack_callback(func)(user, arg, &obj); \ | |
122 | if(ret < 0) { goto _failed; } \ | |
123 | goto _push | |
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; } \ | |
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) { \ | |
142 | ret = MSGPACK_UNPACK_NOMEM_ERROR; \ | |
143 | goto _failed; \ | |
144 | } /* FIXME */ \ | |
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_; \ | |
150 | ++top; \ | |
151 | goto _header_again | |
152 | ||
153 | #define NEXT_CS(p) \ | |
154 | ((unsigned int)*p & 0x1f) | |
155 | ||
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 } | |
161 | #else | |
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 } } | |
166 | #endif | |
167 | ||
168 | if(p == pe) { goto _out; } | |
169 | do { | |
170 | switch(cs) { | |
171 | case MSGPACK_CS_HEADER: | |
172 | SWITCH_RANGE_BEGIN | |
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 | |
178 | switch(*p) { | |
179 | case 0xc0: // nil | |
180 | push_simple_value(_nil); | |
181 | //case 0xc1: // string | |
182 | // again_terminal_trail(NEXT_CS(p), p+1); | |
183 | case 0xc2: // false | |
184 | push_simple_value(_false); | |
185 | case 0xc3: // true | |
186 | push_simple_value(_true); | |
187 | case 0xc4: // bin 8 | |
188 | case 0xc5: // bin 16 | |
189 | case 0xc6: // bin 32 | |
190 | again_fixed_trail(NEXT_CS(p), 1 << (((unsigned int)*p) & 0x03)); | |
191 | case 0xc7: // ext 8 | |
192 | case 0xc8: // ext 16 | |
193 | case 0xc9: // ext 32 | |
194 | again_fixed_trail(NEXT_CS(p), 1 << ((((unsigned int)*p) + 1) & 0x03)); | |
195 | case 0xca: // float | |
196 | case 0xcb: // double | |
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); | |
214 | ||
215 | case 0xd9: // str 8 | |
216 | case 0xda: // str 16 | |
217 | case 0xdb: // str 32 | |
218 | again_fixed_trail(NEXT_CS(p), 1 << ((((unsigned int)*p) & 0x03) - 1)); | |
219 | case 0xdc: // array 16 | |
220 | case 0xdd: // array 32 | |
221 | case 0xde: // map 16 | |
222 | case 0xdf: // map 32 | |
223 | again_fixed_trail(NEXT_CS(p), 2u << (((unsigned int)*p) & 0x01)); | |
224 | default: | |
225 | ret = MSGPACK_UNPACK_PARSE_ERROR; | |
226 | goto _failed; | |
227 | } | |
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); | |
234 | ||
235 | SWITCH_RANGE_DEFAULT | |
236 | ret = MSGPACK_UNPACK_PARSE_ERROR; | |
237 | goto _failed; | |
238 | SWITCH_RANGE_END | |
239 | // end MSGPACK_CS_HEADER | |
240 | ||
241 | ||
242 | _fixed_trail_again: | |
243 | ++p; | |
244 | // fallthrough | |
245 | ||
246 | default: | |
247 | if((size_t)(pe - p) < trail) { goto _out; } | |
248 | n = p; p += trail - 1; | |
249 | switch(cs) { | |
250 | //case MSGPACK_CS_ | |
251 | //case MSGPACK_CS_ | |
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) | |
260 | // ok | |
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); | |
264 | #endif | |
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:{ | |
269 | uint16_t tmp; | |
270 | _msgpack_load16(uint16_t,n,&tmp); | |
271 | push_fixed_value(_uint16, tmp); | |
272 | } | |
273 | case MSGPACK_CS_UINT_32:{ | |
274 | uint32_t tmp; | |
275 | _msgpack_load32(uint32_t,n,&tmp); | |
276 | push_fixed_value(_uint32, tmp); | |
277 | } | |
278 | case MSGPACK_CS_UINT_64:{ | |
279 | uint64_t tmp; | |
280 | _msgpack_load64(uint64_t,n,&tmp); | |
281 | push_fixed_value(_uint64, tmp); | |
282 | } | |
283 | case MSGPACK_CS_INT_8: | |
284 | push_fixed_value(_int8, *(int8_t*)n); | |
285 | case MSGPACK_CS_INT_16:{ | |
286 | int16_t tmp; | |
287 | _msgpack_load16(int16_t,n,&tmp); | |
288 | push_fixed_value(_int16, tmp); | |
289 | } | |
290 | case MSGPACK_CS_INT_32:{ | |
291 | int32_t tmp; | |
292 | _msgpack_load32(int32_t,n,&tmp); | |
293 | push_fixed_value(_int32, tmp); | |
294 | } | |
295 | case MSGPACK_CS_INT_64:{ | |
296 | int64_t tmp; | |
297 | _msgpack_load64(int64_t,n,&tmp); | |
298 | push_fixed_value(_int64, tmp); | |
299 | } | |
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:{ | |
317 | uint16_t tmp; | |
318 | _msgpack_load16(uint16_t,n,&tmp); | |
319 | again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE, tmp, _str_zero); | |
320 | } | |
321 | case MSGPACK_CS_BIN_16:{ | |
322 | uint16_t tmp; | |
323 | _msgpack_load16(uint16_t,n,&tmp); | |
324 | again_fixed_trail_if_zero(MSGPACK_ACS_BIN_VALUE, tmp, _bin_zero); | |
325 | } | |
326 | case MSGPACK_CS_EXT_16:{ | |
327 | uint16_t tmp; | |
328 | _msgpack_load16(uint16_t,n,&tmp); | |
329 | again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, tmp + 1, _ext_zero); | |
330 | } | |
331 | case MSGPACK_CS_STR_32:{ | |
332 | uint32_t tmp; | |
333 | _msgpack_load32(uint32_t,n,&tmp); | |
334 | again_fixed_trail_if_zero(MSGPACK_ACS_STR_VALUE, tmp, _str_zero); | |
335 | } | |
336 | case MSGPACK_CS_BIN_32:{ | |
337 | uint32_t tmp; | |
338 | _msgpack_load32(uint32_t,n,&tmp); | |
339 | again_fixed_trail_if_zero(MSGPACK_ACS_BIN_VALUE, tmp, _bin_zero); | |
340 | } | |
341 | case MSGPACK_CS_EXT_32:{ | |
342 | uint32_t tmp; | |
343 | _msgpack_load32(uint32_t,n,&tmp); | |
344 | again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, tmp + 1, _ext_zero); | |
345 | } | |
346 | case MSGPACK_ACS_STR_VALUE: | |
347 | _str_zero: | |
348 | push_variable_value(_str, data, n, trail); | |
349 | case MSGPACK_ACS_BIN_VALUE: | |
350 | _bin_zero: | |
351 | push_variable_value(_bin, data, n, trail); | |
352 | case MSGPACK_ACS_EXT_VALUE: | |
353 | _ext_zero: | |
354 | push_variable_value(_ext, data, n, trail); | |
355 | ||
356 | case MSGPACK_CS_ARRAY_16:{ | |
357 | uint16_t tmp; | |
358 | _msgpack_load16(uint16_t,n,&tmp); | |
359 | start_container(_array, tmp, MSGPACK_CT_ARRAY_ITEM); | |
360 | } | |
361 | case MSGPACK_CS_ARRAY_32:{ | |
362 | /* FIXME security guard */ | |
363 | uint32_t tmp; | |
364 | _msgpack_load32(uint32_t,n,&tmp); | |
365 | start_container(_array, tmp, MSGPACK_CT_ARRAY_ITEM); | |
366 | } | |
367 | ||
368 | case MSGPACK_CS_MAP_16:{ | |
369 | uint16_t tmp; | |
370 | _msgpack_load16(uint16_t,n,&tmp); | |
371 | start_container(_map, tmp, MSGPACK_CT_MAP_KEY); | |
372 | } | |
373 | case MSGPACK_CS_MAP_32:{ | |
374 | /* FIXME security guard */ | |
375 | uint32_t tmp; | |
376 | _msgpack_load32(uint32_t,n,&tmp); | |
377 | start_container(_map, tmp, MSGPACK_CT_MAP_KEY); | |
378 | } | |
379 | ||
380 | default: | |
381 | ret = MSGPACK_UNPACK_PARSE_ERROR; | |
382 | goto _failed; | |
383 | } | |
384 | } | |
385 | ||
386 | _push: | |
387 | if(top == 0) { goto _finish; } | |
388 | c = &stack[top-1]; | |
389 | switch(c->ct) { | |
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) { | |
394 | obj = c->obj; | |
395 | --top; | |
396 | /*printf("stack pop %d\n", top);*/ | |
397 | goto _push; | |
398 | } | |
399 | goto _header_again; | |
400 | case MSGPACK_CT_MAP_KEY: | |
401 | c->map_key = obj; | |
402 | c->ct = MSGPACK_CT_MAP_VALUE; | |
403 | goto _header_again; | |
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) { | |
408 | obj = c->obj; | |
409 | --top; | |
410 | /*printf("stack pop %d\n", top);*/ | |
411 | goto _push; | |
412 | } | |
413 | c->ct = MSGPACK_CT_MAP_KEY; | |
414 | goto _header_again; | |
415 | ||
416 | default: | |
417 | ret = MSGPACK_UNPACK_PARSE_ERROR; | |
418 | goto _failed; | |
419 | } | |
420 | ||
421 | _header_again: | |
422 | cs = MSGPACK_CS_HEADER; | |
423 | ++p; | |
424 | } while(p != pe); | |
425 | goto _out; | |
426 | ||
427 | ||
428 | _finish: | |
429 | stack[0].obj = obj; | |
430 | ++p; | |
431 | ret = 1; | |
432 | /*printf("-- finish --\n"); */ | |
433 | goto _end; | |
434 | ||
435 | _failed: | |
436 | /*printf("** FAILED **\n"); */ | |
437 | goto _end; | |
438 | ||
439 | _out: | |
440 | ret = 0; | |
441 | goto _end; | |
442 | ||
443 | _end: | |
444 | ctx->cs = cs; | |
445 | ctx->trail = trail; | |
446 | ctx->top = top; | |
447 | *off = (size_t)(p - (const unsigned char*)data); | |
448 | ||
449 | return ret; | |
450 | } | |
451 | } | |
452 | ||
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 | |
458 | ||
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 | |
465 | ||
466 | #undef NEXT_CS | |
467 | ||
468 | #undef SWITCH_RANGE_BEGIN | |
469 | #undef SWITCH_RANGE | |
470 | #undef SWITCH_RANGE_DEFAULT | |
471 | #undef SWITCH_RANGE_END |