replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / extlibs / tinycbor / tinycbor / tools / json2cbor / json2cbor.c
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 Intel Corporation
4 **
5 ** Permission is hereby granted, free of charge, to any person obtaining a copy
6 ** of this software and associated documentation files (the "Software"), to deal
7 ** in the Software without restriction, including without limitation the rights
8 ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 ** copies of the Software, and to permit persons to whom the Software is
10 ** furnished to do so, subject to the following conditions:
11 **
12 ** The above copyright notice and this permission notice shall be included in
13 ** all copies or substantial portions of the Software.
14 **
15 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 ** THE SOFTWARE.
22 **
23 ****************************************************************************/
24
25 #define _POSIX_C_SOURCE 200809L
26 #define _GNU_SOURCE
27 #include "cbor.h"
28 #include "compilersupport_p.h"
29
30 #if defined (__TIZENRT__)
31 #include <apps/netutils/cJSON.h>
32 #else
33 #include <cJSON.h>
34 #endif
35
36 #include <errno.h>
37 #include <math.h>
38 #include <inttypes.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43
44 static const char meta_data_marker[] = "$cbor";
45 uint8_t *buffer;
46 size_t buffersize;
47 bool usingMetaData = false;
48
49 struct MetaData {
50     CborTag tag;
51     union {
52         const char *v;
53         uint8_t simpleType;
54     };
55     CborType t;
56     bool tagged;
57 };
58
59 uint8_t *decode_base64_generic(const char *string, size_t *len, const int8_t reverse_alphabet[256])
60 {
61     *len = ((strlen(string) + 3) & ~3) * 3 / 4;
62     uint8_t *buffer = malloc(*len);
63     if (buffer == NULL)
64         return NULL;
65
66     uint8_t *out = buffer;
67     const uint8_t *in = (const uint8_t *)string;
68     bool done = false;
69     while (!done) {
70         if (reverse_alphabet[in[0]] < 0 || reverse_alphabet[in[1]] < 0) {
71             if (in[0] == '\0')
72                 done = true;
73             break;
74         }
75
76         uint32_t val = reverse_alphabet[in[0]] << 18;
77         val |= reverse_alphabet[in[1]] << 12;
78         if (in[2] == '=' || in[2] == '\0') {
79             if (in[2] == '=' && (in[3] != '=' || in[4] != '\0'))
80                 break;
81             val >>= 12;
82             done = true;
83         } else if (in[3] == '=' || in[3] == '\0') {
84             if (in[3] == '=' && in[4] != '\0')
85                 break;
86             val >>= 6;
87             val |= reverse_alphabet[in[2]];
88             done = true;
89         } else {
90             val |= reverse_alphabet[in[2]] << 6;
91             val |= reverse_alphabet[in[3]];
92         }
93
94         *out++ = val >> 16;
95         *out++ = val >> 8;
96         *out++ = val;
97         in += 4;
98     }
99
100     if (!done) {
101         free(buffer);
102         return NULL;
103     }
104     *len = out - buffer;
105     return buffer;
106 }
107
108 uint8_t *decode_base64(const char *string, size_t *len)
109 {
110     static const int8_t reverse_alphabet[256] = {
111         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
112         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
113         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
114         52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
115         -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
116         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
117         -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
118         41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
119         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
120         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
121         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
122         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
123         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
124         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
125         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
126         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
127     };
128     return decode_base64_generic(string, len, reverse_alphabet);
129 }
130
131 uint8_t *decode_base64url(const char *string, size_t *len)
132 {
133     static const int8_t reverse_alphabet[256] = {
134         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
135         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
136         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
137         52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
138         -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
139         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
140         -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
141         41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
142         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
143         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
144         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
145         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
146         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
147         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
148         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
149         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
150     };
151     return decode_base64_generic(string, len, reverse_alphabet);
152 }
153
154 uint8_t *decode_base16(const char *string, size_t *len)
155 {
156     *len = strlen(string) / 2;
157     uint8_t *buffer = malloc(*len);
158     if (buffer == NULL)
159         return NULL;
160
161     for (size_t i = 0; i < *len; ++i) {
162         char c = string[i * 2];
163         if (c >= '0' && c <= '9') {
164             buffer[i] = (c - '0') << 4;
165         } else if ((c | 0x20) >= 'a' && (c | 0x20) <= 'f') {
166             buffer[i] = ((c | 0x20) - 'a' + 10) << 4;
167         } else {
168             free(buffer);
169             return NULL;
170         }
171
172         c = string[i * 2 + 1];
173         if (c >= '0' && c <= '9') {
174             buffer[i] |= (c - '0');
175         } else if ((c | 0x20) >= 'a' && (c | 0x20) <= 'f') {
176             buffer[i] |= ((c | 0x20) - 'a' + 10);
177         } else {
178             free(buffer);
179             return NULL;
180         }
181     }
182
183     return buffer;
184 }
185
186 size_t get_cjson_size_limited(cJSON *container)
187 {
188     // cJSON_GetArraySize is O(n), so don't go too far
189     unsigned s = 0;
190     cJSON *item;
191     for (item = container->child; item; item = item->next) {
192         if (++s > 255)
193             return CborIndefiniteLength;
194     }
195     return s;
196 }
197
198 cJSON *get_meta_data(cJSON *object, cJSON *item)
199 {
200     cJSON *meta;
201     char *metadatakey;
202
203     if (asprintf(&metadatakey, "%s%s", item->string, meta_data_marker) < 0 || metadatakey == NULL)
204         return NULL;
205     meta = cJSON_GetObjectItem(object, metadatakey);
206     free(metadatakey);
207     return meta;
208 }
209
210 struct MetaData parse_meta_data(cJSON *md)
211 {
212     struct MetaData result = { 0, {NULL}, CborInvalidType, false };
213     if (md == NULL || md->type != cJSON_Object)
214         return result;
215
216     for (md = md->child; md; md = md->next) {
217         if (strcmp(md->string, "tag") == 0) {
218             if (md->type != cJSON_String || sscanf(md->valuestring, "%" PRIu64, &result.tag) < 0)
219                 fprintf(stderr, "json2cbor: could not parse tag: %s\n", md->valuestring);
220             else
221                 result.tagged = true;
222         } else if (strcmp(md->string, "t") == 0) {
223             result.t = md->valueint;
224         } else if (strcmp(md->string, "v") == 0) {
225             if (md->type == cJSON_Number)
226                 result.simpleType = md->valueint;
227             else
228                 result.v = md->valuestring;
229         }
230     }
231     return result;
232 }
233
234 CborError decode_json(cJSON *json, CborEncoder *encoder);
235 CborError decode_json_with_metadata(cJSON *item, CborEncoder *encoder, struct MetaData md)
236 {
237     switch (md.t) {
238     case CborIntegerType: {
239         // integer that has more than 53 bits of precision
240         uint64_t v;
241         bool positive = *md.v++ == '+';
242         if (sscanf(md.v, "%" PRIx64, &v) < 0) {
243             fprintf(stderr, "json2cbor: could not parse number: %s\n", md.v);
244             break;
245         }
246         return positive ? cbor_encode_uint(encoder, v) : cbor_encode_negative_int(encoder, v);
247     }
248
249     case CborByteStringType: {
250         uint8_t *data;
251         size_t len;
252         if (md.tag == CborExpectedBase64Tag)
253             data = decode_base64(item->valuestring, &len);
254         else if (md.tag == CborExpectedBase16Tag)
255             data = decode_base16(item->valuestring, &len);
256         else if (md.tag == CborNegativeBignumTag)
257             data = decode_base64url(item->valuestring + 1, &len);
258         else
259             data = decode_base64url(item->valuestring, &len);
260
261         if (data != NULL) {
262             CborError err = cbor_encode_byte_string(encoder, data, len);
263             free(data);
264             return err;
265         }
266         fprintf(stderr, "json2cbor: could not decode encoded byte string: %s\n", item->valuestring);
267         break;
268     }
269
270     case CborSimpleType:
271         return cbor_encode_simple_value(encoder, md.simpleType);
272
273     case CborUndefinedType:
274         return cbor_encode_undefined(encoder);
275
276     case CborHalfFloatType:
277     case CborFloatType:
278     case CborDoubleType: {
279         unsigned short half;
280         double v;
281         if (!md.v) {
282             v = item->valuedouble;
283         } else if (strcmp(md.v, "nan") == 0) {
284             v = NAN;
285         } else if (strcmp(md.v, "-inf") == 0) {
286             v = -INFINITY;
287         } else if (strcmp(md.v, "inf") == 0) {
288             v = INFINITY;
289         } else {
290             fprintf(stderr, "json2cbor: invalid floating-point value: %s\n", md.v);
291             break;
292         }
293
294         // we can't get an OOM here because the metadata makes up for space
295         // (the smallest metadata is "$cbor":{"t":250} (17 bytes)
296         return (md.t == CborDoubleType) ? cbor_encode_double(encoder, v) :
297                (md.t == CborFloatType) ? cbor_encode_float(encoder, v) :
298                                          (half = encode_half(v), cbor_encode_half_float(encoder, &half));
299     }
300
301     default:
302         fprintf(stderr, "json2cbor: invalid CBOR type: %d\n", md.t);
303     case CborInvalidType:
304         break;
305     }
306
307     return decode_json(item, encoder);
308 }
309
310 CborError decode_json(cJSON *json, CborEncoder *encoder)
311 {
312     CborEncoder container;
313     CborError err;
314     cJSON *item;
315
316     switch (json->type) {
317     case cJSON_False:
318     case cJSON_True:
319         return cbor_encode_boolean(encoder, json->type == cJSON_True);
320
321     case cJSON_NULL:
322         return cbor_encode_null(encoder);
323
324     case cJSON_Number:
325         if ((double)json->valueint == json->valuedouble)
326             return cbor_encode_int(encoder, json->valueint);
327 encode_double:
328         // the only exception that JSON is larger: floating point numbers
329         container = *encoder;   // save the state
330         err = cbor_encode_double(encoder, json->valuedouble);
331
332         if (err == CborErrorOutOfMemory) {
333             buffersize += 1024;
334             uint8_t *newbuffer = realloc(buffer, buffersize);
335             if (newbuffer == NULL)
336                 return err;
337
338             *encoder = container;   // restore state
339             encoder->ptr = newbuffer + (container.ptr - buffer);
340             encoder->end = newbuffer + buffersize;
341             buffer = newbuffer;
342             goto encode_double;
343         }
344         return err;
345
346     case cJSON_String:
347         return cbor_encode_text_stringz(encoder, json->valuestring);
348
349     default:
350         return CborErrorUnknownType;
351
352     case cJSON_Array:
353         err = cbor_encoder_create_array(encoder, &container, get_cjson_size_limited(json));
354         if (err)
355             return err;
356         for (item = json->child; item; item = item->next) {
357             err = decode_json(item, &container);
358             if (err)
359                 return err;
360         }
361         return cbor_encoder_close_container_checked(encoder, &container);
362
363     case cJSON_Object:
364         err = cbor_encoder_create_map(encoder, &container,
365                                       usingMetaData ? CborIndefiniteLength : get_cjson_size_limited(json));
366         if (err)
367             return err;
368
369         for (item = json->child ; item; item = item->next) {
370             if (usingMetaData && strlen(item->string) > strlen(meta_data_marker)
371                     && strcmp(item->string + strlen(item->string) - 5, meta_data_marker) == 0)
372                 continue;
373
374             err = cbor_encode_text_stringz(&container, item->string);
375             if (err)
376                 return err;
377
378             if (usingMetaData) {
379                 cJSON *meta = get_meta_data(json, item);
380                 struct MetaData md = parse_meta_data(meta);
381                 if (md.tagged) {
382                     err = cbor_encode_tag(&container, md.tag);
383                     if (err)
384                         return err;
385                 }
386
387                 err = decode_json_with_metadata(item, &container, md);
388             } else {
389                 err = decode_json(item, &container);
390             }
391             if (err)
392                 return err;
393         }
394
395         return cbor_encoder_close_container_checked(encoder, &container);
396     }
397 }
398
399 int main(int argc, char **argv)
400 {
401     int c;
402     while ((c = getopt(argc, argv, "M")) != -1) {
403         switch (c) {
404         case 'M':
405             usingMetaData = true;
406             break;
407
408         case '?':
409             fprintf(stderr, "Unknown option -%c.\n", optopt);
410             // fall through
411         case 'h':
412             puts("Usage: json2cbor [OPTION]... [FILE]...\n"
413                  "Reads JSON content from FILE and convert to CBOR.\n"
414                  "\n"
415                  "Options:\n"
416                  " -M       Interpret metadata added by cbordump tool\n"
417                  "");
418             return c == '?' ? EXIT_FAILURE : EXIT_SUCCESS;
419         }
420     }
421
422     FILE *in;
423     const char *fname = argv[optind];
424     if (fname && strcmp(fname, "-") != 0) {
425         in = fopen(fname, "r");
426         if (!in) {
427             perror("open");
428             return EXIT_FAILURE;
429         }
430     } else {
431         in = stdin;
432         fname = "-";
433     }
434
435     /* 1. read the file */
436     off_t fsize;
437     if (fseeko(in, 0, SEEK_END) == 0 && (fsize = ftello(in)) >= 0) {
438         buffersize = fsize + 1;
439         buffer = malloc(buffersize);
440         if (buffer == NULL) {
441             perror("malloc");
442             return EXIT_FAILURE;
443         }
444
445         rewind(in);
446         fsize = fread(buffer, 1, fsize, in);
447         buffer[fsize] = '\0';
448     } else {
449         const unsigned chunk = 16384;
450         buffersize = 0;
451         buffer = NULL;
452         do {    // it the hard way
453             buffer = realloc(buffer, buffersize + chunk);
454             if (buffer == NULL)
455                 perror("malloc");
456
457             buffersize += fread(buffer + buffersize, 1, chunk, in);
458         } while (!feof(in) && !ferror(in));
459         buffer[buffersize] = '\0';
460     }
461
462     if (ferror(in)) {
463         perror("read");
464         return EXIT_FAILURE;
465     }
466     if (in != stdin)
467         fclose(in);
468
469     /* 2. parse as JSON */
470     cJSON *doc = cJSON_ParseWithOpts((char *)buffer, NULL, true);
471     if (doc == NULL) {
472         fprintf(stderr, "json2cbor: %s: could not parse.\n", fname);
473         return EXIT_FAILURE;
474     }
475
476     /* 3. encode as CBOR */
477     // We're going to reuse the buffer, as CBOR is usually shorter than the equivalent JSON
478     CborEncoder encoder;
479     cbor_encoder_init(&encoder, buffer, buffersize, 0);
480     CborError err = decode_json(doc, &encoder);
481
482     cJSON_Delete(doc);
483
484     if (err) {
485         fprintf(stderr, "json2cbor: %s: error encoding to CBOR: %s\n", fname,
486                 cbor_error_string(err));
487         return EXIT_FAILURE;
488     }
489
490     fwrite(buffer, 1, encoder.ptr - buffer, stdout);
491     free(buffer);
492     return EXIT_SUCCESS;
493 }