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