1 /* 2 * Contributed by Jacob Teplitsky <jacob.teplitsky@ericsson.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 /** 9 * This code demonstrates how cJSON (https://github.com/DaveGamble/cJSON) 10 * callbacks can be used in conjuction with the streaming parser to translate 11 * JSON to CBOR. Please note that cbor_builder_* APIs are internal and thus 12 * subject to change. 13 * 14 * The example will only be compiled when cJSON is available 15 */ 16 17 #include <cjson/cJSON.h> 18 #include <float.h> 19 #include <math.h> 20 #include <string.h> 21 #include "cbor.h" 22 #include "cbor/internal/builder_callbacks.h" 23 #include "cbor/internal/loaders.h" 24 25 typedef void (*cbor_load_callback_t)(cJSON *, const struct cbor_callbacks *, 26 void *); 27 28 cbor_item_t *cjson_cbor_load(void *source, 29 cbor_load_callback_t cbor_load_callback) { 30 static struct cbor_callbacks callbacks = { 31 .uint64 = &cbor_builder_uint64_callback, 32 .negint64 = &cbor_builder_negint64_callback, 33 .string = &cbor_builder_string_callback, 34 .array_start = &cbor_builder_array_start_callback, 35 .map_start = &cbor_builder_map_start_callback, 36 .null = &cbor_builder_null_callback, 37 .boolean = &cbor_builder_boolean_callback, 38 .float4 = &cbor_builder_float4_callback, 39 }; 40 41 /* Context stack */ 42 struct _cbor_stack stack = _cbor_stack_init(); 43 44 /* Target for callbacks */ 45 struct _cbor_decoder_context context = (struct _cbor_decoder_context){ 46 .stack = &stack, 47 }; 48 49 cbor_load_callback(source, &callbacks, &context); 50 51 return context.root; 52 } 53 54 void cjson_cbor_stream_decode(cJSON *source, 55 const struct cbor_callbacks *callbacks, 56 void *context) { 57 switch (source->type) { 58 case cJSON_False: { 59 callbacks->boolean(context, false); 60 return; 61 } 62 case cJSON_True: { 63 callbacks->boolean(context, true); 64 return; 65 } 66 case cJSON_NULL: { 67 callbacks->null(context); 68 return; 69 } 70 case cJSON_Number: { 71 // This is stupid -- ints and doubles cannot are not distinguished 72 if (fabs(source->valuedouble - source->valueint) > DBL_EPSILON) { 73 callbacks->float4(context, source->valuedouble); 74 } else { 75 // XXX: This is not portable 76 if (source->valueint >= 0) { 77 callbacks->uint64(context, source->valueint); 78 } else { 79 callbacks->negint64(context, source->valueint + 1); 80 } 81 } 82 return; 83 } 84 case cJSON_String: { 85 // XXX: Assume cJSON handled unicode correctly 86 callbacks->string(context, (unsigned char *)source->valuestring, 87 strlen(source->valuestring)); 88 return; 89 } 90 case cJSON_Array: { 91 callbacks->array_start(context, cJSON_GetArraySize(source)); 92 cJSON *item = source->child; 93 while (item != NULL) { 94 cjson_cbor_stream_decode(item, callbacks, context); 95 item = item->next; 96 } 97 return; 98 } 99 case cJSON_Object: { 100 callbacks->map_start(context, cJSON_GetArraySize(source)); 101 cJSON *item = source->child; 102 while (item != NULL) { 103 callbacks->string(context, (unsigned char *)item->string, 104 strlen(item->string)); 105 cjson_cbor_stream_decode(item, callbacks, context); 106 item = item->next; 107 } 108 return; 109 } 110 } 111 } 112 113 void usage() { 114 printf("Usage: cjson [input JSON file]\n"); 115 exit(1); 116 } 117 118 int main(int argc, char *argv[]) { 119 if (argc != 2) usage(); 120 FILE *f = fopen(argv[1], "rb"); 121 if (f == NULL) usage(); 122 /* Read input file into a buffer (cJSON doesn't work with streams) */ 123 fseek(f, 0, SEEK_END); 124 size_t length = (size_t)ftell(f); 125 fseek(f, 0, SEEK_SET); 126 char *json_buffer = malloc(length + 1); 127 fread(json_buffer, length, 1, f); 128 json_buffer[length] = '\0'; 129 130 /* Convert between JSON and CBOR */ 131 cJSON *json = cJSON_Parse(json_buffer); 132 cbor_item_t *cbor = cjson_cbor_load(json, cjson_cbor_stream_decode); 133 134 /* Print out CBOR bytes */ 135 unsigned char *buffer; 136 size_t buffer_size, 137 cbor_length = cbor_serialize_alloc(cbor, &buffer, &buffer_size); 138 139 fwrite(buffer, 1, cbor_length, stdout); 140 141 free(buffer); 142 fflush(stdout); 143 cJSON_Delete(json); 144 cbor_decref(&cbor); 145 } 146