| File: System\Runtime\Serialization\Json\JsonWriterDelegator.cs | Web Access |
| Project: src\runtime\src\libraries\System.Private.DataContractSerialization\src\System.Private.DataContractSerialization.csproj (System.Private.DataContractSerialization) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; using System.Xml; namespace System.Runtime.Serialization.Json { internal sealed class JsonWriterDelegator : XmlWriterDelegator { private readonly DateTimeFormat? _dateTimeFormat; public JsonWriterDelegator(XmlWriter writer) : base(writer) { } public JsonWriterDelegator(XmlWriter writer, DateTimeFormat? dateTimeFormat) : this(writer) { _dateTimeFormat = dateTimeFormat; } internal override void WriteChar(char value) { WriteString(XmlConvert.ToString(value)); } internal override void WriteBase64(byte[]? bytes) { if (bytes == null) { return; } ByteArrayHelperWithString.WriteArray(Writer, bytes, 0, bytes.Length); } internal override void WriteQName(XmlQualifiedName value) { if (value != XmlQualifiedName.Empty) { writer.WriteString(value.Name); writer.WriteString(JsonGlobals.NameValueSeparatorString); writer.WriteString(value.Namespace); } } internal override void WriteUnsignedLong(ulong value) { WriteDecimal((decimal)value); } internal override void WriteDecimal(decimal value) { writer.WriteAttributeString(JsonGlobals.typeString, JsonGlobals.numberString); base.WriteDecimal(value); } internal override void WriteDouble(double value) { writer.WriteAttributeString(JsonGlobals.typeString, JsonGlobals.numberString); base.WriteDouble(value); } internal override void WriteFloat(float value) { writer.WriteAttributeString(JsonGlobals.typeString, JsonGlobals.numberString); base.WriteFloat(value); } internal override void WriteLong(long value) { writer.WriteAttributeString(JsonGlobals.typeString, JsonGlobals.numberString); base.WriteLong(value); } internal override void WriteSignedByte(sbyte value) { writer.WriteAttributeString(JsonGlobals.typeString, JsonGlobals.numberString); base.WriteSignedByte(value); } internal override void WriteUnsignedInt(uint value) { writer.WriteAttributeString(JsonGlobals.typeString, JsonGlobals.numberString); base.WriteUnsignedInt(value); } internal override void WriteUnsignedShort(ushort value) { writer.WriteAttributeString(JsonGlobals.typeString, JsonGlobals.numberString); base.WriteUnsignedShort(value); } internal override void WriteUnsignedByte(byte value) { writer.WriteAttributeString(JsonGlobals.typeString, JsonGlobals.numberString); base.WriteUnsignedByte(value); } internal override void WriteShort(short value) { writer.WriteAttributeString(JsonGlobals.typeString, JsonGlobals.numberString); base.WriteShort(value); } internal override void WriteBoolean(bool value) { writer.WriteAttributeString(JsonGlobals.typeString, JsonGlobals.booleanString); base.WriteBoolean(value); } internal override void WriteInt(int value) { writer.WriteAttributeString(JsonGlobals.typeString, JsonGlobals.numberString); base.WriteInt(value); } internal void WriteJsonBooleanArray(bool[] value, XmlDictionaryString itemName, XmlDictionaryString? itemNamespace) { for (int i = 0; i < value.Length; i++) { WriteBoolean(value[i], itemName, itemNamespace); } } internal void WriteJsonDateTimeArray(DateTime[] value, XmlDictionaryString itemName, XmlDictionaryString? itemNamespace) { for (int i = 0; i < value.Length; i++) { WriteDateTime(value[i], itemName, itemNamespace); } } internal void WriteJsonDecimalArray(decimal[] value, XmlDictionaryString itemName, XmlDictionaryString? itemNamespace) { for (int i = 0; i < value.Length; i++) { WriteDecimal(value[i], itemName, itemNamespace); } } internal void WriteJsonInt32Array(int[] value, XmlDictionaryString itemName, XmlDictionaryString? itemNamespace) { for (int i = 0; i < value.Length; i++) { WriteInt(value[i], itemName, itemNamespace); } } internal void WriteJsonInt64Array(long[] value, XmlDictionaryString itemName, XmlDictionaryString? itemNamespace) { for (int i = 0; i < value.Length; i++) { WriteLong(value[i], itemName, itemNamespace); } } internal override void WriteDateTime(DateTime value) { if (_dateTimeFormat == null) { WriteDateTimeInDefaultFormat(value); } else { writer.WriteString(value.ToString(_dateTimeFormat.FormatString, _dateTimeFormat.FormatProvider)); } } private void WriteDateTimeInDefaultFormat(DateTime value) { // ToUniversalTime() truncates dates to DateTime.MaxValue or DateTime.MinValue instead of throwing // This will break round-tripping of these dates (see if (value.Kind != DateTimeKind.Utc) { // Fetching the UtcOffset is expensive so we need to avoid it if possible. We can do a fast // bounds check to decide if the more expensive bounds check is needed. The result from // TimeZoneInfo.Local.GetUtcOffset(value) is bounded to +/- 24 hours. If // (DateTime.MinValue + 24 hours) < value < (DateTime.MaxValue - 24 hours), then we don't need // to check using the real UtcOffset as it doesn't matter what the offset is, it can't cause // an overflow/underflow condition. // Pre-calculated value of DateTime.MinValue.AddDays(1.0).Ticks; long lowBound = 0xC92A69C000; // Pre-calculated value of DateTime.MaxValue.AddDays(-1.0).Ticks; long highBound = 0x2BCA27ACC9CD7FFF; long tickCount = value.Ticks; if (lowBound > tickCount || highBound < tickCount) // We could potentially under/over flow { tickCount -= TimeZoneInfo.Local.GetUtcOffset(value).Ticks; if ((tickCount > DateTime.MaxValue.Ticks) || (tickCount < DateTime.MinValue.Ticks)) { throw XmlObjectSerializer.CreateSerializationException(SR.JsonDateTimeOutOfRange, new ArgumentOutOfRangeException(nameof(value))); } } } writer.WriteString(JsonGlobals.DateTimeStartGuardReader); writer.WriteValue((value.ToUniversalTime().Ticks - JsonGlobals.unixEpochTicks) / 10000); switch (value.Kind) { case DateTimeKind.Unspecified: case DateTimeKind.Local: // +"zzzz"; //TimeSpan ts = TimeZone.CurrentTimeZone.GetUtcOffset(value.ToLocalTime()); TimeSpan ts = TimeZoneInfo.Local.GetUtcOffset(value.ToLocalTime()); writer.WriteString(string.Create(CultureInfo.InvariantCulture, $"{ts.Hours:+00;-00}{ts.Minutes:00;00}")); break; case DateTimeKind.Utc: break; } writer.WriteString(JsonGlobals.DateTimeEndGuardReader); } internal void WriteJsonSingleArray(float[] value, XmlDictionaryString itemName, XmlDictionaryString? itemNamespace) { for (int i = 0; i < value.Length; i++) { WriteFloat(value[i], itemName, itemNamespace); } } internal void WriteJsonDoubleArray(double[] value, XmlDictionaryString itemName, XmlDictionaryString? itemNamespace) { for (int i = 0; i < value.Length; i++) { WriteDouble(value[i], itemName, itemNamespace); } } internal override void WriteStartElement(string? prefix, string localName, string? ns) { if (localName != null && localName.Length == 0) { base.WriteStartElement(JsonGlobals.itemString, JsonGlobals.itemString); base.WriteAttributeString(null, JsonGlobals.itemString, null, localName); } else { base.WriteStartElement(prefix, localName!, ns); } } } }