sessiond: Add msgpack-c 3.3.0 to the tree
[lttng-tools.git] / src / vendor / msgpack / unpack.c
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 "vendor/msgpack/unpack.h"
11 #include "vendor/msgpack/unpack_define.h"
12 #include "vendor/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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 "vendor/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 static inline void init_count(void* buffer)
340 {
341 *(volatile _msgpack_atomic_counter_t*)buffer = 1;
342 }
343
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
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
358 static inline _msgpack_atomic_counter_t get_count(void* buffer)
359 {
360 return *(volatile _msgpack_atomic_counter_t*)buffer;
361 }
362
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
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
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
423 void msgpack_unpacker_free(msgpack_unpacker* mpac)
424 {
425 msgpack_unpacker_destroy(mpac);
426 free(mpac);
427 }
428
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
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
515 msgpack_object msgpack_unpacker_data(msgpack_unpacker* mpac)
516 {
517 return template_data(CTX_CAST(mpac->ctx));
518 }
519
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
535 void msgpack_unpacker_reset_zone(msgpack_unpacker* mpac)
536 {
537 msgpack_zone_clear(mpac->z);
538 }
539
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
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
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
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
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
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
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.
699 static void dummy_function_to_avoid_bus_error()
700 {
701 }
702 #endif
This page took 0.067523 seconds and 4 git commands to generate.