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,
45 cbor_to_cjson(cbor_move(cbor_array_get(item, i))));
46 }
47 return result;
48 }
49 case CBOR_TYPE_MAP: {
50 cJSON* result = cJSON_CreateObject();
51 for (size_t i = 0; i < cbor_map_size(item); i++) {
52 char* key = malloc(128);
53 snprintf(key, 128, "Surrogate key %zu", i);
54 // JSON only support string keys
55 if (cbor_isa_string(cbor_map_handle(item)[i].key) &&
56 cbor_string_is_definite(cbor_map_handle(item)[i].key)) {
57 size_t key_length = cbor_string_length(cbor_map_handle(item)[i].key);
58 if (key_length > 127) key_length = 127;
59 // Null-terminated madness
60 memcpy(key, cbor_string_handle(cbor_map_handle(item)[i].key),
61 key_length);
62 key[key_length] = 0;
63 }
64
65 cJSON_AddItemToObject(result, key,
66 cbor_to_cjson(cbor_map_handle(item)[i].value));
67 free(key);
68 }
69 return result;
70 }
71 case CBOR_TYPE_TAG:
72 return cJSON_CreateString("Unsupported CBOR item: Tag");
73 case CBOR_TYPE_FLOAT_CTRL:
74 if (cbor_float_ctrl_is_ctrl(item)) {
75 if (cbor_is_bool(item)) return cJSON_CreateBool(cbor_get_bool(item));
76 if (cbor_is_null(item)) return cJSON_CreateNull();
77 return cJSON_CreateString("Unsupported CBOR item: Control value");
78 }
79 return cJSON_CreateNumber(cbor_float_get_float(item));
80 }
81
82 return cJSON_CreateNull();
83 }
84
85 /*
86 * Reads CBOR data from a file and outputs JSON using cJSON
87 * $ ./examples/cbor2cjson examples/data/nested_array.cbor
88 */
89
main(int argc,char * argv[])90 int main(int argc, char* argv[]) {
91 if (argc != 2) usage();
92 FILE* f = fopen(argv[1], "rb");
93 if (f == NULL) usage();
94 fseek(f, 0, SEEK_END);
95 size_t length = (size_t)ftell(f);
96 fseek(f, 0, SEEK_SET);
97 unsigned char* buffer = malloc(length);
98 fread(buffer, length, 1, f);
99
100 /* Assuming `buffer` contains `length` bytes of input data */
101 struct cbor_load_result result;
102 cbor_item_t* item = cbor_load(buffer, length, &result);
103 free(buffer);
104
105 if (result.error.code != CBOR_ERR_NONE) {
106 printf(
107 "There was an error while reading the input near byte %zu (read %zu "
108 "bytes in total): ",
109 result.error.position, result.read);
110 exit(1);
111 }
112
113 cJSON* cjson_item = cbor_to_cjson(item);
114 char* json_string = cJSON_Print(cjson_item);
115 printf("%s\n", json_string);
116 free(json_string);
117 fflush(stdout);
118
119 /* Deallocate the result */
120 cbor_decref(&item);
121 cJSON_Delete(cjson_item);
122
123 fclose(f);
124 }
125