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