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     size_t size;
193     // Let's leverage the fact that sizeof(msgpack_object) is a compile time constant
194     // to check for int overflows.
195     // Note - while n is constrained to 32-bit, the product of n * sizeof(msgpack_object)
196     // might not be constrained to 4GB on 64-bit systems
197 #if SIZE_MAX == UINT_MAX
198     if (n > SIZE_MAX/sizeof(msgpack_object))
199         return MSGPACK_UNPACK_NOMEM_ERROR;
200 #endif
201 
202     o->type = MSGPACK_OBJECT_ARRAY;
203     o->via.array.size = 0;
204 
205     size = n * sizeof(msgpack_object);
206 
207     if (*u->z == NULL) {
208         *u->z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
209         if(*u->z == NULL) {
210             return MSGPACK_UNPACK_NOMEM_ERROR;
211         }
212     }
213 
214     // Unsure whether size = 0 should be an error, and if so, what to return
215     o->via.array.ptr = (msgpack_object*)msgpack_zone_malloc(*u->z, size);
216     if(o->via.array.ptr == NULL) { return MSGPACK_UNPACK_NOMEM_ERROR; }
217     return 0;
218 }
219 
template_callback_array_item(unpack_user * u,msgpack_object * c,msgpack_object o)220 static inline int template_callback_array_item(unpack_user* u, msgpack_object* c, msgpack_object o)
221 {
222     MSGPACK_UNUSED(u);
223 #if defined(__GNUC__) && !defined(__clang__)
224     memcpy(&c->via.array.ptr[c->via.array.size], &o, sizeof(msgpack_object));
225 #else  /* __GNUC__ && !__clang__ */
226     c->via.array.ptr[c->via.array.size] = o;
227 #endif /* __GNUC__ && !__clang__ */
228     ++c->via.array.size;
229     return 0;
230 }
231 
template_callback_map(unpack_user * u,unsigned int n,msgpack_object * o)232 static inline int template_callback_map(unpack_user* u, unsigned int n, msgpack_object* o)
233 {
234     size_t size;
235     // Let's leverage the fact that sizeof(msgpack_object_kv) is a compile time constant
236     // to check for int overflows
237     // Note - while n is constrained to 32-bit, the product of n * sizeof(msgpack_object)
238     // might not be constrained to 4GB on 64-bit systems
239 
240     // Note - this will always be false on 64-bit systems
241 #if SIZE_MAX == UINT_MAX
242     if (n > SIZE_MAX/sizeof(msgpack_object_kv))
243         return MSGPACK_UNPACK_NOMEM_ERROR;
244 #endif
245 
246     o->type = MSGPACK_OBJECT_MAP;
247     o->via.map.size = 0;
248 
249     size = n * sizeof(msgpack_object_kv);
250 
251     if (*u->z == NULL) {
252         *u->z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
253         if(*u->z == NULL) {
254             return MSGPACK_UNPACK_NOMEM_ERROR;
255         }
256     }
257 
258     // Should size = 0 be an error? If so, what error to return?
259     o->via.map.ptr = (msgpack_object_kv*)msgpack_zone_malloc(*u->z, size);
260     if(o->via.map.ptr == NULL) { return MSGPACK_UNPACK_NOMEM_ERROR; }
261     return 0;
262 }
263 
template_callback_map_item(unpack_user * u,msgpack_object * c,msgpack_object k,msgpack_object v)264 static inline int template_callback_map_item(unpack_user* u, msgpack_object* c, msgpack_object k, msgpack_object v)
265 {
266     MSGPACK_UNUSED(u);
267 #if defined(__GNUC__) && !defined(__clang__)
268     memcpy(&c->via.map.ptr[c->via.map.size].key, &k, sizeof(msgpack_object));
269     memcpy(&c->via.map.ptr[c->via.map.size].val, &v, sizeof(msgpack_object));
270 #else  /* __GNUC__ && !__clang__ */
271     c->via.map.ptr[c->via.map.size].key = k;
272     c->via.map.ptr[c->via.map.size].val = v;
273 #endif /* __GNUC__ && !__clang__ */
274     ++c->via.map.size;
275     return 0;
276 }
277 
template_callback_str(unpack_user * u,const char * b,const char * p,unsigned int l,msgpack_object * o)278 static inline int template_callback_str(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o)
279 {
280     MSGPACK_UNUSED(b);
281     if (*u->z == NULL) {
282         *u->z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
283         if(*u->z == NULL) {
284             return MSGPACK_UNPACK_NOMEM_ERROR;
285         }
286     }
287     o->type = MSGPACK_OBJECT_STR;
288     o->via.str.ptr = p;
289     o->via.str.size = l;
290     u->referenced = true;
291     return 0;
292 }
293 
template_callback_bin(unpack_user * u,const char * b,const char * p,unsigned int l,msgpack_object * o)294 static inline int template_callback_bin(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o)
295 {
296     MSGPACK_UNUSED(b);
297     if (*u->z == NULL) {
298         *u->z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
299         if(*u->z == NULL) {
300             return MSGPACK_UNPACK_NOMEM_ERROR;
301         }
302     }
303     o->type = MSGPACK_OBJECT_BIN;
304     o->via.bin.ptr = p;
305     o->via.bin.size = l;
306     u->referenced = true;
307     return 0;
308 }
309 
template_callback_ext(unpack_user * u,const char * b,const char * p,unsigned int l,msgpack_object * o)310 static inline int template_callback_ext(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o)
311 {
312     MSGPACK_UNUSED(b);
313     if (l == 0) {
314         return MSGPACK_UNPACK_PARSE_ERROR;
315     }
316     if (*u->z == NULL) {
317         *u->z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
318         if(*u->z == NULL) {
319             return MSGPACK_UNPACK_NOMEM_ERROR;
320         }
321     }
322     o->type = MSGPACK_OBJECT_EXT;
323     o->via.ext.type = *p;
324     o->via.ext.ptr = p + 1;
325     o->via.ext.size = l - 1;
326     u->referenced = true;
327     return 0;
328 }
329 
330 #include "msgpack/unpack_template.h"
331 
332 
333 #define CTX_CAST(m) ((template_context*)(m))
334 #define CTX_REFERENCED(mpac) CTX_CAST((mpac)->ctx)->user.referenced
335 
336 #define COUNTER_SIZE (sizeof(_msgpack_atomic_counter_t))
337 
338 
init_count(void * buffer)339 static inline void init_count(void* buffer)
340 {
341     *(volatile _msgpack_atomic_counter_t*)buffer = 1;
342 }
343 
decr_count(void * buffer)344 static inline void decr_count(void* buffer)
345 {
346     // atomic if(--*(_msgpack_atomic_counter_t*)buffer == 0) { free(buffer); }
347     if(_msgpack_sync_decr_and_fetch((volatile _msgpack_atomic_counter_t*)buffer) == 0) {
348         free(buffer);
349     }
350 }
351 
incr_count(void * buffer)352 static inline void incr_count(void* buffer)
353 {
354     // atomic ++*(_msgpack_atomic_counter_t*)buffer;
355     _msgpack_sync_incr_and_fetch((volatile _msgpack_atomic_counter_t*)buffer);
356 }
357 
get_count(void * buffer)358 static inline _msgpack_atomic_counter_t get_count(void* buffer)
359 {
360     return *(volatile _msgpack_atomic_counter_t*)buffer;
361 }
362 
msgpack_unpacker_init(msgpack_unpacker * mpac,size_t initial_buffer_size)363 bool msgpack_unpacker_init(msgpack_unpacker* mpac, size_t initial_buffer_size)
364 {
365     char* buffer;
366     void* ctx;
367 
368     if(initial_buffer_size < COUNTER_SIZE) {
369         initial_buffer_size = COUNTER_SIZE;
370     }
371 
372     buffer = (char*)malloc(initial_buffer_size);
373     if(buffer == NULL) {
374         return false;
375     }
376 
377     ctx = malloc(sizeof(template_context));
378     if(ctx == NULL) {
379         free(buffer);
380         return false;
381     }
382 
383     mpac->buffer = buffer;
384     mpac->used = COUNTER_SIZE;
385     mpac->free = initial_buffer_size - mpac->used;
386     mpac->off = COUNTER_SIZE;
387     mpac->parsed = 0;
388     mpac->initial_buffer_size = initial_buffer_size;
389     mpac->z = NULL;
390     mpac->ctx = ctx;
391 
392     init_count(mpac->buffer);
393 
394     template_init(CTX_CAST(mpac->ctx));
395     CTX_CAST(mpac->ctx)->user.z = &mpac->z;
396     CTX_CAST(mpac->ctx)->user.referenced = false;
397 
398     return true;
399 }
400 
msgpack_unpacker_destroy(msgpack_unpacker * mpac)401 void msgpack_unpacker_destroy(msgpack_unpacker* mpac)
402 {
403     msgpack_zone_free(mpac->z);
404     free(mpac->ctx);
405     decr_count(mpac->buffer);
406 }
407 
msgpack_unpacker_new(size_t initial_buffer_size)408 msgpack_unpacker* msgpack_unpacker_new(size_t initial_buffer_size)
409 {
410     msgpack_unpacker* mpac = (msgpack_unpacker*)malloc(sizeof(msgpack_unpacker));
411     if(mpac == NULL) {
412         return NULL;
413     }
414 
415     if(!msgpack_unpacker_init(mpac, initial_buffer_size)) {
416         free(mpac);
417         return NULL;
418     }
419 
420     return mpac;
421 }
422 
msgpack_unpacker_free(msgpack_unpacker * mpac)423 void msgpack_unpacker_free(msgpack_unpacker* mpac)
424 {
425     msgpack_unpacker_destroy(mpac);
426     free(mpac);
427 }
428 
msgpack_unpacker_expand_buffer(msgpack_unpacker * mpac,size_t size)429 bool msgpack_unpacker_expand_buffer(msgpack_unpacker* mpac, size_t size)
430 {
431     if(mpac->used == mpac->off && get_count(mpac->buffer) == 1
432             && !CTX_REFERENCED(mpac)) {
433         // rewind buffer
434         mpac->free += mpac->used - COUNTER_SIZE;
435         mpac->used = COUNTER_SIZE;
436         mpac->off = COUNTER_SIZE;
437 
438         if(mpac->free >= size) {
439             return true;
440         }
441     }
442 
443     if(mpac->off == COUNTER_SIZE) {
444         char* tmp;
445         size_t next_size = (mpac->used + mpac->free) * 2;  // include COUNTER_SIZE
446         while(next_size < size + mpac->used) {
447             size_t tmp_next_size = next_size * 2;
448             if (tmp_next_size <= next_size) {
449                 next_size = size + mpac->used;
450                 break;
451             }
452             next_size = tmp_next_size;
453         }
454 
455         tmp = (char*)realloc(mpac->buffer, next_size);
456         if(tmp == NULL) {
457             return false;
458         }
459 
460         mpac->buffer = tmp;
461         mpac->free = next_size - mpac->used;
462 
463     } else {
464         char* tmp;
465         size_t next_size = mpac->initial_buffer_size;  // include COUNTER_SIZE
466         size_t not_parsed = mpac->used - mpac->off;
467         while(next_size < size + not_parsed + COUNTER_SIZE) {
468             size_t tmp_next_size = next_size * 2;
469             if (tmp_next_size <= next_size) {
470                 next_size = size + not_parsed + COUNTER_SIZE;
471                 break;
472             }
473             next_size = tmp_next_size;
474         }
475 
476         tmp = (char*)malloc(next_size);
477         if(tmp == NULL) {
478             return false;
479         }
480 
481         init_count(tmp);
482 
483         memcpy(tmp+COUNTER_SIZE, mpac->buffer+mpac->off, not_parsed);
484 
485         if(CTX_REFERENCED(mpac)) {
486             if(!msgpack_zone_push_finalizer(mpac->z, decr_count, mpac->buffer)) {
487                 free(tmp);
488                 return false;
489             }
490             CTX_REFERENCED(mpac) = false;
491         } else {
492             decr_count(mpac->buffer);
493         }
494 
495         mpac->buffer = tmp;
496         mpac->used = not_parsed + COUNTER_SIZE;
497         mpac->free = next_size - mpac->used;
498         mpac->off = COUNTER_SIZE;
499     }
500 
501     return true;
502 }
503 
msgpack_unpacker_execute(msgpack_unpacker * mpac)504 int msgpack_unpacker_execute(msgpack_unpacker* mpac)
505 {
506     size_t off = mpac->off;
507     int ret = template_execute(CTX_CAST(mpac->ctx),
508             mpac->buffer, mpac->used, &mpac->off);
509     if(mpac->off > off) {
510         mpac->parsed += mpac->off - off;
511     }
512     return ret;
513 }
514 
msgpack_unpacker_data(msgpack_unpacker * mpac)515 msgpack_object msgpack_unpacker_data(msgpack_unpacker* mpac)
516 {
517     return template_data(CTX_CAST(mpac->ctx));
518 }
519 
msgpack_unpacker_release_zone(msgpack_unpacker * mpac)520 msgpack_zone* msgpack_unpacker_release_zone(msgpack_unpacker* mpac)
521 {
522     msgpack_zone* old = mpac->z;
523 
524     if (old == NULL) return NULL;
525     if(!msgpack_unpacker_flush_zone(mpac)) {
526         return NULL;
527     }
528 
529     mpac->z = NULL;
530     CTX_CAST(mpac->ctx)->user.z = &mpac->z;
531 
532     return old;
533 }
534 
msgpack_unpacker_reset_zone(msgpack_unpacker * mpac)535 void msgpack_unpacker_reset_zone(msgpack_unpacker* mpac)
536 {
537     msgpack_zone_clear(mpac->z);
538 }
539 
msgpack_unpacker_flush_zone(msgpack_unpacker * mpac)540 bool msgpack_unpacker_flush_zone(msgpack_unpacker* mpac)
541 {
542     if(CTX_REFERENCED(mpac)) {
543         if(!msgpack_zone_push_finalizer(mpac->z, decr_count, mpac->buffer)) {
544             return false;
545         }
546         CTX_REFERENCED(mpac) = false;
547 
548         incr_count(mpac->buffer);
549     }
550 
551     return true;
552 }
553 
msgpack_unpacker_reset(msgpack_unpacker * mpac)554 void msgpack_unpacker_reset(msgpack_unpacker* mpac)
555 {
556     template_init(CTX_CAST(mpac->ctx));
557     // don't reset referenced flag
558     mpac->parsed = 0;
559 }
560 
unpacker_next(msgpack_unpacker * mpac,msgpack_unpacked * result)561 static inline msgpack_unpack_return unpacker_next(msgpack_unpacker* mpac,
562                                                   msgpack_unpacked* result)
563 {
564     int ret;
565 
566     msgpack_unpacked_destroy(result);
567 
568     ret = msgpack_unpacker_execute(mpac);
569 
570     if(ret < 0) {
571         result->zone = NULL;
572         memset(&result->data, 0, sizeof(msgpack_object));
573         return (msgpack_unpack_return)ret;
574     }
575 
576     if(ret == 0) {
577         return MSGPACK_UNPACK_CONTINUE;
578     }
579     result->zone = msgpack_unpacker_release_zone(mpac);
580     result->data = msgpack_unpacker_data(mpac);
581 
582     return MSGPACK_UNPACK_SUCCESS;
583 }
584 
msgpack_unpacker_next(msgpack_unpacker * mpac,msgpack_unpacked * result)585 msgpack_unpack_return msgpack_unpacker_next(msgpack_unpacker* mpac,
586                                             msgpack_unpacked* result)
587 {
588     msgpack_unpack_return ret;
589 
590     ret = unpacker_next(mpac, result);
591     if (ret == MSGPACK_UNPACK_SUCCESS) {
592         msgpack_unpacker_reset(mpac);
593     }
594 
595     return ret;
596 }
597 
598 msgpack_unpack_return
msgpack_unpacker_next_with_size(msgpack_unpacker * mpac,msgpack_unpacked * result,size_t * p_bytes)599 msgpack_unpacker_next_with_size(msgpack_unpacker* mpac,
600                                 msgpack_unpacked* result, size_t *p_bytes)
601 {
602     msgpack_unpack_return ret;
603 
604     ret = unpacker_next(mpac, result);
605     if (ret == MSGPACK_UNPACK_SUCCESS || ret == MSGPACK_UNPACK_CONTINUE) {
606         *p_bytes = mpac->parsed;
607     }
608 
609     if (ret == MSGPACK_UNPACK_SUCCESS) {
610         msgpack_unpacker_reset(mpac);
611     }
612 
613     return ret;
614 }
615 
616 msgpack_unpack_return
msgpack_unpack(const char * data,size_t len,size_t * off,msgpack_zone * result_zone,msgpack_object * result)617 msgpack_unpack(const char* data, size_t len, size_t* off,
618         msgpack_zone* result_zone, msgpack_object* result)
619 {
620     size_t noff = 0;
621     if(off != NULL) { noff = *off; }
622 
623     if(len <= noff) {
624         // FIXME
625         return MSGPACK_UNPACK_CONTINUE;
626     }
627     else {
628         int e;
629         template_context ctx;
630         template_init(&ctx);
631 
632         ctx.user.z = &result_zone;
633         ctx.user.referenced = false;
634 
635         e = template_execute(&ctx, data, len, &noff);
636         if(e < 0) {
637             return (msgpack_unpack_return)e;
638         }
639 
640         if(off != NULL) { *off = noff; }
641 
642         if(e == 0) {
643             return MSGPACK_UNPACK_CONTINUE;
644         }
645 
646         *result = template_data(&ctx);
647 
648         if(noff < len) {
649             return MSGPACK_UNPACK_EXTRA_BYTES;
650         }
651 
652         return MSGPACK_UNPACK_SUCCESS;
653     }
654 }
655 
656 msgpack_unpack_return
msgpack_unpack_next(msgpack_unpacked * result,const char * data,size_t len,size_t * off)657 msgpack_unpack_next(msgpack_unpacked* result,
658         const char* data, size_t len, size_t* off)
659 {
660     size_t noff = 0;
661     msgpack_unpacked_destroy(result);
662 
663     if(off != NULL) { noff = *off; }
664 
665     if(len <= noff) {
666         return MSGPACK_UNPACK_CONTINUE;
667     }
668 
669     {
670         int e;
671         template_context ctx;
672         template_init(&ctx);
673 
674         ctx.user.z = &result->zone;
675         ctx.user.referenced = false;
676 
677         e = template_execute(&ctx, data, len, &noff);
678 
679         if(off != NULL) { *off = noff; }
680 
681         if(e < 0) {
682             msgpack_zone_free(result->zone);
683             result->zone = NULL;
684             return (msgpack_unpack_return)e;
685         }
686 
687         if(e == 0) {
688             return MSGPACK_UNPACK_CONTINUE;
689         }
690 
691         result->data = template_data(&ctx);
692 
693         return MSGPACK_UNPACK_SUCCESS;
694     }
695 }
696 
697 #if defined(MSGPACK_OLD_COMPILER_BUS_ERROR_WORKAROUND)
698 // FIXME: Dirty hack to avoid a bus error caused by OS X's old gcc.
dummy_function_to_avoid_bus_error()699 static void dummy_function_to_avoid_bus_error()
700 {
701 }
702 #endif
703