in encoding/tinycbor/src/cbortojson.c [490:645]
static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType type, ConversionStatus *status)
{
CborError err;
status->flags = 0;
switch (type) {
case CborArrayType:
case CborMapType: {
/* recursive type */
CborValue recursed;
err = cbor_value_enter_container(it, &recursed);
if (err) {
it->offset = recursed.offset;
return err; /* parse error */
}
if (fputc(type == CborArrayType ? '[' : '{', out) < 0)
return CborErrorIO;
err = (type == CborArrayType) ?
array_to_json(out, &recursed, flags, status) :
map_to_json(out, &recursed, flags, status);
if (err) {
it->offset = recursed.offset;
return err; /* parse error */
}
if (fputc(type == CborArrayType ? ']' : '}', out) < 0)
return CborErrorIO;
err = cbor_value_leave_container(it, &recursed);
if (err)
return err; /* parse error */
status->flags = 0; /* reset, there are never conversion errors for us */
return CborNoError;
}
case CborIntegerType: {
double num; /* JS numbers are IEEE double precision */
uint64_t val;
cbor_value_get_raw_integer(it, &val); /* can't fail */
num = (double)val;
if (cbor_value_is_negative_integer(it)) {
num = -num - 1; /* convert to negative */
if ((uint64_t)(-num - 1) != val) {
status->flags = NumberPrecisionWasLost | NumberWasNegative;
status->originalNumber = val;
}
} else {
if ((uint64_t)num != val) {
status->flags = NumberPrecisionWasLost;
status->originalNumber = val;
}
}
if (fprintf(out, "%.0f", num) < 0) /* this number has no fraction, so no decimal points please */
return CborErrorIO;
break;
}
case CborByteStringType:
case CborTextStringType: {
char *str;
if (type == CborByteStringType) {
err = dump_bytestring_base64url(&str, it);
status->flags = TypeWasNotNative;
} else {
size_t n = 0;
err = cbor_value_dup_text_string(it, &str, &n, it);
}
if (err)
return err;
err = (fprintf(out, "\"%s\"", str) < 0) ? CborErrorIO : CborNoError;
free(str);
return err;
}
case CborTagType:
return tagged_value_to_json(out, it, flags, status);
case CborSimpleType: {
uint8_t simple_type;
cbor_value_get_simple_type(it, &simple_type); /* can't fail */
status->flags = TypeWasNotNative;
status->originalNumber = simple_type;
if (fprintf(out, "\"simple(%" PRIu8 ")\"", simple_type) < 0)
return CborErrorIO;
break;
}
case CborNullType:
if (fprintf(out, "null") < 0)
return CborErrorIO;
break;
case CborUndefinedType:
status->flags = TypeWasNotNative;
if (fprintf(out, "\"undefined\"") < 0)
return CborErrorIO;
break;
case CborBooleanType: {
bool val;
cbor_value_get_boolean(it, &val); /* can't fail */
if (fprintf(out, val ? "true" : "false") < 0)
return CborErrorIO;
break;
}
#if FLOAT_SUPPORT
case CborDoubleType: {
double val;
if (false) {
float f;
case CborFloatType:
status->flags = TypeWasNotNative;
cbor_value_get_float(it, &f);
val = f;
} else if (false) {
uint16_t f16;
case CborHalfFloatType:
status->flags = TypeWasNotNative;
cbor_value_get_half_float(it, &f16);
val = decode_half(f16);
} else {
cbor_value_get_double(it, &val);
}
int r = fpclassify(val);
if (r == FP_NAN || r == FP_INFINITE) {
if (fprintf(out, "null") < 0)
return CborErrorIO;
status->flags |= r == FP_NAN ? NumberWasNaN :
NumberWasInfinite | (val < 0 ? NumberWasNegative : 0);
} else {
uint64_t ival = (uint64_t)fabs(val);
if ((double)ival == fabs(val)) {
/* print as integer so we get the full precision */
r = fprintf(out, "%s%" PRIu64, val < 0 ? "-" : "", ival);
status->flags |= TypeWasNotNative; /* mark this integer number as a double */
} else {
/* this number is definitely not a 64-bit integer */
r = fprintf(out, "%." DBL_DECIMAL_DIG_STR "g", val);
}
if (r < 0)
return CborErrorIO;
}
break;
}
#endif
case CborInvalidType:
default:
return CborErrorUnknownType;
}
return cbor_value_advance_fixed(it);
}