110ff414cSEd Maste /* 210ff414cSEd Maste * Contributed by Jacob Teplitsky <jacob.teplitsky@ericsson.com> 310ff414cSEd Maste * 410ff414cSEd Maste * libcbor is free software; you can redistribute it and/or modify 510ff414cSEd Maste * it under the terms of the MIT license. See LICENSE for details. 610ff414cSEd Maste */ 710ff414cSEd Maste 810ff414cSEd Maste /** 910ff414cSEd Maste * This code demonstrates how cJSON (https://github.com/DaveGamble/cJSON) 10*abd87254SEd Maste * callbacks can be used in conjunction with the streaming parser to translate 1110ff414cSEd Maste * JSON to CBOR. Please note that cbor_builder_* APIs are internal and thus 1210ff414cSEd Maste * subject to change. 1310ff414cSEd Maste * 1410ff414cSEd Maste * The example will only be compiled when cJSON is available 1510ff414cSEd Maste */ 1610ff414cSEd Maste 1710ff414cSEd Maste #include <cjson/cJSON.h> 1810ff414cSEd Maste #include <float.h> 1910ff414cSEd Maste #include <math.h> 2010ff414cSEd Maste #include <string.h> 2110ff414cSEd Maste #include "cbor.h" 2210ff414cSEd Maste #include "cbor/internal/builder_callbacks.h" 2310ff414cSEd Maste #include "cbor/internal/loaders.h" 2410ff414cSEd Maste 2510ff414cSEd Maste typedef void (*cbor_load_callback_t)(cJSON *, const struct cbor_callbacks *, 2610ff414cSEd Maste void *); 2710ff414cSEd Maste 2810ff414cSEd Maste cbor_item_t *cjson_cbor_load(void *source, 2910ff414cSEd Maste cbor_load_callback_t cbor_load_callback) { 3010ff414cSEd Maste static struct cbor_callbacks callbacks = { 3110ff414cSEd Maste .uint64 = &cbor_builder_uint64_callback, 3210ff414cSEd Maste .negint64 = &cbor_builder_negint64_callback, 3310ff414cSEd Maste .string = &cbor_builder_string_callback, 3410ff414cSEd Maste .array_start = &cbor_builder_array_start_callback, 3510ff414cSEd Maste .map_start = &cbor_builder_map_start_callback, 3610ff414cSEd Maste .null = &cbor_builder_null_callback, 3710ff414cSEd Maste .boolean = &cbor_builder_boolean_callback, 3810ff414cSEd Maste .float4 = &cbor_builder_float4_callback, 3910ff414cSEd Maste }; 4010ff414cSEd Maste 4110ff414cSEd Maste /* Context stack */ 4210ff414cSEd Maste struct _cbor_stack stack = _cbor_stack_init(); 4310ff414cSEd Maste 4410ff414cSEd Maste /* Target for callbacks */ 4510ff414cSEd Maste struct _cbor_decoder_context context = (struct _cbor_decoder_context){ 4610ff414cSEd Maste .stack = &stack, 4710ff414cSEd Maste }; 4810ff414cSEd Maste 4910ff414cSEd Maste cbor_load_callback(source, &callbacks, &context); 5010ff414cSEd Maste 5110ff414cSEd Maste return context.root; 5210ff414cSEd Maste } 5310ff414cSEd Maste 5410ff414cSEd Maste void cjson_cbor_stream_decode(cJSON *source, 5510ff414cSEd Maste const struct cbor_callbacks *callbacks, 5610ff414cSEd Maste void *context) { 5710ff414cSEd Maste switch (source->type) { 5810ff414cSEd Maste case cJSON_False: { 5910ff414cSEd Maste callbacks->boolean(context, false); 6010ff414cSEd Maste return; 6110ff414cSEd Maste } 6210ff414cSEd Maste case cJSON_True: { 6310ff414cSEd Maste callbacks->boolean(context, true); 6410ff414cSEd Maste return; 6510ff414cSEd Maste } 6610ff414cSEd Maste case cJSON_NULL: { 6710ff414cSEd Maste callbacks->null(context); 6810ff414cSEd Maste return; 6910ff414cSEd Maste } 7010ff414cSEd Maste case cJSON_Number: { 7110ff414cSEd Maste // This is stupid -- ints and doubles cannot are not distinguished 7210ff414cSEd Maste if (fabs(source->valuedouble - source->valueint) > DBL_EPSILON) { 7310ff414cSEd Maste callbacks->float4(context, source->valuedouble); 7410ff414cSEd Maste } else { 7510ff414cSEd Maste // XXX: This is not portable 7610ff414cSEd Maste if (source->valueint >= 0) { 7710ff414cSEd Maste callbacks->uint64(context, source->valueint); 7810ff414cSEd Maste } else { 7910ff414cSEd Maste callbacks->negint64(context, source->valueint + 1); 8010ff414cSEd Maste } 8110ff414cSEd Maste } 8210ff414cSEd Maste return; 8310ff414cSEd Maste } 8410ff414cSEd Maste case cJSON_String: { 8510ff414cSEd Maste // XXX: Assume cJSON handled unicode correctly 8610ff414cSEd Maste callbacks->string(context, (unsigned char *)source->valuestring, 8710ff414cSEd Maste strlen(source->valuestring)); 8810ff414cSEd Maste return; 8910ff414cSEd Maste } 9010ff414cSEd Maste case cJSON_Array: { 9110ff414cSEd Maste callbacks->array_start(context, cJSON_GetArraySize(source)); 9210ff414cSEd Maste cJSON *item = source->child; 9310ff414cSEd Maste while (item != NULL) { 9410ff414cSEd Maste cjson_cbor_stream_decode(item, callbacks, context); 9510ff414cSEd Maste item = item->next; 9610ff414cSEd Maste } 9710ff414cSEd Maste return; 9810ff414cSEd Maste } 9910ff414cSEd Maste case cJSON_Object: { 10010ff414cSEd Maste callbacks->map_start(context, cJSON_GetArraySize(source)); 10110ff414cSEd Maste cJSON *item = source->child; 10210ff414cSEd Maste while (item != NULL) { 10310ff414cSEd Maste callbacks->string(context, (unsigned char *)item->string, 10410ff414cSEd Maste strlen(item->string)); 10510ff414cSEd Maste cjson_cbor_stream_decode(item, callbacks, context); 10610ff414cSEd Maste item = item->next; 10710ff414cSEd Maste } 10810ff414cSEd Maste return; 10910ff414cSEd Maste } 11010ff414cSEd Maste } 11110ff414cSEd Maste } 11210ff414cSEd Maste 1135d3e7166SEd Maste void usage(void) { 114*abd87254SEd Maste printf("Usage: cjson2cbor [input JSON file]\n"); 11510ff414cSEd Maste exit(1); 11610ff414cSEd Maste } 11710ff414cSEd Maste 11810ff414cSEd Maste int main(int argc, char *argv[]) { 11910ff414cSEd Maste if (argc != 2) usage(); 12010ff414cSEd Maste FILE *f = fopen(argv[1], "rb"); 12110ff414cSEd Maste if (f == NULL) usage(); 12210ff414cSEd Maste /* Read input file into a buffer (cJSON doesn't work with streams) */ 12310ff414cSEd Maste fseek(f, 0, SEEK_END); 12410ff414cSEd Maste size_t length = (size_t)ftell(f); 12510ff414cSEd Maste fseek(f, 0, SEEK_SET); 12610ff414cSEd Maste char *json_buffer = malloc(length + 1); 12710ff414cSEd Maste fread(json_buffer, length, 1, f); 12810ff414cSEd Maste json_buffer[length] = '\0'; 12910ff414cSEd Maste 13010ff414cSEd Maste /* Convert between JSON and CBOR */ 13110ff414cSEd Maste cJSON *json = cJSON_Parse(json_buffer); 13210ff414cSEd Maste cbor_item_t *cbor = cjson_cbor_load(json, cjson_cbor_stream_decode); 13310ff414cSEd Maste 13410ff414cSEd Maste /* Print out CBOR bytes */ 13510ff414cSEd Maste unsigned char *buffer; 1365d3e7166SEd Maste size_t buffer_size; 1375d3e7166SEd Maste cbor_serialize_alloc(cbor, &buffer, &buffer_size); 13810ff414cSEd Maste 1395d3e7166SEd Maste fwrite(buffer, 1, buffer_size, stdout); 14010ff414cSEd Maste 14110ff414cSEd Maste free(buffer); 14210ff414cSEd Maste fflush(stdout); 14310ff414cSEd Maste cJSON_Delete(json); 14410ff414cSEd Maste cbor_decref(&cbor); 14510ff414cSEd Maste } 146