text: #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;
  }
  