1 /*
2 * MessagePack for C dynamic typing 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/object.h"
11 #include "msgpack/pack.h"
12 #include <ctype.h>
13 #include <stdio.h>
14 #include <string.h>
15
16 #if defined(_MSC_VER)
17 #if _MSC_VER >= 1800
18 #include <inttypes.h>
19 #else
20 #define PRIu64 "I64u"
21 #define PRIi64 "I64i"
22 #define PRIi8 "i"
23 #endif
24 #else
25 #include <inttypes.h>
26 #endif
27
28
msgpack_pack_object(msgpack_packer * pk,msgpack_object d)29 int msgpack_pack_object(msgpack_packer* pk, msgpack_object d)
30 {
31 switch(d.type) {
32 case MSGPACK_OBJECT_NIL:
33 return msgpack_pack_nil(pk);
34
35 case MSGPACK_OBJECT_BOOLEAN:
36 if(d.via.boolean) {
37 return msgpack_pack_true(pk);
38 } else {
39 return msgpack_pack_false(pk);
40 }
41
42 case MSGPACK_OBJECT_POSITIVE_INTEGER:
43 return msgpack_pack_uint64(pk, d.via.u64);
44
45 case MSGPACK_OBJECT_NEGATIVE_INTEGER:
46 return msgpack_pack_int64(pk, d.via.i64);
47
48 case MSGPACK_OBJECT_FLOAT32:
49 return msgpack_pack_float(pk, (float)d.via.f64);
50
51 case MSGPACK_OBJECT_FLOAT64:
52 return msgpack_pack_double(pk, d.via.f64);
53
54 case MSGPACK_OBJECT_STR:
55 {
56 int ret = msgpack_pack_str(pk, d.via.str.size);
57 if(ret < 0) { return ret; }
58 return msgpack_pack_str_body(pk, d.via.str.ptr, d.via.str.size);
59 }
60
61 case MSGPACK_OBJECT_BIN:
62 {
63 int ret = msgpack_pack_bin(pk, d.via.bin.size);
64 if(ret < 0) { return ret; }
65 return msgpack_pack_bin_body(pk, d.via.bin.ptr, d.via.bin.size);
66 }
67
68 case MSGPACK_OBJECT_EXT:
69 {
70 int ret = msgpack_pack_ext(pk, d.via.ext.size, d.via.ext.type);
71 if(ret < 0) { return ret; }
72 return msgpack_pack_ext_body(pk, d.via.ext.ptr, d.via.ext.size);
73 }
74
75 case MSGPACK_OBJECT_ARRAY:
76 {
77 int ret = msgpack_pack_array(pk, d.via.array.size);
78 if(ret < 0) {
79 return ret;
80 }
81 else {
82 msgpack_object* o = d.via.array.ptr;
83 msgpack_object* const oend = d.via.array.ptr + d.via.array.size;
84 for(; o != oend; ++o) {
85 ret = msgpack_pack_object(pk, *o);
86 if(ret < 0) { return ret; }
87 }
88
89 return 0;
90 }
91 }
92
93 case MSGPACK_OBJECT_MAP:
94 {
95 int ret = msgpack_pack_map(pk, d.via.map.size);
96 if(ret < 0) {
97 return ret;
98 }
99 else {
100 msgpack_object_kv* kv = d.via.map.ptr;
101 msgpack_object_kv* const kvend = d.via.map.ptr + d.via.map.size;
102 for(; kv != kvend; ++kv) {
103 ret = msgpack_pack_object(pk, kv->key);
104 if(ret < 0) { return ret; }
105 ret = msgpack_pack_object(pk, kv->val);
106 if(ret < 0) { return ret; }
107 }
108
109 return 0;
110 }
111 }
112
113 default:
114 return -1;
115 }
116 }
117
118
msgpack_object_bin_print(FILE * out,const char * ptr,size_t size)119 static void msgpack_object_bin_print(FILE* out, const char *ptr, size_t size)
120 {
121 size_t i;
122 for (i = 0; i < size; ++i) {
123 if (ptr[i] == '"') {
124 fputs("\\\"", out);
125 } else if (isprint((unsigned char)ptr[i])) {
126 fputc(ptr[i], out);
127 } else {
128 fprintf(out, "\\x%02x", (unsigned char)ptr[i]);
129 }
130 }
131 }
132
msgpack_object_bin_print_buffer(char * buffer,size_t buffer_size,const char * ptr,size_t size)133 static int msgpack_object_bin_print_buffer(char *buffer, size_t buffer_size, const char *ptr, size_t size)
134 {
135 size_t i;
136 char *aux_buffer = buffer;
137 size_t aux_buffer_size = buffer_size;
138 int ret;
139
140 for (i = 0; i < size; ++i) {
141 if (ptr[i] == '"') {
142 ret = snprintf(aux_buffer, aux_buffer_size, "\\\"");
143 aux_buffer = aux_buffer + ret;
144 aux_buffer_size = aux_buffer_size - ret;
145 } else if (isprint((unsigned char)ptr[i])) {
146 if (aux_buffer_size > 0) {
147 memcpy(aux_buffer, ptr + i, 1);
148 aux_buffer = aux_buffer + 1;
149 aux_buffer_size = aux_buffer_size - 1;
150 }
151 } else {
152 ret = snprintf(aux_buffer, aux_buffer_size, "\\x%02x", (unsigned char)ptr[i]);
153 aux_buffer = aux_buffer + ret;
154 aux_buffer_size = aux_buffer_size - ret;
155 }
156 }
157
158 return buffer_size - aux_buffer_size;
159 }
160
161
msgpack_object_print(FILE * out,msgpack_object o)162 void msgpack_object_print(FILE* out, msgpack_object o)
163 {
164 switch(o.type) {
165 case MSGPACK_OBJECT_NIL:
166 fprintf(out, "nil");
167 break;
168
169 case MSGPACK_OBJECT_BOOLEAN:
170 fprintf(out, (o.via.boolean ? "true" : "false"));
171 break;
172
173 case MSGPACK_OBJECT_POSITIVE_INTEGER:
174 #if defined(PRIu64)
175 fprintf(out, "%" PRIu64, o.via.u64);
176 #else
177 if (o.via.u64 > ULONG_MAX)
178 fprintf(out, "over 4294967295");
179 else
180 fprintf(out, "%lu", (unsigned long)o.via.u64);
181 #endif
182 break;
183
184 case MSGPACK_OBJECT_NEGATIVE_INTEGER:
185 #if defined(PRIi64)
186 fprintf(out, "%" PRIi64, o.via.i64);
187 #else
188 if (o.via.i64 > LONG_MAX)
189 fprintf(out, "over +2147483647");
190 else if (o.via.i64 < LONG_MIN)
191 fprintf(out, "under -2147483648");
192 else
193 fprintf(out, "%ld", (signed long)o.via.i64);
194 #endif
195 break;
196
197 case MSGPACK_OBJECT_FLOAT32:
198 case MSGPACK_OBJECT_FLOAT64:
199 fprintf(out, "%f", o.via.f64);
200 break;
201
202 case MSGPACK_OBJECT_STR:
203 fprintf(out, "\"");
204 fwrite(o.via.str.ptr, o.via.str.size, 1, out);
205 fprintf(out, "\"");
206 break;
207
208 case MSGPACK_OBJECT_BIN:
209 fprintf(out, "\"");
210 msgpack_object_bin_print(out, o.via.bin.ptr, o.via.bin.size);
211 fprintf(out, "\"");
212 break;
213
214 case MSGPACK_OBJECT_EXT:
215 #if defined(PRIi8)
216 fprintf(out, "(ext: %" PRIi8 ")", o.via.ext.type);
217 #else
218 fprintf(out, "(ext: %d)", (int)o.via.ext.type);
219 #endif
220 fprintf(out, "\"");
221 msgpack_object_bin_print(out, o.via.ext.ptr, o.via.ext.size);
222 fprintf(out, "\"");
223 break;
224
225 case MSGPACK_OBJECT_ARRAY:
226 fprintf(out, "[");
227 if(o.via.array.size != 0) {
228 msgpack_object* p = o.via.array.ptr;
229 msgpack_object* const pend = o.via.array.ptr + o.via.array.size;
230 msgpack_object_print(out, *p);
231 ++p;
232 for(; p < pend; ++p) {
233 fprintf(out, ", ");
234 msgpack_object_print(out, *p);
235 }
236 }
237 fprintf(out, "]");
238 break;
239
240 case MSGPACK_OBJECT_MAP:
241 fprintf(out, "{");
242 if(o.via.map.size != 0) {
243 msgpack_object_kv* p = o.via.map.ptr;
244 msgpack_object_kv* const pend = o.via.map.ptr + o.via.map.size;
245 msgpack_object_print(out, p->key);
246 fprintf(out, "=>");
247 msgpack_object_print(out, p->val);
248 ++p;
249 for(; p < pend; ++p) {
250 fprintf(out, ", ");
251 msgpack_object_print(out, p->key);
252 fprintf(out, "=>");
253 msgpack_object_print(out, p->val);
254 }
255 }
256 fprintf(out, "}");
257 break;
258
259 default:
260 // FIXME
261 #if defined(PRIu64)
262 fprintf(out, "#<UNKNOWN %i %" PRIu64 ">", o.type, o.via.u64);
263 #else
264 if (o.via.u64 > ULONG_MAX)
265 fprintf(out, "#<UNKNOWN %i over 4294967295>", o.type);
266 else
267 fprintf(out, "#<UNKNOWN %i %lu>", o.type, (unsigned long)o.via.u64);
268 #endif
269
270 }
271 }
272
msgpack_object_print_buffer(char * buffer,size_t buffer_size,msgpack_object o)273 int msgpack_object_print_buffer(char *buffer, size_t buffer_size, msgpack_object o)
274 {
275 char *aux_buffer = buffer;
276 size_t aux_buffer_size = buffer_size;
277 int ret;
278 switch(o.type) {
279 case MSGPACK_OBJECT_NIL:
280 ret = snprintf(aux_buffer, aux_buffer_size, "nil");
281 aux_buffer = aux_buffer + ret;
282 aux_buffer_size = aux_buffer_size - ret;
283 break;
284
285 case MSGPACK_OBJECT_BOOLEAN:
286 ret = snprintf(aux_buffer, aux_buffer_size, (o.via.boolean ? "true" : "false"));
287 aux_buffer = aux_buffer + ret;
288 aux_buffer_size = aux_buffer_size - ret;
289 break;
290
291 case MSGPACK_OBJECT_POSITIVE_INTEGER:
292 #if defined(PRIu64)
293 ret = snprintf(aux_buffer, aux_buffer_size, "%" PRIu64, o.via.u64);
294 aux_buffer = aux_buffer + ret;
295 aux_buffer_size = aux_buffer_size - ret;
296 #else
297 if (o.via.u64 > ULONG_MAX) {
298 ret = snprintf(aux_buffer, aux_buffer_size, "over 4294967295");
299 aux_buffer = aux_buffer + ret;
300 aux_buffer_size = aux_buffer_size - ret;
301 } else {
302 ret = snprintf(aux_buffer, aux_buffer_size, "%lu", (unsigned long)o.via.u64);
303 aux_buffer = aux_buffer + ret;
304 aux_buffer_size = aux_buffer_size - ret;
305 }
306 #endif
307 break;
308
309 case MSGPACK_OBJECT_NEGATIVE_INTEGER:
310 #if defined(PRIi64)
311 ret = snprintf(aux_buffer, aux_buffer_size, "%" PRIi64, o.via.i64);
312 aux_buffer = aux_buffer + ret;
313 aux_buffer_size = aux_buffer_size - ret;
314 #else
315 if (o.via.i64 > LONG_MAX) {
316 ret = snprintf(aux_buffer, aux_buffer_size, "over +2147483647");
317 aux_buffer = aux_buffer + ret;
318 aux_buffer_size = aux_buffer_size - ret;
319 } else if (o.via.i64 < LONG_MIN) {
320 ret = snprintf(aux_buffer, aux_buffer_size, "under -2147483648");
321 aux_buffer = aux_buffer + ret;
322 aux_buffer_size = aux_buffer_size - ret;
323 } else {
324 ret = snprintf(aux_buffer, aux_buffer_size, "%ld", (signed long)o.via.i64);
325 aux_buffer = aux_buffer + ret;
326 aux_buffer_size = aux_buffer_size - ret;
327 }
328 #endif
329 break;
330
331 case MSGPACK_OBJECT_FLOAT32:
332 case MSGPACK_OBJECT_FLOAT64:
333 ret = snprintf(aux_buffer, aux_buffer_size, "%f", o.via.f64);
334 aux_buffer = aux_buffer + ret;
335 aux_buffer_size = aux_buffer_size - ret;
336 break;
337
338 case MSGPACK_OBJECT_STR:
339 ret = snprintf(aux_buffer, aux_buffer_size, "\"");
340 aux_buffer = aux_buffer + ret;
341 aux_buffer_size = aux_buffer_size - ret;
342 ret = snprintf(aux_buffer, aux_buffer_size, "%.*s", (int)o.via.str.size, o.via.str.ptr);
343 aux_buffer = aux_buffer + ret;
344 aux_buffer_size = aux_buffer_size - ret;
345 ret = snprintf(aux_buffer, aux_buffer_size, "\"");
346 aux_buffer = aux_buffer + ret;
347 aux_buffer_size = aux_buffer_size - ret;
348 break;
349
350 case MSGPACK_OBJECT_BIN:
351 ret = snprintf(aux_buffer, aux_buffer_size, "\"");
352 aux_buffer = aux_buffer + ret;
353 aux_buffer_size = aux_buffer_size - ret;
354
355 ret = msgpack_object_bin_print_buffer(aux_buffer, aux_buffer_size, o.via.bin.ptr, o.via.bin.size);
356 aux_buffer = aux_buffer + ret;
357 aux_buffer_size = aux_buffer_size - ret;
358
359 ret = snprintf(aux_buffer, aux_buffer_size, "\"");
360 aux_buffer = aux_buffer + ret;
361 aux_buffer_size = aux_buffer_size - ret;
362 break;
363
364 case MSGPACK_OBJECT_EXT:
365 #if defined(PRIi8)
366 ret = snprintf(aux_buffer, aux_buffer_size, "(ext: %" PRIi8 ")", o.via.ext.type);
367 aux_buffer = aux_buffer + ret;
368 aux_buffer_size = aux_buffer_size - ret;
369 #else
370 ret = snprintf(aux_buffer, aux_buffer_size, "(ext: %d)", (int)o.via.ext.type);
371 aux_buffer = aux_buffer + ret;
372 aux_buffer_size = aux_buffer_size - ret;
373 #endif
374 ret = snprintf(aux_buffer, aux_buffer_size, "\"");
375 aux_buffer = aux_buffer + ret;
376 aux_buffer_size = aux_buffer_size - ret;
377
378 ret = msgpack_object_bin_print_buffer(aux_buffer, aux_buffer_size, o.via.ext.ptr, o.via.ext.size);
379 aux_buffer = aux_buffer + ret;
380 aux_buffer_size = aux_buffer_size - ret;
381
382 ret = snprintf(aux_buffer, aux_buffer_size, "\"");
383 aux_buffer = aux_buffer + ret;
384 aux_buffer_size = aux_buffer_size - ret;
385 break;
386
387 case MSGPACK_OBJECT_ARRAY:
388 ret = snprintf(aux_buffer, aux_buffer_size, "[");
389 aux_buffer = aux_buffer + ret;
390 aux_buffer_size = aux_buffer_size - ret;
391 if(o.via.array.size != 0) {
392 msgpack_object* p = o.via.array.ptr;
393 msgpack_object* const pend = o.via.array.ptr + o.via.array.size;
394 ret = msgpack_object_print_buffer(aux_buffer, aux_buffer_size, *p);
395 aux_buffer = aux_buffer + ret;
396 aux_buffer_size = aux_buffer_size - ret;
397 ++p;
398 for(; p < pend; ++p) {
399 ret = snprintf(aux_buffer, aux_buffer_size, ", ");
400 aux_buffer = aux_buffer + ret;
401 aux_buffer_size = aux_buffer_size - ret;
402 ret = msgpack_object_print_buffer(aux_buffer, aux_buffer_size, *p);
403 aux_buffer = aux_buffer + ret;
404 aux_buffer_size = aux_buffer_size - ret;
405 }
406 }
407 ret = snprintf(aux_buffer, aux_buffer_size, "]");
408 aux_buffer = aux_buffer + ret;
409 aux_buffer_size = aux_buffer_size - ret;
410 break;
411
412 case MSGPACK_OBJECT_MAP:
413 ret = snprintf(aux_buffer, aux_buffer_size, "{");
414 aux_buffer = aux_buffer + ret;
415 aux_buffer_size = aux_buffer_size - ret;
416 if(o.via.map.size != 0) {
417 msgpack_object_kv* p = o.via.map.ptr;
418 msgpack_object_kv* const pend = o.via.map.ptr + o.via.map.size;
419 ret = msgpack_object_print_buffer(aux_buffer, aux_buffer_size, p->key);
420 aux_buffer = aux_buffer + ret;
421 aux_buffer_size = aux_buffer_size - ret;
422 ret = snprintf(aux_buffer, aux_buffer_size, "=>");
423 aux_buffer = aux_buffer + ret;
424 aux_buffer_size = aux_buffer_size - ret;
425 ret = msgpack_object_print_buffer(aux_buffer, aux_buffer_size, p->val);
426 aux_buffer = aux_buffer + ret;
427 aux_buffer_size = aux_buffer_size - ret;
428 ++p;
429 for(; p < pend; ++p) {
430 ret = snprintf(aux_buffer, aux_buffer_size, ", ");
431 aux_buffer = aux_buffer + ret;
432 aux_buffer_size = aux_buffer_size - ret;
433 ret = msgpack_object_print_buffer(aux_buffer, aux_buffer_size, p->key);
434 aux_buffer = aux_buffer + ret;
435 aux_buffer_size = aux_buffer_size - ret;
436 ret = snprintf(aux_buffer, aux_buffer_size, "=>");
437 aux_buffer = aux_buffer + ret;
438 aux_buffer_size = aux_buffer_size - ret;
439 ret = msgpack_object_print_buffer(aux_buffer, aux_buffer_size, p->val);
440 aux_buffer = aux_buffer + ret;
441 aux_buffer_size = aux_buffer_size - ret;
442 }
443 }
444 ret = snprintf(aux_buffer, aux_buffer_size, "}");
445 aux_buffer = aux_buffer + ret;
446 aux_buffer_size = aux_buffer_size - ret;
447 break;
448
449 default:
450 // FIXME
451 #if defined(PRIu64)
452 ret = snprintf(aux_buffer, aux_buffer_size, "#<UNKNOWN %i %" PRIu64 ">", o.type, o.via.u64);
453 aux_buffer = aux_buffer + ret;
454 aux_buffer_size = aux_buffer_size - ret;
455 #else
456 if (o.via.u64 > ULONG_MAX) {
457 ret = snprintf(aux_buffer, aux_buffer_size, "#<UNKNOWN %i over 4294967295>", o.type);
458 aux_buffer = aux_buffer + ret;
459 aux_buffer_size = aux_buffer_size - ret;
460 } else {
461 ret = snprintf(aux_buffer, aux_buffer_size, "#<UNKNOWN %i %lu>", o.type, (unsigned long)o.via.u64);
462 aux_buffer = aux_buffer + ret;
463 aux_buffer_size = aux_buffer_size - ret;
464 }
465 #endif
466 }
467
468 return buffer_size - aux_buffer_size;
469 }
470
471
msgpack_object_equal(const msgpack_object x,const msgpack_object y)472 bool msgpack_object_equal(const msgpack_object x, const msgpack_object y)
473 {
474 if(x.type != y.type) { return false; }
475
476 switch(x.type) {
477 case MSGPACK_OBJECT_NIL:
478 return true;
479
480 case MSGPACK_OBJECT_BOOLEAN:
481 return x.via.boolean == y.via.boolean;
482
483 case MSGPACK_OBJECT_POSITIVE_INTEGER:
484 return x.via.u64 == y.via.u64;
485
486 case MSGPACK_OBJECT_NEGATIVE_INTEGER:
487 return x.via.i64 == y.via.i64;
488
489 case MSGPACK_OBJECT_FLOAT32:
490 case MSGPACK_OBJECT_FLOAT64:
491 return x.via.f64 == y.via.f64;
492
493 case MSGPACK_OBJECT_STR:
494 return x.via.str.size == y.via.str.size &&
495 memcmp(x.via.str.ptr, y.via.str.ptr, x.via.str.size) == 0;
496
497 case MSGPACK_OBJECT_BIN:
498 return x.via.bin.size == y.via.bin.size &&
499 memcmp(x.via.bin.ptr, y.via.bin.ptr, x.via.bin.size) == 0;
500
501 case MSGPACK_OBJECT_EXT:
502 return x.via.ext.size == y.via.ext.size &&
503 x.via.ext.type == y.via.ext.type &&
504 memcmp(x.via.ext.ptr, y.via.ext.ptr, x.via.ext.size) == 0;
505
506 case MSGPACK_OBJECT_ARRAY:
507 if(x.via.array.size != y.via.array.size) {
508 return false;
509 } else if(x.via.array.size == 0) {
510 return true;
511 } else {
512 msgpack_object* px = x.via.array.ptr;
513 msgpack_object* const pxend = x.via.array.ptr + x.via.array.size;
514 msgpack_object* py = y.via.array.ptr;
515 do {
516 if(!msgpack_object_equal(*px, *py)) {
517 return false;
518 }
519 ++px;
520 ++py;
521 } while(px < pxend);
522 return true;
523 }
524
525 case MSGPACK_OBJECT_MAP:
526 if(x.via.map.size != y.via.map.size) {
527 return false;
528 } else if(x.via.map.size == 0) {
529 return true;
530 } else {
531 msgpack_object_kv* px = x.via.map.ptr;
532 msgpack_object_kv* const pxend = x.via.map.ptr + x.via.map.size;
533 msgpack_object_kv* py = y.via.map.ptr;
534 do {
535 if(!msgpack_object_equal(px->key, py->key) || !msgpack_object_equal(px->val, py->val)) {
536 return false;
537 }
538 ++px;
539 ++py;
540 } while(px < pxend);
541 return true;
542 }
543
544 default:
545 return false;
546 }
547 }
548