static int
cbor_internal_read_object(CborValue *root_value,
                          const struct cbor_attr_t *attrs,
                          const struct cbor_array_t *parent,
                          int offset)
{
    const struct cbor_attr_t *cursor, *best_match;
    char attrbuf[MYNEWT_VAL(CBORATTR_MAX_SIZE) + 1];
    void *lptr;
    CborValue cur_value;
    CborError err = 0;
    size_t len;
    CborType type = CborInvalidType;

    /* stuff fields with defaults in case they're omitted in the JSON input */
    for (cursor = attrs; cursor->attribute != NULL; cursor++) {
        if (!cursor->nodefault) {
            lptr = cbor_target_address(cursor, parent, offset);
            if (lptr != NULL) {
                switch (cursor->type) {
                case CborAttrIntegerType:
                    memcpy(lptr, &cursor->dflt.integer, sizeof(long long int));
                    break;
                case CborAttrUnsignedIntegerType:
                    memcpy(lptr, &cursor->dflt.integer,
                           sizeof(long long unsigned int));
                    break;
                case CborAttrBooleanType:
                    memcpy(lptr, &cursor->dflt.boolean, sizeof(bool));
                    break;
#if FLOAT_SUPPORT
                case CborAttrFloatType:
                    memcpy(lptr, &cursor->dflt.fval, sizeof(float));
                    break;
                case CborAttrDoubleType:
                    memcpy(lptr, &cursor->dflt.real, sizeof(double));
                    break;
#endif
                default:
                    break;
                }
            }
        }
    }

    if (cbor_value_is_map(root_value)) {
        err |= cbor_value_enter_container(root_value, &cur_value);
    } else {
        err |= CborErrorIllegalType;
        return err;
    }

    /* contains key value pairs */
    while (cbor_value_is_valid(&cur_value) && !err) {
        /* get the attribute */
        if (cbor_value_is_text_string(&cur_value)) {
            if (cbor_value_calculate_string_length(&cur_value, &len) == 0) {
                if (len > MYNEWT_VAL(CBORATTR_MAX_SIZE)) {
                    err |= CborErrorDataTooLarge;
                    break;
                }
                err |= cbor_value_copy_text_string(&cur_value, attrbuf, &len,
                                                     NULL);
            }

            /* at least get the type of the next value so we can match the
             * attribute name and type for a perfect match */
            err |= cbor_value_advance(&cur_value);
            if (cbor_value_is_valid(&cur_value)) {
                type = cbor_value_get_type(&cur_value);
            } else {
                err |= CborErrorIllegalType;
                break;
            }
        } else {
            attrbuf[0] = '\0';
            type = cbor_value_get_type(&cur_value);
        }

        /* find this attribute in our list */
        best_match = NULL;
        for (cursor = attrs; cursor->attribute != NULL; cursor++) {
            if (valid_attr_type(type, cursor->type)) {
                if (cursor->attribute == CBORATTR_ATTR_UNNAMED &&
                    attrbuf[0] == '\0') {
                    best_match = cursor;
                } else if (strlen(cursor->attribute) == len &&
                    !memcmp(cursor->attribute, attrbuf, len)) {
                    break;
                }
            }
        }
        if (!cursor->attribute && best_match) {
            cursor = best_match;
        }
        /* we found a match */
        if (cursor->attribute != NULL) {
            lptr = cbor_target_address(cursor, parent, offset);
            switch (cursor->type) {
            case CborAttrNullType:
                /* nothing to do */
                break;
            case CborAttrBooleanType:
                err |= cbor_value_get_boolean(&cur_value, lptr);
                break;
            case CborAttrIntegerType:
                err |= cbor_value_get_int64(&cur_value, lptr);
                break;
            case CborAttrUnsignedIntegerType:
                err |= cbor_value_get_uint64(&cur_value, lptr);
                break;
#if FLOAT_SUPPORT
            case CborAttrFloatType:
                err |= cbor_value_get_float(&cur_value, lptr);
                break;
            case CborAttrDoubleType:
                err |= cbor_value_get_double(&cur_value, lptr);
                break;
#endif
            case CborAttrByteStringType: {
                size_t len = cursor->len;
                err |= cbor_value_copy_byte_string(&cur_value, lptr,
                                                   &len, NULL);
                *cursor->addr.bytestring.len = len;
                break;
            }
            case CborAttrTextStringType: {
                size_t len = cursor->len;
                err |= cbor_value_copy_text_string(&cur_value, lptr,
                                                   &len, NULL);
                break;
            }
            case CborAttrArrayType:
                err |= cbor_read_array(&cur_value, &cursor->addr.array);
                continue;
            case CborAttrObjectType:
                err |= cbor_internal_read_object(&cur_value, cursor->addr.obj,
                                                 NULL, 0);
                continue;
            default:
                err |= CborErrorIllegalType;
            }
        }
        cbor_value_advance(&cur_value);
    }
    if (!err) {
        /* that should be it for this container */
        err |= cbor_value_leave_container(root_value, &cur_value);
    }
    return err;
}
/* Parse single property */
static void
oc_parse_rep_value(CborValue *value, oc_rep_t **rep, CborError *err)
{
  size_t k, len;
  CborValue map, array;
  *rep = _alloc_rep();
  oc_rep_t *cur = *rep, **prev = 0;
  cur->next = 0;
  cur->value_object_array = 0;
  /* key */
  *err |= cbor_value_calculate_string_length(value, &len);
  len++;
  oc_alloc_string(&cur->name, len);
  *err |= cbor_value_copy_text_string(value, (char *)oc_string(cur->name), &len,
                                      NULL);
  *err |= cbor_value_advance(value);
  /* value */
  switch (value->type) {
  case CborIntegerType:
    *err |= cbor_value_get_int64(value, &cur->value_int);
    cur->type = INT;
    break;
  case CborBooleanType:
    *err |= cbor_value_get_boolean(value, &cur->value_boolean);
    cur->type = BOOL;
    break;
  case CborDoubleType:
    *err |= cbor_value_get_double(value, &cur->value_double);
    cur->type = DOUBLE;
    break;
  case CborByteStringType:
    *err |= cbor_value_calculate_string_length(value, &len);
    len++;
    oc_alloc_string(&cur->value_string, len);
    *err |= cbor_value_copy_byte_string(
      value, oc_cast(cur->value_string, uint8_t), &len, NULL);
    cur->type = BYTE_STRING;
    break;
  case CborTextStringType:
    *err |= cbor_value_calculate_string_length(value, &len);
    len++;
    oc_alloc_string(&cur->value_string, len);
    *err |= cbor_value_copy_text_string(value, oc_string(cur->value_string),
                                        &len, NULL);
    cur->type = STRING;
    break;
  case CborMapType: /* when value is a map/object */ {
    oc_rep_t **obj = &cur->value_object; // object points to list of properties
    *err |= cbor_value_enter_container(value, &map);
    while (!cbor_value_at_end(&map)) {
      oc_parse_rep_value(&map, obj, err);
      (*obj)->next = 0;
      obj = &(*obj)->next;
      *err |= cbor_value_advance(&map);
    }
    cur->type = OBJECT;
  } break;
  case CborArrayType:
    *err |= cbor_value_enter_container(value, &array);
    len = 0;
    cbor_value_get_array_length(value, &len);
    if (len == 0) {
      CborValue t = array;
      while (!cbor_value_at_end(&t)) {
        len++;
        cbor_value_advance(&t);
      }
    }
    k = 0;
    while (!cbor_value_at_end(&array)) {
      switch (array.type) {
      case CborIntegerType:
        if (k == 0) {
          oc_new_int_array(&cur->value_array, len);
          cur->type = INT | ARRAY;
        }
        *err |=
          cbor_value_get_int64(&array, oc_int_array(cur->value_array) + k);
        break;
      case CborDoubleType:
        if (k == 0) {
          oc_new_double_array(&cur->value_array, len);
          cur->type = DOUBLE | ARRAY;
        }
        *err |=
          cbor_value_get_double(&array, oc_double_array(cur->value_array) + k);
        break;
      case CborBooleanType:
        if (k == 0) {
          oc_new_bool_array(&cur->value_array, len);
          cur->type = BOOL | ARRAY;
        }
        *err |=
          cbor_value_get_boolean(&array, oc_bool_array(cur->value_array) + k);
        break;
      case CborByteStringType:
        if (k == 0) {
          oc_new_string_array(&cur->value_array, len);
          cur->type = BYTE_STRING | ARRAY;
        }
        *err |= cbor_value_calculate_string_length(&array, &len);
        len++;
        *err |= cbor_value_copy_byte_string(
          &array, (uint8_t *)oc_string_array_get_item(cur->value_array, k),
          &len, NULL);
        break;
      case CborTextStringType:
        if (k == 0) {
          oc_new_string_array(&cur->value_array, len);
          cur->type = STRING | ARRAY;
        }
        *err |= cbor_value_calculate_string_length(&array, &len);
        len++;
        *err |= cbor_value_copy_text_string(
          &array, (char *)oc_string_array_get_item(cur->value_array, k), &len,
          NULL);
        break;
      case CborMapType:
        if (k == 0) {
          cur->type = OBJECT | ARRAY;
          cur->value_object_array = _alloc_rep();
          prev = &cur->value_object_array;
        } else {
          (*prev)->next = _alloc_rep();
          prev = &(*prev)->next;
        }
        (*prev)->type = OBJECT;
        (*prev)->next = 0;
        oc_rep_t **obj = &(*prev)->value_object;
        /* Process a series of properties that make up an object of the array */
        *err |= cbor_value_enter_container(&array, &map);
        while (!cbor_value_at_end(&map)) {
          oc_parse_rep_value(&map, obj, err);
          obj = &(*obj)->next;
          *err |= cbor_value_advance(&map);
        }
        break;
      default:
        break;
      }
      k++;
      *err |= cbor_value_advance(&array);
    }
    break;
  default:
    break;
  }
}