File Coverage

deps/msgpack-c/src/unpack.c
Criterion Covered Total %
statement 138 323 42.7
branch 29 116 25.0
condition n/a
subroutine n/a
pod n/a
total 167 439 38.0


line stmt bran cond sub pod time code
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
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              
51 15           static inline msgpack_object template_callback_root(unpack_user* u)
52             {
53             msgpack_object o;
54             MSGPACK_UNUSED(u);
55 15           o.type = MSGPACK_OBJECT_NIL;
56 15           return o;
57             }
58              
59 1           static inline int template_callback_uint8(unpack_user* u, uint8_t d, msgpack_object* o)
60             {
61             MSGPACK_UNUSED(u);
62 1           o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
63 1           o->via.u64 = d;
64 1           return 0;
65             }
66              
67 0           static inline int template_callback_uint16(unpack_user* u, uint16_t d, msgpack_object* o)
68             {
69             MSGPACK_UNUSED(u);
70 0           o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
71 0           o->via.u64 = d;
72 0           return 0;
73             }
74              
75 0           static inline int template_callback_uint32(unpack_user* u, uint32_t d, msgpack_object* o)
76             {
77             MSGPACK_UNUSED(u);
78 0           o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
79 0           o->via.u64 = d;
80 0           return 0;
81             }
82              
83 0           static inline int template_callback_uint64(unpack_user* u, uint64_t d, msgpack_object* o)
84             {
85             MSGPACK_UNUSED(u);
86 0           o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
87 0           o->via.u64 = d;
88 0           return 0;
89             }
90              
91 0           static inline int template_callback_int8(unpack_user* u, int8_t d, msgpack_object* o)
92             {
93             MSGPACK_UNUSED(u);
94 0 0         if(d >= 0) {
95 0           o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
96 0           o->via.u64 = (uint64_t)d;
97 0           return 0;
98             }
99             else {
100 0           o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER;
101 0           o->via.i64 = d;
102 0           return 0;
103             }
104             }
105              
106 0           static inline int template_callback_int16(unpack_user* u, int16_t d, msgpack_object* o)
107             {
108             MSGPACK_UNUSED(u);
109 0 0         if(d >= 0) {
110 0           o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
111 0           o->via.u64 = (uint64_t)d;
112 0           return 0;
113             }
114             else {
115 0           o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER;
116 0           o->via.i64 = d;
117 0           return 0;
118             }
119             }
120              
121 0           static inline int template_callback_int32(unpack_user* u, int32_t d, msgpack_object* o)
122             {
123             MSGPACK_UNUSED(u);
124 0 0         if(d >= 0) {
125 0           o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
126 0           o->via.u64 = (uint64_t)d;
127 0           return 0;
128             }
129             else {
130 0           o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER;
131 0           o->via.i64 = d;
132 0           return 0;
133             }
134             }
135              
136 0           static inline int template_callback_int64(unpack_user* u, int64_t d, msgpack_object* o)
137             {
138             MSGPACK_UNUSED(u);
139 0 0         if(d >= 0) {
140 0           o->type = MSGPACK_OBJECT_POSITIVE_INTEGER;
141 0           o->via.u64 = (uint64_t)d;
142 0           return 0;
143             }
144             else {
145 0           o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER;
146 0           o->via.i64 = d;
147 0           return 0;
148             }
149             }
150              
151 0           static inline int template_callback_float(unpack_user* u, float d, msgpack_object* o)
152             {
153             MSGPACK_UNUSED(u);
154 0           o->type = MSGPACK_OBJECT_FLOAT32;
155 0           o->via.f64 = d;
156 0           return 0;
157             }
158              
159 0           static inline int template_callback_double(unpack_user* u, double d, msgpack_object* o)
160             {
161             MSGPACK_UNUSED(u);
162 0           o->type = MSGPACK_OBJECT_FLOAT64;
163 0           o->via.f64 = d;
164 0           return 0;
165             }
166              
167 0           static inline int template_callback_nil(unpack_user* u, msgpack_object* o)
168             {
169             MSGPACK_UNUSED(u);
170 0           o->type = MSGPACK_OBJECT_NIL;
171 0           return 0;
172             }
173              
174 2           static inline int template_callback_true(unpack_user* u, msgpack_object* o)
175             {
176             MSGPACK_UNUSED(u);
177 2           o->type = MSGPACK_OBJECT_BOOLEAN;
178 2           o->via.boolean = true;
179 2           return 0;
180             }
181              
182 2           static inline int template_callback_false(unpack_user* u, msgpack_object* o)
183             {
184             MSGPACK_UNUSED(u);
185 2           o->type = MSGPACK_OBJECT_BOOLEAN;
186 2           o->via.boolean = false;
187 2           return 0;
188             }
189              
190 2           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 2           o->type = MSGPACK_OBJECT_ARRAY;
203 2           o->via.array.size = 0;
204              
205 2           size = n * sizeof(msgpack_object);
206              
207 2 50         if (*u->z == NULL) {
208 2           *u->z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
209 2 50         if(*u->z == NULL) {
210 0           return MSGPACK_UNPACK_NOMEM_ERROR;
211             }
212             }
213              
214             // Unsure whether size = 0 should be an error, and if so, what to return
215 2           o->via.array.ptr = (msgpack_object*)msgpack_zone_malloc(*u->z, size);
216 2 50         if(o->via.array.ptr == NULL) { return MSGPACK_UNPACK_NOMEM_ERROR; }
217 2           return 0;
218             }
219              
220 4           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 4           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 4           ++c->via.array.size;
229 4           return 0;
230             }
231              
232 2           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 2           o->type = MSGPACK_OBJECT_MAP;
247 2           o->via.map.size = 0;
248              
249 2           size = n * sizeof(msgpack_object_kv);
250              
251 2 50         if (*u->z == NULL) {
252 2           *u->z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
253 2 50         if(*u->z == NULL) {
254 0           return MSGPACK_UNPACK_NOMEM_ERROR;
255             }
256             }
257              
258             // Should size = 0 be an error? If so, what error to return?
259 2           o->via.map.ptr = (msgpack_object_kv*)msgpack_zone_malloc(*u->z, size);
260 2 50         if(o->via.map.ptr == NULL) { return MSGPACK_UNPACK_NOMEM_ERROR; }
261 2           return 0;
262             }
263              
264 4           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 4           memcpy(&c->via.map.ptr[c->via.map.size].key, &k, sizeof(msgpack_object));
269 4           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 4           ++c->via.map.size;
275 4           return 0;
276             }
277              
278 0           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 0 0         if (*u->z == NULL) {
282 0           *u->z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
283 0 0         if(*u->z == NULL) {
284 0           return MSGPACK_UNPACK_NOMEM_ERROR;
285             }
286             }
287 0           o->type = MSGPACK_OBJECT_STR;
288 0           o->via.str.ptr = p;
289 0           o->via.str.size = l;
290 0           u->referenced = true;
291 0           return 0;
292             }
293              
294 10           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 10 100         if (*u->z == NULL) {
298 1           *u->z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
299 1 50         if(*u->z == NULL) {
300 0           return MSGPACK_UNPACK_NOMEM_ERROR;
301             }
302             }
303 10           o->type = MSGPACK_OBJECT_BIN;
304 10           o->via.bin.ptr = p;
305 10           o->via.bin.size = l;
306 10           u->referenced = true;
307 10           return 0;
308             }
309              
310 2           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 2 50         if (l == 0) {
314 0           return MSGPACK_UNPACK_PARSE_ERROR;
315             }
316 2 50         if (*u->z == NULL) {
317 2           *u->z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
318 2 50         if(*u->z == NULL) {
319 0           return MSGPACK_UNPACK_NOMEM_ERROR;
320             }
321             }
322 2           o->type = MSGPACK_OBJECT_EXT;
323 2           o->via.ext.type = *p;
324 2           o->via.ext.ptr = p + 1;
325 2           o->via.ext.size = l - 1;
326 2           u->referenced = true;
327 2           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              
339 6           static inline void init_count(void* buffer)
340             {
341 6           *(volatile _msgpack_atomic_counter_t*)buffer = 1;
342 6           }
343              
344 13           static inline void decr_count(void* buffer)
345             {
346             // atomic if(--*(_msgpack_atomic_counter_t*)buffer == 0) { free(buffer); }
347 13 100         if(_msgpack_sync_decr_and_fetch((volatile _msgpack_atomic_counter_t*)buffer) == 0) {
348 6           free(buffer);
349             }
350 13           }
351              
352 7           static inline void incr_count(void* buffer)
353             {
354             // atomic ++*(_msgpack_atomic_counter_t*)buffer;
355 7           _msgpack_sync_incr_and_fetch((volatile _msgpack_atomic_counter_t*)buffer);
356 7           }
357              
358 0           static inline _msgpack_atomic_counter_t get_count(void* buffer)
359             {
360 0           return *(volatile _msgpack_atomic_counter_t*)buffer;
361             }
362              
363 6           bool msgpack_unpacker_init(msgpack_unpacker* mpac, size_t initial_buffer_size)
364             {
365             char* buffer;
366             void* ctx;
367              
368 6 50         if(initial_buffer_size < COUNTER_SIZE) {
369 0           initial_buffer_size = COUNTER_SIZE;
370             }
371              
372 6           buffer = (char*)malloc(initial_buffer_size);
373 6 50         if(buffer == NULL) {
374 0           return false;
375             }
376              
377 6           ctx = malloc(sizeof(template_context));
378 6 50         if(ctx == NULL) {
379 0           free(buffer);
380 0           return false;
381             }
382              
383 6           mpac->buffer = buffer;
384 6           mpac->used = COUNTER_SIZE;
385 6           mpac->free = initial_buffer_size - mpac->used;
386 6           mpac->off = COUNTER_SIZE;
387 6           mpac->parsed = 0;
388 6           mpac->initial_buffer_size = initial_buffer_size;
389 6           mpac->z = NULL;
390 6           mpac->ctx = ctx;
391              
392 6           init_count(mpac->buffer);
393              
394 6           template_init(CTX_CAST(mpac->ctx));
395 6           CTX_CAST(mpac->ctx)->user.z = &mpac->z;
396 6           CTX_CAST(mpac->ctx)->user.referenced = false;
397              
398 6           return true;
399             }
400              
401 6           void msgpack_unpacker_destroy(msgpack_unpacker* mpac)
402             {
403 6           msgpack_zone_free(mpac->z);
404 6           free(mpac->ctx);
405 6           decr_count(mpac->buffer);
406 6           }
407              
408 0           msgpack_unpacker* msgpack_unpacker_new(size_t initial_buffer_size)
409             {
410 0           msgpack_unpacker* mpac = (msgpack_unpacker*)malloc(sizeof(msgpack_unpacker));
411 0 0         if(mpac == NULL) {
412 0           return NULL;
413             }
414              
415 0 0         if(!msgpack_unpacker_init(mpac, initial_buffer_size)) {
416 0           free(mpac);
417 0           return NULL;
418             }
419              
420 0           return mpac;
421             }
422              
423 0           void msgpack_unpacker_free(msgpack_unpacker* mpac)
424             {
425 0           msgpack_unpacker_destroy(mpac);
426 0           free(mpac);
427 0           }
428              
429 0           bool msgpack_unpacker_expand_buffer(msgpack_unpacker* mpac, size_t size)
430             {
431 0 0         if(mpac->used == mpac->off && get_count(mpac->buffer) == 1
    0          
432 0 0         && !CTX_REFERENCED(mpac)) {
433             // rewind buffer
434 0           mpac->free += mpac->used - COUNTER_SIZE;
435 0           mpac->used = COUNTER_SIZE;
436 0           mpac->off = COUNTER_SIZE;
437              
438 0 0         if(mpac->free >= size) {
439 0           return true;
440             }
441             }
442              
443 0 0         if(mpac->off == COUNTER_SIZE) {
444             char* tmp;
445 0           size_t next_size = (mpac->used + mpac->free) * 2; // include COUNTER_SIZE
446 0 0         while(next_size < size + mpac->used) {
447 0           size_t tmp_next_size = next_size * 2;
448 0 0         if (tmp_next_size <= next_size) {
449 0           next_size = size + mpac->used;
450 0           break;
451             }
452 0           next_size = tmp_next_size;
453             }
454              
455 0           tmp = (char*)realloc(mpac->buffer, next_size);
456 0 0         if(tmp == NULL) {
457 0           return false;
458             }
459              
460 0           mpac->buffer = tmp;
461 0           mpac->free = next_size - mpac->used;
462              
463             } else {
464             char* tmp;
465 0           size_t next_size = mpac->initial_buffer_size; // include COUNTER_SIZE
466 0           size_t not_parsed = mpac->used - mpac->off;
467 0 0         while(next_size < size + not_parsed + COUNTER_SIZE) {
468 0           size_t tmp_next_size = next_size * 2;
469 0 0         if (tmp_next_size <= next_size) {
470 0           next_size = size + not_parsed + COUNTER_SIZE;
471 0           break;
472             }
473 0           next_size = tmp_next_size;
474             }
475              
476 0           tmp = (char*)malloc(next_size);
477 0 0         if(tmp == NULL) {
478 0           return false;
479             }
480              
481 0           init_count(tmp);
482              
483 0           memcpy(tmp+COUNTER_SIZE, mpac->buffer+mpac->off, not_parsed);
484              
485 0 0         if(CTX_REFERENCED(mpac)) {
486 0 0         if(!msgpack_zone_push_finalizer(mpac->z, decr_count, mpac->buffer)) {
487 0           free(tmp);
488 0           return false;
489             }
490 0           CTX_REFERENCED(mpac) = false;
491             } else {
492 0           decr_count(mpac->buffer);
493             }
494              
495 0           mpac->buffer = tmp;
496 0           mpac->used = not_parsed + COUNTER_SIZE;
497 0           mpac->free = next_size - mpac->used;
498 0           mpac->off = COUNTER_SIZE;
499             }
500              
501 0           return true;
502             }
503              
504 16           int msgpack_unpacker_execute(msgpack_unpacker* mpac)
505             {
506 16           size_t off = mpac->off;
507 16           int ret = template_execute(CTX_CAST(mpac->ctx),
508 16           mpac->buffer, mpac->used, &mpac->off);
509 16 100         if(mpac->off > off) {
510 9           mpac->parsed += mpac->off - off;
511             }
512 16           return ret;
513             }
514              
515 9           msgpack_object msgpack_unpacker_data(msgpack_unpacker* mpac)
516             {
517 9           return template_data(CTX_CAST(mpac->ctx));
518             }
519              
520 9           msgpack_zone* msgpack_unpacker_release_zone(msgpack_unpacker* mpac)
521             {
522 9           msgpack_zone* old = mpac->z;
523              
524 9 100         if (old == NULL) return NULL;
525 7 50         if(!msgpack_unpacker_flush_zone(mpac)) {
526 0           return NULL;
527             }
528              
529 7           mpac->z = NULL;
530 7           CTX_CAST(mpac->ctx)->user.z = &mpac->z;
531              
532 7           return old;
533             }
534              
535 0           void msgpack_unpacker_reset_zone(msgpack_unpacker* mpac)
536             {
537 0           msgpack_zone_clear(mpac->z);
538 0           }
539              
540 7           bool msgpack_unpacker_flush_zone(msgpack_unpacker* mpac)
541             {
542 7 50         if(CTX_REFERENCED(mpac)) {
543 7 50         if(!msgpack_zone_push_finalizer(mpac->z, decr_count, mpac->buffer)) {
544 0           return false;
545             }
546 7           CTX_REFERENCED(mpac) = false;
547              
548 7           incr_count(mpac->buffer);
549             }
550              
551 7           return true;
552             }
553              
554 9           void msgpack_unpacker_reset(msgpack_unpacker* mpac)
555             {
556 9           template_init(CTX_CAST(mpac->ctx));
557             // don't reset referenced flag
558 9           mpac->parsed = 0;
559 9           }
560              
561 16           static inline msgpack_unpack_return unpacker_next(msgpack_unpacker* mpac,
562             msgpack_unpacked* result)
563             {
564             int ret;
565              
566 16           msgpack_unpacked_destroy(result);
567              
568 16           ret = msgpack_unpacker_execute(mpac);
569              
570 16 50         if(ret < 0) {
571 0           result->zone = NULL;
572 0           memset(&result->data, 0, sizeof(msgpack_object));
573 0           return (msgpack_unpack_return)ret;
574             }
575              
576 16 100         if(ret == 0) {
577 7           return MSGPACK_UNPACK_CONTINUE;
578             }
579 9           result->zone = msgpack_unpacker_release_zone(mpac);
580 9           result->data = msgpack_unpacker_data(mpac);
581              
582 9           return MSGPACK_UNPACK_SUCCESS;
583             }
584              
585 16           msgpack_unpack_return msgpack_unpacker_next(msgpack_unpacker* mpac,
586             msgpack_unpacked* result)
587             {
588             msgpack_unpack_return ret;
589              
590 16           ret = unpacker_next(mpac, result);
591 16 100         if (ret == MSGPACK_UNPACK_SUCCESS) {
592 9           msgpack_unpacker_reset(mpac);
593             }
594              
595 16           return ret;
596             }
597              
598             msgpack_unpack_return
599 0           msgpack_unpacker_next_with_size(msgpack_unpacker* mpac,
600             msgpack_unpacked* result, size_t *p_bytes)
601             {
602             msgpack_unpack_return ret;
603              
604 0           ret = unpacker_next(mpac, result);
605 0 0         if (ret == MSGPACK_UNPACK_SUCCESS || ret == MSGPACK_UNPACK_CONTINUE) {
    0          
606 0           *p_bytes = mpac->parsed;
607             }
608              
609 0 0         if (ret == MSGPACK_UNPACK_SUCCESS) {
610 0           msgpack_unpacker_reset(mpac);
611             }
612              
613 0           return ret;
614             }
615              
616             msgpack_unpack_return
617 0           msgpack_unpack(const char* data, size_t len, size_t* off,
618             msgpack_zone* result_zone, msgpack_object* result)
619             {
620 0           size_t noff = 0;
621 0 0         if(off != NULL) { noff = *off; }
622              
623 0 0         if(len <= noff) {
624             // FIXME
625 0           return MSGPACK_UNPACK_CONTINUE;
626             }
627             else {
628             int e;
629             template_context ctx;
630 0           template_init(&ctx);
631              
632 0           ctx.user.z = &result_zone;
633 0           ctx.user.referenced = false;
634              
635 0           e = template_execute(&ctx, data, len, &noff);
636 0 0         if(e < 0) {
637 0           return (msgpack_unpack_return)e;
638             }
639              
640 0 0         if(off != NULL) { *off = noff; }
641              
642 0 0         if(e == 0) {
643 0           return MSGPACK_UNPACK_CONTINUE;
644             }
645              
646 0           *result = template_data(&ctx);
647              
648 0 0         if(noff < len) {
649 0           return MSGPACK_UNPACK_EXTRA_BYTES;
650             }
651              
652 0           return MSGPACK_UNPACK_SUCCESS;
653             }
654             }
655              
656             msgpack_unpack_return
657 0           msgpack_unpack_next(msgpack_unpacked* result,
658             const char* data, size_t len, size_t* off)
659             {
660 0           size_t noff = 0;
661 0           msgpack_unpacked_destroy(result);
662              
663 0 0         if(off != NULL) { noff = *off; }
664              
665 0 0         if(len <= noff) {
666 0           return MSGPACK_UNPACK_CONTINUE;
667             }
668              
669             {
670             int e;
671             template_context ctx;
672 0           template_init(&ctx);
673              
674 0           ctx.user.z = &result->zone;
675 0           ctx.user.referenced = false;
676              
677 0           e = template_execute(&ctx, data, len, &noff);
678              
679 0 0         if(off != NULL) { *off = noff; }
680              
681 0 0         if(e < 0) {
682 0           msgpack_zone_free(result->zone);
683 0           result->zone = NULL;
684 0           return (msgpack_unpack_return)e;
685             }
686              
687 0 0         if(e == 0) {
688 0           return MSGPACK_UNPACK_CONTINUE;
689             }
690              
691 0           result->data = template_data(&ctx);
692              
693 0           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.
699             static void dummy_function_to_avoid_bus_error()
700             {
701             }
702             #endif