1 /*
2 * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3 *
4 * libcbor is free software; you can redistribute it and/or modify
5 * it under the terms of the MIT license. See LICENSE for details.
6 */
7
8 #include <cjson/cJSON.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #include "cbor.h"
13
usage(void)14 void usage(void) {
15 printf("Usage: cbor2cjson [input file]\n");
16 exit(1);
17 }
18
cbor_to_cjson(cbor_item_t * item)19 cJSON* cbor_to_cjson(cbor_item_t* item) {
20 switch (cbor_typeof(item)) {
21 case CBOR_TYPE_UINT:
22 return cJSON_CreateNumber(cbor_get_int(item));
23 case CBOR_TYPE_NEGINT:
24 return cJSON_CreateNumber(-1 - cbor_get_int(item));
25 case CBOR_TYPE_BYTESTRING:
26 // cJSON only handles null-terminated string -- binary data would have to
27 // be escaped
28 return cJSON_CreateString("Unsupported CBOR item: Bytestring");
29 case CBOR_TYPE_STRING:
30 if (cbor_string_is_definite(item)) {
31 // cJSON only handles null-terminated string
32 char* null_terminated_string = malloc(cbor_string_length(item) + 1);
33 memcpy(null_terminated_string, cbor_string_handle(item),
34 cbor_string_length(item));
35 null_terminated_string[cbor_string_length(item)] = 0;
36 cJSON* result = cJSON_CreateString(null_terminated_string);
37 free(null_terminated_string);
38 return result;
39 }
40 return cJSON_CreateString("Unsupported CBOR item: Chunked string");
41 case CBOR_TYPE_ARRAY: {
42 cJSON* result = cJSON_CreateArray();
43 for (size_t i = 0; i < cbor_array_size(item); i++) {
44 cJSON_AddItemToArray(result, cbor_to_cjson(cbor_array_get(item, i)));
45 }
46 return result;
47 }
48 case CBOR_TYPE_MAP: {
49 cJSON* result = cJSON_CreateObject();
50 for (size_t i = 0; i < cbor_map_size(item); i++) {
51 char* key = malloc(128);
52 snprintf(key, 128, "Surrogate key %zu", i);
53 // JSON only support string keys
54 if (cbor_isa_string(cbor_map_handle(item)[i].key) &&
55 cbor_string_is_definite(cbor_map_handle(item)[i].key)) {
56 size_t key_length = cbor_string_length(cbor_map_handle(item)[i].key);
57 if (key_length > 127) key_length = 127;
58 // Null-terminated madness
59 memcpy(key, cbor_string_handle(cbor_map_handle(item)[i].key),
60 key_length);
61 key[key_length] = 0;
62 }
63
64 cJSON_AddItemToObject(result, key,
65 cbor_to_cjson(cbor_map_handle(item)[i].value));
66 free(key);
67 }
68 return result;
69 }
70 case CBOR_TYPE_TAG:
71 return cJSON_CreateString("Unsupported CBOR item: Tag");
72 case CBOR_TYPE_FLOAT_CTRL:
73 if (cbor_float_ctrl_is_ctrl(item)) {
74 if (cbor_is_bool(item)) return cJSON_CreateBool(cbor_get_bool(item));
75 if (cbor_is_null(item)) return cJSON_CreateNull();
76 return cJSON_CreateString("Unsupported CBOR item: Control value");
77 }
78 return cJSON_CreateNumber(cbor_float_get_float(item));
79 }
80
81 return cJSON_CreateNull();
82 }
83
84 /*
85 * Reads CBOR data from a file and outputs JSON using cJSON
86 * $ ./examples/cbor2cjson examples/data/nested_array.cbor
87 */
88
main(int argc,char * argv[])89 int main(int argc, char* argv[]) {
90 if (argc != 2) usage();
91 FILE* f = fopen(argv[1], "rb");
92 if (f == NULL) usage();
93 fseek(f, 0, SEEK_END);
94 size_t length = (size_t)ftell(f);
95 fseek(f, 0, SEEK_SET);
96 unsigned char* buffer = malloc(length);
97 fread(buffer, length, 1, f);
98
99 /* Assuming `buffer` contains `length` bytes of input data */
100 struct cbor_load_result result;
101 cbor_item_t* item = cbor_load(buffer, length, &result);
102 free(buffer);
103
104 if (result.error.code != CBOR_ERR_NONE) {
105 printf(
106 "There was an error while reading the input near byte %zu (read %zu "
107 "bytes in total): ",
108 result.error.position, result.read);
109 exit(1);
110 }
111
112 cJSON* cjson_item = cbor_to_cjson(item);
113 char* json_string = cJSON_Print(cjson_item);
114 printf("%s\n", json_string);
115 free(json_string);
116 fflush(stdout);
117
118 /* Deallocate the result */
119 cbor_decref(&item);
120 cJSON_Delete(cjson_item);
121
122 fclose(f);
123 }
124