summaryrefslogtreecommitdiff
path: root/lib/cbor/tinycbor/tools
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-01-21 14:04:56 +1100
committerjacqueline <me@jacqueline.id.au>2023-01-21 14:09:00 +1100
commit393b268e159a40b23bc63464f4d04d5be09e070f (patch)
treed78167662cd68de3e08d90bb1b44070ab542e433 /lib/cbor/tinycbor/tools
parentbb50cf52cd8984704b757b1e5f9e11a126b24eba (diff)
downloadtangara-fw-393b268e159a40b23bc63464f4d04d5be09e070f.tar.gz
Vendor tinycbor, since v5 no longer includes it
Diffstat (limited to 'lib/cbor/tinycbor/tools')
-rw-r--r--lib/cbor/tinycbor/tools/cbordump/cbordump.c164
-rw-r--r--lib/cbor/tinycbor/tools/cbordump/cbordump.pro10
-rw-r--r--lib/cbor/tinycbor/tools/json2cbor/json2cbor.c493
-rw-r--r--lib/cbor/tinycbor/tools/json2cbor/json2cbor.pro20
4 files changed, 687 insertions, 0 deletions
diff --git a/lib/cbor/tinycbor/tools/cbordump/cbordump.c b/lib/cbor/tinycbor/tools/cbordump/cbordump.c
new file mode 100644
index 00000000..26268132
--- /dev/null
+++ b/lib/cbor/tinycbor/tools/cbordump/cbordump.c
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#define _POSIX_C_SOURCE 200809L
+#include "cbor.h"
+#include "cborjson.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void *xrealloc(void *old, size_t size, const char *fname)
+{
+ old = realloc(old, size);
+ if (old == NULL) {
+ fprintf(stderr, "%s: %s\n", fname, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ return old;
+}
+
+void printerror(CborError err, const char *fname)
+{
+ fprintf(stderr, "%s: %s\n", fname, cbor_error_string(err));
+ exit(EXIT_FAILURE);
+}
+
+void dumpFile(FILE *in, const char *fname, bool printJosn, int flags)
+{
+ static const size_t chunklen = 16 * 1024;
+ static size_t bufsize = 0;
+ static uint8_t *buffer = NULL;
+
+ size_t buflen = 0;
+ do {
+ if (bufsize == buflen)
+ buffer = xrealloc(buffer, bufsize += chunklen, fname);
+
+ size_t n = fread(buffer + buflen, 1, bufsize - buflen, in);
+ buflen += n;
+ if (n == 0) {
+ if (!ferror(in))
+ continue;
+ fprintf(stderr, "%s: %s\n", fname, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ } while (!feof(in));
+
+ CborParser parser;
+ CborValue value;
+ CborError err = cbor_parser_init(buffer, buflen, 0, &parser, &value);
+ if (!err) {
+ if (printJosn)
+ err = cbor_value_to_json_advance(stdout, &value, flags);
+ else
+ err = cbor_value_to_pretty_advance_flags(stdout, &value, flags);
+ if (!err)
+ puts("");
+ }
+ if (!err && cbor_value_get_next_byte(&value) != buffer + buflen)
+ err = CborErrorGarbageAtEnd;
+ if (err)
+ printerror(err, fname);
+}
+
+int main(int argc, char **argv)
+{
+ bool printJson = false;
+ int json_flags = CborConvertDefaultFlags;
+ int cbor_flags = CborPrettyDefaultFlags;
+ int c;
+ while ((c = getopt(argc, argv, "MOSUcjhfn")) != -1) {
+ switch (c) {
+ case 'c':
+ printJson = false;
+ break;
+ case 'j':
+ printJson = true;
+ break;
+
+ case 'f':
+ cbor_flags |= CborPrettyShowStringFragments;
+ break;
+ case 'n':
+ cbor_flags |= CborPrettyIndicateIndeterminateLength | CborPrettyNumericEncodingIndicators;
+ break;
+
+ case 'M':
+ json_flags |= CborConvertAddMetadata;
+ break;
+ case 'O':
+ json_flags |= CborConvertTagsToObjects;
+ break;
+ case 'S':
+ json_flags |= CborConvertStringifyMapKeys;
+ break;
+ case 'U':
+ json_flags |= CborConvertByteStringsToBase64Url;
+ break;
+
+ case '?':
+ fprintf(stderr, "Unknown option -%c.\n", optopt);
+ /* fall through */
+ case 'h':
+ puts("Usage: cbordump [OPTION]... [FILE]...\n"
+ "Interprets FILEs as CBOR binary data and dumps the content to stdout.\n"
+ "\n"
+ "Options:\n"
+ " -c Print a CBOR dump (see RFC 7049) (default)\n"
+ " -j Print a JSON equivalent version\n"
+ " -h Print this help output and exit\n"
+ "When JSON output is active, the following options are recognized:\n"
+ " -M Add metadata so converting back to CBOR is possible\n"
+ " -O Convert CBOR tags to JSON objects\n"
+ " -S Stringify non-text string map keys\n"
+ " -U Convert all CBOR byte strings to Base64url regardless of tags\n"
+ "When CBOR dump is active, the following options are recognized:\n"
+ " -f Show text and byte string fragments\n"
+ " -n Show overlong encoding of CBOR numbers and length"
+ "");
+ return c == '?' ? EXIT_FAILURE : EXIT_SUCCESS;
+ }
+ }
+
+ char **fname = argv + optind;
+ if (!*fname) {
+ dumpFile(stdin, "-", printJson, printJson ? json_flags : cbor_flags);
+ } else {
+ for ( ; *fname; ++fname) {
+ FILE *in = fopen(*fname, "rb");
+ if (!in) {
+ perror("open");
+ return EXIT_FAILURE;
+ }
+
+ dumpFile(in, *fname, printJson, printJson ? json_flags : cbor_flags);
+ fclose(in);
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/lib/cbor/tinycbor/tools/cbordump/cbordump.pro b/lib/cbor/tinycbor/tools/cbordump/cbordump.pro
new file mode 100644
index 00000000..71ae6f76
--- /dev/null
+++ b/lib/cbor/tinycbor/tools/cbordump/cbordump.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+CONFIG += console
+CONFIG -= app_bundle
+CONFIG -= qt
+DESTDIR = ../../bin
+
+CBORDIR = $$PWD/../../src
+INCLUDEPATH += $$CBORDIR
+SOURCES += cbordump.c
+LIBS += ../../lib/libtinycbor.a
diff --git a/lib/cbor/tinycbor/tools/json2cbor/json2cbor.c b/lib/cbor/tinycbor/tools/json2cbor/json2cbor.c
new file mode 100644
index 00000000..c13a7510
--- /dev/null
+++ b/lib/cbor/tinycbor/tools/json2cbor/json2cbor.c
@@ -0,0 +1,493 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#define _POSIX_C_SOURCE 200809L
+#define _GNU_SOURCE
+#include "cbor.h"
+#include "cborinternal_p.h"
+#include "compilersupport_p.h"
+
+#include <cjson/cJSON.h>
+
+#include <errno.h>
+#include <math.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static const char meta_data_marker[] = "$cbor";
+uint8_t *buffer;
+size_t buffersize;
+bool usingMetaData = false;
+
+struct MetaData {
+ CborTag tag;
+ union {
+ const char *v;
+ uint8_t simpleType;
+ };
+ CborType t;
+ bool tagged;
+};
+
+uint8_t *decode_base64_generic(const char *string, size_t *len, const int8_t reverse_alphabet[256])
+{
+ *len = ((strlen(string) + 3) & ~3) * 3 / 4;
+ uint8_t *buffer = malloc(*len);
+ if (buffer == NULL)
+ return NULL;
+
+ uint8_t *out = buffer;
+ const uint8_t *in = (const uint8_t *)string;
+ bool done = false;
+ while (!done) {
+ if (reverse_alphabet[in[0]] < 0 || reverse_alphabet[in[1]] < 0) {
+ if (in[0] == '\0')
+ done = true;
+ break;
+ }
+
+ uint32_t val = reverse_alphabet[in[0]] << 18;
+ val |= reverse_alphabet[in[1]] << 12;
+ if (in[2] == '=' || in[2] == '\0') {
+ if (in[2] == '=' && (in[3] != '=' || in[4] != '\0'))
+ break;
+ val >>= 12;
+ done = true;
+ } else if (in[3] == '=' || in[3] == '\0') {
+ if (in[3] == '=' && in[4] != '\0')
+ break;
+ val >>= 6;
+ val |= reverse_alphabet[in[2]];
+ done = true;
+ } else {
+ val |= reverse_alphabet[in[2]] << 6;
+ val |= reverse_alphabet[in[3]];
+ }
+
+ *out++ = val >> 16;
+ *out++ = val >> 8;
+ *out++ = val;
+ in += 4;
+ }
+
+ if (!done) {
+ free(buffer);
+ return NULL;
+ }
+ *len = out - buffer;
+ return buffer;
+}
+
+uint8_t *decode_base64(const char *string, size_t *len)
+{
+ static const int8_t reverse_alphabet[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+ return decode_base64_generic(string, len, reverse_alphabet);
+}
+
+uint8_t *decode_base64url(const char *string, size_t *len)
+{
+ static const int8_t reverse_alphabet[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+ return decode_base64_generic(string, len, reverse_alphabet);
+}
+
+uint8_t *decode_base16(const char *string, size_t *len)
+{
+ size_t i;
+ *len = strlen(string) / 2;
+ uint8_t *buffer = malloc(*len);
+ if (buffer == NULL)
+ return NULL;
+
+ for (i = 0; i < *len; ++i) {
+ char c = string[i * 2];
+ if (c >= '0' && c <= '9') {
+ buffer[i] = (c - '0') << 4;
+ } else if ((c | 0x20) >= 'a' && (c | 0x20) <= 'f') {
+ buffer[i] = ((c | 0x20) - 'a' + 10) << 4;
+ } else {
+ free(buffer);
+ return NULL;
+ }
+
+ c = string[i * 2 + 1];
+ if (c >= '0' && c <= '9') {
+ buffer[i] |= (c - '0');
+ } else if ((c | 0x20) >= 'a' && (c | 0x20) <= 'f') {
+ buffer[i] |= ((c | 0x20) - 'a' + 10);
+ } else {
+ free(buffer);
+ return NULL;
+ }
+ }
+
+ return buffer;
+}
+
+size_t get_cjson_size_limited(cJSON *container)
+{
+ // cJSON_GetArraySize is O(n), so don't go too far
+ unsigned s = 0;
+ cJSON *item;
+ for (item = container->child; item; item = item->next) {
+ if (++s > 255)
+ return CborIndefiniteLength;
+ }
+ return s;
+}
+
+cJSON *get_meta_data(cJSON *object, cJSON *item)
+{
+ cJSON *meta;
+ char *metadatakey;
+
+ if (asprintf(&metadatakey, "%s%s", item->string, meta_data_marker) < 0 || metadatakey == NULL)
+ return NULL;
+ meta = cJSON_GetObjectItem(object, metadatakey);
+ free(metadatakey);
+ return meta;
+}
+
+struct MetaData parse_meta_data(cJSON *md)
+{
+ struct MetaData result = { 0, {NULL}, CborInvalidType, false };
+ if (md == NULL || md->type != cJSON_Object)
+ return result;
+
+ for (md = md->child; md; md = md->next) {
+ if (strcmp(md->string, "tag") == 0) {
+ if (md->type != cJSON_String || sscanf(md->valuestring, "%" PRIu64, &result.tag) < 0)
+ fprintf(stderr, "json2cbor: could not parse tag: %s\n", md->valuestring);
+ else
+ result.tagged = true;
+ } else if (strcmp(md->string, "t") == 0) {
+ result.t = md->valueint;
+ } else if (strcmp(md->string, "v") == 0) {
+ if (md->type == cJSON_Number)
+ result.simpleType = md->valueint;
+ else
+ result.v = md->valuestring;
+ }
+ }
+ return result;
+}
+
+CborError decode_json(cJSON *json, CborEncoder *encoder);
+CborError decode_json_with_metadata(cJSON *item, CborEncoder *encoder, struct MetaData md)
+{
+ switch (md.t) {
+ case CborIntegerType: {
+ // integer that has more than 53 bits of precision
+ uint64_t v;
+ bool positive = *md.v++ == '+';
+ if (sscanf(md.v, "%" PRIx64, &v) < 0) {
+ fprintf(stderr, "json2cbor: could not parse number: %s\n", md.v);
+ break;
+ }
+ return positive ? cbor_encode_uint(encoder, v) : cbor_encode_negative_int(encoder, v);
+ }
+
+ case CborByteStringType: {
+ uint8_t *data;
+ size_t len;
+ if (md.tag == CborExpectedBase64Tag)
+ data = decode_base64(item->valuestring, &len);
+ else if (md.tag == CborExpectedBase16Tag)
+ data = decode_base16(item->valuestring, &len);
+ else if (md.tag == CborNegativeBignumTag)
+ data = decode_base64url(item->valuestring + 1, &len);
+ else
+ data = decode_base64url(item->valuestring, &len);
+
+ if (data != NULL) {
+ CborError err = cbor_encode_byte_string(encoder, data, len);
+ free(data);
+ return err;
+ }
+ fprintf(stderr, "json2cbor: could not decode encoded byte string: %s\n", item->valuestring);
+ break;
+ }
+
+ case CborSimpleType:
+ return cbor_encode_simple_value(encoder, md.simpleType);
+
+ case CborUndefinedType:
+ return cbor_encode_undefined(encoder);
+
+ case CborHalfFloatType:
+ case CborFloatType:
+ case CborDoubleType: {
+ unsigned short half;
+ double v;
+ if (!md.v) {
+ v = item->valuedouble;
+ } else if (strcmp(md.v, "nan") == 0) {
+ v = NAN;
+ } else if (strcmp(md.v, "-inf") == 0) {
+ v = -INFINITY;
+ } else if (strcmp(md.v, "inf") == 0) {
+ v = INFINITY;
+ } else {
+ fprintf(stderr, "json2cbor: invalid floating-point value: %s\n", md.v);
+ break;
+ }
+
+ // we can't get an OOM here because the metadata makes up for space
+ // (the smallest metadata is "$cbor":{"t":250} (17 bytes)
+ return (md.t == CborDoubleType) ? cbor_encode_double(encoder, v) :
+ (md.t == CborFloatType) ? cbor_encode_float(encoder, v) :
+ (half = encode_half(v), cbor_encode_half_float(encoder, &half));
+ }
+
+ default:
+ fprintf(stderr, "json2cbor: invalid CBOR type: %d\n", md.t);
+ case CborInvalidType:
+ break;
+ }
+
+ return decode_json(item, encoder);
+}
+
+CborError decode_json(cJSON *json, CborEncoder *encoder)
+{
+ CborEncoder container;
+ CborError err;
+ cJSON *item;
+
+ switch (json->type) {
+ case cJSON_False:
+ case cJSON_True:
+ return cbor_encode_boolean(encoder, json->type == cJSON_True);
+
+ case cJSON_NULL:
+ return cbor_encode_null(encoder);
+
+ case cJSON_Number:
+ if ((double)json->valueint == json->valuedouble)
+ return cbor_encode_int(encoder, json->valueint);
+encode_double:
+ // the only exception that JSON is larger: floating point numbers
+ container = *encoder; // save the state
+ err = cbor_encode_double(encoder, json->valuedouble);
+
+ if (err == CborErrorOutOfMemory) {
+ buffersize += 1024;
+ uint8_t *newbuffer = realloc(buffer, buffersize);
+ if (newbuffer == NULL)
+ return err;
+
+ *encoder = container; // restore state
+ encoder->data.ptr = newbuffer + (container.data.ptr - buffer);
+ encoder->end = newbuffer + buffersize;
+ buffer = newbuffer;
+ goto encode_double;
+ }
+ return err;
+
+ case cJSON_String:
+ return cbor_encode_text_stringz(encoder, json->valuestring);
+
+ default:
+ return CborErrorUnknownType;
+
+ case cJSON_Array:
+ err = cbor_encoder_create_array(encoder, &container, get_cjson_size_limited(json));
+ if (err)
+ return err;
+ for (item = json->child; item; item = item->next) {
+ err = decode_json(item, &container);
+ if (err)
+ return err;
+ }
+ return cbor_encoder_close_container_checked(encoder, &container);
+
+ case cJSON_Object:
+ err = cbor_encoder_create_map(encoder, &container,
+ usingMetaData ? CborIndefiniteLength : get_cjson_size_limited(json));
+ if (err)
+ return err;
+
+ for (item = json->child ; item; item = item->next) {
+ if (usingMetaData && strlen(item->string) > strlen(meta_data_marker)
+ && strcmp(item->string + strlen(item->string) - strlen(meta_data_marker), meta_data_marker) == 0)
+ continue;
+
+ err = cbor_encode_text_stringz(&container, item->string);
+ if (err)
+ return err;
+
+ if (usingMetaData) {
+ cJSON *meta = get_meta_data(json, item);
+ struct MetaData md = parse_meta_data(meta);
+ if (md.tagged) {
+ err = cbor_encode_tag(&container, md.tag);
+ if (err)
+ return err;
+ }
+
+ err = decode_json_with_metadata(item, &container, md);
+ } else {
+ err = decode_json(item, &container);
+ }
+ if (err)
+ return err;
+ }
+
+ return cbor_encoder_close_container_checked(encoder, &container);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ while ((c = getopt(argc, argv, "M")) != -1) {
+ switch (c) {
+ case 'M':
+ usingMetaData = true;
+ break;
+
+ case '?':
+ fprintf(stderr, "Unknown option -%c.\n", optopt);
+ // fall through
+ case 'h':
+ puts("Usage: json2cbor [OPTION]... [FILE]...\n"
+ "Reads JSON content from FILE and converts to CBOR.\n"
+ "\n"
+ "Options:\n"
+ " -M Interpret metadata added by cbordump tool\n"
+ "");
+ return c == '?' ? EXIT_FAILURE : EXIT_SUCCESS;
+ }
+ }
+
+ FILE *in;
+ const char *fname = argv[optind];
+ if (fname && strcmp(fname, "-") != 0) {
+ in = fopen(fname, "r");
+ if (!in) {
+ perror("open");
+ return EXIT_FAILURE;
+ }
+ } else {
+ in = stdin;
+ fname = "-";
+ }
+
+ /* 1. read the file */
+ off_t fsize;
+ if (fseeko(in, 0, SEEK_END) == 0 && (fsize = ftello(in)) >= 0) {
+ buffersize = fsize + 1;
+ buffer = malloc(buffersize);
+ if (buffer == NULL) {
+ perror("malloc");
+ return EXIT_FAILURE;
+ }
+
+ rewind(in);
+ fsize = fread(buffer, 1, fsize, in);
+ buffer[fsize] = '\0';
+ } else {
+ const unsigned chunk = 16384;
+ buffersize = 0;
+ buffer = NULL;
+ do { // it the hard way
+ buffer = realloc(buffer, buffersize + chunk);
+ if (buffer == NULL) {
+ perror("malloc");
+ return EXIT_FAILURE;
+ }
+
+ buffersize += fread(buffer + buffersize, 1, chunk, in);
+ } while (!feof(in) && !ferror(in));
+ buffer[buffersize] = '\0';
+ }
+
+ if (ferror(in)) {
+ perror("read");
+ return EXIT_FAILURE;
+ }
+ if (in != stdin)
+ fclose(in);
+
+ /* 2. parse as JSON */
+ cJSON *doc = cJSON_ParseWithOpts((char *)buffer, NULL, true);
+ if (doc == NULL) {
+ fprintf(stderr, "json2cbor: %s: could not parse.\n", fname);
+ return EXIT_FAILURE;
+ }
+
+ /* 3. encode as CBOR */
+ // We're going to reuse the buffer, as CBOR is usually shorter than the equivalent JSON
+ CborEncoder encoder;
+ cbor_encoder_init(&encoder, buffer, buffersize, 0);
+ CborError err = decode_json(doc, &encoder);
+
+ cJSON_Delete(doc);
+
+ if (err) {
+ fprintf(stderr, "json2cbor: %s: error encoding to CBOR: %s\n", fname,
+ cbor_error_string(err));
+ return EXIT_FAILURE;
+ }
+
+ fwrite(buffer, 1, encoder.data.ptr - buffer, stdout);
+ free(buffer);
+ return EXIT_SUCCESS;
+}
diff --git a/lib/cbor/tinycbor/tools/json2cbor/json2cbor.pro b/lib/cbor/tinycbor/tools/json2cbor/json2cbor.pro
new file mode 100644
index 00000000..fd6bcd09
--- /dev/null
+++ b/lib/cbor/tinycbor/tools/json2cbor/json2cbor.pro
@@ -0,0 +1,20 @@
+TEMPLATE = app
+CONFIG += console
+CONFIG -= app_bundle
+CONFIG -= qt
+DESTDIR = ../../bin
+
+CBORDIR = $$PWD/../../src
+INCLUDEPATH += $$CBORDIR
+SOURCES += json2cbor.c
+LIBS += ../../lib/libtinycbor.a
+
+CJSONDIR = .
+!exists($$CJSONDIR/cJSON.h): CJSONDIR = $$CBORDIR/cjson
+exists($$CJSONDIR/cJSON.h) {
+ INCLUDEPATH += $$CJSONDIR
+ SOURCES += $$CJSONDIR/cJSON.c
+} else {
+ message("cJSON not found, not building json2cbor.")
+ TEMPLATE = aux
+}