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)
1010ff414cSEd Maste  * callbacks can be used in conjuction 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 
cjson_cbor_load(void * source,cbor_load_callback_t cbor_load_callback)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 
cjson_cbor_stream_decode(cJSON * source,const struct cbor_callbacks * callbacks,void * context)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 
usage(void)113*5d3e7166SEd Maste void usage(void) {
11410ff414cSEd Maste   printf("Usage: cjson [input JSON file]\n");
11510ff414cSEd Maste   exit(1);
11610ff414cSEd Maste }
11710ff414cSEd Maste 
main(int argc,char * argv[])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;
136*5d3e7166SEd Maste   size_t buffer_size;
137*5d3e7166SEd Maste   cbor_serialize_alloc(cbor, &buffer, &buffer_size);
13810ff414cSEd Maste 
139*5d3e7166SEd 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