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"); } }