internal static void WriteJSONToInternal(
CBORObject obj,
StringOutput writer)
{
int type = obj.ItemType;
object thisItem = obj.ThisItem;
switch (type) {
case CBORObject.CBORObjectTypeSimpleValue: {
if (obj.IsTrue) {
writer.WriteString("true");
return;
}
if (obj.IsFalse) {
writer.WriteString("false");
return;
}
writer.WriteString("null");
return;
}
case CBORObject.CBORObjectTypeSingle: {
var f = (float)thisItem;
if (Single.IsNegativeInfinity(f) ||
Single.IsPositiveInfinity(f) || Single.IsNaN(f)) {
writer.WriteString("null");
return;
}
writer.WriteString(
CBORObject.TrimDotZero(
CBORUtilities.SingleToString(f)));
return;
}
case CBORObject.CBORObjectTypeDouble: {
var f = (double)thisItem;
if (Double.IsNegativeInfinity(f) || Double.IsPositiveInfinity(f) ||
Double.IsNaN(f)) {
writer.WriteString("null");
return;
}
string dblString = CBORUtilities.DoubleToString(f);
writer.WriteString(
CBORObject.TrimDotZero(dblString));
return;
}
case CBORObject.CBORObjectTypeInteger: {
var longItem = (long)thisItem;
writer.WriteString(CBORUtilities.LongToString(longItem));
return;
}
case CBORObject.CBORObjectTypeBigInteger: {
writer.WriteString(
CBORUtilities.BigIntToString((EInteger)thisItem));
return;
}
case CBORObject.CBORObjectTypeExtendedDecimal: {
var dec = (EDecimal)thisItem;
if (dec.IsInfinity() || dec.IsNaN()) {
writer.WriteString("null");
} else {
writer.WriteString(dec.ToString());
}
return;
}
case CBORObject.CBORObjectTypeExtendedFloat: {
var flo = (EFloat)thisItem;
if (flo.IsInfinity() || flo.IsNaN()) {
writer.WriteString("null");
return;
}
if (flo.IsFinite &&
flo.Exponent.Abs().CompareTo((EInteger)2500) > 0) {
// Too inefficient to convert to a decimal number
// from a bigfloat with a very high exponent,
// so convert to double instead
double f = flo.ToDouble();
if (Double.IsNegativeInfinity(f) ||
Double.IsPositiveInfinity(f) || Double.IsNaN(f)) {
writer.WriteString("null");
return;
}
string dblString =
CBORUtilities.DoubleToString(f);
writer.WriteString(
CBORObject.TrimDotZero(dblString));
return;
}
writer.WriteString(flo.ToString());
return;
}
case CBORObject.CBORObjectTypeByteString:
{
var byteArray = (byte[])thisItem;
if (byteArray.Length == 0) {
writer.WriteString("\"\"");
return;
}
writer.WriteCodePoint((int)'\"');
if (obj.HasTag(22)) {
Base64.WriteBase64(
writer,
byteArray,
0,
byteArray.Length,
false);
} else if (obj.HasTag(23)) {
// Write as base16
for (int i = 0; i < byteArray.Length; ++i) {
writer.WriteCodePoint((int)Hex16[(byteArray[i] >> 4) & 15]);
writer.WriteCodePoint((int)Hex16[byteArray[i] & 15]);
}
} else {
Base64.WriteBase64URL(
writer,
byteArray,
0,
byteArray.Length,
false);
}
writer.WriteCodePoint((int)'\"');
break;
}
case CBORObject.CBORObjectTypeTextString: {
var thisString = (string)thisItem;
if (thisString.Length == 0) {
writer.WriteString("\"\"");
return;
}
writer.WriteCodePoint((int)'\"');
WriteJSONStringUnquoted(thisString, writer);
writer.WriteCodePoint((int)'\"');
break;
}
case CBORObject.CBORObjectTypeArray: {
var first = true;
writer.WriteCodePoint((int)'[');
foreach (CBORObject i in obj.AsList()) {
if (!first) {
writer.WriteCodePoint((int)',');
}
WriteJSONToInternal(i, writer);
first = false;
}
writer.WriteCodePoint((int)']');
break;
}
case CBORObject.CBORObjectTypeExtendedRational: {
var dec = (ERational)thisItem;
EDecimal f = dec.ToEDecimalExactIfPossible(
EContext.Decimal128.WithUnlimitedExponents());
if (!f.IsFinite) {
writer.WriteString("null");
} else {
writer.WriteString(f.ToString());
}
break;
}
case CBORObject.CBORObjectTypeMap: {
var first = true;
var hasNonStringKeys = false;
IDictionary<CBORObject, CBORObject> objMap = obj.AsMap();
foreach (KeyValuePair<CBORObject, CBORObject> entry in objMap) {
CBORObject key = entry.Key;
if (key.ItemType != CBORObject.CBORObjectTypeTextString) {
hasNonStringKeys = true;
break;
}
}
if (!hasNonStringKeys) {
writer.WriteCodePoint((int)'{');
foreach (KeyValuePair<CBORObject, CBORObject> entry in objMap) {
CBORObject key = entry.Key;
CBORObject value = entry.Value;
if (!first) {
writer.WriteCodePoint((int)',');
}
writer.WriteCodePoint((int)'\"');
WriteJSONStringUnquoted((string)key.ThisItem, writer);
writer.WriteCodePoint((int)'\"');
writer.WriteCodePoint((int)':');
WriteJSONToInternal(value, writer);
first = false;
}
writer.WriteCodePoint((int)'}');
} else {
// This map has non-string keys
IDictionary<string, CBORObject> stringMap = new
Dictionary<string, CBORObject>();
// Copy to a map with String keys, since
// some keys could be duplicates
// when serialized to strings
foreach (KeyValuePair<CBORObject, CBORObject> entry in objMap) {
CBORObject key = entry.Key;
CBORObject value = entry.Value;
string str = (key.ItemType == CBORObject.CBORObjectTypeTextString) ?
((string)key.ThisItem) : key.ToJSONString();
stringMap[str] = value;
}
first = true;
writer.WriteCodePoint((int)'{');
foreach (KeyValuePair<string, CBORObject> entry in stringMap) {
string key = entry.Key;
CBORObject value = entry.Value;
if (!first) {
writer.WriteCodePoint((int)',');
}
writer.WriteCodePoint((int)'\"');
WriteJSONStringUnquoted((string)key, writer);
writer.WriteCodePoint((int)'\"');
writer.WriteCodePoint((int)':');
WriteJSONToInternal(value, writer);
first = false;
}
writer.WriteCodePoint((int)'}');
}
break;
}
default:
throw new InvalidOperationException("Unexpected item type");
}
}