Path: blob/main/contrib/libcbor/examples/cjson2cbor.c
39586 views
/*1* Contributed by Jacob Teplitsky <[email protected]>2*3* libcbor is free software; you can redistribute it and/or modify4* it under the terms of the MIT license. See LICENSE for details.5*/67/**8* This code demonstrates how cJSON (https://github.com/DaveGamble/cJSON)9* callbacks can be used in conjunction with the streaming parser to translate10* JSON to CBOR. Please note that cbor_builder_* APIs are internal and thus11* subject to change.12*13* The example will only be compiled when cJSON is available14*/1516#include <cjson/cJSON.h>17#include <float.h>18#include <math.h>19#include <string.h>20#include "cbor.h"21#include "cbor/internal/builder_callbacks.h"22#include "cbor/internal/loaders.h"2324typedef void (*cbor_load_callback_t)(cJSON *, const struct cbor_callbacks *,25void *);2627cbor_item_t *cjson_cbor_load(void *source,28cbor_load_callback_t cbor_load_callback) {29static struct cbor_callbacks callbacks = {30.uint64 = &cbor_builder_uint64_callback,31.negint64 = &cbor_builder_negint64_callback,32.string = &cbor_builder_string_callback,33.array_start = &cbor_builder_array_start_callback,34.map_start = &cbor_builder_map_start_callback,35.null = &cbor_builder_null_callback,36.boolean = &cbor_builder_boolean_callback,37.float4 = &cbor_builder_float4_callback,38};3940/* Context stack */41struct _cbor_stack stack = _cbor_stack_init();4243/* Target for callbacks */44struct _cbor_decoder_context context = (struct _cbor_decoder_context){45.stack = &stack,46};4748cbor_load_callback(source, &callbacks, &context);4950return context.root;51}5253void cjson_cbor_stream_decode(cJSON *source,54const struct cbor_callbacks *callbacks,55void *context) {56switch (source->type) {57case cJSON_False: {58callbacks->boolean(context, false);59return;60}61case cJSON_True: {62callbacks->boolean(context, true);63return;64}65case cJSON_NULL: {66callbacks->null(context);67return;68}69case cJSON_Number: {70// This is stupid -- ints and doubles cannot are not distinguished71if (fabs(source->valuedouble - source->valueint) > DBL_EPSILON) {72callbacks->float4(context, source->valuedouble);73} else {74// XXX: This is not portable75if (source->valueint >= 0) {76callbacks->uint64(context, source->valueint);77} else {78callbacks->negint64(context, source->valueint + 1);79}80}81return;82}83case cJSON_String: {84// XXX: Assume cJSON handled unicode correctly85callbacks->string(context, (unsigned char *)source->valuestring,86strlen(source->valuestring));87return;88}89case cJSON_Array: {90callbacks->array_start(context, cJSON_GetArraySize(source));91cJSON *item = source->child;92while (item != NULL) {93cjson_cbor_stream_decode(item, callbacks, context);94item = item->next;95}96return;97}98case cJSON_Object: {99callbacks->map_start(context, cJSON_GetArraySize(source));100cJSON *item = source->child;101while (item != NULL) {102callbacks->string(context, (unsigned char *)item->string,103strlen(item->string));104cjson_cbor_stream_decode(item, callbacks, context);105item = item->next;106}107return;108}109}110}111112void usage(void) {113printf("Usage: cjson2cbor [input JSON file]\n");114exit(1);115}116117int main(int argc, char *argv[]) {118if (argc != 2) usage();119FILE *f = fopen(argv[1], "rb");120if (f == NULL) usage();121/* Read input file into a buffer (cJSON doesn't work with streams) */122fseek(f, 0, SEEK_END);123size_t length = (size_t)ftell(f);124fseek(f, 0, SEEK_SET);125char *json_buffer = malloc(length + 1);126fread(json_buffer, length, 1, f);127json_buffer[length] = '\0';128129/* Convert between JSON and CBOR */130cJSON *json = cJSON_Parse(json_buffer);131cbor_item_t *cbor = cjson_cbor_load(json, cjson_cbor_stream_decode);132133/* Print out CBOR bytes */134unsigned char *buffer;135size_t buffer_size;136cbor_serialize_alloc(cbor, &buffer, &buffer_size);137138fwrite(buffer, 1, buffer_size, stdout);139140free(buffer);141fflush(stdout);142cJSON_Delete(json);143cbor_decref(&cbor);144}145146147