| #include "../src/cbor.h" |
| |
| #include <sys/stat.h> |
| #include <assert.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| |
| static uint8_t *readfile(const char *fname, size_t *size) |
| { |
| struct stat st; |
| FILE *f = fopen(fname, "rb"); |
| if (!f) |
| return NULL; |
| if (fstat(fileno(f), &st) == -1) |
| return NULL; |
| uint8_t *buf = malloc(st.st_size); |
| if (buf == NULL) |
| return NULL; |
| *size = fread(buf, st.st_size, 1, f) == 1 ? st.st_size : 0; |
| fclose(f); |
| return buf; |
| } |
| |
| static void indent(int nestingLevel) |
| { |
| while (nestingLevel--) |
| printf(" "); |
| } |
| |
| static void dumpbytes(const uint8_t *buf, size_t len) |
| { |
| printf("\""); |
| while (len--) |
| printf("\\x%02X", *buf++); |
| printf("\""); |
| } |
| |
| static CborError dumprecursive(CborValue *it, int nestingLevel) |
| { |
| while (!cbor_value_at_end(it)) { |
| CborError err; |
| CborType type = cbor_value_get_type(it); |
| |
| indent(nestingLevel); |
| switch (type) { |
| case CborArrayType: |
| case CborMapType: { |
| // recursive type |
| CborValue recursed; |
| assert(cbor_value_is_container(it)); |
| puts(type == CborArrayType ? "Array[" : "Map["); |
| err = cbor_value_enter_container(it, &recursed); |
| if (err) |
| return err; // parse error |
| err = dumprecursive(&recursed, nestingLevel + 1); |
| if (err) |
| return err; // parse error |
| err = cbor_value_leave_container(it, &recursed); |
| if (err) |
| return err; // parse error |
| indent(nestingLevel); |
| puts("]"); |
| continue; |
| } |
| |
| case CborIntegerType: { |
| int64_t val; |
| cbor_value_get_int64(it, &val); // can't fail |
| printf("%lld\n", (long long)val); |
| break; |
| } |
| |
| case CborByteStringType: { |
| uint8_t *buf; |
| size_t n; |
| err = cbor_value_dup_byte_string(it, &buf, &n, it); |
| if (err) |
| return err; // parse error |
| dumpbytes(buf, n); |
| puts(""); |
| free(buf); |
| continue; |
| } |
| |
| case CborTextStringType: { |
| char *buf; |
| size_t n; |
| err = cbor_value_dup_text_string(it, &buf, &n, it); |
| if (err) |
| return err; // parse error |
| printf("\"%s\"\n", buf); |
| free(buf); |
| continue; |
| } |
| |
| case CborTagType: { |
| CborTag tag; |
| cbor_value_get_tag(it, &tag); // can't fail |
| printf("Tag(%lld)\n", (long long)tag); |
| break; |
| } |
| |
| case CborSimpleType: { |
| uint8_t type; |
| cbor_value_get_simple_type(it, &type); // can't fail |
| printf("simple(%u)\n", type); |
| break; |
| } |
| |
| case CborNullType: |
| puts("null"); |
| break; |
| |
| case CborUndefinedType: |
| puts("undefined"); |
| break; |
| |
| case CborBooleanType: { |
| bool val; |
| cbor_value_get_boolean(it, &val); // can't fail |
| puts(val ? "true" : "false"); |
| break; |
| } |
| |
| case CborDoubleType: { |
| double val; |
| if (false) { |
| float f; |
| case CborFloatType: |
| cbor_value_get_float(it, &f); |
| val = f; |
| } else { |
| cbor_value_get_double(it, &val); |
| } |
| printf("%g\n", val); |
| break; |
| } |
| case CborHalfFloatType: { |
| uint16_t val; |
| cbor_value_get_half_float(it, &val); |
| printf("__f16(%04x)\n", val); |
| break; |
| } |
| |
| case CborInvalidType: |
| assert(false); // can't happen |
| break; |
| } |
| |
| err = cbor_value_advance_fixed(it); |
| if (err) |
| return err; |
| } |
| return CborNoError; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| if (argc != 2) { |
| puts("simplereader <filename>"); |
| return 1; |
| } |
| |
| size_t length; |
| uint8_t *buf = readfile(argv[1], &length); |
| if (!buf) { |
| perror("readfile"); |
| return 1; |
| } |
| |
| CborParser parser; |
| CborValue it; |
| CborError err = cbor_parser_init(buf, length, 0, &parser, &it); |
| if (!err) |
| err = dumprecursive(&it, 0); |
| free(buf); |
| |
| if (err) { |
| fprintf(stderr, "CBOR parsing failure at offset %ld: %s\n", |
| it.ptr - buf, cbor_error_string(err)); |
| return 1; |
| } |
| return 0; |
| } |