1 /*
2  * MessagePack for C unpacking routine
3  *
4  * Copyright (C) 2008-2009 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 #include "msgpack/unpack.h"
11 #include "msgpack/unpack_define.h"
12 #include "msgpack/util.h"
13 #include <stdlib.h>
14 
15 #ifdef _msgpack_atomic_counter_header
16 #include _msgpack_atomic_counter_header
17 #endif
18 
19 
20 typedef struct {
21     msgpack_zone* z;
22     bool referenced;
23 } unpack_user;
24 
25 
26 #define msgpack_unpack_struct(name) \
27     struct template ## name
28 
29 #define msgpack_unpack_func(ret, name) \
30     ret template ## name
31 
32 #define msgpack_unpack_callback(name) \
33     template_callback ## name
34 
35 #define msgpack_unpack_object msgpack_object
36 
37 #define msgpack_unpack_user unpack_user
38 
39 
40 struct template_context;
41 typedef struct template_context template_context;
42 
43 static void template_init(template_context* ctx);
44 
45 static msgpack_object template_data(template_context* ctx);
46 
47 static int template_execute(
48     template_context* ctx, const char* data, size_t len, size_t* off);
49 
50 
template_callback_root(unpack_user * u)51 static inline msgpack_object template_callback_root(unpack_user* u)
52 {
53     msgpack_object o;
54     MSGPACK_UNUSED(u);
55     o.type = MSGPACK_OBJECT_NIL;
56     return o;
57 }
58 
template_callback_uint8(unpack_user * u,uint8_t d,msgpack_object * o)59 static inline int template_callback_uint8(unpack_user* u, uint8_t d, msgpack_object* o)
60 {
61     MSGPACK_UNUSED(u);
62     o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
63     o->via.u64 = d;
64     return 0;
65 }
66 
template_callback_uint16(unpack_user * u,uint16_t d,msgpack_object * o)67 static inline int template_callback_uint16(unpack_user* u, uint16_t d, msgpack_object* o)
68 {
69     MSGPACK_UNUSED(u);
70     o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
71     o->via.u64 = d;
72     return 0;
73 }
74 
template_callback_uint32(unpack_user * u,uint32_t d,msgpack_object * o)75 static inline int template_callback_uint32(unpack_user* u, uint32_t d, msgpack_object* o)
76 {
77     MSGPACK_UNUSED(u);
78     o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
79     o->via.u64 = d;
80     return 0;
81 }
82 
template_callback_uint64(unpack_user * u,uint64_t d,msgpack_object * o)83 static inline int template_callback_uint64(unpack_user* u, uint64_t d, msgpack_object* o)
84 {
85     MSGPACK_UNUSED(u);
86     o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
87     o->via.u64 = d;
88     return 0;
89 }
90 
template_callback_int8(unpack_user * u,int8_t d,msgpack_object * o)91 static inline int template_callback_int8(unpack_user* u, int8_t d, msgpack_object* o)
92 {
93     MSGPACK_UNUSED(u);
94     if(d >= 0) {
95         o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
96         o->via.u64 = (uint64_t)d;
97         return 0;
98     }
99     else {
100         o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER;
101         o->via.i64 = d;
102         return 0;
103     }
104 }
105 
template_callback_int16(unpack_user * u,int16_t d,msgpack_object * o)106 static inline int template_callback_int16(unpack_user* u, int16_t d, msgpack_object* o)
107 {
108     MSGPACK_UNUSED(u);
109     if(d >= 0) {
110         o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
111         o->via.u64 = (uint64_t)d;
112         return 0;
113     }
114     else {
115         o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER;
116         o->via.i64 = d;
117         return 0;
118     }
119 }
120 
template_callback_int32(unpack_user * u,int32_t d,msgpack_object * o)121 static inline int template_callback_int32(unpack_user* u, int32_t d, msgpack_object* o)
122 {
123     MSGPACK_UNUSED(u);
124     if(d >= 0) {
125         o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
126         o->via.u64 = (uint64_t)d;
127         return 0;
128     }
129     else {
130         o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER;
131         o->via.i64 = d;
132         return 0;
133     }
134 }
135 
template_callback_int64(unpack_user * u,int64_t d,msgpack_object * o)136 static inline int template_callback_int64(unpack_user* u, int64_t d, msgpack_object* o)
137 {
138     MSGPACK_UNUSED(u);
139     if(d >= 0) {
140         o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
141         o->via.u64 = (uint64_t)d;
142         return 0;
143     }
144     else {
145         o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER;
146         o->via.i64 = d;
147         return 0;
148     }
149 }
150 
template_callback_float(unpack_user * u,float d,msgpack_object * o)151 static inline int template_callback_float(unpack_user* u, float d, msgpack_object* o)
152 {
153     MSGPACK_UNUSED(u);
154     o->type = MSGPACK_OBJECT_FLOAT32;
155     o->via.f64 = d;
156     return 0;
157 }
158 
template_callback_double(unpack_user * u,double d,msgpack_object * o)159 static inline int template_callback_double(unpack_user* u, double d, msgpack_object* o)
160 {
161     MSGPACK_UNUSED(u);
162     o->type = MSGPACK_OBJECT_FLOAT64;
163     o->via.f64 = d;
164     return 0;
165 }
166 
template_callback_nil(unpack_user * u,msgpack_object * o)167 static inline int template_callback_nil(unpack_user* u, msgpack_object* o)
168 {
169     MSGPACK_UNUSED(u);
170     o->type = MSGPACK_OBJECT_NIL;
171     return 0;
172 }
173 
template_callback_true(unpack_user * u,msgpack_object * o)174 static inline int template_callback_true(unpack_user* u, msgpack_object* o)
175 {
176     MSGPACK_UNUSED(u);
177     o->type = MSGPACK_OBJECT_BOOLEAN;
178     o->via.boolean = true;
179     return 0;
180 }
181 
template_callback_false(unpack_user * u,msgpack_object * o)182 static inline int template_callback_false(unpack_user* u, msgpack_object* o)
183 {
184     MSGPACK_UNUSED(u);
185     o->type = MSGPACK_OBJECT_BOOLEAN;
186     o->via.boolean = false;
187     return 0;
188 }
189 
template_callback_array(unpack_user * u,unsigned int n,msgpack_object * o)190 static inline int template_callback_array(unpack_user* u, unsigned int n, msgpack_object* o)
191 {
192     unsigned int size;
193     o->type = MSGPACK_OBJECT_ARRAY;
194     o->via.array.size = 0;
195     size = n*sizeof(msgpack_object);
196     if (size / sizeof(msgpack_object) != n) {
197         // integer overflow
198         return MSGPACK_UNPACK_NOMEM_ERROR;
199     }
200     o->via.array.ptr = (msgpack_object*)msgpack_zone_malloc(u->z, size);
201     if(o->via.array.ptr == NULL) { return MSGPACK_UNPACK_NOMEM_ERROR; }
202     return 0;
203 }
204 
template_callback_array_item(unpack_user * u,msgpack_object * c,msgpack_object o)205 static inline int template_callback_array_item(unpack_user* u, msgpack_object* c, msgpack_object o)
206 {
207     MSGPACK_UNUSED(u);
208 #if defined(__GNUC__) && !defined(__clang__)
209     memcpy(&c->via.array.ptr[c->via.array.size], &o, sizeof(msgpack_object));
210 #else  /* __GNUC__ && !__clang__ */
211     c->via.array.ptr[c->via.array.size] = o;
212 #endif /* __GNUC__ && !__clang__ */
213     ++c->via.array.size;
214     return 0;
215 }
216 
template_callback_map(unpack_user * u,unsigned int n,msgpack_object * o)217 static inline int template_callback_map(unpack_user* u, unsigned int n, msgpack_object* o)
218 {
219     unsigned int size;
220     o->type = MSGPACK_OBJECT_MAP;
221     o->via.map.size = 0;
222     size = n*sizeof(msgpack_object_kv);
223     if (size / sizeof(msgpack_object_kv) != n) {
224         // integer overflow
225         return MSGPACK_UNPACK_NOMEM_ERROR;
226     }
227     o->via.map.ptr = (msgpack_object_kv*)msgpack_zone_malloc(u->z, size);
228     if(o->via.map.ptr == NULL) { return MSGPACK_UNPACK_NOMEM_ERROR; }
229     return 0;
230 }
231 
template_callback_map_item(unpack_user * u,msgpack_object * c,msgpack_object k,msgpack_object v)232 static inline int template_callback_map_item(unpack_user* u, msgpack_object* c, msgpack_object k, msgpack_object v)
233 {
234     MSGPACK_UNUSED(u);
235 #if defined(__GNUC__) && !defined(__clang__)
236     memcpy(&c->via.map.ptr[c->via.map.size].key, &k, sizeof(msgpack_object));
237     memcpy(&c->via.map.ptr[c->via.map.size].val, &v, sizeof(msgpack_object));
238 #else  /* __GNUC__ && !__clang__ */
239     c->via.map.ptr[c->via.map.size].key = k;
240     c->via.map.ptr[c->via.map.size].val = v;
241 #endif /* __GNUC__ && !__clang__ */
242     ++c->via.map.size;
243     return 0;
244 }
245 
template_callback_str(unpack_user * u,const char * b,const char * p,unsigned int l,msgpack_object * o)246 static inline int template_callback_str(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o)
247 {
248     MSGPACK_UNUSED(u);
249     MSGPACK_UNUSED(b);
250     o->type = MSGPACK_OBJECT_STR;
251     o->via.str.ptr = p;
252     o->via.str.size = l;
253     u->referenced = true;
254     return 0;
255 }
256 
template_callback_bin(unpack_user * u,const char * b,const char * p,unsigned int l,msgpack_object * o)257 static inline int template_callback_bin(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o)
258 {
259     MSGPACK_UNUSED(u);
260     MSGPACK_UNUSED(b);
261     o->type = MSGPACK_OBJECT_BIN;
262     o->via.bin.ptr = p;
263     o->via.bin.size = l;
264     u->referenced = true;
265     return 0;
266 }
267 
template_callback_ext(unpack_user * u,const char * b,const char * p,unsigned int l,msgpack_object * o)268 static inline int template_callback_ext(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o)
269 {
270     if (l == 0) {
271         return MSGPACK_UNPACK_PARSE_ERROR;
272     }
273     MSGPACK_UNUSED(u);
274     MSGPACK_UNUSED(b);
275     o->type = MSGPACK_OBJECT_EXT;
276     o->via.ext.type = *p;
277     o->via.ext.ptr = p + 1;
278     o->via.ext.size = l - 1;
279     u->referenced = true;
280     return 0;
281 }
282 
283 #include "msgpack/unpack_template.h"
284 
285 
286 #define CTX_CAST(m) ((template_context*)(m))
287 #define CTX_REFERENCED(mpac) CTX_CAST((mpac)->ctx)->user.referenced
288 
289 #define COUNTER_SIZE (sizeof(_msgpack_atomic_counter_t))
290 
291 
init_count(void * buffer)292 static inline void init_count(void* buffer)
293 {
294     *(volatile _msgpack_atomic_counter_t*)buffer = 1;
295 }
296 
decr_count(void * buffer)297 static inline void decr_count(void* buffer)
298 {
299     // atomic if(--*(_msgpack_atomic_counter_t*)buffer == 0) { free(buffer); }
300     if(_msgpack_sync_decr_and_fetch((volatile _msgpack_atomic_counter_t*)buffer) == 0) {
301         free(buffer);
302     }
303 }
304 
incr_count(void * buffer)305 static inline void incr_count(void* buffer)
306 {
307     // atomic ++*(_msgpack_atomic_counter_t*)buffer;
308     _msgpack_sync_incr_and_fetch((volatile _msgpack_atomic_counter_t*)buffer);
309 }
310 
get_count(void * buffer)311 static inline _msgpack_atomic_counter_t get_count(void* buffer)
312 {
313     return *(volatile _msgpack_atomic_counter_t*)buffer;
314 }
315 
msgpack_unpacker_init(msgpack_unpacker * mpac,size_t initial_buffer_size)316 bool msgpack_unpacker_init(msgpack_unpacker* mpac, size_t initial_buffer_size)
317 {
318     char* buffer;
319     void* ctx;
320     msgpack_zone* z;
321 
322     if(initial_buffer_size < COUNTER_SIZE) {
323         initial_buffer_size = COUNTER_SIZE;
324     }
325 
326     buffer = (char*)malloc(initial_buffer_size);
327     if(buffer == NULL) {
328         return false;
329     }
330 
331     ctx = malloc(sizeof(template_context));
332     if(ctx == NULL) {
333         free(buffer);
334         return false;
335     }
336 
337     z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
338     if(z == NULL) {
339         free(ctx);
340         free(buffer);
341         return false;
342     }
343 
344     mpac->buffer = buffer;
345     mpac->used = COUNTER_SIZE;
346     mpac->free = initial_buffer_size - mpac->used;
347     mpac->off = COUNTER_SIZE;
348     mpac->parsed = 0;
349     mpac->initial_buffer_size = initial_buffer_size;
350     mpac->z = z;
351     mpac->ctx = ctx;
352 
353     init_count(mpac->buffer);
354 
355     template_init(CTX_CAST(mpac->ctx));
356     CTX_CAST(mpac->ctx)->user.z = mpac->z;
357     CTX_CAST(mpac->ctx)->user.referenced = false;
358 
359     return true;
360 }
361 
msgpack_unpacker_destroy(msgpack_unpacker * mpac)362 void msgpack_unpacker_destroy(msgpack_unpacker* mpac)
363 {
364     msgpack_zone_free(mpac->z);
365     free(mpac->ctx);
366     decr_count(mpac->buffer);
367 }
368 
msgpack_unpacker_new(size_t initial_buffer_size)369 msgpack_unpacker* msgpack_unpacker_new(size_t initial_buffer_size)
370 {
371     msgpack_unpacker* mpac = (msgpack_unpacker*)malloc(sizeof(msgpack_unpacker));
372     if(mpac == NULL) {
373         return NULL;
374     }
375 
376     if(!msgpack_unpacker_init(mpac, initial_buffer_size)) {
377         free(mpac);
378         return NULL;
379     }
380 
381     return mpac;
382 }
383 
msgpack_unpacker_free(msgpack_unpacker * mpac)384 void msgpack_unpacker_free(msgpack_unpacker* mpac)
385 {
386     msgpack_unpacker_destroy(mpac);
387     free(mpac);
388 }
389 
msgpack_unpacker_expand_buffer(msgpack_unpacker * mpac,size_t size)390 bool msgpack_unpacker_expand_buffer(msgpack_unpacker* mpac, size_t size)
391 {
392     if(mpac->used == mpac->off && get_count(mpac->buffer) == 1
393             && !CTX_REFERENCED(mpac)) {
394         // rewind buffer
395         mpac->free += mpac->used - COUNTER_SIZE;
396         mpac->used = COUNTER_SIZE;
397         mpac->off = COUNTER_SIZE;
398 
399         if(mpac->free >= size) {
400             return true;
401         }
402     }
403 
404     if(mpac->off == COUNTER_SIZE) {
405         char* tmp;
406         size_t next_size = (mpac->used + mpac->free) * 2;  // include COUNTER_SIZE
407         while(next_size < size + mpac->used) {
408             size_t tmp_next_size = next_size * 2;
409             if (tmp_next_size <= next_size) {
410                 next_size = size + mpac->used;
411                 break;
412             }
413             next_size = tmp_next_size;
414         }
415 
416         tmp = (char*)realloc(mpac->buffer, next_size);
417         if(tmp == NULL) {
418             return false;
419         }
420 
421         mpac->buffer = tmp;
422         mpac->free = next_size - mpac->used;
423 
424     } else {
425         char* tmp;
426         size_t next_size = mpac->initial_buffer_size;  // include COUNTER_SIZE
427         size_t not_parsed = mpac->used - mpac->off;
428         while(next_size < size + not_parsed + COUNTER_SIZE) {
429             size_t tmp_next_size = next_size * 2;
430             if (tmp_next_size <= next_size) {
431                 next_size = size + not_parsed + COUNTER_SIZE;
432                 break;
433             }
434             next_size = tmp_next_size;
435         }
436 
437         tmp = (char*)malloc(next_size);
438         if(tmp == NULL) {
439             return false;
440         }
441 
442         init_count(tmp);
443 
444         memcpy(tmp+COUNTER_SIZE, mpac->buffer+mpac->off, not_parsed);
445 
446         if(CTX_REFERENCED(mpac)) {
447             if(!msgpack_zone_push_finalizer(mpac->z, decr_count, mpac->buffer)) {
448                 free(tmp);
449                 return false;
450             }
451             CTX_REFERENCED(mpac) = false;
452         } else {
453             decr_count(mpac->buffer);
454         }
455 
456         mpac->buffer = tmp;
457         mpac->used = not_parsed + COUNTER_SIZE;
458         mpac->free = next_size - mpac->used;
459         mpac->off = COUNTER_SIZE;
460     }
461 
462     return true;
463 }
464 
msgpack_unpacker_execute(msgpack_unpacker * mpac)465 int msgpack_unpacker_execute(msgpack_unpacker* mpac)
466 {
467     size_t off = mpac->off;
468     int ret = template_execute(CTX_CAST(mpac->ctx),
469             mpac->buffer, mpac->used, &mpac->off);
470     if(mpac->off > off) {
471         mpac->parsed += mpac->off - off;
472     }
473     return ret;
474 }
475 
msgpack_unpacker_data(msgpack_unpacker * mpac)476 msgpack_object msgpack_unpacker_data(msgpack_unpacker* mpac)
477 {
478     return template_data(CTX_CAST(mpac->ctx));
479 }
480 
msgpack_unpacker_release_zone(msgpack_unpacker * mpac)481 msgpack_zone* msgpack_unpacker_release_zone(msgpack_unpacker* mpac)
482 {
483     msgpack_zone* r;
484     msgpack_zone* old;
485 
486     if(!msgpack_unpacker_flush_zone(mpac)) {
487         return NULL;
488     }
489 
490     r = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
491     if(r == NULL) {
492         return NULL;
493     }
494 
495     old = mpac->z;
496     mpac->z = r;
497     CTX_CAST(mpac->ctx)->user.z = mpac->z;
498 
499     return old;
500 }
501 
msgpack_unpacker_reset_zone(msgpack_unpacker * mpac)502 void msgpack_unpacker_reset_zone(msgpack_unpacker* mpac)
503 {
504     msgpack_zone_clear(mpac->z);
505 }
506 
msgpack_unpacker_flush_zone(msgpack_unpacker * mpac)507 bool msgpack_unpacker_flush_zone(msgpack_unpacker* mpac)
508 {
509     if(CTX_REFERENCED(mpac)) {
510         if(!msgpack_zone_push_finalizer(mpac->z, decr_count, mpac->buffer)) {
511             return false;
512         }
513         CTX_REFERENCED(mpac) = false;
514 
515         incr_count(mpac->buffer);
516     }
517 
518     return true;
519 }
520 
msgpack_unpacker_reset(msgpack_unpacker * mpac)521 void msgpack_unpacker_reset(msgpack_unpacker* mpac)
522 {
523     template_init(CTX_CAST(mpac->ctx));
524     // don't reset referenced flag
525     mpac->parsed = 0;
526 }
527 
unpacker_next(msgpack_unpacker * mpac,msgpack_unpacked * result)528 static inline msgpack_unpack_return unpacker_next(msgpack_unpacker* mpac,
529                                                   msgpack_unpacked* result)
530 {
531     int ret;
532 
533     msgpack_unpacked_destroy(result);
534 
535     ret = msgpack_unpacker_execute(mpac);
536 
537     if(ret < 0) {
538         result->zone = NULL;
539         memset(&result->data, 0, sizeof(msgpack_object));
540         return ret;
541     }
542 
543     if(ret == 0) {
544         return MSGPACK_UNPACK_CONTINUE;
545     }
546     result->zone = msgpack_unpacker_release_zone(mpac);
547     result->data = msgpack_unpacker_data(mpac);
548 
549     return MSGPACK_UNPACK_SUCCESS;
550 }
551 
msgpack_unpacker_next(msgpack_unpacker * mpac,msgpack_unpacked * result)552 msgpack_unpack_return msgpack_unpacker_next(msgpack_unpacker* mpac,
553                                             msgpack_unpacked* result)
554 {
555     int ret;
556 
557     ret = unpacker_next(mpac, result);
558     if (ret == MSGPACK_UNPACK_SUCCESS) {
559         msgpack_unpacker_reset(mpac);
560     }
561 
562     return ret;
563 }
564 
565 msgpack_unpack_return
msgpack_unpacker_next_with_size(msgpack_unpacker * mpac,msgpack_unpacked * result,size_t * p_bytes)566 msgpack_unpacker_next_with_size(msgpack_unpacker* mpac,
567                                 msgpack_unpacked* result, size_t *p_bytes)
568 {
569     int ret;
570 
571     ret = unpacker_next(mpac, result);
572     if (ret == MSGPACK_UNPACK_SUCCESS || ret == MSGPACK_UNPACK_CONTINUE) {
573         *p_bytes = mpac->parsed;
574     }
575 
576     if (ret == MSGPACK_UNPACK_SUCCESS) {
577         msgpack_unpacker_reset(mpac);
578     }
579 
580     return ret;
581 }
582 
583 msgpack_unpack_return
msgpack_unpack(const char * data,size_t len,size_t * off,msgpack_zone * result_zone,msgpack_object * result)584 msgpack_unpack(const char* data, size_t len, size_t* off,
585         msgpack_zone* result_zone, msgpack_object* result)
586 {
587     size_t noff = 0;
588     if(off != NULL) { noff = *off; }
589 
590     if(len <= noff) {
591         // FIXME
592         return MSGPACK_UNPACK_CONTINUE;
593     }
594     else {
595         int e;
596         template_context ctx;
597         template_init(&ctx);
598 
599         ctx.user.z = result_zone;
600         ctx.user.referenced = false;
601 
602         e = template_execute(&ctx, data, len, &noff);
603         if(e < 0) {
604             return e;
605         }
606 
607         if(off != NULL) { *off = noff; }
608 
609         if(e == 0) {
610             return MSGPACK_UNPACK_CONTINUE;
611         }
612 
613         *result = template_data(&ctx);
614 
615         if(noff < len) {
616             return MSGPACK_UNPACK_EXTRA_BYTES;
617         }
618 
619         return MSGPACK_UNPACK_SUCCESS;
620     }
621 }
622 
623 msgpack_unpack_return
msgpack_unpack_next(msgpack_unpacked * result,const char * data,size_t len,size_t * off)624 msgpack_unpack_next(msgpack_unpacked* result,
625         const char* data, size_t len, size_t* off)
626 {
627     size_t noff = 0;
628     msgpack_unpacked_destroy(result);
629 
630     if(off != NULL) { noff = *off; }
631 
632     if(len <= noff) {
633         return MSGPACK_UNPACK_CONTINUE;
634     }
635 
636     if (!result->zone) {
637         result->zone = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
638     }
639 
640     if (!result->zone) {
641         return MSGPACK_UNPACK_NOMEM_ERROR;
642     }
643     else {
644         int e;
645         template_context ctx;
646         template_init(&ctx);
647 
648         ctx.user.z = result->zone;
649         ctx.user.referenced = false;
650 
651         e = template_execute(&ctx, data, len, &noff);
652 
653         if(off != NULL) { *off = noff; }
654 
655         if(e < 0) {
656             msgpack_zone_free(result->zone);
657             result->zone = NULL;
658             return e;
659         }
660 
661         if(e == 0) {
662             return MSGPACK_UNPACK_CONTINUE;
663         }
664 
665         result->data = template_data(&ctx);
666 
667         return MSGPACK_UNPACK_SUCCESS;
668     }
669 }
670 
671 #if defined(MSGPACK_OLD_COMPILER_BUS_ERROR_WORKAROUND)
672 // FIXME: Dirty hack to avoid a bus error caused by OS X's old gcc.
dummy_function_to_avoid_bus_error()673 static void dummy_function_to_avoid_bus_error()
674 {
675 }
676 #endif
677