diff --git a/Common/Common.AOT/Common.AOT.csproj b/Common/Common.AOT/Common.AOT.csproj
new file mode 100644
index 0000000..a69ba82
--- /dev/null
+++ b/Common/Common.AOT/Common.AOT.csproj
@@ -0,0 +1,47 @@
+
+
+
+ netstandard2.0
+ 0.7.1
+ Common
+ true
+
+
+
+
+
+
+
+ Common\Common.csproj
+
+
+
+
+ Common\AppRouter\LCAppServer.cs
+
+
+ Common\AppRouter\LCAppRouter.cs
+
+
+ Common\Json\LCJsonConverter.cs
+
+
+ Common\Json\LCJsonUtils.cs
+
+
+ Common\Http\LCHttpUtils.cs
+
+
+ Common\Task\LCTaskExtensions.cs
+
+
+ Common\Log\LCLogger.cs
+
+
+ Common\Log\LCLogLevel.cs
+
+
+ Common\Exception\LCException.cs
+
+
+
diff --git a/Libs/Newtonsoft.Json.AOT/Bson/BsonBinaryType.cs b/Libs/Newtonsoft.Json.AOT/Bson/BsonBinaryType.cs
new file mode 100644
index 0000000..8c37edf
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Bson/BsonBinaryType.cs
@@ -0,0 +1,46 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+
+#nullable disable
+
+namespace LC.Newtonsoft.Json.Bson
+{
+ internal enum BsonBinaryType : byte
+ {
+ Binary = 0x00,
+ Function = 0x01,
+
+ [Obsolete("This type has been deprecated in the BSON specification. Use Binary instead.")]
+ BinaryOld = 0x02,
+
+ [Obsolete("This type has been deprecated in the BSON specification. Use Uuid instead.")]
+ UuidOld = 0x03,
+ Uuid = 0x04,
+ Md5 = 0x05,
+ UserDefined = 0x80
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Bson/BsonBinaryWriter.cs b/Libs/Newtonsoft.Json.AOT/Bson/BsonBinaryWriter.cs
new file mode 100644
index 0000000..2617ff6
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Bson/BsonBinaryWriter.cs
@@ -0,0 +1,330 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using LC.Newtonsoft.Json.Utilities;
+
+#nullable disable
+
+namespace LC.Newtonsoft.Json.Bson
+{
+ internal class BsonBinaryWriter
+ {
+ private static readonly Encoding Encoding = new UTF8Encoding(false);
+
+ private readonly BinaryWriter _writer;
+
+ private byte[] _largeByteBuffer;
+
+ public DateTimeKind DateTimeKindHandling { get; set; }
+
+ public BsonBinaryWriter(BinaryWriter writer)
+ {
+ DateTimeKindHandling = DateTimeKind.Utc;
+ _writer = writer;
+ }
+
+ public void Flush()
+ {
+ _writer.Flush();
+ }
+
+ public void Close()
+ {
+#if HAVE_STREAM_READER_WRITER_CLOSE
+ _writer.Close();
+#else
+ _writer.Dispose();
+#endif
+ }
+
+ public void WriteToken(BsonToken t)
+ {
+ CalculateSize(t);
+ WriteTokenInternal(t);
+ }
+
+ private void WriteTokenInternal(BsonToken t)
+ {
+ switch (t.Type)
+ {
+ case BsonType.Object:
+ {
+ BsonObject value = (BsonObject)t;
+ _writer.Write(value.CalculatedSize);
+ foreach (BsonProperty property in value)
+ {
+ _writer.Write((sbyte)property.Value.Type);
+ WriteString((string)property.Name.Value, property.Name.ByteCount, null);
+ WriteTokenInternal(property.Value);
+ }
+ _writer.Write((byte)0);
+ }
+ break;
+ case BsonType.Array:
+ {
+ BsonArray value = (BsonArray)t;
+ _writer.Write(value.CalculatedSize);
+ ulong index = 0;
+ foreach (BsonToken c in value)
+ {
+ _writer.Write((sbyte)c.Type);
+ WriteString(index.ToString(CultureInfo.InvariantCulture), MathUtils.IntLength(index), null);
+ WriteTokenInternal(c);
+ index++;
+ }
+ _writer.Write((byte)0);
+ }
+ break;
+ case BsonType.Integer:
+ {
+ BsonValue value = (BsonValue)t;
+ _writer.Write(Convert.ToInt32(value.Value, CultureInfo.InvariantCulture));
+ }
+ break;
+ case BsonType.Long:
+ {
+ BsonValue value = (BsonValue)t;
+ _writer.Write(Convert.ToInt64(value.Value, CultureInfo.InvariantCulture));
+ }
+ break;
+ case BsonType.Number:
+ {
+ BsonValue value = (BsonValue)t;
+ _writer.Write(Convert.ToDouble(value.Value, CultureInfo.InvariantCulture));
+ }
+ break;
+ case BsonType.String:
+ {
+ BsonString value = (BsonString)t;
+ WriteString((string)value.Value, value.ByteCount, value.CalculatedSize - 4);
+ }
+ break;
+ case BsonType.Boolean:
+ _writer.Write(t == BsonBoolean.True);
+ break;
+ case BsonType.Null:
+ case BsonType.Undefined:
+ break;
+ case BsonType.Date:
+ {
+ BsonValue value = (BsonValue)t;
+
+ long ticks = 0;
+
+ if (value.Value is DateTime dateTime)
+ {
+ if (DateTimeKindHandling == DateTimeKind.Utc)
+ {
+ dateTime = dateTime.ToUniversalTime();
+ }
+ else if (DateTimeKindHandling == DateTimeKind.Local)
+ {
+ dateTime = dateTime.ToLocalTime();
+ }
+
+ ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(dateTime, false);
+ }
+#if HAVE_DATE_TIME_OFFSET
+ else
+ {
+ DateTimeOffset dateTimeOffset = (DateTimeOffset)value.Value;
+ ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(dateTimeOffset.UtcDateTime, dateTimeOffset.Offset);
+ }
+#endif
+
+ _writer.Write(ticks);
+ }
+ break;
+ case BsonType.Binary:
+ {
+ BsonBinary value = (BsonBinary)t;
+
+ byte[] data = (byte[])value.Value;
+ _writer.Write(data.Length);
+ _writer.Write((byte)value.BinaryType);
+ _writer.Write(data);
+ }
+ break;
+ case BsonType.Oid:
+ {
+ BsonValue value = (BsonValue)t;
+
+ byte[] data = (byte[])value.Value;
+ _writer.Write(data);
+ }
+ break;
+ case BsonType.Regex:
+ {
+ BsonRegex value = (BsonRegex)t;
+
+ WriteString((string)value.Pattern.Value, value.Pattern.ByteCount, null);
+ WriteString((string)value.Options.Value, value.Options.ByteCount, null);
+ }
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(t), "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
+ }
+ }
+
+ private void WriteString(string s, int byteCount, int? calculatedlengthPrefix)
+ {
+ if (calculatedlengthPrefix != null)
+ {
+ _writer.Write(calculatedlengthPrefix.GetValueOrDefault());
+ }
+
+ WriteUtf8Bytes(s, byteCount);
+
+ _writer.Write((byte)0);
+ }
+
+ public void WriteUtf8Bytes(string s, int byteCount)
+ {
+ if (s != null)
+ {
+ if (byteCount <= 256)
+ {
+ if (_largeByteBuffer == null)
+ {
+ _largeByteBuffer = new byte[256];
+ }
+
+ Encoding.GetBytes(s, 0, s.Length, _largeByteBuffer, 0);
+ _writer.Write(_largeByteBuffer, 0, byteCount);
+ }
+ else
+ {
+ byte[] bytes = Encoding.GetBytes(s);
+ _writer.Write(bytes);
+ }
+ }
+ }
+
+ private int CalculateSize(int stringByteCount)
+ {
+ return stringByteCount + 1;
+ }
+
+ private int CalculateSizeWithLength(int stringByteCount, bool includeSize)
+ {
+ int baseSize = (includeSize)
+ ? 5 // size bytes + terminator
+ : 1; // terminator
+
+ return baseSize + stringByteCount;
+ }
+
+ private int CalculateSize(BsonToken t)
+ {
+ switch (t.Type)
+ {
+ case BsonType.Object:
+ {
+ BsonObject value = (BsonObject)t;
+
+ int bases = 4;
+ foreach (BsonProperty p in value)
+ {
+ int size = 1;
+ size += CalculateSize(p.Name);
+ size += CalculateSize(p.Value);
+
+ bases += size;
+ }
+ bases += 1;
+ value.CalculatedSize = bases;
+ return bases;
+ }
+ case BsonType.Array:
+ {
+ BsonArray value = (BsonArray)t;
+
+ int size = 4;
+ ulong index = 0;
+ foreach (BsonToken c in value)
+ {
+ size += 1;
+ size += CalculateSize(MathUtils.IntLength(index));
+ size += CalculateSize(c);
+ index++;
+ }
+ size += 1;
+ value.CalculatedSize = size;
+
+ return value.CalculatedSize;
+ }
+ case BsonType.Integer:
+ return 4;
+ case BsonType.Long:
+ return 8;
+ case BsonType.Number:
+ return 8;
+ case BsonType.String:
+ {
+ BsonString value = (BsonString)t;
+ string s = (string)value.Value;
+ value.ByteCount = (s != null) ? Encoding.GetByteCount(s) : 0;
+ value.CalculatedSize = CalculateSizeWithLength(value.ByteCount, value.IncludeLength);
+
+ return value.CalculatedSize;
+ }
+ case BsonType.Boolean:
+ return 1;
+ case BsonType.Null:
+ case BsonType.Undefined:
+ return 0;
+ case BsonType.Date:
+ return 8;
+ case BsonType.Binary:
+ {
+ BsonBinary value = (BsonBinary)t;
+
+ byte[] data = (byte[])value.Value;
+ value.CalculatedSize = 4 + 1 + data.Length;
+
+ return value.CalculatedSize;
+ }
+ case BsonType.Oid:
+ return 12;
+ case BsonType.Regex:
+ {
+ BsonRegex value = (BsonRegex)t;
+ int size = 0;
+ size += CalculateSize(value.Pattern);
+ size += CalculateSize(value.Options);
+ value.CalculatedSize = size;
+
+ return value.CalculatedSize;
+ }
+ default:
+ throw new ArgumentOutOfRangeException(nameof(t), "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Bson/BsonObjectId.cs b/Libs/Newtonsoft.Json.AOT/Bson/BsonObjectId.cs
new file mode 100644
index 0000000..4244cb2
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Bson/BsonObjectId.cs
@@ -0,0 +1,60 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using LC.Newtonsoft.Json.Utilities;
+
+#nullable disable
+
+namespace LC.Newtonsoft.Json.Bson
+{
+ ///
+ /// Represents a BSON Oid (object id).
+ ///
+ [Obsolete("BSON reading and writing has been moved to its own package. See https://www.nuget.org/packages/Newtonsoft.Json.Bson for more details.")]
+ public class BsonObjectId
+ {
+ ///
+ /// Gets or sets the value of the Oid.
+ ///
+ /// The value of the Oid.
+ public byte[] Value { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Oid value.
+ public BsonObjectId(byte[] value)
+ {
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ if (value.Length != 12)
+ {
+ throw new ArgumentException("An ObjectId must be 12 bytes", nameof(value));
+ }
+
+ Value = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Bson/BsonReader.cs b/Libs/Newtonsoft.Json.AOT/Bson/BsonReader.cs
new file mode 100644
index 0000000..3790513
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Bson/BsonReader.cs
@@ -0,0 +1,836 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using System.IO;
+using LC.Newtonsoft.Json.Serialization;
+using LC.Newtonsoft.Json.Utilities;
+using LC.Newtonsoft.Json.Linq;
+
+#nullable disable
+
+namespace LC.Newtonsoft.Json.Bson
+{
+ ///
+ /// Represents a reader that provides fast, non-cached, forward-only access to serialized BSON data.
+ ///
+ [Obsolete("BSON reading and writing has been moved to its own package. See https://www.nuget.org/packages/Newtonsoft.Json.Bson for more details.")]
+ public class BsonReader : JsonReader
+ {
+ private const int MaxCharBytesSize = 128;
+ private static readonly byte[] SeqRange1 = new byte[] { 0, 127 }; // range of 1-byte sequence
+ private static readonly byte[] SeqRange2 = new byte[] { 194, 223 }; // range of 2-byte sequence
+ private static readonly byte[] SeqRange3 = new byte[] { 224, 239 }; // range of 3-byte sequence
+ private static readonly byte[] SeqRange4 = new byte[] { 240, 244 }; // range of 4-byte sequence
+
+ private readonly BinaryReader _reader;
+ private readonly List _stack;
+
+ private byte[] _byteBuffer;
+ private char[] _charBuffer;
+
+ private BsonType _currentElementType;
+ private BsonReaderState _bsonReaderState;
+ private ContainerContext _currentContext;
+
+ private bool _readRootValueAsArray;
+ private bool _jsonNet35BinaryCompatibility;
+ private DateTimeKind _dateTimeKindHandling;
+
+ private enum BsonReaderState
+ {
+ Normal = 0,
+ ReferenceStart = 1,
+ ReferenceRef = 2,
+ ReferenceId = 3,
+ CodeWScopeStart = 4,
+ CodeWScopeCode = 5,
+ CodeWScopeScope = 6,
+ CodeWScopeScopeObject = 7,
+ CodeWScopeScopeEnd = 8
+ }
+
+ private class ContainerContext
+ {
+ public readonly BsonType Type;
+ public int Length;
+ public int Position;
+
+ public ContainerContext(BsonType type)
+ {
+ Type = type;
+ }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether binary data reading should be compatible with incorrect Json.NET 3.5 written binary.
+ ///
+ ///
+ /// true if binary data reading will be compatible with incorrect Json.NET 3.5 written binary; otherwise, false .
+ ///
+ [Obsolete("JsonNet35BinaryCompatibility will be removed in a future version of Json.NET.")]
+ public bool JsonNet35BinaryCompatibility
+ {
+ get => _jsonNet35BinaryCompatibility;
+ set => _jsonNet35BinaryCompatibility = value;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether the root object will be read as a JSON array.
+ ///
+ ///
+ /// true if the root object will be read as a JSON array; otherwise, false .
+ ///
+ public bool ReadRootValueAsArray
+ {
+ get => _readRootValueAsArray;
+ set => _readRootValueAsArray = value;
+ }
+
+ ///
+ /// Gets or sets the used when reading values from BSON.
+ ///
+ /// The used when reading values from BSON.
+ public DateTimeKind DateTimeKindHandling
+ {
+ get => _dateTimeKindHandling;
+ set => _dateTimeKindHandling = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The containing the BSON data to read.
+ public BsonReader(Stream stream)
+ : this(stream, false, DateTimeKind.Local)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The containing the BSON data to read.
+ public BsonReader(BinaryReader reader)
+ : this(reader, false, DateTimeKind.Local)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The containing the BSON data to read.
+ /// if set to true the root object will be read as a JSON array.
+ /// The used when reading values from BSON.
+ public BsonReader(Stream stream, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
+ {
+ ValidationUtils.ArgumentNotNull(stream, nameof(stream));
+ _reader = new BinaryReader(stream);
+ _stack = new List();
+ _readRootValueAsArray = readRootValueAsArray;
+ _dateTimeKindHandling = dateTimeKindHandling;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The containing the BSON data to read.
+ /// if set to true the root object will be read as a JSON array.
+ /// The used when reading values from BSON.
+ public BsonReader(BinaryReader reader, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
+ {
+ ValidationUtils.ArgumentNotNull(reader, nameof(reader));
+ _reader = reader;
+ _stack = new List();
+ _readRootValueAsArray = readRootValueAsArray;
+ _dateTimeKindHandling = dateTimeKindHandling;
+ }
+
+ private string ReadElement()
+ {
+ _currentElementType = ReadType();
+ string elementName = ReadString();
+ return elementName;
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying .
+ ///
+ ///
+ /// true if the next token was read successfully; false if there are no more tokens to read.
+ ///
+ public override bool Read()
+ {
+ try
+ {
+ bool success;
+
+ switch (_bsonReaderState)
+ {
+ case BsonReaderState.Normal:
+ success = ReadNormal();
+ break;
+ case BsonReaderState.ReferenceStart:
+ case BsonReaderState.ReferenceRef:
+ case BsonReaderState.ReferenceId:
+ success = ReadReference();
+ break;
+ case BsonReaderState.CodeWScopeStart:
+ case BsonReaderState.CodeWScopeCode:
+ case BsonReaderState.CodeWScopeScope:
+ case BsonReaderState.CodeWScopeScopeObject:
+ case BsonReaderState.CodeWScopeScopeEnd:
+ success = ReadCodeWScope();
+ break;
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state: {0}".FormatWith(CultureInfo.InvariantCulture, _bsonReaderState));
+ }
+
+ if (!success)
+ {
+ SetToken(JsonToken.None);
+ return false;
+ }
+
+ return true;
+ }
+ catch (EndOfStreamException)
+ {
+ SetToken(JsonToken.None);
+ return false;
+ }
+ }
+
+ ///
+ /// Changes the reader's state to .
+ /// If is set to true , the underlying is also closed.
+ ///
+ public override void Close()
+ {
+ base.Close();
+
+ if (CloseInput)
+ {
+#if HAVE_STREAM_READER_WRITER_CLOSE
+ _reader?.Close();
+#else
+ _reader?.Dispose();
+#endif
+ }
+ }
+
+ private bool ReadCodeWScope()
+ {
+ switch (_bsonReaderState)
+ {
+ case BsonReaderState.CodeWScopeStart:
+ SetToken(JsonToken.PropertyName, "$code");
+ _bsonReaderState = BsonReaderState.CodeWScopeCode;
+ return true;
+ case BsonReaderState.CodeWScopeCode:
+ // total CodeWScope size - not used
+ ReadInt32();
+
+ SetToken(JsonToken.String, ReadLengthString());
+ _bsonReaderState = BsonReaderState.CodeWScopeScope;
+ return true;
+ case BsonReaderState.CodeWScopeScope:
+ if (CurrentState == State.PostValue)
+ {
+ SetToken(JsonToken.PropertyName, "$scope");
+ return true;
+ }
+ else
+ {
+ SetToken(JsonToken.StartObject);
+ _bsonReaderState = BsonReaderState.CodeWScopeScopeObject;
+
+ ContainerContext newContext = new ContainerContext(BsonType.Object);
+ PushContext(newContext);
+ newContext.Length = ReadInt32();
+
+ return true;
+ }
+ case BsonReaderState.CodeWScopeScopeObject:
+ bool result = ReadNormal();
+ if (result && TokenType == JsonToken.EndObject)
+ {
+ _bsonReaderState = BsonReaderState.CodeWScopeScopeEnd;
+ }
+
+ return result;
+ case BsonReaderState.CodeWScopeScopeEnd:
+ SetToken(JsonToken.EndObject);
+ _bsonReaderState = BsonReaderState.Normal;
+ return true;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ private bool ReadReference()
+ {
+ switch (CurrentState)
+ {
+ case State.ObjectStart:
+ {
+ SetToken(JsonToken.PropertyName, JsonTypeReflector.RefPropertyName);
+ _bsonReaderState = BsonReaderState.ReferenceRef;
+ return true;
+ }
+ case State.Property:
+ {
+ if (_bsonReaderState == BsonReaderState.ReferenceRef)
+ {
+ SetToken(JsonToken.String, ReadLengthString());
+ return true;
+ }
+ else if (_bsonReaderState == BsonReaderState.ReferenceId)
+ {
+ SetToken(JsonToken.Bytes, ReadBytes(12));
+ return true;
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + _bsonReaderState);
+ }
+ }
+ case State.PostValue:
+ {
+ if (_bsonReaderState == BsonReaderState.ReferenceRef)
+ {
+ SetToken(JsonToken.PropertyName, JsonTypeReflector.IdPropertyName);
+ _bsonReaderState = BsonReaderState.ReferenceId;
+ return true;
+ }
+ else if (_bsonReaderState == BsonReaderState.ReferenceId)
+ {
+ SetToken(JsonToken.EndObject);
+ _bsonReaderState = BsonReaderState.Normal;
+ return true;
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + _bsonReaderState);
+ }
+ }
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + CurrentState);
+ }
+ }
+
+ private bool ReadNormal()
+ {
+ switch (CurrentState)
+ {
+ case State.Start:
+ {
+ JsonToken token = (!_readRootValueAsArray) ? JsonToken.StartObject : JsonToken.StartArray;
+ BsonType type = (!_readRootValueAsArray) ? BsonType.Object : BsonType.Array;
+
+ SetToken(token);
+ ContainerContext newContext = new ContainerContext(type);
+ PushContext(newContext);
+ newContext.Length = ReadInt32();
+ return true;
+ }
+ case State.Complete:
+ case State.Closed:
+ return false;
+ case State.Property:
+ {
+ ReadType(_currentElementType);
+ return true;
+ }
+ case State.ObjectStart:
+ case State.ArrayStart:
+ case State.PostValue:
+ ContainerContext context = _currentContext;
+ if (context == null)
+ {
+ if (SupportMultipleContent)
+ {
+ goto case State.Start;
+ }
+
+ return false;
+ }
+
+ int lengthMinusEnd = context.Length - 1;
+
+ if (context.Position < lengthMinusEnd)
+ {
+ if (context.Type == BsonType.Array)
+ {
+ ReadElement();
+ ReadType(_currentElementType);
+ return true;
+ }
+ else
+ {
+ SetToken(JsonToken.PropertyName, ReadElement());
+ return true;
+ }
+ }
+ else if (context.Position == lengthMinusEnd)
+ {
+ if (ReadByte() != 0)
+ {
+ throw JsonReaderException.Create(this, "Unexpected end of object byte value.");
+ }
+
+ PopContext();
+ if (_currentContext != null)
+ {
+ MovePosition(context.Length);
+ }
+
+ JsonToken endToken = (context.Type == BsonType.Object) ? JsonToken.EndObject : JsonToken.EndArray;
+ SetToken(endToken);
+ return true;
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Read past end of current container context.");
+ }
+ case State.ConstructorStart:
+ break;
+ case State.Constructor:
+ break;
+ case State.Error:
+ break;
+ case State.Finished:
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ return false;
+ }
+
+ private void PopContext()
+ {
+ _stack.RemoveAt(_stack.Count - 1);
+ if (_stack.Count == 0)
+ {
+ _currentContext = null;
+ }
+ else
+ {
+ _currentContext = _stack[_stack.Count - 1];
+ }
+ }
+
+ private void PushContext(ContainerContext newContext)
+ {
+ _stack.Add(newContext);
+ _currentContext = newContext;
+ }
+
+ private byte ReadByte()
+ {
+ MovePosition(1);
+ return _reader.ReadByte();
+ }
+
+ private void ReadType(BsonType type)
+ {
+ switch (type)
+ {
+ case BsonType.Number:
+ double d = ReadDouble();
+
+ if (_floatParseHandling == FloatParseHandling.Decimal)
+ {
+ SetToken(JsonToken.Float, Convert.ToDecimal(d, CultureInfo.InvariantCulture));
+ }
+ else
+ {
+ SetToken(JsonToken.Float, d);
+ }
+ break;
+ case BsonType.String:
+ case BsonType.Symbol:
+ SetToken(JsonToken.String, ReadLengthString());
+ break;
+ case BsonType.Object:
+ {
+ SetToken(JsonToken.StartObject);
+
+ ContainerContext newContext = new ContainerContext(BsonType.Object);
+ PushContext(newContext);
+ newContext.Length = ReadInt32();
+ break;
+ }
+ case BsonType.Array:
+ {
+ SetToken(JsonToken.StartArray);
+
+ ContainerContext newContext = new ContainerContext(BsonType.Array);
+ PushContext(newContext);
+ newContext.Length = ReadInt32();
+ break;
+ }
+ case BsonType.Binary:
+ BsonBinaryType binaryType;
+ byte[] data = ReadBinary(out binaryType);
+
+ object value = (binaryType != BsonBinaryType.Uuid)
+ ? data
+ : (object)new Guid(data);
+
+ SetToken(JsonToken.Bytes, value);
+ break;
+ case BsonType.Undefined:
+ SetToken(JsonToken.Undefined);
+ break;
+ case BsonType.Oid:
+ byte[] oid = ReadBytes(12);
+ SetToken(JsonToken.Bytes, oid);
+ break;
+ case BsonType.Boolean:
+ bool b = Convert.ToBoolean(ReadByte());
+ SetToken(JsonToken.Boolean, b);
+ break;
+ case BsonType.Date:
+ long ticks = ReadInt64();
+ DateTime utcDateTime = DateTimeUtils.ConvertJavaScriptTicksToDateTime(ticks);
+
+ DateTime dateTime;
+ switch (DateTimeKindHandling)
+ {
+ case DateTimeKind.Unspecified:
+ dateTime = DateTime.SpecifyKind(utcDateTime, DateTimeKind.Unspecified);
+ break;
+ case DateTimeKind.Local:
+ dateTime = utcDateTime.ToLocalTime();
+ break;
+ default:
+ dateTime = utcDateTime;
+ break;
+ }
+
+ SetToken(JsonToken.Date, dateTime);
+ break;
+ case BsonType.Null:
+ SetToken(JsonToken.Null);
+ break;
+ case BsonType.Regex:
+ string expression = ReadString();
+ string modifiers = ReadString();
+
+ string regex = @"/" + expression + @"/" + modifiers;
+ SetToken(JsonToken.String, regex);
+ break;
+ case BsonType.Reference:
+ SetToken(JsonToken.StartObject);
+ _bsonReaderState = BsonReaderState.ReferenceStart;
+ break;
+ case BsonType.Code:
+ SetToken(JsonToken.String, ReadLengthString());
+ break;
+ case BsonType.CodeWScope:
+ SetToken(JsonToken.StartObject);
+ _bsonReaderState = BsonReaderState.CodeWScopeStart;
+ break;
+ case BsonType.Integer:
+ SetToken(JsonToken.Integer, (long)ReadInt32());
+ break;
+ case BsonType.TimeStamp:
+ case BsonType.Long:
+ SetToken(JsonToken.Integer, ReadInt64());
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(type), "Unexpected BsonType value: " + type);
+ }
+ }
+
+ private byte[] ReadBinary(out BsonBinaryType binaryType)
+ {
+ int dataLength = ReadInt32();
+
+ binaryType = (BsonBinaryType)ReadByte();
+
+#pragma warning disable 612,618
+ // the old binary type has the data length repeated in the data for some reason
+ if (binaryType == BsonBinaryType.BinaryOld && !_jsonNet35BinaryCompatibility)
+ {
+ dataLength = ReadInt32();
+ }
+#pragma warning restore 612,618
+
+ return ReadBytes(dataLength);
+ }
+
+ private string ReadString()
+ {
+ EnsureBuffers();
+
+ StringBuilder builder = null;
+
+ int totalBytesRead = 0;
+ // used in case of left over multibyte characters in the buffer
+ int offset = 0;
+ while (true)
+ {
+ int count = offset;
+ byte b;
+ while (count < MaxCharBytesSize && (b = _reader.ReadByte()) > 0)
+ {
+ _byteBuffer[count++] = b;
+ }
+ int byteCount = count - offset;
+ totalBytesRead += byteCount;
+
+ if (count < MaxCharBytesSize && builder == null)
+ {
+ // pref optimization to avoid reading into a string builder
+ // if string is smaller than the buffer then return it directly
+ int length = Encoding.UTF8.GetChars(_byteBuffer, 0, byteCount, _charBuffer, 0);
+
+ MovePosition(totalBytesRead + 1);
+ return new string(_charBuffer, 0, length);
+ }
+ else
+ {
+ // calculate the index of the end of the last full character in the buffer
+ int lastFullCharStop = GetLastFullCharStop(count - 1);
+
+ int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
+
+ if (builder == null)
+ {
+ builder = new StringBuilder(MaxCharBytesSize * 2);
+ }
+
+ builder.Append(_charBuffer, 0, charCount);
+
+ if (lastFullCharStop < byteCount - 1)
+ {
+ offset = byteCount - lastFullCharStop - 1;
+ // copy left over multi byte characters to beginning of buffer for next iteration
+ Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, offset);
+ }
+ else
+ {
+ // reached end of string
+ if (count < MaxCharBytesSize)
+ {
+ MovePosition(totalBytesRead + 1);
+ return builder.ToString();
+ }
+
+ offset = 0;
+ }
+ }
+ }
+ }
+
+ private string ReadLengthString()
+ {
+ int length = ReadInt32();
+
+ MovePosition(length);
+
+ string s = GetString(length - 1);
+ _reader.ReadByte();
+
+ return s;
+ }
+
+ private string GetString(int length)
+ {
+ if (length == 0)
+ {
+ return string.Empty;
+ }
+
+ EnsureBuffers();
+
+ StringBuilder builder = null;
+
+ int totalBytesRead = 0;
+
+ // used in case of left over multibyte characters in the buffer
+ int offset = 0;
+ do
+ {
+ int count = ((length - totalBytesRead) > MaxCharBytesSize - offset)
+ ? MaxCharBytesSize - offset
+ : length - totalBytesRead;
+
+ int byteCount = _reader.Read(_byteBuffer, offset, count);
+
+ if (byteCount == 0)
+ {
+ throw new EndOfStreamException("Unable to read beyond the end of the stream.");
+ }
+
+ totalBytesRead += byteCount;
+
+ // Above, byteCount is how many bytes we read this time.
+ // Below, byteCount is how many bytes are in the _byteBuffer.
+ byteCount += offset;
+
+ if (byteCount == length)
+ {
+ // pref optimization to avoid reading into a string builder
+ // first iteration and all bytes read then return string directly
+ int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, byteCount, _charBuffer, 0);
+ return new string(_charBuffer, 0, charCount);
+ }
+ else
+ {
+ int lastFullCharStop = GetLastFullCharStop(byteCount - 1);
+
+ if (builder == null)
+ {
+ builder = new StringBuilder(length);
+ }
+
+ int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
+ builder.Append(_charBuffer, 0, charCount);
+
+ if (lastFullCharStop < byteCount - 1)
+ {
+ offset = byteCount - lastFullCharStop - 1;
+ // copy left over multi byte characters to beginning of buffer for next iteration
+ Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, offset);
+ }
+ else
+ {
+ offset = 0;
+ }
+ }
+ } while (totalBytesRead < length);
+
+ return builder.ToString();
+ }
+
+ private int GetLastFullCharStop(int start)
+ {
+ int lookbackPos = start;
+ int bis = 0;
+ while (lookbackPos >= 0)
+ {
+ bis = BytesInSequence(_byteBuffer[lookbackPos]);
+ if (bis == 0)
+ {
+ lookbackPos--;
+ continue;
+ }
+ else if (bis == 1)
+ {
+ break;
+ }
+ else
+ {
+ lookbackPos--;
+ break;
+ }
+ }
+ if (bis == start - lookbackPos)
+ {
+ //Full character.
+ return start;
+ }
+ else
+ {
+ return lookbackPos;
+ }
+ }
+
+ private int BytesInSequence(byte b)
+ {
+ if (b <= SeqRange1[1])
+ {
+ return 1;
+ }
+ if (b >= SeqRange2[0] && b <= SeqRange2[1])
+ {
+ return 2;
+ }
+ if (b >= SeqRange3[0] && b <= SeqRange3[1])
+ {
+ return 3;
+ }
+ if (b >= SeqRange4[0] && b <= SeqRange4[1])
+ {
+ return 4;
+ }
+ return 0;
+ }
+
+ private void EnsureBuffers()
+ {
+ if (_byteBuffer == null)
+ {
+ _byteBuffer = new byte[MaxCharBytesSize];
+ }
+ if (_charBuffer == null)
+ {
+ int charBufferSize = Encoding.UTF8.GetMaxCharCount(MaxCharBytesSize);
+ _charBuffer = new char[charBufferSize];
+ }
+ }
+
+ private double ReadDouble()
+ {
+ MovePosition(8);
+ return _reader.ReadDouble();
+ }
+
+ private int ReadInt32()
+ {
+ MovePosition(4);
+ return _reader.ReadInt32();
+ }
+
+ private long ReadInt64()
+ {
+ MovePosition(8);
+ return _reader.ReadInt64();
+ }
+
+ private BsonType ReadType()
+ {
+ MovePosition(1);
+ return (BsonType)_reader.ReadSByte();
+ }
+
+ private void MovePosition(int count)
+ {
+ _currentContext.Position += count;
+ }
+
+ private byte[] ReadBytes(int count)
+ {
+ MovePosition(count);
+ return _reader.ReadBytes(count);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Bson/BsonToken.cs b/Libs/Newtonsoft.Json.AOT/Bson/BsonToken.cs
new file mode 100644
index 0000000..73e5014
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Bson/BsonToken.cs
@@ -0,0 +1,168 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System.Collections;
+using System.Collections.Generic;
+
+#nullable disable
+
+namespace LC.Newtonsoft.Json.Bson
+{
+ internal abstract class BsonToken
+ {
+ public abstract BsonType Type { get; }
+ public BsonToken Parent { get; set; }
+ public int CalculatedSize { get; set; }
+ }
+
+ internal class BsonObject : BsonToken, IEnumerable
+ {
+ private readonly List _children = new List();
+
+ public void Add(string name, BsonToken token)
+ {
+ _children.Add(new BsonProperty { Name = new BsonString(name, false), Value = token });
+ token.Parent = this;
+ }
+
+ public override BsonType Type => BsonType.Object;
+
+ public IEnumerator GetEnumerator()
+ {
+ return _children.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+
+ internal class BsonArray : BsonToken, IEnumerable
+ {
+ private readonly List _children = new List();
+
+ public void Add(BsonToken token)
+ {
+ _children.Add(token);
+ token.Parent = this;
+ }
+
+ public override BsonType Type => BsonType.Array;
+
+ public IEnumerator GetEnumerator()
+ {
+ return _children.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+
+ internal class BsonEmpty : BsonToken
+ {
+ public static readonly BsonToken Null = new BsonEmpty(BsonType.Null);
+ public static readonly BsonToken Undefined = new BsonEmpty(BsonType.Undefined);
+
+ private BsonEmpty(BsonType type)
+ {
+ Type = type;
+ }
+
+ public override BsonType Type { get; }
+ }
+
+ internal class BsonValue : BsonToken
+ {
+ private readonly object _value;
+ private readonly BsonType _type;
+
+ public BsonValue(object value, BsonType type)
+ {
+ _value = value;
+ _type = type;
+ }
+
+ public object Value => _value;
+
+ public override BsonType Type => _type;
+ }
+
+ internal class BsonBoolean : BsonValue
+ {
+ public static readonly BsonBoolean False = new BsonBoolean(false);
+ public static readonly BsonBoolean True = new BsonBoolean(true);
+
+ private BsonBoolean(bool value)
+ : base(value, BsonType.Boolean)
+ {
+ }
+ }
+
+ internal class BsonString : BsonValue
+ {
+ public int ByteCount { get; set; }
+ public bool IncludeLength { get; }
+
+ public BsonString(object value, bool includeLength)
+ : base(value, BsonType.String)
+ {
+ IncludeLength = includeLength;
+ }
+ }
+
+ internal class BsonBinary : BsonValue
+ {
+ public BsonBinaryType BinaryType { get; set; }
+
+ public BsonBinary(byte[] value, BsonBinaryType binaryType)
+ : base(value, BsonType.Binary)
+ {
+ BinaryType = binaryType;
+ }
+ }
+
+ internal class BsonRegex : BsonToken
+ {
+ public BsonString Pattern { get; set; }
+ public BsonString Options { get; set; }
+
+ public BsonRegex(string pattern, string options)
+ {
+ Pattern = new BsonString(pattern, false);
+ Options = new BsonString(options, false);
+ }
+
+ public override BsonType Type => BsonType.Regex;
+ }
+
+ internal class BsonProperty
+ {
+ public BsonString Name { get; set; }
+ public BsonToken Value { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Bson/BsonType.cs b/Libs/Newtonsoft.Json.AOT/Bson/BsonType.cs
new file mode 100644
index 0000000..90d7b08
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Bson/BsonType.cs
@@ -0,0 +1,53 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#nullable disable
+
+namespace LC.Newtonsoft.Json.Bson
+{
+ internal enum BsonType : sbyte
+ {
+ Number = 1,
+ String = 2,
+ Object = 3,
+ Array = 4,
+ Binary = 5,
+ Undefined = 6,
+ Oid = 7,
+ Boolean = 8,
+ Date = 9,
+ Null = 10,
+ Regex = 11,
+ Reference = 12,
+ Code = 13,
+ Symbol = 14,
+ CodeWScope = 15,
+ Integer = 16,
+ TimeStamp = 17,
+ Long = 18,
+ MinKey = -1,
+ MaxKey = 127
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Bson/BsonWriter.cs b/Libs/Newtonsoft.Json.AOT/Bson/BsonWriter.cs
new file mode 100644
index 0000000..1f059d6
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Bson/BsonWriter.cs
@@ -0,0 +1,539 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+#if HAVE_BIG_INTEGER
+using System.Numerics;
+#endif
+using System.Text;
+using LC.Newtonsoft.Json.Utilities;
+using LC.Newtonsoft.Json.Linq;
+using System.Globalization;
+
+#nullable disable
+
+namespace LC.Newtonsoft.Json.Bson
+{
+ ///
+ /// Represents a writer that provides a fast, non-cached, forward-only way of generating BSON data.
+ ///
+ [Obsolete("BSON reading and writing has been moved to its own package. See https://www.nuget.org/packages/Newtonsoft.Json.Bson for more details.")]
+ public class BsonWriter : JsonWriter
+ {
+ private readonly BsonBinaryWriter _writer;
+
+ private BsonToken _root;
+ private BsonToken _parent;
+ private string _propertyName;
+
+ ///
+ /// Gets or sets the used when writing values to BSON.
+ /// When set to no conversion will occur.
+ ///
+ /// The used when writing values to BSON.
+ public DateTimeKind DateTimeKindHandling
+ {
+ get => _writer.DateTimeKindHandling;
+ set => _writer.DateTimeKindHandling = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to write to.
+ public BsonWriter(Stream stream)
+ {
+ ValidationUtils.ArgumentNotNull(stream, nameof(stream));
+ _writer = new BsonBinaryWriter(new BinaryWriter(stream));
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to write to.
+ public BsonWriter(BinaryWriter writer)
+ {
+ ValidationUtils.ArgumentNotNull(writer, nameof(writer));
+ _writer = new BsonBinaryWriter(writer);
+ }
+
+ ///
+ /// Flushes whatever is in the buffer to the underlying and also flushes the underlying stream.
+ ///
+ public override void Flush()
+ {
+ _writer.Flush();
+ }
+
+ ///
+ /// Writes the end.
+ ///
+ /// The token.
+ protected override void WriteEnd(JsonToken token)
+ {
+ base.WriteEnd(token);
+ RemoveParent();
+
+ if (Top == 0)
+ {
+ _writer.WriteToken(_root);
+ }
+ }
+
+ ///
+ /// Writes a comment /*...*/ containing the specified text.
+ ///
+ /// Text to place inside the comment.
+ public override void WriteComment(string text)
+ {
+ throw JsonWriterException.Create(this, "Cannot write JSON comment as BSON.", null);
+ }
+
+ ///
+ /// Writes the start of a constructor with the given name.
+ ///
+ /// The name of the constructor.
+ public override void WriteStartConstructor(string name)
+ {
+ throw JsonWriterException.Create(this, "Cannot write JSON constructor as BSON.", null);
+ }
+
+ ///
+ /// Writes raw JSON.
+ ///
+ /// The raw JSON to write.
+ public override void WriteRaw(string json)
+ {
+ throw JsonWriterException.Create(this, "Cannot write raw JSON as BSON.", null);
+ }
+
+ ///
+ /// Writes raw JSON where a value is expected and updates the writer's state.
+ ///
+ /// The raw JSON to write.
+ public override void WriteRawValue(string json)
+ {
+ throw JsonWriterException.Create(this, "Cannot write raw JSON as BSON.", null);
+ }
+
+ ///
+ /// Writes the beginning of a JSON array.
+ ///
+ public override void WriteStartArray()
+ {
+ base.WriteStartArray();
+
+ AddParent(new BsonArray());
+ }
+
+ ///
+ /// Writes the beginning of a JSON object.
+ ///
+ public override void WriteStartObject()
+ {
+ base.WriteStartObject();
+
+ AddParent(new BsonObject());
+ }
+
+ ///
+ /// Writes the property name of a name/value pair on a JSON object.
+ ///
+ /// The name of the property.
+ public override void WritePropertyName(string name)
+ {
+ base.WritePropertyName(name);
+
+ _propertyName = name;
+ }
+
+ ///
+ /// Closes this writer.
+ /// If is set to true , the underlying is also closed.
+ /// If is set to true , the JSON is auto-completed.
+ ///
+ public override void Close()
+ {
+ base.Close();
+
+ if (CloseOutput)
+ {
+ _writer?.Close();
+ }
+ }
+
+ private void AddParent(BsonToken container)
+ {
+ AddToken(container);
+ _parent = container;
+ }
+
+ private void RemoveParent()
+ {
+ _parent = _parent.Parent;
+ }
+
+ private void AddValue(object value, BsonType type)
+ {
+ AddToken(new BsonValue(value, type));
+ }
+
+ internal void AddToken(BsonToken token)
+ {
+ if (_parent != null)
+ {
+ if (_parent is BsonObject bo)
+ {
+ bo.Add(_propertyName, token);
+ _propertyName = null;
+ }
+ else
+ {
+ ((BsonArray)_parent).Add(token);
+ }
+ }
+ else
+ {
+ if (token.Type != BsonType.Object && token.Type != BsonType.Array)
+ {
+ throw JsonWriterException.Create(this, "Error writing {0} value. BSON must start with an Object or Array.".FormatWith(CultureInfo.InvariantCulture, token.Type), null);
+ }
+
+ _parent = token;
+ _root = token;
+ }
+ }
+
+ #region WriteValue methods
+ ///
+ /// Writes a value.
+ /// An error will raised if the value cannot be written as a single JSON token.
+ ///
+ /// The value to write.
+ public override void WriteValue(object value)
+ {
+#if HAVE_BIG_INTEGER
+ if (value is BigInteger i)
+ {
+ SetWriteState(JsonToken.Integer, null);
+ AddToken(new BsonBinary(i.ToByteArray(), BsonBinaryType.Binary));
+ }
+ else
+#endif
+ {
+ base.WriteValue(value);
+ }
+ }
+
+ ///
+ /// Writes a null value.
+ ///
+ public override void WriteNull()
+ {
+ base.WriteNull();
+ AddToken(BsonEmpty.Null);
+ }
+
+ ///
+ /// Writes an undefined value.
+ ///
+ public override void WriteUndefined()
+ {
+ base.WriteUndefined();
+ AddToken(BsonEmpty.Undefined);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(string value)
+ {
+ base.WriteValue(value);
+ AddToken(value == null ? BsonEmpty.Null : new BsonString(value, true));
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(int value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public override void WriteValue(uint value)
+ {
+ if (value > int.MaxValue)
+ {
+ throw JsonWriterException.Create(this, "Value is too large to fit in a signed 32 bit integer. BSON does not support unsigned values.", null);
+ }
+
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(long value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Long);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public override void WriteValue(ulong value)
+ {
+ if (value > long.MaxValue)
+ {
+ throw JsonWriterException.Create(this, "Value is too large to fit in a signed 64 bit integer. BSON does not support unsigned values.", null);
+ }
+
+ base.WriteValue(value);
+ AddValue(value, BsonType.Long);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(float value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Number);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(double value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Number);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(bool value)
+ {
+ base.WriteValue(value);
+ AddToken(value ? BsonBoolean.True : BsonBoolean.False);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(short value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public override void WriteValue(ushort value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(char value)
+ {
+ base.WriteValue(value);
+ string s = null;
+#if HAVE_CHAR_TO_STRING_WITH_CULTURE
+ s = value.ToString(CultureInfo.InvariantCulture);
+#else
+ s = value.ToString();
+#endif
+ AddToken(new BsonString(s, true));
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(byte value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public override void WriteValue(sbyte value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(decimal value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Number);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(DateTime value)
+ {
+ base.WriteValue(value);
+ value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling);
+ AddValue(value, BsonType.Date);
+ }
+
+#if HAVE_DATE_TIME_OFFSET
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(DateTimeOffset value)
+ {
+ base.WriteValue(value);
+ AddValue(value, BsonType.Date);
+ }
+#endif
+
+ ///
+ /// Writes a [] value.
+ ///
+ /// The [] value to write.
+ public override void WriteValue(byte[] value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ return;
+ }
+
+ base.WriteValue(value);
+ AddToken(new BsonBinary(value, BsonBinaryType.Binary));
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(Guid value)
+ {
+ base.WriteValue(value);
+ AddToken(new BsonBinary(value.ToByteArray(), BsonBinaryType.Uuid));
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(TimeSpan value)
+ {
+ base.WriteValue(value);
+ AddToken(new BsonString(value.ToString(), true));
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(Uri value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ return;
+ }
+
+ base.WriteValue(value);
+ AddToken(new BsonString(value.ToString(), true));
+ }
+ #endregion
+
+ ///
+ /// Writes a [] value that represents a BSON object id.
+ ///
+ /// The Object ID value to write.
+ public void WriteObjectId(byte[] value)
+ {
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+
+ if (value.Length != 12)
+ {
+ throw JsonWriterException.Create(this, "An object id must be 12 bytes", null);
+ }
+
+ // hack to update the writer state
+ SetWriteState(JsonToken.Undefined, null);
+ AddValue(value, BsonType.Oid);
+ }
+
+ ///
+ /// Writes a BSON regex.
+ ///
+ /// The regex pattern.
+ /// The regex options.
+ public void WriteRegex(string pattern, string options)
+ {
+ ValidationUtils.ArgumentNotNull(pattern, nameof(pattern));
+
+ // hack to update the writer state
+ SetWriteState(JsonToken.Undefined, null);
+ AddToken(new BsonRegex(pattern, options));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/ConstructorHandling.cs b/Libs/Newtonsoft.Json.AOT/ConstructorHandling.cs
new file mode 100644
index 0000000..499e734
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/ConstructorHandling.cs
@@ -0,0 +1,43 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Specifies how constructors are used when initializing objects during deserialization by the .
+ ///
+ public enum ConstructorHandling
+ {
+ ///
+ /// First attempt to use the public default constructor, then fall back to a single parameterized constructor, then to the non-public default constructor.
+ ///
+ Default = 0,
+
+ ///
+ /// Json.NET will use a non-public default constructor before falling back to a parameterized constructor.
+ ///
+ AllowNonPublicDefaultConstructor = 1
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/BinaryConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/BinaryConverter.cs
new file mode 100644
index 0000000..8462478
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/BinaryConverter.cs
@@ -0,0 +1,212 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if HAVE_LINQ || HAVE_ADO_NET
+using System;
+using System.Globalization;
+using LC.Newtonsoft.Json.Utilities;
+using System.Collections.Generic;
+using System.Diagnostics;
+#if HAVE_ADO_NET
+using System.Data.SqlTypes;
+#endif
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts a binary value to and from a base 64 string value.
+ ///
+ public class BinaryConverter : JsonConverter
+ {
+#if HAVE_LINQ
+ private const string BinaryTypeName = "System.Data.Linq.Binary";
+ private const string BinaryToArrayName = "ToArray";
+ private static ReflectionObject? _reflectionObject;
+#endif
+
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ byte[] data = GetByteArray(value);
+
+ writer.WriteValue(data);
+ }
+
+ private byte[] GetByteArray(object value)
+ {
+#if HAVE_LINQ
+ if (value.GetType().FullName == BinaryTypeName)
+ {
+ EnsureReflectionObject(value.GetType());
+ MiscellaneousUtils.Assert(_reflectionObject != null);
+
+ return (byte[])_reflectionObject.GetValue(value, BinaryToArrayName)!;
+ }
+#endif
+#if HAVE_ADO_NET
+ if (value is SqlBinary binary)
+ {
+ return binary.Value;
+ }
+#endif
+
+ throw new JsonSerializationException("Unexpected value type when writing binary: {0}".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
+ }
+
+#if HAVE_LINQ
+ private static void EnsureReflectionObject(Type t)
+ {
+ if (_reflectionObject == null)
+ {
+ _reflectionObject = ReflectionObject.Create(t, t.GetConstructor(new[] { typeof(byte[]) }), BinaryToArrayName);
+ }
+ }
+#endif
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ if (!ReflectionUtils.IsNullable(objectType))
+ {
+ throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
+ }
+
+ return null;
+ }
+
+ byte[] data;
+
+ if (reader.TokenType == JsonToken.StartArray)
+ {
+ data = ReadByteArray(reader);
+ }
+ else if (reader.TokenType == JsonToken.String)
+ {
+ // current token is already at base64 string
+ // unable to call ReadAsBytes so do it the old fashion way
+ string encodedData = reader.Value!.ToString();
+ data = Convert.FromBase64String(encodedData);
+ }
+ else
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected token parsing binary. Expected String or StartArray, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
+ }
+
+ Type t = (ReflectionUtils.IsNullableType(objectType))
+ ? Nullable.GetUnderlyingType(objectType)
+ : objectType;
+
+#if HAVE_LINQ
+ if (t.FullName == BinaryTypeName)
+ {
+ EnsureReflectionObject(t);
+ MiscellaneousUtils.Assert(_reflectionObject != null);
+
+ return _reflectionObject.Creator!(data);
+ }
+#endif
+
+#if HAVE_ADO_NET
+ if (t == typeof(SqlBinary))
+ {
+ return new SqlBinary(data);
+ }
+#endif
+
+ throw JsonSerializationException.Create(reader, "Unexpected object type when writing binary: {0}".FormatWith(CultureInfo.InvariantCulture, objectType));
+ }
+
+ private byte[] ReadByteArray(JsonReader reader)
+ {
+ List byteList = new List();
+
+ while (reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.Integer:
+ byteList.Add(Convert.ToByte(reader.Value, CultureInfo.InvariantCulture));
+ break;
+ case JsonToken.EndArray:
+ return byteList.ToArray();
+ case JsonToken.Comment:
+ // skip
+ break;
+ default:
+ throw JsonSerializationException.Create(reader, "Unexpected token when reading bytes: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
+ }
+ }
+
+ throw JsonSerializationException.Create(reader, "Unexpected end when reading bytes.");
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+#if HAVE_LINQ
+ if (objectType.FullName == BinaryTypeName)
+ {
+ return true;
+ }
+#endif
+#if HAVE_ADO_NET
+ if (objectType == typeof(SqlBinary) || objectType == typeof(SqlBinary?))
+ {
+ return true;
+ }
+#endif
+
+ return false;
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/BsonObjectIdConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/BsonObjectIdConverter.cs
new file mode 100644
index 0000000..6e2a3e9
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/BsonObjectIdConverter.cs
@@ -0,0 +1,93 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using LC.Newtonsoft.Json.Bson;
+using System.Globalization;
+using LC.Newtonsoft.Json.Utilities;
+
+#nullable disable
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts a to and from JSON and BSON.
+ ///
+ [Obsolete("BSON reading and writing has been moved to its own package. See https://www.nuget.org/packages/Newtonsoft.Json.Bson for more details.")]
+ public class BsonObjectIdConverter : JsonConverter
+ {
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ BsonObjectId objectId = (BsonObjectId)value;
+
+ if (writer is BsonWriter bsonWriter)
+ {
+ bsonWriter.WriteObjectId(objectId.Value);
+ }
+ else
+ {
+ writer.WriteValue(objectId.Value);
+ }
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType != JsonToken.Bytes)
+ {
+ throw new JsonSerializationException("Expected Bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
+ }
+
+ byte[] value = (byte[])reader.Value;
+
+ return new BsonObjectId(value);
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ return (objectType == typeof(BsonObjectId));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/CustomCreationConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/CustomCreationConverter.cs
new file mode 100644
index 0000000..b08fe59
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/CustomCreationConverter.cs
@@ -0,0 +1,101 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Reflection;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Creates a custom object.
+ ///
+ /// The object type to convert.
+ public abstract class CustomCreationConverter : JsonConverter
+ {
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ throw new NotSupportedException("CustomCreationConverter should only be used while deserializing.");
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return null;
+ }
+
+ T value = Create(objectType);
+ if (value == null)
+ {
+ throw new JsonSerializationException("No object created.");
+ }
+
+ serializer.Populate(reader, value);
+ return value;
+ }
+
+ ///
+ /// Creates an object which will then be populated by the serializer.
+ ///
+ /// Type of the object.
+ /// The created object.
+ public abstract T Create(Type objectType);
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ return typeof(T).IsAssignableFrom(objectType);
+ }
+
+ ///
+ /// Gets a value indicating whether this can write JSON.
+ ///
+ ///
+ /// true if this can write JSON; otherwise, false .
+ ///
+ public override bool CanWrite => false;
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/DataSetConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/DataSetConverter.cs
new file mode 100644
index 0000000..c4f57bf
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/DataSetConverter.cs
@@ -0,0 +1,125 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if HAVE_ADO_NET
+using System;
+using System.Data;
+using LC.Newtonsoft.Json.Serialization;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts a to and from JSON.
+ ///
+ public class DataSetConverter : JsonConverter
+ {
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ DataSet dataSet = (DataSet)value;
+ DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver;
+
+ DataTableConverter converter = new DataTableConverter();
+
+ writer.WriteStartObject();
+
+ foreach (DataTable table in dataSet.Tables)
+ {
+ writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(table.TableName) : table.TableName);
+
+ converter.WriteJson(writer, table, serializer);
+ }
+
+ writer.WriteEndObject();
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return null;
+ }
+
+ // handle typed datasets
+ DataSet ds = (objectType == typeof(DataSet))
+ ? new DataSet()
+ : (DataSet)Activator.CreateInstance(objectType);
+
+ DataTableConverter converter = new DataTableConverter();
+
+ reader.ReadAndAssert();
+
+ while (reader.TokenType == JsonToken.PropertyName)
+ {
+ DataTable dt = ds.Tables[(string)reader.Value!];
+ bool exists = (dt != null);
+
+ dt = (DataTable)converter.ReadJson(reader, typeof(DataTable), dt, serializer)!;
+
+ if (!exists)
+ {
+ ds.Tables.Add(dt);
+ }
+
+ reader.ReadAndAssert();
+ }
+
+ return ds;
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified value type.
+ ///
+ /// Type of the value.
+ ///
+ /// true if this instance can convert the specified value type; otherwise, false .
+ ///
+ public override bool CanConvert(Type valueType)
+ {
+ return typeof(DataSet).IsAssignableFrom(valueType);
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/DataTableConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/DataTableConverter.cs
new file mode 100644
index 0000000..afaec81
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/DataTableConverter.cs
@@ -0,0 +1,254 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if HAVE_ADO_NET
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using LC.Newtonsoft.Json.Utilities;
+using System;
+using System.Data;
+using LC.Newtonsoft.Json.Serialization;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts a to and from JSON.
+ ///
+ public class DataTableConverter : JsonConverter
+ {
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ DataTable table = (DataTable)value;
+ DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver;
+
+ writer.WriteStartArray();
+
+ foreach (DataRow row in table.Rows)
+ {
+ writer.WriteStartObject();
+ foreach (DataColumn column in row.Table.Columns)
+ {
+ object columnValue = row[column];
+
+ if (serializer.NullValueHandling == NullValueHandling.Ignore && (columnValue == null || columnValue == DBNull.Value))
+ {
+ continue;
+ }
+
+ writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(column.ColumnName) : column.ColumnName);
+ serializer.Serialize(writer, columnValue);
+ }
+ writer.WriteEndObject();
+ }
+
+ writer.WriteEndArray();
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return null;
+ }
+
+ if (!(existingValue is DataTable dt))
+ {
+ // handle typed datasets
+ dt = (objectType == typeof(DataTable))
+ ? new DataTable()
+ : (DataTable)Activator.CreateInstance(objectType);
+ }
+
+ // DataTable is inside a DataSet
+ // populate the name from the property name
+ if (reader.TokenType == JsonToken.PropertyName)
+ {
+ dt.TableName = (string)reader.Value!;
+
+ reader.ReadAndAssert();
+
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return dt;
+ }
+ }
+
+ if (reader.TokenType != JsonToken.StartArray)
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected JSON token when reading DataTable. Expected StartArray, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
+ }
+
+ reader.ReadAndAssert();
+
+ while (reader.TokenType != JsonToken.EndArray)
+ {
+ CreateRow(reader, dt, serializer);
+
+ reader.ReadAndAssert();
+ }
+
+ return dt;
+ }
+
+ private static void CreateRow(JsonReader reader, DataTable dt, JsonSerializer serializer)
+ {
+ DataRow dr = dt.NewRow();
+ reader.ReadAndAssert();
+
+ while (reader.TokenType == JsonToken.PropertyName)
+ {
+ string columnName = (string)reader.Value!;
+
+ reader.ReadAndAssert();
+
+ DataColumn column = dt.Columns[columnName];
+ if (column == null)
+ {
+ Type columnType = GetColumnDataType(reader);
+ column = new DataColumn(columnName, columnType);
+ dt.Columns.Add(column);
+ }
+
+ if (column.DataType == typeof(DataTable))
+ {
+ if (reader.TokenType == JsonToken.StartArray)
+ {
+ reader.ReadAndAssert();
+ }
+
+ DataTable nestedDt = new DataTable();
+
+ while (reader.TokenType != JsonToken.EndArray)
+ {
+ CreateRow(reader, nestedDt, serializer);
+
+ reader.ReadAndAssert();
+ }
+
+ dr[columnName] = nestedDt;
+ }
+ else if (column.DataType.IsArray && column.DataType != typeof(byte[]))
+ {
+ if (reader.TokenType == JsonToken.StartArray)
+ {
+ reader.ReadAndAssert();
+ }
+
+ List o = new List();
+
+ while (reader.TokenType != JsonToken.EndArray)
+ {
+ o.Add(reader.Value);
+ reader.ReadAndAssert();
+ }
+
+ Array destinationArray = Array.CreateInstance(column.DataType.GetElementType(), o.Count);
+ ((IList)o).CopyTo(destinationArray, 0);
+
+ dr[columnName] = destinationArray;
+ }
+ else
+ {
+ object columnValue = (reader.Value != null)
+ ? serializer.Deserialize(reader, column.DataType) ?? DBNull.Value
+ : DBNull.Value;
+
+ dr[columnName] = columnValue;
+ }
+
+ reader.ReadAndAssert();
+ }
+
+ dr.EndEdit();
+ dt.Rows.Add(dr);
+ }
+
+ private static Type GetColumnDataType(JsonReader reader)
+ {
+ JsonToken tokenType = reader.TokenType;
+
+ switch (tokenType)
+ {
+ case JsonToken.Integer:
+ case JsonToken.Boolean:
+ case JsonToken.Float:
+ case JsonToken.String:
+ case JsonToken.Date:
+ case JsonToken.Bytes:
+ return reader.ValueType!;
+ case JsonToken.Null:
+ case JsonToken.Undefined:
+ case JsonToken.EndArray:
+ return typeof(string);
+ case JsonToken.StartArray:
+ reader.ReadAndAssert();
+ if (reader.TokenType == JsonToken.StartObject)
+ {
+ return typeof(DataTable); // nested datatable
+ }
+
+ Type arrayType = GetColumnDataType(reader);
+ return arrayType.MakeArrayType();
+ default:
+ throw JsonSerializationException.Create(reader, "Unexpected JSON token when reading DataTable: {0}".FormatWith(CultureInfo.InvariantCulture, tokenType));
+ }
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified value type.
+ ///
+ /// Type of the value.
+ ///
+ /// true if this instance can convert the specified value type; otherwise, false .
+ ///
+ public override bool CanConvert(Type valueType)
+ {
+ return typeof(DataTable).IsAssignableFrom(valueType);
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/DateTimeConverterBase.cs b/Libs/Newtonsoft.Json.AOT/Converters/DateTimeConverterBase.cs
new file mode 100644
index 0000000..49a0e19
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/DateTimeConverterBase.cs
@@ -0,0 +1,58 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Provides a base class for converting a to and from JSON.
+ ///
+ public abstract class DateTimeConverterBase : JsonConverter
+ {
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ if (objectType == typeof(DateTime) || objectType == typeof(DateTime?))
+ {
+ return true;
+ }
+#if HAVE_DATE_TIME_OFFSET
+ if (objectType == typeof(DateTimeOffset) || objectType == typeof(DateTimeOffset?))
+ {
+ return true;
+ }
+#endif
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/DiscriminatedUnionConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/DiscriminatedUnionConverter.cs
new file mode 100644
index 0000000..184ecb5
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/DiscriminatedUnionConverter.cs
@@ -0,0 +1,298 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if HAVE_FSHARP_TYPES
+using LC.Newtonsoft.Json.Linq;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+#if !HAVE_LINQ
+using LC.Newtonsoft.Json.Utilities.LinqBridge;
+#else
+using System.Linq;
+#endif
+using System.Reflection;
+using LC.Newtonsoft.Json.Serialization;
+using System.Globalization;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts a F# discriminated union type to and from JSON.
+ ///
+ public class DiscriminatedUnionConverter : JsonConverter
+ {
+ #region UnionDefinition
+ internal class Union
+ {
+ public readonly FSharpFunction TagReader;
+ public readonly List Cases;
+
+ public Union(FSharpFunction tagReader, List cases)
+ {
+ TagReader = tagReader;
+ Cases = cases;
+ }
+ }
+
+ internal class UnionCase
+ {
+ public readonly int Tag;
+ public readonly string Name;
+ public readonly PropertyInfo[] Fields;
+ public readonly FSharpFunction FieldReader;
+ public readonly FSharpFunction Constructor;
+
+ public UnionCase(int tag, string name, PropertyInfo[] fields, FSharpFunction fieldReader, FSharpFunction constructor)
+ {
+ Tag = tag;
+ Name = name;
+ Fields = fields;
+ FieldReader = fieldReader;
+ Constructor = constructor;
+ }
+ }
+ #endregion
+
+ private const string CasePropertyName = "Case";
+ private const string FieldsPropertyName = "Fields";
+
+ private static readonly ThreadSafeStore UnionCache = new ThreadSafeStore(CreateUnion);
+ private static readonly ThreadSafeStore UnionTypeLookupCache = new ThreadSafeStore(CreateUnionTypeLookup);
+
+ private static Type CreateUnionTypeLookup(Type t)
+ {
+ // this lookup is because cases with fields are derived from union type
+ // need to get declaring type to avoid duplicate Unions in cache
+
+ // hacky but I can't find an API to get the declaring type without GetUnionCases
+ object[] cases = (object[])FSharpUtils.Instance.GetUnionCases(null, t, null)!;
+
+ object caseInfo = cases.First();
+
+ Type unionType = (Type)FSharpUtils.Instance.GetUnionCaseInfoDeclaringType(caseInfo)!;
+ return unionType;
+ }
+
+ private static Union CreateUnion(Type t)
+ {
+ Union u = new Union((FSharpFunction)FSharpUtils.Instance.PreComputeUnionTagReader(null, t, null), new List());
+
+ object[] cases = (object[])FSharpUtils.Instance.GetUnionCases(null, t, null)!;
+
+ foreach (object unionCaseInfo in cases)
+ {
+ UnionCase unionCase = new UnionCase(
+ (int)FSharpUtils.Instance.GetUnionCaseInfoTag(unionCaseInfo),
+ (string)FSharpUtils.Instance.GetUnionCaseInfoName(unionCaseInfo),
+ (PropertyInfo[])FSharpUtils.Instance.GetUnionCaseInfoFields(unionCaseInfo)!,
+ (FSharpFunction)FSharpUtils.Instance.PreComputeUnionReader(null, unionCaseInfo, null),
+ (FSharpFunction)FSharpUtils.Instance.PreComputeUnionConstructor(null, unionCaseInfo, null));
+
+ u.Cases.Add(unionCase);
+ }
+
+ return u;
+ }
+
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver;
+
+ Type unionType = UnionTypeLookupCache.Get(value.GetType());
+ Union union = UnionCache.Get(unionType);
+
+ int tag = (int)union.TagReader.Invoke(value);
+ UnionCase caseInfo = union.Cases.Single(c => c.Tag == tag);
+
+ writer.WriteStartObject();
+ writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(CasePropertyName) : CasePropertyName);
+ writer.WriteValue(caseInfo.Name);
+ if (caseInfo.Fields != null && caseInfo.Fields.Length > 0)
+ {
+ object[] fields = (object[])caseInfo.FieldReader.Invoke(value)!;
+
+ writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(FieldsPropertyName) : FieldsPropertyName);
+ writer.WriteStartArray();
+ foreach (object field in fields)
+ {
+ serializer.Serialize(writer, field);
+ }
+ writer.WriteEndArray();
+ }
+ writer.WriteEndObject();
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return null;
+ }
+
+ UnionCase? caseInfo = null;
+ string? caseName = null;
+ JArray? fields = null;
+
+ // start object
+ reader.ReadAndAssert();
+
+ while (reader.TokenType == JsonToken.PropertyName)
+ {
+ string propertyName = reader.Value!.ToString();
+ if (string.Equals(propertyName, CasePropertyName, StringComparison.OrdinalIgnoreCase))
+ {
+ reader.ReadAndAssert();
+
+ Union union = UnionCache.Get(objectType);
+
+ caseName = reader.Value!.ToString();
+
+ caseInfo = union.Cases.SingleOrDefault(c => c.Name == caseName);
+
+ if (caseInfo == null)
+ {
+ throw JsonSerializationException.Create(reader, "No union type found with the name '{0}'.".FormatWith(CultureInfo.InvariantCulture, caseName));
+ }
+ }
+ else if (string.Equals(propertyName, FieldsPropertyName, StringComparison.OrdinalIgnoreCase))
+ {
+ reader.ReadAndAssert();
+ if (reader.TokenType != JsonToken.StartArray)
+ {
+ throw JsonSerializationException.Create(reader, "Union fields must been an array.");
+ }
+
+ fields = (JArray)JToken.ReadFrom(reader);
+ }
+ else
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected property '{0}' found when reading union.".FormatWith(CultureInfo.InvariantCulture, propertyName));
+ }
+
+ reader.ReadAndAssert();
+ }
+
+ if (caseInfo == null)
+ {
+ throw JsonSerializationException.Create(reader, "No '{0}' property with union name found.".FormatWith(CultureInfo.InvariantCulture, CasePropertyName));
+ }
+
+ object?[] typedFieldValues = new object?[caseInfo.Fields.Length];
+
+ if (caseInfo.Fields.Length > 0 && fields == null)
+ {
+ throw JsonSerializationException.Create(reader, "No '{0}' property with union fields found.".FormatWith(CultureInfo.InvariantCulture, FieldsPropertyName));
+ }
+
+ if (fields != null)
+ {
+ if (caseInfo.Fields.Length != fields.Count)
+ {
+ throw JsonSerializationException.Create(reader, "The number of field values does not match the number of properties defined by union '{0}'.".FormatWith(CultureInfo.InvariantCulture, caseName));
+ }
+
+ for (int i = 0; i < fields.Count; i++)
+ {
+ JToken t = fields[i];
+ PropertyInfo fieldProperty = caseInfo.Fields[i];
+
+ typedFieldValues[i] = t.ToObject(fieldProperty.PropertyType, serializer);
+ }
+ }
+
+ object[] args = { typedFieldValues };
+
+ return caseInfo.Constructor.Invoke(args);
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ if (typeof(IEnumerable).IsAssignableFrom(objectType))
+ {
+ return false;
+ }
+
+ // all fsharp objects have CompilationMappingAttribute
+ // get the fsharp assembly from the attribute and initialize latebound methods
+ object[] attributes;
+#if HAVE_FULL_REFLECTION
+ attributes = objectType.GetCustomAttributes(true);
+#else
+ attributes = objectType.GetTypeInfo().GetCustomAttributes(true).ToArray();
+#endif
+
+ bool isFSharpType = false;
+ foreach (object attribute in attributes)
+ {
+ Type attributeType = attribute.GetType();
+ if (attributeType.FullName == "Microsoft.FSharp.Core.CompilationMappingAttribute")
+ {
+ FSharpUtils.EnsureInitialized(attributeType.Assembly());
+
+ isFSharpType = true;
+ break;
+ }
+ }
+
+ if (!isFSharpType)
+ {
+ return false;
+ }
+
+ return (bool)FSharpUtils.Instance.IsUnion(null, objectType, null);
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/EntityKeyMemberConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/EntityKeyMemberConverter.cs
new file mode 100644
index 0000000..f138b6e
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/EntityKeyMemberConverter.cs
@@ -0,0 +1,165 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if HAVE_ENTITY_FRAMEWORK
+using System;
+using LC.Newtonsoft.Json.Serialization;
+using System.Globalization;
+using LC.Newtonsoft.Json.Utilities;
+using System.Diagnostics;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts an Entity Framework to and from JSON.
+ ///
+ public class EntityKeyMemberConverter : JsonConverter
+ {
+ private const string EntityKeyMemberFullTypeName = "System.Data.EntityKeyMember";
+
+ private const string KeyPropertyName = "Key";
+ private const string TypePropertyName = "Type";
+ private const string ValuePropertyName = "Value";
+
+ private static ReflectionObject? _reflectionObject;
+
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ EnsureReflectionObject(value.GetType());
+ MiscellaneousUtils.Assert(_reflectionObject != null);
+
+ DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver;
+
+ string keyName = (string)_reflectionObject.GetValue(value, KeyPropertyName)!;
+ object? keyValue = _reflectionObject.GetValue(value, ValuePropertyName);
+
+ Type? keyValueType = keyValue?.GetType();
+
+ writer.WriteStartObject();
+ writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(KeyPropertyName) : KeyPropertyName);
+ writer.WriteValue(keyName);
+ writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(TypePropertyName) : TypePropertyName);
+ writer.WriteValue(keyValueType?.FullName);
+
+ writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(ValuePropertyName) : ValuePropertyName);
+
+ if (keyValueType != null)
+ {
+ if (JsonSerializerInternalWriter.TryConvertToString(keyValue!, keyValueType, out string? valueJson))
+ {
+ writer.WriteValue(valueJson);
+ }
+ else
+ {
+ writer.WriteValue(keyValue);
+ }
+ }
+ else
+ {
+ writer.WriteNull();
+ }
+
+ writer.WriteEndObject();
+ }
+
+ private static void ReadAndAssertProperty(JsonReader reader, string propertyName)
+ {
+ reader.ReadAndAssert();
+
+ if (reader.TokenType != JsonToken.PropertyName || !string.Equals(reader.Value?.ToString(), propertyName, StringComparison.OrdinalIgnoreCase))
+ {
+ throw new JsonSerializationException("Expected JSON property '{0}'.".FormatWith(CultureInfo.InvariantCulture, propertyName));
+ }
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ EnsureReflectionObject(objectType);
+ MiscellaneousUtils.Assert(_reflectionObject != null);
+
+ object entityKeyMember = _reflectionObject.Creator!();
+
+ ReadAndAssertProperty(reader, KeyPropertyName);
+ reader.ReadAndAssert();
+ _reflectionObject.SetValue(entityKeyMember, KeyPropertyName, reader.Value?.ToString());
+
+ ReadAndAssertProperty(reader, TypePropertyName);
+ reader.ReadAndAssert();
+ string? type = reader.Value?.ToString();
+
+ Type t = Type.GetType(type);
+
+ ReadAndAssertProperty(reader, ValuePropertyName);
+ reader.ReadAndAssert();
+ _reflectionObject.SetValue(entityKeyMember, ValuePropertyName, serializer.Deserialize(reader, t));
+
+ reader.ReadAndAssert();
+
+ return entityKeyMember;
+ }
+
+ private static void EnsureReflectionObject(Type objectType)
+ {
+ if (_reflectionObject == null)
+ {
+ _reflectionObject = ReflectionObject.Create(objectType, KeyPropertyName, ValuePropertyName);
+ }
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType.AssignableToTypeName(EntityKeyMemberFullTypeName, false);
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/ExpandoObjectConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/ExpandoObjectConverter.cs
new file mode 100644
index 0000000..8c8fef7
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/ExpandoObjectConverter.cs
@@ -0,0 +1,165 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if HAVE_DYNAMIC
+
+using System;
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts an to and from JSON.
+ ///
+ public class ExpandoObjectConverter : JsonConverter
+ {
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ // can write is set to false
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ return ReadValue(reader);
+ }
+
+ private object? ReadValue(JsonReader reader)
+ {
+ if (!reader.MoveToContent())
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject.");
+ }
+
+ switch (reader.TokenType)
+ {
+ case JsonToken.StartObject:
+ return ReadObject(reader);
+ case JsonToken.StartArray:
+ return ReadList(reader);
+ default:
+ if (JsonTokenUtils.IsPrimitiveToken(reader.TokenType))
+ {
+ return reader.Value;
+ }
+
+ throw JsonSerializationException.Create(reader, "Unexpected token when converting ExpandoObject: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
+ }
+ }
+
+ private object ReadList(JsonReader reader)
+ {
+ IList list = new List();
+
+ while (reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.Comment:
+ break;
+ default:
+ object? v = ReadValue(reader);
+
+ list.Add(v);
+ break;
+ case JsonToken.EndArray:
+ return list;
+ }
+ }
+
+ throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject.");
+ }
+
+ private object ReadObject(JsonReader reader)
+ {
+ IDictionary expandoObject = new ExpandoObject();
+
+ while (reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string propertyName = reader.Value!.ToString();
+
+ if (!reader.Read())
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject.");
+ }
+
+ object? v = ReadValue(reader);
+
+ expandoObject[propertyName] = v;
+ break;
+ case JsonToken.Comment:
+ break;
+ case JsonToken.EndObject:
+ return expandoObject;
+ }
+ }
+
+ throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject.");
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ return (objectType == typeof(ExpandoObject));
+ }
+
+ ///
+ /// Gets a value indicating whether this can write JSON.
+ ///
+ ///
+ /// true if this can write JSON; otherwise, false .
+ ///
+ public override bool CanWrite => false;
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/IsoDateTimeConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/IsoDateTimeConverter.cs
new file mode 100644
index 0000000..92d1a5e
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/IsoDateTimeConverter.cs
@@ -0,0 +1,194 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Globalization;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts a to and from the ISO 8601 date format (e.g. "2008-04-12T12:53Z" ).
+ ///
+ public class IsoDateTimeConverter : DateTimeConverterBase
+ {
+ private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";
+
+ private DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind;
+ private string? _dateTimeFormat;
+ private CultureInfo? _culture;
+
+ ///
+ /// Gets or sets the date time styles used when converting a date to and from JSON.
+ ///
+ /// The date time styles used when converting a date to and from JSON.
+ public DateTimeStyles DateTimeStyles
+ {
+ get => _dateTimeStyles;
+ set => _dateTimeStyles = value;
+ }
+
+ ///
+ /// Gets or sets the date time format used when converting a date to and from JSON.
+ ///
+ /// The date time format used when converting a date to and from JSON.
+ public string? DateTimeFormat
+ {
+ get => _dateTimeFormat ?? string.Empty;
+ set => _dateTimeFormat = (StringUtils.IsNullOrEmpty(value)) ? null : value;
+ }
+
+ ///
+ /// Gets or sets the culture used when converting a date to and from JSON.
+ ///
+ /// The culture used when converting a date to and from JSON.
+ public CultureInfo Culture
+ {
+ get => _culture ?? CultureInfo.CurrentCulture;
+ set => _culture = value;
+ }
+
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ string text;
+
+ if (value is DateTime dateTime)
+ {
+ if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal
+ || (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal)
+ {
+ dateTime = dateTime.ToUniversalTime();
+ }
+
+ text = dateTime.ToString(_dateTimeFormat ?? DefaultDateTimeFormat, Culture);
+ }
+#if HAVE_DATE_TIME_OFFSET
+ else if (value is DateTimeOffset dateTimeOffset)
+ {
+ if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal
+ || (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal)
+ {
+ dateTimeOffset = dateTimeOffset.ToUniversalTime();
+ }
+
+ text = dateTimeOffset.ToString(_dateTimeFormat ?? DefaultDateTimeFormat, Culture);
+ }
+#endif
+ else
+ {
+ throw new JsonSerializationException("Unexpected value when converting date. Expected DateTime or DateTimeOffset, got {0}.".FormatWith(CultureInfo.InvariantCulture, ReflectionUtils.GetObjectType(value)!));
+ }
+
+ writer.WriteValue(text);
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ bool nullable = ReflectionUtils.IsNullableType(objectType);
+ if (reader.TokenType == JsonToken.Null)
+ {
+ if (!nullable)
+ {
+ throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
+ }
+
+ return null;
+ }
+
+#if HAVE_DATE_TIME_OFFSET
+ Type t = (nullable)
+ ? Nullable.GetUnderlyingType(objectType)
+ : objectType;
+#endif
+
+ if (reader.TokenType == JsonToken.Date)
+ {
+#if HAVE_DATE_TIME_OFFSET
+ if (t == typeof(DateTimeOffset))
+ {
+ return (reader.Value is DateTimeOffset) ? reader.Value : new DateTimeOffset((DateTime)reader.Value!);
+ }
+
+ // converter is expected to return a DateTime
+ if (reader.Value is DateTimeOffset offset)
+ {
+ return offset.DateTime;
+ }
+#endif
+
+ return reader.Value;
+ }
+
+ if (reader.TokenType != JsonToken.String)
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected token parsing date. Expected String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
+ }
+
+ string? dateText = reader.Value?.ToString();
+
+ if (StringUtils.IsNullOrEmpty(dateText) && nullable)
+ {
+ return null;
+ }
+
+#if HAVE_DATE_TIME_OFFSET
+ if (t == typeof(DateTimeOffset))
+ {
+ if (!StringUtils.IsNullOrEmpty(_dateTimeFormat))
+ {
+ return DateTimeOffset.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles);
+ }
+ else
+ {
+ return DateTimeOffset.Parse(dateText, Culture, _dateTimeStyles);
+ }
+ }
+#endif
+
+ if (!StringUtils.IsNullOrEmpty(_dateTimeFormat))
+ {
+ return DateTime.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles);
+ }
+ else
+ {
+ return DateTime.Parse(dateText, Culture, _dateTimeStyles);
+ }
+ }
+ }
+}
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/JavaScriptDateTimeConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/JavaScriptDateTimeConverter.cs
new file mode 100644
index 0000000..0101751
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/JavaScriptDateTimeConverter.cs
@@ -0,0 +1,111 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Globalization;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts a to and from a JavaScript Date constructor (e.g. new Date(52231943) ).
+ ///
+ public class JavaScriptDateTimeConverter : DateTimeConverterBase
+ {
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ long ticks;
+
+ if (value is DateTime dateTime)
+ {
+ DateTime utcDateTime = dateTime.ToUniversalTime();
+ ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(utcDateTime);
+ }
+#if HAVE_DATE_TIME_OFFSET
+ else if (value is DateTimeOffset dateTimeOffset)
+ {
+ DateTimeOffset utcDateTimeOffset = dateTimeOffset.ToUniversalTime();
+ ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(utcDateTimeOffset.UtcDateTime);
+ }
+#endif
+ else
+ {
+ throw new JsonSerializationException("Expected date object value.");
+ }
+
+ writer.WriteStartConstructor("Date");
+ writer.WriteValue(ticks);
+ writer.WriteEndConstructor();
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing property value of the JSON that is being converted.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ if (!ReflectionUtils.IsNullable(objectType))
+ {
+ throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
+ }
+
+ return null;
+ }
+
+ if (reader.TokenType != JsonToken.StartConstructor || !string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal))
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected token or value when parsing date. Token: {0}, Value: {1}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType, reader.Value));
+ }
+
+ if (!JavaScriptUtils.TryGetDateFromConstructorJson(reader, out DateTime d, out string? errorMessage))
+ {
+ throw JsonSerializationException.Create(reader, errorMessage);
+ }
+
+#if HAVE_DATE_TIME_OFFSET
+ Type t = (ReflectionUtils.IsNullableType(objectType))
+ ? Nullable.GetUnderlyingType(objectType)
+ : objectType;
+ if (t == typeof(DateTimeOffset))
+ {
+ return new DateTimeOffset(d);
+ }
+#endif
+ return d;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/KeyValuePairConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/KeyValuePairConverter.cs
new file mode 100644
index 0000000..085af0c
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/KeyValuePairConverter.cs
@@ -0,0 +1,159 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using LC.Newtonsoft.Json.Serialization;
+using LC.Newtonsoft.Json.Utilities;
+using System.Reflection;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts a to and from JSON.
+ ///
+ public class KeyValuePairConverter : JsonConverter
+ {
+ private const string KeyName = "Key";
+ private const string ValueName = "Value";
+
+ private static readonly ThreadSafeStore ReflectionObjectPerType = new ThreadSafeStore(InitializeReflectionObject);
+
+ private static ReflectionObject InitializeReflectionObject(Type t)
+ {
+ IList genericArguments = t.GetGenericArguments();
+ Type keyType = genericArguments[0];
+ Type valueType = genericArguments[1];
+
+ return ReflectionObject.Create(t, t.GetConstructor(new[] { keyType, valueType }), KeyName, ValueName);
+ }
+
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ ReflectionObject reflectionObject = ReflectionObjectPerType.Get(value.GetType());
+
+ DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver;
+
+ writer.WriteStartObject();
+ writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(KeyName) : KeyName);
+ serializer.Serialize(writer, reflectionObject.GetValue(value, KeyName), reflectionObject.GetType(KeyName));
+ writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(ValueName) : ValueName);
+ serializer.Serialize(writer, reflectionObject.GetValue(value, ValueName), reflectionObject.GetType(ValueName));
+ writer.WriteEndObject();
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ if (!ReflectionUtils.IsNullableType(objectType))
+ {
+ throw JsonSerializationException.Create(reader, "Cannot convert null value to KeyValuePair.");
+ }
+
+ return null;
+ }
+
+ object? key = null;
+ object? value = null;
+
+ reader.ReadAndAssert();
+
+ Type t = ReflectionUtils.IsNullableType(objectType)
+ ? Nullable.GetUnderlyingType(objectType)
+ : objectType;
+
+ ReflectionObject reflectionObject = ReflectionObjectPerType.Get(t);
+ JsonContract keyContract = serializer.ContractResolver.ResolveContract(reflectionObject.GetType(KeyName));
+ JsonContract valueContract = serializer.ContractResolver.ResolveContract(reflectionObject.GetType(ValueName));
+
+ while (reader.TokenType == JsonToken.PropertyName)
+ {
+ string propertyName = reader.Value!.ToString();
+ if (string.Equals(propertyName, KeyName, StringComparison.OrdinalIgnoreCase))
+ {
+ reader.ReadForTypeAndAssert(keyContract, false);
+
+ key = serializer.Deserialize(reader, keyContract.UnderlyingType);
+ }
+ else if (string.Equals(propertyName, ValueName, StringComparison.OrdinalIgnoreCase))
+ {
+ reader.ReadForTypeAndAssert(valueContract, false);
+
+ value = serializer.Deserialize(reader, valueContract.UnderlyingType);
+ }
+ else
+ {
+ reader.Skip();
+ }
+
+ reader.ReadAndAssert();
+ }
+
+ return reflectionObject.Creator!(key, value);
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ Type t = (ReflectionUtils.IsNullableType(objectType))
+ ? Nullable.GetUnderlyingType(objectType)
+ : objectType;
+
+ if (t.IsValueType() && t.IsGenericType())
+ {
+ return (t.GetGenericTypeDefinition() == typeof(KeyValuePair<,>));
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/RegexConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/RegexConverter.cs
new file mode 100644
index 0000000..69ea8d8
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/RegexConverter.cs
@@ -0,0 +1,235 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Text.RegularExpressions;
+using LC.Newtonsoft.Json.Bson;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using LC.Newtonsoft.Json.Serialization;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts a to and from JSON and BSON.
+ ///
+ public class RegexConverter : JsonConverter
+ {
+ private const string PatternName = "Pattern";
+ private const string OptionsName = "Options";
+
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ Regex regex = (Regex)value;
+
+#pragma warning disable 618
+ if (writer is BsonWriter bsonWriter)
+ {
+ WriteBson(bsonWriter, regex);
+ }
+#pragma warning restore 618
+ else
+ {
+ WriteJson(writer, regex, serializer);
+ }
+ }
+
+ private bool HasFlag(RegexOptions options, RegexOptions flag)
+ {
+ return ((options & flag) == flag);
+ }
+
+#pragma warning disable 618
+ private void WriteBson(BsonWriter writer, Regex regex)
+ {
+ // Regular expression - The first cstring is the regex pattern, the second
+ // is the regex options string. Options are identified by characters, which
+ // must be stored in alphabetical order. Valid options are 'i' for case
+ // insensitive matching, 'm' for multiline matching, 'x' for verbose mode,
+ // 'l' to make \w, \W, etc. locale dependent, 's' for dotall mode
+ // ('.' matches everything), and 'u' to make \w, \W, etc. match unicode.
+
+ string? options = null;
+
+ if (HasFlag(regex.Options, RegexOptions.IgnoreCase))
+ {
+ options += "i";
+ }
+
+ if (HasFlag(regex.Options, RegexOptions.Multiline))
+ {
+ options += "m";
+ }
+
+ if (HasFlag(regex.Options, RegexOptions.Singleline))
+ {
+ options += "s";
+ }
+
+ options += "u";
+
+ if (HasFlag(regex.Options, RegexOptions.ExplicitCapture))
+ {
+ options += "x";
+ }
+
+ writer.WriteRegex(regex.ToString(), options);
+ }
+#pragma warning restore 618
+
+ private void WriteJson(JsonWriter writer, Regex regex, JsonSerializer serializer)
+ {
+ DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver;
+
+ writer.WriteStartObject();
+ writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(PatternName) : PatternName);
+ writer.WriteValue(regex.ToString());
+ writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(OptionsName) : OptionsName);
+ serializer.Serialize(writer, regex.Options);
+ writer.WriteEndObject();
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.StartObject:
+ return ReadRegexObject(reader, serializer);
+ case JsonToken.String:
+ return ReadRegexString(reader);
+ case JsonToken.Null:
+ return null;
+ }
+
+ throw JsonSerializationException.Create(reader, "Unexpected token when reading Regex.");
+ }
+
+ private object ReadRegexString(JsonReader reader)
+ {
+ string regexText = (string)reader.Value!;
+
+ if (regexText.Length > 0 && regexText[0] == '/')
+ {
+ int patternOptionDelimiterIndex = regexText.LastIndexOf('/');
+
+ if (patternOptionDelimiterIndex > 0)
+ {
+ string patternText = regexText.Substring(1, patternOptionDelimiterIndex - 1);
+ string optionsText = regexText.Substring(patternOptionDelimiterIndex + 1);
+
+ RegexOptions options = MiscellaneousUtils.GetRegexOptions(optionsText);
+
+ return new Regex(patternText, options);
+ }
+ }
+
+ throw JsonSerializationException.Create(reader, "Regex pattern must be enclosed by slashes.");
+ }
+
+ private Regex ReadRegexObject(JsonReader reader, JsonSerializer serializer)
+ {
+ string? pattern = null;
+ RegexOptions? options = null;
+
+ while (reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string propertyName = reader.Value!.ToString();
+
+ if (!reader.Read())
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected end when reading Regex.");
+ }
+
+ if (string.Equals(propertyName, PatternName, StringComparison.OrdinalIgnoreCase))
+ {
+ pattern = (string?)reader.Value;
+ }
+ else if (string.Equals(propertyName, OptionsName, StringComparison.OrdinalIgnoreCase))
+ {
+ options = serializer.Deserialize(reader);
+ }
+ else
+ {
+ reader.Skip();
+ }
+ break;
+ case JsonToken.Comment:
+ break;
+ case JsonToken.EndObject:
+ if (pattern == null)
+ {
+ throw JsonSerializationException.Create(reader, "Error deserializing Regex. No pattern found.");
+ }
+
+ return new Regex(pattern, options ?? RegexOptions.None);
+ }
+ }
+
+ throw JsonSerializationException.Create(reader, "Unexpected end when reading Regex.");
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType.Name == nameof(Regex) && IsRegex(objectType);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private bool IsRegex(Type objectType)
+ {
+ return (objectType == typeof(Regex));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/StringEnumConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/StringEnumConverter.cs
new file mode 100644
index 0000000..b0b93a0
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/StringEnumConverter.cs
@@ -0,0 +1,276 @@
+#region License
+
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+using System.Runtime.Serialization;
+using LC.Newtonsoft.Json.Utilities;
+using LC.Newtonsoft.Json.Serialization;
+#if !HAVE_LINQ
+using LC.Newtonsoft.Json.Utilities.LinqBridge;
+#else
+using System.Linq;
+
+#endif
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts an to and from its name string value.
+ ///
+ public class StringEnumConverter : JsonConverter
+ {
+ ///
+ /// Gets or sets a value indicating whether the written enum text should be camel case.
+ /// The default value is false .
+ ///
+ /// true if the written enum text will be camel case; otherwise, false .
+ [Obsolete("StringEnumConverter.CamelCaseText is obsolete. Set StringEnumConverter.NamingStrategy with CamelCaseNamingStrategy instead.")]
+ public bool CamelCaseText
+ {
+ get => NamingStrategy is CamelCaseNamingStrategy ? true : false;
+ set
+ {
+ if (value)
+ {
+ if (NamingStrategy is CamelCaseNamingStrategy)
+ {
+ return;
+ }
+
+ NamingStrategy = new CamelCaseNamingStrategy();
+ }
+ else
+ {
+ if (!(NamingStrategy is CamelCaseNamingStrategy))
+ {
+ return;
+ }
+
+ NamingStrategy = null;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the naming strategy used to resolve how enum text is written.
+ ///
+ /// The naming strategy used to resolve how enum text is written.
+ public NamingStrategy? NamingStrategy { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether integer values are allowed when serializing and deserializing.
+ /// The default value is true .
+ ///
+ /// true if integers are allowed when serializing and deserializing; otherwise, false .
+ public bool AllowIntegerValues { get; set; } = true;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public StringEnumConverter()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// true if the written enum text will be camel case; otherwise, false .
+ [Obsolete("StringEnumConverter(bool) is obsolete. Create a converter with StringEnumConverter(NamingStrategy, bool) instead.")]
+ public StringEnumConverter(bool camelCaseText)
+ {
+ if (camelCaseText)
+ {
+ NamingStrategy = new CamelCaseNamingStrategy();
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The naming strategy used to resolve how enum text is written.
+ /// true if integers are allowed when serializing and deserializing; otherwise, false .
+ public StringEnumConverter(NamingStrategy namingStrategy, bool allowIntegerValues = true)
+ {
+ NamingStrategy = namingStrategy;
+ AllowIntegerValues = allowIntegerValues;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The of the used to write enum text.
+ public StringEnumConverter(Type namingStrategyType)
+ {
+ ValidationUtils.ArgumentNotNull(namingStrategyType, nameof(namingStrategyType));
+
+ NamingStrategy = JsonTypeReflector.CreateNamingStrategyInstance(namingStrategyType, null);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The of the used to write enum text.
+ ///
+ /// The parameter list to use when constructing the described by .
+ /// If null , the default constructor is used.
+ /// When non-null , there must be a constructor defined in the that exactly matches the number,
+ /// order, and type of these parameters.
+ ///
+ public StringEnumConverter(Type namingStrategyType, object[] namingStrategyParameters)
+ {
+ ValidationUtils.ArgumentNotNull(namingStrategyType, nameof(namingStrategyType));
+
+ NamingStrategy = JsonTypeReflector.CreateNamingStrategyInstance(namingStrategyType, namingStrategyParameters);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The of the used to write enum text.
+ ///
+ /// The parameter list to use when constructing the described by .
+ /// If null , the default constructor is used.
+ /// When non-null , there must be a constructor defined in the that exactly matches the number,
+ /// order, and type of these parameters.
+ ///
+ /// true if integers are allowed when serializing and deserializing; otherwise, false .
+ public StringEnumConverter(Type namingStrategyType, object[] namingStrategyParameters, bool allowIntegerValues)
+ {
+ ValidationUtils.ArgumentNotNull(namingStrategyType, nameof(namingStrategyType));
+
+ NamingStrategy = JsonTypeReflector.CreateNamingStrategyInstance(namingStrategyType, namingStrategyParameters);
+ AllowIntegerValues = allowIntegerValues;
+ }
+
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ Enum e = (Enum)value;
+
+ if (!EnumUtils.TryToString(e.GetType(), value, NamingStrategy, out string? enumName))
+ {
+ if (!AllowIntegerValues)
+ {
+ throw JsonSerializationException.Create(null, writer.ContainerPath, "Integer value {0} is not allowed.".FormatWith(CultureInfo.InvariantCulture, e.ToString("D")), null);
+ }
+
+ // enum value has no name so write number
+ writer.WriteValue(value);
+ }
+ else
+ {
+ writer.WriteValue(enumName);
+ }
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ if (!ReflectionUtils.IsNullableType(objectType))
+ {
+ throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
+ }
+
+ return null;
+ }
+
+ bool isNullable = ReflectionUtils.IsNullableType(objectType);
+ Type t = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType;
+
+ try
+ {
+ if (reader.TokenType == JsonToken.String)
+ {
+ string? enumText = reader.Value?.ToString();
+
+ if (StringUtils.IsNullOrEmpty(enumText) && isNullable)
+ {
+ return null;
+ }
+
+ return EnumUtils.ParseEnum(t, NamingStrategy, enumText!, !AllowIntegerValues);
+ }
+
+ if (reader.TokenType == JsonToken.Integer)
+ {
+ if (!AllowIntegerValues)
+ {
+ throw JsonSerializationException.Create(reader, "Integer value {0} is not allowed.".FormatWith(CultureInfo.InvariantCulture, reader.Value));
+ }
+
+ return ConvertUtils.ConvertOrCast(reader.Value, CultureInfo.InvariantCulture, t);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw JsonSerializationException.Create(reader, "Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(reader.Value), objectType), ex);
+ }
+
+ // we don't actually expect to get here.
+ throw JsonSerializationException.Create(reader, "Unexpected token {0} when parsing enum.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ Type t = (ReflectionUtils.IsNullableType(objectType))
+ ? Nullable.GetUnderlyingType(objectType)
+ : objectType;
+
+ return t.IsEnum();
+ }
+ }
+}
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/UnixDateTimeConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/UnixDateTimeConverter.cs
new file mode 100644
index 0000000..d69d224
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/UnixDateTimeConverter.cs
@@ -0,0 +1,132 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Globalization;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts a to and from Unix epoch time
+ ///
+ public class UnixDateTimeConverter : DateTimeConverterBase
+ {
+ internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ long seconds;
+
+ if (value is DateTime dateTime)
+ {
+ seconds = (long)(dateTime.ToUniversalTime() - UnixEpoch).TotalSeconds;
+ }
+#if HAVE_DATE_TIME_OFFSET
+ else if (value is DateTimeOffset dateTimeOffset)
+ {
+ seconds = (long)(dateTimeOffset.ToUniversalTime() - UnixEpoch).TotalSeconds;
+ }
+#endif
+ else
+ {
+ throw new JsonSerializationException("Expected date object value.");
+ }
+
+ if (seconds < 0)
+ {
+ throw new JsonSerializationException("Cannot convert date value that is before Unix epoch of 00:00:00 UTC on 1 January 1970.");
+ }
+
+ writer.WriteValue(seconds);
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing property value of the JSON that is being converted.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ bool nullable = ReflectionUtils.IsNullable(objectType);
+ if (reader.TokenType == JsonToken.Null)
+ {
+ if (!nullable)
+ {
+ throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
+ }
+
+ return null;
+ }
+
+ long seconds;
+
+ if (reader.TokenType == JsonToken.Integer)
+ {
+ seconds = (long)reader.Value!;
+ }
+ else if (reader.TokenType == JsonToken.String)
+ {
+ if (!long.TryParse((string)reader.Value!, out seconds))
+ {
+ throw JsonSerializationException.Create(reader, "Cannot convert invalid value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
+ }
+ }
+ else
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected token parsing date. Expected Integer or String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
+ }
+
+ if (seconds >= 0)
+ {
+ DateTime d = UnixEpoch.AddSeconds(seconds);
+
+#if HAVE_DATE_TIME_OFFSET
+ Type t = (nullable)
+ ? Nullable.GetUnderlyingType(objectType)
+ : objectType;
+ if (t == typeof(DateTimeOffset))
+ {
+ return new DateTimeOffset(d, TimeSpan.Zero);
+ }
+#endif
+ return d;
+ }
+ else
+ {
+ throw JsonSerializationException.Create(reader, "Cannot convert value that is before Unix epoch of 00:00:00 UTC on 1 January 1970 to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/VersionConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/VersionConverter.cs
new file mode 100644
index 0000000..449d950
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/VersionConverter.cs
@@ -0,0 +1,106 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Globalization;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ ///
+ /// Converts a to and from a string (e.g. "1.2.3.4" ).
+ ///
+ public class VersionConverter : JsonConverter
+ {
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ }
+ else if (value is Version)
+ {
+ writer.WriteValue(value.ToString());
+ }
+ else
+ {
+ throw new JsonSerializationException("Expected Version object value");
+ }
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing property value of the JSON that is being converted.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return null;
+ }
+ else
+ {
+ if (reader.TokenType == JsonToken.String)
+ {
+ try
+ {
+ Version v = new Version((string)reader.Value!);
+ return v;
+ }
+ catch (Exception ex)
+ {
+ throw JsonSerializationException.Create(reader, "Error parsing version string: {0}".FormatWith(CultureInfo.InvariantCulture, reader.Value), ex);
+ }
+ }
+ else
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected token or value when parsing version. Token: {0}, Value: {1}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType, reader.Value));
+ }
+ }
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType == typeof(Version);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Converters/XmlNodeConverter.cs b/Libs/Newtonsoft.Json.AOT/Converters/XmlNodeConverter.cs
new file mode 100644
index 0000000..1d8d320
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Converters/XmlNodeConverter.cs
@@ -0,0 +1,2222 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if (HAVE_XML_DOCUMENT || HAVE_XLINQ)
+
+#if HAVE_BIG_INTEGER
+using System.Numerics;
+#endif
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Xml;
+using LC.Newtonsoft.Json.Serialization;
+#if HAVE_XLINQ
+using System.Xml.Linq;
+#endif
+using LC.Newtonsoft.Json.Utilities;
+using System.Runtime.CompilerServices;
+using System.Diagnostics.CodeAnalysis;
+
+namespace LC.Newtonsoft.Json.Converters
+{
+ #region XmlNodeWrappers
+#if HAVE_XML_DOCUMENT
+ internal class XmlDocumentWrapper : XmlNodeWrapper, IXmlDocument
+ {
+ private readonly XmlDocument _document;
+
+ public XmlDocumentWrapper(XmlDocument document)
+ : base(document)
+ {
+ _document = document;
+ }
+
+ public IXmlNode CreateComment(string? data)
+ {
+ return new XmlNodeWrapper(_document.CreateComment(data));
+ }
+
+ public IXmlNode CreateTextNode(string? text)
+ {
+ return new XmlNodeWrapper(_document.CreateTextNode(text));
+ }
+
+ public IXmlNode CreateCDataSection(string? data)
+ {
+ return new XmlNodeWrapper(_document.CreateCDataSection(data));
+ }
+
+ public IXmlNode CreateWhitespace(string? text)
+ {
+ return new XmlNodeWrapper(_document.CreateWhitespace(text));
+ }
+
+ public IXmlNode CreateSignificantWhitespace(string? text)
+ {
+ return new XmlNodeWrapper(_document.CreateSignificantWhitespace(text));
+ }
+
+ public IXmlNode CreateXmlDeclaration(string? version, string? encoding, string? standalone)
+ {
+ return new XmlDeclarationWrapper(_document.CreateXmlDeclaration(version, encoding, standalone));
+ }
+
+#if HAVE_XML_DOCUMENT_TYPE
+ public IXmlNode CreateXmlDocumentType(string? name, string? publicId, string? systemId, string? internalSubset)
+ {
+ return new XmlDocumentTypeWrapper(_document.CreateDocumentType(name, publicId, systemId, null));
+ }
+#endif
+
+ public IXmlNode CreateProcessingInstruction(string target, string? data)
+ {
+ return new XmlNodeWrapper(_document.CreateProcessingInstruction(target, data));
+ }
+
+ public IXmlElement CreateElement(string elementName)
+ {
+ return new XmlElementWrapper(_document.CreateElement(elementName));
+ }
+
+ public IXmlElement CreateElement(string qualifiedName, string namespaceUri)
+ {
+ return new XmlElementWrapper(_document.CreateElement(qualifiedName, namespaceUri));
+ }
+
+ public IXmlNode CreateAttribute(string name, string? value)
+ {
+ XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(name));
+ attribute.Value = value;
+
+ return attribute;
+ }
+
+ public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string? value)
+ {
+ XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(qualifiedName, namespaceUri));
+ attribute.Value = value;
+
+ return attribute;
+ }
+
+ public IXmlElement? DocumentElement
+ {
+ get
+ {
+ if (_document.DocumentElement == null)
+ {
+ return null;
+ }
+
+ return new XmlElementWrapper(_document.DocumentElement);
+ }
+ }
+ }
+
+ internal class XmlElementWrapper : XmlNodeWrapper, IXmlElement
+ {
+ private readonly XmlElement _element;
+
+ public XmlElementWrapper(XmlElement element)
+ : base(element)
+ {
+ _element = element;
+ }
+
+ public void SetAttributeNode(IXmlNode attribute)
+ {
+ XmlNodeWrapper xmlAttributeWrapper = (XmlNodeWrapper)attribute;
+
+ _element.SetAttributeNode((XmlAttribute)xmlAttributeWrapper.WrappedNode!);
+ }
+
+ public string GetPrefixOfNamespace(string namespaceUri)
+ {
+ return _element.GetPrefixOfNamespace(namespaceUri);
+ }
+
+ public bool IsEmpty => _element.IsEmpty;
+ }
+
+ internal class XmlDeclarationWrapper : XmlNodeWrapper, IXmlDeclaration
+ {
+ private readonly XmlDeclaration _declaration;
+
+ public XmlDeclarationWrapper(XmlDeclaration declaration)
+ : base(declaration)
+ {
+ _declaration = declaration;
+ }
+
+ public string Version => _declaration.Version;
+
+ public string Encoding
+ {
+ get => _declaration.Encoding;
+ set => _declaration.Encoding = value;
+ }
+
+ public string Standalone
+ {
+ get => _declaration.Standalone;
+ set => _declaration.Standalone = value;
+ }
+ }
+
+#if HAVE_XML_DOCUMENT_TYPE
+ internal class XmlDocumentTypeWrapper : XmlNodeWrapper, IXmlDocumentType
+ {
+ private readonly XmlDocumentType _documentType;
+
+ public XmlDocumentTypeWrapper(XmlDocumentType documentType)
+ : base(documentType)
+ {
+ _documentType = documentType;
+ }
+
+ public string Name => _documentType.Name;
+
+ public string System => _documentType.SystemId;
+
+ public string Public => _documentType.PublicId;
+
+ public string InternalSubset => _documentType.InternalSubset;
+
+ public override string? LocalName => "DOCTYPE";
+ }
+#endif
+
+ internal class XmlNodeWrapper : IXmlNode
+ {
+ private readonly XmlNode _node;
+ private List? _childNodes;
+ private List? _attributes;
+
+ public XmlNodeWrapper(XmlNode node)
+ {
+ _node = node;
+ }
+
+ public object? WrappedNode => _node;
+
+ public XmlNodeType NodeType => _node.NodeType;
+
+ public virtual string? LocalName => _node.LocalName;
+
+ public List ChildNodes
+ {
+ get
+ {
+ // childnodes is read multiple times
+ // cache results to prevent multiple reads which kills perf in large documents
+ if (_childNodes == null)
+ {
+ if (!_node.HasChildNodes)
+ {
+ _childNodes = XmlNodeConverter.EmptyChildNodes;
+ }
+ else
+ {
+ _childNodes = new List(_node.ChildNodes.Count);
+ foreach (XmlNode childNode in _node.ChildNodes)
+ {
+ _childNodes.Add(WrapNode(childNode));
+ }
+ }
+ }
+
+ return _childNodes;
+ }
+ }
+
+ protected virtual bool HasChildNodes => _node.HasChildNodes;
+
+ internal static IXmlNode WrapNode(XmlNode node)
+ {
+ switch (node.NodeType)
+ {
+ case XmlNodeType.Element:
+ return new XmlElementWrapper((XmlElement)node);
+ case XmlNodeType.XmlDeclaration:
+ return new XmlDeclarationWrapper((XmlDeclaration)node);
+#if HAVE_XML_DOCUMENT_TYPE
+ case XmlNodeType.DocumentType:
+ return new XmlDocumentTypeWrapper((XmlDocumentType)node);
+#endif
+ default:
+ return new XmlNodeWrapper(node);
+ }
+ }
+
+ public List Attributes
+ {
+ get
+ {
+ // attributes is read multiple times
+ // cache results to prevent multiple reads which kills perf in large documents
+ if (_attributes == null)
+ {
+ if (!HasAttributes)
+ {
+ _attributes = XmlNodeConverter.EmptyChildNodes;
+ }
+ else
+ {
+ _attributes = new List(_node.Attributes.Count);
+ foreach (XmlAttribute attribute in _node.Attributes)
+ {
+ _attributes.Add(WrapNode(attribute));
+ }
+ }
+ }
+
+ return _attributes;
+ }
+ }
+
+ private bool HasAttributes
+ {
+ get
+ {
+ if (_node is XmlElement element)
+ {
+ return element.HasAttributes;
+ }
+
+ return _node.Attributes?.Count > 0;
+ }
+ }
+
+ public IXmlNode? ParentNode
+ {
+ get
+ {
+ XmlNode node = _node is XmlAttribute attribute ? attribute.OwnerElement : _node.ParentNode;
+
+ if (node == null)
+ {
+ return null;
+ }
+
+ return WrapNode(node);
+ }
+ }
+
+ public string? Value
+ {
+ get => _node.Value;
+ set => _node.Value = value;
+ }
+
+ public IXmlNode AppendChild(IXmlNode newChild)
+ {
+ XmlNodeWrapper xmlNodeWrapper = (XmlNodeWrapper)newChild;
+ _node.AppendChild(xmlNodeWrapper._node);
+ _childNodes = null;
+ _attributes = null;
+
+ return newChild;
+ }
+
+ public string? NamespaceUri => _node.NamespaceURI;
+ }
+#endif
+#endregion
+
+#region Interfaces
+ internal interface IXmlDocument : IXmlNode
+ {
+ IXmlNode CreateComment(string? text);
+ IXmlNode CreateTextNode(string? text);
+ IXmlNode CreateCDataSection(string? data);
+ IXmlNode CreateWhitespace(string? text);
+ IXmlNode CreateSignificantWhitespace(string? text);
+ IXmlNode CreateXmlDeclaration(string? version, string? encoding, string? standalone);
+#if HAVE_XML_DOCUMENT_TYPE
+ IXmlNode CreateXmlDocumentType(string? name, string? publicId, string? systemId, string? internalSubset);
+#endif
+ IXmlNode CreateProcessingInstruction(string target, string? data);
+ IXmlElement CreateElement(string elementName);
+ IXmlElement CreateElement(string qualifiedName, string namespaceUri);
+ IXmlNode CreateAttribute(string name, string? value);
+ IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string? value);
+
+ IXmlElement? DocumentElement { get; }
+ }
+
+ internal interface IXmlDeclaration : IXmlNode
+ {
+ string Version { get; }
+ string Encoding { get; set; }
+ string Standalone { get; set; }
+ }
+
+ internal interface IXmlDocumentType : IXmlNode
+ {
+ string Name { get; }
+ string System { get; }
+ string Public { get; }
+ string InternalSubset { get; }
+ }
+
+ internal interface IXmlElement : IXmlNode
+ {
+ void SetAttributeNode(IXmlNode attribute);
+ string GetPrefixOfNamespace(string namespaceUri);
+ bool IsEmpty { get; }
+ }
+
+ internal interface IXmlNode
+ {
+ XmlNodeType NodeType { get; }
+ string? LocalName { get; }
+ List ChildNodes { get; }
+ List Attributes { get; }
+ IXmlNode? ParentNode { get; }
+ string? Value { get; set; }
+ IXmlNode AppendChild(IXmlNode newChild);
+ string? NamespaceUri { get; }
+ object? WrappedNode { get; }
+ }
+#endregion
+
+#region XNodeWrappers
+#if HAVE_XLINQ
+ internal class XDeclarationWrapper : XObjectWrapper, IXmlDeclaration
+ {
+ internal XDeclaration Declaration { get; }
+
+ public XDeclarationWrapper(XDeclaration declaration)
+ : base(null)
+ {
+ Declaration = declaration;
+ }
+
+ public override XmlNodeType NodeType => XmlNodeType.XmlDeclaration;
+
+ public string Version => Declaration.Version;
+
+ public string Encoding
+ {
+ get => Declaration.Encoding;
+ set => Declaration.Encoding = value;
+ }
+
+ public string Standalone
+ {
+ get => Declaration.Standalone;
+ set => Declaration.Standalone = value;
+ }
+ }
+
+ internal class XDocumentTypeWrapper : XObjectWrapper, IXmlDocumentType
+ {
+ private readonly XDocumentType _documentType;
+
+ public XDocumentTypeWrapper(XDocumentType documentType)
+ : base(documentType)
+ {
+ _documentType = documentType;
+ }
+
+ public string Name => _documentType.Name;
+
+ public string System => _documentType.SystemId;
+
+ public string Public => _documentType.PublicId;
+
+ public string InternalSubset => _documentType.InternalSubset;
+
+ public override string? LocalName => "DOCTYPE";
+ }
+
+ internal class XDocumentWrapper : XContainerWrapper, IXmlDocument
+ {
+ private XDocument Document => (XDocument)WrappedNode!;
+
+ public XDocumentWrapper(XDocument document)
+ : base(document)
+ {
+ }
+
+ public override List ChildNodes
+ {
+ get
+ {
+ List childNodes = base.ChildNodes;
+ if (Document.Declaration != null && (childNodes.Count == 0 || childNodes[0].NodeType != XmlNodeType.XmlDeclaration))
+ {
+ childNodes.Insert(0, new XDeclarationWrapper(Document.Declaration));
+ }
+
+ return childNodes;
+ }
+ }
+
+ protected override bool HasChildNodes
+ {
+ get
+ {
+ if (base.HasChildNodes)
+ {
+ return true;
+ }
+
+ return Document.Declaration != null;
+ }
+ }
+
+ public IXmlNode CreateComment(string? text)
+ {
+ return new XObjectWrapper(new XComment(text));
+ }
+
+ public IXmlNode CreateTextNode(string? text)
+ {
+ return new XObjectWrapper(new XText(text));
+ }
+
+ public IXmlNode CreateCDataSection(string? data)
+ {
+ return new XObjectWrapper(new XCData(data));
+ }
+
+ public IXmlNode CreateWhitespace(string? text)
+ {
+ return new XObjectWrapper(new XText(text));
+ }
+
+ public IXmlNode CreateSignificantWhitespace(string? text)
+ {
+ return new XObjectWrapper(new XText(text));
+ }
+
+ public IXmlNode CreateXmlDeclaration(string? version, string? encoding, string? standalone)
+ {
+ return new XDeclarationWrapper(new XDeclaration(version, encoding, standalone));
+ }
+
+ public IXmlNode CreateXmlDocumentType(string? name, string? publicId, string? systemId, string? internalSubset)
+ {
+ return new XDocumentTypeWrapper(new XDocumentType(name, publicId, systemId, internalSubset));
+ }
+
+ public IXmlNode CreateProcessingInstruction(string target, string? data)
+ {
+ return new XProcessingInstructionWrapper(new XProcessingInstruction(target, data));
+ }
+
+ public IXmlElement CreateElement(string elementName)
+ {
+ return new XElementWrapper(new XElement(elementName));
+ }
+
+ public IXmlElement CreateElement(string qualifiedName, string namespaceUri)
+ {
+ string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
+ return new XElementWrapper(new XElement(XName.Get(localName, namespaceUri)));
+ }
+
+ public IXmlNode CreateAttribute(string name, string? value)
+ {
+ return new XAttributeWrapper(new XAttribute(name, value));
+ }
+
+ public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string? value)
+ {
+ string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
+ return new XAttributeWrapper(new XAttribute(XName.Get(localName, namespaceUri), value));
+ }
+
+ public IXmlElement? DocumentElement
+ {
+ get
+ {
+ if (Document.Root == null)
+ {
+ return null;
+ }
+
+ return new XElementWrapper(Document.Root);
+ }
+ }
+
+ public override IXmlNode AppendChild(IXmlNode newChild)
+ {
+ if (newChild is XDeclarationWrapper declarationWrapper)
+ {
+ Document.Declaration = declarationWrapper.Declaration;
+ return declarationWrapper;
+ }
+ else
+ {
+ return base.AppendChild(newChild);
+ }
+ }
+ }
+
+ internal class XTextWrapper : XObjectWrapper
+ {
+ private XText Text => (XText)WrappedNode!;
+
+ public XTextWrapper(XText text)
+ : base(text)
+ {
+ }
+
+ public override string? Value
+ {
+ get => Text.Value;
+ set => Text.Value = value;
+ }
+
+ public override IXmlNode? ParentNode
+ {
+ get
+ {
+ if (Text.Parent == null)
+ {
+ return null;
+ }
+
+ return XContainerWrapper.WrapNode(Text.Parent);
+ }
+ }
+ }
+
+ internal class XCommentWrapper : XObjectWrapper
+ {
+ private XComment Text => (XComment)WrappedNode!;
+
+ public XCommentWrapper(XComment text)
+ : base(text)
+ {
+ }
+
+ public override string? Value
+ {
+ get => Text.Value;
+ set => Text.Value = value;
+ }
+
+ public override IXmlNode? ParentNode
+ {
+ get
+ {
+ if (Text.Parent == null)
+ {
+ return null;
+ }
+
+ return XContainerWrapper.WrapNode(Text.Parent);
+ }
+ }
+ }
+
+ internal class XProcessingInstructionWrapper : XObjectWrapper
+ {
+ private XProcessingInstruction ProcessingInstruction => (XProcessingInstruction)WrappedNode!;
+
+ public XProcessingInstructionWrapper(XProcessingInstruction processingInstruction)
+ : base(processingInstruction)
+ {
+ }
+
+ public override string? LocalName => ProcessingInstruction.Target;
+
+ public override string? Value
+ {
+ get => ProcessingInstruction.Data;
+ set => ProcessingInstruction.Data = value;
+ }
+ }
+
+ internal class XContainerWrapper : XObjectWrapper
+ {
+ private List? _childNodes;
+
+ private XContainer Container => (XContainer)WrappedNode!;
+
+ public XContainerWrapper(XContainer container)
+ : base(container)
+ {
+ }
+
+ public override List ChildNodes
+ {
+ get
+ {
+ // childnodes is read multiple times
+ // cache results to prevent multiple reads which kills perf in large documents
+ if (_childNodes == null)
+ {
+ if (!HasChildNodes)
+ {
+ _childNodes = XmlNodeConverter.EmptyChildNodes;
+ }
+ else
+ {
+ _childNodes = new List();
+ foreach (XNode node in Container.Nodes())
+ {
+ _childNodes.Add(WrapNode(node));
+ }
+ }
+ }
+
+ return _childNodes;
+ }
+ }
+
+ protected virtual bool HasChildNodes => Container.LastNode != null;
+
+ public override IXmlNode? ParentNode
+ {
+ get
+ {
+ if (Container.Parent == null)
+ {
+ return null;
+ }
+
+ return WrapNode(Container.Parent);
+ }
+ }
+
+ internal static IXmlNode WrapNode(XObject node)
+ {
+ if (node is XDocument document)
+ {
+ return new XDocumentWrapper(document);
+ }
+
+ if (node is XElement element)
+ {
+ return new XElementWrapper(element);
+ }
+
+ if (node is XContainer container)
+ {
+ return new XContainerWrapper(container);
+ }
+
+ if (node is XProcessingInstruction pi)
+ {
+ return new XProcessingInstructionWrapper(pi);
+ }
+
+ if (node is XText text)
+ {
+ return new XTextWrapper(text);
+ }
+
+ if (node is XComment comment)
+ {
+ return new XCommentWrapper(comment);
+ }
+
+ if (node is XAttribute attribute)
+ {
+ return new XAttributeWrapper(attribute);
+ }
+
+ if (node is XDocumentType type)
+ {
+ return new XDocumentTypeWrapper(type);
+ }
+
+ return new XObjectWrapper(node);
+ }
+
+ public override IXmlNode AppendChild(IXmlNode newChild)
+ {
+ Container.Add(newChild.WrappedNode);
+ _childNodes = null;
+
+ return newChild;
+ }
+ }
+
+ internal class XObjectWrapper : IXmlNode
+ {
+ private readonly XObject? _xmlObject;
+
+ public XObjectWrapper(XObject? xmlObject)
+ {
+ _xmlObject = xmlObject;
+ }
+
+ public object? WrappedNode => _xmlObject;
+
+ public virtual XmlNodeType NodeType => _xmlObject?.NodeType ?? XmlNodeType.None;
+
+ public virtual string? LocalName => null;
+
+ public virtual List ChildNodes => XmlNodeConverter.EmptyChildNodes;
+
+ public virtual List Attributes => XmlNodeConverter.EmptyChildNodes;
+
+ public virtual IXmlNode? ParentNode => null;
+
+ public virtual string? Value
+ {
+ get => null;
+ set => throw new InvalidOperationException();
+ }
+
+ public virtual IXmlNode AppendChild(IXmlNode newChild)
+ {
+ throw new InvalidOperationException();
+ }
+
+ public virtual string? NamespaceUri => null;
+ }
+
+ internal class XAttributeWrapper : XObjectWrapper
+ {
+ private XAttribute Attribute => (XAttribute)WrappedNode!;
+
+ public XAttributeWrapper(XAttribute attribute)
+ : base(attribute)
+ {
+ }
+
+ public override string? Value
+ {
+ get => Attribute.Value;
+ set => Attribute.Value = value;
+ }
+
+ public override string? LocalName => Attribute.Name.LocalName;
+
+ public override string? NamespaceUri => Attribute.Name.NamespaceName;
+
+ public override IXmlNode? ParentNode
+ {
+ get
+ {
+ if (Attribute.Parent == null)
+ {
+ return null;
+ }
+
+ return XContainerWrapper.WrapNode(Attribute.Parent);
+ }
+ }
+ }
+
+ internal class XElementWrapper : XContainerWrapper, IXmlElement
+ {
+ private List? _attributes;
+
+ private XElement Element => (XElement)WrappedNode!;
+
+ public XElementWrapper(XElement element)
+ : base(element)
+ {
+ }
+
+ public void SetAttributeNode(IXmlNode attribute)
+ {
+ XObjectWrapper wrapper = (XObjectWrapper)attribute;
+ Element.Add(wrapper.WrappedNode);
+ _attributes = null;
+ }
+
+ public override List Attributes
+ {
+ get
+ {
+ // attributes is read multiple times
+ // cache results to prevent multiple reads which kills perf in large documents
+ if (_attributes == null)
+ {
+ if (!Element.HasAttributes && !HasImplicitNamespaceAttribute(NamespaceUri!))
+ {
+ _attributes = XmlNodeConverter.EmptyChildNodes;
+ }
+ else
+ {
+ _attributes = new List();
+ foreach (XAttribute attribute in Element.Attributes())
+ {
+ _attributes.Add(new XAttributeWrapper(attribute));
+ }
+
+ // ensure elements created with a namespace but no namespace attribute are converted correctly
+ // e.g. new XElement("{http://example.com}MyElement");
+ string namespaceUri = NamespaceUri!;
+ if (HasImplicitNamespaceAttribute(namespaceUri))
+ {
+ _attributes.Insert(0, new XAttributeWrapper(new XAttribute("xmlns", namespaceUri)));
+ }
+ }
+ }
+
+ return _attributes;
+ }
+ }
+
+ private bool HasImplicitNamespaceAttribute(string namespaceUri)
+ {
+ if (!StringUtils.IsNullOrEmpty(namespaceUri) && namespaceUri != ParentNode?.NamespaceUri)
+ {
+ if (StringUtils.IsNullOrEmpty(GetPrefixOfNamespace(namespaceUri)))
+ {
+ bool namespaceDeclared = false;
+
+ if (Element.HasAttributes)
+ {
+ foreach (XAttribute attribute in Element.Attributes())
+ {
+ if (attribute.Name.LocalName == "xmlns" && StringUtils.IsNullOrEmpty(attribute.Name.NamespaceName) && attribute.Value == namespaceUri)
+ {
+ namespaceDeclared = true;
+ }
+ }
+ }
+
+ if (!namespaceDeclared)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public override IXmlNode AppendChild(IXmlNode newChild)
+ {
+ IXmlNode result = base.AppendChild(newChild);
+ _attributes = null;
+ return result;
+ }
+
+ public override string? Value
+ {
+ get => Element.Value;
+ set => Element.Value = value;
+ }
+
+ public override string? LocalName => Element.Name.LocalName;
+
+ public override string? NamespaceUri => Element.Name.NamespaceName;
+
+ public string GetPrefixOfNamespace(string namespaceUri)
+ {
+ return Element.GetPrefixOfNamespace(namespaceUri);
+ }
+
+ public bool IsEmpty => Element.IsEmpty;
+ }
+#endif
+#endregion
+
+ ///
+ /// Converts XML to and from JSON.
+ ///
+ public class XmlNodeConverter : JsonConverter
+ {
+ internal static readonly List EmptyChildNodes = new List();
+
+ private const string TextName = "#text";
+ private const string CommentName = "#comment";
+ private const string CDataName = "#cdata-section";
+ private const string WhitespaceName = "#whitespace";
+ private const string SignificantWhitespaceName = "#significant-whitespace";
+ private const string DeclarationName = "?xml";
+ private const string JsonNamespaceUri = "http://james.newtonking.com/projects/json";
+
+ ///
+ /// Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produced multiple root elements.
+ ///
+ /// The name of the deserialized root element.
+ public string? DeserializeRootElementName { get; set; }
+
+ ///
+ /// Gets or sets a value to indicate whether to write the Json.NET array attribute.
+ /// This attribute helps preserve arrays when converting the written XML back to JSON.
+ ///
+ /// true if the array attribute is written to the XML; otherwise, false .
+ public bool WriteArrayAttribute { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to write the root JSON object.
+ ///
+ /// true if the JSON root object is omitted; otherwise, false .
+ public bool OmitRootObject { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to encode special characters when converting JSON to XML.
+ /// If true , special characters like ':', '@', '?', '#' and '$' in JSON property names aren't used to specify
+ /// XML namespaces, attributes or processing directives. Instead special characters are encoded and written
+ /// as part of the XML element name.
+ ///
+ /// true if special characters are encoded; otherwise, false .
+ public bool EncodeSpecialCharacters { get; set; }
+
+ #region Writing
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The calling serializer.
+ /// The value.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ IXmlNode node = WrapXml(value);
+
+ XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
+ PushParentNamespaces(node, manager);
+
+ if (!OmitRootObject)
+ {
+ writer.WriteStartObject();
+ }
+
+ SerializeNode(writer, node, manager, !OmitRootObject);
+
+ if (!OmitRootObject)
+ {
+ writer.WriteEndObject();
+ }
+ }
+
+ private IXmlNode WrapXml(object value)
+ {
+#if HAVE_XLINQ
+ if (value is XObject xObject)
+ {
+ return XContainerWrapper.WrapNode(xObject);
+ }
+#endif
+#if HAVE_XML_DOCUMENT
+ if (value is XmlNode node)
+ {
+ return XmlNodeWrapper.WrapNode(node);
+ }
+#endif
+
+ throw new ArgumentException("Value must be an XML object.", nameof(value));
+ }
+
+ private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager)
+ {
+ List? parentElements = null;
+
+ IXmlNode? parent = node;
+ while ((parent = parent.ParentNode) != null)
+ {
+ if (parent.NodeType == XmlNodeType.Element)
+ {
+ if (parentElements == null)
+ {
+ parentElements = new List();
+ }
+
+ parentElements.Add(parent);
+ }
+ }
+
+ if (parentElements != null)
+ {
+ parentElements.Reverse();
+
+ foreach (IXmlNode parentElement in parentElements)
+ {
+ manager.PushScope();
+ foreach (IXmlNode attribute in parentElement.Attributes)
+ {
+ if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns")
+ {
+ manager.AddNamespace(attribute.LocalName, attribute.Value);
+ }
+ }
+ }
+ }
+ }
+
+ private string ResolveFullName(IXmlNode node, XmlNamespaceManager manager)
+ {
+ string? prefix = (node.NamespaceUri == null || (node.LocalName == "xmlns" && node.NamespaceUri == "http://www.w3.org/2000/xmlns/"))
+ ? null
+ : manager.LookupPrefix(node.NamespaceUri);
+
+ if (!StringUtils.IsNullOrEmpty(prefix))
+ {
+ return prefix + ":" + XmlConvert.DecodeName(node.LocalName);
+ }
+ else
+ {
+ return XmlConvert.DecodeName(node.LocalName);
+ }
+ }
+
+ private string GetPropertyName(IXmlNode node, XmlNamespaceManager manager)
+ {
+ switch (node.NodeType)
+ {
+ case XmlNodeType.Attribute:
+ if (node.NamespaceUri == JsonNamespaceUri)
+ {
+ return "$" + node.LocalName;
+ }
+ else
+ {
+ return "@" + ResolveFullName(node, manager);
+ }
+ case XmlNodeType.CDATA:
+ return CDataName;
+ case XmlNodeType.Comment:
+ return CommentName;
+ case XmlNodeType.Element:
+ if (node.NamespaceUri == JsonNamespaceUri)
+ {
+ return "$" + node.LocalName;
+ }
+ else
+ {
+ return ResolveFullName(node, manager);
+ }
+ case XmlNodeType.ProcessingInstruction:
+ return "?" + ResolveFullName(node, manager);
+ case XmlNodeType.DocumentType:
+ return "!" + ResolveFullName(node, manager);
+ case XmlNodeType.XmlDeclaration:
+ return DeclarationName;
+ case XmlNodeType.SignificantWhitespace:
+ return SignificantWhitespaceName;
+ case XmlNodeType.Text:
+ return TextName;
+ case XmlNodeType.Whitespace:
+ return WhitespaceName;
+ default:
+ throw new JsonSerializationException("Unexpected XmlNodeType when getting node name: " + node.NodeType);
+ }
+ }
+
+ private bool IsArray(IXmlNode node)
+ {
+ foreach (IXmlNode attribute in node.Attributes)
+ {
+ if (attribute.LocalName == "Array" && attribute.NamespaceUri == JsonNamespaceUri)
+ {
+ return XmlConvert.ToBoolean(attribute.Value);
+ }
+ }
+
+ return false;
+ }
+
+ private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
+ {
+ switch (node.ChildNodes.Count)
+ {
+ case 0:
+ {
+ // nothing to serialize
+ break;
+ }
+ case 1:
+ {
+ // avoid grouping when there is only one node
+ string nodeName = GetPropertyName(node.ChildNodes[0], manager);
+ WriteGroupedNodes(writer, manager, writePropertyName, node.ChildNodes, nodeName);
+ break;
+ }
+ default:
+ {
+ // check whether nodes have the same name
+ // if they don't then group into dictionary together by name
+
+ // value of dictionary will be a single IXmlNode when there is one for a name,
+ // or a List when there are multiple
+ Dictionary? nodesGroupedByName = null;
+
+ string? nodeName = null;
+
+ for (int i = 0; i < node.ChildNodes.Count; i++)
+ {
+ IXmlNode childNode = node.ChildNodes[i];
+ string currentNodeName = GetPropertyName(childNode, manager);
+
+ if (nodesGroupedByName == null)
+ {
+ if (nodeName == null)
+ {
+ nodeName = currentNodeName;
+ }
+ else if (currentNodeName == nodeName)
+ {
+ // current node name matches others
+ }
+ else
+ {
+ nodesGroupedByName = new Dictionary();
+ if (i > 1)
+ {
+ List nodes = new List(i);
+ for (int j = 0; j < i; j++)
+ {
+ nodes.Add(node.ChildNodes[j]);
+ }
+ nodesGroupedByName.Add(nodeName, nodes);
+ }
+ else
+ {
+ nodesGroupedByName.Add(nodeName, node.ChildNodes[0]);
+ }
+ nodesGroupedByName.Add(currentNodeName, childNode);
+ }
+ }
+ else
+ {
+ if (!nodesGroupedByName.TryGetValue(currentNodeName, out object value))
+ {
+ nodesGroupedByName.Add(currentNodeName, childNode);
+ }
+ else
+ {
+ if (!(value is List nodes))
+ {
+ nodes = new List {(IXmlNode)value!};
+ nodesGroupedByName[currentNodeName] = nodes;
+ }
+
+ nodes.Add(childNode);
+ }
+ }
+ }
+
+ if (nodesGroupedByName == null)
+ {
+ WriteGroupedNodes(writer, manager, writePropertyName, node.ChildNodes, nodeName!);
+ }
+ else
+ {
+ // loop through grouped nodes. write single name instances as normal,
+ // write multiple names together in an array
+ foreach (KeyValuePair nodeNameGroup in nodesGroupedByName)
+ {
+ if (nodeNameGroup.Value is List nodes)
+ {
+ WriteGroupedNodes(writer, manager, writePropertyName, nodes, nodeNameGroup.Key);
+ }
+ else
+ {
+ WriteGroupedNodes(writer, manager, writePropertyName, (IXmlNode)nodeNameGroup.Value, nodeNameGroup.Key);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ private void WriteGroupedNodes(JsonWriter writer, XmlNamespaceManager manager, bool writePropertyName, List groupedNodes, string elementNames)
+ {
+ bool writeArray = groupedNodes.Count != 1 || IsArray(groupedNodes[0]);
+
+ if (!writeArray)
+ {
+ SerializeNode(writer, groupedNodes[0], manager, writePropertyName);
+ }
+ else
+ {
+ if (writePropertyName)
+ {
+ writer.WritePropertyName(elementNames);
+ }
+
+ writer.WriteStartArray();
+
+ for (int i = 0; i < groupedNodes.Count; i++)
+ {
+ SerializeNode(writer, groupedNodes[i], manager, false);
+ }
+
+ writer.WriteEndArray();
+ }
+ }
+
+ private void WriteGroupedNodes(JsonWriter writer, XmlNamespaceManager manager, bool writePropertyName, IXmlNode node, string elementNames)
+ {
+ bool writeArray = IsArray(node);
+
+ if (!writeArray)
+ {
+ SerializeNode(writer, node, manager, writePropertyName);
+ }
+ else
+ {
+ if (writePropertyName)
+ {
+ writer.WritePropertyName(elementNames);
+ }
+
+ writer.WriteStartArray();
+
+ SerializeNode(writer, node, manager, false);
+
+ writer.WriteEndArray();
+ }
+ }
+
+ private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
+ {
+ switch (node.NodeType)
+ {
+ case XmlNodeType.Document:
+ case XmlNodeType.DocumentFragment:
+ SerializeGroupedNodes(writer, node, manager, writePropertyName);
+ break;
+ case XmlNodeType.Element:
+ if (IsArray(node) && AllSameName(node) && node.ChildNodes.Count > 0)
+ {
+ SerializeGroupedNodes(writer, node, manager, false);
+ }
+ else
+ {
+ manager.PushScope();
+
+ foreach (IXmlNode attribute in node.Attributes)
+ {
+ if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/")
+ {
+ string namespacePrefix = (attribute.LocalName != "xmlns")
+ ? XmlConvert.DecodeName(attribute.LocalName)
+ : string.Empty;
+ string? namespaceUri = attribute.Value;
+ if (namespaceUri == null)
+ {
+ throw new JsonSerializationException("Namespace attribute must have a value.");
+ }
+
+ manager.AddNamespace(namespacePrefix, namespaceUri);
+ }
+ }
+
+ if (writePropertyName)
+ {
+ writer.WritePropertyName(GetPropertyName(node, manager));
+ }
+
+ if (!ValueAttributes(node.Attributes) && node.ChildNodes.Count == 1
+ && node.ChildNodes[0].NodeType == XmlNodeType.Text)
+ {
+ // write elements with a single text child as a name value pair
+ writer.WriteValue(node.ChildNodes[0].Value);
+ }
+ else if (node.ChildNodes.Count == 0 && node.Attributes.Count == 0)
+ {
+ IXmlElement element = (IXmlElement)node;
+
+ // empty element
+ if (element.IsEmpty)
+ {
+ writer.WriteNull();
+ }
+ else
+ {
+ writer.WriteValue(string.Empty);
+ }
+ }
+ else
+ {
+ writer.WriteStartObject();
+
+ for (int i = 0; i < node.Attributes.Count; i++)
+ {
+ SerializeNode(writer, node.Attributes[i], manager, true);
+ }
+
+ SerializeGroupedNodes(writer, node, manager, true);
+
+ writer.WriteEndObject();
+ }
+
+ manager.PopScope();
+ }
+
+ break;
+ case XmlNodeType.Comment:
+ if (writePropertyName)
+ {
+ writer.WriteComment(node.Value);
+ }
+ break;
+ case XmlNodeType.Attribute:
+ case XmlNodeType.Text:
+ case XmlNodeType.CDATA:
+ case XmlNodeType.ProcessingInstruction:
+ case XmlNodeType.Whitespace:
+ case XmlNodeType.SignificantWhitespace:
+ if (node.NamespaceUri == "http://www.w3.org/2000/xmlns/" && node.Value == JsonNamespaceUri)
+ {
+ return;
+ }
+
+ if (node.NamespaceUri == JsonNamespaceUri)
+ {
+ if (node.LocalName == "Array")
+ {
+ return;
+ }
+ }
+
+ if (writePropertyName)
+ {
+ writer.WritePropertyName(GetPropertyName(node, manager));
+ }
+ writer.WriteValue(node.Value);
+ break;
+ case XmlNodeType.XmlDeclaration:
+ IXmlDeclaration declaration = (IXmlDeclaration)node;
+ writer.WritePropertyName(GetPropertyName(node, manager));
+ writer.WriteStartObject();
+
+ if (!StringUtils.IsNullOrEmpty(declaration.Version))
+ {
+ writer.WritePropertyName("@version");
+ writer.WriteValue(declaration.Version);
+ }
+ if (!StringUtils.IsNullOrEmpty(declaration.Encoding))
+ {
+ writer.WritePropertyName("@encoding");
+ writer.WriteValue(declaration.Encoding);
+ }
+ if (!StringUtils.IsNullOrEmpty(declaration.Standalone))
+ {
+ writer.WritePropertyName("@standalone");
+ writer.WriteValue(declaration.Standalone);
+ }
+
+ writer.WriteEndObject();
+ break;
+ case XmlNodeType.DocumentType:
+ IXmlDocumentType documentType = (IXmlDocumentType)node;
+ writer.WritePropertyName(GetPropertyName(node, manager));
+ writer.WriteStartObject();
+
+ if (!StringUtils.IsNullOrEmpty(documentType.Name))
+ {
+ writer.WritePropertyName("@name");
+ writer.WriteValue(documentType.Name);
+ }
+ if (!StringUtils.IsNullOrEmpty(documentType.Public))
+ {
+ writer.WritePropertyName("@public");
+ writer.WriteValue(documentType.Public);
+ }
+ if (!StringUtils.IsNullOrEmpty(documentType.System))
+ {
+ writer.WritePropertyName("@system");
+ writer.WriteValue(documentType.System);
+ }
+ if (!StringUtils.IsNullOrEmpty(documentType.InternalSubset))
+ {
+ writer.WritePropertyName("@internalSubset");
+ writer.WriteValue(documentType.InternalSubset);
+ }
+
+ writer.WriteEndObject();
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected XmlNodeType when serializing nodes: " + node.NodeType);
+ }
+ }
+
+ private static bool AllSameName(IXmlNode node)
+ {
+ foreach (IXmlNode childNode in node.ChildNodes)
+ {
+ if (childNode.LocalName != node.LocalName)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+#endregion
+
+ #region Reading
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.Null:
+ return null;
+ case JsonToken.StartObject:
+ break;
+ default:
+ throw JsonSerializationException.Create(reader, "XmlNodeConverter can only convert JSON that begins with an object.");
+ }
+
+ XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
+ IXmlDocument? document = null;
+ IXmlNode? rootNode = null;
+
+#if HAVE_XLINQ
+ if (typeof(XObject).IsAssignableFrom(objectType))
+ {
+ if (objectType != typeof(XContainer)
+ && objectType != typeof(XDocument)
+ && objectType != typeof(XElement)
+ && objectType != typeof(XNode)
+ && objectType != typeof(XObject))
+ {
+ throw JsonSerializationException.Create(reader, "XmlNodeConverter only supports deserializing XDocument, XElement, XContainer, XNode or XObject.");
+ }
+
+ XDocument d = new XDocument();
+ document = new XDocumentWrapper(d);
+ rootNode = document;
+ }
+#endif
+#if HAVE_XML_DOCUMENT
+ if (typeof(XmlNode).IsAssignableFrom(objectType))
+ {
+ if (objectType != typeof(XmlDocument)
+ && objectType != typeof(XmlElement)
+ && objectType != typeof(XmlNode))
+ {
+ throw JsonSerializationException.Create(reader, "XmlNodeConverter only supports deserializing XmlDocument, XmlElement or XmlNode.");
+ }
+
+ XmlDocument d = new XmlDocument();
+#if HAVE_XML_DOCUMENT_TYPE
+ // prevent http request when resolving any DTD references
+ d.XmlResolver = null;
+#endif
+
+ document = new XmlDocumentWrapper(d);
+ rootNode = document;
+ }
+#endif
+
+ if (document == null || rootNode == null)
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected type when converting XML: " + objectType);
+ }
+
+ if (!StringUtils.IsNullOrEmpty(DeserializeRootElementName))
+ {
+ ReadElement(reader, document, rootNode, DeserializeRootElementName, manager);
+ }
+ else
+ {
+ reader.ReadAndAssert();
+ DeserializeNode(reader, document, manager, rootNode);
+ }
+
+#if HAVE_XLINQ
+ if (objectType == typeof(XElement))
+ {
+ XElement element = (XElement)document.DocumentElement!.WrappedNode!;
+ element.Remove();
+
+ return element;
+ }
+#endif
+#if HAVE_XML_DOCUMENT
+ if (objectType == typeof(XmlElement))
+ {
+ return document.DocumentElement!.WrappedNode;
+ }
+#endif
+
+ return document.WrappedNode;
+ }
+
+ private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, string propertyName, IXmlNode currentNode)
+ {
+ if (!EncodeSpecialCharacters)
+ {
+ switch (propertyName)
+ {
+ case TextName:
+ currentNode.AppendChild(document.CreateTextNode(ConvertTokenToXmlValue(reader)));
+ return;
+ case CDataName:
+ currentNode.AppendChild(document.CreateCDataSection(ConvertTokenToXmlValue(reader)));
+ return;
+ case WhitespaceName:
+ currentNode.AppendChild(document.CreateWhitespace(ConvertTokenToXmlValue(reader)));
+ return;
+ case SignificantWhitespaceName:
+ currentNode.AppendChild(document.CreateSignificantWhitespace(ConvertTokenToXmlValue(reader)));
+ return;
+ default:
+ // processing instructions and the xml declaration start with ?
+ if (!StringUtils.IsNullOrEmpty(propertyName) && propertyName[0] == '?')
+ {
+ CreateInstruction(reader, document, currentNode, propertyName);
+ return;
+ }
+#if HAVE_XML_DOCUMENT_TYPE
+ else if (string.Equals(propertyName, "!DOCTYPE", StringComparison.OrdinalIgnoreCase))
+ {
+ CreateDocumentType(reader, document, currentNode);
+ return;
+ }
+#endif
+ break;
+ }
+ }
+
+ if (reader.TokenType == JsonToken.StartArray)
+ {
+ // handle nested arrays
+ ReadArrayElements(reader, document, propertyName, currentNode, manager);
+ return;
+ }
+
+ // have to wait until attributes have been parsed before creating element
+ // attributes may contain namespace info used by the element
+ ReadElement(reader, document, currentNode, propertyName, manager);
+ }
+
+ private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager)
+ {
+ if (StringUtils.IsNullOrEmpty(propertyName))
+ {
+ throw JsonSerializationException.Create(reader, "XmlNodeConverter cannot convert JSON with an empty property name to XML.");
+ }
+
+ Dictionary? attributeNameValues = null;
+ string? elementPrefix = null;
+
+ if (!EncodeSpecialCharacters)
+ {
+ attributeNameValues = ShouldReadInto(reader)
+ ? ReadAttributeElements(reader, manager)
+ : null;
+ elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
+
+ if (propertyName.StartsWith('@'))
+ {
+ string attributeName = propertyName.Substring(1);
+ string? attributePrefix = MiscellaneousUtils.GetPrefix(attributeName);
+
+ AddAttribute(reader, document, currentNode, propertyName, attributeName, manager, attributePrefix);
+ return;
+ }
+
+ if (propertyName.StartsWith('$'))
+ {
+ switch (propertyName)
+ {
+ case JsonTypeReflector.ArrayValuesPropertyName:
+ propertyName = propertyName.Substring(1);
+ elementPrefix = manager.LookupPrefix(JsonNamespaceUri);
+ CreateElement(reader, document, currentNode, propertyName, manager, elementPrefix, attributeNameValues);
+ return;
+ case JsonTypeReflector.IdPropertyName:
+ case JsonTypeReflector.RefPropertyName:
+ case JsonTypeReflector.TypePropertyName:
+ case JsonTypeReflector.ValuePropertyName:
+ string attributeName = propertyName.Substring(1);
+ string attributePrefix = manager.LookupPrefix(JsonNamespaceUri);
+ AddAttribute(reader, document, currentNode, propertyName, attributeName, manager, attributePrefix);
+ return;
+ }
+ }
+ }
+ else
+ {
+ if (ShouldReadInto(reader))
+ {
+ reader.ReadAndAssert();
+ }
+ }
+
+ CreateElement(reader, document, currentNode, propertyName, manager, elementPrefix, attributeNameValues);
+ }
+
+ private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string elementName, XmlNamespaceManager manager, string? elementPrefix, Dictionary? attributeNameValues)
+ {
+ IXmlElement element = CreateElement(elementName, document, elementPrefix, manager);
+
+ currentNode.AppendChild(element);
+
+ if (attributeNameValues != null)
+ {
+ // add attributes to newly created element
+ foreach (KeyValuePair nameValue in attributeNameValues)
+ {
+ string encodedName = XmlConvert.EncodeName(nameValue.Key);
+ string? attributePrefix = MiscellaneousUtils.GetPrefix(nameValue.Key);
+
+ IXmlNode attribute = (!StringUtils.IsNullOrEmpty(attributePrefix)) ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix) ?? string.Empty, nameValue.Value) : document.CreateAttribute(encodedName, nameValue.Value);
+
+ element.SetAttributeNode(attribute);
+ }
+ }
+
+ switch (reader.TokenType)
+ {
+ case JsonToken.String:
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ case JsonToken.Boolean:
+ case JsonToken.Date:
+ case JsonToken.Bytes:
+ string? text = ConvertTokenToXmlValue(reader);
+ if (text != null)
+ {
+ element.AppendChild(document.CreateTextNode(text));
+ }
+ break;
+ case JsonToken.Null:
+
+ // empty element. do nothing
+ break;
+ case JsonToken.EndObject:
+
+ // finished element will have no children to deserialize
+ manager.RemoveNamespace(string.Empty, manager.DefaultNamespace);
+ break;
+ default:
+ manager.PushScope();
+ DeserializeNode(reader, document, manager, element);
+ manager.PopScope();
+ manager.RemoveNamespace(string.Empty, manager.DefaultNamespace);
+ break;
+ }
+ }
+
+ private static void AddAttribute(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, string attributeName, XmlNamespaceManager manager, string? attributePrefix)
+ {
+ if (currentNode.NodeType == XmlNodeType.Document)
+ {
+ throw JsonSerializationException.Create(reader, "JSON root object has property '{0}' that will be converted to an attribute. A root object cannot have any attribute properties. Consider specifying a DeserializeRootElementName.".FormatWith(CultureInfo.InvariantCulture, propertyName));
+ }
+
+ string encodedName = XmlConvert.EncodeName(attributeName);
+ string? attributeValue = ConvertTokenToXmlValue(reader);
+
+ IXmlNode attribute = (!StringUtils.IsNullOrEmpty(attributePrefix))
+ ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix), attributeValue)
+ : document.CreateAttribute(encodedName, attributeValue);
+
+ ((IXmlElement)currentNode).SetAttributeNode(attribute);
+ }
+
+ private static string? ConvertTokenToXmlValue(JsonReader reader)
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.String:
+ return reader.Value?.ToString();
+ case JsonToken.Integer:
+#if HAVE_BIG_INTEGER
+ if (reader.Value is BigInteger i)
+ {
+ return i.ToString(CultureInfo.InvariantCulture);
+ }
+#endif
+ return XmlConvert.ToString(Convert.ToInt64(reader.Value, CultureInfo.InvariantCulture));
+ case JsonToken.Float:
+ {
+ if (reader.Value is decimal d)
+ {
+ return XmlConvert.ToString(d);
+ }
+
+ if (reader.Value is float f)
+ {
+ return XmlConvert.ToString(f);
+ }
+
+ return XmlConvert.ToString(Convert.ToDouble(reader.Value, CultureInfo.InvariantCulture));
+ }
+ case JsonToken.Boolean:
+ return XmlConvert.ToString(Convert.ToBoolean(reader.Value, CultureInfo.InvariantCulture));
+ case JsonToken.Date:
+ {
+#if HAVE_DATE_TIME_OFFSET
+ if (reader.Value is DateTimeOffset offset)
+ {
+ return XmlConvert.ToString(offset);
+ }
+
+#endif
+ DateTime d = Convert.ToDateTime(reader.Value, CultureInfo.InvariantCulture);
+#if !PORTABLE || NETSTANDARD1_3
+ return XmlConvert.ToString(d, DateTimeUtils.ToSerializationMode(d.Kind));
+#else
+ return d.ToString(DateTimeUtils.ToDateTimeFormat(d.Kind), CultureInfo.InvariantCulture);
+#endif
+ }
+ case JsonToken.Bytes:
+ return Convert.ToBase64String((byte[])reader.Value!);
+ case JsonToken.Null:
+ return null;
+ default:
+ throw JsonSerializationException.Create(reader, "Cannot get an XML string value from token type '{0}'.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
+ }
+ }
+
+ private void ReadArrayElements(JsonReader reader, IXmlDocument document, string propertyName, IXmlNode currentNode, XmlNamespaceManager manager)
+ {
+ string? elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
+
+ IXmlElement nestedArrayElement = CreateElement(propertyName, document, elementPrefix, manager);
+
+ currentNode.AppendChild(nestedArrayElement);
+
+ int count = 0;
+ while (reader.Read() && reader.TokenType != JsonToken.EndArray)
+ {
+ DeserializeValue(reader, document, manager, propertyName, nestedArrayElement);
+ count++;
+ }
+
+ if (WriteArrayAttribute)
+ {
+ AddJsonArrayAttribute(nestedArrayElement, document);
+ }
+
+ if (count == 1 && WriteArrayAttribute)
+ {
+ foreach (IXmlNode childNode in nestedArrayElement.ChildNodes)
+ {
+ if (childNode is IXmlElement element && element.LocalName == propertyName)
+ {
+ AddJsonArrayAttribute(element, document);
+ break;
+ }
+ }
+ }
+ }
+
+ private void AddJsonArrayAttribute(IXmlElement element, IXmlDocument document)
+ {
+ element.SetAttributeNode(document.CreateAttribute("json:Array", JsonNamespaceUri, "true"));
+
+#if HAVE_XLINQ
+ // linq to xml doesn't automatically include prefixes via the namespace manager
+ if (element is XElementWrapper)
+ {
+ if (element.GetPrefixOfNamespace(JsonNamespaceUri) == null)
+ {
+ element.SetAttributeNode(document.CreateAttribute("xmlns:json", "http://www.w3.org/2000/xmlns/", JsonNamespaceUri));
+ }
+ }
+#endif
+ }
+
+ private bool ShouldReadInto(JsonReader reader)
+ {
+ // a string token means the element only has a single text child
+ switch (reader.TokenType)
+ {
+ case JsonToken.String:
+ case JsonToken.Null:
+ case JsonToken.Boolean:
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ case JsonToken.Date:
+ case JsonToken.Bytes:
+ case JsonToken.StartConstructor:
+ return false;
+ }
+
+ return true;
+ }
+
+ private Dictionary? ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
+ {
+ Dictionary? attributeNameValues = null;
+ bool finished = false;
+
+ // read properties until first non-attribute is encountered
+ while (!finished && reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string attributeName = reader.Value!.ToString();
+
+ if (!StringUtils.IsNullOrEmpty(attributeName))
+ {
+ char firstChar = attributeName[0];
+ string? attributeValue;
+
+ switch (firstChar)
+ {
+ case '@':
+ if (attributeNameValues == null)
+ {
+ attributeNameValues = new Dictionary();
+ }
+
+ attributeName = attributeName.Substring(1);
+ reader.ReadAndAssert();
+ attributeValue = ConvertTokenToXmlValue(reader);
+ attributeNameValues.Add(attributeName, attributeValue);
+
+ if (IsNamespaceAttribute(attributeName, out string? namespacePrefix))
+ {
+ manager.AddNamespace(namespacePrefix, attributeValue);
+ }
+ break;
+ case '$':
+ switch (attributeName)
+ {
+ case JsonTypeReflector.ArrayValuesPropertyName:
+ case JsonTypeReflector.IdPropertyName:
+ case JsonTypeReflector.RefPropertyName:
+ case JsonTypeReflector.TypePropertyName:
+ case JsonTypeReflector.ValuePropertyName:
+ // check that JsonNamespaceUri is in scope
+ // if it isn't then add it to document and namespace manager
+ string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri);
+ if (jsonPrefix == null)
+ {
+ if (attributeNameValues == null)
+ {
+ attributeNameValues = new Dictionary();
+ }
+
+ // ensure that the prefix used is free
+ int? i = null;
+ while (manager.LookupNamespace("json" + i) != null)
+ {
+ i = i.GetValueOrDefault() + 1;
+ }
+ jsonPrefix = "json" + i;
+
+ attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri);
+ manager.AddNamespace(jsonPrefix, JsonNamespaceUri);
+ }
+
+ // special case $values, it will have a non-primitive value
+ if (attributeName == JsonTypeReflector.ArrayValuesPropertyName)
+ {
+ finished = true;
+ break;
+ }
+
+ attributeName = attributeName.Substring(1);
+ reader.ReadAndAssert();
+
+ if (!JsonTokenUtils.IsPrimitiveToken(reader.TokenType))
+ {
+ throw JsonSerializationException.Create(reader, "Unexpected JsonToken: " + reader.TokenType);
+ }
+
+ if (attributeNameValues == null)
+ {
+ attributeNameValues = new Dictionary();
+ }
+
+ attributeValue = reader.Value?.ToString();
+ attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue);
+ break;
+ default:
+ finished = true;
+ break;
+ }
+ break;
+ default:
+ finished = true;
+ break;
+ }
+ }
+ else
+ {
+ finished = true;
+ }
+
+ break;
+ case JsonToken.EndObject:
+ case JsonToken.Comment:
+ finished = true;
+ break;
+ default:
+ throw JsonSerializationException.Create(reader, "Unexpected JsonToken: " + reader.TokenType);
+ }
+ }
+
+ return attributeNameValues;
+ }
+
+ private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName)
+ {
+ if (propertyName == DeclarationName)
+ {
+ string? version = null;
+ string? encoding = null;
+ string? standalone = null;
+ while (reader.Read() && reader.TokenType != JsonToken.EndObject)
+ {
+ switch (reader.Value?.ToString())
+ {
+ case "@version":
+ reader.ReadAndAssert();
+ version = ConvertTokenToXmlValue(reader);
+ break;
+ case "@encoding":
+ reader.ReadAndAssert();
+ encoding = ConvertTokenToXmlValue(reader);
+ break;
+ case "@standalone":
+ reader.ReadAndAssert();
+ standalone = ConvertTokenToXmlValue(reader);
+ break;
+ default:
+ throw JsonSerializationException.Create(reader, "Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
+ }
+ }
+
+ IXmlNode declaration = document.CreateXmlDeclaration(version, encoding, standalone);
+ currentNode.AppendChild(declaration);
+ }
+ else
+ {
+ IXmlNode instruction = document.CreateProcessingInstruction(propertyName.Substring(1), ConvertTokenToXmlValue(reader));
+ currentNode.AppendChild(instruction);
+ }
+ }
+
+#if HAVE_XML_DOCUMENT_TYPE
+ private void CreateDocumentType(JsonReader reader, IXmlDocument document, IXmlNode currentNode)
+ {
+ string? name = null;
+ string? publicId = null;
+ string? systemId = null;
+ string? internalSubset = null;
+ while (reader.Read() && reader.TokenType != JsonToken.EndObject)
+ {
+ switch (reader.Value?.ToString())
+ {
+ case "@name":
+ reader.ReadAndAssert();
+ name = ConvertTokenToXmlValue(reader);
+ break;
+ case "@public":
+ reader.ReadAndAssert();
+ publicId = ConvertTokenToXmlValue(reader);
+ break;
+ case "@system":
+ reader.ReadAndAssert();
+ systemId = ConvertTokenToXmlValue(reader);
+ break;
+ case "@internalSubset":
+ reader.ReadAndAssert();
+ internalSubset = ConvertTokenToXmlValue(reader);
+ break;
+ default:
+ throw JsonSerializationException.Create(reader, "Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
+ }
+ }
+
+ IXmlNode documentType = document.CreateXmlDocumentType(name, publicId, systemId, internalSubset);
+ currentNode.AppendChild(documentType);
+ }
+#endif
+
+ private IXmlElement CreateElement(string elementName, IXmlDocument document, string? elementPrefix, XmlNamespaceManager manager)
+ {
+ string encodeName = EncodeSpecialCharacters ? XmlConvert.EncodeLocalName(elementName) : XmlConvert.EncodeName(elementName);
+ string ns = StringUtils.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix);
+
+ IXmlElement element = (!StringUtils.IsNullOrEmpty(ns)) ? document.CreateElement(encodeName, ns) : document.CreateElement(encodeName);
+
+ return element;
+ }
+
+ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, IXmlNode currentNode)
+ {
+ do
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ if (currentNode.NodeType == XmlNodeType.Document && document.DocumentElement != null)
+ {
+ throw JsonSerializationException.Create(reader, "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifying a DeserializeRootElementName.");
+ }
+
+ string propertyName = reader.Value!.ToString();
+ reader.ReadAndAssert();
+
+ if (reader.TokenType == JsonToken.StartArray)
+ {
+ int count = 0;
+ while (reader.Read() && reader.TokenType != JsonToken.EndArray)
+ {
+ DeserializeValue(reader, document, manager, propertyName, currentNode);
+ count++;
+ }
+
+ if (count == 1 && WriteArrayAttribute)
+ {
+ MiscellaneousUtils.GetQualifiedNameParts(propertyName, out string? elementPrefix, out string localName);
+ string ns = StringUtils.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix);
+
+ foreach (IXmlNode childNode in currentNode.ChildNodes)
+ {
+ if (childNode is IXmlElement element && element.LocalName == localName && element.NamespaceUri == ns)
+ {
+ AddJsonArrayAttribute(element, document);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ DeserializeValue(reader, document, manager, propertyName, currentNode);
+ }
+ continue;
+ case JsonToken.StartConstructor:
+ string constructorName = reader.Value!.ToString();
+
+ while (reader.Read() && reader.TokenType != JsonToken.EndConstructor)
+ {
+ DeserializeValue(reader, document, manager, constructorName, currentNode);
+ }
+ break;
+ case JsonToken.Comment:
+ currentNode.AppendChild(document.CreateComment((string)reader.Value!));
+ break;
+ case JsonToken.EndObject:
+ case JsonToken.EndArray:
+ return;
+ default:
+ throw JsonSerializationException.Create(reader, "Unexpected JsonToken when deserializing node: " + reader.TokenType);
+ }
+ } while (reader.Read());
+ // don't read if current token is a property. token was already read when parsing element attributes
+ }
+
+ ///
+ /// Checks if the is a namespace attribute.
+ ///
+ /// Attribute name to test.
+ /// The attribute name prefix if it has one, otherwise an empty string.
+ /// true if attribute name is for a namespace attribute, otherwise false .
+ private bool IsNamespaceAttribute(string attributeName, [NotNullWhen(true)]out string? prefix)
+ {
+ if (attributeName.StartsWith("xmlns", StringComparison.Ordinal))
+ {
+ if (attributeName.Length == 5)
+ {
+ prefix = string.Empty;
+ return true;
+ }
+ else if (attributeName[5] == ':')
+ {
+ prefix = attributeName.Substring(6, attributeName.Length - 6);
+ return true;
+ }
+ }
+ prefix = null;
+ return false;
+ }
+
+ private bool ValueAttributes(List c)
+ {
+ foreach (IXmlNode xmlNode in c)
+ {
+ if (xmlNode.NamespaceUri == JsonNamespaceUri)
+ {
+ continue;
+ }
+
+ if (xmlNode.NamespaceUri == "http://www.w3.org/2000/xmlns/" && xmlNode.Value == JsonNamespaceUri)
+ {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+#endregion
+
+ ///
+ /// Determines whether this instance can convert the specified value type.
+ ///
+ /// Type of the value.
+ ///
+ /// true if this instance can convert the specified value type; otherwise, false .
+ ///
+ public override bool CanConvert(Type valueType)
+ {
+#if HAVE_XLINQ
+ if (valueType.AssignableToTypeName("System.Xml.Linq.XObject", false))
+ {
+ return IsXObject(valueType);
+ }
+#endif
+#if HAVE_XML_DOCUMENT
+ if (valueType.AssignableToTypeName("System.Xml.XmlNode", false))
+ {
+ return IsXmlNode(valueType);
+ }
+#endif
+
+ return false;
+ }
+
+#if HAVE_XLINQ
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private bool IsXObject(Type valueType)
+ {
+ return typeof(XObject).IsAssignableFrom(valueType);
+ }
+#endif
+
+#if HAVE_XML_DOCUMENT
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private bool IsXmlNode(Type valueType)
+ {
+ return typeof(XmlNode).IsAssignableFrom(valueType);
+ }
+#endif
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/DateFormatHandling.cs b/Libs/Newtonsoft.Json.AOT/DateFormatHandling.cs
new file mode 100644
index 0000000..70b86f6
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/DateFormatHandling.cs
@@ -0,0 +1,43 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Specifies how dates are formatted when writing JSON text.
+ ///
+ public enum DateFormatHandling
+ {
+ ///
+ /// Dates are written in the ISO 8601 format, e.g. "2012-03-21T05:40Z" .
+ ///
+ IsoDateFormat,
+
+ ///
+ /// Dates are written in the Microsoft JSON format, e.g. "\/Date(1198908717056)\/" .
+ ///
+ MicrosoftDateFormat
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/DateParseHandling.cs b/Libs/Newtonsoft.Json.AOT/DateParseHandling.cs
new file mode 100644
index 0000000..10bd229
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/DateParseHandling.cs
@@ -0,0 +1,49 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Specifies how date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z" , are parsed when reading JSON text.
+ ///
+ public enum DateParseHandling
+ {
+ ///
+ /// Date formatted strings are not parsed to a date type and are read as strings.
+ ///
+ None = 0,
+
+ ///
+ /// Date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z" , are parsed to .
+ ///
+ DateTime = 1,
+#if HAVE_DATE_TIME_OFFSET
+ ///
+ /// Date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z" , are parsed to .
+ ///
+ DateTimeOffset = 2
+#endif
+ }
+}
diff --git a/Libs/Newtonsoft.Json.AOT/DateTimeZoneHandling.cs b/Libs/Newtonsoft.Json.AOT/DateTimeZoneHandling.cs
new file mode 100644
index 0000000..c8f5c7a
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/DateTimeZoneHandling.cs
@@ -0,0 +1,56 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Specifies how to treat the time value when converting between string and .
+ ///
+ public enum DateTimeZoneHandling
+ {
+ ///
+ /// Treat as local time. If the object represents a Coordinated Universal Time (UTC), it is converted to the local time.
+ ///
+ Local = 0,
+
+ ///
+ /// Treat as a UTC. If the object represents a local time, it is converted to a UTC.
+ ///
+ Utc = 1,
+
+ ///
+ /// Treat as a local time if a is being converted to a string.
+ /// If a string is being converted to , convert to a local time if a time zone is specified.
+ ///
+ Unspecified = 2,
+
+ ///
+ /// Time zone information should be preserved when converting.
+ ///
+ RoundtripKind = 3
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/DefaultJsonNameTable.cs b/Libs/Newtonsoft.Json.AOT/DefaultJsonNameTable.cs
new file mode 100644
index 0000000..9d56e0d
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/DefaultJsonNameTable.cs
@@ -0,0 +1,197 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// The default JSON name table implementation.
+ ///
+ public class DefaultJsonNameTable : JsonNameTable
+ {
+ // used to defeat hashtable DoS attack where someone passes in lots of strings that hash to the same hash code
+ private static readonly int HashCodeRandomizer;
+
+ private int _count;
+ private Entry[] _entries;
+ private int _mask = 31;
+
+ static DefaultJsonNameTable()
+ {
+ HashCodeRandomizer = Environment.TickCount;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public DefaultJsonNameTable()
+ {
+ _entries = new Entry[_mask + 1];
+ }
+
+ ///
+ /// Gets a string containing the same characters as the specified range of characters in the given array.
+ ///
+ /// The character array containing the name to find.
+ /// The zero-based index into the array specifying the first character of the name.
+ /// The number of characters in the name.
+ /// A string containing the same characters as the specified range of characters in the given array.
+ public override string? Get(char[] key, int start, int length)
+ {
+ if (length == 0)
+ {
+ return string.Empty;
+ }
+
+ int hashCode = length + HashCodeRandomizer;
+ hashCode += (hashCode << 7) ^ key[start];
+ int end = start + length;
+ for (int i = start + 1; i < end; i++)
+ {
+ hashCode += (hashCode << 7) ^ key[i];
+ }
+ hashCode -= hashCode >> 17;
+ hashCode -= hashCode >> 11;
+ hashCode -= hashCode >> 5;
+
+ // make sure index is evaluated before accessing _entries, otherwise potential race condition causing IndexOutOfRangeException
+ var index = hashCode & _mask;
+ var entries = _entries;
+
+ for (Entry entry = entries[index]; entry != null; entry = entry.Next)
+ {
+ if (entry.HashCode == hashCode && TextEquals(entry.Value, key, start, length))
+ {
+ return entry.Value;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Adds the specified string into name table.
+ ///
+ /// The string to add.
+ /// This method is not thread-safe.
+ /// The resolved string.
+ public string Add(string key)
+ {
+ if (key == null)
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+
+ int length = key.Length;
+ if (length == 0)
+ {
+ return string.Empty;
+ }
+
+ int hashCode = length + HashCodeRandomizer;
+ for (int i = 0; i < key.Length; i++)
+ {
+ hashCode += (hashCode << 7) ^ key[i];
+ }
+ hashCode -= hashCode >> 17;
+ hashCode -= hashCode >> 11;
+ hashCode -= hashCode >> 5;
+ for (Entry entry = _entries[hashCode & _mask]; entry != null; entry = entry.Next)
+ {
+ if (entry.HashCode == hashCode && entry.Value.Equals(key, StringComparison.Ordinal))
+ {
+ return entry.Value;
+ }
+ }
+
+ return AddEntry(key, hashCode);
+ }
+
+ private string AddEntry(string str, int hashCode)
+ {
+ int index = hashCode & _mask;
+ Entry entry = new Entry(str, hashCode, _entries[index]);
+ _entries[index] = entry;
+ if (_count++ == _mask)
+ {
+ Grow();
+ }
+ return entry.Value;
+ }
+
+ private void Grow()
+ {
+ Entry[] entries = _entries;
+ int newMask = (_mask * 2) + 1;
+ Entry[] newEntries = new Entry[newMask + 1];
+
+ for (int i = 0; i < entries.Length; i++)
+ {
+ Entry next;
+ for (Entry entry = entries[i]; entry != null; entry = next)
+ {
+ int index = entry.HashCode & newMask;
+ next = entry.Next;
+ entry.Next = newEntries[index];
+ newEntries[index] = entry;
+ }
+ }
+ _entries = newEntries;
+ _mask = newMask;
+ }
+
+ private static bool TextEquals(string str1, char[] str2, int str2Start, int str2Length)
+ {
+ if (str1.Length != str2Length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < str1.Length; i++)
+ {
+ if (str1[i] != str2[str2Start + i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private class Entry
+ {
+ internal readonly string Value;
+ internal readonly int HashCode;
+ internal Entry Next;
+
+ internal Entry(string value, int hashCode, Entry next)
+ {
+ Value = value;
+ HashCode = hashCode;
+ Next = next;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/DefaultValueHandling.cs b/Libs/Newtonsoft.Json.AOT/DefaultValueHandling.cs
new file mode 100644
index 0000000..b00ea10
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/DefaultValueHandling.cs
@@ -0,0 +1,67 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.ComponentModel;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Specifies default value handling options for the .
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Flags]
+ public enum DefaultValueHandling
+ {
+ ///
+ /// Include members where the member value is the same as the member's default value when serializing objects.
+ /// Included members are written to JSON. Has no effect when deserializing.
+ ///
+ Include = 0,
+
+ ///
+ /// Ignore members where the member value is the same as the member's default value when serializing objects
+ /// so that it is not written to JSON.
+ /// This option will ignore all default values (e.g. null for objects and nullable types; 0 for integers,
+ /// decimals and floating point numbers; and false for booleans). The default value ignored can be changed by
+ /// placing the on the property.
+ ///
+ Ignore = 1,
+
+ ///
+ /// Members with a default value but no JSON will be set to their default value when deserializing.
+ ///
+ Populate = 2,
+
+ ///
+ /// Ignore members where the member value is the same as the member's default value when serializing objects
+ /// and set members to their default value when deserializing.
+ ///
+ IgnoreAndPopulate = Ignore | Populate
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/FloatFormatHandling.cs b/Libs/Newtonsoft.Json.AOT/FloatFormatHandling.cs
new file mode 100644
index 0000000..aa8ef75
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/FloatFormatHandling.cs
@@ -0,0 +1,52 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Specifies float format handling options when writing special floating point numbers, e.g. ,
+ /// and with .
+ ///
+ public enum FloatFormatHandling
+ {
+ ///
+ /// Write special floating point values as strings in JSON, e.g. "NaN" , "Infinity" , "-Infinity" .
+ ///
+ String = 0,
+
+ ///
+ /// Write special floating point values as symbols in JSON, e.g. NaN , Infinity , -Infinity .
+ /// Note that this will produce non-valid JSON.
+ ///
+ Symbol = 1,
+
+ ///
+ /// Write special floating point values as the property's default value in JSON, e.g. 0.0 for a property, null for a of property.
+ ///
+ DefaultValue = 2
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/FloatParseHandling.cs b/Libs/Newtonsoft.Json.AOT/FloatParseHandling.cs
new file mode 100644
index 0000000..3d2f263
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/FloatParseHandling.cs
@@ -0,0 +1,43 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Specifies how floating point numbers, e.g. 1.0 and 9.9, are parsed when reading JSON text.
+ ///
+ public enum FloatParseHandling
+ {
+ ///
+ /// Floating point numbers are parsed to .
+ ///
+ Double = 0,
+
+ ///
+ /// Floating point numbers are parsed to .
+ ///
+ Decimal = 1
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/FormatterAssemblyStyle.cs b/Libs/Newtonsoft.Json.AOT/FormatterAssemblyStyle.cs
new file mode 100644
index 0000000..d03a269
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/FormatterAssemblyStyle.cs
@@ -0,0 +1,24 @@
+
+#if HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE
+
+namespace System.Runtime.Serialization.Formatters
+{
+ ///
+ /// Indicates the method that will be used during deserialization for locating and loading assemblies.
+ ///
+ [Obsolete("FormatterAssemblyStyle is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
+ public enum FormatterAssemblyStyle
+ {
+ ///
+ /// In simple mode, the assembly used during deserialization need not match exactly the assembly used during serialization. Specifically, the version numbers need not match as the method is used to load the assembly.
+ ///
+ Simple = 0,
+
+ ///
+ /// In full mode, the assembly used during deserialization must match exactly the assembly used during serialization. The is used to load the assembly.
+ ///
+ Full = 1
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Formatting.cs b/Libs/Newtonsoft.Json.AOT/Formatting.cs
new file mode 100644
index 0000000..0b03ef4
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Formatting.cs
@@ -0,0 +1,43 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Specifies formatting options for the .
+ ///
+ public enum Formatting
+ {
+ ///
+ /// No special formatting is applied. This is the default.
+ ///
+ None = 0,
+
+ ///
+ /// Causes child objects to be indented according to the and settings.
+ ///
+ Indented = 1
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/IArrayPool.cs b/Libs/Newtonsoft.Json.AOT/IArrayPool.cs
new file mode 100644
index 0000000..b641274
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/IArrayPool.cs
@@ -0,0 +1,22 @@
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Provides an interface for using pooled arrays.
+ ///
+ /// The array type content.
+ public interface IArrayPool
+ {
+ ///
+ /// Rent an array from the pool. This array must be returned when it is no longer needed.
+ ///
+ /// The minimum required length of the array. The returned array may be longer.
+ /// The rented array from the pool. This array must be returned when it is no longer needed.
+ T[] Rent(int minimumLength);
+
+ ///
+ /// Return an array to the pool.
+ ///
+ /// The array that is being returned.
+ void Return(T[]? array);
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/IJsonLineInfo.cs b/Libs/Newtonsoft.Json.AOT/IJsonLineInfo.cs
new file mode 100644
index 0000000..05cc80e
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/IJsonLineInfo.cs
@@ -0,0 +1,53 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Provides an interface to enable a class to return line and position information.
+ ///
+ public interface IJsonLineInfo
+ {
+ ///
+ /// Gets a value indicating whether the class can return line information.
+ ///
+ ///
+ /// true if and can be provided; otherwise, false .
+ ///
+ bool HasLineInfo();
+
+ ///
+ /// Gets the current line number.
+ ///
+ /// The current line number or 0 if no line information is available (for example, when returns false ).
+ int LineNumber { get; }
+
+ ///
+ /// Gets the current line position.
+ ///
+ /// The current line position or 0 if no line information is available (for example, when returns false ).
+ int LinePosition { get; }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonArrayAttribute.cs b/Libs/Newtonsoft.Json.AOT/JsonArrayAttribute.cs
new file mode 100644
index 0000000..eeaa67c
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonArrayAttribute.cs
@@ -0,0 +1,73 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Instructs the how to serialize the collection.
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
+ public sealed class JsonArrayAttribute : JsonContainerAttribute
+ {
+ private bool _allowNullItems;
+
+ ///
+ /// Gets or sets a value indicating whether null items are allowed in the collection.
+ ///
+ /// true if null items are allowed in the collection; otherwise, false .
+ public bool AllowNullItems
+ {
+ get => _allowNullItems;
+ set => _allowNullItems = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public JsonArrayAttribute()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a flag indicating whether the array can contain null items.
+ ///
+ /// A flag indicating whether the array can contain null items.
+ public JsonArrayAttribute(bool allowNullItems)
+ {
+ _allowNullItems = allowNullItems;
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified container Id.
+ ///
+ /// The container Id.
+ public JsonArrayAttribute(string id)
+ : base(id)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonConstructorAttribute.cs b/Libs/Newtonsoft.Json.AOT/JsonConstructorAttribute.cs
new file mode 100644
index 0000000..f05c0da
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonConstructorAttribute.cs
@@ -0,0 +1,37 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Instructs the to use the specified constructor when deserializing that object.
+ ///
+ [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)]
+ public sealed class JsonConstructorAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonContainerAttribute.cs b/Libs/Newtonsoft.Json.AOT/JsonContainerAttribute.cs
new file mode 100644
index 0000000..e4e29d4
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonContainerAttribute.cs
@@ -0,0 +1,180 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using LC.Newtonsoft.Json.Serialization;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Instructs the how to serialize the object.
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
+ public abstract class JsonContainerAttribute : Attribute
+ {
+ ///
+ /// Gets or sets the id.
+ ///
+ /// The id.
+ public string? Id { get; set; }
+
+ ///
+ /// Gets or sets the title.
+ ///
+ /// The title.
+ public string? Title { get; set; }
+
+ ///
+ /// Gets or sets the description.
+ ///
+ /// The description.
+ public string? Description { get; set; }
+
+ ///
+ /// Gets or sets the collection's items converter.
+ ///
+ /// The collection's items converter.
+ public Type? ItemConverterType { get; set; }
+
+ ///
+ /// The parameter list to use when constructing the described by .
+ /// If null , the default constructor is used.
+ /// When non-null , there must be a constructor defined in the that exactly matches the number,
+ /// order, and type of these parameters.
+ ///
+ ///
+ ///
+ /// [JsonContainer(ItemConverterType = typeof(MyContainerConverter), ItemConverterParameters = new object[] { 123, "Four" })]
+ ///
+ ///
+ public object[]? ItemConverterParameters { get; set; }
+
+ ///
+ /// Gets or sets the of the .
+ ///
+ /// The of the .
+ public Type? NamingStrategyType
+ {
+ get => _namingStrategyType;
+ set
+ {
+ _namingStrategyType = value;
+ NamingStrategyInstance = null;
+ }
+ }
+
+ ///
+ /// The parameter list to use when constructing the described by .
+ /// If null , the default constructor is used.
+ /// When non-null , there must be a constructor defined in the that exactly matches the number,
+ /// order, and type of these parameters.
+ ///
+ ///
+ ///
+ /// [JsonContainer(NamingStrategyType = typeof(MyNamingStrategy), NamingStrategyParameters = new object[] { 123, "Four" })]
+ ///
+ ///
+ public object[]? NamingStrategyParameters
+ {
+ get => _namingStrategyParameters;
+ set
+ {
+ _namingStrategyParameters = value;
+ NamingStrategyInstance = null;
+ }
+ }
+
+ internal NamingStrategy? NamingStrategyInstance { get; set; }
+
+ // yuck. can't set nullable properties on an attribute in C#
+ // have to use this approach to get an unset default state
+ internal bool? _isReference;
+ internal bool? _itemIsReference;
+ internal ReferenceLoopHandling? _itemReferenceLoopHandling;
+ internal TypeNameHandling? _itemTypeNameHandling;
+ private Type? _namingStrategyType;
+ private object[]? _namingStrategyParameters;
+
+ ///
+ /// Gets or sets a value that indicates whether to preserve object references.
+ ///
+ ///
+ /// true to keep object reference; otherwise, false . The default is false .
+ ///
+ public bool IsReference
+ {
+ get => _isReference ?? default;
+ set => _isReference = value;
+ }
+
+ ///
+ /// Gets or sets a value that indicates whether to preserve collection's items references.
+ ///
+ ///
+ /// true to keep collection's items object references; otherwise, false . The default is false .
+ ///
+ public bool ItemIsReference
+ {
+ get => _itemIsReference ?? default;
+ set => _itemIsReference = value;
+ }
+
+ ///
+ /// Gets or sets the reference loop handling used when serializing the collection's items.
+ ///
+ /// The reference loop handling.
+ public ReferenceLoopHandling ItemReferenceLoopHandling
+ {
+ get => _itemReferenceLoopHandling ?? default;
+ set => _itemReferenceLoopHandling = value;
+ }
+
+ ///
+ /// Gets or sets the type name handling used when serializing the collection's items.
+ ///
+ /// The type name handling.
+ public TypeNameHandling ItemTypeNameHandling
+ {
+ get => _itemTypeNameHandling ?? default;
+ set => _itemTypeNameHandling = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ protected JsonContainerAttribute()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified container Id.
+ ///
+ /// The container Id.
+ protected JsonContainerAttribute(string id)
+ {
+ Id = id;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonConvert.cs b/Libs/Newtonsoft.Json.AOT/JsonConvert.cs
new file mode 100644
index 0000000..639a169
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonConvert.cs
@@ -0,0 +1,1085 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.IO;
+using System.Globalization;
+#if HAVE_BIG_INTEGER
+using System.Numerics;
+#endif
+using LC.Newtonsoft.Json.Linq;
+using LC.Newtonsoft.Json.Utilities;
+using System.Xml;
+using LC.Newtonsoft.Json.Converters;
+using LC.Newtonsoft.Json.Serialization;
+using System.Text;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Diagnostics.CodeAnalysis;
+#if HAVE_XLINQ
+using System.Xml.Linq;
+#endif
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Provides methods for converting between .NET types and JSON types.
+ ///
+ ///
+ ///
+ ///
+ public static class JsonConvert
+ {
+ ///
+ /// Gets or sets a function that creates default .
+ /// Default settings are automatically used by serialization methods on ,
+ /// and and on .
+ /// To serialize without using any default settings create a with
+ /// .
+ ///
+ public static Func? DefaultSettings { get; set; }
+
+ ///
+ /// Represents JavaScript's boolean value true as a string. This field is read-only.
+ ///
+ public static readonly string True = "true";
+
+ ///
+ /// Represents JavaScript's boolean value false as a string. This field is read-only.
+ ///
+ public static readonly string False = "false";
+
+ ///
+ /// Represents JavaScript's null as a string. This field is read-only.
+ ///
+ public static readonly string Null = "null";
+
+ ///
+ /// Represents JavaScript's undefined as a string. This field is read-only.
+ ///
+ public static readonly string Undefined = "undefined";
+
+ ///
+ /// Represents JavaScript's positive infinity as a string. This field is read-only.
+ ///
+ public static readonly string PositiveInfinity = "Infinity";
+
+ ///
+ /// Represents JavaScript's negative infinity as a string. This field is read-only.
+ ///
+ public static readonly string NegativeInfinity = "-Infinity";
+
+ ///
+ /// Represents JavaScript's NaN as a string. This field is read-only.
+ ///
+ public static readonly string NaN = "NaN";
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(DateTime value)
+ {
+ return ToString(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.RoundtripKind);
+ }
+
+ ///
+ /// Converts the to its JSON string representation using the specified.
+ ///
+ /// The value to convert.
+ /// The format the date will be converted to.
+ /// The time zone handling when the date is converted to a string.
+ /// A JSON string representation of the .
+ public static string ToString(DateTime value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling)
+ {
+ DateTime updatedDateTime = DateTimeUtils.EnsureDateTime(value, timeZoneHandling);
+
+ using (StringWriter writer = StringUtils.CreateStringWriter(64))
+ {
+ writer.Write('"');
+ DateTimeUtils.WriteDateTimeString(writer, updatedDateTime, format, null, CultureInfo.InvariantCulture);
+ writer.Write('"');
+ return writer.ToString();
+ }
+ }
+
+#if HAVE_DATE_TIME_OFFSET
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(DateTimeOffset value)
+ {
+ return ToString(value, DateFormatHandling.IsoDateFormat);
+ }
+
+ ///
+ /// Converts the to its JSON string representation using the specified.
+ ///
+ /// The value to convert.
+ /// The format the date will be converted to.
+ /// A JSON string representation of the .
+ public static string ToString(DateTimeOffset value, DateFormatHandling format)
+ {
+ using (StringWriter writer = StringUtils.CreateStringWriter(64))
+ {
+ writer.Write('"');
+ DateTimeUtils.WriteDateTimeOffsetString(writer, value, format, null, CultureInfo.InvariantCulture);
+ writer.Write('"');
+ return writer.ToString();
+ }
+ }
+#endif
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(bool value)
+ {
+ return (value) ? True : False;
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(char value)
+ {
+ return ToString(char.ToString(value));
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(Enum value)
+ {
+ return value.ToString("D");
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(int value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(short value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ [CLSCompliant(false)]
+ public static string ToString(ushort value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ [CLSCompliant(false)]
+ public static string ToString(uint value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(long value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+#if HAVE_BIG_INTEGER
+ private static string ToStringInternal(BigInteger value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+#endif
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ [CLSCompliant(false)]
+ public static string ToString(ulong value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(float value)
+ {
+ return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
+ }
+
+ internal static string ToString(float value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
+ {
+ return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
+ }
+
+ private static string EnsureFloatFormat(double value, string text, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
+ {
+ if (floatFormatHandling == FloatFormatHandling.Symbol || !(double.IsInfinity(value) || double.IsNaN(value)))
+ {
+ return text;
+ }
+
+ if (floatFormatHandling == FloatFormatHandling.DefaultValue)
+ {
+ return (!nullable) ? "0.0" : Null;
+ }
+
+ return quoteChar + text + quoteChar;
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(double value)
+ {
+ return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
+ }
+
+ internal static string ToString(double value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
+ {
+ return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
+ }
+
+ private static string EnsureDecimalPlace(double value, string text)
+ {
+ if (double.IsNaN(value) || double.IsInfinity(value) || text.IndexOf('.') != -1 || text.IndexOf('E') != -1 || text.IndexOf('e') != -1)
+ {
+ return text;
+ }
+
+ return text + ".0";
+ }
+
+ private static string EnsureDecimalPlace(string text)
+ {
+ if (text.IndexOf('.') != -1)
+ {
+ return text;
+ }
+
+ return text + ".0";
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(byte value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ [CLSCompliant(false)]
+ public static string ToString(sbyte value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(decimal value)
+ {
+ return EnsureDecimalPlace(value.ToString(null, CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(Guid value)
+ {
+ return ToString(value, '"');
+ }
+
+ internal static string ToString(Guid value, char quoteChar)
+ {
+ string text;
+ string qc;
+#if HAVE_CHAR_TO_STRING_WITH_CULTURE
+ text = value.ToString("D", CultureInfo.InvariantCulture);
+ qc = quoteChar.ToString(CultureInfo.InvariantCulture);
+#else
+ text = value.ToString("D");
+ qc = quoteChar.ToString();
+#endif
+
+ return qc + text + qc;
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(TimeSpan value)
+ {
+ return ToString(value, '"');
+ }
+
+ internal static string ToString(TimeSpan value, char quoteChar)
+ {
+ return ToString(value.ToString(), quoteChar);
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(Uri? value)
+ {
+ if (value == null)
+ {
+ return Null;
+ }
+
+ return ToString(value, '"');
+ }
+
+ internal static string ToString(Uri value, char quoteChar)
+ {
+ return ToString(value.OriginalString, quoteChar);
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(string? value)
+ {
+ return ToString(value, '"');
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// The string delimiter character.
+ /// A JSON string representation of the .
+ public static string ToString(string? value, char delimiter)
+ {
+ return ToString(value, delimiter, StringEscapeHandling.Default);
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// The string delimiter character.
+ /// The string escape handling.
+ /// A JSON string representation of the .
+ public static string ToString(string? value, char delimiter, StringEscapeHandling stringEscapeHandling)
+ {
+ if (delimiter != '"' && delimiter != '\'')
+ {
+ throw new ArgumentException("Delimiter must be a single or double quote.", nameof(delimiter));
+ }
+
+ return JavaScriptUtils.ToEscapedJavaScriptString(value, delimiter, true, stringEscapeHandling);
+ }
+
+ ///
+ /// Converts the to its JSON string representation.
+ ///
+ /// The value to convert.
+ /// A JSON string representation of the .
+ public static string ToString(object? value)
+ {
+ if (value == null)
+ {
+ return Null;
+ }
+
+ PrimitiveTypeCode typeCode = ConvertUtils.GetTypeCode(value.GetType());
+
+ switch (typeCode)
+ {
+ case PrimitiveTypeCode.String:
+ return ToString((string)value);
+ case PrimitiveTypeCode.Char:
+ return ToString((char)value);
+ case PrimitiveTypeCode.Boolean:
+ return ToString((bool)value);
+ case PrimitiveTypeCode.SByte:
+ return ToString((sbyte)value);
+ case PrimitiveTypeCode.Int16:
+ return ToString((short)value);
+ case PrimitiveTypeCode.UInt16:
+ return ToString((ushort)value);
+ case PrimitiveTypeCode.Int32:
+ return ToString((int)value);
+ case PrimitiveTypeCode.Byte:
+ return ToString((byte)value);
+ case PrimitiveTypeCode.UInt32:
+ return ToString((uint)value);
+ case PrimitiveTypeCode.Int64:
+ return ToString((long)value);
+ case PrimitiveTypeCode.UInt64:
+ return ToString((ulong)value);
+ case PrimitiveTypeCode.Single:
+ return ToString((float)value);
+ case PrimitiveTypeCode.Double:
+ return ToString((double)value);
+ case PrimitiveTypeCode.DateTime:
+ return ToString((DateTime)value);
+ case PrimitiveTypeCode.Decimal:
+ return ToString((decimal)value);
+#if HAVE_DB_NULL_TYPE_CODE
+ case PrimitiveTypeCode.DBNull:
+ return Null;
+#endif
+#if HAVE_DATE_TIME_OFFSET
+ case PrimitiveTypeCode.DateTimeOffset:
+ return ToString((DateTimeOffset)value);
+#endif
+ case PrimitiveTypeCode.Guid:
+ return ToString((Guid)value);
+ case PrimitiveTypeCode.Uri:
+ return ToString((Uri)value);
+ case PrimitiveTypeCode.TimeSpan:
+ return ToString((TimeSpan)value);
+#if HAVE_BIG_INTEGER
+ case PrimitiveTypeCode.BigInteger:
+ return ToStringInternal((BigInteger)value);
+#endif
+ }
+
+ throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
+ }
+
+ #region Serialize
+ ///
+ /// Serializes the specified object to a JSON string.
+ ///
+ /// The object to serialize.
+ /// A JSON string representation of the object.
+ [DebuggerStepThrough]
+ public static string SerializeObject(object? value)
+ {
+ return SerializeObject(value, null, (JsonSerializerSettings?)null);
+ }
+
+ ///
+ /// Serializes the specified object to a JSON string using formatting.
+ ///
+ /// The object to serialize.
+ /// Indicates how the output should be formatted.
+ ///
+ /// A JSON string representation of the object.
+ ///
+ [DebuggerStepThrough]
+ public static string SerializeObject(object? value, Formatting formatting)
+ {
+ return SerializeObject(value, formatting, (JsonSerializerSettings?)null);
+ }
+
+ ///
+ /// Serializes the specified object to a JSON string using a collection of .
+ ///
+ /// The object to serialize.
+ /// A collection of converters used while serializing.
+ /// A JSON string representation of the object.
+ [DebuggerStepThrough]
+ public static string SerializeObject(object? value, params JsonConverter[] converters)
+ {
+ JsonSerializerSettings? settings = (converters != null && converters.Length > 0)
+ ? new JsonSerializerSettings { Converters = converters }
+ : null;
+
+ return SerializeObject(value, null, settings);
+ }
+
+ ///
+ /// Serializes the specified object to a JSON string using formatting and a collection of .
+ ///
+ /// The object to serialize.
+ /// Indicates how the output should be formatted.
+ /// A collection of converters used while serializing.
+ /// A JSON string representation of the object.
+ [DebuggerStepThrough]
+ public static string SerializeObject(object? value, Formatting formatting, params JsonConverter[] converters)
+ {
+ JsonSerializerSettings? settings = (converters != null && converters.Length > 0)
+ ? new JsonSerializerSettings { Converters = converters }
+ : null;
+
+ return SerializeObject(value, null, formatting, settings);
+ }
+
+ ///
+ /// Serializes the specified object to a JSON string using .
+ ///
+ /// The object to serialize.
+ /// The used to serialize the object.
+ /// If this is null , default serialization settings will be used.
+ ///
+ /// A JSON string representation of the object.
+ ///
+ [DebuggerStepThrough]
+ public static string SerializeObject(object? value, JsonSerializerSettings? settings)
+ {
+ return SerializeObject(value, null, settings);
+ }
+
+ ///
+ /// Serializes the specified object to a JSON string using a type, formatting and .
+ ///
+ /// The object to serialize.
+ /// The used to serialize the object.
+ /// If this is null , default serialization settings will be used.
+ ///
+ /// The type of the value being serialized.
+ /// This parameter is used when is to write out the type name if the type of the value does not match.
+ /// Specifying the type is optional.
+ ///
+ ///
+ /// A JSON string representation of the object.
+ ///
+ [DebuggerStepThrough]
+ public static string SerializeObject(object? value, Type? type, JsonSerializerSettings? settings)
+ {
+ JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
+
+ return SerializeObjectInternal(value, type, jsonSerializer);
+ }
+
+ ///
+ /// Serializes the specified object to a JSON string using formatting and .
+ ///
+ /// The object to serialize.
+ /// Indicates how the output should be formatted.
+ /// The used to serialize the object.
+ /// If this is null , default serialization settings will be used.
+ ///
+ /// A JSON string representation of the object.
+ ///
+ [DebuggerStepThrough]
+ public static string SerializeObject(object? value, Formatting formatting, JsonSerializerSettings? settings)
+ {
+ return SerializeObject(value, null, formatting, settings);
+ }
+
+ ///
+ /// Serializes the specified object to a JSON string using a type, formatting and .
+ ///
+ /// The object to serialize.
+ /// Indicates how the output should be formatted.
+ /// The used to serialize the object.
+ /// If this is null , default serialization settings will be used.
+ ///
+ /// The type of the value being serialized.
+ /// This parameter is used when is to write out the type name if the type of the value does not match.
+ /// Specifying the type is optional.
+ ///
+ ///
+ /// A JSON string representation of the object.
+ ///
+ [DebuggerStepThrough]
+ public static string SerializeObject(object? value, Type? type, Formatting formatting, JsonSerializerSettings? settings)
+ {
+ JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
+ jsonSerializer.Formatting = formatting;
+
+ return SerializeObjectInternal(value, type, jsonSerializer);
+ }
+
+ private static string SerializeObjectInternal(object? value, Type? type, JsonSerializer jsonSerializer)
+ {
+ StringBuilder sb = new StringBuilder(256);
+ StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture);
+ using (JsonTextWriter jsonWriter = new JsonTextWriter(sw))
+ {
+ jsonWriter.Formatting = jsonSerializer.Formatting;
+
+ jsonSerializer.Serialize(jsonWriter, value, type);
+ }
+
+ return sw.ToString();
+ }
+ #endregion
+
+ #region Deserialize
+ ///
+ /// Deserializes the JSON to a .NET object.
+ ///
+ /// The JSON to deserialize.
+ /// The deserialized object from the JSON string.
+ [DebuggerStepThrough]
+ public static object? DeserializeObject(string value)
+ {
+ return DeserializeObject(value, null, (JsonSerializerSettings?)null);
+ }
+
+ ///
+ /// Deserializes the JSON to a .NET object using .
+ ///
+ /// The JSON to deserialize.
+ ///
+ /// The used to deserialize the object.
+ /// If this is null , default serialization settings will be used.
+ ///
+ /// The deserialized object from the JSON string.
+ [DebuggerStepThrough]
+ public static object? DeserializeObject(string value, JsonSerializerSettings settings)
+ {
+ return DeserializeObject(value, null, settings);
+ }
+
+ ///
+ /// Deserializes the JSON to the specified .NET type.
+ ///
+ /// The JSON to deserialize.
+ /// The of object being deserialized.
+ /// The deserialized object from the JSON string.
+ [DebuggerStepThrough]
+ public static object? DeserializeObject(string value, Type type)
+ {
+ return DeserializeObject(value, type, (JsonSerializerSettings?)null);
+ }
+
+ ///
+ /// Deserializes the JSON to the specified .NET type.
+ ///
+ /// The type of the object to deserialize to.
+ /// The JSON to deserialize.
+ /// The deserialized object from the JSON string.
+ [DebuggerStepThrough]
+ public static T? DeserializeObject(string value)
+ {
+ return DeserializeObject(value, (JsonSerializerSettings?)null);
+ }
+
+ ///
+ /// Deserializes the JSON to the given anonymous type.
+ ///
+ ///
+ /// The anonymous type to deserialize to. This can't be specified
+ /// traditionally and must be inferred from the anonymous type passed
+ /// as a parameter.
+ ///
+ /// The JSON to deserialize.
+ /// The anonymous type object.
+ /// The deserialized anonymous type from the JSON string.
+ [DebuggerStepThrough]
+ public static T? DeserializeAnonymousType(string value, T anonymousTypeObject)
+ {
+ return DeserializeObject(value);
+ }
+
+ ///
+ /// Deserializes the JSON to the given anonymous type using .
+ ///
+ ///
+ /// The anonymous type to deserialize to. This can't be specified
+ /// traditionally and must be inferred from the anonymous type passed
+ /// as a parameter.
+ ///
+ /// The JSON to deserialize.
+ /// The anonymous type object.
+ ///
+ /// The used to deserialize the object.
+ /// If this is null , default serialization settings will be used.
+ ///
+ /// The deserialized anonymous type from the JSON string.
+ [DebuggerStepThrough]
+ public static T? DeserializeAnonymousType(string value, T anonymousTypeObject, JsonSerializerSettings settings)
+ {
+ return DeserializeObject(value, settings);
+ }
+
+ ///
+ /// Deserializes the JSON to the specified .NET type using a collection of .
+ ///
+ /// The type of the object to deserialize to.
+ /// The JSON to deserialize.
+ /// Converters to use while deserializing.
+ /// The deserialized object from the JSON string.
+ [DebuggerStepThrough]
+ public static T? DeserializeObject(string value, params JsonConverter[] converters)
+ {
+ return (T?)DeserializeObject(value, typeof(T), converters);
+ }
+
+ ///
+ /// Deserializes the JSON to the specified .NET type using .
+ ///
+ /// The type of the object to deserialize to.
+ /// The object to deserialize.
+ ///
+ /// The used to deserialize the object.
+ /// If this is null , default serialization settings will be used.
+ ///
+ /// The deserialized object from the JSON string.
+ [DebuggerStepThrough]
+ public static T? DeserializeObject(string value, JsonSerializerSettings? settings)
+ {
+ return (T?)DeserializeObject(value, typeof(T), settings);
+ }
+
+ ///
+ /// Deserializes the JSON to the specified .NET type using a collection of .
+ ///
+ /// The JSON to deserialize.
+ /// The type of the object to deserialize.
+ /// Converters to use while deserializing.
+ /// The deserialized object from the JSON string.
+ [DebuggerStepThrough]
+ public static object? DeserializeObject(string value, Type type, params JsonConverter[] converters)
+ {
+ JsonSerializerSettings? settings = (converters != null && converters.Length > 0)
+ ? new JsonSerializerSettings { Converters = converters }
+ : null;
+
+ return DeserializeObject(value, type, settings);
+ }
+
+ ///
+ /// Deserializes the JSON to the specified .NET type using .
+ ///
+ /// The JSON to deserialize.
+ /// The type of the object to deserialize to.
+ ///
+ /// The used to deserialize the object.
+ /// If this is null , default serialization settings will be used.
+ ///
+ /// The deserialized object from the JSON string.
+ public static object? DeserializeObject(string value, Type? type, JsonSerializerSettings? settings)
+ {
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+
+ JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
+
+ // by default DeserializeObject should check for additional content
+ if (!jsonSerializer.IsCheckAdditionalContentSet())
+ {
+ jsonSerializer.CheckAdditionalContent = true;
+ }
+
+ using (JsonTextReader reader = new JsonTextReader(new StringReader(value)))
+ {
+ return jsonSerializer.Deserialize(reader, type);
+ }
+ }
+ #endregion
+
+ #region Populate
+ ///
+ /// Populates the object with values from the JSON string.
+ ///
+ /// The JSON to populate values from.
+ /// The target object to populate values onto.
+ [DebuggerStepThrough]
+ public static void PopulateObject(string value, object target)
+ {
+ PopulateObject(value, target, null);
+ }
+
+ ///
+ /// Populates the object with values from the JSON string using .
+ ///
+ /// The JSON to populate values from.
+ /// The target object to populate values onto.
+ ///
+ /// The used to deserialize the object.
+ /// If this is null , default serialization settings will be used.
+ ///
+ public static void PopulateObject(string value, object target, JsonSerializerSettings? settings)
+ {
+ JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
+
+ using (JsonReader jsonReader = new JsonTextReader(new StringReader(value)))
+ {
+ jsonSerializer.Populate(jsonReader, target);
+
+ if (settings != null && settings.CheckAdditionalContent)
+ {
+ while (jsonReader.Read())
+ {
+ if (jsonReader.TokenType != JsonToken.Comment)
+ {
+ throw JsonSerializationException.Create(jsonReader, "Additional text found in JSON string after finishing deserializing object.");
+ }
+ }
+ }
+ }
+ }
+ #endregion
+
+ #region Xml
+#if HAVE_XML_DOCUMENT
+ ///
+ /// Serializes the to a JSON string.
+ ///
+ /// The node to serialize.
+ /// A JSON string of the .
+ public static string SerializeXmlNode(XmlNode? node)
+ {
+ return SerializeXmlNode(node, Formatting.None);
+ }
+
+ ///
+ /// Serializes the to a JSON string using formatting.
+ ///
+ /// The node to serialize.
+ /// Indicates how the output should be formatted.
+ /// A JSON string of the .
+ public static string SerializeXmlNode(XmlNode? node, Formatting formatting)
+ {
+ XmlNodeConverter converter = new XmlNodeConverter();
+
+ return SerializeObject(node, formatting, converter);
+ }
+
+ ///
+ /// Serializes the to a JSON string using formatting and omits the root object if is true .
+ ///
+ /// The node to serialize.
+ /// Indicates how the output should be formatted.
+ /// Omits writing the root object.
+ /// A JSON string of the .
+ public static string SerializeXmlNode(XmlNode? node, Formatting formatting, bool omitRootObject)
+ {
+ XmlNodeConverter converter = new XmlNodeConverter { OmitRootObject = omitRootObject };
+
+ return SerializeObject(node, formatting, converter);
+ }
+
+ ///
+ /// Deserializes the from a JSON string.
+ ///
+ /// The JSON string.
+ /// The deserialized .
+ public static XmlDocument? DeserializeXmlNode(string value)
+ {
+ return DeserializeXmlNode(value, null);
+ }
+
+ ///
+ /// Deserializes the from a JSON string nested in a root element specified by .
+ ///
+ /// The JSON string.
+ /// The name of the root element to append when deserializing.
+ /// The deserialized .
+ public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName)
+ {
+ return DeserializeXmlNode(value, deserializeRootElementName, false);
+ }
+
+ ///
+ /// Deserializes the from a JSON string nested in a root element specified by
+ /// and writes a Json.NET array attribute for collections.
+ ///
+ /// The JSON string.
+ /// The name of the root element to append when deserializing.
+ ///
+ /// A value to indicate whether to write the Json.NET array attribute.
+ /// This attribute helps preserve arrays when converting the written XML back to JSON.
+ ///
+ /// The deserialized .
+ public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
+ {
+ return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute, false);
+ }
+
+ ///
+ /// Deserializes the from a JSON string nested in a root element specified by ,
+ /// writes a Json.NET array attribute for collections, and encodes special characters.
+ ///
+ /// The JSON string.
+ /// The name of the root element to append when deserializing.
+ ///
+ /// A value to indicate whether to write the Json.NET array attribute.
+ /// This attribute helps preserve arrays when converting the written XML back to JSON.
+ ///
+ ///
+ /// A value to indicate whether to encode special characters when converting JSON to XML.
+ /// If true , special characters like ':', '@', '?', '#' and '$' in JSON property names aren't used to specify
+ /// XML namespaces, attributes or processing directives. Instead special characters are encoded and written
+ /// as part of the XML element name.
+ ///
+ /// The deserialized .
+ public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
+ {
+ XmlNodeConverter converter = new XmlNodeConverter();
+ converter.DeserializeRootElementName = deserializeRootElementName;
+ converter.WriteArrayAttribute = writeArrayAttribute;
+ converter.EncodeSpecialCharacters = encodeSpecialCharacters;
+
+ return (XmlDocument?)DeserializeObject(value, typeof(XmlDocument), converter);
+ }
+#endif
+
+#if HAVE_XLINQ
+ ///
+ /// Serializes the to a JSON string.
+ ///
+ /// The node to convert to JSON.
+ /// A JSON string of the .
+ public static string SerializeXNode(XObject? node)
+ {
+ return SerializeXNode(node, Formatting.None);
+ }
+
+ ///
+ /// Serializes the to a JSON string using formatting.
+ ///
+ /// The node to convert to JSON.
+ /// Indicates how the output should be formatted.
+ /// A JSON string of the .
+ public static string SerializeXNode(XObject? node, Formatting formatting)
+ {
+ return SerializeXNode(node, formatting, false);
+ }
+
+ ///
+ /// Serializes the to a JSON string using formatting and omits the root object if is true .
+ ///
+ /// The node to serialize.
+ /// Indicates how the output should be formatted.
+ /// Omits writing the root object.
+ /// A JSON string of the .
+ public static string SerializeXNode(XObject? node, Formatting formatting, bool omitRootObject)
+ {
+ XmlNodeConverter converter = new XmlNodeConverter { OmitRootObject = omitRootObject };
+
+ return SerializeObject(node, formatting, converter);
+ }
+
+ ///
+ /// Deserializes the from a JSON string.
+ ///
+ /// The JSON string.
+ /// The deserialized .
+ public static XDocument? DeserializeXNode(string value)
+ {
+ return DeserializeXNode(value, null);
+ }
+
+ ///
+ /// Deserializes the from a JSON string nested in a root element specified by .
+ ///
+ /// The JSON string.
+ /// The name of the root element to append when deserializing.
+ /// The deserialized .
+ public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName)
+ {
+ return DeserializeXNode(value, deserializeRootElementName, false);
+ }
+
+ ///
+ /// Deserializes the from a JSON string nested in a root element specified by
+ /// and writes a Json.NET array attribute for collections.
+ ///
+ /// The JSON string.
+ /// The name of the root element to append when deserializing.
+ ///
+ /// A value to indicate whether to write the Json.NET array attribute.
+ /// This attribute helps preserve arrays when converting the written XML back to JSON.
+ ///
+ /// The deserialized .
+ public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
+ {
+ return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute, false);
+ }
+
+ ///
+ /// Deserializes the from a JSON string nested in a root element specified by ,
+ /// writes a Json.NET array attribute for collections, and encodes special characters.
+ ///
+ /// The JSON string.
+ /// The name of the root element to append when deserializing.
+ ///
+ /// A value to indicate whether to write the Json.NET array attribute.
+ /// This attribute helps preserve arrays when converting the written XML back to JSON.
+ ///
+ ///
+ /// A value to indicate whether to encode special characters when converting JSON to XML.
+ /// If true , special characters like ':', '@', '?', '#' and '$' in JSON property names aren't used to specify
+ /// XML namespaces, attributes or processing directives. Instead special characters are encoded and written
+ /// as part of the XML element name.
+ ///
+ /// The deserialized .
+ public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
+ {
+ XmlNodeConverter converter = new XmlNodeConverter();
+ converter.DeserializeRootElementName = deserializeRootElementName;
+ converter.WriteArrayAttribute = writeArrayAttribute;
+ converter.EncodeSpecialCharacters = encodeSpecialCharacters;
+
+ return (XDocument?)DeserializeObject(value, typeof(XDocument), converter);
+ }
+#endif
+ #endregion
+ }
+}
diff --git a/Libs/Newtonsoft.Json.AOT/JsonConverter.cs b/Libs/Newtonsoft.Json.AOT/JsonConverter.cs
new file mode 100644
index 0000000..9f5ff5d
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonConverter.cs
@@ -0,0 +1,149 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using LC.Newtonsoft.Json.Utilities;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Diagnostics.CodeAnalysis;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Converts an object to and from JSON.
+ ///
+ public abstract class JsonConverter
+ {
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer);
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer);
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public abstract bool CanConvert(Type objectType);
+
+ ///
+ /// Gets a value indicating whether this can read JSON.
+ ///
+ /// true if this can read JSON; otherwise, false .
+ public virtual bool CanRead => true;
+
+ ///
+ /// Gets a value indicating whether this can write JSON.
+ ///
+ /// true if this can write JSON; otherwise, false .
+ public virtual bool CanWrite => true;
+ }
+
+ ///
+ /// Converts an object to and from JSON.
+ ///
+ /// The object type to convert.
+ public abstract class JsonConverter : JsonConverter
+ {
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (!(value != null ? value is T : ReflectionUtils.IsNullable(typeof(T))))
+ {
+ throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
+ }
+ WriteJson(writer, (T?)value, serializer);
+ }
+
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer);
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ bool existingIsNull = existingValue == null;
+ if (!(existingIsNull || existingValue is T))
+ {
+ throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
+ }
+ return ReadJson(reader, objectType, existingIsNull ? default : (T?)existingValue, !existingIsNull, serializer);
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read. If there is no existing value then null will be used.
+ /// The existing value has a value.
+ /// The calling serializer.
+ /// The object value.
+ public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer);
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false .
+ ///
+ public sealed override bool CanConvert(Type objectType)
+ {
+ return typeof(T).IsAssignableFrom(objectType);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonConverterAttribute.cs b/Libs/Newtonsoft.Json.AOT/JsonConverterAttribute.cs
new file mode 100644
index 0000000..51d12bd
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonConverterAttribute.cs
@@ -0,0 +1,77 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using LC.Newtonsoft.Json.Utilities;
+using System.Globalization;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Instructs the to use the specified when serializing the member or class.
+ ///
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Parameter, AllowMultiple = false)]
+ public sealed class JsonConverterAttribute : Attribute
+ {
+ private readonly Type _converterType;
+
+ ///
+ /// Gets the of the .
+ ///
+ /// The of the .
+ public Type ConverterType => _converterType;
+
+ ///
+ /// The parameter list to use when constructing the described by .
+ /// If null , the default constructor is used.
+ ///
+ public object[]? ConverterParameters { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Type of the .
+ public JsonConverterAttribute(Type converterType)
+ {
+ if (converterType == null)
+ {
+ throw new ArgumentNullException(nameof(converterType));
+ }
+
+ _converterType = converterType;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Type of the .
+ /// Parameter list to use when constructing the . Can be null .
+ public JsonConverterAttribute(Type converterType, params object[] converterParameters)
+ : this(converterType)
+ {
+ ConverterParameters = converterParameters;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonConverterCollection.cs b/Libs/Newtonsoft.Json.AOT/JsonConverterCollection.cs
new file mode 100644
index 0000000..a77b25d
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonConverterCollection.cs
@@ -0,0 +1,39 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Collections.ObjectModel;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Represents a collection of .
+ ///
+ public class JsonConverterCollection : Collection
+ {
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonDictionaryAttribute.cs b/Libs/Newtonsoft.Json.AOT/JsonDictionaryAttribute.cs
new file mode 100644
index 0000000..bb5023d
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonDictionaryAttribute.cs
@@ -0,0 +1,52 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Instructs the how to serialize the collection.
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
+ public sealed class JsonDictionaryAttribute : JsonContainerAttribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public JsonDictionaryAttribute()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified container Id.
+ ///
+ /// The container Id.
+ public JsonDictionaryAttribute(string id)
+ : base(id)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonException.cs b/Libs/Newtonsoft.Json.AOT/JsonException.cs
new file mode 100644
index 0000000..9907d05
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonException.cs
@@ -0,0 +1,92 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.Serialization;
+using System.Text;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// The exception thrown when an error occurs during JSON serialization or deserialization.
+ ///
+#if HAVE_BINARY_EXCEPTION_SERIALIZATION
+ [Serializable]
+#endif
+ public class JsonException : Exception
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public JsonException()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message.
+ ///
+ /// The error message that explains the reason for the exception.
+ public JsonException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The error message that explains the reason for the exception.
+ /// The exception that is the cause of the current exception, or null if no inner exception is specified.
+ public JsonException(string message, Exception? innerException)
+ : base(message, innerException)
+ {
+ }
+
+#if HAVE_BINARY_EXCEPTION_SERIALIZATION
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The that holds the serialized object data about the exception being thrown.
+ /// The that contains contextual information about the source or destination.
+ /// The parameter is null .
+ /// The class name is null or is zero (0).
+ public JsonException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+#endif
+
+ internal static JsonException Create(IJsonLineInfo lineInfo, string path, string message)
+ {
+ message = JsonPosition.FormatMessage(lineInfo, path, message);
+
+ return new JsonException(message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonExtensionDataAttribute.cs b/Libs/Newtonsoft.Json.AOT/JsonExtensionDataAttribute.cs
new file mode 100644
index 0000000..c66ecfe
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonExtensionDataAttribute.cs
@@ -0,0 +1,37 @@
+using System;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Instructs the to deserialize properties with no matching class member into the specified collection
+ /// and write values during serialization.
+ ///
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
+ public class JsonExtensionDataAttribute : Attribute
+ {
+ ///
+ /// Gets or sets a value that indicates whether to write extension data when serializing the object.
+ ///
+ ///
+ /// true to write extension data when serializing the object; otherwise, false . The default is true .
+ ///
+ public bool WriteData { get; set; }
+
+ ///
+ /// Gets or sets a value that indicates whether to read extension data when deserializing the object.
+ ///
+ ///
+ /// true to read extension data when deserializing the object; otherwise, false . The default is true .
+ ///
+ public bool ReadData { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public JsonExtensionDataAttribute()
+ {
+ WriteData = true;
+ ReadData = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonIgnoreAttribute.cs b/Libs/Newtonsoft.Json.AOT/JsonIgnoreAttribute.cs
new file mode 100644
index 0000000..fd6a243
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonIgnoreAttribute.cs
@@ -0,0 +1,39 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Instructs the not to serialize the public field or public read/write property value.
+ ///
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
+ public sealed class JsonIgnoreAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonNameTable.cs b/Libs/Newtonsoft.Json.AOT/JsonNameTable.cs
new file mode 100644
index 0000000..01c5ceb
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonNameTable.cs
@@ -0,0 +1,17 @@
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Base class for a table of atomized string objects.
+ ///
+ public abstract class JsonNameTable
+ {
+ ///
+ /// Gets a string containing the same characters as the specified range of characters in the given array.
+ ///
+ /// The character array containing the name to find.
+ /// The zero-based index into the array specifying the first character of the name.
+ /// The number of characters in the name.
+ /// A string containing the same characters as the specified range of characters in the given array.
+ public abstract string? Get(char[] key, int start, int length);
+ }
+}
diff --git a/Libs/Newtonsoft.Json.AOT/JsonObjectAttribute.cs b/Libs/Newtonsoft.Json.AOT/JsonObjectAttribute.cs
new file mode 100644
index 0000000..4b87ba5
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonObjectAttribute.cs
@@ -0,0 +1,111 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Instructs the how to serialize the object.
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false)]
+ public sealed class JsonObjectAttribute : JsonContainerAttribute
+ {
+ private MemberSerialization _memberSerialization = MemberSerialization.OptOut;
+ internal MissingMemberHandling? _missingMemberHandling;
+
+ // yuck. can't set nullable properties on an attribute in C#
+ // have to use this approach to get an unset default state
+ internal Required? _itemRequired;
+ internal NullValueHandling? _itemNullValueHandling;
+
+ ///
+ /// Gets or sets the member serialization.
+ ///
+ /// The member serialization.
+ public MemberSerialization MemberSerialization
+ {
+ get => _memberSerialization;
+ set => _memberSerialization = value;
+ }
+
+ ///
+ /// Gets or sets the missing member handling used when deserializing this object.
+ ///
+ /// The missing member handling.
+ public MissingMemberHandling MissingMemberHandling
+ {
+ get => _missingMemberHandling ?? default;
+ set => _missingMemberHandling = value;
+ }
+
+ ///
+ /// Gets or sets how the object's properties with null values are handled during serialization and deserialization.
+ ///
+ /// How the object's properties with null values are handled during serialization and deserialization.
+ public NullValueHandling ItemNullValueHandling
+ {
+ get => _itemNullValueHandling ?? default;
+ set => _itemNullValueHandling = value;
+ }
+
+ ///
+ /// Gets or sets a value that indicates whether the object's properties are required.
+ ///
+ ///
+ /// A value indicating whether the object's properties are required.
+ ///
+ public Required ItemRequired
+ {
+ get => _itemRequired ?? default;
+ set => _itemRequired = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public JsonObjectAttribute()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified member serialization.
+ ///
+ /// The member serialization.
+ public JsonObjectAttribute(MemberSerialization memberSerialization)
+ {
+ MemberSerialization = memberSerialization;
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified container Id.
+ ///
+ /// The container Id.
+ public JsonObjectAttribute(string id)
+ : base(id)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonPosition.cs b/Libs/Newtonsoft.Json.AOT/JsonPosition.cs
new file mode 100644
index 0000000..ba9ed25
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonPosition.cs
@@ -0,0 +1,177 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json
+{
+ internal enum JsonContainerType
+ {
+ None = 0,
+ Object = 1,
+ Array = 2,
+ Constructor = 3
+ }
+
+ internal struct JsonPosition
+ {
+ private static readonly char[] SpecialCharacters = { '.', ' ', '\'', '/', '"', '[', ']', '(', ')', '\t', '\n', '\r', '\f', '\b', '\\', '\u0085', '\u2028', '\u2029' };
+
+ internal JsonContainerType Type;
+ internal int Position;
+ internal string? PropertyName;
+ internal bool HasIndex;
+
+ public JsonPosition(JsonContainerType type)
+ {
+ Type = type;
+ HasIndex = TypeHasIndex(type);
+ Position = -1;
+ PropertyName = null;
+ }
+
+ internal int CalculateLength()
+ {
+ switch (Type)
+ {
+ case JsonContainerType.Object:
+ return PropertyName!.Length + 5;
+ case JsonContainerType.Array:
+ case JsonContainerType.Constructor:
+ return MathUtils.IntLength((ulong)Position) + 2;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(Type));
+ }
+ }
+
+ internal void WriteTo(StringBuilder sb, ref StringWriter? writer, ref char[]? buffer)
+ {
+ switch (Type)
+ {
+ case JsonContainerType.Object:
+ string propertyName = PropertyName!;
+ if (propertyName.IndexOfAny(SpecialCharacters) != -1)
+ {
+ sb.Append(@"['");
+
+ if (writer == null)
+ {
+ writer = new StringWriter(sb);
+ }
+
+ JavaScriptUtils.WriteEscapedJavaScriptString(writer, propertyName, '\'', false, JavaScriptUtils.SingleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer);
+
+ sb.Append(@"']");
+ }
+ else
+ {
+ if (sb.Length > 0)
+ {
+ sb.Append('.');
+ }
+
+ sb.Append(propertyName);
+ }
+ break;
+ case JsonContainerType.Array:
+ case JsonContainerType.Constructor:
+ sb.Append('[');
+ sb.Append(Position);
+ sb.Append(']');
+ break;
+ }
+ }
+
+ internal static bool TypeHasIndex(JsonContainerType type)
+ {
+ return (type == JsonContainerType.Array || type == JsonContainerType.Constructor);
+ }
+
+ internal static string BuildPath(List positions, JsonPosition? currentPosition)
+ {
+ int capacity = 0;
+ if (positions != null)
+ {
+ for (int i = 0; i < positions.Count; i++)
+ {
+ capacity += positions[i].CalculateLength();
+ }
+ }
+ if (currentPosition != null)
+ {
+ capacity += currentPosition.GetValueOrDefault().CalculateLength();
+ }
+
+ StringBuilder sb = new StringBuilder(capacity);
+ StringWriter? writer = null;
+ char[]? buffer = null;
+ if (positions != null)
+ {
+ foreach (JsonPosition state in positions)
+ {
+ state.WriteTo(sb, ref writer, ref buffer);
+ }
+ }
+ if (currentPosition != null)
+ {
+ currentPosition.GetValueOrDefault().WriteTo(sb, ref writer, ref buffer);
+ }
+
+ return sb.ToString();
+ }
+
+ internal static string FormatMessage(IJsonLineInfo? lineInfo, string path, string message)
+ {
+ // don't add a fullstop and space when message ends with a new line
+ if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal))
+ {
+ message = message.Trim();
+
+ if (!message.EndsWith('.'))
+ {
+ message += ".";
+ }
+
+ message += " ";
+ }
+
+ message += "Path '{0}'".FormatWith(CultureInfo.InvariantCulture, path);
+
+ if (lineInfo != null && lineInfo.HasLineInfo())
+ {
+ message += ", line {0}, position {1}".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition);
+ }
+
+ message += ".";
+
+ return message;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonPropertyAttribute.cs b/Libs/Newtonsoft.Json.AOT/JsonPropertyAttribute.cs
new file mode 100644
index 0000000..4faf778
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonPropertyAttribute.cs
@@ -0,0 +1,223 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using LC.Newtonsoft.Json.Serialization;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Instructs the to always serialize the member with the specified name.
+ ///
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false)]
+ public sealed class JsonPropertyAttribute : Attribute
+ {
+ // yuck. can't set nullable properties on an attribute in C#
+ // have to use this approach to get an unset default state
+ internal NullValueHandling? _nullValueHandling;
+ internal DefaultValueHandling? _defaultValueHandling;
+ internal ReferenceLoopHandling? _referenceLoopHandling;
+ internal ObjectCreationHandling? _objectCreationHandling;
+ internal TypeNameHandling? _typeNameHandling;
+ internal bool? _isReference;
+ internal int? _order;
+ internal Required? _required;
+ internal bool? _itemIsReference;
+ internal ReferenceLoopHandling? _itemReferenceLoopHandling;
+ internal TypeNameHandling? _itemTypeNameHandling;
+
+ ///
+ /// Gets or sets the type used when serializing the property's collection items.
+ ///
+ /// The collection's items type.
+ public Type? ItemConverterType { get; set; }
+
+ ///
+ /// The parameter list to use when constructing the described by .
+ /// If null , the default constructor is used.
+ /// When non-null , there must be a constructor defined in the that exactly matches the number,
+ /// order, and type of these parameters.
+ ///
+ ///
+ ///
+ /// [JsonProperty(ItemConverterType = typeof(MyContainerConverter), ItemConverterParameters = new object[] { 123, "Four" })]
+ ///
+ ///
+ public object[]? ItemConverterParameters { get; set; }
+
+ ///
+ /// Gets or sets the of the .
+ ///
+ /// The of the .
+ public Type? NamingStrategyType { get; set; }
+
+ ///
+ /// The parameter list to use when constructing the described by .
+ /// If null , the default constructor is used.
+ /// When non-null , there must be a constructor defined in the that exactly matches the number,
+ /// order, and type of these parameters.
+ ///
+ ///
+ ///
+ /// [JsonProperty(NamingStrategyType = typeof(MyNamingStrategy), NamingStrategyParameters = new object[] { 123, "Four" })]
+ ///
+ ///
+ public object[]? NamingStrategyParameters { get; set; }
+
+ ///
+ /// Gets or sets the null value handling used when serializing this property.
+ ///
+ /// The null value handling.
+ public NullValueHandling NullValueHandling
+ {
+ get => _nullValueHandling ?? default;
+ set => _nullValueHandling = value;
+ }
+
+ ///
+ /// Gets or sets the default value handling used when serializing this property.
+ ///
+ /// The default value handling.
+ public DefaultValueHandling DefaultValueHandling
+ {
+ get => _defaultValueHandling ?? default;
+ set => _defaultValueHandling = value;
+ }
+
+ ///
+ /// Gets or sets the reference loop handling used when serializing this property.
+ ///
+ /// The reference loop handling.
+ public ReferenceLoopHandling ReferenceLoopHandling
+ {
+ get => _referenceLoopHandling ?? default;
+ set => _referenceLoopHandling = value;
+ }
+
+ ///
+ /// Gets or sets the object creation handling used when deserializing this property.
+ ///
+ /// The object creation handling.
+ public ObjectCreationHandling ObjectCreationHandling
+ {
+ get => _objectCreationHandling ?? default;
+ set => _objectCreationHandling = value;
+ }
+
+ ///
+ /// Gets or sets the type name handling used when serializing this property.
+ ///
+ /// The type name handling.
+ public TypeNameHandling TypeNameHandling
+ {
+ get => _typeNameHandling ?? default;
+ set => _typeNameHandling = value;
+ }
+
+ ///
+ /// Gets or sets whether this property's value is serialized as a reference.
+ ///
+ /// Whether this property's value is serialized as a reference.
+ public bool IsReference
+ {
+ get => _isReference ?? default;
+ set => _isReference = value;
+ }
+
+ ///
+ /// Gets or sets the order of serialization of a member.
+ ///
+ /// The numeric order of serialization.
+ public int Order
+ {
+ get => _order ?? default;
+ set => _order = value;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether this property is required.
+ ///
+ ///
+ /// A value indicating whether this property is required.
+ ///
+ public Required Required
+ {
+ get => _required ?? Required.Default;
+ set => _required = value;
+ }
+
+ ///
+ /// Gets or sets the name of the property.
+ ///
+ /// The name of the property.
+ public string? PropertyName { get; set; }
+
+ ///
+ /// Gets or sets the reference loop handling used when serializing the property's collection items.
+ ///
+ /// The collection's items reference loop handling.
+ public ReferenceLoopHandling ItemReferenceLoopHandling
+ {
+ get => _itemReferenceLoopHandling ?? default;
+ set => _itemReferenceLoopHandling = value;
+ }
+
+ ///
+ /// Gets or sets the type name handling used when serializing the property's collection items.
+ ///
+ /// The collection's items type name handling.
+ public TypeNameHandling ItemTypeNameHandling
+ {
+ get => _itemTypeNameHandling ?? default;
+ set => _itemTypeNameHandling = value;
+ }
+
+ ///
+ /// Gets or sets whether this property's collection items are serialized as a reference.
+ ///
+ /// Whether this property's collection items are serialized as a reference.
+ public bool ItemIsReference
+ {
+ get => _itemIsReference ?? default;
+ set => _itemIsReference = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public JsonPropertyAttribute()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified name.
+ ///
+ /// Name of the property.
+ public JsonPropertyAttribute(string propertyName)
+ {
+ PropertyName = propertyName;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonReader.Async.cs b/Libs/Newtonsoft.Json.AOT/JsonReader.Async.cs
new file mode 100644
index 0000000..a97ec69
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonReader.Async.cs
@@ -0,0 +1,246 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if HAVE_ASYNC
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json
+{
+ public abstract partial class JsonReader
+ {
+ ///
+ /// Asynchronously reads the next JSON token from the source.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns true if the next token was read successfully; false if there are no more tokens to read.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task ReadAsync(CancellationToken cancellationToken = default)
+ {
+ return cancellationToken.CancelIfRequestedAsync() ?? Read().ToAsync();
+ }
+
+ ///
+ /// Asynchronously skips the children of the current token.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public async Task SkipAsync(CancellationToken cancellationToken = default)
+ {
+ if (TokenType == JsonToken.PropertyName)
+ {
+ await ReadAsync(cancellationToken).ConfigureAwait(false);
+ }
+
+ if (JsonTokenUtils.IsStartToken(TokenType))
+ {
+ int depth = Depth;
+
+ while (await ReadAsync(cancellationToken).ConfigureAwait(false) && depth < Depth)
+ {
+ }
+ }
+ }
+
+ internal async Task ReaderReadAndAssertAsync(CancellationToken cancellationToken)
+ {
+ if (!await ReadAsync(cancellationToken).ConfigureAwait(false))
+ {
+ throw CreateUnexpectedEndException();
+ }
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task ReadAsBooleanAsync(CancellationToken cancellationToken = default)
+ {
+ return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsBoolean());
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a [].
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the []. This result will be null at the end of an array.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task ReadAsBytesAsync(CancellationToken cancellationToken = default)
+ {
+ return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsBytes());
+ }
+
+ internal async Task ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken)
+ {
+ List buffer = new List();
+
+ while (true)
+ {
+ if (!await ReadAsync(cancellationToken).ConfigureAwait(false))
+ {
+ SetToken(JsonToken.None);
+ }
+
+ if (ReadArrayElementIntoByteArrayReportDone(buffer))
+ {
+ byte[] d = buffer.ToArray();
+ SetToken(JsonToken.Bytes, d, false);
+ return d;
+ }
+ }
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task ReadAsDateTimeAsync(CancellationToken cancellationToken = default)
+ {
+ return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsDateTime());
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task ReadAsDateTimeOffsetAsync(CancellationToken cancellationToken = default)
+ {
+ return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsDateTimeOffset());
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task ReadAsDecimalAsync(CancellationToken cancellationToken = default)
+ {
+ return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsDecimal());
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task ReadAsDoubleAsync(CancellationToken cancellationToken = default)
+ {
+ return Task.FromResult(ReadAsDouble());
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task ReadAsInt32Async(CancellationToken cancellationToken = default)
+ {
+ return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsInt32());
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the . This result will be null at the end of an array.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task ReadAsStringAsync(CancellationToken cancellationToken = default)
+ {
+ return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsString());
+ }
+
+ internal async Task ReadAndMoveToContentAsync(CancellationToken cancellationToken)
+ {
+ return await ReadAsync(cancellationToken).ConfigureAwait(false) && await MoveToContentAsync(cancellationToken).ConfigureAwait(false);
+ }
+
+ internal Task MoveToContentAsync(CancellationToken cancellationToken)
+ {
+ switch (TokenType)
+ {
+ case JsonToken.None:
+ case JsonToken.Comment:
+ return MoveToContentFromNonContentAsync(cancellationToken);
+ default:
+ return AsyncUtils.True;
+ }
+ }
+
+ private async Task MoveToContentFromNonContentAsync(CancellationToken cancellationToken)
+ {
+ while (true)
+ {
+ if (!await ReadAsync(cancellationToken).ConfigureAwait(false))
+ {
+ return false;
+ }
+
+ switch (TokenType)
+ {
+ case JsonToken.None:
+ case JsonToken.Comment:
+ break;
+ default:
+ return true;
+ }
+ }
+ }
+ }
+}
+
+#endif
diff --git a/Libs/Newtonsoft.Json.AOT/JsonReader.cs b/Libs/Newtonsoft.Json.AOT/JsonReader.cs
new file mode 100644
index 0000000..bea7c47
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonReader.cs
@@ -0,0 +1,1278 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Globalization;
+#if HAVE_BIG_INTEGER
+using System.Numerics;
+#endif
+using LC.Newtonsoft.Json.Serialization;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Represents a reader that provides fast, non-cached, forward-only access to serialized JSON data.
+ ///
+ public abstract partial class JsonReader : IDisposable
+ {
+ ///
+ /// Specifies the state of the reader.
+ ///
+ protected internal enum State
+ {
+ ///
+ /// A read method has not been called.
+ ///
+ Start,
+
+ ///
+ /// The end of the file has been reached successfully.
+ ///
+ Complete,
+
+ ///
+ /// Reader is at a property.
+ ///
+ Property,
+
+ ///
+ /// Reader is at the start of an object.
+ ///
+ ObjectStart,
+
+ ///
+ /// Reader is in an object.
+ ///
+ Object,
+
+ ///
+ /// Reader is at the start of an array.
+ ///
+ ArrayStart,
+
+ ///
+ /// Reader is in an array.
+ ///
+ Array,
+
+ ///
+ /// The method has been called.
+ ///
+ Closed,
+
+ ///
+ /// Reader has just read a value.
+ ///
+ PostValue,
+
+ ///
+ /// Reader is at the start of a constructor.
+ ///
+ ConstructorStart,
+
+ ///
+ /// Reader is in a constructor.
+ ///
+ Constructor,
+
+ ///
+ /// An error occurred that prevents the read operation from continuing.
+ ///
+ Error,
+
+ ///
+ /// The end of the file has been reached successfully.
+ ///
+ Finished
+ }
+
+ // current Token data
+ private JsonToken _tokenType;
+ private object? _value;
+ internal char _quoteChar;
+ internal State _currentState;
+ private JsonPosition _currentPosition;
+ private CultureInfo? _culture;
+ private DateTimeZoneHandling _dateTimeZoneHandling;
+ private int? _maxDepth;
+ private bool _hasExceededMaxDepth;
+ internal DateParseHandling _dateParseHandling;
+ internal FloatParseHandling _floatParseHandling;
+ private string? _dateFormatString;
+ private List? _stack;
+
+ ///
+ /// Gets the current reader state.
+ ///
+ /// The current reader state.
+ protected State CurrentState => _currentState;
+
+ ///
+ /// Gets or sets a value indicating whether the source should be closed when this reader is closed.
+ ///
+ ///
+ /// true to close the source when this reader is closed; otherwise false . The default is true .
+ ///
+ public bool CloseInput { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether multiple pieces of JSON content can
+ /// be read from a continuous stream without erroring.
+ ///
+ ///
+ /// true to support reading multiple pieces of JSON content; otherwise false .
+ /// The default is false .
+ ///
+ public bool SupportMultipleContent { get; set; }
+
+ ///
+ /// Gets the quotation mark character used to enclose the value of a string.
+ ///
+ public virtual char QuoteChar
+ {
+ get => _quoteChar;
+ protected internal set => _quoteChar = value;
+ }
+
+ ///
+ /// Gets or sets how time zones are handled when reading JSON.
+ ///
+ public DateTimeZoneHandling DateTimeZoneHandling
+ {
+ get => _dateTimeZoneHandling;
+ set
+ {
+ if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _dateTimeZoneHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed when reading JSON.
+ ///
+ public DateParseHandling DateParseHandling
+ {
+ get => _dateParseHandling;
+ set
+ {
+ if (value < DateParseHandling.None ||
+#if HAVE_DATE_TIME_OFFSET
+ value > DateParseHandling.DateTimeOffset
+#else
+ value > DateParseHandling.DateTime
+#endif
+ )
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _dateParseHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how floating point numbers, e.g. 1.0 and 9.9, are parsed when reading JSON text.
+ ///
+ public FloatParseHandling FloatParseHandling
+ {
+ get => _floatParseHandling;
+ set
+ {
+ if (value < FloatParseHandling.Double || value > FloatParseHandling.Decimal)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _floatParseHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how custom date formatted strings are parsed when reading JSON.
+ ///
+ public string? DateFormatString
+ {
+ get => _dateFormatString;
+ set => _dateFormatString = value;
+ }
+
+ ///
+ /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a .
+ /// A null value means there is no maximum.
+ /// The default value is 128 .
+ ///
+ public int? MaxDepth
+ {
+ get => _maxDepth;
+ set
+ {
+ if (value <= 0)
+ {
+ throw new ArgumentException("Value must be positive.", nameof(value));
+ }
+
+ _maxDepth = value;
+ }
+ }
+
+ ///
+ /// Gets the type of the current JSON token.
+ ///
+ public virtual JsonToken TokenType => _tokenType;
+
+ ///
+ /// Gets the text value of the current JSON token.
+ ///
+ public virtual object? Value => _value;
+
+ ///
+ /// Gets the .NET type for the current JSON token.
+ ///
+ public virtual Type? ValueType => _value?.GetType();
+
+ ///
+ /// Gets the depth of the current token in the JSON document.
+ ///
+ /// The depth of the current token in the JSON document.
+ public virtual int Depth
+ {
+ get
+ {
+ int depth = _stack?.Count ?? 0;
+ if (JsonTokenUtils.IsStartToken(TokenType) || _currentPosition.Type == JsonContainerType.None)
+ {
+ return depth;
+ }
+ else
+ {
+ return depth + 1;
+ }
+ }
+ }
+
+ ///
+ /// Gets the path of the current JSON token.
+ ///
+ public virtual string Path
+ {
+ get
+ {
+ if (_currentPosition.Type == JsonContainerType.None)
+ {
+ return string.Empty;
+ }
+
+ bool insideContainer = (_currentState != State.ArrayStart
+ && _currentState != State.ConstructorStart
+ && _currentState != State.ObjectStart);
+
+ JsonPosition? current = insideContainer ? (JsonPosition?)_currentPosition : null;
+
+ return JsonPosition.BuildPath(_stack!, current);
+ }
+ }
+
+ ///
+ /// Gets or sets the culture used when reading JSON. Defaults to .
+ ///
+ public CultureInfo Culture
+ {
+ get => _culture ?? CultureInfo.InvariantCulture;
+ set => _culture = value;
+ }
+
+ internal JsonPosition GetPosition(int depth)
+ {
+ if (_stack != null && depth < _stack.Count)
+ {
+ return _stack[depth];
+ }
+
+ return _currentPosition;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ protected JsonReader()
+ {
+ _currentState = State.Start;
+ _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
+ _dateParseHandling = DateParseHandling.DateTime;
+ _floatParseHandling = FloatParseHandling.Double;
+ _maxDepth = 64;
+
+ CloseInput = true;
+ }
+
+ private void Push(JsonContainerType value)
+ {
+ UpdateScopeWithFinishedValue();
+
+ if (_currentPosition.Type == JsonContainerType.None)
+ {
+ _currentPosition = new JsonPosition(value);
+ }
+ else
+ {
+ if (_stack == null)
+ {
+ _stack = new List();
+ }
+
+ _stack.Add(_currentPosition);
+ _currentPosition = new JsonPosition(value);
+
+ // this is a little hacky because Depth increases when first property/value is written but only testing here is faster/simpler
+ if (_maxDepth != null && Depth + 1 > _maxDepth && !_hasExceededMaxDepth)
+ {
+ _hasExceededMaxDepth = true;
+ throw JsonReaderException.Create(this, "The reader's MaxDepth of {0} has been exceeded.".FormatWith(CultureInfo.InvariantCulture, _maxDepth));
+ }
+ }
+ }
+
+ private JsonContainerType Pop()
+ {
+ JsonPosition oldPosition;
+ if (_stack != null && _stack.Count > 0)
+ {
+ oldPosition = _currentPosition;
+ _currentPosition = _stack[_stack.Count - 1];
+ _stack.RemoveAt(_stack.Count - 1);
+ }
+ else
+ {
+ oldPosition = _currentPosition;
+ _currentPosition = new JsonPosition();
+ }
+
+ if (_maxDepth != null && Depth <= _maxDepth)
+ {
+ _hasExceededMaxDepth = false;
+ }
+
+ return oldPosition.Type;
+ }
+
+ private JsonContainerType Peek()
+ {
+ return _currentPosition.Type;
+ }
+
+ ///
+ /// Reads the next JSON token from the source.
+ ///
+ /// true if the next token was read successfully; false if there are no more tokens to read.
+ public abstract bool Read();
+
+ ///
+ /// Reads the next JSON token from the source as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public virtual int? ReadAsInt32()
+ {
+ JsonToken t = GetContentToken();
+
+ switch (t)
+ {
+ case JsonToken.None:
+ case JsonToken.Null:
+ case JsonToken.EndArray:
+ return null;
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ object v = Value!;
+ if (v is int i)
+ {
+ return i;
+ }
+
+#if HAVE_BIG_INTEGER
+ if (v is BigInteger value)
+ {
+ i = (int)value;
+ }
+ else
+#endif
+ {
+ try
+ {
+ i = Convert.ToInt32(v, CultureInfo.InvariantCulture);
+ }
+ catch (Exception ex)
+ {
+ // handle error for large integer overflow exceptions
+ throw JsonReaderException.Create(this, "Could not convert to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, v), ex);
+ }
+ }
+
+ SetToken(JsonToken.Integer, i, false);
+ return i;
+ case JsonToken.String:
+ string? s = (string?)Value;
+ return ReadInt32String(s);
+ }
+
+ throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
+ }
+
+ internal int? ReadInt32String(string? s)
+ {
+ if (StringUtils.IsNullOrEmpty(s))
+ {
+ SetToken(JsonToken.Null, null, false);
+ return null;
+ }
+
+ if (int.TryParse(s, NumberStyles.Integer, Culture, out int i))
+ {
+ SetToken(JsonToken.Integer, i, false);
+ return i;
+ }
+ else
+ {
+ SetToken(JsonToken.String, s, false);
+ throw JsonReaderException.Create(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
+ }
+ }
+
+ ///
+ /// Reads the next JSON token from the source as a .
+ ///
+ /// A . This method will return null at the end of an array.
+ public virtual string? ReadAsString()
+ {
+ JsonToken t = GetContentToken();
+
+ switch (t)
+ {
+ case JsonToken.None:
+ case JsonToken.Null:
+ case JsonToken.EndArray:
+ return null;
+ case JsonToken.String:
+ return (string?)Value;
+ }
+
+ if (JsonTokenUtils.IsPrimitiveToken(t))
+ {
+ object? v = Value;
+ if (v != null)
+ {
+ string s;
+ if (v is IFormattable formattable)
+ {
+ s = formattable.ToString(null, Culture);
+ }
+ else
+ {
+ s = v is Uri uri ? uri.OriginalString : v.ToString();
+ }
+
+ SetToken(JsonToken.String, s, false);
+ return s;
+ }
+ }
+
+ throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
+ }
+
+ ///
+ /// Reads the next JSON token from the source as a [].
+ ///
+ /// A [] or null if the next JSON token is null. This method will return null at the end of an array.
+ public virtual byte[]? ReadAsBytes()
+ {
+ JsonToken t = GetContentToken();
+
+ switch (t)
+ {
+ case JsonToken.StartObject:
+ {
+ ReadIntoWrappedTypeObject();
+
+ byte[]? data = ReadAsBytes();
+ ReaderReadAndAssert();
+
+ if (TokenType != JsonToken.EndObject)
+ {
+ throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+
+ SetToken(JsonToken.Bytes, data, false);
+ return data;
+ }
+ case JsonToken.String:
+ {
+ // attempt to convert possible base 64 or GUID string to bytes
+ // GUID has to have format 00000000-0000-0000-0000-000000000000
+ string s = (string)Value!;
+
+ byte[] data;
+
+ if (s.Length == 0)
+ {
+ data = CollectionUtils.ArrayEmpty();
+ }
+ else if (ConvertUtils.TryConvertGuid(s, out Guid g1))
+ {
+ data = g1.ToByteArray();
+ }
+ else
+ {
+ data = Convert.FromBase64String(s);
+ }
+
+ SetToken(JsonToken.Bytes, data, false);
+ return data;
+ }
+ case JsonToken.None:
+ case JsonToken.Null:
+ case JsonToken.EndArray:
+ return null;
+ case JsonToken.Bytes:
+ if (Value is Guid g2)
+ {
+ byte[] data = g2.ToByteArray();
+ SetToken(JsonToken.Bytes, data, false);
+ return data;
+ }
+
+ return (byte[]?)Value;
+ case JsonToken.StartArray:
+ return ReadArrayIntoByteArray();
+ }
+
+ throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
+ }
+
+ internal byte[] ReadArrayIntoByteArray()
+ {
+ List buffer = new List();
+
+ while (true)
+ {
+ if (!Read())
+ {
+ SetToken(JsonToken.None);
+ }
+
+ if (ReadArrayElementIntoByteArrayReportDone(buffer))
+ {
+ byte[] d = buffer.ToArray();
+ SetToken(JsonToken.Bytes, d, false);
+ return d;
+ }
+ }
+ }
+
+ private bool ReadArrayElementIntoByteArrayReportDone(List buffer)
+ {
+ switch (TokenType)
+ {
+ case JsonToken.None:
+ throw JsonReaderException.Create(this, "Unexpected end when reading bytes.");
+ case JsonToken.Integer:
+ buffer.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture));
+ return false;
+ case JsonToken.EndArray:
+ return true;
+ case JsonToken.Comment:
+ return false;
+ default:
+ throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+ }
+
+ ///
+ /// Reads the next JSON token from the source as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public virtual double? ReadAsDouble()
+ {
+ JsonToken t = GetContentToken();
+
+ switch (t)
+ {
+ case JsonToken.None:
+ case JsonToken.Null:
+ case JsonToken.EndArray:
+ return null;
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ object v = Value!;
+ if (v is double d)
+ {
+ return d;
+ }
+
+#if HAVE_BIG_INTEGER
+ if (v is BigInteger value)
+ {
+ d = (double)value;
+ }
+ else
+#endif
+ {
+ d = Convert.ToDouble(v, CultureInfo.InvariantCulture);
+ }
+
+ SetToken(JsonToken.Float, d, false);
+
+ return (double)d;
+ case JsonToken.String:
+ return ReadDoubleString((string?)Value);
+ }
+
+ throw JsonReaderException.Create(this, "Error reading double. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
+ }
+
+ internal double? ReadDoubleString(string? s)
+ {
+ if (StringUtils.IsNullOrEmpty(s))
+ {
+ SetToken(JsonToken.Null, null, false);
+ return null;
+ }
+
+ if (double.TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, Culture, out double d))
+ {
+ SetToken(JsonToken.Float, d, false);
+ return d;
+ }
+ else
+ {
+ SetToken(JsonToken.String, s, false);
+ throw JsonReaderException.Create(this, "Could not convert string to double: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
+ }
+ }
+
+ ///
+ /// Reads the next JSON token from the source as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public virtual bool? ReadAsBoolean()
+ {
+ JsonToken t = GetContentToken();
+
+ switch (t)
+ {
+ case JsonToken.None:
+ case JsonToken.Null:
+ case JsonToken.EndArray:
+ return null;
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ bool b;
+#if HAVE_BIG_INTEGER
+ if (Value is BigInteger integer)
+ {
+ b = integer != 0;
+ }
+ else
+#endif
+ {
+ b = Convert.ToBoolean(Value, CultureInfo.InvariantCulture);
+ }
+
+ SetToken(JsonToken.Boolean, b, false);
+ return b;
+ case JsonToken.String:
+ return ReadBooleanString((string?)Value);
+ case JsonToken.Boolean:
+ return (bool)Value!;
+ }
+
+ throw JsonReaderException.Create(this, "Error reading boolean. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
+ }
+
+ internal bool? ReadBooleanString(string? s)
+ {
+ if (StringUtils.IsNullOrEmpty(s))
+ {
+ SetToken(JsonToken.Null, null, false);
+ return null;
+ }
+
+ if (bool.TryParse(s, out bool b))
+ {
+ SetToken(JsonToken.Boolean, b, false);
+ return b;
+ }
+ else
+ {
+ SetToken(JsonToken.String, s, false);
+ throw JsonReaderException.Create(this, "Could not convert string to boolean: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
+ }
+ }
+
+ ///
+ /// Reads the next JSON token from the source as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public virtual decimal? ReadAsDecimal()
+ {
+ JsonToken t = GetContentToken();
+
+ switch (t)
+ {
+ case JsonToken.None:
+ case JsonToken.Null:
+ case JsonToken.EndArray:
+ return null;
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ object v = Value!;
+
+ if (v is decimal d)
+ {
+ return d;
+ }
+
+#if HAVE_BIG_INTEGER
+ if (v is BigInteger value)
+ {
+ d = (decimal)value;
+ }
+ else
+#endif
+ {
+ try
+ {
+ d = Convert.ToDecimal(v, CultureInfo.InvariantCulture);
+ }
+ catch (Exception ex)
+ {
+ // handle error for large integer overflow exceptions
+ throw JsonReaderException.Create(this, "Could not convert to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, v), ex);
+ }
+ }
+
+ SetToken(JsonToken.Float, d, false);
+ return d;
+ case JsonToken.String:
+ return ReadDecimalString((string?)Value);
+ }
+
+ throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
+ }
+
+ internal decimal? ReadDecimalString(string? s)
+ {
+ if (StringUtils.IsNullOrEmpty(s))
+ {
+ SetToken(JsonToken.Null, null, false);
+ return null;
+ }
+
+ if (decimal.TryParse(s, NumberStyles.Number, Culture, out decimal d))
+ {
+ SetToken(JsonToken.Float, d, false);
+ return d;
+ }
+ else if (ConvertUtils.DecimalTryParse(s.ToCharArray(), 0, s.Length, out d) == ParseResult.Success)
+ {
+ // This is to handle strings like "96.014e-05" that are not supported by traditional decimal.TryParse
+ SetToken(JsonToken.Float, d, false);
+ return d;
+ }
+ else
+ {
+ SetToken(JsonToken.String, s, false);
+ throw JsonReaderException.Create(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
+ }
+ }
+
+ ///
+ /// Reads the next JSON token from the source as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public virtual DateTime? ReadAsDateTime()
+ {
+ switch (GetContentToken())
+ {
+ case JsonToken.None:
+ case JsonToken.Null:
+ case JsonToken.EndArray:
+ return null;
+ case JsonToken.Date:
+#if HAVE_DATE_TIME_OFFSET
+ if (Value is DateTimeOffset offset)
+ {
+ SetToken(JsonToken.Date, offset.DateTime, false);
+ }
+#endif
+
+ return (DateTime)Value!;
+ case JsonToken.String:
+ return ReadDateTimeString((string?)Value);
+ }
+
+ throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+
+ internal DateTime? ReadDateTimeString(string? s)
+ {
+ if (StringUtils.IsNullOrEmpty(s))
+ {
+ SetToken(JsonToken.Null, null, false);
+ return null;
+ }
+
+ if (DateTimeUtils.TryParseDateTime(s, DateTimeZoneHandling, _dateFormatString, Culture, out DateTime dt))
+ {
+ dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
+ SetToken(JsonToken.Date, dt, false);
+ return dt;
+ }
+
+ if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
+ {
+ dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
+ SetToken(JsonToken.Date, dt, false);
+ return dt;
+ }
+
+ throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
+ }
+
+#if HAVE_DATE_TIME_OFFSET
+ ///
+ /// Reads the next JSON token from the source as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public virtual DateTimeOffset? ReadAsDateTimeOffset()
+ {
+ JsonToken t = GetContentToken();
+
+ switch (t)
+ {
+ case JsonToken.None:
+ case JsonToken.Null:
+ case JsonToken.EndArray:
+ return null;
+ case JsonToken.Date:
+ if (Value is DateTime time)
+ {
+ SetToken(JsonToken.Date, new DateTimeOffset(time), false);
+ }
+
+ return (DateTimeOffset)Value!;
+ case JsonToken.String:
+ string? s = (string?)Value;
+ return ReadDateTimeOffsetString(s);
+ default:
+ throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
+ }
+ }
+
+ internal DateTimeOffset? ReadDateTimeOffsetString(string? s)
+ {
+ if (StringUtils.IsNullOrEmpty(s))
+ {
+ SetToken(JsonToken.Null, null, false);
+ return null;
+ }
+
+ if (DateTimeUtils.TryParseDateTimeOffset(s, _dateFormatString, Culture, out DateTimeOffset dt))
+ {
+ SetToken(JsonToken.Date, dt, false);
+ return dt;
+ }
+
+ if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
+ {
+ SetToken(JsonToken.Date, dt, false);
+ return dt;
+ }
+
+ SetToken(JsonToken.String, s, false);
+ throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
+ }
+#endif
+
+ internal void ReaderReadAndAssert()
+ {
+ if (!Read())
+ {
+ throw CreateUnexpectedEndException();
+ }
+ }
+
+ internal JsonReaderException CreateUnexpectedEndException()
+ {
+ return JsonReaderException.Create(this, "Unexpected end when reading JSON.");
+ }
+
+ internal void ReadIntoWrappedTypeObject()
+ {
+ ReaderReadAndAssert();
+ if (Value != null && Value.ToString() == JsonTypeReflector.TypePropertyName)
+ {
+ ReaderReadAndAssert();
+ if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal))
+ {
+ ReaderReadAndAssert();
+ if (Value.ToString() == JsonTypeReflector.ValuePropertyName)
+ {
+ return;
+ }
+ }
+ }
+
+ throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
+ }
+
+ ///
+ /// Skips the children of the current token.
+ ///
+ public void Skip()
+ {
+ if (TokenType == JsonToken.PropertyName)
+ {
+ Read();
+ }
+
+ if (JsonTokenUtils.IsStartToken(TokenType))
+ {
+ int depth = Depth;
+
+ while (Read() && (depth < Depth))
+ {
+ }
+ }
+ }
+
+ ///
+ /// Sets the current token.
+ ///
+ /// The new token.
+ protected void SetToken(JsonToken newToken)
+ {
+ SetToken(newToken, null, true);
+ }
+
+ ///
+ /// Sets the current token and value.
+ ///
+ /// The new token.
+ /// The value.
+ protected void SetToken(JsonToken newToken, object? value)
+ {
+ SetToken(newToken, value, true);
+ }
+
+ ///
+ /// Sets the current token and value.
+ ///
+ /// The new token.
+ /// The value.
+ /// A flag indicating whether the position index inside an array should be updated.
+ protected void SetToken(JsonToken newToken, object? value, bool updateIndex)
+ {
+ _tokenType = newToken;
+ _value = value;
+
+ switch (newToken)
+ {
+ case JsonToken.StartObject:
+ _currentState = State.ObjectStart;
+ Push(JsonContainerType.Object);
+ break;
+ case JsonToken.StartArray:
+ _currentState = State.ArrayStart;
+ Push(JsonContainerType.Array);
+ break;
+ case JsonToken.StartConstructor:
+ _currentState = State.ConstructorStart;
+ Push(JsonContainerType.Constructor);
+ break;
+ case JsonToken.EndObject:
+ ValidateEnd(JsonToken.EndObject);
+ break;
+ case JsonToken.EndArray:
+ ValidateEnd(JsonToken.EndArray);
+ break;
+ case JsonToken.EndConstructor:
+ ValidateEnd(JsonToken.EndConstructor);
+ break;
+ case JsonToken.PropertyName:
+ _currentState = State.Property;
+
+ _currentPosition.PropertyName = (string)value!;
+ break;
+ case JsonToken.Undefined:
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ case JsonToken.Boolean:
+ case JsonToken.Null:
+ case JsonToken.Date:
+ case JsonToken.String:
+ case JsonToken.Raw:
+ case JsonToken.Bytes:
+ SetPostValueState(updateIndex);
+ break;
+ }
+ }
+
+ internal void SetPostValueState(bool updateIndex)
+ {
+ if (Peek() != JsonContainerType.None || SupportMultipleContent)
+ {
+ _currentState = State.PostValue;
+ }
+ else
+ {
+ SetFinished();
+ }
+
+ if (updateIndex)
+ {
+ UpdateScopeWithFinishedValue();
+ }
+ }
+
+ private void UpdateScopeWithFinishedValue()
+ {
+ if (_currentPosition.HasIndex)
+ {
+ _currentPosition.Position++;
+ }
+ }
+
+ private void ValidateEnd(JsonToken endToken)
+ {
+ JsonContainerType currentObject = Pop();
+
+ if (GetTypeForCloseToken(endToken) != currentObject)
+ {
+ throw JsonReaderException.Create(this, "JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, currentObject));
+ }
+
+ if (Peek() != JsonContainerType.None || SupportMultipleContent)
+ {
+ _currentState = State.PostValue;
+ }
+ else
+ {
+ SetFinished();
+ }
+ }
+
+ ///
+ /// Sets the state based on current token type.
+ ///
+ protected void SetStateBasedOnCurrent()
+ {
+ JsonContainerType currentObject = Peek();
+
+ switch (currentObject)
+ {
+ case JsonContainerType.Object:
+ _currentState = State.Object;
+ break;
+ case JsonContainerType.Array:
+ _currentState = State.Array;
+ break;
+ case JsonContainerType.Constructor:
+ _currentState = State.Constructor;
+ break;
+ case JsonContainerType.None:
+ SetFinished();
+ break;
+ default:
+ throw JsonReaderException.Create(this, "While setting the reader state back to current object an unexpected JsonType was encountered: {0}".FormatWith(CultureInfo.InvariantCulture, currentObject));
+ }
+ }
+
+ private void SetFinished()
+ {
+ _currentState = SupportMultipleContent ? State.Start : State.Finished;
+ }
+
+ private JsonContainerType GetTypeForCloseToken(JsonToken token)
+ {
+ switch (token)
+ {
+ case JsonToken.EndObject:
+ return JsonContainerType.Object;
+ case JsonToken.EndArray:
+ return JsonContainerType.Array;
+ case JsonToken.EndConstructor:
+ return JsonContainerType.Constructor;
+ default:
+ throw JsonReaderException.Create(this, "Not a valid close JsonToken: {0}".FormatWith(CultureInfo.InvariantCulture, token));
+ }
+ }
+
+ void IDisposable.Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources.
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_currentState != State.Closed && disposing)
+ {
+ Close();
+ }
+ }
+
+ ///
+ /// Changes the reader's state to .
+ /// If is set to true , the source is also closed.
+ ///
+ public virtual void Close()
+ {
+ _currentState = State.Closed;
+ _tokenType = JsonToken.None;
+ _value = null;
+ }
+
+ internal void ReadAndAssert()
+ {
+ if (!Read())
+ {
+ throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
+ }
+ }
+
+ internal void ReadForTypeAndAssert(JsonContract? contract, bool hasConverter)
+ {
+ if (!ReadForType(contract, hasConverter))
+ {
+ throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
+ }
+ }
+
+ internal bool ReadForType(JsonContract? contract, bool hasConverter)
+ {
+ // don't read properties with converters as a specific value
+ // the value might be a string which will then get converted which will error if read as date for example
+ if (hasConverter)
+ {
+ return Read();
+ }
+
+ ReadType t = contract?.InternalReadType ?? ReadType.Read;
+
+ switch (t)
+ {
+ case ReadType.Read:
+ return ReadAndMoveToContent();
+ case ReadType.ReadAsInt32:
+ ReadAsInt32();
+ break;
+ case ReadType.ReadAsInt64:
+ bool result = ReadAndMoveToContent();
+ if (TokenType == JsonToken.Undefined)
+ {
+ throw JsonReaderException.Create(this, "An undefined token is not a valid {0}.".FormatWith(CultureInfo.InvariantCulture, contract?.UnderlyingType ?? typeof(long)));
+ }
+ return result;
+ case ReadType.ReadAsDecimal:
+ ReadAsDecimal();
+ break;
+ case ReadType.ReadAsDouble:
+ ReadAsDouble();
+ break;
+ case ReadType.ReadAsBytes:
+ ReadAsBytes();
+ break;
+ case ReadType.ReadAsBoolean:
+ ReadAsBoolean();
+ break;
+ case ReadType.ReadAsString:
+ ReadAsString();
+ break;
+ case ReadType.ReadAsDateTime:
+ ReadAsDateTime();
+ break;
+#if HAVE_DATE_TIME_OFFSET
+ case ReadType.ReadAsDateTimeOffset:
+ ReadAsDateTimeOffset();
+ break;
+#endif
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ return (TokenType != JsonToken.None);
+ }
+
+ internal bool ReadAndMoveToContent()
+ {
+ return Read() && MoveToContent();
+ }
+
+ internal bool MoveToContent()
+ {
+ JsonToken t = TokenType;
+ while (t == JsonToken.None || t == JsonToken.Comment)
+ {
+ if (!Read())
+ {
+ return false;
+ }
+
+ t = TokenType;
+ }
+
+ return true;
+ }
+
+ private JsonToken GetContentToken()
+ {
+ JsonToken t;
+ do
+ {
+ if (!Read())
+ {
+ SetToken(JsonToken.None);
+ return JsonToken.None;
+ }
+ else
+ {
+ t = TokenType;
+ }
+ } while (t == JsonToken.Comment);
+
+ return t;
+ }
+ }
+}
diff --git a/Libs/Newtonsoft.Json.AOT/JsonReaderException.cs b/Libs/Newtonsoft.Json.AOT/JsonReaderException.cs
new file mode 100644
index 0000000..8a0ec38
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonReaderException.cs
@@ -0,0 +1,148 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Globalization;
+using System.Runtime.Serialization;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// The exception thrown when an error occurs while reading JSON text.
+ ///
+#if HAVE_BINARY_EXCEPTION_SERIALIZATION
+ [Serializable]
+#endif
+ public class JsonReaderException : JsonException
+ {
+ ///
+ /// Gets the line number indicating where the error occurred.
+ ///
+ /// The line number indicating where the error occurred.
+ public int LineNumber { get; }
+
+ ///
+ /// Gets the line position indicating where the error occurred.
+ ///
+ /// The line position indicating where the error occurred.
+ public int LinePosition { get; }
+
+ ///
+ /// Gets the path to the JSON where the error occurred.
+ ///
+ /// The path to the JSON where the error occurred.
+ public string? Path { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public JsonReaderException()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message.
+ ///
+ /// The error message that explains the reason for the exception.
+ public JsonReaderException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The error message that explains the reason for the exception.
+ /// The exception that is the cause of the current exception, or null if no inner exception is specified.
+ public JsonReaderException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+#if HAVE_BINARY_EXCEPTION_SERIALIZATION
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The that holds the serialized object data about the exception being thrown.
+ /// The that contains contextual information about the source or destination.
+ /// The parameter is null .
+ /// The class name is null or is zero (0).
+ public JsonReaderException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+#endif
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message, JSON path, line number, line position, and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The error message that explains the reason for the exception.
+ /// The path to the JSON where the error occurred.
+ /// The line number indicating where the error occurred.
+ /// The line position indicating where the error occurred.
+ /// The exception that is the cause of the current exception, or null if no inner exception is specified.
+ public JsonReaderException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
+ : base(message, innerException)
+ {
+ Path = path;
+ LineNumber = lineNumber;
+ LinePosition = linePosition;
+ }
+
+ internal static JsonReaderException Create(JsonReader reader, string message)
+ {
+ return Create(reader, message, null);
+ }
+
+ internal static JsonReaderException Create(JsonReader reader, string message, Exception? ex)
+ {
+ return Create(reader as IJsonLineInfo, reader.Path, message, ex);
+ }
+
+ internal static JsonReaderException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex)
+ {
+ message = JsonPosition.FormatMessage(lineInfo, path, message);
+
+ int lineNumber;
+ int linePosition;
+ if (lineInfo != null && lineInfo.HasLineInfo())
+ {
+ lineNumber = lineInfo.LineNumber;
+ linePosition = lineInfo.LinePosition;
+ }
+ else
+ {
+ lineNumber = 0;
+ linePosition = 0;
+ }
+
+ return new JsonReaderException(message, path, lineNumber, linePosition, ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonRequiredAttribute.cs b/Libs/Newtonsoft.Json.AOT/JsonRequiredAttribute.cs
new file mode 100644
index 0000000..98606b7
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonRequiredAttribute.cs
@@ -0,0 +1,39 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Instructs the to always serialize the member, and to require that the member has a value.
+ ///
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
+ public sealed class JsonRequiredAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonSerializationException.cs b/Libs/Newtonsoft.Json.AOT/JsonSerializationException.cs
new file mode 100644
index 0000000..8c44980
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonSerializationException.cs
@@ -0,0 +1,148 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// The exception thrown when an error occurs during JSON serialization or deserialization.
+ ///
+#if HAVE_BINARY_EXCEPTION_SERIALIZATION
+ [Serializable]
+#endif
+ public class JsonSerializationException : JsonException
+ {
+ ///
+ /// Gets the line number indicating where the error occurred.
+ ///
+ /// The line number indicating where the error occurred.
+ public int LineNumber { get; }
+
+ ///
+ /// Gets the line position indicating where the error occurred.
+ ///
+ /// The line position indicating where the error occurred.
+ public int LinePosition { get; }
+
+ ///
+ /// Gets the path to the JSON where the error occurred.
+ ///
+ /// The path to the JSON where the error occurred.
+ public string? Path { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public JsonSerializationException()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message.
+ ///
+ /// The error message that explains the reason for the exception.
+ public JsonSerializationException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The error message that explains the reason for the exception.
+ /// The exception that is the cause of the current exception, or null if no inner exception is specified.
+ public JsonSerializationException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+#if HAVE_BINARY_EXCEPTION_SERIALIZATION
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The that holds the serialized object data about the exception being thrown.
+ /// The that contains contextual information about the source or destination.
+ /// The parameter is null .
+ /// The class name is null or is zero (0).
+ public JsonSerializationException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+#endif
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message, JSON path, line number, line position, and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The error message that explains the reason for the exception.
+ /// The path to the JSON where the error occurred.
+ /// The line number indicating where the error occurred.
+ /// The line position indicating where the error occurred.
+ /// The exception that is the cause of the current exception, or null if no inner exception is specified.
+ public JsonSerializationException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
+ : base(message, innerException)
+ {
+ Path = path;
+ LineNumber = lineNumber;
+ LinePosition = linePosition;
+ }
+
+ internal static JsonSerializationException Create(JsonReader reader, string message)
+ {
+ return Create(reader, message, null);
+ }
+
+ internal static JsonSerializationException Create(JsonReader reader, string message, Exception? ex)
+ {
+ return Create(reader as IJsonLineInfo, reader.Path, message, ex);
+ }
+
+ internal static JsonSerializationException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex)
+ {
+ message = JsonPosition.FormatMessage(lineInfo, path, message);
+
+ int lineNumber;
+ int linePosition;
+ if (lineInfo != null && lineInfo.HasLineInfo())
+ {
+ lineNumber = lineInfo.LineNumber;
+ linePosition = lineInfo.LinePosition;
+ }
+ else
+ {
+ lineNumber = 0;
+ linePosition = 0;
+ }
+
+ return new JsonSerializationException(message, path, lineNumber, linePosition, ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonSerializer.cs b/Libs/Newtonsoft.Json.AOT/JsonSerializer.cs
new file mode 100644
index 0000000..aab727f
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonSerializer.cs
@@ -0,0 +1,1226 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Runtime.Serialization.Formatters;
+using LC.Newtonsoft.Json.Converters;
+using LC.Newtonsoft.Json.Serialization;
+using LC.Newtonsoft.Json.Utilities;
+using System.Runtime.Serialization;
+using ErrorEventArgs = LC.Newtonsoft.Json.Serialization.ErrorEventArgs;
+using System.Runtime.CompilerServices;
+using System.Diagnostics.CodeAnalysis;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Serializes and deserializes objects into and from the JSON format.
+ /// The enables you to control how objects are encoded into JSON.
+ ///
+ public class JsonSerializer
+ {
+ internal TypeNameHandling _typeNameHandling;
+ internal TypeNameAssemblyFormatHandling _typeNameAssemblyFormatHandling;
+ internal PreserveReferencesHandling _preserveReferencesHandling;
+ internal ReferenceLoopHandling _referenceLoopHandling;
+ internal MissingMemberHandling _missingMemberHandling;
+ internal ObjectCreationHandling _objectCreationHandling;
+ internal NullValueHandling _nullValueHandling;
+ internal DefaultValueHandling _defaultValueHandling;
+ internal ConstructorHandling _constructorHandling;
+ internal MetadataPropertyHandling _metadataPropertyHandling;
+ internal JsonConverterCollection? _converters;
+ internal IContractResolver _contractResolver;
+ internal ITraceWriter? _traceWriter;
+ internal IEqualityComparer? _equalityComparer;
+ internal ISerializationBinder _serializationBinder;
+ internal StreamingContext _context;
+ private IReferenceResolver? _referenceResolver;
+
+ private Formatting? _formatting;
+ private DateFormatHandling? _dateFormatHandling;
+ private DateTimeZoneHandling? _dateTimeZoneHandling;
+ private DateParseHandling? _dateParseHandling;
+ private FloatFormatHandling? _floatFormatHandling;
+ private FloatParseHandling? _floatParseHandling;
+ private StringEscapeHandling? _stringEscapeHandling;
+ private CultureInfo _culture;
+ private int? _maxDepth;
+ private bool _maxDepthSet;
+ private bool? _checkAdditionalContent;
+ private string? _dateFormatString;
+ private bool _dateFormatStringSet;
+
+ ///
+ /// Occurs when the errors during serialization and deserialization.
+ ///
+ public virtual event EventHandler? Error;
+
+ ///
+ /// Gets or sets the used by the serializer when resolving references.
+ ///
+ public virtual IReferenceResolver? ReferenceResolver
+ {
+ get => GetReferenceResolver();
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value), "Reference resolver cannot be null.");
+ }
+
+ _referenceResolver = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the used by the serializer when resolving type names.
+ ///
+ [Obsolete("Binder is obsolete. Use SerializationBinder instead.")]
+ public virtual SerializationBinder Binder
+ {
+ get
+ {
+ if (_serializationBinder is SerializationBinder legacySerializationBinder)
+ {
+ return legacySerializationBinder;
+ }
+
+ if (_serializationBinder is SerializationBinderAdapter adapter)
+ {
+ return adapter.SerializationBinder;
+ }
+
+ throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set.");
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value), "Serialization binder cannot be null.");
+ }
+
+ _serializationBinder = value as ISerializationBinder ?? new SerializationBinderAdapter(value);
+ }
+ }
+
+ ///
+ /// Gets or sets the used by the serializer when resolving type names.
+ ///
+ public virtual ISerializationBinder SerializationBinder
+ {
+ get => _serializationBinder;
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value), "Serialization binder cannot be null.");
+ }
+
+ _serializationBinder = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the used by the serializer when writing trace messages.
+ ///
+ /// The trace writer.
+ public virtual ITraceWriter? TraceWriter
+ {
+ get => _traceWriter;
+ set => _traceWriter = value;
+ }
+
+ ///
+ /// Gets or sets the equality comparer used by the serializer when comparing references.
+ ///
+ /// The equality comparer.
+ public virtual IEqualityComparer? EqualityComparer
+ {
+ get => _equalityComparer;
+ set => _equalityComparer = value;
+ }
+
+ ///
+ /// Gets or sets how type name writing and reading is handled by the serializer.
+ /// The default value is .
+ ///
+ ///
+ /// should be used with caution when your application deserializes JSON from an external source.
+ /// Incoming types should be validated with a custom
+ /// when deserializing with a value other than .
+ ///
+ public virtual TypeNameHandling TypeNameHandling
+ {
+ get => _typeNameHandling;
+ set
+ {
+ if (value < TypeNameHandling.None || value > TypeNameHandling.Auto)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _typeNameHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how a type name assembly is written and resolved by the serializer.
+ /// The default value is .
+ ///
+ /// The type name assembly format.
+ [Obsolete("TypeNameAssemblyFormat is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
+ public virtual FormatterAssemblyStyle TypeNameAssemblyFormat
+ {
+ get => (FormatterAssemblyStyle)_typeNameAssemblyFormatHandling;
+ set
+ {
+ if (value < FormatterAssemblyStyle.Simple || value > FormatterAssemblyStyle.Full)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _typeNameAssemblyFormatHandling = (TypeNameAssemblyFormatHandling)value;
+ }
+ }
+
+ ///
+ /// Gets or sets how a type name assembly is written and resolved by the serializer.
+ /// The default value is .
+ ///
+ /// The type name assembly format.
+ public virtual TypeNameAssemblyFormatHandling TypeNameAssemblyFormatHandling
+ {
+ get => _typeNameAssemblyFormatHandling;
+ set
+ {
+ if (value < TypeNameAssemblyFormatHandling.Simple || value > TypeNameAssemblyFormatHandling.Full)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _typeNameAssemblyFormatHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how object references are preserved by the serializer.
+ /// The default value is .
+ ///
+ public virtual PreserveReferencesHandling PreserveReferencesHandling
+ {
+ get => _preserveReferencesHandling;
+ set
+ {
+ if (value < PreserveReferencesHandling.None || value > PreserveReferencesHandling.All)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _preserveReferencesHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how reference loops (e.g. a class referencing itself) is handled.
+ /// The default value is .
+ ///
+ public virtual ReferenceLoopHandling ReferenceLoopHandling
+ {
+ get => _referenceLoopHandling;
+ set
+ {
+ if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _referenceLoopHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization.
+ /// The default value is .
+ ///
+ public virtual MissingMemberHandling MissingMemberHandling
+ {
+ get => _missingMemberHandling;
+ set
+ {
+ if (value < MissingMemberHandling.Ignore || value > MissingMemberHandling.Error)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _missingMemberHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how null values are handled during serialization and deserialization.
+ /// The default value is .
+ ///
+ public virtual NullValueHandling NullValueHandling
+ {
+ get => _nullValueHandling;
+ set
+ {
+ if (value < NullValueHandling.Include || value > NullValueHandling.Ignore)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _nullValueHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how default values are handled during serialization and deserialization.
+ /// The default value is .
+ ///
+ public virtual DefaultValueHandling DefaultValueHandling
+ {
+ get => _defaultValueHandling;
+ set
+ {
+ if (value < DefaultValueHandling.Include || value > DefaultValueHandling.IgnoreAndPopulate)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _defaultValueHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how objects are created during deserialization.
+ /// The default value is .
+ ///
+ /// The object creation handling.
+ public virtual ObjectCreationHandling ObjectCreationHandling
+ {
+ get => _objectCreationHandling;
+ set
+ {
+ if (value < ObjectCreationHandling.Auto || value > ObjectCreationHandling.Replace)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _objectCreationHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how constructors are used during deserialization.
+ /// The default value is .
+ ///
+ /// The constructor handling.
+ public virtual ConstructorHandling ConstructorHandling
+ {
+ get => _constructorHandling;
+ set
+ {
+ if (value < ConstructorHandling.Default || value > ConstructorHandling.AllowNonPublicDefaultConstructor)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _constructorHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how metadata properties are used during deserialization.
+ /// The default value is .
+ ///
+ /// The metadata properties handling.
+ public virtual MetadataPropertyHandling MetadataPropertyHandling
+ {
+ get => _metadataPropertyHandling;
+ set
+ {
+ if (value < MetadataPropertyHandling.Default || value > MetadataPropertyHandling.Ignore)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _metadataPropertyHandling = value;
+ }
+ }
+
+ ///
+ /// Gets a collection that will be used during serialization.
+ ///
+ /// Collection that will be used during serialization.
+ public virtual JsonConverterCollection Converters
+ {
+ get
+ {
+ if (_converters == null)
+ {
+ _converters = new JsonConverterCollection();
+ }
+
+ return _converters;
+ }
+ }
+
+ ///
+ /// Gets or sets the contract resolver used by the serializer when
+ /// serializing .NET objects to JSON and vice versa.
+ ///
+ public virtual IContractResolver ContractResolver
+ {
+ get => _contractResolver;
+ set => _contractResolver = value ?? DefaultContractResolver.Instance;
+ }
+
+ ///
+ /// Gets or sets the used by the serializer when invoking serialization callback methods.
+ ///
+ /// The context.
+ public virtual StreamingContext Context
+ {
+ get => _context;
+ set => _context = value;
+ }
+
+ ///
+ /// Indicates how JSON text output is formatted.
+ /// The default value is .
+ ///
+ public virtual Formatting Formatting
+ {
+ get => _formatting ?? JsonSerializerSettings.DefaultFormatting;
+ set => _formatting = value;
+ }
+
+ ///
+ /// Gets or sets how dates are written to JSON text.
+ /// The default value is .
+ ///
+ public virtual DateFormatHandling DateFormatHandling
+ {
+ get => _dateFormatHandling ?? JsonSerializerSettings.DefaultDateFormatHandling;
+ set => _dateFormatHandling = value;
+ }
+
+ ///
+ /// Gets or sets how time zones are handled during serialization and deserialization.
+ /// The default value is .
+ ///
+ public virtual DateTimeZoneHandling DateTimeZoneHandling
+ {
+ get => _dateTimeZoneHandling ?? JsonSerializerSettings.DefaultDateTimeZoneHandling;
+ set => _dateTimeZoneHandling = value;
+ }
+
+ ///
+ /// Gets or sets how date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z" , are parsed when reading JSON.
+ /// The default value is .
+ ///
+ public virtual DateParseHandling DateParseHandling
+ {
+ get => _dateParseHandling ?? JsonSerializerSettings.DefaultDateParseHandling;
+ set => _dateParseHandling = value;
+ }
+
+ ///
+ /// Gets or sets how floating point numbers, e.g. 1.0 and 9.9, are parsed when reading JSON text.
+ /// The default value is .
+ ///
+ public virtual FloatParseHandling FloatParseHandling
+ {
+ get => _floatParseHandling ?? JsonSerializerSettings.DefaultFloatParseHandling;
+ set => _floatParseHandling = value;
+ }
+
+ ///
+ /// Gets or sets how special floating point numbers, e.g. ,
+ /// and ,
+ /// are written as JSON text.
+ /// The default value is .
+ ///
+ public virtual FloatFormatHandling FloatFormatHandling
+ {
+ get => _floatFormatHandling ?? JsonSerializerSettings.DefaultFloatFormatHandling;
+ set => _floatFormatHandling = value;
+ }
+
+ ///
+ /// Gets or sets how strings are escaped when writing JSON text.
+ /// The default value is .
+ ///
+ public virtual StringEscapeHandling StringEscapeHandling
+ {
+ get => _stringEscapeHandling ?? JsonSerializerSettings.DefaultStringEscapeHandling;
+ set => _stringEscapeHandling = value;
+ }
+
+ ///
+ /// Gets or sets how and values are formatted when writing JSON text,
+ /// and the expected date format when reading JSON text.
+ /// The default value is "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK" .
+ ///
+ public virtual string DateFormatString
+ {
+ get => _dateFormatString ?? JsonSerializerSettings.DefaultDateFormatString;
+ set
+ {
+ _dateFormatString = value;
+ _dateFormatStringSet = true;
+ }
+ }
+
+ ///
+ /// Gets or sets the culture used when reading JSON.
+ /// The default value is .
+ ///
+ public virtual CultureInfo Culture
+ {
+ get => _culture ?? JsonSerializerSettings.DefaultCulture;
+ set => _culture = value;
+ }
+
+ ///
+ /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a .
+ /// A null value means there is no maximum.
+ /// The default value is 128 .
+ ///
+ public virtual int? MaxDepth
+ {
+ get => _maxDepth;
+ set
+ {
+ if (value <= 0)
+ {
+ throw new ArgumentException("Value must be positive.", nameof(value));
+ }
+
+ _maxDepth = value;
+ _maxDepthSet = true;
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether there will be a check for additional JSON content after deserializing an object.
+ /// The default value is false .
+ ///
+ ///
+ /// true if there will be a check for additional JSON content after deserializing an object; otherwise, false .
+ ///
+ public virtual bool CheckAdditionalContent
+ {
+ get => _checkAdditionalContent ?? JsonSerializerSettings.DefaultCheckAdditionalContent;
+ set => _checkAdditionalContent = value;
+ }
+
+ internal bool IsCheckAdditionalContentSet()
+ {
+ return (_checkAdditionalContent != null);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public JsonSerializer()
+ {
+ _referenceLoopHandling = JsonSerializerSettings.DefaultReferenceLoopHandling;
+ _missingMemberHandling = JsonSerializerSettings.DefaultMissingMemberHandling;
+ _nullValueHandling = JsonSerializerSettings.DefaultNullValueHandling;
+ _defaultValueHandling = JsonSerializerSettings.DefaultDefaultValueHandling;
+ _objectCreationHandling = JsonSerializerSettings.DefaultObjectCreationHandling;
+ _preserveReferencesHandling = JsonSerializerSettings.DefaultPreserveReferencesHandling;
+ _constructorHandling = JsonSerializerSettings.DefaultConstructorHandling;
+ _typeNameHandling = JsonSerializerSettings.DefaultTypeNameHandling;
+ _metadataPropertyHandling = JsonSerializerSettings.DefaultMetadataPropertyHandling;
+ _context = JsonSerializerSettings.DefaultContext;
+ _serializationBinder = DefaultSerializationBinder.Instance;
+
+ _culture = JsonSerializerSettings.DefaultCulture;
+ _contractResolver = DefaultContractResolver.Instance;
+ }
+
+ ///
+ /// Creates a new instance.
+ /// The will not use default settings
+ /// from .
+ ///
+ ///
+ /// A new instance.
+ /// The will not use default settings
+ /// from .
+ ///
+ public static JsonSerializer Create()
+ {
+ return new JsonSerializer();
+ }
+
+ ///
+ /// Creates a new instance using the specified .
+ /// The will not use default settings
+ /// from .
+ ///
+ /// The settings to be applied to the .
+ ///
+ /// A new instance using the specified .
+ /// The will not use default settings
+ /// from .
+ ///
+ public static JsonSerializer Create(JsonSerializerSettings? settings)
+ {
+ JsonSerializer serializer = Create();
+
+ if (settings != null)
+ {
+ ApplySerializerSettings(serializer, settings);
+ }
+
+ return serializer;
+ }
+
+ ///
+ /// Creates a new instance.
+ /// The will use default settings
+ /// from .
+ ///
+ ///
+ /// A new instance.
+ /// The will use default settings
+ /// from .
+ ///
+ public static JsonSerializer CreateDefault()
+ {
+ // copy static to local variable to avoid concurrency issues
+ JsonSerializerSettings? defaultSettings = JsonConvert.DefaultSettings?.Invoke();
+
+ return Create(defaultSettings);
+ }
+
+ ///
+ /// Creates a new instance using the specified .
+ /// The will use default settings
+ /// from as well as the specified .
+ ///
+ /// The settings to be applied to the .
+ ///
+ /// A new instance using the specified .
+ /// The will use default settings
+ /// from as well as the specified .
+ ///
+ public static JsonSerializer CreateDefault(JsonSerializerSettings? settings)
+ {
+ JsonSerializer serializer = CreateDefault();
+ if (settings != null)
+ {
+ ApplySerializerSettings(serializer, settings);
+ }
+
+ return serializer;
+ }
+
+ private static void ApplySerializerSettings(JsonSerializer serializer, JsonSerializerSettings settings)
+ {
+ if (!CollectionUtils.IsNullOrEmpty(settings.Converters))
+ {
+ // insert settings converters at the beginning so they take precedence
+ // if user wants to remove one of the default converters they will have to do it manually
+ for (int i = 0; i < settings.Converters.Count; i++)
+ {
+ serializer.Converters.Insert(i, settings.Converters[i]);
+ }
+ }
+
+ // serializer specific
+ if (settings._typeNameHandling != null)
+ {
+ serializer.TypeNameHandling = settings.TypeNameHandling;
+ }
+ if (settings._metadataPropertyHandling != null)
+ {
+ serializer.MetadataPropertyHandling = settings.MetadataPropertyHandling;
+ }
+ if (settings._typeNameAssemblyFormatHandling != null)
+ {
+ serializer.TypeNameAssemblyFormatHandling = settings.TypeNameAssemblyFormatHandling;
+ }
+ if (settings._preserveReferencesHandling != null)
+ {
+ serializer.PreserveReferencesHandling = settings.PreserveReferencesHandling;
+ }
+ if (settings._referenceLoopHandling != null)
+ {
+ serializer.ReferenceLoopHandling = settings.ReferenceLoopHandling;
+ }
+ if (settings._missingMemberHandling != null)
+ {
+ serializer.MissingMemberHandling = settings.MissingMemberHandling;
+ }
+ if (settings._objectCreationHandling != null)
+ {
+ serializer.ObjectCreationHandling = settings.ObjectCreationHandling;
+ }
+ if (settings._nullValueHandling != null)
+ {
+ serializer.NullValueHandling = settings.NullValueHandling;
+ }
+ if (settings._defaultValueHandling != null)
+ {
+ serializer.DefaultValueHandling = settings.DefaultValueHandling;
+ }
+ if (settings._constructorHandling != null)
+ {
+ serializer.ConstructorHandling = settings.ConstructorHandling;
+ }
+ if (settings._context != null)
+ {
+ serializer.Context = settings.Context;
+ }
+ if (settings._checkAdditionalContent != null)
+ {
+ serializer._checkAdditionalContent = settings._checkAdditionalContent;
+ }
+
+ if (settings.Error != null)
+ {
+ serializer.Error += settings.Error;
+ }
+
+ if (settings.ContractResolver != null)
+ {
+ serializer.ContractResolver = settings.ContractResolver;
+ }
+ if (settings.ReferenceResolverProvider != null)
+ {
+ serializer.ReferenceResolver = settings.ReferenceResolverProvider();
+ }
+ if (settings.TraceWriter != null)
+ {
+ serializer.TraceWriter = settings.TraceWriter;
+ }
+ if (settings.EqualityComparer != null)
+ {
+ serializer.EqualityComparer = settings.EqualityComparer;
+ }
+ if (settings.SerializationBinder != null)
+ {
+ serializer.SerializationBinder = settings.SerializationBinder;
+ }
+
+ // reader/writer specific
+ // unset values won't override reader/writer set values
+ if (settings._formatting != null)
+ {
+ serializer._formatting = settings._formatting;
+ }
+ if (settings._dateFormatHandling != null)
+ {
+ serializer._dateFormatHandling = settings._dateFormatHandling;
+ }
+ if (settings._dateTimeZoneHandling != null)
+ {
+ serializer._dateTimeZoneHandling = settings._dateTimeZoneHandling;
+ }
+ if (settings._dateParseHandling != null)
+ {
+ serializer._dateParseHandling = settings._dateParseHandling;
+ }
+ if (settings._dateFormatStringSet)
+ {
+ serializer._dateFormatString = settings._dateFormatString;
+ serializer._dateFormatStringSet = settings._dateFormatStringSet;
+ }
+ if (settings._floatFormatHandling != null)
+ {
+ serializer._floatFormatHandling = settings._floatFormatHandling;
+ }
+ if (settings._floatParseHandling != null)
+ {
+ serializer._floatParseHandling = settings._floatParseHandling;
+ }
+ if (settings._stringEscapeHandling != null)
+ {
+ serializer._stringEscapeHandling = settings._stringEscapeHandling;
+ }
+ if (settings._culture != null)
+ {
+ serializer._culture = settings._culture;
+ }
+ if (settings._maxDepthSet)
+ {
+ serializer._maxDepth = settings._maxDepth;
+ serializer._maxDepthSet = settings._maxDepthSet;
+ }
+ }
+
+ ///
+ /// Populates the JSON values onto the target object.
+ ///
+ /// The that contains the JSON structure to read values from.
+ /// The target object to populate values onto.
+ [DebuggerStepThrough]
+ public void Populate(TextReader reader, object target)
+ {
+ Populate(new JsonTextReader(reader), target);
+ }
+
+ ///
+ /// Populates the JSON values onto the target object.
+ ///
+ /// The that contains the JSON structure to read values from.
+ /// The target object to populate values onto.
+ [DebuggerStepThrough]
+ public void Populate(JsonReader reader, object target)
+ {
+ PopulateInternal(reader, target);
+ }
+
+ internal virtual void PopulateInternal(JsonReader reader, object target)
+ {
+ ValidationUtils.ArgumentNotNull(reader, nameof(reader));
+ ValidationUtils.ArgumentNotNull(target, nameof(target));
+
+ SetupReader(
+ reader,
+ out CultureInfo? previousCulture,
+ out DateTimeZoneHandling? previousDateTimeZoneHandling,
+ out DateParseHandling? previousDateParseHandling,
+ out FloatParseHandling? previousFloatParseHandling,
+ out int? previousMaxDepth,
+ out string? previousDateFormatString);
+
+ TraceJsonReader? traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
+ ? CreateTraceJsonReader(reader)
+ : null;
+
+ JsonSerializerInternalReader serializerReader = new JsonSerializerInternalReader(this);
+ serializerReader.Populate(traceJsonReader ?? reader, target);
+
+ if (traceJsonReader != null)
+ {
+ TraceWriter!.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
+ }
+
+ ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
+ }
+
+ ///
+ /// Deserializes the JSON structure contained by the specified .
+ ///
+ /// The that contains the JSON structure to deserialize.
+ /// The being deserialized.
+ [DebuggerStepThrough]
+ public object? Deserialize(JsonReader reader)
+ {
+ return Deserialize(reader, null);
+ }
+
+ ///
+ /// Deserializes the JSON structure contained by the specified
+ /// into an instance of the specified type.
+ ///
+ /// The containing the object.
+ /// The of object being deserialized.
+ /// The instance of being deserialized.
+ [DebuggerStepThrough]
+ public object? Deserialize(TextReader reader, Type objectType)
+ {
+ return Deserialize(new JsonTextReader(reader), objectType);
+ }
+
+ ///
+ /// Deserializes the JSON structure contained by the specified
+ /// into an instance of the specified type.
+ ///
+ /// The containing the object.
+ /// The type of the object to deserialize.
+ /// The instance of being deserialized.
+ [DebuggerStepThrough]
+ public T? Deserialize(JsonReader reader)
+ {
+ return (T?)Deserialize(reader, typeof(T));
+ }
+
+ ///
+ /// Deserializes the JSON structure contained by the specified
+ /// into an instance of the specified type.
+ ///
+ /// The containing the object.
+ /// The of object being deserialized.
+ /// The instance of being deserialized.
+ [DebuggerStepThrough]
+ public object? Deserialize(JsonReader reader, Type? objectType)
+ {
+ return DeserializeInternal(reader, objectType);
+ }
+
+ internal virtual object? DeserializeInternal(JsonReader reader, Type? objectType)
+ {
+ ValidationUtils.ArgumentNotNull(reader, nameof(reader));
+
+ SetupReader(
+ reader,
+ out CultureInfo? previousCulture,
+ out DateTimeZoneHandling? previousDateTimeZoneHandling,
+ out DateParseHandling? previousDateParseHandling,
+ out FloatParseHandling? previousFloatParseHandling,
+ out int? previousMaxDepth,
+ out string? previousDateFormatString);
+
+ TraceJsonReader? traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
+ ? CreateTraceJsonReader(reader)
+ : null;
+
+ JsonSerializerInternalReader serializerReader = new JsonSerializerInternalReader(this);
+ object? value = serializerReader.Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent);
+
+ if (traceJsonReader != null)
+ {
+ TraceWriter!.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
+ }
+
+ ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
+
+ return value;
+ }
+
+ private void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString)
+ {
+ if (_culture != null && !_culture.Equals(reader.Culture))
+ {
+ previousCulture = reader.Culture;
+ reader.Culture = _culture;
+ }
+ else
+ {
+ previousCulture = null;
+ }
+
+ if (_dateTimeZoneHandling != null && reader.DateTimeZoneHandling != _dateTimeZoneHandling)
+ {
+ previousDateTimeZoneHandling = reader.DateTimeZoneHandling;
+ reader.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
+ }
+ else
+ {
+ previousDateTimeZoneHandling = null;
+ }
+
+ if (_dateParseHandling != null && reader.DateParseHandling != _dateParseHandling)
+ {
+ previousDateParseHandling = reader.DateParseHandling;
+ reader.DateParseHandling = _dateParseHandling.GetValueOrDefault();
+ }
+ else
+ {
+ previousDateParseHandling = null;
+ }
+
+ if (_floatParseHandling != null && reader.FloatParseHandling != _floatParseHandling)
+ {
+ previousFloatParseHandling = reader.FloatParseHandling;
+ reader.FloatParseHandling = _floatParseHandling.GetValueOrDefault();
+ }
+ else
+ {
+ previousFloatParseHandling = null;
+ }
+
+ if (_maxDepthSet && reader.MaxDepth != _maxDepth)
+ {
+ previousMaxDepth = reader.MaxDepth;
+ reader.MaxDepth = _maxDepth;
+ }
+ else
+ {
+ previousMaxDepth = null;
+ }
+
+ if (_dateFormatStringSet && reader.DateFormatString != _dateFormatString)
+ {
+ previousDateFormatString = reader.DateFormatString;
+ reader.DateFormatString = _dateFormatString;
+ }
+ else
+ {
+ previousDateFormatString = null;
+ }
+
+ if (reader is JsonTextReader textReader)
+ {
+ if (textReader.PropertyNameTable == null && _contractResolver is DefaultContractResolver resolver)
+ {
+ textReader.PropertyNameTable = resolver.GetNameTable();
+ }
+ }
+ }
+
+ private void ResetReader(JsonReader reader, CultureInfo? previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string? previousDateFormatString)
+ {
+ // reset reader back to previous options
+ if (previousCulture != null)
+ {
+ reader.Culture = previousCulture;
+ }
+ if (previousDateTimeZoneHandling != null)
+ {
+ reader.DateTimeZoneHandling = previousDateTimeZoneHandling.GetValueOrDefault();
+ }
+ if (previousDateParseHandling != null)
+ {
+ reader.DateParseHandling = previousDateParseHandling.GetValueOrDefault();
+ }
+ if (previousFloatParseHandling != null)
+ {
+ reader.FloatParseHandling = previousFloatParseHandling.GetValueOrDefault();
+ }
+ if (_maxDepthSet)
+ {
+ reader.MaxDepth = previousMaxDepth;
+ }
+ if (_dateFormatStringSet)
+ {
+ reader.DateFormatString = previousDateFormatString;
+ }
+
+ if (reader is JsonTextReader textReader && textReader.PropertyNameTable != null &&
+ _contractResolver is DefaultContractResolver resolver && textReader.PropertyNameTable == resolver.GetNameTable())
+ {
+ textReader.PropertyNameTable = null;
+ }
+ }
+
+ ///
+ /// Serializes the specified and writes the JSON structure
+ /// using the specified .
+ ///
+ /// The used to write the JSON structure.
+ /// The to serialize.
+ public void Serialize(TextWriter textWriter, object? value)
+ {
+ Serialize(new JsonTextWriter(textWriter), value);
+ }
+
+ ///
+ /// Serializes the specified and writes the JSON structure
+ /// using the specified .
+ ///
+ /// The used to write the JSON structure.
+ /// The to serialize.
+ ///
+ /// The type of the value being serialized.
+ /// This parameter is used when is to write out the type name if the type of the value does not match.
+ /// Specifying the type is optional.
+ ///
+ public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType)
+ {
+ SerializeInternal(jsonWriter, value, objectType);
+ }
+
+ ///
+ /// Serializes the specified and writes the JSON structure
+ /// using the specified .
+ ///
+ /// The used to write the JSON structure.
+ /// The to serialize.
+ ///
+ /// The type of the value being serialized.
+ /// This parameter is used when is Auto to write out the type name if the type of the value does not match.
+ /// Specifying the type is optional.
+ ///
+ public void Serialize(TextWriter textWriter, object? value, Type objectType)
+ {
+ Serialize(new JsonTextWriter(textWriter), value, objectType);
+ }
+
+ ///
+ /// Serializes the specified and writes the JSON structure
+ /// using the specified .
+ ///
+ /// The used to write the JSON structure.
+ /// The to serialize.
+ public void Serialize(JsonWriter jsonWriter, object? value)
+ {
+ SerializeInternal(jsonWriter, value, null);
+ }
+
+ private TraceJsonReader CreateTraceJsonReader(JsonReader reader)
+ {
+ TraceJsonReader traceReader = new TraceJsonReader(reader);
+ if (reader.TokenType != JsonToken.None)
+ {
+ traceReader.WriteCurrentToken();
+ }
+
+ return traceReader;
+ }
+
+ internal virtual void SerializeInternal(JsonWriter jsonWriter, object? value, Type? objectType)
+ {
+ ValidationUtils.ArgumentNotNull(jsonWriter, nameof(jsonWriter));
+
+ // set serialization options onto writer
+ Formatting? previousFormatting = null;
+ if (_formatting != null && jsonWriter.Formatting != _formatting)
+ {
+ previousFormatting = jsonWriter.Formatting;
+ jsonWriter.Formatting = _formatting.GetValueOrDefault();
+ }
+
+ DateFormatHandling? previousDateFormatHandling = null;
+ if (_dateFormatHandling != null && jsonWriter.DateFormatHandling != _dateFormatHandling)
+ {
+ previousDateFormatHandling = jsonWriter.DateFormatHandling;
+ jsonWriter.DateFormatHandling = _dateFormatHandling.GetValueOrDefault();
+ }
+
+ DateTimeZoneHandling? previousDateTimeZoneHandling = null;
+ if (_dateTimeZoneHandling != null && jsonWriter.DateTimeZoneHandling != _dateTimeZoneHandling)
+ {
+ previousDateTimeZoneHandling = jsonWriter.DateTimeZoneHandling;
+ jsonWriter.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
+ }
+
+ FloatFormatHandling? previousFloatFormatHandling = null;
+ if (_floatFormatHandling != null && jsonWriter.FloatFormatHandling != _floatFormatHandling)
+ {
+ previousFloatFormatHandling = jsonWriter.FloatFormatHandling;
+ jsonWriter.FloatFormatHandling = _floatFormatHandling.GetValueOrDefault();
+ }
+
+ StringEscapeHandling? previousStringEscapeHandling = null;
+ if (_stringEscapeHandling != null && jsonWriter.StringEscapeHandling != _stringEscapeHandling)
+ {
+ previousStringEscapeHandling = jsonWriter.StringEscapeHandling;
+ jsonWriter.StringEscapeHandling = _stringEscapeHandling.GetValueOrDefault();
+ }
+
+ CultureInfo? previousCulture = null;
+ if (_culture != null && !_culture.Equals(jsonWriter.Culture))
+ {
+ previousCulture = jsonWriter.Culture;
+ jsonWriter.Culture = _culture;
+ }
+
+ string? previousDateFormatString = null;
+ if (_dateFormatStringSet && jsonWriter.DateFormatString != _dateFormatString)
+ {
+ previousDateFormatString = jsonWriter.DateFormatString;
+ jsonWriter.DateFormatString = _dateFormatString;
+ }
+
+ TraceJsonWriter? traceJsonWriter = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
+ ? new TraceJsonWriter(jsonWriter)
+ : null;
+
+ JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(this);
+ serializerWriter.Serialize(traceJsonWriter ?? jsonWriter, value, objectType);
+
+ if (traceJsonWriter != null)
+ {
+ TraceWriter!.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null);
+ }
+
+ // reset writer back to previous options
+ if (previousFormatting != null)
+ {
+ jsonWriter.Formatting = previousFormatting.GetValueOrDefault();
+ }
+ if (previousDateFormatHandling != null)
+ {
+ jsonWriter.DateFormatHandling = previousDateFormatHandling.GetValueOrDefault();
+ }
+ if (previousDateTimeZoneHandling != null)
+ {
+ jsonWriter.DateTimeZoneHandling = previousDateTimeZoneHandling.GetValueOrDefault();
+ }
+ if (previousFloatFormatHandling != null)
+ {
+ jsonWriter.FloatFormatHandling = previousFloatFormatHandling.GetValueOrDefault();
+ }
+ if (previousStringEscapeHandling != null)
+ {
+ jsonWriter.StringEscapeHandling = previousStringEscapeHandling.GetValueOrDefault();
+ }
+ if (_dateFormatStringSet)
+ {
+ jsonWriter.DateFormatString = previousDateFormatString;
+ }
+ if (previousCulture != null)
+ {
+ jsonWriter.Culture = previousCulture;
+ }
+ }
+
+ internal IReferenceResolver GetReferenceResolver()
+ {
+ if (_referenceResolver == null)
+ {
+ _referenceResolver = new DefaultReferenceResolver();
+ }
+
+ return _referenceResolver;
+ }
+
+ internal JsonConverter? GetMatchingConverter(Type type)
+ {
+ return GetMatchingConverter(_converters, type);
+ }
+
+ internal static JsonConverter? GetMatchingConverter(IList? converters, Type objectType)
+ {
+#if DEBUG
+ ValidationUtils.ArgumentNotNull(objectType, nameof(objectType));
+#endif
+
+ if (converters != null)
+ {
+ for (int i = 0; i < converters.Count; i++)
+ {
+ JsonConverter converter = converters[i];
+
+ if (converter.CanConvert(objectType))
+ {
+ return converter;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ internal void OnError(ErrorEventArgs e)
+ {
+ Error?.Invoke(this, e);
+ }
+ }
+}
diff --git a/Libs/Newtonsoft.Json.AOT/JsonSerializerSettings.cs b/Libs/Newtonsoft.Json.AOT/JsonSerializerSettings.cs
new file mode 100644
index 0000000..e0d42b8
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonSerializerSettings.cs
@@ -0,0 +1,456 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.Serialization.Formatters;
+using LC.Newtonsoft.Json.Serialization;
+using System.Runtime.Serialization;
+using System.Diagnostics;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Specifies the settings on a object.
+ ///
+ public class JsonSerializerSettings
+ {
+ internal const ReferenceLoopHandling DefaultReferenceLoopHandling = ReferenceLoopHandling.Error;
+ internal const MissingMemberHandling DefaultMissingMemberHandling = MissingMemberHandling.Ignore;
+ internal const NullValueHandling DefaultNullValueHandling = NullValueHandling.Include;
+ internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include;
+ internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto;
+ internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None;
+ internal const ConstructorHandling DefaultConstructorHandling = ConstructorHandling.Default;
+ internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None;
+ internal const MetadataPropertyHandling DefaultMetadataPropertyHandling = MetadataPropertyHandling.Default;
+ internal static readonly StreamingContext DefaultContext;
+
+ internal const Formatting DefaultFormatting = Formatting.None;
+ internal const DateFormatHandling DefaultDateFormatHandling = DateFormatHandling.IsoDateFormat;
+ internal const DateTimeZoneHandling DefaultDateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
+ internal const DateParseHandling DefaultDateParseHandling = DateParseHandling.DateTime;
+ internal const FloatParseHandling DefaultFloatParseHandling = FloatParseHandling.Double;
+ internal const FloatFormatHandling DefaultFloatFormatHandling = FloatFormatHandling.String;
+ internal const StringEscapeHandling DefaultStringEscapeHandling = StringEscapeHandling.Default;
+ internal const TypeNameAssemblyFormatHandling DefaultTypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple;
+ internal static readonly CultureInfo DefaultCulture;
+ internal const bool DefaultCheckAdditionalContent = false;
+ internal const string DefaultDateFormatString = @"yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";
+ internal const int DefaultMaxDepth = 64;
+
+ internal Formatting? _formatting;
+ internal DateFormatHandling? _dateFormatHandling;
+ internal DateTimeZoneHandling? _dateTimeZoneHandling;
+ internal DateParseHandling? _dateParseHandling;
+ internal FloatFormatHandling? _floatFormatHandling;
+ internal FloatParseHandling? _floatParseHandling;
+ internal StringEscapeHandling? _stringEscapeHandling;
+ internal CultureInfo? _culture;
+ internal bool? _checkAdditionalContent;
+ internal int? _maxDepth;
+ internal bool _maxDepthSet;
+ internal string? _dateFormatString;
+ internal bool _dateFormatStringSet;
+ internal TypeNameAssemblyFormatHandling? _typeNameAssemblyFormatHandling;
+ internal DefaultValueHandling? _defaultValueHandling;
+ internal PreserveReferencesHandling? _preserveReferencesHandling;
+ internal NullValueHandling? _nullValueHandling;
+ internal ObjectCreationHandling? _objectCreationHandling;
+ internal MissingMemberHandling? _missingMemberHandling;
+ internal ReferenceLoopHandling? _referenceLoopHandling;
+ internal StreamingContext? _context;
+ internal ConstructorHandling? _constructorHandling;
+ internal TypeNameHandling? _typeNameHandling;
+ internal MetadataPropertyHandling? _metadataPropertyHandling;
+
+ ///
+ /// Gets or sets how reference loops (e.g. a class referencing itself) are handled.
+ /// The default value is .
+ ///
+ /// Reference loop handling.
+ public ReferenceLoopHandling ReferenceLoopHandling
+ {
+ get => _referenceLoopHandling ?? DefaultReferenceLoopHandling;
+ set => _referenceLoopHandling = value;
+ }
+
+ ///
+ /// Gets or sets how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization.
+ /// The default value is .
+ ///
+ /// Missing member handling.
+ public MissingMemberHandling MissingMemberHandling
+ {
+ get => _missingMemberHandling ?? DefaultMissingMemberHandling;
+ set => _missingMemberHandling = value;
+ }
+
+ ///
+ /// Gets or sets how objects are created during deserialization.
+ /// The default value is .
+ ///
+ /// The object creation handling.
+ public ObjectCreationHandling ObjectCreationHandling
+ {
+ get => _objectCreationHandling ?? DefaultObjectCreationHandling;
+ set => _objectCreationHandling = value;
+ }
+
+ ///
+ /// Gets or sets how null values are handled during serialization and deserialization.
+ /// The default value is .
+ ///
+ /// Null value handling.
+ public NullValueHandling NullValueHandling
+ {
+ get => _nullValueHandling ?? DefaultNullValueHandling;
+ set => _nullValueHandling = value;
+ }
+
+ ///
+ /// Gets or sets how default values are handled during serialization and deserialization.
+ /// The default value is .
+ ///
+ /// The default value handling.
+ public DefaultValueHandling DefaultValueHandling
+ {
+ get => _defaultValueHandling ?? DefaultDefaultValueHandling;
+ set => _defaultValueHandling = value;
+ }
+
+ ///
+ /// Gets or sets a collection that will be used during serialization.
+ ///
+ /// The converters.
+ public IList Converters { get; set; }
+
+ ///
+ /// Gets or sets how object references are preserved by the serializer.
+ /// The default value is .
+ ///
+ /// The preserve references handling.
+ public PreserveReferencesHandling PreserveReferencesHandling
+ {
+ get => _preserveReferencesHandling ?? DefaultPreserveReferencesHandling;
+ set => _preserveReferencesHandling = value;
+ }
+
+ ///
+ /// Gets or sets how type name writing and reading is handled by the serializer.
+ /// The default value is .
+ ///
+ ///
+ /// should be used with caution when your application deserializes JSON from an external source.
+ /// Incoming types should be validated with a custom
+ /// when deserializing with a value other than .
+ ///
+ /// The type name handling.
+ public TypeNameHandling TypeNameHandling
+ {
+ get => _typeNameHandling ?? DefaultTypeNameHandling;
+ set => _typeNameHandling = value;
+ }
+
+ ///
+ /// Gets or sets how metadata properties are used during deserialization.
+ /// The default value is .
+ ///
+ /// The metadata properties handling.
+ public MetadataPropertyHandling MetadataPropertyHandling
+ {
+ get => _metadataPropertyHandling ?? DefaultMetadataPropertyHandling;
+ set => _metadataPropertyHandling = value;
+ }
+
+ ///
+ /// Gets or sets how a type name assembly is written and resolved by the serializer.
+ /// The default value is .
+ ///
+ /// The type name assembly format.
+ [Obsolete("TypeNameAssemblyFormat is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
+ public FormatterAssemblyStyle TypeNameAssemblyFormat
+ {
+ get => (FormatterAssemblyStyle)TypeNameAssemblyFormatHandling;
+ set => TypeNameAssemblyFormatHandling = (TypeNameAssemblyFormatHandling)value;
+ }
+
+ ///
+ /// Gets or sets how a type name assembly is written and resolved by the serializer.
+ /// The default value is .
+ ///
+ /// The type name assembly format.
+ public TypeNameAssemblyFormatHandling TypeNameAssemblyFormatHandling
+ {
+ get => _typeNameAssemblyFormatHandling ?? DefaultTypeNameAssemblyFormatHandling;
+ set => _typeNameAssemblyFormatHandling = value;
+ }
+
+ ///
+ /// Gets or sets how constructors are used during deserialization.
+ /// The default value is .
+ ///
+ /// The constructor handling.
+ public ConstructorHandling ConstructorHandling
+ {
+ get => _constructorHandling ?? DefaultConstructorHandling;
+ set => _constructorHandling = value;
+ }
+
+ ///
+ /// Gets or sets the contract resolver used by the serializer when
+ /// serializing .NET objects to JSON and vice versa.
+ ///
+ /// The contract resolver.
+ public IContractResolver? ContractResolver { get; set; }
+
+ ///
+ /// Gets or sets the equality comparer used by the serializer when comparing references.
+ ///
+ /// The equality comparer.
+ public IEqualityComparer? EqualityComparer { get; set; }
+
+ ///
+ /// Gets or sets the used by the serializer when resolving references.
+ ///
+ /// The reference resolver.
+ [Obsolete("ReferenceResolver property is obsolete. Use the ReferenceResolverProvider property to set the IReferenceResolver: settings.ReferenceResolverProvider = () => resolver")]
+ public IReferenceResolver? ReferenceResolver
+ {
+ get => ReferenceResolverProvider?.Invoke();
+ set
+ {
+ ReferenceResolverProvider = (value != null)
+ ? () => value
+ : (Func?)null;
+ }
+ }
+
+ ///
+ /// Gets or sets a function that creates the used by the serializer when resolving references.
+ ///
+ /// A function that creates the used by the serializer when resolving references.
+ public Func? ReferenceResolverProvider { get; set; }
+
+ ///
+ /// Gets or sets the used by the serializer when writing trace messages.
+ ///
+ /// The trace writer.
+ public ITraceWriter? TraceWriter { get; set; }
+
+ ///
+ /// Gets or sets the used by the serializer when resolving type names.
+ ///
+ /// The binder.
+ [Obsolete("Binder is obsolete. Use SerializationBinder instead.")]
+ public SerializationBinder? Binder
+ {
+ get
+ {
+ if (SerializationBinder == null)
+ {
+ return null;
+ }
+
+ if (SerializationBinder is SerializationBinderAdapter adapter)
+ {
+ return adapter.SerializationBinder;
+ }
+
+ throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set.");
+ }
+ set => SerializationBinder = value == null ? null : new SerializationBinderAdapter(value);
+ }
+
+ ///
+ /// Gets or sets the used by the serializer when resolving type names.
+ ///
+ /// The binder.
+ public ISerializationBinder? SerializationBinder { get; set; }
+
+ ///
+ /// Gets or sets the error handler called during serialization and deserialization.
+ ///
+ /// The error handler called during serialization and deserialization.
+ public EventHandler? Error { get; set; }
+
+ ///
+ /// Gets or sets the used by the serializer when invoking serialization callback methods.
+ ///
+ /// The context.
+ public StreamingContext Context
+ {
+ get => _context ?? DefaultContext;
+ set => _context = value;
+ }
+
+ ///
+ /// Gets or sets how and values are formatted when writing JSON text,
+ /// and the expected date format when reading JSON text.
+ /// The default value is "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK" .
+ ///
+ public string DateFormatString
+ {
+ get => _dateFormatString ?? DefaultDateFormatString;
+ set
+ {
+ _dateFormatString = value;
+ _dateFormatStringSet = true;
+ }
+ }
+
+ ///
+ /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a .
+ /// A null value means there is no maximum.
+ /// The default value is 128 .
+ ///
+ public int? MaxDepth
+ {
+ get => _maxDepthSet ? _maxDepth : DefaultMaxDepth;
+ set
+ {
+ if (value <= 0)
+ {
+ throw new ArgumentException("Value must be positive.", nameof(value));
+ }
+
+ _maxDepth = value;
+ _maxDepthSet = true;
+ }
+ }
+
+ ///
+ /// Indicates how JSON text output is formatted.
+ /// The default value is .
+ ///
+ public Formatting Formatting
+ {
+ get => _formatting ?? DefaultFormatting;
+ set => _formatting = value;
+ }
+
+ ///
+ /// Gets or sets how dates are written to JSON text.
+ /// The default value is .
+ ///
+ public DateFormatHandling DateFormatHandling
+ {
+ get => _dateFormatHandling ?? DefaultDateFormatHandling;
+ set => _dateFormatHandling = value;
+ }
+
+ ///
+ /// Gets or sets how time zones are handled during serialization and deserialization.
+ /// The default value is .
+ ///
+ public DateTimeZoneHandling DateTimeZoneHandling
+ {
+ get => _dateTimeZoneHandling ?? DefaultDateTimeZoneHandling;
+ set => _dateTimeZoneHandling = value;
+ }
+
+ ///
+ /// Gets or sets how date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z" , are parsed when reading JSON.
+ /// The default value is .
+ ///
+ public DateParseHandling DateParseHandling
+ {
+ get => _dateParseHandling ?? DefaultDateParseHandling;
+ set => _dateParseHandling = value;
+ }
+
+ ///
+ /// Gets or sets how special floating point numbers, e.g. ,
+ /// and ,
+ /// are written as JSON.
+ /// The default value is .
+ ///
+ public FloatFormatHandling FloatFormatHandling
+ {
+ get => _floatFormatHandling ?? DefaultFloatFormatHandling;
+ set => _floatFormatHandling = value;
+ }
+
+ ///
+ /// Gets or sets how floating point numbers, e.g. 1.0 and 9.9, are parsed when reading JSON text.
+ /// The default value is .
+ ///
+ public FloatParseHandling FloatParseHandling
+ {
+ get => _floatParseHandling ?? DefaultFloatParseHandling;
+ set => _floatParseHandling = value;
+ }
+
+ ///
+ /// Gets or sets how strings are escaped when writing JSON text.
+ /// The default value is .
+ ///
+ public StringEscapeHandling StringEscapeHandling
+ {
+ get => _stringEscapeHandling ?? DefaultStringEscapeHandling;
+ set => _stringEscapeHandling = value;
+ }
+
+ ///
+ /// Gets or sets the culture used when reading JSON.
+ /// The default value is .
+ ///
+ public CultureInfo Culture
+ {
+ get => _culture ?? DefaultCulture;
+ set => _culture = value;
+ }
+
+ ///
+ /// Gets a value indicating whether there will be a check for additional content after deserializing an object.
+ /// The default value is false .
+ ///
+ ///
+ /// true if there will be a check for additional content after deserializing an object; otherwise, false .
+ ///
+ public bool CheckAdditionalContent
+ {
+ get => _checkAdditionalContent ?? DefaultCheckAdditionalContent;
+ set => _checkAdditionalContent = value;
+ }
+
+ static JsonSerializerSettings()
+ {
+ DefaultContext = new StreamingContext();
+ DefaultCulture = CultureInfo.InvariantCulture;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ [DebuggerStepThrough]
+ public JsonSerializerSettings()
+ {
+ Converters = new List();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonTextReader.Async.cs b/Libs/Newtonsoft.Json.AOT/JsonTextReader.Async.cs
new file mode 100644
index 0000000..79ffe99
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonTextReader.Async.cs
@@ -0,0 +1,1806 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if HAVE_ASYNC
+
+using System;
+using System.Globalization;
+using System.Threading;
+#if HAVE_BIG_INTEGER
+using System.Numerics;
+#endif
+using System.Threading.Tasks;
+using LC.Newtonsoft.Json.Serialization;
+using LC.Newtonsoft.Json.Utilities;
+using System.Diagnostics;
+
+namespace LC.Newtonsoft.Json
+{
+ public partial class JsonTextReader
+ {
+ // It's not safe to perform the async methods here in a derived class as if the synchronous equivalent
+ // has been overriden then the asychronous method will no longer be doing the same operation
+#if HAVE_ASYNC // Double-check this isn't included inappropriately.
+ private readonly bool _safeAsync;
+#endif
+
+ ///
+ /// Asynchronously reads the next JSON token from the source.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns true if the next token was read successfully; false if there are no more tokens to read.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task ReadAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoReadAsync(cancellationToken) : base.ReadAsync(cancellationToken);
+ }
+
+ internal Task DoReadAsync(CancellationToken cancellationToken)
+ {
+ EnsureBuffer();
+
+ while (true)
+ {
+ switch (_currentState)
+ {
+ case State.Start:
+ case State.Property:
+ case State.Array:
+ case State.ArrayStart:
+ case State.Constructor:
+ case State.ConstructorStart:
+ return ParseValueAsync(cancellationToken);
+ case State.Object:
+ case State.ObjectStart:
+ return ParseObjectAsync(cancellationToken);
+ case State.PostValue:
+ Task task = ParsePostValueAsync(false, cancellationToken);
+ if (task.IsCompletedSucessfully())
+ {
+ if (task.Result)
+ {
+ return AsyncUtils.True;
+ }
+ }
+ else
+ {
+ return DoReadAsync(task, cancellationToken);
+ }
+ break;
+ case State.Finished:
+ return ReadFromFinishedAsync(cancellationToken);
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
+ }
+ }
+ }
+
+ private async Task DoReadAsync(Task task, CancellationToken cancellationToken)
+ {
+ bool result = await task.ConfigureAwait(false);
+ if (result)
+ {
+ return true;
+ }
+ return await DoReadAsync(cancellationToken).ConfigureAwait(false);
+ }
+
+ private async Task ParsePostValueAsync(bool ignoreComments, CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (_charsUsed == _charPos)
+ {
+ if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0)
+ {
+ _currentState = State.Finished;
+ return false;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+
+ break;
+ case '}':
+ _charPos++;
+ SetToken(JsonToken.EndObject);
+ return true;
+ case ']':
+ _charPos++;
+ SetToken(JsonToken.EndArray);
+ return true;
+ case ')':
+ _charPos++;
+ SetToken(JsonToken.EndConstructor);
+ return true;
+ case '/':
+ await ParseCommentAsync(!ignoreComments, cancellationToken).ConfigureAwait(false);
+ if (!ignoreComments)
+ {
+ return true;
+ }
+ break;
+ case ',':
+ _charPos++;
+
+ // finished parsing
+ SetStateBasedOnCurrent();
+ return false;
+ case ' ':
+ case StringUtils.Tab:
+
+ // eat
+ _charPos++;
+ break;
+ case StringUtils.CarriageReturn:
+ await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ default:
+ if (char.IsWhiteSpace(currentChar))
+ {
+ // eat
+ _charPos++;
+ }
+ else
+ {
+ // handle multiple content without comma delimiter
+ if (SupportMultipleContent && Depth == 0)
+ {
+ SetStateBasedOnCurrent();
+ return false;
+ }
+
+ throw JsonReaderException.Create(this, "After parsing a value an unexpected character was encountered: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar));
+ }
+
+ break;
+ }
+ }
+ }
+
+ private async Task ReadFromFinishedAsync(CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false))
+ {
+ await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false);
+ if (_isEndOfFile)
+ {
+ SetToken(JsonToken.None);
+ return false;
+ }
+
+ if (_chars[_charPos] == '/')
+ {
+ await ParseCommentAsync(true, cancellationToken).ConfigureAwait(false);
+ return true;
+ }
+
+ throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+
+ SetToken(JsonToken.None);
+ return false;
+ }
+
+ private Task ReadDataAsync(bool append, CancellationToken cancellationToken)
+ {
+ return ReadDataAsync(append, 0, cancellationToken);
+ }
+
+ private async Task ReadDataAsync(bool append, int charsRequired, CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (_isEndOfFile)
+ {
+ return 0;
+ }
+
+ PrepareBufferForReadData(append, charsRequired);
+
+ int charsRead = await _reader.ReadAsync(_chars, _charsUsed, _chars.Length - _charsUsed - 1, cancellationToken).ConfigureAwait(false);
+
+ _charsUsed += charsRead;
+
+ if (charsRead == 0)
+ {
+ _isEndOfFile = true;
+ }
+
+ _chars[_charsUsed] = '\0';
+ return charsRead;
+ }
+
+ private async Task ParseValueAsync(CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (_charsUsed == _charPos)
+ {
+ if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+
+ break;
+ case '"':
+ case '\'':
+ await ParseStringAsync(currentChar, ReadType.Read, cancellationToken).ConfigureAwait(false);
+ return true;
+ case 't':
+ await ParseTrueAsync(cancellationToken).ConfigureAwait(false);
+ return true;
+ case 'f':
+ await ParseFalseAsync(cancellationToken).ConfigureAwait(false);
+ return true;
+ case 'n':
+ if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false))
+ {
+ switch (_chars[_charPos + 1])
+ {
+ case 'u':
+ await ParseNullAsync(cancellationToken).ConfigureAwait(false);
+ break;
+ case 'e':
+ await ParseConstructorAsync(cancellationToken).ConfigureAwait(false);
+ break;
+ default:
+ throw CreateUnexpectedCharacterException(_chars[_charPos]);
+ }
+ }
+ else
+ {
+ _charPos++;
+ throw CreateUnexpectedEndException();
+ }
+
+ return true;
+ case 'N':
+ await ParseNumberNaNAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
+ return true;
+ case 'I':
+ await ParseNumberPositiveInfinityAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
+ return true;
+ case '-':
+ if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos + 1] == 'I')
+ {
+ await ParseNumberNegativeInfinityAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await ParseNumberAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
+ }
+ return true;
+ case '/':
+ await ParseCommentAsync(true, cancellationToken).ConfigureAwait(false);
+ return true;
+ case 'u':
+ await ParseUndefinedAsync(cancellationToken).ConfigureAwait(false);
+ return true;
+ case '{':
+ _charPos++;
+ SetToken(JsonToken.StartObject);
+ return true;
+ case '[':
+ _charPos++;
+ SetToken(JsonToken.StartArray);
+ return true;
+ case ']':
+ _charPos++;
+ SetToken(JsonToken.EndArray);
+ return true;
+ case ',':
+
+ // don't increment position, the next call to read will handle comma
+ // this is done to handle multiple empty comma values
+ SetToken(JsonToken.Undefined);
+ return true;
+ case ')':
+ _charPos++;
+ SetToken(JsonToken.EndConstructor);
+ return true;
+ case StringUtils.CarriageReturn:
+ await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+
+ // eat
+ _charPos++;
+ break;
+ default:
+ if (char.IsWhiteSpace(currentChar))
+ {
+ // eat
+ _charPos++;
+ break;
+ }
+
+ if (char.IsNumber(currentChar) || currentChar == '-' || currentChar == '.')
+ {
+ await ParseNumberAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
+ return true;
+ }
+
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+ }
+ }
+
+ private async Task ReadStringIntoBufferAsync(char quote, CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ int charPos = _charPos;
+ int initialPosition = _charPos;
+ int lastWritePosition = _charPos;
+ _stringBuffer.Position = 0;
+
+ while (true)
+ {
+ switch (_chars[charPos++])
+ {
+ case '\0':
+ if (_charsUsed == charPos - 1)
+ {
+ charPos--;
+
+ if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0)
+ {
+ _charPos = charPos;
+ throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote));
+ }
+ }
+
+ break;
+ case '\\':
+ _charPos = charPos;
+ if (!await EnsureCharsAsync(0, true, cancellationToken).ConfigureAwait(false))
+ {
+ throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote));
+ }
+
+ // start of escape sequence
+ int escapeStartPos = charPos - 1;
+
+ char currentChar = _chars[charPos];
+ charPos++;
+
+ char writeChar;
+
+ switch (currentChar)
+ {
+ case 'b':
+ writeChar = '\b';
+ break;
+ case 't':
+ writeChar = '\t';
+ break;
+ case 'n':
+ writeChar = '\n';
+ break;
+ case 'f':
+ writeChar = '\f';
+ break;
+ case 'r':
+ writeChar = '\r';
+ break;
+ case '\\':
+ writeChar = '\\';
+ break;
+ case '"':
+ case '\'':
+ case '/':
+ writeChar = currentChar;
+ break;
+ case 'u':
+ _charPos = charPos;
+ writeChar = await ParseUnicodeAsync(cancellationToken).ConfigureAwait(false);
+
+ if (StringUtils.IsLowSurrogate(writeChar))
+ {
+ // low surrogate with no preceding high surrogate; this char is replaced
+ writeChar = UnicodeReplacementChar;
+ }
+ else if (StringUtils.IsHighSurrogate(writeChar))
+ {
+ bool anotherHighSurrogate;
+
+ // loop for handling situations where there are multiple consecutive high surrogates
+ do
+ {
+ anotherHighSurrogate = false;
+
+ // potential start of a surrogate pair
+ if (await EnsureCharsAsync(2, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos] == '\\' && _chars[_charPos + 1] == 'u')
+ {
+ char highSurrogate = writeChar;
+
+ _charPos += 2;
+ writeChar = await ParseUnicodeAsync(cancellationToken).ConfigureAwait(false);
+
+ if (StringUtils.IsLowSurrogate(writeChar))
+ {
+ // a valid surrogate pair!
+ }
+ else if (StringUtils.IsHighSurrogate(writeChar))
+ {
+ // another high surrogate; replace current and start check over
+ highSurrogate = UnicodeReplacementChar;
+ anotherHighSurrogate = true;
+ }
+ else
+ {
+ // high surrogate not followed by low surrogate; original char is replaced
+ highSurrogate = UnicodeReplacementChar;
+ }
+
+ EnsureBufferNotEmpty();
+
+ WriteCharToBuffer(highSurrogate, lastWritePosition, escapeStartPos);
+ lastWritePosition = _charPos;
+ }
+ else
+ {
+ // there are not enough remaining chars for the low surrogate or is not follow by unicode sequence
+ // replace high surrogate and continue on as usual
+ writeChar = UnicodeReplacementChar;
+ }
+ } while (anotherHighSurrogate);
+ }
+
+ charPos = _charPos;
+ break;
+ default:
+ _charPos = charPos;
+ throw JsonReaderException.Create(this, "Bad JSON escape sequence: {0}.".FormatWith(CultureInfo.InvariantCulture, @"\" + currentChar));
+ }
+
+ EnsureBufferNotEmpty();
+ WriteCharToBuffer(writeChar, lastWritePosition, escapeStartPos);
+
+ lastWritePosition = charPos;
+ break;
+ case StringUtils.CarriageReturn:
+ _charPos = charPos - 1;
+ await ProcessCarriageReturnAsync(true, cancellationToken).ConfigureAwait(false);
+ charPos = _charPos;
+ break;
+ case StringUtils.LineFeed:
+ _charPos = charPos - 1;
+ ProcessLineFeed();
+ charPos = _charPos;
+ break;
+ case '"':
+ case '\'':
+ if (_chars[charPos - 1] == quote)
+ {
+ FinishReadStringIntoBuffer(charPos - 1, initialPosition, lastWritePosition);
+ return;
+ }
+
+ break;
+ }
+ }
+ }
+
+ private Task ProcessCarriageReturnAsync(bool append, CancellationToken cancellationToken)
+ {
+ _charPos++;
+
+ Task task = EnsureCharsAsync(1, append, cancellationToken);
+ if (task.IsCompletedSucessfully())
+ {
+ SetNewLine(task.Result);
+ return AsyncUtils.CompletedTask;
+ }
+
+ return ProcessCarriageReturnAsync(task);
+ }
+
+ private async Task ProcessCarriageReturnAsync(Task task)
+ {
+ SetNewLine(await task.ConfigureAwait(false));
+ }
+
+ private async Task ParseUnicodeAsync(CancellationToken cancellationToken)
+ {
+ return ConvertUnicode(await EnsureCharsAsync(4, true, cancellationToken).ConfigureAwait(false));
+ }
+
+ private Task EnsureCharsAsync(int relativePosition, bool append, CancellationToken cancellationToken)
+ {
+ if (_charPos + relativePosition < _charsUsed)
+ {
+ return AsyncUtils.True;
+ }
+
+ if (_isEndOfFile)
+ {
+ return AsyncUtils.False;
+ }
+
+ return ReadCharsAsync(relativePosition, append, cancellationToken);
+ }
+
+ private async Task ReadCharsAsync(int relativePosition, bool append, CancellationToken cancellationToken)
+ {
+ int charsRequired = _charPos + relativePosition - _charsUsed + 1;
+
+ // it is possible that the TextReader doesn't return all data at once
+ // repeat read until the required text is returned or the reader is out of content
+ do
+ {
+ int charsRead = await ReadDataAsync(append, charsRequired, cancellationToken).ConfigureAwait(false);
+
+ // no more content
+ if (charsRead == 0)
+ {
+ return false;
+ }
+
+ charsRequired -= charsRead;
+ } while (charsRequired > 0);
+
+ return true;
+ }
+
+ private async Task ParseObjectAsync(CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (_charsUsed == _charPos)
+ {
+ if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+
+ break;
+ case '}':
+ SetToken(JsonToken.EndObject);
+ _charPos++;
+ return true;
+ case '/':
+ await ParseCommentAsync(true, cancellationToken).ConfigureAwait(false);
+ return true;
+ case StringUtils.CarriageReturn:
+ await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+
+ // eat
+ _charPos++;
+ break;
+ default:
+ if (char.IsWhiteSpace(currentChar))
+ {
+ // eat
+ _charPos++;
+ }
+ else
+ {
+ return await ParsePropertyAsync(cancellationToken).ConfigureAwait(false);
+ }
+
+ break;
+ }
+ }
+ }
+
+ private async Task ParseCommentAsync(bool setToken, CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ // should have already parsed / character before reaching this method
+ _charPos++;
+
+ if (!await EnsureCharsAsync(1, false, cancellationToken).ConfigureAwait(false))
+ {
+ throw JsonReaderException.Create(this, "Unexpected end while parsing comment.");
+ }
+
+ bool singlelineComment;
+
+ if (_chars[_charPos] == '*')
+ {
+ singlelineComment = false;
+ }
+ else if (_chars[_charPos] == '/')
+ {
+ singlelineComment = true;
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Error parsing comment. Expected: *, got {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+
+ _charPos++;
+
+ int initialPosition = _charPos;
+
+ while (true)
+ {
+ switch (_chars[_charPos])
+ {
+ case '\0':
+ if (_charsUsed == _charPos)
+ {
+ if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0)
+ {
+ if (!singlelineComment)
+ {
+ throw JsonReaderException.Create(this, "Unexpected end while parsing comment.");
+ }
+
+ EndComment(setToken, initialPosition, _charPos);
+ return;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+
+ break;
+ case '*':
+ _charPos++;
+
+ if (!singlelineComment)
+ {
+ if (await EnsureCharsAsync(0, true, cancellationToken).ConfigureAwait(false))
+ {
+ if (_chars[_charPos] == '/')
+ {
+ EndComment(setToken, initialPosition, _charPos - 1);
+
+ _charPos++;
+ return;
+ }
+ }
+ }
+
+ break;
+ case StringUtils.CarriageReturn:
+ if (singlelineComment)
+ {
+ EndComment(setToken, initialPosition, _charPos);
+ return;
+ }
+
+ await ProcessCarriageReturnAsync(true, cancellationToken).ConfigureAwait(false);
+ break;
+ case StringUtils.LineFeed:
+ if (singlelineComment)
+ {
+ EndComment(setToken, initialPosition, _charPos);
+ return;
+ }
+
+ ProcessLineFeed();
+ break;
+ default:
+ _charPos++;
+ break;
+ }
+ }
+ }
+
+ private async Task EatWhitespaceAsync(CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (_charsUsed == _charPos)
+ {
+ if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0)
+ {
+ return;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+ break;
+ case StringUtils.CarriageReturn:
+ await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ default:
+ if (currentChar == ' ' || char.IsWhiteSpace(currentChar))
+ {
+ _charPos++;
+ }
+ else
+ {
+ return;
+ }
+ break;
+ }
+ }
+ }
+
+ private async Task ParseStringAsync(char quote, ReadType readType, CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ _charPos++;
+
+ ShiftBufferIfNeeded();
+ await ReadStringIntoBufferAsync(quote, cancellationToken).ConfigureAwait(false);
+ ParseReadString(quote, readType);
+ }
+
+ private async Task MatchValueAsync(string value, CancellationToken cancellationToken)
+ {
+ return MatchValue(await EnsureCharsAsync(value.Length - 1, true, cancellationToken).ConfigureAwait(false), value);
+ }
+
+ private async Task MatchValueWithTrailingSeparatorAsync(string value, CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ // will match value and then move to the next character, checking that it is a separator character
+ if (!await MatchValueAsync(value, cancellationToken).ConfigureAwait(false))
+ {
+ return false;
+ }
+
+ if (!await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false))
+ {
+ return true;
+ }
+
+ return IsSeparator(_chars[_charPos]) || _chars[_charPos] == '\0';
+ }
+
+ private async Task MatchAndSetAsync(string value, JsonToken newToken, object? tokenValue, CancellationToken cancellationToken)
+ {
+ if (await MatchValueWithTrailingSeparatorAsync(value, cancellationToken).ConfigureAwait(false))
+ {
+ SetToken(newToken, tokenValue);
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Error parsing " + newToken.ToString().ToLowerInvariant() + " value.");
+ }
+ }
+
+ private Task ParseTrueAsync(CancellationToken cancellationToken)
+ {
+ return MatchAndSetAsync(JsonConvert.True, JsonToken.Boolean, true, cancellationToken);
+ }
+
+ private Task ParseFalseAsync(CancellationToken cancellationToken)
+ {
+ return MatchAndSetAsync(JsonConvert.False, JsonToken.Boolean, false, cancellationToken);
+ }
+
+ private Task ParseNullAsync(CancellationToken cancellationToken)
+ {
+ return MatchAndSetAsync(JsonConvert.Null, JsonToken.Null, null, cancellationToken);
+ }
+
+ private async Task ParseConstructorAsync(CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (await MatchValueWithTrailingSeparatorAsync("new", cancellationToken).ConfigureAwait(false))
+ {
+ await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false);
+
+ int initialPosition = _charPos;
+ int endPosition;
+
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+ if (currentChar == '\0')
+ {
+ if (_charsUsed == _charPos)
+ {
+ if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0)
+ {
+ throw JsonReaderException.Create(this, "Unexpected end while parsing constructor.");
+ }
+ }
+ else
+ {
+ endPosition = _charPos;
+ _charPos++;
+ break;
+ }
+ }
+ else if (char.IsLetterOrDigit(currentChar))
+ {
+ _charPos++;
+ }
+ else if (currentChar == StringUtils.CarriageReturn)
+ {
+ endPosition = _charPos;
+ await ProcessCarriageReturnAsync(true, cancellationToken).ConfigureAwait(false);
+ break;
+ }
+ else if (currentChar == StringUtils.LineFeed)
+ {
+ endPosition = _charPos;
+ ProcessLineFeed();
+ break;
+ }
+ else if (char.IsWhiteSpace(currentChar))
+ {
+ endPosition = _charPos;
+ _charPos++;
+ break;
+ }
+ else if (currentChar == '(')
+ {
+ endPosition = _charPos;
+ break;
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar));
+ }
+ }
+
+ _stringReference = new StringReference(_chars, initialPosition, endPosition - initialPosition);
+ string constructorName = _stringReference.ToString();
+
+ await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false);
+
+ if (_chars[_charPos] != '(')
+ {
+ throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+
+ _charPos++;
+
+ ClearRecentString();
+
+ SetToken(JsonToken.StartConstructor, constructorName);
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Unexpected content while parsing JSON.");
+ }
+ }
+
+ private async Task ParseNumberNaNAsync(ReadType readType, CancellationToken cancellationToken)
+ {
+ return ParseNumberNaN(readType, await MatchValueWithTrailingSeparatorAsync(JsonConvert.NaN, cancellationToken).ConfigureAwait(false));
+ }
+
+ private async Task ParseNumberPositiveInfinityAsync(ReadType readType, CancellationToken cancellationToken)
+ {
+ return ParseNumberPositiveInfinity(readType, await MatchValueWithTrailingSeparatorAsync(JsonConvert.PositiveInfinity, cancellationToken).ConfigureAwait(false));
+ }
+
+ private async Task ParseNumberNegativeInfinityAsync(ReadType readType, CancellationToken cancellationToken)
+ {
+ return ParseNumberNegativeInfinity(readType, await MatchValueWithTrailingSeparatorAsync(JsonConvert.NegativeInfinity, cancellationToken).ConfigureAwait(false));
+ }
+
+ private async Task ParseNumberAsync(ReadType readType, CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ ShiftBufferIfNeeded();
+
+ char firstChar = _chars[_charPos];
+ int initialPosition = _charPos;
+
+ await ReadNumberIntoBufferAsync(cancellationToken).ConfigureAwait(false);
+
+ ParseReadNumber(readType, firstChar, initialPosition);
+ }
+
+ private Task ParseUndefinedAsync(CancellationToken cancellationToken)
+ {
+ return MatchAndSetAsync(JsonConvert.Undefined, JsonToken.Undefined, null, cancellationToken);
+ }
+
+ private async Task ParsePropertyAsync(CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ char firstChar = _chars[_charPos];
+ char quoteChar;
+
+ if (firstChar == '"' || firstChar == '\'')
+ {
+ _charPos++;
+ quoteChar = firstChar;
+ ShiftBufferIfNeeded();
+ await ReadStringIntoBufferAsync(quoteChar, cancellationToken).ConfigureAwait(false);
+ }
+ else if (ValidIdentifierChar(firstChar))
+ {
+ quoteChar = '\0';
+ ShiftBufferIfNeeded();
+ await ParseUnquotedPropertyAsync(cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+
+ string propertyName;
+
+ if (PropertyNameTable != null)
+ {
+ propertyName = PropertyNameTable.Get(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length)
+ // no match in name table
+ ?? _stringReference.ToString();
+ }
+ else
+ {
+ propertyName = _stringReference.ToString();
+ }
+
+ await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false);
+
+ if (_chars[_charPos] != ':')
+ {
+ throw JsonReaderException.Create(this, "Invalid character after parsing property name. Expected ':' but got: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+
+ _charPos++;
+
+ SetToken(JsonToken.PropertyName, propertyName);
+ _quoteChar = quoteChar;
+ ClearRecentString();
+
+ return true;
+ }
+
+ private async Task ReadNumberIntoBufferAsync(CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ int charPos = _charPos;
+
+ while (true)
+ {
+ char currentChar = _chars[charPos];
+ if (currentChar == '\0')
+ {
+ _charPos = charPos;
+
+ if (_charsUsed == charPos)
+ {
+ if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0)
+ {
+ return;
+ }
+ }
+ else
+ {
+ return;
+ }
+ }
+ else if (ReadNumberCharIntoBuffer(currentChar, charPos))
+ {
+ return;
+ }
+ else
+ {
+ charPos++;
+ }
+ }
+ }
+
+ private async Task ParseUnquotedPropertyAsync(CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ int initialPosition = _charPos;
+
+ // parse unquoted property name until whitespace or colon
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+ if (currentChar == '\0')
+ {
+ if (_charsUsed == _charPos)
+ {
+ if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0)
+ {
+ throw JsonReaderException.Create(this, "Unexpected end while parsing unquoted property name.");
+ }
+
+ continue;
+ }
+
+ _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition);
+ return;
+ }
+
+ if (ReadUnquotedPropertyReportIfDone(currentChar, initialPosition))
+ {
+ return;
+ }
+ }
+ }
+
+ private async Task ReadNullCharAsync(CancellationToken cancellationToken)
+ {
+ if (_charsUsed == _charPos)
+ {
+ if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0)
+ {
+ _isEndOfFile = true;
+ return true;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+
+ return false;
+ }
+
+ private async Task HandleNullAsync(CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false))
+ {
+ if (_chars[_charPos + 1] == 'u')
+ {
+ await ParseNullAsync(cancellationToken).ConfigureAwait(false);
+ return;
+ }
+
+ _charPos += 2;
+ throw CreateUnexpectedCharacterException(_chars[_charPos - 1]);
+ }
+
+ _charPos = _charsUsed;
+ throw CreateUnexpectedEndException();
+ }
+
+ private async Task ReadFinishedAsync(CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false))
+ {
+ await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false);
+ if (_isEndOfFile)
+ {
+ SetToken(JsonToken.None);
+ return;
+ }
+
+ if (_chars[_charPos] == '/')
+ {
+ await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+ }
+
+ SetToken(JsonToken.None);
+ }
+
+ private async Task ReadStringValueAsync(ReadType readType, CancellationToken cancellationToken)
+ {
+ EnsureBuffer();
+ MiscellaneousUtils.Assert(_chars != null);
+
+ switch (_currentState)
+ {
+ case State.PostValue:
+ if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false))
+ {
+ return null;
+ }
+ goto case State.Start;
+ case State.Start:
+ case State.Property:
+ case State.Array:
+ case State.ArrayStart:
+ case State.Constructor:
+ case State.ConstructorStart:
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false))
+ {
+ SetToken(JsonToken.None, null, false);
+ return null;
+ }
+
+ break;
+ case '"':
+ case '\'':
+ await ParseStringAsync(currentChar, readType, cancellationToken).ConfigureAwait(false);
+ return FinishReadQuotedStringValue(readType);
+ case '-':
+ if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos + 1] == 'I')
+ {
+ return ParseNumberNegativeInfinity(readType);
+ }
+ else
+ {
+ await ParseNumberAsync(readType, cancellationToken).ConfigureAwait(false);
+ return Value;
+ }
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (readType != ReadType.ReadAsString)
+ {
+ _charPos++;
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+
+ await ParseNumberAsync(ReadType.ReadAsString, cancellationToken).ConfigureAwait(false);
+ return Value;
+ case 't':
+ case 'f':
+ if (readType != ReadType.ReadAsString)
+ {
+ _charPos++;
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+
+ string expected = currentChar == 't' ? JsonConvert.True : JsonConvert.False;
+ if (!await MatchValueWithTrailingSeparatorAsync(expected, cancellationToken).ConfigureAwait(false))
+ {
+ throw CreateUnexpectedCharacterException(_chars[_charPos]);
+ }
+
+ SetToken(JsonToken.String, expected);
+ return expected;
+ case 'I':
+ return await ParseNumberPositiveInfinityAsync(readType, cancellationToken).ConfigureAwait(false);
+ case 'N':
+ return await ParseNumberNaNAsync(readType, cancellationToken).ConfigureAwait(false);
+ case 'n':
+ await HandleNullAsync(cancellationToken).ConfigureAwait(false);
+ return null;
+ case '/':
+ await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case ',':
+ ProcessValueComma();
+ break;
+ case ']':
+ _charPos++;
+ if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
+ {
+ SetToken(JsonToken.EndArray);
+ return null;
+ }
+
+ throw CreateUnexpectedCharacterException(currentChar);
+ case StringUtils.CarriageReturn:
+ await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+
+ // eat
+ _charPos++;
+ break;
+ default:
+ _charPos++;
+
+ if (!char.IsWhiteSpace(currentChar))
+ {
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+
+ // eat
+ break;
+ }
+ }
+ case State.Finished:
+ await ReadFinishedAsync(cancellationToken).ConfigureAwait(false);
+ return null;
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
+ }
+ }
+
+ private async Task ReadNumberValueAsync(ReadType readType, CancellationToken cancellationToken)
+ {
+ EnsureBuffer();
+ MiscellaneousUtils.Assert(_chars != null);
+
+ switch (_currentState)
+ {
+ case State.PostValue:
+ if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false))
+ {
+ return null;
+ }
+ goto case State.Start;
+ case State.Start:
+ case State.Property:
+ case State.Array:
+ case State.ArrayStart:
+ case State.Constructor:
+ case State.ConstructorStart:
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false))
+ {
+ SetToken(JsonToken.None, null, false);
+ return null;
+ }
+
+ break;
+ case '"':
+ case '\'':
+ await ParseStringAsync(currentChar, readType, cancellationToken).ConfigureAwait(false);
+ return FinishReadQuotedNumber(readType);
+ case 'n':
+ await HandleNullAsync(cancellationToken).ConfigureAwait(false);
+ return null;
+ case 'N':
+ return await ParseNumberNaNAsync(readType, cancellationToken).ConfigureAwait(false);
+ case 'I':
+ return await ParseNumberPositiveInfinityAsync(readType, cancellationToken).ConfigureAwait(false);
+ case '-':
+ if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos + 1] == 'I')
+ {
+ return await ParseNumberNegativeInfinityAsync(readType, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await ParseNumberAsync(readType, cancellationToken).ConfigureAwait(false);
+ return Value;
+ }
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ await ParseNumberAsync(readType, cancellationToken).ConfigureAwait(false);
+ return Value;
+ case '/':
+ await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case ',':
+ ProcessValueComma();
+ break;
+ case ']':
+ _charPos++;
+ if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
+ {
+ SetToken(JsonToken.EndArray);
+ return null;
+ }
+
+ throw CreateUnexpectedCharacterException(currentChar);
+ case StringUtils.CarriageReturn:
+ await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+
+ // eat
+ _charPos++;
+ break;
+ default:
+ _charPos++;
+
+ if (!char.IsWhiteSpace(currentChar))
+ {
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+
+ // eat
+ break;
+ }
+ }
+ case State.Finished:
+ await ReadFinishedAsync(cancellationToken).ConfigureAwait(false);
+ return null;
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
+ }
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task ReadAsBooleanAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoReadAsBooleanAsync(cancellationToken) : base.ReadAsBooleanAsync(cancellationToken);
+ }
+
+ internal async Task DoReadAsBooleanAsync(CancellationToken cancellationToken)
+ {
+ EnsureBuffer();
+ MiscellaneousUtils.Assert(_chars != null);
+
+ switch (_currentState)
+ {
+ case State.PostValue:
+ if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false))
+ {
+ return null;
+ }
+ goto case State.Start;
+ case State.Start:
+ case State.Property:
+ case State.Array:
+ case State.ArrayStart:
+ case State.Constructor:
+ case State.ConstructorStart:
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false))
+ {
+ SetToken(JsonToken.None, null, false);
+ return null;
+ }
+
+ break;
+ case '"':
+ case '\'':
+ await ParseStringAsync(currentChar, ReadType.Read, cancellationToken).ConfigureAwait(false);
+ return ReadBooleanString(_stringReference.ToString());
+ case 'n':
+ await HandleNullAsync(cancellationToken).ConfigureAwait(false);
+ return null;
+ case '-':
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ await ParseNumberAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
+ bool b;
+#if HAVE_BIG_INTEGER
+ if (Value is BigInteger i)
+ {
+ b = i != 0;
+ }
+ else
+#endif
+ {
+ b = Convert.ToBoolean(Value, CultureInfo.InvariantCulture);
+ }
+ SetToken(JsonToken.Boolean, b, false);
+ return b;
+ case 't':
+ case 'f':
+ bool isTrue = currentChar == 't';
+ if (!await MatchValueWithTrailingSeparatorAsync(isTrue ? JsonConvert.True : JsonConvert.False, cancellationToken).ConfigureAwait(false))
+ {
+ throw CreateUnexpectedCharacterException(_chars[_charPos]);
+ }
+
+ SetToken(JsonToken.Boolean, isTrue);
+ return isTrue;
+ case '/':
+ await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case ',':
+ ProcessValueComma();
+ break;
+ case ']':
+ _charPos++;
+ if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
+ {
+ SetToken(JsonToken.EndArray);
+ return null;
+ }
+
+ throw CreateUnexpectedCharacterException(currentChar);
+ case StringUtils.CarriageReturn:
+ await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+
+ // eat
+ _charPos++;
+ break;
+ default:
+ _charPos++;
+
+ if (!char.IsWhiteSpace(currentChar))
+ {
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+
+ // eat
+ break;
+ }
+ }
+ case State.Finished:
+ await ReadFinishedAsync(cancellationToken).ConfigureAwait(false);
+ return null;
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
+ }
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a [].
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the []. This result will be null at the end of an array.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task ReadAsBytesAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoReadAsBytesAsync(cancellationToken) : base.ReadAsBytesAsync(cancellationToken);
+ }
+
+ internal async Task DoReadAsBytesAsync(CancellationToken cancellationToken)
+ {
+ EnsureBuffer();
+ MiscellaneousUtils.Assert(_chars != null);
+
+ bool isWrapped = false;
+
+ switch (_currentState)
+ {
+ case State.PostValue:
+ if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false))
+ {
+ return null;
+ }
+ goto case State.Start;
+ case State.Start:
+ case State.Property:
+ case State.Array:
+ case State.ArrayStart:
+ case State.Constructor:
+ case State.ConstructorStart:
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false))
+ {
+ SetToken(JsonToken.None, null, false);
+ return null;
+ }
+
+ break;
+ case '"':
+ case '\'':
+ await ParseStringAsync(currentChar, ReadType.ReadAsBytes, cancellationToken).ConfigureAwait(false);
+ byte[]? data = (byte[]?)Value;
+ if (isWrapped)
+ {
+ await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false);
+ if (TokenType != JsonToken.EndObject)
+ {
+ throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+
+ SetToken(JsonToken.Bytes, data, false);
+ }
+
+ return data;
+ case '{':
+ _charPos++;
+ SetToken(JsonToken.StartObject);
+ await ReadIntoWrappedTypeObjectAsync(cancellationToken).ConfigureAwait(false);
+ isWrapped = true;
+ break;
+ case '[':
+ _charPos++;
+ SetToken(JsonToken.StartArray);
+ return await ReadArrayIntoByteArrayAsync(cancellationToken).ConfigureAwait(false);
+ case 'n':
+ await HandleNullAsync(cancellationToken).ConfigureAwait(false);
+ return null;
+ case '/':
+ await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case ',':
+ ProcessValueComma();
+ break;
+ case ']':
+ _charPos++;
+ if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
+ {
+ SetToken(JsonToken.EndArray);
+ return null;
+ }
+
+ throw CreateUnexpectedCharacterException(currentChar);
+ case StringUtils.CarriageReturn:
+ await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+
+ // eat
+ _charPos++;
+ break;
+ default:
+ _charPos++;
+
+ if (!char.IsWhiteSpace(currentChar))
+ {
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+
+ // eat
+ break;
+ }
+ }
+ case State.Finished:
+ await ReadFinishedAsync(cancellationToken).ConfigureAwait(false);
+ return null;
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
+ }
+ }
+
+ private async Task ReadIntoWrappedTypeObjectAsync(CancellationToken cancellationToken)
+ {
+ await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false);
+ if (Value != null && Value.ToString() == JsonTypeReflector.TypePropertyName)
+ {
+ await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false);
+ if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal))
+ {
+ await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false);
+ if (Value.ToString() == JsonTypeReflector.ValuePropertyName)
+ {
+ return;
+ }
+ }
+ }
+
+ throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task ReadAsDateTimeAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoReadAsDateTimeAsync(cancellationToken) : base.ReadAsDateTimeAsync(cancellationToken);
+ }
+
+ internal async Task DoReadAsDateTimeAsync(CancellationToken cancellationToken)
+ {
+ return (DateTime?)await ReadStringValueAsync(ReadType.ReadAsDateTime, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task ReadAsDateTimeOffsetAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoReadAsDateTimeOffsetAsync(cancellationToken) : base.ReadAsDateTimeOffsetAsync(cancellationToken);
+ }
+
+ internal async Task DoReadAsDateTimeOffsetAsync(CancellationToken cancellationToken)
+ {
+ return (DateTimeOffset?)await ReadStringValueAsync(ReadType.ReadAsDateTimeOffset, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task ReadAsDecimalAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoReadAsDecimalAsync(cancellationToken) : base.ReadAsDecimalAsync(cancellationToken);
+ }
+
+ internal async Task DoReadAsDecimalAsync(CancellationToken cancellationToken)
+ {
+ return (decimal?)await ReadNumberValueAsync(ReadType.ReadAsDecimal, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task ReadAsDoubleAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoReadAsDoubleAsync(cancellationToken) : base.ReadAsDoubleAsync(cancellationToken);
+ }
+
+ internal async Task DoReadAsDoubleAsync(CancellationToken cancellationToken)
+ {
+ return (double?)await ReadNumberValueAsync(ReadType.ReadAsDouble, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a of .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the of . This result will be null at the end of an array.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task ReadAsInt32Async(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoReadAsInt32Async(cancellationToken) : base.ReadAsInt32Async(cancellationToken);
+ }
+
+ internal async Task DoReadAsInt32Async(CancellationToken cancellationToken)
+ {
+ return (int?)await ReadNumberValueAsync(ReadType.ReadAsInt32, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously reads the next JSON token from the source as a .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous read. The
+ /// property returns the . This result will be null at the end of an array.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task ReadAsStringAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoReadAsStringAsync(cancellationToken) : base.ReadAsStringAsync(cancellationToken);
+ }
+
+ internal async Task DoReadAsStringAsync(CancellationToken cancellationToken)
+ {
+ return (string?)await ReadStringValueAsync(ReadType.ReadAsString, cancellationToken).ConfigureAwait(false);
+ }
+ }
+}
+
+#endif
diff --git a/Libs/Newtonsoft.Json.AOT/JsonTextReader.cs b/Libs/Newtonsoft.Json.AOT/JsonTextReader.cs
new file mode 100644
index 0000000..9bfa85c
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonTextReader.cs
@@ -0,0 +1,2655 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using System.IO;
+using System.Globalization;
+using System.Diagnostics;
+#if HAVE_BIG_INTEGER
+using System.Numerics;
+#endif
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json
+{
+ internal enum ReadType
+ {
+ Read,
+ ReadAsInt32,
+ ReadAsInt64,
+ ReadAsBytes,
+ ReadAsString,
+ ReadAsDecimal,
+ ReadAsDateTime,
+#if HAVE_DATE_TIME_OFFSET
+ ReadAsDateTimeOffset,
+#endif
+ ReadAsDouble,
+ ReadAsBoolean
+ }
+
+ ///
+ /// Represents a reader that provides fast, non-cached, forward-only access to JSON text data.
+ ///
+ public partial class JsonTextReader : JsonReader, IJsonLineInfo
+ {
+ private const char UnicodeReplacementChar = '\uFFFD';
+#if HAVE_BIG_INTEGER
+ private const int MaximumJavascriptIntegerCharacterLength = 380;
+#endif
+#if DEBUG
+ internal int LargeBufferLength { get; set; } = int.MaxValue / 2;
+#else
+ private const int LargeBufferLength = int.MaxValue / 2;
+#endif
+
+ private readonly TextReader _reader;
+ private char[]? _chars;
+ private int _charsUsed;
+ private int _charPos;
+ private int _lineStartPos;
+ private int _lineNumber;
+ private bool _isEndOfFile;
+ private StringBuffer _stringBuffer;
+ private StringReference _stringReference;
+ private IArrayPool? _arrayPool;
+
+ ///
+ /// Initializes a new instance of the class with the specified .
+ ///
+ /// The containing the JSON data to read.
+ public JsonTextReader(TextReader reader)
+ {
+ if (reader == null)
+ {
+ throw new ArgumentNullException(nameof(reader));
+ }
+
+ _reader = reader;
+ _lineNumber = 1;
+
+#if HAVE_ASYNC
+ _safeAsync = GetType() == typeof(JsonTextReader);
+#endif
+ }
+
+#if DEBUG
+ internal char[]? CharBuffer
+ {
+ get => _chars;
+ set => _chars = value;
+ }
+
+ internal int CharPos => _charPos;
+#endif
+
+ ///
+ /// Gets or sets the reader's property name table.
+ ///
+ public JsonNameTable? PropertyNameTable { get; set; }
+
+ ///
+ /// Gets or sets the reader's character buffer pool.
+ ///
+ public IArrayPool? ArrayPool
+ {
+ get => _arrayPool;
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ _arrayPool = value;
+ }
+ }
+
+ private void EnsureBufferNotEmpty()
+ {
+ if (_stringBuffer.IsEmpty)
+ {
+ _stringBuffer = new StringBuffer(_arrayPool, 1024);
+ }
+ }
+
+ private void SetNewLine(bool hasNextChar)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (hasNextChar && _chars[_charPos] == StringUtils.LineFeed)
+ {
+ _charPos++;
+ }
+
+ OnNewLine(_charPos);
+ }
+
+ private void OnNewLine(int pos)
+ {
+ _lineNumber++;
+ _lineStartPos = pos;
+ }
+
+ private void ParseString(char quote, ReadType readType)
+ {
+ _charPos++;
+
+ ShiftBufferIfNeeded();
+ ReadStringIntoBuffer(quote);
+ ParseReadString(quote, readType);
+ }
+
+ private void ParseReadString(char quote, ReadType readType)
+ {
+ SetPostValueState(true);
+
+ switch (readType)
+ {
+ case ReadType.ReadAsBytes:
+ Guid g;
+ byte[] data;
+ if (_stringReference.Length == 0)
+ {
+ data = CollectionUtils.ArrayEmpty();
+ }
+ else if (_stringReference.Length == 36 && ConvertUtils.TryConvertGuid(_stringReference.ToString(), out g))
+ {
+ data = g.ToByteArray();
+ }
+ else
+ {
+ data = Convert.FromBase64CharArray(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length);
+ }
+
+ SetToken(JsonToken.Bytes, data, false);
+ break;
+ case ReadType.ReadAsString:
+ string text = _stringReference.ToString();
+
+ SetToken(JsonToken.String, text, false);
+ _quoteChar = quote;
+ break;
+ case ReadType.ReadAsInt32:
+ case ReadType.ReadAsDecimal:
+ case ReadType.ReadAsBoolean:
+ // caller will convert result
+ break;
+ default:
+ if (_dateParseHandling != DateParseHandling.None)
+ {
+ DateParseHandling dateParseHandling;
+ if (readType == ReadType.ReadAsDateTime)
+ {
+ dateParseHandling = DateParseHandling.DateTime;
+ }
+#if HAVE_DATE_TIME_OFFSET
+ else if (readType == ReadType.ReadAsDateTimeOffset)
+ {
+ dateParseHandling = DateParseHandling.DateTimeOffset;
+ }
+#endif
+ else
+ {
+ dateParseHandling = _dateParseHandling;
+ }
+
+ if (dateParseHandling == DateParseHandling.DateTime)
+ {
+ if (DateTimeUtils.TryParseDateTime(_stringReference, DateTimeZoneHandling, DateFormatString, Culture, out DateTime dt))
+ {
+ SetToken(JsonToken.Date, dt, false);
+ return;
+ }
+ }
+#if HAVE_DATE_TIME_OFFSET
+ else
+ {
+ if (DateTimeUtils.TryParseDateTimeOffset(_stringReference, DateFormatString, Culture, out DateTimeOffset dt))
+ {
+ SetToken(JsonToken.Date, dt, false);
+ return;
+ }
+ }
+#endif
+ }
+
+ SetToken(JsonToken.String, _stringReference.ToString(), false);
+ _quoteChar = quote;
+ break;
+ }
+ }
+
+ private static void BlockCopyChars(char[] src, int srcOffset, char[] dst, int dstOffset, int count)
+ {
+ const int charByteCount = 2;
+
+ Buffer.BlockCopy(src, srcOffset * charByteCount, dst, dstOffset * charByteCount, count * charByteCount);
+ }
+
+ private void ShiftBufferIfNeeded()
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ // once in the last 10% of the buffer, or buffer is already very large then
+ // shift the remaining content to the start to avoid unnecessarily increasing
+ // the buffer size when reading numbers/strings
+ int length = _chars.Length;
+ if (length - _charPos <= length * 0.1 || length >= LargeBufferLength)
+ {
+ int count = _charsUsed - _charPos;
+ if (count > 0)
+ {
+ BlockCopyChars(_chars, _charPos, _chars, 0, count);
+ }
+
+ _lineStartPos -= _charPos;
+ _charPos = 0;
+ _charsUsed = count;
+ _chars[_charsUsed] = '\0';
+ }
+ }
+
+ private int ReadData(bool append)
+ {
+ return ReadData(append, 0);
+ }
+
+ private void PrepareBufferForReadData(bool append, int charsRequired)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ // char buffer is full
+ if (_charsUsed + charsRequired >= _chars.Length - 1)
+ {
+ if (append)
+ {
+ int doubledArrayLength = _chars.Length * 2;
+
+ // copy to new array either double the size of the current or big enough to fit required content
+ int newArrayLength = Math.Max(
+ doubledArrayLength < 0 ? int.MaxValue : doubledArrayLength, // handle overflow
+ _charsUsed + charsRequired + 1);
+
+ // increase the size of the buffer
+ char[] dst = BufferUtils.RentBuffer(_arrayPool, newArrayLength);
+
+ BlockCopyChars(_chars, 0, dst, 0, _chars.Length);
+
+ BufferUtils.ReturnBuffer(_arrayPool, _chars);
+
+ _chars = dst;
+ }
+ else
+ {
+ int remainingCharCount = _charsUsed - _charPos;
+
+ if (remainingCharCount + charsRequired + 1 >= _chars.Length)
+ {
+ // the remaining count plus the required is bigger than the current buffer size
+ char[] dst = BufferUtils.RentBuffer(_arrayPool, remainingCharCount + charsRequired + 1);
+
+ if (remainingCharCount > 0)
+ {
+ BlockCopyChars(_chars, _charPos, dst, 0, remainingCharCount);
+ }
+
+ BufferUtils.ReturnBuffer(_arrayPool, _chars);
+
+ _chars = dst;
+ }
+ else
+ {
+ // copy any remaining data to the beginning of the buffer if needed and reset positions
+ if (remainingCharCount > 0)
+ {
+ BlockCopyChars(_chars, _charPos, _chars, 0, remainingCharCount);
+ }
+ }
+
+ _lineStartPos -= _charPos;
+ _charPos = 0;
+ _charsUsed = remainingCharCount;
+ }
+ }
+ }
+
+ private int ReadData(bool append, int charsRequired)
+ {
+ if (_isEndOfFile)
+ {
+ return 0;
+ }
+
+ PrepareBufferForReadData(append, charsRequired);
+ MiscellaneousUtils.Assert(_chars != null);
+
+ int attemptCharReadCount = _chars.Length - _charsUsed - 1;
+
+ int charsRead = _reader.Read(_chars, _charsUsed, attemptCharReadCount);
+
+ _charsUsed += charsRead;
+
+ if (charsRead == 0)
+ {
+ _isEndOfFile = true;
+ }
+
+ _chars[_charsUsed] = '\0';
+ return charsRead;
+ }
+
+ private bool EnsureChars(int relativePosition, bool append)
+ {
+ if (_charPos + relativePosition >= _charsUsed)
+ {
+ return ReadChars(relativePosition, append);
+ }
+
+ return true;
+ }
+
+ private bool ReadChars(int relativePosition, bool append)
+ {
+ if (_isEndOfFile)
+ {
+ return false;
+ }
+
+ int charsRequired = _charPos + relativePosition - _charsUsed + 1;
+
+ int totalCharsRead = 0;
+
+ // it is possible that the TextReader doesn't return all data at once
+ // repeat read until the required text is returned or the reader is out of content
+ do
+ {
+ int charsRead = ReadData(append, charsRequired - totalCharsRead);
+
+ // no more content
+ if (charsRead == 0)
+ {
+ break;
+ }
+
+ totalCharsRead += charsRead;
+ } while (totalCharsRead < charsRequired);
+
+ if (totalCharsRead < charsRequired)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying .
+ ///
+ ///
+ /// true if the next token was read successfully; false if there are no more tokens to read.
+ ///
+ public override bool Read()
+ {
+ EnsureBuffer();
+ MiscellaneousUtils.Assert(_chars != null);
+
+ while (true)
+ {
+ switch (_currentState)
+ {
+ case State.Start:
+ case State.Property:
+ case State.Array:
+ case State.ArrayStart:
+ case State.Constructor:
+ case State.ConstructorStart:
+ return ParseValue();
+ case State.Object:
+ case State.ObjectStart:
+ return ParseObject();
+ case State.PostValue:
+ // returns true if it hits
+ // end of object or array
+ if (ParsePostValue(false))
+ {
+ return true;
+ }
+ break;
+ case State.Finished:
+ if (EnsureChars(0, false))
+ {
+ EatWhitespace();
+ if (_isEndOfFile)
+ {
+ SetToken(JsonToken.None);
+ return false;
+ }
+ if (_chars[_charPos] == '/')
+ {
+ ParseComment(true);
+ return true;
+ }
+
+ throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+ SetToken(JsonToken.None);
+ return false;
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
+ }
+ }
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public override int? ReadAsInt32()
+ {
+ return (int?)ReadNumberValue(ReadType.ReadAsInt32);
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public override DateTime? ReadAsDateTime()
+ {
+ return (DateTime?)ReadStringValue(ReadType.ReadAsDateTime);
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a .
+ ///
+ /// A . This method will return null at the end of an array.
+ public override string? ReadAsString()
+ {
+ return (string?)ReadStringValue(ReadType.ReadAsString);
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a [].
+ ///
+ /// A [] or null if the next JSON token is null. This method will return null at the end of an array.
+ public override byte[]? ReadAsBytes()
+ {
+ EnsureBuffer();
+ MiscellaneousUtils.Assert(_chars != null);
+
+ bool isWrapped = false;
+
+ switch (_currentState)
+ {
+ case State.PostValue:
+ if (ParsePostValue(true))
+ {
+ return null;
+ }
+ goto case State.Start;
+ case State.Start:
+ case State.Property:
+ case State.Array:
+ case State.ArrayStart:
+ case State.Constructor:
+ case State.ConstructorStart:
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (ReadNullChar())
+ {
+ SetToken(JsonToken.None, null, false);
+ return null;
+ }
+ break;
+ case '"':
+ case '\'':
+ ParseString(currentChar, ReadType.ReadAsBytes);
+ byte[]? data = (byte[]?)Value;
+ if (isWrapped)
+ {
+ ReaderReadAndAssert();
+ if (TokenType != JsonToken.EndObject)
+ {
+ throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+ SetToken(JsonToken.Bytes, data, false);
+ }
+ return data;
+ case '{':
+ _charPos++;
+ SetToken(JsonToken.StartObject);
+ ReadIntoWrappedTypeObject();
+ isWrapped = true;
+ break;
+ case '[':
+ _charPos++;
+ SetToken(JsonToken.StartArray);
+ return ReadArrayIntoByteArray();
+ case 'n':
+ HandleNull();
+ return null;
+ case '/':
+ ParseComment(false);
+ break;
+ case ',':
+ ProcessValueComma();
+ break;
+ case ']':
+ _charPos++;
+ if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
+ {
+ SetToken(JsonToken.EndArray);
+ return null;
+ }
+ throw CreateUnexpectedCharacterException(currentChar);
+ case StringUtils.CarriageReturn:
+ ProcessCarriageReturn(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+ // eat
+ _charPos++;
+ break;
+ default:
+ _charPos++;
+
+ if (!char.IsWhiteSpace(currentChar))
+ {
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+
+ // eat
+ break;
+ }
+ }
+ case State.Finished:
+ ReadFinished();
+ return null;
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
+ }
+ }
+
+ private object? ReadStringValue(ReadType readType)
+ {
+ EnsureBuffer();
+ MiscellaneousUtils.Assert(_chars != null);
+
+ switch (_currentState)
+ {
+ case State.PostValue:
+ if (ParsePostValue(true))
+ {
+ return null;
+ }
+ goto case State.Start;
+ case State.Start:
+ case State.Property:
+ case State.Array:
+ case State.ArrayStart:
+ case State.Constructor:
+ case State.ConstructorStart:
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (ReadNullChar())
+ {
+ SetToken(JsonToken.None, null, false);
+ return null;
+ }
+ break;
+ case '"':
+ case '\'':
+ ParseString(currentChar, readType);
+ return FinishReadQuotedStringValue(readType);
+ case '-':
+ if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I')
+ {
+ return ParseNumberNegativeInfinity(readType);
+ }
+ else
+ {
+ ParseNumber(readType);
+ return Value;
+ }
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (readType != ReadType.ReadAsString)
+ {
+ _charPos++;
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+ ParseNumber(ReadType.ReadAsString);
+ return Value;
+ case 't':
+ case 'f':
+ if (readType != ReadType.ReadAsString)
+ {
+ _charPos++;
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+ string expected = currentChar == 't' ? JsonConvert.True : JsonConvert.False;
+ if (!MatchValueWithTrailingSeparator(expected))
+ {
+ throw CreateUnexpectedCharacterException(_chars[_charPos]);
+ }
+ SetToken(JsonToken.String, expected);
+ return expected;
+ case 'I':
+ return ParseNumberPositiveInfinity(readType);
+ case 'N':
+ return ParseNumberNaN(readType);
+ case 'n':
+ HandleNull();
+ return null;
+ case '/':
+ ParseComment(false);
+ break;
+ case ',':
+ ProcessValueComma();
+ break;
+ case ']':
+ _charPos++;
+ if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
+ {
+ SetToken(JsonToken.EndArray);
+ return null;
+ }
+ throw CreateUnexpectedCharacterException(currentChar);
+ case StringUtils.CarriageReturn:
+ ProcessCarriageReturn(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+ // eat
+ _charPos++;
+ break;
+ default:
+ _charPos++;
+
+ if (!char.IsWhiteSpace(currentChar))
+ {
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+
+ // eat
+ break;
+ }
+ }
+ case State.Finished:
+ ReadFinished();
+ return null;
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
+ }
+ }
+
+ private object? FinishReadQuotedStringValue(ReadType readType)
+ {
+ switch (readType)
+ {
+ case ReadType.ReadAsBytes:
+ case ReadType.ReadAsString:
+ return Value;
+ case ReadType.ReadAsDateTime:
+ if (Value is DateTime time)
+ {
+ return time;
+ }
+
+ return ReadDateTimeString((string?)Value);
+#if HAVE_DATE_TIME_OFFSET
+ case ReadType.ReadAsDateTimeOffset:
+ if (Value is DateTimeOffset offset)
+ {
+ return offset;
+ }
+
+ return ReadDateTimeOffsetString((string?)Value);
+#endif
+ default:
+ throw new ArgumentOutOfRangeException(nameof(readType));
+ }
+ }
+
+ private JsonReaderException CreateUnexpectedCharacterException(char c)
+ {
+ return JsonReaderException.Create(this, "Unexpected character encountered while parsing value: {0}.".FormatWith(CultureInfo.InvariantCulture, c));
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public override bool? ReadAsBoolean()
+ {
+ EnsureBuffer();
+ MiscellaneousUtils.Assert(_chars != null);
+
+ switch (_currentState)
+ {
+ case State.PostValue:
+ if (ParsePostValue(true))
+ {
+ return null;
+ }
+ goto case State.Start;
+ case State.Start:
+ case State.Property:
+ case State.Array:
+ case State.ArrayStart:
+ case State.Constructor:
+ case State.ConstructorStart:
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (ReadNullChar())
+ {
+ SetToken(JsonToken.None, null, false);
+ return null;
+ }
+ break;
+ case '"':
+ case '\'':
+ ParseString(currentChar, ReadType.Read);
+ return ReadBooleanString(_stringReference.ToString());
+ case 'n':
+ HandleNull();
+ return null;
+ case '-':
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ ParseNumber(ReadType.Read);
+ bool b;
+#if HAVE_BIG_INTEGER
+ if (Value is BigInteger integer)
+ {
+ b = integer != 0;
+ }
+ else
+#endif
+ {
+ b = Convert.ToBoolean(Value, CultureInfo.InvariantCulture);
+ }
+ SetToken(JsonToken.Boolean, b, false);
+ return b;
+ case 't':
+ case 'f':
+ bool isTrue = currentChar == 't';
+ string expected = isTrue ? JsonConvert.True : JsonConvert.False;
+
+ if (!MatchValueWithTrailingSeparator(expected))
+ {
+ throw CreateUnexpectedCharacterException(_chars[_charPos]);
+ }
+ SetToken(JsonToken.Boolean, isTrue);
+ return isTrue;
+ case '/':
+ ParseComment(false);
+ break;
+ case ',':
+ ProcessValueComma();
+ break;
+ case ']':
+ _charPos++;
+ if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
+ {
+ SetToken(JsonToken.EndArray);
+ return null;
+ }
+ throw CreateUnexpectedCharacterException(currentChar);
+ case StringUtils.CarriageReturn:
+ ProcessCarriageReturn(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+ // eat
+ _charPos++;
+ break;
+ default:
+ _charPos++;
+
+ if (!char.IsWhiteSpace(currentChar))
+ {
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+
+ // eat
+ break;
+ }
+ }
+ case State.Finished:
+ ReadFinished();
+ return null;
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
+ }
+ }
+
+ private void ProcessValueComma()
+ {
+ _charPos++;
+
+ if (_currentState != State.PostValue)
+ {
+ SetToken(JsonToken.Undefined);
+ JsonReaderException ex = CreateUnexpectedCharacterException(',');
+ // so the comma will be parsed again
+ _charPos--;
+
+ throw ex;
+ }
+
+ SetStateBasedOnCurrent();
+ }
+
+ private object? ReadNumberValue(ReadType readType)
+ {
+ EnsureBuffer();
+ MiscellaneousUtils.Assert(_chars != null);
+
+ switch (_currentState)
+ {
+ case State.PostValue:
+ if (ParsePostValue(true))
+ {
+ return null;
+ }
+ goto case State.Start;
+ case State.Start:
+ case State.Property:
+ case State.Array:
+ case State.ArrayStart:
+ case State.Constructor:
+ case State.ConstructorStart:
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (ReadNullChar())
+ {
+ SetToken(JsonToken.None, null, false);
+ return null;
+ }
+ break;
+ case '"':
+ case '\'':
+ ParseString(currentChar, readType);
+ return FinishReadQuotedNumber(readType);
+ case 'n':
+ HandleNull();
+ return null;
+ case 'N':
+ return ParseNumberNaN(readType);
+ case 'I':
+ return ParseNumberPositiveInfinity(readType);
+ case '-':
+ if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I')
+ {
+ return ParseNumberNegativeInfinity(readType);
+ }
+ else
+ {
+ ParseNumber(readType);
+ return Value;
+ }
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ ParseNumber(readType);
+ return Value;
+ case '/':
+ ParseComment(false);
+ break;
+ case ',':
+ ProcessValueComma();
+ break;
+ case ']':
+ _charPos++;
+ if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
+ {
+ SetToken(JsonToken.EndArray);
+ return null;
+ }
+ throw CreateUnexpectedCharacterException(currentChar);
+ case StringUtils.CarriageReturn:
+ ProcessCarriageReturn(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+ // eat
+ _charPos++;
+ break;
+ default:
+ _charPos++;
+
+ if (!char.IsWhiteSpace(currentChar))
+ {
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+
+ // eat
+ break;
+ }
+ }
+ case State.Finished:
+ ReadFinished();
+ return null;
+ default:
+ throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
+ }
+ }
+
+ private object? FinishReadQuotedNumber(ReadType readType)
+ {
+ switch (readType)
+ {
+ case ReadType.ReadAsInt32:
+ return ReadInt32String(_stringReference.ToString());
+ case ReadType.ReadAsDecimal:
+ return ReadDecimalString(_stringReference.ToString());
+ case ReadType.ReadAsDouble:
+ return ReadDoubleString(_stringReference.ToString());
+ default:
+ throw new ArgumentOutOfRangeException(nameof(readType));
+ }
+ }
+
+#if HAVE_DATE_TIME_OFFSET
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public override DateTimeOffset? ReadAsDateTimeOffset()
+ {
+ return (DateTimeOffset?)ReadStringValue(ReadType.ReadAsDateTimeOffset);
+ }
+#endif
+
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public override decimal? ReadAsDecimal()
+ {
+ return (decimal?)ReadNumberValue(ReadType.ReadAsDecimal);
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public override double? ReadAsDouble()
+ {
+ return (double?)ReadNumberValue(ReadType.ReadAsDouble);
+ }
+
+ private void HandleNull()
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (EnsureChars(1, true))
+ {
+ char next = _chars[_charPos + 1];
+
+ if (next == 'u')
+ {
+ ParseNull();
+ return;
+ }
+
+ _charPos += 2;
+ throw CreateUnexpectedCharacterException(_chars[_charPos - 1]);
+ }
+
+ _charPos = _charsUsed;
+ throw CreateUnexpectedEndException();
+ }
+
+ private void ReadFinished()
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (EnsureChars(0, false))
+ {
+ EatWhitespace();
+ if (_isEndOfFile)
+ {
+ return;
+ }
+ if (_chars[_charPos] == '/')
+ {
+ ParseComment(false);
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+ }
+
+ SetToken(JsonToken.None);
+ }
+
+ private bool ReadNullChar()
+ {
+ if (_charsUsed == _charPos)
+ {
+ if (ReadData(false) == 0)
+ {
+ _isEndOfFile = true;
+ return true;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+
+ return false;
+ }
+
+ private void EnsureBuffer()
+ {
+ if (_chars == null)
+ {
+ _chars = BufferUtils.RentBuffer(_arrayPool, 1024);
+ _chars[0] = '\0';
+ }
+ }
+
+ private void ReadStringIntoBuffer(char quote)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ int charPos = _charPos;
+ int initialPosition = _charPos;
+ int lastWritePosition = _charPos;
+ _stringBuffer.Position = 0;
+
+ while (true)
+ {
+ switch (_chars[charPos++])
+ {
+ case '\0':
+ if (_charsUsed == charPos - 1)
+ {
+ charPos--;
+
+ if (ReadData(true) == 0)
+ {
+ _charPos = charPos;
+ throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote));
+ }
+ }
+ break;
+ case '\\':
+ _charPos = charPos;
+ if (!EnsureChars(0, true))
+ {
+ throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote));
+ }
+
+ // start of escape sequence
+ int escapeStartPos = charPos - 1;
+
+ char currentChar = _chars[charPos];
+ charPos++;
+
+ char writeChar;
+
+ switch (currentChar)
+ {
+ case 'b':
+ writeChar = '\b';
+ break;
+ case 't':
+ writeChar = '\t';
+ break;
+ case 'n':
+ writeChar = '\n';
+ break;
+ case 'f':
+ writeChar = '\f';
+ break;
+ case 'r':
+ writeChar = '\r';
+ break;
+ case '\\':
+ writeChar = '\\';
+ break;
+ case '"':
+ case '\'':
+ case '/':
+ writeChar = currentChar;
+ break;
+ case 'u':
+ _charPos = charPos;
+ writeChar = ParseUnicode();
+
+ if (StringUtils.IsLowSurrogate(writeChar))
+ {
+ // low surrogate with no preceding high surrogate; this char is replaced
+ writeChar = UnicodeReplacementChar;
+ }
+ else if (StringUtils.IsHighSurrogate(writeChar))
+ {
+ bool anotherHighSurrogate;
+
+ // loop for handling situations where there are multiple consecutive high surrogates
+ do
+ {
+ anotherHighSurrogate = false;
+
+ // potential start of a surrogate pair
+ if (EnsureChars(2, true) && _chars[_charPos] == '\\' && _chars[_charPos + 1] == 'u')
+ {
+ char highSurrogate = writeChar;
+
+ _charPos += 2;
+ writeChar = ParseUnicode();
+
+ if (StringUtils.IsLowSurrogate(writeChar))
+ {
+ // a valid surrogate pair!
+ }
+ else if (StringUtils.IsHighSurrogate(writeChar))
+ {
+ // another high surrogate; replace current and start check over
+ highSurrogate = UnicodeReplacementChar;
+ anotherHighSurrogate = true;
+ }
+ else
+ {
+ // high surrogate not followed by low surrogate; original char is replaced
+ highSurrogate = UnicodeReplacementChar;
+ }
+
+ EnsureBufferNotEmpty();
+
+ WriteCharToBuffer(highSurrogate, lastWritePosition, escapeStartPos);
+ lastWritePosition = _charPos;
+ }
+ else
+ {
+ // there are not enough remaining chars for the low surrogate or is not follow by unicode sequence
+ // replace high surrogate and continue on as usual
+ writeChar = UnicodeReplacementChar;
+ }
+ } while (anotherHighSurrogate);
+ }
+
+ charPos = _charPos;
+ break;
+ default:
+ _charPos = charPos;
+ throw JsonReaderException.Create(this, "Bad JSON escape sequence: {0}.".FormatWith(CultureInfo.InvariantCulture, @"\" + currentChar));
+ }
+
+ EnsureBufferNotEmpty();
+ WriteCharToBuffer(writeChar, lastWritePosition, escapeStartPos);
+
+ lastWritePosition = charPos;
+ break;
+ case StringUtils.CarriageReturn:
+ _charPos = charPos - 1;
+ ProcessCarriageReturn(true);
+ charPos = _charPos;
+ break;
+ case StringUtils.LineFeed:
+ _charPos = charPos - 1;
+ ProcessLineFeed();
+ charPos = _charPos;
+ break;
+ case '"':
+ case '\'':
+ if (_chars[charPos - 1] == quote)
+ {
+ FinishReadStringIntoBuffer(charPos - 1, initialPosition, lastWritePosition);
+ return;
+ }
+ break;
+ }
+ }
+ }
+
+ private void FinishReadStringIntoBuffer(int charPos, int initialPosition, int lastWritePosition)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (initialPosition == lastWritePosition)
+ {
+ _stringReference = new StringReference(_chars, initialPosition, charPos - initialPosition);
+ }
+ else
+ {
+ EnsureBufferNotEmpty();
+
+ if (charPos > lastWritePosition)
+ {
+ _stringBuffer.Append(_arrayPool, _chars, lastWritePosition, charPos - lastWritePosition);
+ }
+
+ _stringReference = new StringReference(_stringBuffer.InternalBuffer!, 0, _stringBuffer.Position);
+ }
+
+ _charPos = charPos + 1;
+ }
+
+ private void WriteCharToBuffer(char writeChar, int lastWritePosition, int writeToPosition)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (writeToPosition > lastWritePosition)
+ {
+ _stringBuffer.Append(_arrayPool, _chars, lastWritePosition, writeToPosition - lastWritePosition);
+ }
+
+ _stringBuffer.Append(_arrayPool, writeChar);
+ }
+
+ private char ConvertUnicode(bool enoughChars)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (enoughChars)
+ {
+ if (ConvertUtils.TryHexTextToInt(_chars, _charPos, _charPos + 4, out int value))
+ {
+ char hexChar = Convert.ToChar(value);
+ _charPos += 4;
+ return hexChar;
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, @"Invalid Unicode escape sequence: \u{0}.".FormatWith(CultureInfo.InvariantCulture, new string(_chars, _charPos, 4)));
+ }
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Unexpected end while parsing Unicode escape sequence.");
+ }
+ }
+
+ private char ParseUnicode()
+ {
+ return ConvertUnicode(EnsureChars(4, true));
+ }
+
+ private void ReadNumberIntoBuffer()
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ int charPos = _charPos;
+
+ while (true)
+ {
+ char currentChar = _chars[charPos];
+ if (currentChar == '\0')
+ {
+ _charPos = charPos;
+
+ if (_charsUsed == charPos)
+ {
+ if (ReadData(true) == 0)
+ {
+ return;
+ }
+ }
+ else
+ {
+ return;
+ }
+ }
+ else if (ReadNumberCharIntoBuffer(currentChar, charPos))
+ {
+ return;
+ }
+ else
+ {
+ charPos++;
+ }
+ }
+ }
+
+ private bool ReadNumberCharIntoBuffer(char currentChar, int charPos)
+ {
+ switch (currentChar)
+ {
+ case '-':
+ case '+':
+ case 'a':
+ case 'A':
+ case 'b':
+ case 'B':
+ case 'c':
+ case 'C':
+ case 'd':
+ case 'D':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'x':
+ case 'X':
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return false;
+ default:
+ _charPos = charPos;
+
+ if (char.IsWhiteSpace(currentChar) || currentChar == ',' || currentChar == '}' || currentChar == ']' || currentChar == ')' || currentChar == '/')
+ {
+ return true;
+ }
+
+ throw JsonReaderException.Create(this, "Unexpected character encountered while parsing number: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar));
+ }
+ }
+
+ private void ClearRecentString()
+ {
+ _stringBuffer.Position = 0;
+ _stringReference = new StringReference();
+ }
+
+ private bool ParsePostValue(bool ignoreComments)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (_charsUsed == _charPos)
+ {
+ if (ReadData(false) == 0)
+ {
+ _currentState = State.Finished;
+ return false;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+ break;
+ case '}':
+ _charPos++;
+ SetToken(JsonToken.EndObject);
+ return true;
+ case ']':
+ _charPos++;
+ SetToken(JsonToken.EndArray);
+ return true;
+ case ')':
+ _charPos++;
+ SetToken(JsonToken.EndConstructor);
+ return true;
+ case '/':
+ ParseComment(!ignoreComments);
+ if (!ignoreComments)
+ {
+ return true;
+ }
+ break;
+ case ',':
+ _charPos++;
+
+ // finished parsing
+ SetStateBasedOnCurrent();
+ return false;
+ case ' ':
+ case StringUtils.Tab:
+ // eat
+ _charPos++;
+ break;
+ case StringUtils.CarriageReturn:
+ ProcessCarriageReturn(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ default:
+ if (char.IsWhiteSpace(currentChar))
+ {
+ // eat
+ _charPos++;
+ }
+ else
+ {
+ // handle multiple content without comma delimiter
+ if (SupportMultipleContent && Depth == 0)
+ {
+ SetStateBasedOnCurrent();
+ return false;
+ }
+
+ throw JsonReaderException.Create(this, "After parsing a value an unexpected character was encountered: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar));
+ }
+ break;
+ }
+ }
+ }
+
+ private bool ParseObject()
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (_charsUsed == _charPos)
+ {
+ if (ReadData(false) == 0)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+ break;
+ case '}':
+ SetToken(JsonToken.EndObject);
+ _charPos++;
+ return true;
+ case '/':
+ ParseComment(true);
+ return true;
+ case StringUtils.CarriageReturn:
+ ProcessCarriageReturn(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+ // eat
+ _charPos++;
+ break;
+ default:
+ if (char.IsWhiteSpace(currentChar))
+ {
+ // eat
+ _charPos++;
+ }
+ else
+ {
+ return ParseProperty();
+ }
+ break;
+ }
+ }
+ }
+
+ private bool ParseProperty()
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ char firstChar = _chars[_charPos];
+ char quoteChar;
+
+ if (firstChar == '"' || firstChar == '\'')
+ {
+ _charPos++;
+ quoteChar = firstChar;
+ ShiftBufferIfNeeded();
+ ReadStringIntoBuffer(quoteChar);
+ }
+ else if (ValidIdentifierChar(firstChar))
+ {
+ quoteChar = '\0';
+ ShiftBufferIfNeeded();
+ ParseUnquotedProperty();
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+
+ string? propertyName;
+
+ if (PropertyNameTable != null)
+ {
+ propertyName = PropertyNameTable.Get(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length);
+
+ // no match in name table
+ if (propertyName == null)
+ {
+ propertyName = _stringReference.ToString();
+ }
+ }
+ else
+ {
+ propertyName = _stringReference.ToString();
+ }
+
+ EatWhitespace();
+
+ if (_chars[_charPos] != ':')
+ {
+ throw JsonReaderException.Create(this, "Invalid character after parsing property name. Expected ':' but got: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+
+ _charPos++;
+
+ SetToken(JsonToken.PropertyName, propertyName);
+ _quoteChar = quoteChar;
+ ClearRecentString();
+
+ return true;
+ }
+
+ private bool ValidIdentifierChar(char value)
+ {
+ return (char.IsLetterOrDigit(value) || value == '_' || value == '$');
+ }
+
+ private void ParseUnquotedProperty()
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ int initialPosition = _charPos;
+
+ // parse unquoted property name until whitespace or colon
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+ if (currentChar == '\0')
+ {
+ if (_charsUsed == _charPos)
+ {
+ if (ReadData(true) == 0)
+ {
+ throw JsonReaderException.Create(this, "Unexpected end while parsing unquoted property name.");
+ }
+
+ continue;
+ }
+
+ _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition);
+ return;
+ }
+
+ if (ReadUnquotedPropertyReportIfDone(currentChar, initialPosition))
+ {
+ return;
+ }
+ }
+ }
+
+ private bool ReadUnquotedPropertyReportIfDone(char currentChar, int initialPosition)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (ValidIdentifierChar(currentChar))
+ {
+ _charPos++;
+ return false;
+ }
+
+ if (char.IsWhiteSpace(currentChar) || currentChar == ':')
+ {
+ _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition);
+ return true;
+ }
+
+ throw JsonReaderException.Create(this, "Invalid JavaScript property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar));
+ }
+
+ private bool ParseValue()
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (_charsUsed == _charPos)
+ {
+ if (ReadData(false) == 0)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+ break;
+ case '"':
+ case '\'':
+ ParseString(currentChar, ReadType.Read);
+ return true;
+ case 't':
+ ParseTrue();
+ return true;
+ case 'f':
+ ParseFalse();
+ return true;
+ case 'n':
+ if (EnsureChars(1, true))
+ {
+ char next = _chars[_charPos + 1];
+
+ if (next == 'u')
+ {
+ ParseNull();
+ }
+ else if (next == 'e')
+ {
+ ParseConstructor();
+ }
+ else
+ {
+ throw CreateUnexpectedCharacterException(_chars[_charPos]);
+ }
+ }
+ else
+ {
+ _charPos++;
+ throw CreateUnexpectedEndException();
+ }
+ return true;
+ case 'N':
+ ParseNumberNaN(ReadType.Read);
+ return true;
+ case 'I':
+ ParseNumberPositiveInfinity(ReadType.Read);
+ return true;
+ case '-':
+ if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I')
+ {
+ ParseNumberNegativeInfinity(ReadType.Read);
+ }
+ else
+ {
+ ParseNumber(ReadType.Read);
+ }
+ return true;
+ case '/':
+ ParseComment(true);
+ return true;
+ case 'u':
+ ParseUndefined();
+ return true;
+ case '{':
+ _charPos++;
+ SetToken(JsonToken.StartObject);
+ return true;
+ case '[':
+ _charPos++;
+ SetToken(JsonToken.StartArray);
+ return true;
+ case ']':
+ _charPos++;
+ SetToken(JsonToken.EndArray);
+ return true;
+ case ',':
+ // don't increment position, the next call to read will handle comma
+ // this is done to handle multiple empty comma values
+ SetToken(JsonToken.Undefined);
+ return true;
+ case ')':
+ _charPos++;
+ SetToken(JsonToken.EndConstructor);
+ return true;
+ case StringUtils.CarriageReturn:
+ ProcessCarriageReturn(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ case ' ':
+ case StringUtils.Tab:
+ // eat
+ _charPos++;
+ break;
+ default:
+ if (char.IsWhiteSpace(currentChar))
+ {
+ // eat
+ _charPos++;
+ break;
+ }
+ if (char.IsNumber(currentChar) || currentChar == '-' || currentChar == '.')
+ {
+ ParseNumber(ReadType.Read);
+ return true;
+ }
+
+ throw CreateUnexpectedCharacterException(currentChar);
+ }
+ }
+ }
+
+ private void ProcessLineFeed()
+ {
+ _charPos++;
+ OnNewLine(_charPos);
+ }
+
+ private void ProcessCarriageReturn(bool append)
+ {
+ _charPos++;
+
+ SetNewLine(EnsureChars(1, append));
+ }
+
+ private void EatWhitespace()
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+
+ switch (currentChar)
+ {
+ case '\0':
+ if (_charsUsed == _charPos)
+ {
+ if (ReadData(false) == 0)
+ {
+ return;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+ break;
+ case StringUtils.CarriageReturn:
+ ProcessCarriageReturn(false);
+ break;
+ case StringUtils.LineFeed:
+ ProcessLineFeed();
+ break;
+ default:
+ if (currentChar == ' ' || char.IsWhiteSpace(currentChar))
+ {
+ _charPos++;
+ }
+ else
+ {
+ return;
+ }
+ break;
+ }
+ }
+ }
+
+ private void ParseConstructor()
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (MatchValueWithTrailingSeparator("new"))
+ {
+ EatWhitespace();
+
+ int initialPosition = _charPos;
+ int endPosition;
+
+ while (true)
+ {
+ char currentChar = _chars[_charPos];
+ if (currentChar == '\0')
+ {
+ if (_charsUsed == _charPos)
+ {
+ if (ReadData(true) == 0)
+ {
+ throw JsonReaderException.Create(this, "Unexpected end while parsing constructor.");
+ }
+ }
+ else
+ {
+ endPosition = _charPos;
+ _charPos++;
+ break;
+ }
+ }
+ else if (char.IsLetterOrDigit(currentChar))
+ {
+ _charPos++;
+ }
+ else if (currentChar == StringUtils.CarriageReturn)
+ {
+ endPosition = _charPos;
+ ProcessCarriageReturn(true);
+ break;
+ }
+ else if (currentChar == StringUtils.LineFeed)
+ {
+ endPosition = _charPos;
+ ProcessLineFeed();
+ break;
+ }
+ else if (char.IsWhiteSpace(currentChar))
+ {
+ endPosition = _charPos;
+ _charPos++;
+ break;
+ }
+ else if (currentChar == '(')
+ {
+ endPosition = _charPos;
+ break;
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar));
+ }
+ }
+
+ _stringReference = new StringReference(_chars, initialPosition, endPosition - initialPosition);
+ string constructorName = _stringReference.ToString();
+
+ EatWhitespace();
+
+ if (_chars[_charPos] != '(')
+ {
+ throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+
+ _charPos++;
+
+ ClearRecentString();
+
+ SetToken(JsonToken.StartConstructor, constructorName);
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Unexpected content while parsing JSON.");
+ }
+ }
+
+ private void ParseNumber(ReadType readType)
+ {
+ ShiftBufferIfNeeded();
+ MiscellaneousUtils.Assert(_chars != null);
+
+ char firstChar = _chars[_charPos];
+ int initialPosition = _charPos;
+
+ ReadNumberIntoBuffer();
+
+ ParseReadNumber(readType, firstChar, initialPosition);
+ }
+
+ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosition)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ // set state to PostValue now so that if there is an error parsing the number then the reader can continue
+ SetPostValueState(true);
+
+ _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition);
+
+ object numberValue;
+ JsonToken numberType;
+
+ bool singleDigit = (char.IsDigit(firstChar) && _stringReference.Length == 1);
+ bool nonBase10 = (firstChar == '0' && _stringReference.Length > 1 && _stringReference.Chars[_stringReference.StartIndex + 1] != '.' && _stringReference.Chars[_stringReference.StartIndex + 1] != 'e' && _stringReference.Chars[_stringReference.StartIndex + 1] != 'E');
+
+ switch (readType)
+ {
+ case ReadType.ReadAsString:
+ {
+ string number = _stringReference.ToString();
+
+ // validate that the string is a valid number
+ if (nonBase10)
+ {
+ try
+ {
+ if (number.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
+ {
+ Convert.ToInt64(number, 16);
+ }
+ else
+ {
+ Convert.ToInt64(number, 8);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, number), ex);
+ }
+ }
+ else
+ {
+ if (!double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out _))
+ {
+ throw ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
+ }
+ }
+
+ numberType = JsonToken.String;
+ numberValue = number;
+ }
+ break;
+ case ReadType.ReadAsInt32:
+ {
+ if (singleDigit)
+ {
+ // digit char values start at 48
+ numberValue = firstChar - 48;
+ }
+ else if (nonBase10)
+ {
+ string number = _stringReference.ToString();
+
+ try
+ {
+ int integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt32(number, 16) : Convert.ToInt32(number, 8);
+
+ numberValue = integer;
+ }
+ catch (Exception ex)
+ {
+ throw ThrowReaderError("Input string '{0}' is not a valid integer.".FormatWith(CultureInfo.InvariantCulture, number), ex);
+ }
+ }
+ else
+ {
+ ParseResult parseResult = ConvertUtils.Int32TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out int value);
+ if (parseResult == ParseResult.Success)
+ {
+ numberValue = value;
+ }
+ else if (parseResult == ParseResult.Overflow)
+ {
+ throw ThrowReaderError("JSON integer {0} is too large or small for an Int32.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
+ }
+ else
+ {
+ throw ThrowReaderError("Input string '{0}' is not a valid integer.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
+ }
+ }
+
+ numberType = JsonToken.Integer;
+ }
+ break;
+ case ReadType.ReadAsDecimal:
+ {
+ if (singleDigit)
+ {
+ // digit char values start at 48
+ numberValue = (decimal)firstChar - 48;
+ }
+ else if (nonBase10)
+ {
+ string number = _stringReference.ToString();
+
+ try
+ {
+ // decimal.Parse doesn't support parsing hexadecimal values
+ long integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8);
+
+ numberValue = Convert.ToDecimal(integer);
+ }
+ catch (Exception ex)
+ {
+ throw ThrowReaderError("Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, number), ex);
+ }
+ }
+ else
+ {
+ ParseResult parseResult = ConvertUtils.DecimalTryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out decimal value);
+ if (parseResult == ParseResult.Success)
+ {
+ numberValue = value;
+ }
+ else
+ {
+ throw ThrowReaderError("Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
+ }
+ }
+
+ numberType = JsonToken.Float;
+ }
+ break;
+ case ReadType.ReadAsDouble:
+ {
+ if (singleDigit)
+ {
+ // digit char values start at 48
+ numberValue = (double)firstChar - 48;
+ }
+ else if (nonBase10)
+ {
+ string number = _stringReference.ToString();
+
+ try
+ {
+ // double.Parse doesn't support parsing hexadecimal values
+ long integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8);
+
+ numberValue = Convert.ToDouble(integer);
+ }
+ catch (Exception ex)
+ {
+ throw ThrowReaderError("Input string '{0}' is not a valid double.".FormatWith(CultureInfo.InvariantCulture, number), ex);
+ }
+ }
+ else
+ {
+ string number = _stringReference.ToString();
+
+ if (double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out double value))
+ {
+ numberValue = value;
+ }
+ else
+ {
+ throw ThrowReaderError("Input string '{0}' is not a valid double.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
+ }
+ }
+
+ numberType = JsonToken.Float;
+ }
+ break;
+ case ReadType.Read:
+ case ReadType.ReadAsInt64:
+ {
+ if (singleDigit)
+ {
+ // digit char values start at 48
+ numberValue = (long)firstChar - 48;
+ numberType = JsonToken.Integer;
+ }
+ else if (nonBase10)
+ {
+ string number = _stringReference.ToString();
+
+ try
+ {
+ numberValue = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8);
+ }
+ catch (Exception ex)
+ {
+ throw ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, number), ex);
+ }
+
+ numberType = JsonToken.Integer;
+ }
+ else
+ {
+ ParseResult parseResult = ConvertUtils.Int64TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out long value);
+ if (parseResult == ParseResult.Success)
+ {
+ numberValue = value;
+ numberType = JsonToken.Integer;
+ }
+ else if (parseResult == ParseResult.Overflow)
+ {
+#if HAVE_BIG_INTEGER
+ string number = _stringReference.ToString();
+
+ if (number.Length > MaximumJavascriptIntegerCharacterLength)
+ {
+ throw ThrowReaderError("JSON integer {0} is too large to parse.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
+ }
+
+ numberValue = BigIntegerParse(number, CultureInfo.InvariantCulture);
+ numberType = JsonToken.Integer;
+#else
+ throw ThrowReaderError("JSON integer {0} is too large or small for an Int64.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
+#endif
+ }
+ else
+ {
+ if (_floatParseHandling == FloatParseHandling.Decimal)
+ {
+ parseResult = ConvertUtils.DecimalTryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out decimal d);
+ if (parseResult == ParseResult.Success)
+ {
+ numberValue = d;
+ }
+ else
+ {
+ throw ThrowReaderError("Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
+ }
+ }
+ else
+ {
+ string number = _stringReference.ToString();
+
+ if (double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out double d))
+ {
+ numberValue = d;
+ }
+ else
+ {
+ throw ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
+ }
+ }
+
+ numberType = JsonToken.Float;
+ }
+ }
+ }
+ break;
+ default:
+ throw JsonReaderException.Create(this, "Cannot read number value as type.");
+ }
+
+ ClearRecentString();
+
+ // index has already been updated
+ SetToken(numberType, numberValue, false);
+ }
+
+ private JsonReaderException ThrowReaderError(string message, Exception? ex = null)
+ {
+ SetToken(JsonToken.Undefined, null, false);
+ return JsonReaderException.Create(this, message, ex);
+ }
+
+#if HAVE_BIG_INTEGER
+ // By using the BigInteger type in a separate method,
+ // the runtime can execute the ParseNumber even if
+ // the System.Numerics.BigInteger.Parse method is
+ // missing, which happens in some versions of Mono
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static object BigIntegerParse(string number, CultureInfo culture)
+ {
+ return System.Numerics.BigInteger.Parse(number, culture);
+ }
+#endif
+
+ private void ParseComment(bool setToken)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ // should have already parsed / character before reaching this method
+ _charPos++;
+
+ if (!EnsureChars(1, false))
+ {
+ throw JsonReaderException.Create(this, "Unexpected end while parsing comment.");
+ }
+
+ bool singlelineComment;
+
+ if (_chars[_charPos] == '*')
+ {
+ singlelineComment = false;
+ }
+ else if (_chars[_charPos] == '/')
+ {
+ singlelineComment = true;
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Error parsing comment. Expected: *, got {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
+ }
+
+ _charPos++;
+
+ int initialPosition = _charPos;
+
+ while (true)
+ {
+ switch (_chars[_charPos])
+ {
+ case '\0':
+ if (_charsUsed == _charPos)
+ {
+ if (ReadData(true) == 0)
+ {
+ if (!singlelineComment)
+ {
+ throw JsonReaderException.Create(this, "Unexpected end while parsing comment.");
+ }
+
+ EndComment(setToken, initialPosition, _charPos);
+ return;
+ }
+ }
+ else
+ {
+ _charPos++;
+ }
+ break;
+ case '*':
+ _charPos++;
+
+ if (!singlelineComment)
+ {
+ if (EnsureChars(0, true))
+ {
+ if (_chars[_charPos] == '/')
+ {
+ EndComment(setToken, initialPosition, _charPos - 1);
+
+ _charPos++;
+ return;
+ }
+ }
+ }
+ break;
+ case StringUtils.CarriageReturn:
+ if (singlelineComment)
+ {
+ EndComment(setToken, initialPosition, _charPos);
+ return;
+ }
+ ProcessCarriageReturn(true);
+ break;
+ case StringUtils.LineFeed:
+ if (singlelineComment)
+ {
+ EndComment(setToken, initialPosition, _charPos);
+ return;
+ }
+ ProcessLineFeed();
+ break;
+ default:
+ _charPos++;
+ break;
+ }
+ }
+ }
+
+ private void EndComment(bool setToken, int initialPosition, int endPosition)
+ {
+ if (setToken)
+ {
+ SetToken(JsonToken.Comment, new string(_chars, initialPosition, endPosition - initialPosition));
+ }
+ }
+
+ private bool MatchValue(string value)
+ {
+ return MatchValue(EnsureChars(value.Length - 1, true), value);
+ }
+
+ private bool MatchValue(bool enoughChars, string value)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ if (!enoughChars)
+ {
+ _charPos = _charsUsed;
+ throw CreateUnexpectedEndException();
+ }
+
+ for (int i = 0; i < value.Length; i++)
+ {
+ if (_chars[_charPos + i] != value[i])
+ {
+ _charPos += i;
+ return false;
+ }
+ }
+
+ _charPos += value.Length;
+
+ return true;
+ }
+
+ private bool MatchValueWithTrailingSeparator(string value)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ // will match value and then move to the next character, checking that it is a separator character
+ bool match = MatchValue(value);
+
+ if (!match)
+ {
+ return false;
+ }
+
+ if (!EnsureChars(0, false))
+ {
+ return true;
+ }
+
+ return IsSeparator(_chars[_charPos]) || _chars[_charPos] == '\0';
+ }
+
+ private bool IsSeparator(char c)
+ {
+ MiscellaneousUtils.Assert(_chars != null);
+
+ switch (c)
+ {
+ case '}':
+ case ']':
+ case ',':
+ return true;
+ case '/':
+ // check next character to see if start of a comment
+ if (!EnsureChars(1, false))
+ {
+ return false;
+ }
+
+ char nextChart = _chars[_charPos + 1];
+
+ return (nextChart == '*' || nextChart == '/');
+ case ')':
+ if (CurrentState == State.Constructor || CurrentState == State.ConstructorStart)
+ {
+ return true;
+ }
+ break;
+ case ' ':
+ case StringUtils.Tab:
+ case StringUtils.LineFeed:
+ case StringUtils.CarriageReturn:
+ return true;
+ default:
+ if (char.IsWhiteSpace(c))
+ {
+ return true;
+ }
+ break;
+ }
+
+ return false;
+ }
+
+ private void ParseTrue()
+ {
+ // check characters equal 'true'
+ // and that it is followed by either a separator character
+ // or the text ends
+ if (MatchValueWithTrailingSeparator(JsonConvert.True))
+ {
+ SetToken(JsonToken.Boolean, true);
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Error parsing boolean value.");
+ }
+ }
+
+ private void ParseNull()
+ {
+ if (MatchValueWithTrailingSeparator(JsonConvert.Null))
+ {
+ SetToken(JsonToken.Null);
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Error parsing null value.");
+ }
+ }
+
+ private void ParseUndefined()
+ {
+ if (MatchValueWithTrailingSeparator(JsonConvert.Undefined))
+ {
+ SetToken(JsonToken.Undefined);
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Error parsing undefined value.");
+ }
+ }
+
+ private void ParseFalse()
+ {
+ if (MatchValueWithTrailingSeparator(JsonConvert.False))
+ {
+ SetToken(JsonToken.Boolean, false);
+ }
+ else
+ {
+ throw JsonReaderException.Create(this, "Error parsing boolean value.");
+ }
+ }
+
+ private object ParseNumberNegativeInfinity(ReadType readType)
+ {
+ return ParseNumberNegativeInfinity(readType, MatchValueWithTrailingSeparator(JsonConvert.NegativeInfinity));
+ }
+
+ private object ParseNumberNegativeInfinity(ReadType readType, bool matched)
+ {
+ if (matched)
+ {
+ switch (readType)
+ {
+ case ReadType.Read:
+ case ReadType.ReadAsDouble:
+ if (_floatParseHandling == FloatParseHandling.Double)
+ {
+ SetToken(JsonToken.Float, double.NegativeInfinity);
+ return double.NegativeInfinity;
+ }
+ break;
+ case ReadType.ReadAsString:
+ SetToken(JsonToken.String, JsonConvert.NegativeInfinity);
+ return JsonConvert.NegativeInfinity;
+ }
+
+ throw JsonReaderException.Create(this, "Cannot read -Infinity value.");
+ }
+
+ throw JsonReaderException.Create(this, "Error parsing -Infinity value.");
+ }
+
+ private object ParseNumberPositiveInfinity(ReadType readType)
+ {
+ return ParseNumberPositiveInfinity(readType, MatchValueWithTrailingSeparator(JsonConvert.PositiveInfinity));
+ }
+ private object ParseNumberPositiveInfinity(ReadType readType, bool matched)
+ {
+ if (matched)
+ {
+ switch (readType)
+ {
+ case ReadType.Read:
+ case ReadType.ReadAsDouble:
+ if (_floatParseHandling == FloatParseHandling.Double)
+ {
+ SetToken(JsonToken.Float, double.PositiveInfinity);
+ return double.PositiveInfinity;
+ }
+ break;
+ case ReadType.ReadAsString:
+ SetToken(JsonToken.String, JsonConvert.PositiveInfinity);
+ return JsonConvert.PositiveInfinity;
+ }
+
+ throw JsonReaderException.Create(this, "Cannot read Infinity value.");
+ }
+
+ throw JsonReaderException.Create(this, "Error parsing Infinity value.");
+ }
+
+ private object ParseNumberNaN(ReadType readType)
+ {
+ return ParseNumberNaN(readType, MatchValueWithTrailingSeparator(JsonConvert.NaN));
+ }
+
+ private object ParseNumberNaN(ReadType readType, bool matched)
+ {
+ if (matched)
+ {
+ switch (readType)
+ {
+ case ReadType.Read:
+ case ReadType.ReadAsDouble:
+ if (_floatParseHandling == FloatParseHandling.Double)
+ {
+ SetToken(JsonToken.Float, double.NaN);
+ return double.NaN;
+ }
+ break;
+ case ReadType.ReadAsString:
+ SetToken(JsonToken.String, JsonConvert.NaN);
+ return JsonConvert.NaN;
+ }
+
+ throw JsonReaderException.Create(this, "Cannot read NaN value.");
+ }
+
+ throw JsonReaderException.Create(this, "Error parsing NaN value.");
+ }
+
+ ///
+ /// Changes the reader's state to .
+ /// If is set to true , the underlying is also closed.
+ ///
+ public override void Close()
+ {
+ base.Close();
+
+ if (_chars != null)
+ {
+ BufferUtils.ReturnBuffer(_arrayPool, _chars);
+ _chars = null;
+ }
+
+ if (CloseInput)
+ {
+#if HAVE_STREAM_READER_WRITER_CLOSE
+ _reader?.Close();
+#else
+ _reader?.Dispose();
+#endif
+ }
+
+ _stringBuffer.Clear(_arrayPool);
+ }
+
+ ///
+ /// Gets a value indicating whether the class can return line information.
+ ///
+ ///
+ /// true if and can be provided; otherwise, false .
+ ///
+ public bool HasLineInfo()
+ {
+ return true;
+ }
+
+ ///
+ /// Gets the current line number.
+ ///
+ ///
+ /// The current line number or 0 if no line information is available (for example, returns false ).
+ ///
+ public int LineNumber
+ {
+ get
+ {
+ if (CurrentState == State.Start && LinePosition == 0 && TokenType != JsonToken.Comment)
+ {
+ return 0;
+ }
+
+ return _lineNumber;
+ }
+ }
+
+ ///
+ /// Gets the current line position.
+ ///
+ ///
+ /// The current line position or 0 if no line information is available (for example, returns false ).
+ ///
+ public int LinePosition => _charPos - _lineStartPos;
+ }
+}
diff --git a/Libs/Newtonsoft.Json.AOT/JsonTextWriter.Async.cs b/Libs/Newtonsoft.Json.AOT/JsonTextWriter.Async.cs
new file mode 100644
index 0000000..dd7309e
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonTextWriter.Async.cs
@@ -0,0 +1,1361 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if HAVE_ASYNC
+
+using System;
+using System.Globalization;
+using System.Threading;
+#if HAVE_BIG_INTEGER
+using System.Numerics;
+#endif
+using System.Threading.Tasks;
+using LC.Newtonsoft.Json.Utilities;
+using System.Diagnostics;
+
+namespace LC.Newtonsoft.Json
+{
+ public partial class JsonTextWriter
+ {
+ // It's not safe to perform the async methods here in a derived class as if the synchronous equivalent
+ // has been overriden then the asychronous method will no longer be doing the same operation.
+#if HAVE_ASYNC // Double-check this isn't included inappropriately.
+ private readonly bool _safeAsync;
+#endif
+
+ ///
+ /// Asynchronously flushes whatever is in the buffer to the destination and also flushes the destination.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task FlushAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoFlushAsync(cancellationToken) : base.FlushAsync(cancellationToken);
+ }
+
+ internal Task DoFlushAsync(CancellationToken cancellationToken)
+ {
+ return cancellationToken.CancelIfRequestedAsync() ?? _writer.FlushAsync();
+ }
+
+ ///
+ /// Asynchronously writes the JSON value delimiter.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ protected override Task WriteValueDelimiterAsync(CancellationToken cancellationToken)
+ {
+ return _safeAsync ? DoWriteValueDelimiterAsync(cancellationToken) : base.WriteValueDelimiterAsync(cancellationToken);
+ }
+
+ internal Task DoWriteValueDelimiterAsync(CancellationToken cancellationToken)
+ {
+ return _writer.WriteAsync(',', cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes the specified end token.
+ ///
+ /// The end token to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ protected override Task WriteEndAsync(JsonToken token, CancellationToken cancellationToken)
+ {
+ return _safeAsync ? DoWriteEndAsync(token, cancellationToken) : base.WriteEndAsync(token, cancellationToken);
+ }
+
+ internal Task DoWriteEndAsync(JsonToken token, CancellationToken cancellationToken)
+ {
+ switch (token)
+ {
+ case JsonToken.EndObject:
+ return _writer.WriteAsync('}', cancellationToken);
+ case JsonToken.EndArray:
+ return _writer.WriteAsync(']', cancellationToken);
+ case JsonToken.EndConstructor:
+ return _writer.WriteAsync(')', cancellationToken);
+ default:
+ throw JsonWriterException.Create(this, "Invalid JsonToken: " + token, null);
+ }
+ }
+
+ ///
+ /// Asynchronously closes this writer.
+ /// If is set to true , the destination is also closed.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task CloseAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoCloseAsync(cancellationToken) : base.CloseAsync(cancellationToken);
+ }
+
+ internal async Task DoCloseAsync(CancellationToken cancellationToken)
+ {
+ if (Top == 0) // otherwise will happen in calls to WriteEndAsync
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ }
+
+ while (Top > 0)
+ {
+ await WriteEndAsync(cancellationToken).ConfigureAwait(false);
+ }
+
+ CloseBufferAndWriter();
+ }
+
+ ///
+ /// Asynchronously writes the end of the current JSON object or array.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteEndAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? WriteEndInternalAsync(cancellationToken) : base.WriteEndAsync(cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes indent characters.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ protected override Task WriteIndentAsync(CancellationToken cancellationToken)
+ {
+ return _safeAsync ? DoWriteIndentAsync(cancellationToken) : base.WriteIndentAsync(cancellationToken);
+ }
+
+ internal Task DoWriteIndentAsync(CancellationToken cancellationToken)
+ {
+ // levels of indentation multiplied by the indent count
+ int currentIndentCount = Top * _indentation;
+
+ int newLineLen = SetIndentChars();
+ MiscellaneousUtils.Assert(_indentChars != null);
+
+ if (currentIndentCount <= IndentCharBufferSize)
+ {
+ return _writer.WriteAsync(_indentChars, 0, newLineLen + currentIndentCount, cancellationToken);
+ }
+
+ return WriteIndentAsync(currentIndentCount, newLineLen, cancellationToken);
+ }
+
+ private async Task WriteIndentAsync(int currentIndentCount, int newLineLen, CancellationToken cancellationToken)
+ {
+ MiscellaneousUtils.Assert(_indentChars != null);
+
+ await _writer.WriteAsync(_indentChars, 0, newLineLen + Math.Min(currentIndentCount, IndentCharBufferSize), cancellationToken).ConfigureAwait(false);
+
+ while ((currentIndentCount -= IndentCharBufferSize) > 0)
+ {
+ await _writer.WriteAsync(_indentChars, newLineLen, Math.Min(currentIndentCount, IndentCharBufferSize), cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ private Task WriteValueInternalAsync(JsonToken token, string value, CancellationToken cancellationToken)
+ {
+ Task task = InternalWriteValueAsync(token, cancellationToken);
+ if (task.IsCompletedSucessfully())
+ {
+ return _writer.WriteAsync(value, cancellationToken);
+ }
+
+ return WriteValueInternalAsync(task, value, cancellationToken);
+ }
+
+ private async Task WriteValueInternalAsync(Task task, string value, CancellationToken cancellationToken)
+ {
+ await task.ConfigureAwait(false);
+ await _writer.WriteAsync(value, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes an indent space.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ protected override Task WriteIndentSpaceAsync(CancellationToken cancellationToken)
+ {
+ return _safeAsync ? DoWriteIndentSpaceAsync(cancellationToken) : base.WriteIndentSpaceAsync(cancellationToken);
+ }
+
+ internal Task DoWriteIndentSpaceAsync(CancellationToken cancellationToken)
+ {
+ return _writer.WriteAsync(' ', cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes raw JSON without changing the writer's state.
+ ///
+ /// The raw JSON to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteRawAsync(string? json, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteRawAsync(json, cancellationToken) : base.WriteRawAsync(json, cancellationToken);
+ }
+
+ internal Task DoWriteRawAsync(string? json, CancellationToken cancellationToken)
+ {
+ return _writer.WriteAsync(json, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a null value.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteNullAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteNullAsync(cancellationToken) : base.WriteNullAsync(cancellationToken);
+ }
+
+ internal Task DoWriteNullAsync(CancellationToken cancellationToken)
+ {
+ return WriteValueInternalAsync(JsonToken.Null, JsonConvert.Null, cancellationToken);
+ }
+
+ private Task WriteDigitsAsync(ulong uvalue, bool negative, CancellationToken cancellationToken)
+ {
+ if (uvalue <= 9 & !negative)
+ {
+ return _writer.WriteAsync((char)('0' + uvalue), cancellationToken);
+ }
+
+ int length = WriteNumberToBuffer(uvalue, negative);
+ return _writer.WriteAsync(_writeBuffer!, 0, length, cancellationToken);
+ }
+
+ private Task WriteIntegerValueAsync(ulong uvalue, bool negative, CancellationToken cancellationToken)
+ {
+ Task task = InternalWriteValueAsync(JsonToken.Integer, cancellationToken);
+ if (task.IsCompletedSucessfully())
+ {
+ return WriteDigitsAsync(uvalue, negative, cancellationToken);
+ }
+
+ return WriteIntegerValueAsync(task, uvalue, negative, cancellationToken);
+ }
+
+ private async Task WriteIntegerValueAsync(Task task, ulong uvalue, bool negative, CancellationToken cancellationToken)
+ {
+ await task.ConfigureAwait(false);
+ await WriteDigitsAsync(uvalue, negative, cancellationToken).ConfigureAwait(false);
+ }
+
+ internal Task WriteIntegerValueAsync(long value, CancellationToken cancellationToken)
+ {
+ bool negative = value < 0;
+ if (negative)
+ {
+ value = -value;
+ }
+
+ return WriteIntegerValueAsync((ulong)value, negative, cancellationToken);
+ }
+
+ internal Task WriteIntegerValueAsync(ulong uvalue, CancellationToken cancellationToken)
+ {
+ return WriteIntegerValueAsync(uvalue, false, cancellationToken);
+ }
+
+ private Task WriteEscapedStringAsync(string value, bool quote, CancellationToken cancellationToken)
+ {
+ return JavaScriptUtils.WriteEscapedJavaScriptStringAsync(_writer, value, _quoteChar, quote, _charEscapeFlags!, StringEscapeHandling, this, _writeBuffer!, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes the property name of a name/value pair of a JSON object.
+ ///
+ /// The name of the property.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WritePropertyNameAsync(string name, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWritePropertyNameAsync(name, cancellationToken) : base.WritePropertyNameAsync(name, cancellationToken);
+ }
+
+ internal Task DoWritePropertyNameAsync(string name, CancellationToken cancellationToken)
+ {
+ Task task = InternalWritePropertyNameAsync(name, cancellationToken);
+ if (!task.IsCompletedSucessfully())
+ {
+ return DoWritePropertyNameAsync(task, name, cancellationToken);
+ }
+
+ task = WriteEscapedStringAsync(name, _quoteName, cancellationToken);
+ if (task.IsCompletedSucessfully())
+ {
+ return _writer.WriteAsync(':', cancellationToken);
+ }
+
+ return JavaScriptUtils.WriteCharAsync(task, _writer, ':', cancellationToken);
+ }
+
+ private async Task DoWritePropertyNameAsync(Task task, string name, CancellationToken cancellationToken)
+ {
+ await task.ConfigureAwait(false);
+
+ await WriteEscapedStringAsync(name, _quoteName, cancellationToken).ConfigureAwait(false);
+
+ await _writer.WriteAsync(':').ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes the property name of a name/value pair of a JSON object.
+ ///
+ /// The name of the property.
+ /// A flag to indicate whether the text should be escaped when it is written as a JSON property name.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WritePropertyNameAsync(string name, bool escape, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWritePropertyNameAsync(name, escape, cancellationToken) : base.WritePropertyNameAsync(name, escape, cancellationToken);
+ }
+
+ internal async Task DoWritePropertyNameAsync(string name, bool escape, CancellationToken cancellationToken)
+ {
+ await InternalWritePropertyNameAsync(name, cancellationToken).ConfigureAwait(false);
+
+ if (escape)
+ {
+ await WriteEscapedStringAsync(name, _quoteName, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ if (_quoteName)
+ {
+ await _writer.WriteAsync(_quoteChar).ConfigureAwait(false);
+ }
+
+ await _writer.WriteAsync(name, cancellationToken).ConfigureAwait(false);
+
+ if (_quoteName)
+ {
+ await _writer.WriteAsync(_quoteChar).ConfigureAwait(false);
+ }
+ }
+
+ await _writer.WriteAsync(':').ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes the beginning of a JSON array.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteStartArrayAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteStartArrayAsync(cancellationToken) : base.WriteStartArrayAsync(cancellationToken);
+ }
+
+ internal Task DoWriteStartArrayAsync(CancellationToken cancellationToken)
+ {
+ Task task = InternalWriteStartAsync(JsonToken.StartArray, JsonContainerType.Array, cancellationToken);
+ if (task.IsCompletedSucessfully())
+ {
+ return _writer.WriteAsync('[', cancellationToken);
+ }
+
+ return DoWriteStartArrayAsync(task, cancellationToken);
+ }
+
+ internal async Task DoWriteStartArrayAsync(Task task, CancellationToken cancellationToken)
+ {
+ await task.ConfigureAwait(false);
+
+ await _writer.WriteAsync('[', cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes the beginning of a JSON object.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteStartObjectAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteStartObjectAsync(cancellationToken) : base.WriteStartObjectAsync(cancellationToken);
+ }
+
+ internal Task DoWriteStartObjectAsync(CancellationToken cancellationToken)
+ {
+ Task task = InternalWriteStartAsync(JsonToken.StartObject, JsonContainerType.Object, cancellationToken);
+ if (task.IsCompletedSucessfully())
+ {
+ return _writer.WriteAsync('{', cancellationToken);
+ }
+
+ return DoWriteStartObjectAsync(task, cancellationToken);
+ }
+
+ internal async Task DoWriteStartObjectAsync(Task task, CancellationToken cancellationToken)
+ {
+ await task.ConfigureAwait(false);
+
+ await _writer.WriteAsync('{', cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes the start of a constructor with the given name.
+ ///
+ /// The name of the constructor.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteStartConstructorAsync(string name, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteStartConstructorAsync(name, cancellationToken) : base.WriteStartConstructorAsync(name, cancellationToken);
+ }
+
+ internal async Task DoWriteStartConstructorAsync(string name, CancellationToken cancellationToken)
+ {
+ await InternalWriteStartAsync(JsonToken.StartConstructor, JsonContainerType.Constructor, cancellationToken).ConfigureAwait(false);
+
+ await _writer.WriteAsync("new ", cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync(name, cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync('(').ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes an undefined value.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteUndefinedAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteUndefinedAsync(cancellationToken) : base.WriteUndefinedAsync(cancellationToken);
+ }
+
+ internal Task DoWriteUndefinedAsync(CancellationToken cancellationToken)
+ {
+ Task task = InternalWriteValueAsync(JsonToken.Undefined, cancellationToken);
+ if (task.IsCompletedSucessfully())
+ {
+ return _writer.WriteAsync(JsonConvert.Undefined, cancellationToken);
+ }
+
+ return DoWriteUndefinedAsync(task, cancellationToken);
+ }
+
+ private async Task DoWriteUndefinedAsync(Task task, CancellationToken cancellationToken)
+ {
+ await task.ConfigureAwait(false);
+ await _writer.WriteAsync(JsonConvert.Undefined, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes the given white space.
+ ///
+ /// The string of white space characters.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteWhitespaceAsync(string ws, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteWhitespaceAsync(ws, cancellationToken) : base.WriteWhitespaceAsync(ws, cancellationToken);
+ }
+
+ internal Task DoWriteWhitespaceAsync(string ws, CancellationToken cancellationToken)
+ {
+ InternalWriteWhitespace(ws);
+ return _writer.WriteAsync(ws, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(bool value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(bool value, CancellationToken cancellationToken)
+ {
+ return WriteValueInternalAsync(JsonToken.Boolean, JsonConvert.ToString(value), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(bool? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(bool? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : DoWriteValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(byte value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(byte? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(byte? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : WriteIntegerValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a [] value.
+ ///
+ /// The [] value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(byte[]? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? (value == null ? WriteNullAsync(cancellationToken) : WriteValueNonNullAsync(value, cancellationToken)) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal async Task WriteValueNonNullAsync(byte[] value, CancellationToken cancellationToken)
+ {
+ await InternalWriteValueAsync(JsonToken.Bytes, cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync(_quoteChar).ConfigureAwait(false);
+ await Base64Encoder.EncodeAsync(value, 0, value.Length, cancellationToken).ConfigureAwait(false);
+ await Base64Encoder.FlushAsync(cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync(_quoteChar).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(char value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(char value, CancellationToken cancellationToken)
+ {
+ return WriteValueInternalAsync(JsonToken.String, JsonConvert.ToString(value), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(char? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(char? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : DoWriteValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(DateTime value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal async Task DoWriteValueAsync(DateTime value, CancellationToken cancellationToken)
+ {
+ await InternalWriteValueAsync(JsonToken.Date, cancellationToken).ConfigureAwait(false);
+ value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling);
+
+ if (StringUtils.IsNullOrEmpty(DateFormatString))
+ {
+ int length = WriteValueToBuffer(value);
+
+ await _writer.WriteAsync(_writeBuffer!, 0, length, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await _writer.WriteAsync(_quoteChar).ConfigureAwait(false);
+ await _writer.WriteAsync(value.ToString(DateFormatString, Culture), cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync(_quoteChar).ConfigureAwait(false);
+ }
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(DateTime? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(DateTime? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : DoWriteValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(DateTimeOffset value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal async Task DoWriteValueAsync(DateTimeOffset value, CancellationToken cancellationToken)
+ {
+ await InternalWriteValueAsync(JsonToken.Date, cancellationToken).ConfigureAwait(false);
+
+ if (StringUtils.IsNullOrEmpty(DateFormatString))
+ {
+ int length = WriteValueToBuffer(value);
+
+ await _writer.WriteAsync(_writeBuffer!, 0, length, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await _writer.WriteAsync(_quoteChar).ConfigureAwait(false);
+ await _writer.WriteAsync(value.ToString(DateFormatString, Culture), cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync(_quoteChar).ConfigureAwait(false);
+ }
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(DateTimeOffset? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(DateTimeOffset? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : DoWriteValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(decimal value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(decimal value, CancellationToken cancellationToken)
+ {
+ return WriteValueInternalAsync(JsonToken.Float, JsonConvert.ToString(value), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(decimal? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(decimal? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : DoWriteValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(double value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? WriteValueAsync(value, false, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task WriteValueAsync(double value, bool nullable, CancellationToken cancellationToken)
+ {
+ return WriteValueInternalAsync(JsonToken.Float, JsonConvert.ToString(value, FloatFormatHandling, QuoteChar, nullable), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(double? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? (value.HasValue ? WriteValueAsync(value.GetValueOrDefault(), true, cancellationToken) : WriteNullAsync(cancellationToken)) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(float value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? WriteValueAsync(value, false, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task WriteValueAsync(float value, bool nullable, CancellationToken cancellationToken)
+ {
+ return WriteValueInternalAsync(JsonToken.Float, JsonConvert.ToString(value, FloatFormatHandling, QuoteChar, nullable), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(float? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? (value.HasValue ? WriteValueAsync(value.GetValueOrDefault(), true, cancellationToken) : WriteNullAsync(cancellationToken)) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(Guid value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal async Task DoWriteValueAsync(Guid value, CancellationToken cancellationToken)
+ {
+ await InternalWriteValueAsync(JsonToken.String, cancellationToken).ConfigureAwait(false);
+
+ await _writer.WriteAsync(_quoteChar).ConfigureAwait(false);
+#if HAVE_CHAR_TO_STRING_WITH_CULTURE
+ await _writer.WriteAsync(value.ToString("D", CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false);
+#else
+ await _writer.WriteAsync(value.ToString("D"), cancellationToken).ConfigureAwait(false);
+#endif
+ await _writer.WriteAsync(_quoteChar).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(Guid? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(Guid? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : DoWriteValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(int value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(int? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(int? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : WriteIntegerValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(long value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(long? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(long? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : WriteIntegerValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+#if HAVE_BIG_INTEGER
+ internal Task WriteValueAsync(BigInteger value, CancellationToken cancellationToken)
+ {
+ return WriteValueInternalAsync(JsonToken.Integer, value.ToString(CultureInfo.InvariantCulture), cancellationToken);
+ }
+#endif
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(object? value, CancellationToken cancellationToken = default)
+ {
+ if (_safeAsync)
+ {
+ if (value == null)
+ {
+ return WriteNullAsync(cancellationToken);
+ }
+#if HAVE_BIG_INTEGER
+ if (value is BigInteger i)
+ {
+ return WriteValueAsync(i, cancellationToken);
+ }
+#endif
+
+ return WriteValueAsync(this, ConvertUtils.GetTypeCode(value.GetType()), value, cancellationToken);
+ }
+
+ return base.WriteValueAsync(value, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ [CLSCompliant(false)]
+ public override Task WriteValueAsync(sbyte value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ [CLSCompliant(false)]
+ public override Task WriteValueAsync(sbyte? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(sbyte? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : WriteIntegerValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(short value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(short? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(short? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : WriteIntegerValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(string? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(string? value, CancellationToken cancellationToken)
+ {
+ Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken);
+ if (task.IsCompletedSucessfully())
+ {
+ return value == null ? _writer.WriteAsync(JsonConvert.Null, cancellationToken) : WriteEscapedStringAsync(value, true, cancellationToken);
+ }
+
+ return DoWriteValueAsync(task, value, cancellationToken);
+ }
+
+ private async Task DoWriteValueAsync(Task task, string? value, CancellationToken cancellationToken)
+ {
+ await task.ConfigureAwait(false);
+ await (value == null ? _writer.WriteAsync(JsonConvert.Null, cancellationToken) : WriteEscapedStringAsync(value, true, cancellationToken)).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(TimeSpan value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal async Task DoWriteValueAsync(TimeSpan value, CancellationToken cancellationToken)
+ {
+ await InternalWriteValueAsync(JsonToken.String, cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync(_quoteChar, cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync(value.ToString(null, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync(_quoteChar, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(TimeSpan? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(TimeSpan? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : DoWriteValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ [CLSCompliant(false)]
+ public override Task WriteValueAsync(uint value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ [CLSCompliant(false)]
+ public override Task WriteValueAsync(uint? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(uint? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : WriteIntegerValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ [CLSCompliant(false)]
+ public override Task WriteValueAsync(ulong value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ [CLSCompliant(false)]
+ public override Task WriteValueAsync(ulong? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(ulong? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : WriteIntegerValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteValueAsync(Uri? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? (value == null ? WriteNullAsync(cancellationToken) : WriteValueNotNullAsync(value, cancellationToken)) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task WriteValueNotNullAsync(Uri value, CancellationToken cancellationToken)
+ {
+ Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken);
+ if (task.IsCompletedSucessfully())
+ {
+ return WriteEscapedStringAsync(value.OriginalString, true, cancellationToken);
+ }
+
+ return WriteValueNotNullAsync(task, value, cancellationToken);
+ }
+
+ internal async Task WriteValueNotNullAsync(Task task, Uri value, CancellationToken cancellationToken)
+ {
+ await task.ConfigureAwait(false);
+ await WriteEscapedStringAsync(value.OriginalString, true, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ [CLSCompliant(false)]
+ public override Task WriteValueAsync(ushort value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ [CLSCompliant(false)]
+ public override Task WriteValueAsync(ushort? value, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken);
+ }
+
+ internal Task DoWriteValueAsync(ushort? value, CancellationToken cancellationToken)
+ {
+ return value == null ? DoWriteNullAsync(cancellationToken) : WriteIntegerValueAsync(value.GetValueOrDefault(), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes a comment /*...*/ containing the specified text.
+ ///
+ /// Text to place inside the comment.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteCommentAsync(string? text, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteCommentAsync(text, cancellationToken) : base.WriteCommentAsync(text, cancellationToken);
+ }
+
+ internal async Task DoWriteCommentAsync(string? text, CancellationToken cancellationToken)
+ {
+ await InternalWriteCommentAsync(cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync("/*", cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync(text ?? string.Empty, cancellationToken).ConfigureAwait(false);
+ await _writer.WriteAsync("*/", cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes the end of an array.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteEndArrayAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? InternalWriteEndAsync(JsonContainerType.Array, cancellationToken) : base.WriteEndArrayAsync(cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes the end of a constructor.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteEndConstructorAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? InternalWriteEndAsync(JsonContainerType.Constructor, cancellationToken) : base.WriteEndConstructorAsync(cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes the end of a JSON object.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteEndObjectAsync(CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? InternalWriteEndAsync(JsonContainerType.Object, cancellationToken) : base.WriteEndObjectAsync(cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes raw JSON where a value is expected and updates the writer's state.
+ ///
+ /// The raw JSON to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will
+ /// execute synchronously, returning an already-completed task.
+ public override Task WriteRawValueAsync(string? json, CancellationToken cancellationToken = default)
+ {
+ return _safeAsync ? DoWriteRawValueAsync(json, cancellationToken) : base.WriteRawValueAsync(json, cancellationToken);
+ }
+
+ internal Task DoWriteRawValueAsync(string? json, CancellationToken cancellationToken)
+ {
+ UpdateScopeWithFinishedValue();
+ Task task = AutoCompleteAsync(JsonToken.Undefined, cancellationToken);
+ if (task.IsCompletedSucessfully())
+ {
+ return WriteRawAsync(json, cancellationToken);
+ }
+
+ return DoWriteRawValueAsync(task, json, cancellationToken);
+ }
+
+ private async Task DoWriteRawValueAsync(Task task, string? json, CancellationToken cancellationToken)
+ {
+ await task.ConfigureAwait(false);
+ await WriteRawAsync(json, cancellationToken).ConfigureAwait(false);
+ }
+
+ internal char[] EnsureWriteBuffer(int length, int copyTo)
+ {
+ if (length < 35)
+ {
+ length = 35;
+ }
+
+ char[]? buffer = _writeBuffer;
+ if (buffer == null)
+ {
+ return _writeBuffer = BufferUtils.RentBuffer(_arrayPool, length);
+ }
+
+ if (buffer.Length >= length)
+ {
+ return buffer;
+ }
+
+ char[] newBuffer = BufferUtils.RentBuffer(_arrayPool, length);
+ if (copyTo != 0)
+ {
+ Array.Copy(buffer, newBuffer, copyTo);
+ }
+
+ BufferUtils.ReturnBuffer(_arrayPool, buffer);
+ _writeBuffer = newBuffer;
+ return newBuffer;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonTextWriter.cs b/Libs/Newtonsoft.Json.AOT/JsonTextWriter.cs
new file mode 100644
index 0000000..9719604
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonTextWriter.cs
@@ -0,0 +1,920 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+#if HAVE_BIG_INTEGER
+using System.Numerics;
+#endif
+using System.Text;
+using System.IO;
+using System.Xml;
+using LC.Newtonsoft.Json.Utilities;
+using System.Diagnostics;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
+ ///
+ public partial class JsonTextWriter : JsonWriter
+ {
+ private const int IndentCharBufferSize = 12;
+ private readonly TextWriter _writer;
+ private Base64Encoder? _base64Encoder;
+ private char _indentChar;
+ private int _indentation;
+ private char _quoteChar;
+ private bool _quoteName;
+ private bool[]? _charEscapeFlags;
+ private char[]? _writeBuffer;
+ private IArrayPool? _arrayPool;
+ private char[]? _indentChars;
+
+ private Base64Encoder Base64Encoder
+ {
+ get
+ {
+ if (_base64Encoder == null)
+ {
+ _base64Encoder = new Base64Encoder(_writer);
+ }
+
+ return _base64Encoder;
+ }
+ }
+
+ ///
+ /// Gets or sets the writer's character array pool.
+ ///
+ public IArrayPool? ArrayPool
+ {
+ get => _arrayPool;
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ _arrayPool = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how many s to write for each level in the hierarchy when is set to .
+ ///
+ public int Indentation
+ {
+ get => _indentation;
+ set
+ {
+ if (value < 0)
+ {
+ throw new ArgumentException("Indentation value must be greater than 0.");
+ }
+
+ _indentation = value;
+ }
+ }
+
+ ///
+ /// Gets or sets which character to use to quote attribute values.
+ ///
+ public char QuoteChar
+ {
+ get => _quoteChar;
+ set
+ {
+ if (value != '"' && value != '\'')
+ {
+ throw new ArgumentException(@"Invalid JavaScript string quote character. Valid quote characters are ' and "".");
+ }
+
+ _quoteChar = value;
+ UpdateCharEscapeFlags();
+ }
+ }
+
+ ///
+ /// Gets or sets which character to use for indenting when is set to .
+ ///
+ public char IndentChar
+ {
+ get => _indentChar;
+ set
+ {
+ if (value != _indentChar)
+ {
+ _indentChar = value;
+ _indentChars = null;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether object names will be surrounded with quotes.
+ ///
+ public bool QuoteName
+ {
+ get => _quoteName;
+ set => _quoteName = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class using the specified .
+ ///
+ /// The to write to.
+ public JsonTextWriter(TextWriter textWriter)
+ {
+ if (textWriter == null)
+ {
+ throw new ArgumentNullException(nameof(textWriter));
+ }
+
+ _writer = textWriter;
+ _quoteChar = '"';
+ _quoteName = true;
+ _indentChar = ' ';
+ _indentation = 2;
+
+ UpdateCharEscapeFlags();
+
+#if HAVE_ASYNC
+ _safeAsync = GetType() == typeof(JsonTextWriter);
+#endif
+ }
+
+ ///
+ /// Flushes whatever is in the buffer to the underlying and also flushes the underlying .
+ ///
+ public override void Flush()
+ {
+ _writer.Flush();
+ }
+
+ ///
+ /// Closes this writer.
+ /// If is set to true , the underlying is also closed.
+ /// If is set to true , the JSON is auto-completed.
+ ///
+ public override void Close()
+ {
+ base.Close();
+
+ CloseBufferAndWriter();
+ }
+
+ private void CloseBufferAndWriter()
+ {
+ if (_writeBuffer != null)
+ {
+ BufferUtils.ReturnBuffer(_arrayPool, _writeBuffer);
+ _writeBuffer = null;
+ }
+
+ if (CloseOutput)
+ {
+#if HAVE_STREAM_READER_WRITER_CLOSE
+ _writer?.Close();
+#else
+ _writer?.Dispose();
+#endif
+ }
+ }
+
+ ///
+ /// Writes the beginning of a JSON object.
+ ///
+ public override void WriteStartObject()
+ {
+ InternalWriteStart(JsonToken.StartObject, JsonContainerType.Object);
+
+ _writer.Write('{');
+ }
+
+ ///
+ /// Writes the beginning of a JSON array.
+ ///
+ public override void WriteStartArray()
+ {
+ InternalWriteStart(JsonToken.StartArray, JsonContainerType.Array);
+
+ _writer.Write('[');
+ }
+
+ ///
+ /// Writes the start of a constructor with the given name.
+ ///
+ /// The name of the constructor.
+ public override void WriteStartConstructor(string name)
+ {
+ InternalWriteStart(JsonToken.StartConstructor, JsonContainerType.Constructor);
+
+ _writer.Write("new ");
+ _writer.Write(name);
+ _writer.Write('(');
+ }
+
+ ///
+ /// Writes the specified end token.
+ ///
+ /// The end token to write.
+ protected override void WriteEnd(JsonToken token)
+ {
+ switch (token)
+ {
+ case JsonToken.EndObject:
+ _writer.Write('}');
+ break;
+ case JsonToken.EndArray:
+ _writer.Write(']');
+ break;
+ case JsonToken.EndConstructor:
+ _writer.Write(')');
+ break;
+ default:
+ throw JsonWriterException.Create(this, "Invalid JsonToken: " + token, null);
+ }
+ }
+
+ ///
+ /// Writes the property name of a name/value pair on a JSON object.
+ ///
+ /// The name of the property.
+ public override void WritePropertyName(string name)
+ {
+ InternalWritePropertyName(name);
+
+ WriteEscapedString(name, _quoteName);
+
+ _writer.Write(':');
+ }
+
+ ///
+ /// Writes the property name of a name/value pair on a JSON object.
+ ///
+ /// The name of the property.
+ /// A flag to indicate whether the text should be escaped when it is written as a JSON property name.
+ public override void WritePropertyName(string name, bool escape)
+ {
+ InternalWritePropertyName(name);
+
+ if (escape)
+ {
+ WriteEscapedString(name, _quoteName);
+ }
+ else
+ {
+ if (_quoteName)
+ {
+ _writer.Write(_quoteChar);
+ }
+
+ _writer.Write(name);
+
+ if (_quoteName)
+ {
+ _writer.Write(_quoteChar);
+ }
+ }
+
+ _writer.Write(':');
+ }
+
+ internal override void OnStringEscapeHandlingChanged()
+ {
+ UpdateCharEscapeFlags();
+ }
+
+ private void UpdateCharEscapeFlags()
+ {
+ _charEscapeFlags = JavaScriptUtils.GetCharEscapeFlags(StringEscapeHandling, _quoteChar);
+ }
+
+ ///
+ /// Writes indent characters.
+ ///
+ protected override void WriteIndent()
+ {
+ // levels of indentation multiplied by the indent count
+ int currentIndentCount = Top * _indentation;
+
+ int newLineLen = SetIndentChars();
+
+ _writer.Write(_indentChars, 0, newLineLen + Math.Min(currentIndentCount, IndentCharBufferSize));
+
+ while ((currentIndentCount -= IndentCharBufferSize) > 0)
+ {
+ _writer.Write(_indentChars, newLineLen, Math.Min(currentIndentCount, IndentCharBufferSize));
+ }
+ }
+
+ private int SetIndentChars()
+ {
+ // Set _indentChars to be a newline followed by IndentCharBufferSize indent characters.
+ string writerNewLine = _writer.NewLine;
+ int newLineLen = writerNewLine.Length;
+ bool match = _indentChars != null && _indentChars.Length == IndentCharBufferSize + newLineLen;
+ if (match)
+ {
+ for (int i = 0; i != newLineLen; ++i)
+ {
+ if (writerNewLine[i] != _indentChars![i])
+ {
+ match = false;
+ break;
+ }
+ }
+ }
+
+ if (!match)
+ {
+ // If we're here, either _indentChars hasn't been set yet, or _writer.NewLine
+ // has been changed, or _indentChar has been changed.
+ _indentChars = (writerNewLine + new string(_indentChar, IndentCharBufferSize)).ToCharArray();
+ }
+
+ return newLineLen;
+ }
+
+ ///
+ /// Writes the JSON value delimiter.
+ ///
+ protected override void WriteValueDelimiter()
+ {
+ _writer.Write(',');
+ }
+
+ ///
+ /// Writes an indent space.
+ ///
+ protected override void WriteIndentSpace()
+ {
+ _writer.Write(' ');
+ }
+
+ private void WriteValueInternal(string value, JsonToken token)
+ {
+ _writer.Write(value);
+ }
+
+ #region WriteValue methods
+ ///
+ /// Writes a value.
+ /// An error will raised if the value cannot be written as a single JSON token.
+ ///
+ /// The value to write.
+ public override void WriteValue(object? value)
+ {
+#if HAVE_BIG_INTEGER
+ if (value is BigInteger i)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ WriteValueInternal(i.ToString(CultureInfo.InvariantCulture), JsonToken.String);
+ }
+ else
+#endif
+ {
+ base.WriteValue(value);
+ }
+ }
+
+ ///
+ /// Writes a null value.
+ ///
+ public override void WriteNull()
+ {
+ InternalWriteValue(JsonToken.Null);
+ WriteValueInternal(JsonConvert.Null, JsonToken.Null);
+ }
+
+ ///
+ /// Writes an undefined value.
+ ///
+ public override void WriteUndefined()
+ {
+ InternalWriteValue(JsonToken.Undefined);
+ WriteValueInternal(JsonConvert.Undefined, JsonToken.Undefined);
+ }
+
+ ///
+ /// Writes raw JSON.
+ ///
+ /// The raw JSON to write.
+ public override void WriteRaw(string? json)
+ {
+ InternalWriteRaw();
+
+ _writer.Write(json);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(string? value)
+ {
+ InternalWriteValue(JsonToken.String);
+
+ if (value == null)
+ {
+ WriteValueInternal(JsonConvert.Null, JsonToken.Null);
+ }
+ else
+ {
+ WriteEscapedString(value, true);
+ }
+ }
+
+ private void WriteEscapedString(string value, bool quote)
+ {
+ EnsureWriteBuffer();
+ JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, quote, _charEscapeFlags!, StringEscapeHandling, _arrayPool, ref _writeBuffer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(int value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ WriteIntegerValue(value);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public override void WriteValue(uint value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ WriteIntegerValue(value);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(long value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ WriteIntegerValue(value);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public override void WriteValue(ulong value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ WriteIntegerValue(value, false);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(float value)
+ {
+ InternalWriteValue(JsonToken.Float);
+ WriteValueInternal(JsonConvert.ToString(value, FloatFormatHandling, QuoteChar, false), JsonToken.Float);
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public override void WriteValue(float? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ InternalWriteValue(JsonToken.Float);
+ WriteValueInternal(JsonConvert.ToString(value.GetValueOrDefault(), FloatFormatHandling, QuoteChar, true), JsonToken.Float);
+ }
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(double value)
+ {
+ InternalWriteValue(JsonToken.Float);
+ WriteValueInternal(JsonConvert.ToString(value, FloatFormatHandling, QuoteChar, false), JsonToken.Float);
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public override void WriteValue(double? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ InternalWriteValue(JsonToken.Float);
+ WriteValueInternal(JsonConvert.ToString(value.GetValueOrDefault(), FloatFormatHandling, QuoteChar, true), JsonToken.Float);
+ }
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(bool value)
+ {
+ InternalWriteValue(JsonToken.Boolean);
+ WriteValueInternal(JsonConvert.ToString(value), JsonToken.Boolean);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(short value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ WriteIntegerValue(value);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public override void WriteValue(ushort value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ WriteIntegerValue(value);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(char value)
+ {
+ InternalWriteValue(JsonToken.String);
+ WriteValueInternal(JsonConvert.ToString(value), JsonToken.String);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(byte value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ WriteIntegerValue(value);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public override void WriteValue(sbyte value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ WriteIntegerValue(value);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(decimal value)
+ {
+ InternalWriteValue(JsonToken.Float);
+ WriteValueInternal(JsonConvert.ToString(value), JsonToken.Float);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(DateTime value)
+ {
+ InternalWriteValue(JsonToken.Date);
+ value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling);
+
+ if (StringUtils.IsNullOrEmpty(DateFormatString))
+ {
+ int length = WriteValueToBuffer(value);
+
+ _writer.Write(_writeBuffer, 0, length);
+ }
+ else
+ {
+ _writer.Write(_quoteChar);
+ _writer.Write(value.ToString(DateFormatString, Culture));
+ _writer.Write(_quoteChar);
+ }
+ }
+
+ private int WriteValueToBuffer(DateTime value)
+ {
+ EnsureWriteBuffer();
+ MiscellaneousUtils.Assert(_writeBuffer != null);
+
+ int pos = 0;
+ _writeBuffer[pos++] = _quoteChar;
+ pos = DateTimeUtils.WriteDateTimeString(_writeBuffer, pos, value, null, value.Kind, DateFormatHandling);
+ _writeBuffer[pos++] = _quoteChar;
+ return pos;
+ }
+
+ ///
+ /// Writes a [] value.
+ ///
+ /// The [] value to write.
+ public override void WriteValue(byte[]? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ InternalWriteValue(JsonToken.Bytes);
+ _writer.Write(_quoteChar);
+ Base64Encoder.Encode(value, 0, value.Length);
+ Base64Encoder.Flush();
+ _writer.Write(_quoteChar);
+ }
+ }
+
+#if HAVE_DATE_TIME_OFFSET
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(DateTimeOffset value)
+ {
+ InternalWriteValue(JsonToken.Date);
+
+ if (StringUtils.IsNullOrEmpty(DateFormatString))
+ {
+ int length = WriteValueToBuffer(value);
+
+ _writer.Write(_writeBuffer, 0, length);
+ }
+ else
+ {
+ _writer.Write(_quoteChar);
+ _writer.Write(value.ToString(DateFormatString, Culture));
+ _writer.Write(_quoteChar);
+ }
+ }
+
+ private int WriteValueToBuffer(DateTimeOffset value)
+ {
+ EnsureWriteBuffer();
+ MiscellaneousUtils.Assert(_writeBuffer != null);
+
+ int pos = 0;
+ _writeBuffer[pos++] = _quoteChar;
+ pos = DateTimeUtils.WriteDateTimeString(_writeBuffer, pos, (DateFormatHandling == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, DateFormatHandling);
+ _writeBuffer[pos++] = _quoteChar;
+ return pos;
+ }
+#endif
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(Guid value)
+ {
+ InternalWriteValue(JsonToken.String);
+
+ string text;
+
+#if HAVE_CHAR_TO_STRING_WITH_CULTURE
+ text = value.ToString("D", CultureInfo.InvariantCulture);
+#else
+ text = value.ToString("D");
+#endif
+
+ _writer.Write(_quoteChar);
+ _writer.Write(text);
+ _writer.Write(_quoteChar);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(TimeSpan value)
+ {
+ InternalWriteValue(JsonToken.String);
+
+ string text;
+#if !HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE
+ text = value.ToString();
+#else
+ text = value.ToString(null, CultureInfo.InvariantCulture);
+#endif
+
+ _writer.Write(_quoteChar);
+ _writer.Write(text);
+ _writer.Write(_quoteChar);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public override void WriteValue(Uri? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ InternalWriteValue(JsonToken.String);
+ WriteEscapedString(value.OriginalString, true);
+ }
+ }
+ #endregion
+
+ ///
+ /// Writes a comment /*...*/ containing the specified text.
+ ///
+ /// Text to place inside the comment.
+ public override void WriteComment(string? text)
+ {
+ InternalWriteComment();
+
+ _writer.Write("/*");
+ _writer.Write(text);
+ _writer.Write("*/");
+ }
+
+ ///
+ /// Writes the given white space.
+ ///
+ /// The string of white space characters.
+ public override void WriteWhitespace(string ws)
+ {
+ InternalWriteWhitespace(ws);
+
+ _writer.Write(ws);
+ }
+
+ private void EnsureWriteBuffer()
+ {
+ if (_writeBuffer == null)
+ {
+ // maximum buffer sized used when writing iso date
+ _writeBuffer = BufferUtils.RentBuffer(_arrayPool, 35);
+ }
+ }
+
+ private void WriteIntegerValue(long value)
+ {
+ if (value >= 0 && value <= 9)
+ {
+ _writer.Write((char)('0' + value));
+ }
+ else
+ {
+ bool negative = value < 0;
+ WriteIntegerValue(negative ? (ulong)-value : (ulong)value, negative);
+ }
+ }
+
+ private void WriteIntegerValue(ulong value, bool negative)
+ {
+ if (!negative & value <= 9)
+ {
+ _writer.Write((char)('0' + value));
+ }
+ else
+ {
+ int length = WriteNumberToBuffer(value, negative);
+ _writer.Write(_writeBuffer, 0, length);
+ }
+ }
+
+ private int WriteNumberToBuffer(ulong value, bool negative)
+ {
+ if (value <= uint.MaxValue)
+ {
+ // avoid the 64 bit division if possible
+ return WriteNumberToBuffer((uint)value, negative);
+ }
+
+ EnsureWriteBuffer();
+ MiscellaneousUtils.Assert(_writeBuffer != null);
+
+ int totalLength = MathUtils.IntLength(value);
+
+ if (negative)
+ {
+ totalLength++;
+ _writeBuffer[0] = '-';
+ }
+
+ int index = totalLength;
+
+ do
+ {
+ ulong quotient = value / 10;
+ ulong digit = value - (quotient * 10);
+ _writeBuffer[--index] = (char)('0' + digit);
+ value = quotient;
+ } while (value != 0);
+
+ return totalLength;
+ }
+
+ private void WriteIntegerValue(int value)
+ {
+ if (value >= 0 && value <= 9)
+ {
+ _writer.Write((char)('0' + value));
+ }
+ else
+ {
+ bool negative = value < 0;
+ WriteIntegerValue(negative ? (uint)-value : (uint)value, negative);
+ }
+ }
+
+ private void WriteIntegerValue(uint value, bool negative)
+ {
+ if (!negative & value <= 9)
+ {
+ _writer.Write((char)('0' + value));
+ }
+ else
+ {
+ int length = WriteNumberToBuffer(value, negative);
+ _writer.Write(_writeBuffer, 0, length);
+ }
+ }
+
+ private int WriteNumberToBuffer(uint value, bool negative)
+ {
+ EnsureWriteBuffer();
+ MiscellaneousUtils.Assert(_writeBuffer != null);
+
+ int totalLength = MathUtils.IntLength(value);
+
+ if (negative)
+ {
+ totalLength++;
+ _writeBuffer[0] = '-';
+ }
+
+ int index = totalLength;
+
+ do
+ {
+ uint quotient = value / 10;
+ uint digit = value - (quotient * 10);
+ _writeBuffer[--index] = (char)('0' + digit);
+ value = quotient;
+ } while (value != 0);
+
+ return totalLength;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonToken.cs b/Libs/Newtonsoft.Json.AOT/JsonToken.cs
new file mode 100644
index 0000000..9229cd3
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonToken.cs
@@ -0,0 +1,127 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Specifies the type of JSON token.
+ ///
+ public enum JsonToken
+ {
+ ///
+ /// This is returned by the if a read method has not been called.
+ ///
+ None = 0,
+
+ ///
+ /// An object start token.
+ ///
+ StartObject = 1,
+
+ ///
+ /// An array start token.
+ ///
+ StartArray = 2,
+
+ ///
+ /// A constructor start token.
+ ///
+ StartConstructor = 3,
+
+ ///
+ /// An object property name.
+ ///
+ PropertyName = 4,
+
+ ///
+ /// A comment.
+ ///
+ Comment = 5,
+
+ ///
+ /// Raw JSON.
+ ///
+ Raw = 6,
+
+ ///
+ /// An integer.
+ ///
+ Integer = 7,
+
+ ///
+ /// A float.
+ ///
+ Float = 8,
+
+ ///
+ /// A string.
+ ///
+ String = 9,
+
+ ///
+ /// A boolean.
+ ///
+ Boolean = 10,
+
+ ///
+ /// A null token.
+ ///
+ Null = 11,
+
+ ///
+ /// An undefined token.
+ ///
+ Undefined = 12,
+
+ ///
+ /// An object end token.
+ ///
+ EndObject = 13,
+
+ ///
+ /// An array end token.
+ ///
+ EndArray = 14,
+
+ ///
+ /// A constructor end token.
+ ///
+ EndConstructor = 15,
+
+ ///
+ /// A Date.
+ ///
+ Date = 16,
+
+ ///
+ /// Byte data.
+ ///
+ Bytes = 17
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonValidatingReader.cs b/Libs/Newtonsoft.Json.AOT/JsonValidatingReader.cs
new file mode 100644
index 0000000..93efb46
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonValidatingReader.cs
@@ -0,0 +1,1025 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+#if HAVE_BIG_INTEGER
+using System.Numerics;
+#endif
+using LC.Newtonsoft.Json.Linq;
+using LC.Newtonsoft.Json.Schema;
+using LC.Newtonsoft.Json.Utilities;
+using System.Globalization;
+using System.Text.RegularExpressions;
+using System.IO;
+#if !HAVE_LINQ
+using LC.Newtonsoft.Json.Utilities.LinqBridge;
+#else
+using System.Linq;
+
+#endif
+
+#nullable disable
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ ///
+ /// Represents a reader that provides validation.
+ ///
+ ///
+ /// JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.
+ ///
+ ///
+ [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")]
+ public class JsonValidatingReader : JsonReader, IJsonLineInfo
+ {
+ private class SchemaScope
+ {
+ private readonly JTokenType _tokenType;
+ private readonly IList _schemas;
+ private readonly Dictionary _requiredProperties;
+
+ public string CurrentPropertyName { get; set; }
+ public int ArrayItemCount { get; set; }
+ public bool IsUniqueArray { get; }
+ public IList UniqueArrayItems { get; }
+ public JTokenWriter CurrentItemWriter { get; set; }
+
+ public IList Schemas => _schemas;
+
+ public Dictionary RequiredProperties => _requiredProperties;
+
+ public JTokenType TokenType => _tokenType;
+
+ public SchemaScope(JTokenType tokenType, IList schemas)
+ {
+ _tokenType = tokenType;
+ _schemas = schemas;
+
+ _requiredProperties = schemas.SelectMany(GetRequiredProperties).Distinct().ToDictionary(p => p, p => false);
+
+ if (tokenType == JTokenType.Array && schemas.Any(s => s.UniqueItems))
+ {
+ IsUniqueArray = true;
+ UniqueArrayItems = new List();
+ }
+ }
+
+ private IEnumerable GetRequiredProperties(JsonSchemaModel schema)
+ {
+ if (schema?.Properties == null)
+ {
+ return Enumerable.Empty();
+ }
+
+ return schema.Properties.Where(p => p.Value.Required).Select(p => p.Key);
+ }
+ }
+
+ private readonly JsonReader _reader;
+ private readonly Stack _stack;
+ private JsonSchema _schema;
+ private JsonSchemaModel _model;
+ private SchemaScope _currentScope;
+
+ ///
+ /// Sets an event handler for receiving schema validation errors.
+ ///
+ public event ValidationEventHandler ValidationEventHandler;
+
+ ///
+ /// Gets the text value of the current JSON token.
+ ///
+ ///
+ public override object Value => _reader.Value;
+
+ ///
+ /// Gets the depth of the current token in the JSON document.
+ ///
+ /// The depth of the current token in the JSON document.
+ public override int Depth => _reader.Depth;
+
+ ///
+ /// Gets the path of the current JSON token.
+ ///
+ public override string Path => _reader.Path;
+
+ ///
+ /// Gets the quotation mark character used to enclose the value of a string.
+ ///
+ ///
+ public override char QuoteChar
+ {
+ get { return _reader.QuoteChar; }
+ protected internal set { }
+ }
+
+ ///
+ /// Gets the type of the current JSON token.
+ ///
+ ///
+ public override JsonToken TokenType => _reader.TokenType;
+
+ ///
+ /// Gets the .NET type for the current JSON token.
+ ///
+ ///
+ public override Type ValueType => _reader.ValueType;
+
+ private void Push(SchemaScope scope)
+ {
+ _stack.Push(scope);
+ _currentScope = scope;
+ }
+
+ private SchemaScope Pop()
+ {
+ SchemaScope poppedScope = _stack.Pop();
+ _currentScope = (_stack.Count != 0)
+ ? _stack.Peek()
+ : null;
+
+ return poppedScope;
+ }
+
+ private IList CurrentSchemas => _currentScope.Schemas;
+
+ private static readonly IList EmptySchemaList = new List();
+
+ private IList CurrentMemberSchemas
+ {
+ get
+ {
+ if (_currentScope == null)
+ {
+ return new List(new[] { _model });
+ }
+
+ if (_currentScope.Schemas == null || _currentScope.Schemas.Count == 0)
+ {
+ return EmptySchemaList;
+ }
+
+ switch (_currentScope.TokenType)
+ {
+ case JTokenType.None:
+ return _currentScope.Schemas;
+ case JTokenType.Object:
+ {
+ if (_currentScope.CurrentPropertyName == null)
+ {
+ throw new JsonReaderException("CurrentPropertyName has not been set on scope.");
+ }
+
+ IList schemas = new List();
+
+ foreach (JsonSchemaModel schema in CurrentSchemas)
+ {
+ if (schema.Properties != null && schema.Properties.TryGetValue(_currentScope.CurrentPropertyName, out JsonSchemaModel propertySchema))
+ {
+ schemas.Add(propertySchema);
+ }
+ if (schema.PatternProperties != null)
+ {
+ foreach (KeyValuePair patternProperty in schema.PatternProperties)
+ {
+ if (Regex.IsMatch(_currentScope.CurrentPropertyName, patternProperty.Key))
+ {
+ schemas.Add(patternProperty.Value);
+ }
+ }
+ }
+
+ if (schemas.Count == 0 && schema.AllowAdditionalProperties && schema.AdditionalProperties != null)
+ {
+ schemas.Add(schema.AdditionalProperties);
+ }
+ }
+
+ return schemas;
+ }
+ case JTokenType.Array:
+ {
+ IList schemas = new List();
+
+ foreach (JsonSchemaModel schema in CurrentSchemas)
+ {
+ if (!schema.PositionalItemsValidation)
+ {
+ if (schema.Items != null && schema.Items.Count > 0)
+ {
+ schemas.Add(schema.Items[0]);
+ }
+ }
+ else
+ {
+ if (schema.Items != null && schema.Items.Count > 0)
+ {
+ if (schema.Items.Count > (_currentScope.ArrayItemCount - 1))
+ {
+ schemas.Add(schema.Items[_currentScope.ArrayItemCount - 1]);
+ }
+ }
+
+ if (schema.AllowAdditionalItems && schema.AdditionalItems != null)
+ {
+ schemas.Add(schema.AdditionalItems);
+ }
+ }
+ }
+
+ return schemas;
+ }
+ case JTokenType.Constructor:
+ return EmptySchemaList;
+ default:
+ throw new ArgumentOutOfRangeException("TokenType", "Unexpected token type: {0}".FormatWith(CultureInfo.InvariantCulture, _currentScope.TokenType));
+ }
+ }
+ }
+
+ private void RaiseError(string message, JsonSchemaModel schema)
+ {
+ IJsonLineInfo lineInfo = this;
+
+ string exceptionMessage = (lineInfo.HasLineInfo())
+ ? message + " Line {0}, position {1}.".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition)
+ : message;
+
+ OnValidationEvent(new JsonSchemaException(exceptionMessage, null, Path, lineInfo.LineNumber, lineInfo.LinePosition));
+ }
+
+ private void OnValidationEvent(JsonSchemaException exception)
+ {
+ ValidationEventHandler handler = ValidationEventHandler;
+ if (handler != null)
+ {
+ handler(this, new ValidationEventArgs(exception));
+ }
+ else
+ {
+ throw exception;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class that
+ /// validates the content returned from the given .
+ ///
+ /// The to read from while validating.
+ public JsonValidatingReader(JsonReader reader)
+ {
+ ValidationUtils.ArgumentNotNull(reader, nameof(reader));
+ _reader = reader;
+ _stack = new Stack();
+ }
+
+ ///
+ /// Gets or sets the schema.
+ ///
+ /// The schema.
+ public JsonSchema Schema
+ {
+ get => _schema;
+ set
+ {
+ if (TokenType != JsonToken.None)
+ {
+ throw new InvalidOperationException("Cannot change schema while validating JSON.");
+ }
+
+ _schema = value;
+ _model = null;
+ }
+ }
+
+ ///
+ /// Gets the used to construct this .
+ ///
+ /// The specified in the constructor.
+ public JsonReader Reader => _reader;
+
+ ///
+ /// Changes the reader's state to .
+ /// If is set to true , the underlying is also closed.
+ ///
+ public override void Close()
+ {
+ base.Close();
+ if (CloseInput)
+ {
+ _reader?.Close();
+ }
+ }
+
+ private void ValidateNotDisallowed(JsonSchemaModel schema)
+ {
+ if (schema == null)
+ {
+ return;
+ }
+
+ JsonSchemaType? currentNodeType = GetCurrentNodeSchemaType();
+ if (currentNodeType != null)
+ {
+ if (JsonSchemaGenerator.HasFlag(schema.Disallow, currentNodeType.GetValueOrDefault()))
+ {
+ RaiseError("Type {0} is disallowed.".FormatWith(CultureInfo.InvariantCulture, currentNodeType), schema);
+ }
+ }
+ }
+
+ private JsonSchemaType? GetCurrentNodeSchemaType()
+ {
+ switch (_reader.TokenType)
+ {
+ case JsonToken.StartObject:
+ return JsonSchemaType.Object;
+ case JsonToken.StartArray:
+ return JsonSchemaType.Array;
+ case JsonToken.Integer:
+ return JsonSchemaType.Integer;
+ case JsonToken.Float:
+ return JsonSchemaType.Float;
+ case JsonToken.String:
+ return JsonSchemaType.String;
+ case JsonToken.Boolean:
+ return JsonSchemaType.Boolean;
+ case JsonToken.Null:
+ return JsonSchemaType.Null;
+ default:
+ return null;
+ }
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of .
+ public override int? ReadAsInt32()
+ {
+ int? i = _reader.ReadAsInt32();
+
+ ValidateCurrentToken();
+ return i;
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a [].
+ ///
+ ///
+ /// A [] or null if the next JSON token is null.
+ ///
+ public override byte[] ReadAsBytes()
+ {
+ byte[] data = _reader.ReadAsBytes();
+
+ ValidateCurrentToken();
+ return data;
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of .
+ public override decimal? ReadAsDecimal()
+ {
+ decimal? d = _reader.ReadAsDecimal();
+
+ ValidateCurrentToken();
+ return d;
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of .
+ public override double? ReadAsDouble()
+ {
+ double? d = _reader.ReadAsDouble();
+
+ ValidateCurrentToken();
+ return d;
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of .
+ public override bool? ReadAsBoolean()
+ {
+ bool? b = _reader.ReadAsBoolean();
+
+ ValidateCurrentToken();
+ return b;
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a .
+ ///
+ /// A . This method will return null at the end of an array.
+ public override string ReadAsString()
+ {
+ string s = _reader.ReadAsString();
+
+ ValidateCurrentToken();
+ return s;
+ }
+
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of . This method will return null at the end of an array.
+ public override DateTime? ReadAsDateTime()
+ {
+ DateTime? dateTime = _reader.ReadAsDateTime();
+
+ ValidateCurrentToken();
+ return dateTime;
+ }
+
+#if HAVE_DATE_TIME_OFFSET
+ ///
+ /// Reads the next JSON token from the underlying as a of .
+ ///
+ /// A of .
+ public override DateTimeOffset? ReadAsDateTimeOffset()
+ {
+ DateTimeOffset? dateTimeOffset = _reader.ReadAsDateTimeOffset();
+
+ ValidateCurrentToken();
+ return dateTimeOffset;
+ }
+#endif
+
+ ///
+ /// Reads the next JSON token from the underlying .
+ ///
+ ///
+ /// true if the next token was read successfully; false if there are no more tokens to read.
+ ///
+ public override bool Read()
+ {
+ if (!_reader.Read())
+ {
+ return false;
+ }
+
+ if (_reader.TokenType == JsonToken.Comment)
+ {
+ return true;
+ }
+
+ ValidateCurrentToken();
+ return true;
+ }
+
+ private void ValidateCurrentToken()
+ {
+ // first time validate has been called. build model
+ if (_model == null)
+ {
+ JsonSchemaModelBuilder builder = new JsonSchemaModelBuilder();
+ _model = builder.Build(_schema);
+
+ if (!JsonTokenUtils.IsStartToken(_reader.TokenType))
+ {
+ Push(new SchemaScope(JTokenType.None, CurrentMemberSchemas));
+ }
+ }
+
+ switch (_reader.TokenType)
+ {
+ case JsonToken.StartObject:
+ ProcessValue();
+ IList objectSchemas = CurrentMemberSchemas.Where(ValidateObject).ToList();
+ Push(new SchemaScope(JTokenType.Object, objectSchemas));
+ WriteToken(CurrentSchemas);
+ break;
+ case JsonToken.StartArray:
+ ProcessValue();
+ IList arraySchemas = CurrentMemberSchemas.Where(ValidateArray).ToList();
+ Push(new SchemaScope(JTokenType.Array, arraySchemas));
+ WriteToken(CurrentSchemas);
+ break;
+ case JsonToken.StartConstructor:
+ ProcessValue();
+ Push(new SchemaScope(JTokenType.Constructor, null));
+ WriteToken(CurrentSchemas);
+ break;
+ case JsonToken.PropertyName:
+ WriteToken(CurrentSchemas);
+ foreach (JsonSchemaModel schema in CurrentSchemas)
+ {
+ ValidatePropertyName(schema);
+ }
+ break;
+ case JsonToken.Raw:
+ ProcessValue();
+ break;
+ case JsonToken.Integer:
+ ProcessValue();
+ WriteToken(CurrentMemberSchemas);
+ foreach (JsonSchemaModel schema in CurrentMemberSchemas)
+ {
+ ValidateInteger(schema);
+ }
+ break;
+ case JsonToken.Float:
+ ProcessValue();
+ WriteToken(CurrentMemberSchemas);
+ foreach (JsonSchemaModel schema in CurrentMemberSchemas)
+ {
+ ValidateFloat(schema);
+ }
+ break;
+ case JsonToken.String:
+ ProcessValue();
+ WriteToken(CurrentMemberSchemas);
+ foreach (JsonSchemaModel schema in CurrentMemberSchemas)
+ {
+ ValidateString(schema);
+ }
+ break;
+ case JsonToken.Boolean:
+ ProcessValue();
+ WriteToken(CurrentMemberSchemas);
+ foreach (JsonSchemaModel schema in CurrentMemberSchemas)
+ {
+ ValidateBoolean(schema);
+ }
+ break;
+ case JsonToken.Null:
+ ProcessValue();
+ WriteToken(CurrentMemberSchemas);
+ foreach (JsonSchemaModel schema in CurrentMemberSchemas)
+ {
+ ValidateNull(schema);
+ }
+ break;
+ case JsonToken.EndObject:
+ WriteToken(CurrentSchemas);
+ foreach (JsonSchemaModel schema in CurrentSchemas)
+ {
+ ValidateEndObject(schema);
+ }
+ Pop();
+ break;
+ case JsonToken.EndArray:
+ WriteToken(CurrentSchemas);
+ foreach (JsonSchemaModel schema in CurrentSchemas)
+ {
+ ValidateEndArray(schema);
+ }
+ Pop();
+ break;
+ case JsonToken.EndConstructor:
+ WriteToken(CurrentSchemas);
+ Pop();
+ break;
+ case JsonToken.Undefined:
+ case JsonToken.Date:
+ case JsonToken.Bytes:
+ // these have no equivalent in JSON schema
+ WriteToken(CurrentMemberSchemas);
+ break;
+ case JsonToken.None:
+ // no content, do nothing
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ private void WriteToken(IList schemas)
+ {
+ foreach (SchemaScope schemaScope in _stack)
+ {
+ bool isInUniqueArray = (schemaScope.TokenType == JTokenType.Array && schemaScope.IsUniqueArray && schemaScope.ArrayItemCount > 0);
+
+ if (isInUniqueArray || schemas.Any(s => s.Enum != null))
+ {
+ if (schemaScope.CurrentItemWriter == null)
+ {
+ if (JsonTokenUtils.IsEndToken(_reader.TokenType))
+ {
+ continue;
+ }
+
+ schemaScope.CurrentItemWriter = new JTokenWriter();
+ }
+
+ schemaScope.CurrentItemWriter.WriteToken(_reader, false);
+
+ // finished writing current item
+ if (schemaScope.CurrentItemWriter.Top == 0 && _reader.TokenType != JsonToken.PropertyName)
+ {
+ JToken finishedItem = schemaScope.CurrentItemWriter.Token;
+
+ // start next item with new writer
+ schemaScope.CurrentItemWriter = null;
+
+ if (isInUniqueArray)
+ {
+ if (schemaScope.UniqueArrayItems.Contains(finishedItem, JToken.EqualityComparer))
+ {
+ RaiseError("Non-unique array item at index {0}.".FormatWith(CultureInfo.InvariantCulture, schemaScope.ArrayItemCount - 1), schemaScope.Schemas.First(s => s.UniqueItems));
+ }
+
+ schemaScope.UniqueArrayItems.Add(finishedItem);
+ }
+ else if (schemas.Any(s => s.Enum != null))
+ {
+ foreach (JsonSchemaModel schema in schemas)
+ {
+ if (schema.Enum != null)
+ {
+ if (!schema.Enum.ContainsValue(finishedItem, JToken.EqualityComparer))
+ {
+ StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
+ finishedItem.WriteTo(new JsonTextWriter(sw));
+
+ RaiseError("Value {0} is not defined in enum.".FormatWith(CultureInfo.InvariantCulture, sw.ToString()), schema);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void ValidateEndObject(JsonSchemaModel schema)
+ {
+ if (schema == null)
+ {
+ return;
+ }
+
+ Dictionary requiredProperties = _currentScope.RequiredProperties;
+
+ if (requiredProperties != null && requiredProperties.Values.Any(v => !v))
+ {
+ IEnumerable unmatchedRequiredProperties = requiredProperties.Where(kv => !kv.Value).Select(kv => kv.Key);
+ RaiseError("Required properties are missing from object: {0}.".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", unmatchedRequiredProperties
+#if !HAVE_STRING_JOIN_WITH_ENUMERABLE
+ .ToArray()
+#endif
+ )), schema);
+ }
+ }
+
+ private void ValidateEndArray(JsonSchemaModel schema)
+ {
+ if (schema == null)
+ {
+ return;
+ }
+
+ int arrayItemCount = _currentScope.ArrayItemCount;
+
+ if (schema.MaximumItems != null && arrayItemCount > schema.MaximumItems)
+ {
+ RaiseError("Array item count {0} exceeds maximum count of {1}.".FormatWith(CultureInfo.InvariantCulture, arrayItemCount, schema.MaximumItems), schema);
+ }
+
+ if (schema.MinimumItems != null && arrayItemCount < schema.MinimumItems)
+ {
+ RaiseError("Array item count {0} is less than minimum count of {1}.".FormatWith(CultureInfo.InvariantCulture, arrayItemCount, schema.MinimumItems), schema);
+ }
+ }
+
+ private void ValidateNull(JsonSchemaModel schema)
+ {
+ if (schema == null)
+ {
+ return;
+ }
+
+ if (!TestType(schema, JsonSchemaType.Null))
+ {
+ return;
+ }
+
+ ValidateNotDisallowed(schema);
+ }
+
+ private void ValidateBoolean(JsonSchemaModel schema)
+ {
+ if (schema == null)
+ {
+ return;
+ }
+
+ if (!TestType(schema, JsonSchemaType.Boolean))
+ {
+ return;
+ }
+
+ ValidateNotDisallowed(schema);
+ }
+
+ private void ValidateString(JsonSchemaModel schema)
+ {
+ if (schema == null)
+ {
+ return;
+ }
+
+ if (!TestType(schema, JsonSchemaType.String))
+ {
+ return;
+ }
+
+ ValidateNotDisallowed(schema);
+
+ string value = _reader.Value.ToString();
+
+ if (schema.MaximumLength != null && value.Length > schema.MaximumLength)
+ {
+ RaiseError("String '{0}' exceeds maximum length of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.MaximumLength), schema);
+ }
+
+ if (schema.MinimumLength != null && value.Length < schema.MinimumLength)
+ {
+ RaiseError("String '{0}' is less than minimum length of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.MinimumLength), schema);
+ }
+
+ if (schema.Patterns != null)
+ {
+ foreach (string pattern in schema.Patterns)
+ {
+ if (!Regex.IsMatch(value, pattern))
+ {
+ RaiseError("String '{0}' does not match regex pattern '{1}'.".FormatWith(CultureInfo.InvariantCulture, value, pattern), schema);
+ }
+ }
+ }
+ }
+
+ private void ValidateInteger(JsonSchemaModel schema)
+ {
+ if (schema == null)
+ {
+ return;
+ }
+
+ if (!TestType(schema, JsonSchemaType.Integer))
+ {
+ return;
+ }
+
+ ValidateNotDisallowed(schema);
+
+ object value = _reader.Value;
+
+ if (schema.Maximum != null)
+ {
+ if (JValue.Compare(JTokenType.Integer, value, schema.Maximum) > 0)
+ {
+ RaiseError("Integer {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Maximum), schema);
+ }
+ if (schema.ExclusiveMaximum && JValue.Compare(JTokenType.Integer, value, schema.Maximum) == 0)
+ {
+ RaiseError("Integer {0} equals maximum value of {1} and exclusive maximum is true.".FormatWith(CultureInfo.InvariantCulture, value, schema.Maximum), schema);
+ }
+ }
+
+ if (schema.Minimum != null)
+ {
+ if (JValue.Compare(JTokenType.Integer, value, schema.Minimum) < 0)
+ {
+ RaiseError("Integer {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Minimum), schema);
+ }
+ if (schema.ExclusiveMinimum && JValue.Compare(JTokenType.Integer, value, schema.Minimum) == 0)
+ {
+ RaiseError("Integer {0} equals minimum value of {1} and exclusive minimum is true.".FormatWith(CultureInfo.InvariantCulture, value, schema.Minimum), schema);
+ }
+ }
+
+ if (schema.DivisibleBy != null)
+ {
+ bool notDivisible;
+#if HAVE_BIG_INTEGER
+ if (value is BigInteger i)
+ {
+ // not that this will lose any decimal point on DivisibleBy
+ // so manually raise an error if DivisibleBy is not an integer and value is not zero
+ bool divisibleNonInteger = !Math.Abs(schema.DivisibleBy.Value - Math.Truncate(schema.DivisibleBy.Value)).Equals(0);
+ if (divisibleNonInteger)
+ {
+ notDivisible = i != 0;
+ }
+ else
+ {
+ notDivisible = i % new BigInteger(schema.DivisibleBy.Value) != 0;
+ }
+ }
+ else
+#endif
+ {
+ notDivisible = !IsZero(Convert.ToInt64(value, CultureInfo.InvariantCulture) % schema.DivisibleBy.GetValueOrDefault());
+ }
+
+ if (notDivisible)
+ {
+ RaiseError("Integer {0} is not evenly divisible by {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.DivisibleBy), schema);
+ }
+ }
+ }
+
+ private void ProcessValue()
+ {
+ if (_currentScope != null && _currentScope.TokenType == JTokenType.Array)
+ {
+ _currentScope.ArrayItemCount++;
+
+ foreach (JsonSchemaModel currentSchema in CurrentSchemas)
+ {
+ // if there is positional validation and the array index is past the number of item validation schemas and there are no additional items then error
+ if (currentSchema != null
+ && currentSchema.PositionalItemsValidation
+ && !currentSchema.AllowAdditionalItems
+ && (currentSchema.Items == null || _currentScope.ArrayItemCount - 1 >= currentSchema.Items.Count))
+ {
+ RaiseError("Index {0} has not been defined and the schema does not allow additional items.".FormatWith(CultureInfo.InvariantCulture, _currentScope.ArrayItemCount), currentSchema);
+ }
+ }
+ }
+ }
+
+ private void ValidateFloat(JsonSchemaModel schema)
+ {
+ if (schema == null)
+ {
+ return;
+ }
+
+ if (!TestType(schema, JsonSchemaType.Float))
+ {
+ return;
+ }
+
+ ValidateNotDisallowed(schema);
+
+ double value = Convert.ToDouble(_reader.Value, CultureInfo.InvariantCulture);
+
+ if (schema.Maximum != null)
+ {
+ if (value > schema.Maximum)
+ {
+ RaiseError("Float {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Maximum), schema);
+ }
+ if (schema.ExclusiveMaximum && value == schema.Maximum)
+ {
+ RaiseError("Float {0} equals maximum value of {1} and exclusive maximum is true.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Maximum), schema);
+ }
+ }
+
+ if (schema.Minimum != null)
+ {
+ if (value < schema.Minimum)
+ {
+ RaiseError("Float {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Minimum), schema);
+ }
+ if (schema.ExclusiveMinimum && value == schema.Minimum)
+ {
+ RaiseError("Float {0} equals minimum value of {1} and exclusive minimum is true.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Minimum), schema);
+ }
+ }
+
+ if (schema.DivisibleBy != null)
+ {
+ double remainder = FloatingPointRemainder(value, schema.DivisibleBy.GetValueOrDefault());
+
+ if (!IsZero(remainder))
+ {
+ RaiseError("Float {0} is not evenly divisible by {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.DivisibleBy), schema);
+ }
+ }
+ }
+
+ private static double FloatingPointRemainder(double dividend, double divisor)
+ {
+ return dividend - Math.Floor(dividend / divisor) * divisor;
+ }
+
+ private static bool IsZero(double value)
+ {
+ const double epsilon = 2.2204460492503131e-016;
+
+ return Math.Abs(value) < 20.0 * epsilon;
+ }
+
+ private void ValidatePropertyName(JsonSchemaModel schema)
+ {
+ if (schema == null)
+ {
+ return;
+ }
+
+ string propertyName = Convert.ToString(_reader.Value, CultureInfo.InvariantCulture);
+
+ if (_currentScope.RequiredProperties.ContainsKey(propertyName))
+ {
+ _currentScope.RequiredProperties[propertyName] = true;
+ }
+
+ if (!schema.AllowAdditionalProperties)
+ {
+ bool propertyDefinied = IsPropertyDefinied(schema, propertyName);
+
+ if (!propertyDefinied)
+ {
+ RaiseError("Property '{0}' has not been defined and the schema does not allow additional properties.".FormatWith(CultureInfo.InvariantCulture, propertyName), schema);
+ }
+ }
+
+ _currentScope.CurrentPropertyName = propertyName;
+ }
+
+ private bool IsPropertyDefinied(JsonSchemaModel schema, string propertyName)
+ {
+ if (schema.Properties != null && schema.Properties.ContainsKey(propertyName))
+ {
+ return true;
+ }
+
+ if (schema.PatternProperties != null)
+ {
+ foreach (string pattern in schema.PatternProperties.Keys)
+ {
+ if (Regex.IsMatch(propertyName, pattern))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private bool ValidateArray(JsonSchemaModel schema)
+ {
+ if (schema == null)
+ {
+ return true;
+ }
+
+ return (TestType(schema, JsonSchemaType.Array));
+ }
+
+ private bool ValidateObject(JsonSchemaModel schema)
+ {
+ if (schema == null)
+ {
+ return true;
+ }
+
+ return (TestType(schema, JsonSchemaType.Object));
+ }
+
+ private bool TestType(JsonSchemaModel currentSchema, JsonSchemaType currentType)
+ {
+ if (!JsonSchemaGenerator.HasFlag(currentSchema.Type, currentType))
+ {
+ RaiseError("Invalid type. Expected {0} but got {1}.".FormatWith(CultureInfo.InvariantCulture, currentSchema.Type, currentType), currentSchema);
+ return false;
+ }
+
+ return true;
+ }
+
+ bool IJsonLineInfo.HasLineInfo()
+ {
+ return _reader is IJsonLineInfo lineInfo && lineInfo.HasLineInfo();
+ }
+
+ int IJsonLineInfo.LineNumber => (_reader is IJsonLineInfo lineInfo) ? lineInfo.LineNumber : 0;
+
+ int IJsonLineInfo.LinePosition => (_reader is IJsonLineInfo lineInfo) ? lineInfo.LinePosition : 0;
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonWriter.Async.cs b/Libs/Newtonsoft.Json.AOT/JsonWriter.Async.cs
new file mode 100644
index 0000000..bbeec12
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonWriter.Async.cs
@@ -0,0 +1,1797 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if HAVE_ASYNC
+
+using System;
+using System.Globalization;
+using System.Threading;
+#if HAVE_BIG_INTEGER
+using System.Numerics;
+#endif
+using System.Threading.Tasks;
+using LC.Newtonsoft.Json.Utilities;
+
+namespace LC.Newtonsoft.Json
+{
+ public abstract partial class JsonWriter
+ {
+ internal Task AutoCompleteAsync(JsonToken tokenBeingWritten, CancellationToken cancellationToken)
+ {
+ State oldState = _currentState;
+
+ // gets new state based on the current state and what is being written
+ State newState = StateArray[(int)tokenBeingWritten][(int)oldState];
+
+ if (newState == State.Error)
+ {
+ throw JsonWriterException.Create(this, "Token {0} in state {1} would result in an invalid JSON object.".FormatWith(CultureInfo.InvariantCulture, tokenBeingWritten.ToString(), oldState.ToString()), null);
+ }
+
+ _currentState = newState;
+
+ if (_formatting == Formatting.Indented)
+ {
+ switch (oldState)
+ {
+ case State.Start:
+ break;
+ case State.Property:
+ return WriteIndentSpaceAsync(cancellationToken);
+ case State.ArrayStart:
+ case State.ConstructorStart:
+ return WriteIndentAsync(cancellationToken);
+ case State.Array:
+ case State.Constructor:
+ return tokenBeingWritten == JsonToken.Comment ? WriteIndentAsync(cancellationToken) : AutoCompleteAsync(cancellationToken);
+ case State.Object:
+ switch (tokenBeingWritten)
+ {
+ case JsonToken.Comment:
+ break;
+ case JsonToken.PropertyName:
+ return AutoCompleteAsync(cancellationToken);
+ default:
+ return WriteValueDelimiterAsync(cancellationToken);
+ }
+
+ break;
+ default:
+ if (tokenBeingWritten == JsonToken.PropertyName)
+ {
+ return WriteIndentAsync(cancellationToken);
+ }
+
+ break;
+ }
+ }
+ else if (tokenBeingWritten != JsonToken.Comment)
+ {
+ switch (oldState)
+ {
+ case State.Object:
+ case State.Array:
+ case State.Constructor:
+ return WriteValueDelimiterAsync(cancellationToken);
+ }
+ }
+
+ return AsyncUtils.CompletedTask;
+ }
+
+ private async Task AutoCompleteAsync(CancellationToken cancellationToken)
+ {
+ await WriteValueDelimiterAsync(cancellationToken).ConfigureAwait(false);
+ await WriteIndentAsync(cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously closes this writer.
+ /// If is set to true , the destination is also closed.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task CloseAsync(CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ Close();
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously flushes whatever is in the buffer to the destination and also flushes the destination.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task FlushAsync(CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ Flush();
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes the specified end token.
+ ///
+ /// The end token to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ protected virtual Task WriteEndAsync(JsonToken token, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteEnd(token);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes indent characters.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ protected virtual Task WriteIndentAsync(CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteIndent();
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes the JSON value delimiter.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ protected virtual Task WriteValueDelimiterAsync(CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValueDelimiter();
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes an indent space.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ protected virtual Task WriteIndentSpaceAsync(CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteIndentSpace();
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes raw JSON without changing the writer's state.
+ ///
+ /// The raw JSON to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteRawAsync(string? json, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteRaw(json);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes the end of the current JSON object or array.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteEndAsync(CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteEnd();
+ return AsyncUtils.CompletedTask;
+ }
+
+ internal Task WriteEndInternalAsync(CancellationToken cancellationToken)
+ {
+ JsonContainerType type = Peek();
+ switch (type)
+ {
+ case JsonContainerType.Object:
+ return WriteEndObjectAsync(cancellationToken);
+ case JsonContainerType.Array:
+ return WriteEndArrayAsync(cancellationToken);
+ case JsonContainerType.Constructor:
+ return WriteEndConstructorAsync(cancellationToken);
+ default:
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ throw JsonWriterException.Create(this, "Unexpected type when writing end: " + type, null);
+ }
+ }
+
+ internal Task InternalWriteEndAsync(JsonContainerType type, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ int levelsToComplete = CalculateLevelsToComplete(type);
+ while (levelsToComplete-- > 0)
+ {
+ JsonToken token = GetCloseTokenForType(Pop());
+
+ Task t;
+ if (_currentState == State.Property)
+ {
+ t = WriteNullAsync(cancellationToken);
+ if (!t.IsCompletedSucessfully())
+ {
+ return AwaitProperty(t, levelsToComplete, token, cancellationToken);
+ }
+ }
+
+ if (_formatting == Formatting.Indented)
+ {
+ if (_currentState != State.ObjectStart && _currentState != State.ArrayStart)
+ {
+ t = WriteIndentAsync(cancellationToken);
+ if (!t.IsCompletedSucessfully())
+ {
+ return AwaitIndent(t, levelsToComplete, token, cancellationToken);
+ }
+ }
+ }
+
+ t = WriteEndAsync(token, cancellationToken);
+ if (!t.IsCompletedSucessfully())
+ {
+ return AwaitEnd(t, levelsToComplete, cancellationToken);
+ }
+
+ UpdateCurrentState();
+ }
+
+ return AsyncUtils.CompletedTask;
+
+ // Local functions, params renamed (capitalized) so as not to capture and allocate when calling async
+ async Task AwaitProperty(Task task, int LevelsToComplete, JsonToken token, CancellationToken CancellationToken)
+ {
+ await task.ConfigureAwait(false);
+
+ // Finish current loop
+ if (_formatting == Formatting.Indented)
+ {
+ if (_currentState != State.ObjectStart && _currentState != State.ArrayStart)
+ {
+ await WriteIndentAsync(CancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ await WriteEndAsync(token, CancellationToken).ConfigureAwait(false);
+
+ UpdateCurrentState();
+
+ await AwaitRemaining(LevelsToComplete, CancellationToken).ConfigureAwait(false);
+ }
+
+ async Task AwaitIndent(Task task, int LevelsToComplete, JsonToken token, CancellationToken CancellationToken)
+ {
+ await task.ConfigureAwait(false);
+
+ // Finish current loop
+
+ await WriteEndAsync(token, CancellationToken).ConfigureAwait(false);
+
+ UpdateCurrentState();
+
+ await AwaitRemaining(LevelsToComplete, CancellationToken).ConfigureAwait(false);
+ }
+
+ async Task AwaitEnd(Task task, int LevelsToComplete, CancellationToken CancellationToken)
+ {
+ await task.ConfigureAwait(false);
+
+ // Finish current loop
+
+ UpdateCurrentState();
+
+ await AwaitRemaining(LevelsToComplete, CancellationToken).ConfigureAwait(false);
+ }
+
+ async Task AwaitRemaining(int LevelsToComplete, CancellationToken CancellationToken)
+ {
+ while (LevelsToComplete-- > 0)
+ {
+ JsonToken token = GetCloseTokenForType(Pop());
+
+ if (_currentState == State.Property)
+ {
+ await WriteNullAsync(CancellationToken).ConfigureAwait(false);
+ }
+
+ if (_formatting == Formatting.Indented)
+ {
+ if (_currentState != State.ObjectStart && _currentState != State.ArrayStart)
+ {
+ await WriteIndentAsync(CancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ await WriteEndAsync(token, CancellationToken).ConfigureAwait(false);
+
+ UpdateCurrentState();
+ }
+ }
+ }
+
+ ///
+ /// Asynchronously writes the end of an array.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteEndArrayAsync(CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteEndArray();
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes the end of a constructor.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteEndConstructorAsync(CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteEndConstructor();
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes the end of a JSON object.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteEndObjectAsync(CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteEndObject();
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a null value.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteNullAsync(CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteNull();
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes the property name of a name/value pair of a JSON object.
+ ///
+ /// The name of the property.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WritePropertyNameAsync(string name, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WritePropertyName(name);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes the property name of a name/value pair of a JSON object.
+ ///
+ /// The name of the property.
+ /// A flag to indicate whether the text should be escaped when it is written as a JSON property name.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WritePropertyNameAsync(string name, bool escape, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WritePropertyName(name, escape);
+ return AsyncUtils.CompletedTask;
+ }
+
+ internal Task InternalWritePropertyNameAsync(string name, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ _currentPosition.PropertyName = name;
+ return AutoCompleteAsync(JsonToken.PropertyName, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes the beginning of a JSON array.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteStartArrayAsync(CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteStartArray();
+ return AsyncUtils.CompletedTask;
+ }
+
+ internal async Task InternalWriteStartAsync(JsonToken token, JsonContainerType container, CancellationToken cancellationToken)
+ {
+ UpdateScopeWithFinishedValue();
+ await AutoCompleteAsync(token, cancellationToken).ConfigureAwait(false);
+ Push(container);
+ }
+
+ ///
+ /// Asynchronously writes a comment /*...*/ containing the specified text.
+ ///
+ /// Text to place inside the comment.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteCommentAsync(string? text, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteComment(text);
+ return AsyncUtils.CompletedTask;
+ }
+
+ internal Task InternalWriteCommentAsync(CancellationToken cancellationToken)
+ {
+ return AutoCompleteAsync(JsonToken.Comment, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes raw JSON where a value is expected and updates the writer's state.
+ ///
+ /// The raw JSON to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteRawValueAsync(string? json, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteRawValue(json);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes the start of a constructor with the given name.
+ ///
+ /// The name of the constructor.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteStartConstructorAsync(string name, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteStartConstructor(name);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes the beginning of a JSON object.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteStartObjectAsync(CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteStartObject();
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes the current token.
+ ///
+ /// The to read the token from.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public Task WriteTokenAsync(JsonReader reader, CancellationToken cancellationToken = default)
+ {
+ return WriteTokenAsync(reader, true, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes the current token.
+ ///
+ /// The to read the token from.
+ /// A flag indicating whether the current token's children should be written.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public Task WriteTokenAsync(JsonReader reader, bool writeChildren, CancellationToken cancellationToken = default)
+ {
+ ValidationUtils.ArgumentNotNull(reader, nameof(reader));
+
+ return WriteTokenAsync(reader, writeChildren, true, true, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes the token and its value.
+ ///
+ /// The to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public Task WriteTokenAsync(JsonToken token, CancellationToken cancellationToken = default)
+ {
+ return WriteTokenAsync(token, null, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously writes the token and its value.
+ ///
+ /// The to write.
+ ///
+ /// The value to write.
+ /// A value is only required for tokens that have an associated value, e.g. the property name for .
+ /// null can be passed to the method for tokens that don't have a value, e.g. .
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public Task WriteTokenAsync(JsonToken token, object? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ switch (token)
+ {
+ case JsonToken.None:
+ // read to next
+ return AsyncUtils.CompletedTask;
+ case JsonToken.StartObject:
+ return WriteStartObjectAsync(cancellationToken);
+ case JsonToken.StartArray:
+ return WriteStartArrayAsync(cancellationToken);
+ case JsonToken.StartConstructor:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ return WriteStartConstructorAsync(value.ToString(), cancellationToken);
+ case JsonToken.PropertyName:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ return WritePropertyNameAsync(value.ToString(), cancellationToken);
+ case JsonToken.Comment:
+ return WriteCommentAsync(value?.ToString(), cancellationToken);
+ case JsonToken.Integer:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ return
+#if HAVE_BIG_INTEGER
+ value is BigInteger integer ? WriteValueAsync(integer, cancellationToken) :
+#endif
+ WriteValueAsync(Convert.ToInt64(value, CultureInfo.InvariantCulture), cancellationToken);
+ case JsonToken.Float:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ if (value is decimal dec)
+ {
+ return WriteValueAsync(dec, cancellationToken);
+ }
+
+ if (value is double doub)
+ {
+ return WriteValueAsync(doub, cancellationToken);
+ }
+
+ if (value is float f)
+ {
+ return WriteValueAsync(f, cancellationToken);
+ }
+
+ return WriteValueAsync(Convert.ToDouble(value, CultureInfo.InvariantCulture), cancellationToken);
+ case JsonToken.String:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ return WriteValueAsync(value.ToString(), cancellationToken);
+ case JsonToken.Boolean:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ return WriteValueAsync(Convert.ToBoolean(value, CultureInfo.InvariantCulture), cancellationToken);
+ case JsonToken.Null:
+ return WriteNullAsync(cancellationToken);
+ case JsonToken.Undefined:
+ return WriteUndefinedAsync(cancellationToken);
+ case JsonToken.EndObject:
+ return WriteEndObjectAsync(cancellationToken);
+ case JsonToken.EndArray:
+ return WriteEndArrayAsync(cancellationToken);
+ case JsonToken.EndConstructor:
+ return WriteEndConstructorAsync(cancellationToken);
+ case JsonToken.Date:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ if (value is DateTimeOffset offset)
+ {
+ return WriteValueAsync(offset, cancellationToken);
+ }
+
+ return WriteValueAsync(Convert.ToDateTime(value, CultureInfo.InvariantCulture), cancellationToken);
+ case JsonToken.Raw:
+ return WriteRawValueAsync(value?.ToString(), cancellationToken);
+ case JsonToken.Bytes:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ if (value is Guid guid)
+ {
+ return WriteValueAsync(guid, cancellationToken);
+ }
+
+ return WriteValueAsync((byte[]?)value, cancellationToken);
+ default:
+ throw MiscellaneousUtils.CreateArgumentOutOfRangeException(nameof(token), token, "Unexpected token type.");
+ }
+ }
+
+ internal virtual async Task WriteTokenAsync(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments, CancellationToken cancellationToken)
+ {
+ int initialDepth = CalculateWriteTokenInitialDepth(reader);
+
+ do
+ {
+ // write a JValue date when the constructor is for a date
+ if (writeDateConstructorAsDate && reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal))
+ {
+ await WriteConstructorDateAsync(reader, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ if (writeComments || reader.TokenType != JsonToken.Comment)
+ {
+ await WriteTokenAsync(reader.TokenType, reader.Value, cancellationToken).ConfigureAwait(false);
+ }
+ }
+ } while (
+ // stop if we have reached the end of the token being read
+ initialDepth - 1 < reader.Depth - (JsonTokenUtils.IsEndToken(reader.TokenType) ? 1 : 0)
+ && writeChildren
+ && await reader.ReadAsync(cancellationToken).ConfigureAwait(false));
+
+ if (IsWriteTokenIncomplete(reader, writeChildren, initialDepth))
+ {
+ throw JsonWriterException.Create(this, "Unexpected end when reading token.", null);
+ }
+ }
+
+ // For internal use, when we know the writer does not offer true async support (e.g. when backed
+ // by a StringWriter) and therefore async write methods are always in practice just a less efficient
+ // path through the sync version.
+ internal async Task WriteTokenSyncReadingAsync(JsonReader reader, CancellationToken cancellationToken)
+ {
+ int initialDepth = CalculateWriteTokenInitialDepth(reader);
+
+ do
+ {
+ // write a JValue date when the constructor is for a date
+ if (reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal))
+ {
+ WriteConstructorDate(reader);
+ }
+ else
+ {
+ WriteToken(reader.TokenType, reader.Value);
+ }
+ } while (
+ // stop if we have reached the end of the token being read
+ initialDepth - 1 < reader.Depth - (JsonTokenUtils.IsEndToken(reader.TokenType) ? 1 : 0)
+ && await reader.ReadAsync(cancellationToken).ConfigureAwait(false));
+
+ if (initialDepth < CalculateWriteTokenFinalDepth(reader))
+ {
+ throw JsonWriterException.Create(this, "Unexpected end when reading token.", null);
+ }
+ }
+
+ private async Task WriteConstructorDateAsync(JsonReader reader, CancellationToken cancellationToken)
+ {
+ if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
+ {
+ throw JsonWriterException.Create(this, "Unexpected end when reading date constructor.", null);
+ }
+ if (reader.TokenType != JsonToken.Integer)
+ {
+ throw JsonWriterException.Create(this, "Unexpected token when reading date constructor. Expected Integer, got " + reader.TokenType, null);
+ }
+
+ DateTime date = DateTimeUtils.ConvertJavaScriptTicksToDateTime((long)reader.Value!);
+
+ if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
+ {
+ throw JsonWriterException.Create(this, "Unexpected end when reading date constructor.", null);
+ }
+ if (reader.TokenType != JsonToken.EndConstructor)
+ {
+ throw JsonWriterException.Create(this, "Unexpected token when reading date constructor. Expected EndConstructor, got " + reader.TokenType, null);
+ }
+
+ await WriteValueAsync(date, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(bool value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(bool? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(byte value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(byte? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a [] value.
+ ///
+ /// The [] value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(byte[]? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(char value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(char? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(DateTime value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(DateTime? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(DateTimeOffset value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(DateTimeOffset? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(decimal value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(decimal? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(double value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(double? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(float value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(float? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(Guid value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(Guid? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(int value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(int? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(long value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(long? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(object? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ [CLSCompliant(false)]
+ public virtual Task WriteValueAsync(sbyte value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ [CLSCompliant(false)]
+ public virtual Task WriteValueAsync(sbyte? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(short value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(short? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(string? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(TimeSpan value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(TimeSpan? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ [CLSCompliant(false)]
+ public virtual Task WriteValueAsync(uint value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ [CLSCompliant(false)]
+ public virtual Task WriteValueAsync(uint? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ [CLSCompliant(false)]
+ public virtual Task WriteValueAsync(ulong value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ [CLSCompliant(false)]
+ public virtual Task WriteValueAsync(ulong? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteValueAsync(Uri? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a value.
+ ///
+ /// The value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ [CLSCompliant(false)]
+ public virtual Task WriteValueAsync(ushort value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes a of value.
+ ///
+ /// The of value to write.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ [CLSCompliant(false)]
+ public virtual Task WriteValueAsync(ushort? value, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteValue(value);
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes an undefined value.
+ ///
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteUndefinedAsync(CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteUndefined();
+ return AsyncUtils.CompletedTask;
+ }
+
+ ///
+ /// Asynchronously writes the given white space.
+ ///
+ /// The string of white space characters.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ public virtual Task WriteWhitespaceAsync(string ws, CancellationToken cancellationToken = default)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ WriteWhitespace(ws);
+ return AsyncUtils.CompletedTask;
+ }
+
+ internal Task InternalWriteValueAsync(JsonToken token, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ UpdateScopeWithFinishedValue();
+ return AutoCompleteAsync(token, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously ets the state of the .
+ ///
+ /// The being written.
+ /// The value being written.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A that represents the asynchronous operation.
+ /// The default behaviour is to execute synchronously, returning an already-completed task. Derived
+ /// classes can override this behaviour for true asynchronicity.
+ protected Task SetWriteStateAsync(JsonToken token, object value, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return cancellationToken.FromCanceled();
+ }
+
+ switch (token)
+ {
+ case JsonToken.StartObject:
+ return InternalWriteStartAsync(token, JsonContainerType.Object, cancellationToken);
+ case JsonToken.StartArray:
+ return InternalWriteStartAsync(token, JsonContainerType.Array, cancellationToken);
+ case JsonToken.StartConstructor:
+ return InternalWriteStartAsync(token, JsonContainerType.Constructor, cancellationToken);
+ case JsonToken.PropertyName:
+ if (!(value is string s))
+ {
+ throw new ArgumentException("A name is required when setting property name state.", nameof(value));
+ }
+
+ return InternalWritePropertyNameAsync(s, cancellationToken);
+ case JsonToken.Comment:
+ return InternalWriteCommentAsync(cancellationToken);
+ case JsonToken.Raw:
+ return AsyncUtils.CompletedTask;
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ case JsonToken.String:
+ case JsonToken.Boolean:
+ case JsonToken.Date:
+ case JsonToken.Bytes:
+ case JsonToken.Null:
+ case JsonToken.Undefined:
+ return InternalWriteValueAsync(token, cancellationToken);
+ case JsonToken.EndObject:
+ return InternalWriteEndAsync(JsonContainerType.Object, cancellationToken);
+ case JsonToken.EndArray:
+ return InternalWriteEndAsync(JsonContainerType.Array, cancellationToken);
+ case JsonToken.EndConstructor:
+ return InternalWriteEndAsync(JsonContainerType.Constructor, cancellationToken);
+ default:
+ throw new ArgumentOutOfRangeException(nameof(token));
+ }
+ }
+
+ internal static Task WriteValueAsync(JsonWriter writer, PrimitiveTypeCode typeCode, object value, CancellationToken cancellationToken)
+ {
+ while (true)
+ {
+ switch (typeCode)
+ {
+ case PrimitiveTypeCode.Char:
+ return writer.WriteValueAsync((char)value, cancellationToken);
+ case PrimitiveTypeCode.CharNullable:
+ return writer.WriteValueAsync(value == null ? (char?)null : (char)value, cancellationToken);
+ case PrimitiveTypeCode.Boolean:
+ return writer.WriteValueAsync((bool)value, cancellationToken);
+ case PrimitiveTypeCode.BooleanNullable:
+ return writer.WriteValueAsync(value == null ? (bool?)null : (bool)value, cancellationToken);
+ case PrimitiveTypeCode.SByte:
+ return writer.WriteValueAsync((sbyte)value, cancellationToken);
+ case PrimitiveTypeCode.SByteNullable:
+ return writer.WriteValueAsync(value == null ? (sbyte?)null : (sbyte)value, cancellationToken);
+ case PrimitiveTypeCode.Int16:
+ return writer.WriteValueAsync((short)value, cancellationToken);
+ case PrimitiveTypeCode.Int16Nullable:
+ return writer.WriteValueAsync(value == null ? (short?)null : (short)value, cancellationToken);
+ case PrimitiveTypeCode.UInt16:
+ return writer.WriteValueAsync((ushort)value, cancellationToken);
+ case PrimitiveTypeCode.UInt16Nullable:
+ return writer.WriteValueAsync(value == null ? (ushort?)null : (ushort)value, cancellationToken);
+ case PrimitiveTypeCode.Int32:
+ return writer.WriteValueAsync((int)value, cancellationToken);
+ case PrimitiveTypeCode.Int32Nullable:
+ return writer.WriteValueAsync(value == null ? (int?)null : (int)value, cancellationToken);
+ case PrimitiveTypeCode.Byte:
+ return writer.WriteValueAsync((byte)value, cancellationToken);
+ case PrimitiveTypeCode.ByteNullable:
+ return writer.WriteValueAsync(value == null ? (byte?)null : (byte)value, cancellationToken);
+ case PrimitiveTypeCode.UInt32:
+ return writer.WriteValueAsync((uint)value, cancellationToken);
+ case PrimitiveTypeCode.UInt32Nullable:
+ return writer.WriteValueAsync(value == null ? (uint?)null : (uint)value, cancellationToken);
+ case PrimitiveTypeCode.Int64:
+ return writer.WriteValueAsync((long)value, cancellationToken);
+ case PrimitiveTypeCode.Int64Nullable:
+ return writer.WriteValueAsync(value == null ? (long?)null : (long)value, cancellationToken);
+ case PrimitiveTypeCode.UInt64:
+ return writer.WriteValueAsync((ulong)value, cancellationToken);
+ case PrimitiveTypeCode.UInt64Nullable:
+ return writer.WriteValueAsync(value == null ? (ulong?)null : (ulong)value, cancellationToken);
+ case PrimitiveTypeCode.Single:
+ return writer.WriteValueAsync((float)value, cancellationToken);
+ case PrimitiveTypeCode.SingleNullable:
+ return writer.WriteValueAsync(value == null ? (float?)null : (float)value, cancellationToken);
+ case PrimitiveTypeCode.Double:
+ return writer.WriteValueAsync((double)value, cancellationToken);
+ case PrimitiveTypeCode.DoubleNullable:
+ return writer.WriteValueAsync(value == null ? (double?)null : (double)value, cancellationToken);
+ case PrimitiveTypeCode.DateTime:
+ return writer.WriteValueAsync((DateTime)value, cancellationToken);
+ case PrimitiveTypeCode.DateTimeNullable:
+ return writer.WriteValueAsync(value == null ? (DateTime?)null : (DateTime)value, cancellationToken);
+ case PrimitiveTypeCode.DateTimeOffset:
+ return writer.WriteValueAsync((DateTimeOffset)value, cancellationToken);
+ case PrimitiveTypeCode.DateTimeOffsetNullable:
+ return writer.WriteValueAsync(value == null ? (DateTimeOffset?)null : (DateTimeOffset)value, cancellationToken);
+ case PrimitiveTypeCode.Decimal:
+ return writer.WriteValueAsync((decimal)value, cancellationToken);
+ case PrimitiveTypeCode.DecimalNullable:
+ return writer.WriteValueAsync(value == null ? (decimal?)null : (decimal)value, cancellationToken);
+ case PrimitiveTypeCode.Guid:
+ return writer.WriteValueAsync((Guid)value, cancellationToken);
+ case PrimitiveTypeCode.GuidNullable:
+ return writer.WriteValueAsync(value == null ? (Guid?)null : (Guid)value, cancellationToken);
+ case PrimitiveTypeCode.TimeSpan:
+ return writer.WriteValueAsync((TimeSpan)value, cancellationToken);
+ case PrimitiveTypeCode.TimeSpanNullable:
+ return writer.WriteValueAsync(value == null ? (TimeSpan?)null : (TimeSpan)value, cancellationToken);
+#if HAVE_BIG_INTEGER
+ case PrimitiveTypeCode.BigInteger:
+
+ // this will call to WriteValueAsync(object)
+ return writer.WriteValueAsync((BigInteger)value, cancellationToken);
+ case PrimitiveTypeCode.BigIntegerNullable:
+
+ // this will call to WriteValueAsync(object)
+ return writer.WriteValueAsync(value == null ? (BigInteger?)null : (BigInteger)value, cancellationToken);
+#endif
+ case PrimitiveTypeCode.Uri:
+ return writer.WriteValueAsync((Uri)value, cancellationToken);
+ case PrimitiveTypeCode.String:
+ return writer.WriteValueAsync((string)value, cancellationToken);
+ case PrimitiveTypeCode.Bytes:
+ return writer.WriteValueAsync((byte[])value, cancellationToken);
+#if HAVE_DB_NULL_TYPE_CODE
+ case PrimitiveTypeCode.DBNull:
+ return writer.WriteNullAsync(cancellationToken);
+#endif
+ default:
+#if HAVE_ICONVERTIBLE
+ if (value is IConvertible convertible)
+ {
+ ResolveConvertibleValue(convertible, out typeCode, out value);
+ continue;
+ }
+#endif
+
+ // write an unknown null value, fix https://github.com/JamesNK/Newtonsoft.Json/issues/1460
+ if (value == null)
+ {
+ return writer.WriteNullAsync(cancellationToken);
+ }
+
+ throw CreateUnsupportedTypeException(writer, value);
+ }
+ }
+ }
+ }
+}
+
+#endif
diff --git a/Libs/Newtonsoft.Json.AOT/JsonWriter.cs b/Libs/Newtonsoft.Json.AOT/JsonWriter.cs
new file mode 100644
index 0000000..3149fb4
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonWriter.cs
@@ -0,0 +1,1789 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+#if HAVE_BIG_INTEGER
+using System.Numerics;
+#endif
+using LC.Newtonsoft.Json.Utilities;
+using System.Globalization;
+#if !HAVE_LINQ
+using LC.Newtonsoft.Json.Utilities.LinqBridge;
+#else
+using System.Linq;
+
+#endif
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
+ ///
+ public abstract partial class JsonWriter : IDisposable
+ {
+ internal enum State
+ {
+ Start = 0,
+ Property = 1,
+ ObjectStart = 2,
+ Object = 3,
+ ArrayStart = 4,
+ Array = 5,
+ ConstructorStart = 6,
+ Constructor = 7,
+ Closed = 8,
+ Error = 9
+ }
+
+ // array that gives a new state based on the current state an the token being written
+ private static readonly State[][] StateArray;
+
+ internal static readonly State[][] StateArrayTemplate = new[]
+ {
+ // Start PropertyName ObjectStart Object ArrayStart Array ConstructorStart Constructor Closed Error
+ //
+ /* None */new[] { State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error },
+ /* StartObject */new[] { State.ObjectStart, State.ObjectStart, State.Error, State.Error, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.Error, State.Error },
+ /* StartArray */new[] { State.ArrayStart, State.ArrayStart, State.Error, State.Error, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.Error, State.Error },
+ /* StartConstructor */new[] { State.ConstructorStart, State.ConstructorStart, State.Error, State.Error, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.Error, State.Error },
+ /* Property */new[] { State.Property, State.Error, State.Property, State.Property, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error },
+ /* Comment */new[] { State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error },
+ /* Raw */new[] { State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error },
+ /* Value (this will be copied) */new[] { State.Start, State.Object, State.Error, State.Error, State.Array, State.Array, State.Constructor, State.Constructor, State.Error, State.Error }
+ };
+
+ internal static State[][] BuildStateArray()
+ {
+ List allStates = StateArrayTemplate.ToList();
+ State[] errorStates = StateArrayTemplate[0];
+ State[] valueStates = StateArrayTemplate[7];
+
+ EnumInfo enumValuesAndNames = EnumUtils.GetEnumValuesAndNames(typeof(JsonToken));
+
+ foreach (ulong valueToken in enumValuesAndNames.Values)
+ {
+ if (allStates.Count <= (int)valueToken)
+ {
+ JsonToken token = (JsonToken)valueToken;
+ switch (token)
+ {
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ case JsonToken.String:
+ case JsonToken.Boolean:
+ case JsonToken.Null:
+ case JsonToken.Undefined:
+ case JsonToken.Date:
+ case JsonToken.Bytes:
+ allStates.Add(valueStates);
+ break;
+ default:
+ allStates.Add(errorStates);
+ break;
+ }
+ }
+ }
+
+ return allStates.ToArray();
+ }
+
+ static JsonWriter()
+ {
+ StateArray = BuildStateArray();
+ }
+
+ private List? _stack;
+ private JsonPosition _currentPosition;
+ private State _currentState;
+ private Formatting _formatting;
+
+ ///
+ /// Gets or sets a value indicating whether the destination should be closed when this writer is closed.
+ ///
+ ///
+ /// true to close the destination when this writer is closed; otherwise false . The default is true .
+ ///
+ public bool CloseOutput { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the JSON should be auto-completed when this writer is closed.
+ ///
+ ///
+ /// true to auto-complete the JSON when this writer is closed; otherwise false . The default is true .
+ ///
+ public bool AutoCompleteOnClose { get; set; }
+
+ ///
+ /// Gets the top.
+ ///
+ /// The top.
+ protected internal int Top
+ {
+ get
+ {
+ int depth = _stack?.Count ?? 0;
+ if (Peek() != JsonContainerType.None)
+ {
+ depth++;
+ }
+
+ return depth;
+ }
+ }
+
+ ///
+ /// Gets the state of the writer.
+ ///
+ public WriteState WriteState
+ {
+ get
+ {
+ switch (_currentState)
+ {
+ case State.Error:
+ return WriteState.Error;
+ case State.Closed:
+ return WriteState.Closed;
+ case State.Object:
+ case State.ObjectStart:
+ return WriteState.Object;
+ case State.Array:
+ case State.ArrayStart:
+ return WriteState.Array;
+ case State.Constructor:
+ case State.ConstructorStart:
+ return WriteState.Constructor;
+ case State.Property:
+ return WriteState.Property;
+ case State.Start:
+ return WriteState.Start;
+ default:
+ throw JsonWriterException.Create(this, "Invalid state: " + _currentState, null);
+ }
+ }
+ }
+
+ internal string ContainerPath
+ {
+ get
+ {
+ if (_currentPosition.Type == JsonContainerType.None || _stack == null)
+ {
+ return string.Empty;
+ }
+
+ return JsonPosition.BuildPath(_stack, null);
+ }
+ }
+
+ ///
+ /// Gets the path of the writer.
+ ///
+ public string Path
+ {
+ get
+ {
+ if (_currentPosition.Type == JsonContainerType.None)
+ {
+ return string.Empty;
+ }
+
+ bool insideContainer = (_currentState != State.ArrayStart
+ && _currentState != State.ConstructorStart
+ && _currentState != State.ObjectStart);
+
+ JsonPosition? current = insideContainer ? (JsonPosition?)_currentPosition : null;
+
+ return JsonPosition.BuildPath(_stack!, current);
+ }
+ }
+
+ private DateFormatHandling _dateFormatHandling;
+ private DateTimeZoneHandling _dateTimeZoneHandling;
+ private StringEscapeHandling _stringEscapeHandling;
+ private FloatFormatHandling _floatFormatHandling;
+ private string? _dateFormatString;
+ private CultureInfo? _culture;
+
+ ///
+ /// Gets or sets a value indicating how JSON text output should be formatted.
+ ///
+ public Formatting Formatting
+ {
+ get => _formatting;
+ set
+ {
+ if (value < Formatting.None || value > Formatting.Indented)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _formatting = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how dates are written to JSON text.
+ ///
+ public DateFormatHandling DateFormatHandling
+ {
+ get => _dateFormatHandling;
+ set
+ {
+ if (value < DateFormatHandling.IsoDateFormat || value > DateFormatHandling.MicrosoftDateFormat)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _dateFormatHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how time zones are handled when writing JSON text.
+ ///
+ public DateTimeZoneHandling DateTimeZoneHandling
+ {
+ get => _dateTimeZoneHandling;
+ set
+ {
+ if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _dateTimeZoneHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how strings are escaped when writing JSON text.
+ ///
+ public StringEscapeHandling StringEscapeHandling
+ {
+ get => _stringEscapeHandling;
+ set
+ {
+ if (value < StringEscapeHandling.Default || value > StringEscapeHandling.EscapeHtml)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _stringEscapeHandling = value;
+ OnStringEscapeHandlingChanged();
+ }
+ }
+
+ internal virtual void OnStringEscapeHandlingChanged()
+ {
+ // hacky but there is a calculated value that relies on StringEscapeHandling
+ }
+
+ ///
+ /// Gets or sets how special floating point numbers, e.g. ,
+ /// and ,
+ /// are written to JSON text.
+ ///
+ public FloatFormatHandling FloatFormatHandling
+ {
+ get => _floatFormatHandling;
+ set
+ {
+ if (value < FloatFormatHandling.String || value > FloatFormatHandling.DefaultValue)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _floatFormatHandling = value;
+ }
+ }
+
+ ///
+ /// Gets or sets how and values are formatted when writing JSON text.
+ ///
+ public string? DateFormatString
+ {
+ get => _dateFormatString;
+ set => _dateFormatString = value;
+ }
+
+ ///
+ /// Gets or sets the culture used when writing JSON. Defaults to .
+ ///
+ public CultureInfo Culture
+ {
+ get => _culture ?? CultureInfo.InvariantCulture;
+ set => _culture = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ protected JsonWriter()
+ {
+ _currentState = State.Start;
+ _formatting = Formatting.None;
+ _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
+
+ CloseOutput = true;
+ AutoCompleteOnClose = true;
+ }
+
+ internal void UpdateScopeWithFinishedValue()
+ {
+ if (_currentPosition.HasIndex)
+ {
+ _currentPosition.Position++;
+ }
+ }
+
+ private void Push(JsonContainerType value)
+ {
+ if (_currentPosition.Type != JsonContainerType.None)
+ {
+ if (_stack == null)
+ {
+ _stack = new List();
+ }
+
+ _stack.Add(_currentPosition);
+ }
+
+ _currentPosition = new JsonPosition(value);
+ }
+
+ private JsonContainerType Pop()
+ {
+ JsonPosition oldPosition = _currentPosition;
+
+ if (_stack != null && _stack.Count > 0)
+ {
+ _currentPosition = _stack[_stack.Count - 1];
+ _stack.RemoveAt(_stack.Count - 1);
+ }
+ else
+ {
+ _currentPosition = new JsonPosition();
+ }
+
+ return oldPosition.Type;
+ }
+
+ private JsonContainerType Peek()
+ {
+ return _currentPosition.Type;
+ }
+
+ ///
+ /// Flushes whatever is in the buffer to the destination and also flushes the destination.
+ ///
+ public abstract void Flush();
+
+ ///
+ /// Closes this writer.
+ /// If is set to true , the destination is also closed.
+ /// If is set to true , the JSON is auto-completed.
+ ///
+ public virtual void Close()
+ {
+ if (AutoCompleteOnClose)
+ {
+ AutoCompleteAll();
+ }
+ }
+
+ ///
+ /// Writes the beginning of a JSON object.
+ ///
+ public virtual void WriteStartObject()
+ {
+ InternalWriteStart(JsonToken.StartObject, JsonContainerType.Object);
+ }
+
+ ///
+ /// Writes the end of a JSON object.
+ ///
+ public virtual void WriteEndObject()
+ {
+ InternalWriteEnd(JsonContainerType.Object);
+ }
+
+ ///
+ /// Writes the beginning of a JSON array.
+ ///
+ public virtual void WriteStartArray()
+ {
+ InternalWriteStart(JsonToken.StartArray, JsonContainerType.Array);
+ }
+
+ ///
+ /// Writes the end of an array.
+ ///
+ public virtual void WriteEndArray()
+ {
+ InternalWriteEnd(JsonContainerType.Array);
+ }
+
+ ///
+ /// Writes the start of a constructor with the given name.
+ ///
+ /// The name of the constructor.
+ public virtual void WriteStartConstructor(string name)
+ {
+ InternalWriteStart(JsonToken.StartConstructor, JsonContainerType.Constructor);
+ }
+
+ ///
+ /// Writes the end constructor.
+ ///
+ public virtual void WriteEndConstructor()
+ {
+ InternalWriteEnd(JsonContainerType.Constructor);
+ }
+
+ ///
+ /// Writes the property name of a name/value pair of a JSON object.
+ ///
+ /// The name of the property.
+ public virtual void WritePropertyName(string name)
+ {
+ InternalWritePropertyName(name);
+ }
+
+ ///
+ /// Writes the property name of a name/value pair of a JSON object.
+ ///
+ /// The name of the property.
+ /// A flag to indicate whether the text should be escaped when it is written as a JSON property name.
+ public virtual void WritePropertyName(string name, bool escape)
+ {
+ WritePropertyName(name);
+ }
+
+ ///
+ /// Writes the end of the current JSON object or array.
+ ///
+ public virtual void WriteEnd()
+ {
+ WriteEnd(Peek());
+ }
+
+ ///
+ /// Writes the current token and its children.
+ ///
+ /// The to read the token from.
+ public void WriteToken(JsonReader reader)
+ {
+ WriteToken(reader, true);
+ }
+
+ ///
+ /// Writes the current token.
+ ///
+ /// The to read the token from.
+ /// A flag indicating whether the current token's children should be written.
+ public void WriteToken(JsonReader reader, bool writeChildren)
+ {
+ ValidationUtils.ArgumentNotNull(reader, nameof(reader));
+
+ WriteToken(reader, writeChildren, true, true);
+ }
+
+ ///
+ /// Writes the token and its value.
+ ///
+ /// The to write.
+ ///
+ /// The value to write.
+ /// A value is only required for tokens that have an associated value, e.g. the property name for .
+ /// null can be passed to the method for tokens that don't have a value, e.g. .
+ ///
+ public void WriteToken(JsonToken token, object? value)
+ {
+ switch (token)
+ {
+ case JsonToken.None:
+ // read to next
+ break;
+ case JsonToken.StartObject:
+ WriteStartObject();
+ break;
+ case JsonToken.StartArray:
+ WriteStartArray();
+ break;
+ case JsonToken.StartConstructor:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ WriteStartConstructor(value.ToString());
+ break;
+ case JsonToken.PropertyName:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ WritePropertyName(value.ToString());
+ break;
+ case JsonToken.Comment:
+ WriteComment(value?.ToString());
+ break;
+ case JsonToken.Integer:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+#if HAVE_BIG_INTEGER
+ if (value is BigInteger integer)
+ {
+ WriteValue(integer);
+ }
+ else
+#endif
+ {
+ WriteValue(Convert.ToInt64(value, CultureInfo.InvariantCulture));
+ }
+ break;
+ case JsonToken.Float:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ if (value is decimal decimalValue)
+ {
+ WriteValue(decimalValue);
+ }
+ else if (value is double doubleValue)
+ {
+ WriteValue(doubleValue);
+ }
+ else if (value is float floatValue)
+ {
+ WriteValue(floatValue);
+ }
+ else
+ {
+ WriteValue(Convert.ToDouble(value, CultureInfo.InvariantCulture));
+ }
+ break;
+ case JsonToken.String:
+ // Allow for a null string. This matches JTokenReader behavior which can read
+ // a JsonToken.String with a null value.
+ WriteValue(value?.ToString());
+ break;
+ case JsonToken.Boolean:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ WriteValue(Convert.ToBoolean(value, CultureInfo.InvariantCulture));
+ break;
+ case JsonToken.Null:
+ WriteNull();
+ break;
+ case JsonToken.Undefined:
+ WriteUndefined();
+ break;
+ case JsonToken.EndObject:
+ WriteEndObject();
+ break;
+ case JsonToken.EndArray:
+ WriteEndArray();
+ break;
+ case JsonToken.EndConstructor:
+ WriteEndConstructor();
+ break;
+ case JsonToken.Date:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+#if HAVE_DATE_TIME_OFFSET
+ if (value is DateTimeOffset dt)
+ {
+ WriteValue(dt);
+ }
+ else
+#endif
+ {
+ WriteValue(Convert.ToDateTime(value, CultureInfo.InvariantCulture));
+ }
+ break;
+ case JsonToken.Raw:
+ WriteRawValue(value?.ToString());
+ break;
+ case JsonToken.Bytes:
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+ if (value is Guid guid)
+ {
+ WriteValue(guid);
+ }
+ else
+ {
+ WriteValue((byte[])value!);
+ }
+ break;
+ default:
+ throw MiscellaneousUtils.CreateArgumentOutOfRangeException(nameof(token), token, "Unexpected token type.");
+ }
+ }
+
+ ///
+ /// Writes the token.
+ ///
+ /// The to write.
+ public void WriteToken(JsonToken token)
+ {
+ WriteToken(token, null);
+ }
+
+ internal virtual void WriteToken(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments)
+ {
+ int initialDepth = CalculateWriteTokenInitialDepth(reader);
+
+ do
+ {
+ // write a JValue date when the constructor is for a date
+ if (writeDateConstructorAsDate && reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal))
+ {
+ WriteConstructorDate(reader);
+ }
+ else
+ {
+ if (writeComments || reader.TokenType != JsonToken.Comment)
+ {
+ WriteToken(reader.TokenType, reader.Value);
+ }
+ }
+ } while (
+ // stop if we have reached the end of the token being read
+ initialDepth - 1 < reader.Depth - (JsonTokenUtils.IsEndToken(reader.TokenType) ? 1 : 0)
+ && writeChildren
+ && reader.Read());
+
+ if (IsWriteTokenIncomplete(reader, writeChildren, initialDepth))
+ {
+ throw JsonWriterException.Create(this, "Unexpected end when reading token.", null);
+ }
+ }
+
+ private bool IsWriteTokenIncomplete(JsonReader reader, bool writeChildren, int initialDepth)
+ {
+ int finalDepth = CalculateWriteTokenFinalDepth(reader);
+ return initialDepth < finalDepth ||
+ (writeChildren && initialDepth == finalDepth && JsonTokenUtils.IsStartToken(reader.TokenType));
+ }
+
+ private int CalculateWriteTokenInitialDepth(JsonReader reader)
+ {
+ JsonToken type = reader.TokenType;
+ if (type == JsonToken.None)
+ {
+ return -1;
+ }
+
+ return JsonTokenUtils.IsStartToken(type) ? reader.Depth : reader.Depth + 1;
+ }
+
+ private int CalculateWriteTokenFinalDepth(JsonReader reader)
+ {
+ JsonToken type = reader.TokenType;
+ if (type == JsonToken.None)
+ {
+ return -1;
+ }
+
+ return JsonTokenUtils.IsEndToken(type) ? reader.Depth - 1 : reader.Depth;
+ }
+
+ private void WriteConstructorDate(JsonReader reader)
+ {
+ if (!JavaScriptUtils.TryGetDateFromConstructorJson(reader, out DateTime dateTime, out string? errorMessage))
+ {
+ throw JsonWriterException.Create(this, errorMessage, null);
+ }
+
+ WriteValue(dateTime);
+ }
+
+ private void WriteEnd(JsonContainerType type)
+ {
+ switch (type)
+ {
+ case JsonContainerType.Object:
+ WriteEndObject();
+ break;
+ case JsonContainerType.Array:
+ WriteEndArray();
+ break;
+ case JsonContainerType.Constructor:
+ WriteEndConstructor();
+ break;
+ default:
+ throw JsonWriterException.Create(this, "Unexpected type when writing end: " + type, null);
+ }
+ }
+
+ private void AutoCompleteAll()
+ {
+ while (Top > 0)
+ {
+ WriteEnd();
+ }
+ }
+
+ private JsonToken GetCloseTokenForType(JsonContainerType type)
+ {
+ switch (type)
+ {
+ case JsonContainerType.Object:
+ return JsonToken.EndObject;
+ case JsonContainerType.Array:
+ return JsonToken.EndArray;
+ case JsonContainerType.Constructor:
+ return JsonToken.EndConstructor;
+ default:
+ throw JsonWriterException.Create(this, "No close token for type: " + type, null);
+ }
+ }
+
+ private void AutoCompleteClose(JsonContainerType type)
+ {
+ int levelsToComplete = CalculateLevelsToComplete(type);
+
+ for (int i = 0; i < levelsToComplete; i++)
+ {
+ JsonToken token = GetCloseTokenForType(Pop());
+
+ if (_currentState == State.Property)
+ {
+ WriteNull();
+ }
+
+ if (_formatting == Formatting.Indented)
+ {
+ if (_currentState != State.ObjectStart && _currentState != State.ArrayStart)
+ {
+ WriteIndent();
+ }
+ }
+
+ WriteEnd(token);
+
+ UpdateCurrentState();
+ }
+ }
+
+ private int CalculateLevelsToComplete(JsonContainerType type)
+ {
+ int levelsToComplete = 0;
+
+ if (_currentPosition.Type == type)
+ {
+ levelsToComplete = 1;
+ }
+ else
+ {
+ int top = Top - 2;
+ for (int i = top; i >= 0; i--)
+ {
+ int currentLevel = top - i;
+
+ if (_stack![currentLevel].Type == type)
+ {
+ levelsToComplete = i + 2;
+ break;
+ }
+ }
+ }
+
+ if (levelsToComplete == 0)
+ {
+ throw JsonWriterException.Create(this, "No token to close.", null);
+ }
+
+ return levelsToComplete;
+ }
+
+ private void UpdateCurrentState()
+ {
+ JsonContainerType currentLevelType = Peek();
+
+ switch (currentLevelType)
+ {
+ case JsonContainerType.Object:
+ _currentState = State.Object;
+ break;
+ case JsonContainerType.Array:
+ _currentState = State.Array;
+ break;
+ case JsonContainerType.Constructor:
+ _currentState = State.Array;
+ break;
+ case JsonContainerType.None:
+ _currentState = State.Start;
+ break;
+ default:
+ throw JsonWriterException.Create(this, "Unknown JsonType: " + currentLevelType, null);
+ }
+ }
+
+ ///
+ /// Writes the specified end token.
+ ///
+ /// The end token to write.
+ protected virtual void WriteEnd(JsonToken token)
+ {
+ }
+
+ ///
+ /// Writes indent characters.
+ ///
+ protected virtual void WriteIndent()
+ {
+ }
+
+ ///
+ /// Writes the JSON value delimiter.
+ ///
+ protected virtual void WriteValueDelimiter()
+ {
+ }
+
+ ///
+ /// Writes an indent space.
+ ///
+ protected virtual void WriteIndentSpace()
+ {
+ }
+
+ internal void AutoComplete(JsonToken tokenBeingWritten)
+ {
+ // gets new state based on the current state and what is being written
+ State newState = StateArray[(int)tokenBeingWritten][(int)_currentState];
+
+ if (newState == State.Error)
+ {
+ throw JsonWriterException.Create(this, "Token {0} in state {1} would result in an invalid JSON object.".FormatWith(CultureInfo.InvariantCulture, tokenBeingWritten.ToString(), _currentState.ToString()), null);
+ }
+
+ if ((_currentState == State.Object || _currentState == State.Array || _currentState == State.Constructor) && tokenBeingWritten != JsonToken.Comment)
+ {
+ WriteValueDelimiter();
+ }
+
+ if (_formatting == Formatting.Indented)
+ {
+ if (_currentState == State.Property)
+ {
+ WriteIndentSpace();
+ }
+
+ // don't indent a property when it is the first token to be written (i.e. at the start)
+ if ((_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.Constructor || _currentState == State.ConstructorStart)
+ || (tokenBeingWritten == JsonToken.PropertyName && _currentState != State.Start))
+ {
+ WriteIndent();
+ }
+ }
+
+ _currentState = newState;
+ }
+
+ #region WriteValue methods
+ ///
+ /// Writes a null value.
+ ///
+ public virtual void WriteNull()
+ {
+ InternalWriteValue(JsonToken.Null);
+ }
+
+ ///
+ /// Writes an undefined value.
+ ///
+ public virtual void WriteUndefined()
+ {
+ InternalWriteValue(JsonToken.Undefined);
+ }
+
+ ///
+ /// Writes raw JSON without changing the writer's state.
+ ///
+ /// The raw JSON to write.
+ public virtual void WriteRaw(string? json)
+ {
+ InternalWriteRaw();
+ }
+
+ ///
+ /// Writes raw JSON where a value is expected and updates the writer's state.
+ ///
+ /// The raw JSON to write.
+ public virtual void WriteRawValue(string? json)
+ {
+ // hack. want writer to change state as if a value had been written
+ UpdateScopeWithFinishedValue();
+ AutoComplete(JsonToken.Undefined);
+ WriteRaw(json);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(string? value)
+ {
+ InternalWriteValue(JsonToken.String);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(int value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public virtual void WriteValue(uint value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(long value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public virtual void WriteValue(ulong value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(float value)
+ {
+ InternalWriteValue(JsonToken.Float);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(double value)
+ {
+ InternalWriteValue(JsonToken.Float);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(bool value)
+ {
+ InternalWriteValue(JsonToken.Boolean);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(short value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public virtual void WriteValue(ushort value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(char value)
+ {
+ InternalWriteValue(JsonToken.String);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(byte value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ [CLSCompliant(false)]
+ public virtual void WriteValue(sbyte value)
+ {
+ InternalWriteValue(JsonToken.Integer);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(decimal value)
+ {
+ InternalWriteValue(JsonToken.Float);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(DateTime value)
+ {
+ InternalWriteValue(JsonToken.Date);
+ }
+
+#if HAVE_DATE_TIME_OFFSET
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(DateTimeOffset value)
+ {
+ InternalWriteValue(JsonToken.Date);
+ }
+#endif
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(Guid value)
+ {
+ InternalWriteValue(JsonToken.String);
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(TimeSpan value)
+ {
+ InternalWriteValue(JsonToken.String);
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(int? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ [CLSCompliant(false)]
+ public virtual void WriteValue(uint? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(long? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ [CLSCompliant(false)]
+ public virtual void WriteValue(ulong? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(float? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(double? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(bool? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(short? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ [CLSCompliant(false)]
+ public virtual void WriteValue(ushort? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(char? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(byte? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ [CLSCompliant(false)]
+ public virtual void WriteValue(sbyte? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(decimal? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(DateTime? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+#if HAVE_DATE_TIME_OFFSET
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(DateTimeOffset? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+#endif
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(Guid? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a of value.
+ ///
+ /// The of value to write.
+ public virtual void WriteValue(TimeSpan? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ WriteValue(value.GetValueOrDefault());
+ }
+ }
+
+ ///
+ /// Writes a [] value.
+ ///
+ /// The [] value to write.
+ public virtual void WriteValue(byte[]? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ InternalWriteValue(JsonToken.Bytes);
+ }
+ }
+
+ ///
+ /// Writes a value.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(Uri? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ InternalWriteValue(JsonToken.String);
+ }
+ }
+
+ ///
+ /// Writes a value.
+ /// An error will raised if the value cannot be written as a single JSON token.
+ ///
+ /// The value to write.
+ public virtual void WriteValue(object? value)
+ {
+ if (value == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+#if HAVE_BIG_INTEGER
+ // this is here because adding a WriteValue(BigInteger) to JsonWriter will
+ // mean the user has to add a reference to System.Numerics.dll
+ if (value is BigInteger)
+ {
+ throw CreateUnsupportedTypeException(this, value);
+ }
+#endif
+
+ WriteValue(this, ConvertUtils.GetTypeCode(value.GetType()), value);
+ }
+ }
+ #endregion
+
+ ///
+ /// Writes a comment /*...*/ containing the specified text.
+ ///
+ /// Text to place inside the comment.
+ public virtual void WriteComment(string? text)
+ {
+ InternalWriteComment();
+ }
+
+ ///
+ /// Writes the given white space.
+ ///
+ /// The string of white space characters.
+ public virtual void WriteWhitespace(string ws)
+ {
+ InternalWriteWhitespace(ws);
+ }
+
+ void IDisposable.Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources.
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_currentState != State.Closed && disposing)
+ {
+ Close();
+ }
+ }
+
+ internal static void WriteValue(JsonWriter writer, PrimitiveTypeCode typeCode, object value)
+ {
+ while (true)
+ {
+ switch (typeCode)
+ {
+ case PrimitiveTypeCode.Char:
+ writer.WriteValue((char)value);
+ return;
+
+ case PrimitiveTypeCode.CharNullable:
+ writer.WriteValue((value == null) ? (char?)null : (char)value);
+ return;
+
+ case PrimitiveTypeCode.Boolean:
+ writer.WriteValue((bool)value);
+ return;
+
+ case PrimitiveTypeCode.BooleanNullable:
+ writer.WriteValue((value == null) ? (bool?)null : (bool)value);
+ return;
+
+ case PrimitiveTypeCode.SByte:
+ writer.WriteValue((sbyte)value);
+ return;
+
+ case PrimitiveTypeCode.SByteNullable:
+ writer.WriteValue((value == null) ? (sbyte?)null : (sbyte)value);
+ return;
+
+ case PrimitiveTypeCode.Int16:
+ writer.WriteValue((short)value);
+ return;
+
+ case PrimitiveTypeCode.Int16Nullable:
+ writer.WriteValue((value == null) ? (short?)null : (short)value);
+ return;
+
+ case PrimitiveTypeCode.UInt16:
+ writer.WriteValue((ushort)value);
+ return;
+
+ case PrimitiveTypeCode.UInt16Nullable:
+ writer.WriteValue((value == null) ? (ushort?)null : (ushort)value);
+ return;
+
+ case PrimitiveTypeCode.Int32:
+ writer.WriteValue((int)value);
+ return;
+
+ case PrimitiveTypeCode.Int32Nullable:
+ writer.WriteValue((value == null) ? (int?)null : (int)value);
+ return;
+
+ case PrimitiveTypeCode.Byte:
+ writer.WriteValue((byte)value);
+ return;
+
+ case PrimitiveTypeCode.ByteNullable:
+ writer.WriteValue((value == null) ? (byte?)null : (byte)value);
+ return;
+
+ case PrimitiveTypeCode.UInt32:
+ writer.WriteValue((uint)value);
+ return;
+
+ case PrimitiveTypeCode.UInt32Nullable:
+ writer.WriteValue((value == null) ? (uint?)null : (uint)value);
+ return;
+
+ case PrimitiveTypeCode.Int64:
+ writer.WriteValue((long)value);
+ return;
+
+ case PrimitiveTypeCode.Int64Nullable:
+ writer.WriteValue((value == null) ? (long?)null : (long)value);
+ return;
+
+ case PrimitiveTypeCode.UInt64:
+ writer.WriteValue((ulong)value);
+ return;
+
+ case PrimitiveTypeCode.UInt64Nullable:
+ writer.WriteValue((value == null) ? (ulong?)null : (ulong)value);
+ return;
+
+ case PrimitiveTypeCode.Single:
+ writer.WriteValue((float)value);
+ return;
+
+ case PrimitiveTypeCode.SingleNullable:
+ writer.WriteValue((value == null) ? (float?)null : (float)value);
+ return;
+
+ case PrimitiveTypeCode.Double:
+ writer.WriteValue((double)value);
+ return;
+
+ case PrimitiveTypeCode.DoubleNullable:
+ writer.WriteValue((value == null) ? (double?)null : (double)value);
+ return;
+
+ case PrimitiveTypeCode.DateTime:
+ writer.WriteValue((DateTime)value);
+ return;
+
+ case PrimitiveTypeCode.DateTimeNullable:
+ writer.WriteValue((value == null) ? (DateTime?)null : (DateTime)value);
+ return;
+
+#if HAVE_DATE_TIME_OFFSET
+ case PrimitiveTypeCode.DateTimeOffset:
+ writer.WriteValue((DateTimeOffset)value);
+ return;
+
+ case PrimitiveTypeCode.DateTimeOffsetNullable:
+ writer.WriteValue((value == null) ? (DateTimeOffset?)null : (DateTimeOffset)value);
+ return;
+#endif
+ case PrimitiveTypeCode.Decimal:
+ writer.WriteValue((decimal)value);
+ return;
+
+ case PrimitiveTypeCode.DecimalNullable:
+ writer.WriteValue((value == null) ? (decimal?)null : (decimal)value);
+ return;
+
+ case PrimitiveTypeCode.Guid:
+ writer.WriteValue((Guid)value);
+ return;
+
+ case PrimitiveTypeCode.GuidNullable:
+ writer.WriteValue((value == null) ? (Guid?)null : (Guid)value);
+ return;
+
+ case PrimitiveTypeCode.TimeSpan:
+ writer.WriteValue((TimeSpan)value);
+ return;
+
+ case PrimitiveTypeCode.TimeSpanNullable:
+ writer.WriteValue((value == null) ? (TimeSpan?)null : (TimeSpan)value);
+ return;
+
+#if HAVE_BIG_INTEGER
+ case PrimitiveTypeCode.BigInteger:
+ // this will call to WriteValue(object)
+ writer.WriteValue((BigInteger)value);
+ return;
+
+ case PrimitiveTypeCode.BigIntegerNullable:
+ // this will call to WriteValue(object)
+ writer.WriteValue((value == null) ? (BigInteger?)null : (BigInteger)value);
+ return;
+#endif
+ case PrimitiveTypeCode.Uri:
+ writer.WriteValue((Uri)value);
+ return;
+
+ case PrimitiveTypeCode.String:
+ writer.WriteValue((string)value);
+ return;
+
+ case PrimitiveTypeCode.Bytes:
+ writer.WriteValue((byte[])value);
+ return;
+
+#if HAVE_DB_NULL_TYPE_CODE
+ case PrimitiveTypeCode.DBNull:
+ writer.WriteNull();
+ return;
+#endif
+ default:
+#if HAVE_ICONVERTIBLE
+ if (value is IConvertible convertible)
+ {
+ ResolveConvertibleValue(convertible, out typeCode, out value);
+ continue;
+ }
+#endif
+
+ // write an unknown null value, fix https://github.com/JamesNK/Newtonsoft.Json/issues/1460
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ throw CreateUnsupportedTypeException(writer, value);
+ }
+ }
+ }
+
+#if HAVE_ICONVERTIBLE
+ private static void ResolveConvertibleValue(IConvertible convertible, out PrimitiveTypeCode typeCode, out object value)
+ {
+ // the value is a non-standard IConvertible
+ // convert to the underlying value and retry
+ TypeInformation typeInformation = ConvertUtils.GetTypeInformation(convertible);
+
+ // if convertible has an underlying typecode of Object then attempt to convert it to a string
+ typeCode = typeInformation.TypeCode == PrimitiveTypeCode.Object ? PrimitiveTypeCode.String : typeInformation.TypeCode;
+ Type resolvedType = typeInformation.TypeCode == PrimitiveTypeCode.Object ? typeof(string) : typeInformation.Type;
+ value = convertible.ToType(resolvedType, CultureInfo.InvariantCulture);
+ }
+#endif
+
+ private static JsonWriterException CreateUnsupportedTypeException(JsonWriter writer, object value)
+ {
+ return JsonWriterException.Create(writer, "Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType()), null);
+ }
+
+ ///
+ /// Sets the state of the .
+ ///
+ /// The being written.
+ /// The value being written.
+ protected void SetWriteState(JsonToken token, object value)
+ {
+ switch (token)
+ {
+ case JsonToken.StartObject:
+ InternalWriteStart(token, JsonContainerType.Object);
+ break;
+ case JsonToken.StartArray:
+ InternalWriteStart(token, JsonContainerType.Array);
+ break;
+ case JsonToken.StartConstructor:
+ InternalWriteStart(token, JsonContainerType.Constructor);
+ break;
+ case JsonToken.PropertyName:
+ if (!(value is string s))
+ {
+ throw new ArgumentException("A name is required when setting property name state.", nameof(value));
+ }
+
+ InternalWritePropertyName(s);
+ break;
+ case JsonToken.Comment:
+ InternalWriteComment();
+ break;
+ case JsonToken.Raw:
+ InternalWriteRaw();
+ break;
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ case JsonToken.String:
+ case JsonToken.Boolean:
+ case JsonToken.Date:
+ case JsonToken.Bytes:
+ case JsonToken.Null:
+ case JsonToken.Undefined:
+ InternalWriteValue(token);
+ break;
+ case JsonToken.EndObject:
+ InternalWriteEnd(JsonContainerType.Object);
+ break;
+ case JsonToken.EndArray:
+ InternalWriteEnd(JsonContainerType.Array);
+ break;
+ case JsonToken.EndConstructor:
+ InternalWriteEnd(JsonContainerType.Constructor);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(token));
+ }
+ }
+
+ internal void InternalWriteEnd(JsonContainerType container)
+ {
+ AutoCompleteClose(container);
+ }
+
+ internal void InternalWritePropertyName(string name)
+ {
+ _currentPosition.PropertyName = name;
+ AutoComplete(JsonToken.PropertyName);
+ }
+
+ internal void InternalWriteRaw()
+ {
+ }
+
+ internal void InternalWriteStart(JsonToken token, JsonContainerType container)
+ {
+ UpdateScopeWithFinishedValue();
+ AutoComplete(token);
+ Push(container);
+ }
+
+ internal void InternalWriteValue(JsonToken token)
+ {
+ UpdateScopeWithFinishedValue();
+ AutoComplete(token);
+ }
+
+ internal void InternalWriteWhitespace(string ws)
+ {
+ if (ws != null)
+ {
+ if (!StringUtils.IsWhiteSpace(ws))
+ {
+ throw JsonWriterException.Create(this, "Only white space characters should be used.", null);
+ }
+ }
+ }
+
+ internal void InternalWriteComment()
+ {
+ AutoComplete(JsonToken.Comment);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/JsonWriterException.cs b/Libs/Newtonsoft.Json.AOT/JsonWriterException.cs
new file mode 100644
index 0000000..a2c8d34
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/JsonWriterException.cs
@@ -0,0 +1,114 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace LC.Newtonsoft.Json
+{
+ ///
+ /// The exception thrown when an error occurs while writing JSON text.
+ ///
+#if HAVE_BINARY_EXCEPTION_SERIALIZATION
+ [Serializable]
+#endif
+ public class JsonWriterException : JsonException
+ {
+ ///
+ /// Gets the path to the JSON where the error occurred.
+ ///
+ /// The path to the JSON where the error occurred.
+ public string? Path { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public JsonWriterException()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message.
+ ///
+ /// The error message that explains the reason for the exception.
+ public JsonWriterException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The error message that explains the reason for the exception.
+ /// The exception that is the cause of the current exception, or null if no inner exception is specified.
+ public JsonWriterException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+#if HAVE_BINARY_EXCEPTION_SERIALIZATION
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The that holds the serialized object data about the exception being thrown.
+ /// The that contains contextual information about the source or destination.
+ /// The parameter is null .
+ /// The class name is null or is zero (0).
+ public JsonWriterException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+#endif
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message, JSON path and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The error message that explains the reason for the exception.
+ /// The path to the JSON where the error occurred.
+ /// The exception that is the cause of the current exception, or null if no inner exception is specified.
+ public JsonWriterException(string message, string path, Exception? innerException)
+ : base(message, innerException)
+ {
+ Path = path;
+ }
+
+ internal static JsonWriterException Create(JsonWriter writer, string message, Exception? ex)
+ {
+ return Create(writer.ContainerPath, message, ex);
+ }
+
+ internal static JsonWriterException Create(string path, string message, Exception? ex)
+ {
+ message = JsonPosition.FormatMessage(null, path, message);
+
+ return new JsonWriterException(message, path, ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/LC.Newtonsoft.Json.AOT.csproj b/Libs/Newtonsoft.Json.AOT/LC.Newtonsoft.Json.AOT.csproj
new file mode 100644
index 0000000..4703b3c
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/LC.Newtonsoft.Json.AOT.csproj
@@ -0,0 +1,81 @@
+
+
+ AOT
+ netstandard2.0
+ $(LibraryFrameworks)
+ 9.0
+
+ 11.0.0.0
+ 11.0.1
+ 11.0.1
+ beta2
+ James Newton-King
+ Newtonsoft
+ Json.NET
+ Json.NET is a popular high-performance JSON framework for .NET
+ Copyright © James Newton-King 2008
+ Json.NET is a popular high-performance JSON framework for .NET
+ en-US
+ Json.NET for Unity
+ LC.Newtonsoft.Json
+ json
+ packageIcon.png
+ $(MSBuildThisFileDirectory)packageIcon.png
+ https://www.newtonsoft.com/json
+ MIT
+ true
+ LC.Newtonsoft.Json
+ LC.Newtonsoft.Json
+ true
+ enable
+ 2.12
+
+ Full
+
+ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
+ false
+ 0.7.1
+
+
+
+
+ Newtonsoft.Json.xml
+
+
+
+
+
+
+
+
+
+ net46
+ Json.NET for Unity tests (NOT FOR PRODUCTION)
+ DEBUG;NET45;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_CONCURRENT_DICTIONARY;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;$(AdditionalConstants)
+ bin\$(Configuration)\unity-tests
+
+
+
+ netstandard2.0
+ Json.NET for Unity Editor (NOT FOR PRODUCTION)
+ NETSTANDARD2_0;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_CONCURRENT_DICTIONARY;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;$(AdditionalConstants)
+ bin\$(Configuration)\unity-editor
+
+
+
+ netstandard2.0
+ Json.NET for Unity standalone (Win, OS X, Linux)
+ NETSTANDARD2_0;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_BIG_INTEGER;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_FAST_REVERSE;HAVE_FULL_REFLECTION;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;$(AdditionalConstants)
+ bin\$(Configuration)\unity-standalone
+
+
+
+ netstandard2.0
+ Json.NET for Unity AOT (IL2CPP)
+ NETSTANDARD2_0;UNITY_LTS;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_CONCURRENT_DICTIONARY;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;$(AdditionalConstants)
+ bin\$(Configuration)\unity-aot
+
+
+ NETSTANDARD2_0;UNITY_LTS;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_CONCURRENT_DICTIONARY;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;$(AdditionalConstants)
+
+
diff --git a/Libs/Newtonsoft.Json.AOT/Linq/CommentHandling.cs b/Libs/Newtonsoft.Json.AOT/Linq/CommentHandling.cs
new file mode 100644
index 0000000..c849d8f
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Linq/CommentHandling.cs
@@ -0,0 +1,43 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+namespace LC.Newtonsoft.Json.Linq
+{
+ ///
+ /// Specifies how JSON comments are handled when loading JSON.
+ ///
+ public enum CommentHandling
+ {
+ ///
+ /// Ignore comments.
+ ///
+ Ignore = 0,
+
+ ///
+ /// Load comments as a with type .
+ ///
+ Load = 1
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Linq/DuplicatePropertyNameHandling.cs b/Libs/Newtonsoft.Json.AOT/Linq/DuplicatePropertyNameHandling.cs
new file mode 100644
index 0000000..14c3232
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Linq/DuplicatePropertyNameHandling.cs
@@ -0,0 +1,46 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+namespace LC.Newtonsoft.Json.Linq
+{
+ ///
+ /// Specifies how duplicate property names are handled when loading JSON.
+ ///
+ public enum DuplicatePropertyNameHandling
+ {
+ ///
+ /// Replace the existing value when there is a duplicate property. The value of the last property in the JSON object will be used.
+ ///
+ Replace = 0,
+ ///
+ /// Ignore the new value when there is a duplicate property. The value of the first property in the JSON object will be used.
+ ///
+ Ignore = 1,
+ ///
+ /// Throw a when a duplicate property is encountered.
+ ///
+ Error = 2
+ }
+}
\ No newline at end of file
diff --git a/Libs/Newtonsoft.Json.AOT/Linq/Extensions.cs b/Libs/Newtonsoft.Json.AOT/Linq/Extensions.cs
new file mode 100644
index 0000000..e401a5c
--- /dev/null
+++ b/Libs/Newtonsoft.Json.AOT/Linq/Extensions.cs
@@ -0,0 +1,336 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using LC.Newtonsoft.Json.Utilities;
+using System.Globalization;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+#if !HAVE_LINQ
+using LC.Newtonsoft.Json.Utilities.LinqBridge;
+#else
+using System.Linq;
+
+#endif
+
+namespace LC.Newtonsoft.Json.Linq
+{
+ ///
+ /// Contains the LINQ to JSON extension methods.
+ ///
+ public static class Extensions
+ {
+ ///
+ /// Returns a collection of tokens that contains the ancestors of every token in the source collection.
+ ///
+ /// The type of the objects in source, constrained to .
+ /// An of that contains the source collection.
+ /// An of that contains the ancestors of every token in the source collection.
+ public static IJEnumerable Ancestors(this IEnumerable source) where T : JToken
+ {
+ ValidationUtils.ArgumentNotNull(source, nameof(source));
+
+ return source.SelectMany(j => j.Ancestors()).AsJEnumerable();
+ }
+
+ ///
+ /// Returns a collection of tokens that contains every token in the source collection, and the ancestors of every token in the source collection.
+ ///
+ /// The type of the objects in source, constrained to .
+ /// An of that contains the source collection.
+ /// An of that contains every token in the source collection, the ancestors of every token in the source collection.
+ public static IJEnumerable AncestorsAndSelf(this IEnumerable source) where T : JToken
+ {
+ ValidationUtils.ArgumentNotNull(source, nameof(source));
+
+ return source.SelectMany(j => j.AncestorsAndSelf()).AsJEnumerable();
+ }
+
+ ///
+ /// Returns a collection of tokens that contains the descendants of every token in the source collection.
+ ///
+ /// The type of the objects in source, constrained to .
+ /// An of that contains the source collection.
+ /// An of that contains the descendants of every token in the source collection.
+ public static IJEnumerable Descendants(this IEnumerable source) where T : JContainer
+ {
+ ValidationUtils.ArgumentNotNull(source, nameof(source));
+
+ return source.SelectMany(j => j.Descendants()).AsJEnumerable();
+ }
+
+ ///
+ /// Returns a collection of tokens that contains every token in the source collection, and the descendants of every token in the source collection.
+ ///
+ /// The type of the objects in source, constrained to .
+ /// An of that contains the source collection.
+ /// An of that contains every token in the source collection, and the descendants of every token in the source collection.
+ public static IJEnumerable DescendantsAndSelf(this IEnumerable source) where T : JContainer
+ {
+ ValidationUtils.ArgumentNotNull(source, nameof(source));
+
+ return source.SelectMany(j => j.DescendantsAndSelf()).AsJEnumerable();
+ }
+
+ ///
+ /// Returns a collection of child properties of every object in the source collection.
+ ///
+ /// An of that contains the source collection.
+ /// An of that contains the properties of every object in the source collection.
+ public static IJEnumerable Properties(this IEnumerable source)
+ {
+ ValidationUtils.ArgumentNotNull(source, nameof(source));
+
+ return source.SelectMany(d => d.Properties()).AsJEnumerable();
+ }
+
+ ///
+ /// Returns a collection of child values of every object in the source collection with the given key.
+ ///
+ /// An of that contains the source collection.
+ /// The token key.
+ /// An of that contains the values of every token in the source collection with the given key.
+ public static IJEnumerable Values(this IEnumerable source, object? key)
+ {
+ return Values(source, key)!.AsJEnumerable();
+ }
+
+ ///
+ /// Returns a collection of child values of every object in the source collection.
+ ///
+ /// An of that contains the source collection.
+ /// An of that contains the values of every token in the source collection.
+ public static IJEnumerable Values(this IEnumerable source)
+ {
+ return source.Values(null);
+ }
+
+ ///
+ /// Returns a collection of converted child values of every object in the source collection with the given key.
+ ///
+ /// The type to convert the values to.
+ /// An of that contains the source collection.
+ /// The token key.
+ /// An that contains the converted values of every token in the source collection with the given key.
+ public static IEnumerable Values(this IEnumerable source, object key)
+ {
+ return Values(source, key);
+ }
+
+ ///
+ /// Returns a collection of converted child values of every object in the source collection.
+ ///
+ /// The type to convert the values to.
+ /// An of that contains the source collection.
+ /// An that contains the converted values of every token in the source collection.
+ public static IEnumerable Values(this IEnumerable source)
+ {
+ return Values(source, null);
+ }
+
+ ///
+ /// Converts the value.
+ ///
+ /// The type to convert the value to.
+ /// A cast as a of .
+ /// A converted value.
+ public static U? Value(this IEnumerable value)
+ {
+ return value.Value();
+ }
+
+ ///
+ /// Converts the value.
+ ///
+ /// The source collection type.
+ /// The type to convert the value to.
+ /// A cast as a of .
+ /// A converted value.
+ public static U? Value(this IEnumerable value) where T : JToken
+ {
+ ValidationUtils.ArgumentNotNull(value, nameof(value));
+
+ if (!(value is JToken token))
+ {
+ throw new ArgumentException("Source value must be a JToken.");
+ }
+
+ return token.Convert();
+ }
+
+ internal static IEnumerable Values(this IEnumerable source, object? key) where T : JToken
+ {
+ ValidationUtils.ArgumentNotNull(source, nameof(source));
+
+ if (key == null)
+ {
+ foreach (T token in source)
+ {
+ if (token is JValue value)
+ {
+ yield return Convert(value);
+ }
+ else
+ {
+ foreach (JToken t in token.Children())
+ {
+ yield return t.Convert();
+ }
+ }
+ }
+ }
+ else
+ {
+ foreach (T token in source)
+ {
+ JToken? value = token[key];
+ if (value != null)
+ {
+ yield return value.Convert();
+ }
+ }
+ }
+ }
+
+ //TODO
+ //public static IEnumerable InDocumentOrder(this IEnumerable source) where T : JObject;
+
+ ///
+ /// Returns a collection of child tokens of every array in the source collection.
+ ///
+ /// The source collection type.
+ /// An of that contains the source collection.
+ /// An of that contains the values of every token in the source collection.
+ public static IJEnumerable Children(this IEnumerable source) where T : JToken
+ {
+ return Children(source)!.AsJEnumerable();
+ }
+
+ ///
+ /// Returns a collection of converted child tokens of every array in the source collection.
+ ///
+ /// An of that contains the source collection.
+ /// The type to convert the values to.
+ /// The source collection type.
+ /// An that contains the converted values of every token in the source collection.
+ public static IEnumerable Children(this IEnumerable source) where T : JToken
+ {
+ ValidationUtils.ArgumentNotNull(source, nameof(source));
+
+ return source.SelectMany(c => c.Children()).Convert();
+ }
+
+ internal static IEnumerable Convert(this IEnumerable source) where T : JToken
+ {
+ ValidationUtils.ArgumentNotNull(source, nameof(source));
+
+ foreach (T token in source)
+ {
+ yield return Convert(token);
+ }
+ }
+
+ internal static U? Convert(this T token) where T : JToken?
+ {
+ if (token == null)
+ {
+#pragma warning disable CS8653 // A default expression introduces a null value for a type parameter.
+ return default;
+#pragma warning restore CS8653 // A default expression introduces a null value for a type parameter.
+ }
+
+ if (token is U castValue
+ // don't want to cast JValue to its interfaces, want to get the internal value
+ && typeof(U) != typeof(IComparable) && typeof(U) != typeof(IFormattable))
+ {
+ return castValue;
+ }
+ else
+ {
+ if (!(token is JValue value))
+ {
+ throw new InvalidCastException("Cannot cast {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, token.GetType(), typeof(T)));
+ }
+
+ if (value.Value is U u)
+ {
+ return u;
+ }
+
+ Type targetType = typeof(U);
+
+ if (ReflectionUtils.IsNullableType(targetType))
+ {
+ if (value.Value == null)
+ {
+#pragma warning disable CS8653 // A default expression introduces a null value for a type parameter.
+ return default;
+#pragma warning restore CS8653 // A default expression introduces a null value for a type parameter.
+ }
+
+ targetType = Nullable.GetUnderlyingType(targetType);
+ }
+
+ return (U)System.Convert.ChangeType(value.Value, targetType, CultureInfo.InvariantCulture);
+ }
+ }
+
+ //TODO
+ //public static void Remove(this IEnumerable source) where T : JContainer;
+
+ ///