chore: Newtonsoft.Json.AOT
parent
c14ac61e59
commit
34955cd95b
|
@ -0,0 +1,47 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<ReleaseVersion>0.7.1</ReleaseVersion>
|
||||||
|
<AssemblyName>Common</AssemblyName>
|
||||||
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Libs\Newtonsoft.Json.AOT\LC.Newtonsoft.Json.AOT.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\Common\Common.csproj">
|
||||||
|
<Link>Common\Common.csproj</Link>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\Common\AppRouter\LCAppServer.cs">
|
||||||
|
<Link>Common\AppRouter\LCAppServer.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Common\AppRouter\LCAppRouter.cs">
|
||||||
|
<Link>Common\AppRouter\LCAppRouter.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Common\Json\LCJsonConverter.cs">
|
||||||
|
<Link>Common\Json\LCJsonConverter.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Common\Json\LCJsonUtils.cs">
|
||||||
|
<Link>Common\Json\LCJsonUtils.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Common\Http\LCHttpUtils.cs">
|
||||||
|
<Link>Common\Http\LCHttpUtils.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Common\Task\LCTaskExtensions.cs">
|
||||||
|
<Link>Common\Task\LCTaskExtensions.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Common\Log\LCLogger.cs">
|
||||||
|
<Link>Common\Log\LCLogger.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Common\Log\LCLogLevel.cs">
|
||||||
|
<Link>Common\Log\LCLogLevel.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Common\Exception\LCException.cs">
|
||||||
|
<Link>Common\Exception\LCException.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a BSON Oid (object id).
|
||||||
|
/// </summary>
|
||||||
|
[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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value of the Oid.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The value of the Oid.</value>
|
||||||
|
public byte[] Value { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BsonObjectId"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The Oid value.</param>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a reader that provides fast, non-cached, forward-only access to serialized BSON data.
|
||||||
|
/// </summary>
|
||||||
|
[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<ContainerContext> _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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether binary data reading should be compatible with incorrect Json.NET 3.5 written binary.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if binary data reading will be compatible with incorrect Json.NET 3.5 written binary; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
[Obsolete("JsonNet35BinaryCompatibility will be removed in a future version of Json.NET.")]
|
||||||
|
public bool JsonNet35BinaryCompatibility
|
||||||
|
{
|
||||||
|
get => _jsonNet35BinaryCompatibility;
|
||||||
|
set => _jsonNet35BinaryCompatibility = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether the root object will be read as a JSON array.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if the root object will be read as a JSON array; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
public bool ReadRootValueAsArray
|
||||||
|
{
|
||||||
|
get => _readRootValueAsArray;
|
||||||
|
set => _readRootValueAsArray = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</value>
|
||||||
|
public DateTimeKind DateTimeKindHandling
|
||||||
|
{
|
||||||
|
get => _dateTimeKindHandling;
|
||||||
|
set => _dateTimeKindHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BsonReader"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The <see cref="Stream"/> containing the BSON data to read.</param>
|
||||||
|
public BsonReader(Stream stream)
|
||||||
|
: this(stream, false, DateTimeKind.Local)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BsonReader"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="BinaryReader"/> containing the BSON data to read.</param>
|
||||||
|
public BsonReader(BinaryReader reader)
|
||||||
|
: this(reader, false, DateTimeKind.Local)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BsonReader"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The <see cref="Stream"/> containing the BSON data to read.</param>
|
||||||
|
/// <param name="readRootValueAsArray">if set to <c>true</c> the root object will be read as a JSON array.</param>
|
||||||
|
/// <param name="dateTimeKindHandling">The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</param>
|
||||||
|
public BsonReader(Stream stream, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(stream, nameof(stream));
|
||||||
|
_reader = new BinaryReader(stream);
|
||||||
|
_stack = new List<ContainerContext>();
|
||||||
|
_readRootValueAsArray = readRootValueAsArray;
|
||||||
|
_dateTimeKindHandling = dateTimeKindHandling;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BsonReader"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="BinaryReader"/> containing the BSON data to read.</param>
|
||||||
|
/// <param name="readRootValueAsArray">if set to <c>true</c> the root object will be read as a JSON array.</param>
|
||||||
|
/// <param name="dateTimeKindHandling">The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</param>
|
||||||
|
public BsonReader(BinaryReader reader, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(reader, nameof(reader));
|
||||||
|
_reader = reader;
|
||||||
|
_stack = new List<ContainerContext>();
|
||||||
|
_readRootValueAsArray = readRootValueAsArray;
|
||||||
|
_dateTimeKindHandling = dateTimeKindHandling;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ReadElement()
|
||||||
|
{
|
||||||
|
_currentElementType = ReadType();
|
||||||
|
string elementName = ReadString();
|
||||||
|
return elementName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the next JSON token from the underlying <see cref="Stream"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if the next token was read successfully; <c>false</c> if there are no more tokens to read.
|
||||||
|
/// </returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the reader's state to <see cref="JsonReader.State.Closed"/>.
|
||||||
|
/// If <see cref="JsonReader.CloseInput"/> is set to <c>true</c>, the underlying <see cref="Stream"/> is also closed.
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<BsonProperty>
|
||||||
|
{
|
||||||
|
private readonly List<BsonProperty> _children = new List<BsonProperty>();
|
||||||
|
|
||||||
|
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<BsonProperty> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _children.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class BsonArray : BsonToken, IEnumerable<BsonToken>
|
||||||
|
{
|
||||||
|
private readonly List<BsonToken> _children = new List<BsonToken>();
|
||||||
|
|
||||||
|
public void Add(BsonToken token)
|
||||||
|
{
|
||||||
|
_children.Add(token);
|
||||||
|
token.Parent = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BsonType Type => BsonType.Array;
|
||||||
|
|
||||||
|
public IEnumerator<BsonToken> 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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a writer that provides a fast, non-cached, forward-only way of generating BSON data.
|
||||||
|
/// </summary>
|
||||||
|
[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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="DateTimeKind" /> used when writing <see cref="DateTime"/> values to BSON.
|
||||||
|
/// When set to <see cref="DateTimeKind.Unspecified" /> no conversion will occur.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The <see cref="DateTimeKind" /> used when writing <see cref="DateTime"/> values to BSON.</value>
|
||||||
|
public DateTimeKind DateTimeKindHandling
|
||||||
|
{
|
||||||
|
get => _writer.DateTimeKindHandling;
|
||||||
|
set => _writer.DateTimeKindHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BsonWriter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The <see cref="Stream"/> to write to.</param>
|
||||||
|
public BsonWriter(Stream stream)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(stream, nameof(stream));
|
||||||
|
_writer = new BsonBinaryWriter(new BinaryWriter(stream));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BsonWriter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="BinaryWriter"/> to write to.</param>
|
||||||
|
public BsonWriter(BinaryWriter writer)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(writer, nameof(writer));
|
||||||
|
_writer = new BsonBinaryWriter(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flushes whatever is in the buffer to the underlying <see cref="Stream"/> and also flushes the underlying stream.
|
||||||
|
/// </summary>
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
_writer.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the end.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">The token.</param>
|
||||||
|
protected override void WriteEnd(JsonToken token)
|
||||||
|
{
|
||||||
|
base.WriteEnd(token);
|
||||||
|
RemoveParent();
|
||||||
|
|
||||||
|
if (Top == 0)
|
||||||
|
{
|
||||||
|
_writer.WriteToken(_root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a comment <c>/*...*/</c> containing the specified text.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">Text to place inside the comment.</param>
|
||||||
|
public override void WriteComment(string text)
|
||||||
|
{
|
||||||
|
throw JsonWriterException.Create(this, "Cannot write JSON comment as BSON.", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the start of a constructor with the given name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the constructor.</param>
|
||||||
|
public override void WriteStartConstructor(string name)
|
||||||
|
{
|
||||||
|
throw JsonWriterException.Create(this, "Cannot write JSON constructor as BSON.", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes raw JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">The raw JSON to write.</param>
|
||||||
|
public override void WriteRaw(string json)
|
||||||
|
{
|
||||||
|
throw JsonWriterException.Create(this, "Cannot write raw JSON as BSON.", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes raw JSON where a value is expected and updates the writer's state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">The raw JSON to write.</param>
|
||||||
|
public override void WriteRawValue(string json)
|
||||||
|
{
|
||||||
|
throw JsonWriterException.Create(this, "Cannot write raw JSON as BSON.", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the beginning of a JSON array.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteStartArray()
|
||||||
|
{
|
||||||
|
base.WriteStartArray();
|
||||||
|
|
||||||
|
AddParent(new BsonArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the beginning of a JSON object.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteStartObject()
|
||||||
|
{
|
||||||
|
base.WriteStartObject();
|
||||||
|
|
||||||
|
AddParent(new BsonObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the property name of a name/value pair on a JSON object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the property.</param>
|
||||||
|
public override void WritePropertyName(string name)
|
||||||
|
{
|
||||||
|
base.WritePropertyName(name);
|
||||||
|
|
||||||
|
_propertyName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Closes this writer.
|
||||||
|
/// If <see cref="JsonWriter.CloseOutput"/> is set to <c>true</c>, the underlying <see cref="Stream"/> is also closed.
|
||||||
|
/// If <see cref="JsonWriter.AutoCompleteOnClose"/> is set to <c>true</c>, the JSON is auto-completed.
|
||||||
|
/// </summary>
|
||||||
|
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
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Object"/> value.
|
||||||
|
/// An error will raised if the value cannot be written as a single JSON token.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Object"/> value to write.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a null value.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteNull()
|
||||||
|
{
|
||||||
|
base.WriteNull();
|
||||||
|
AddToken(BsonEmpty.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an undefined value.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteUndefined()
|
||||||
|
{
|
||||||
|
base.WriteUndefined();
|
||||||
|
AddToken(BsonEmpty.Undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="String"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="String"/> value to write.</param>
|
||||||
|
public override void WriteValue(string value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddToken(value == null ? BsonEmpty.Null : new BsonString(value, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Int32"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Int32"/> value to write.</param>
|
||||||
|
public override void WriteValue(int value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, BsonType.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="UInt32"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="UInt32"/> value to write.</param>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Int64"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Int64"/> value to write.</param>
|
||||||
|
public override void WriteValue(long value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, BsonType.Long);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="UInt64"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="UInt64"/> value to write.</param>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Single"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Single"/> value to write.</param>
|
||||||
|
public override void WriteValue(float value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, BsonType.Number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Double"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Double"/> value to write.</param>
|
||||||
|
public override void WriteValue(double value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, BsonType.Number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Boolean"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Boolean"/> value to write.</param>
|
||||||
|
public override void WriteValue(bool value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddToken(value ? BsonBoolean.True : BsonBoolean.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Int16"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Int16"/> value to write.</param>
|
||||||
|
public override void WriteValue(short value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, BsonType.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="UInt16"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="UInt16"/> value to write.</param>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void WriteValue(ushort value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, BsonType.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Char"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Char"/> value to write.</param>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Byte"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Byte"/> value to write.</param>
|
||||||
|
public override void WriteValue(byte value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, BsonType.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="SByte"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="SByte"/> value to write.</param>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void WriteValue(sbyte value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, BsonType.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Decimal"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Decimal"/> value to write.</param>
|
||||||
|
public override void WriteValue(decimal value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, BsonType.Number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="DateTime"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="DateTime"/> value to write.</param>
|
||||||
|
public override void WriteValue(DateTime value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling);
|
||||||
|
AddValue(value, BsonType.Date);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_DATE_TIME_OFFSET
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="DateTimeOffset"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="DateTimeOffset"/> value to write.</param>
|
||||||
|
public override void WriteValue(DateTimeOffset value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, BsonType.Date);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Byte"/>[] value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Byte"/>[] value to write.</param>
|
||||||
|
public override void WriteValue(byte[] value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
WriteNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddToken(new BsonBinary(value, BsonBinaryType.Binary));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Guid"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Guid"/> value to write.</param>
|
||||||
|
public override void WriteValue(Guid value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddToken(new BsonBinary(value.ToByteArray(), BsonBinaryType.Uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="TimeSpan"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="TimeSpan"/> value to write.</param>
|
||||||
|
public override void WriteValue(TimeSpan value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddToken(new BsonString(value.ToString(), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Uri"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Uri"/> value to write.</param>
|
||||||
|
public override void WriteValue(Uri value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
WriteNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddToken(new BsonString(value.ToString(), true));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Byte"/>[] value that represents a BSON object id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The Object ID value to write.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a BSON regex.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">The regex pattern.</param>
|
||||||
|
/// <param name="options">The regex options.</param>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies how constructors are used when initializing objects during deserialization by the <see cref="JsonSerializer"/>.
|
||||||
|
/// </summary>
|
||||||
|
public enum ConstructorHandling
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// First attempt to use the public default constructor, then fall back to a single parameterized constructor, then to the non-public default constructor.
|
||||||
|
/// </summary>
|
||||||
|
Default = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Json.NET will use a non-public default constructor before falling back to a parameterized constructor.
|
||||||
|
/// </summary>
|
||||||
|
AllowNonPublicDefaultConstructor = 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a binary value to and from a base 64 string value.
|
||||||
|
/// </summary>
|
||||||
|
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
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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<byte> byteList = new List<byte>();
|
||||||
|
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
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
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="BsonObjectId"/> to and from JSON and BSON.
|
||||||
|
/// </summary>
|
||||||
|
[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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return (objectType == typeof(BsonObjectId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a custom object.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The object type to convert.</typeparam>
|
||||||
|
public abstract class CustomCreationConverter<T> : JsonConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("CustomCreationConverter should only be used while deserializing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an object which will then be populated by the serializer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>The created object.</returns>
|
||||||
|
public abstract T Create(Type objectType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return typeof(T).IsAssignableFrom(objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
public override bool CanWrite => false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="DataSet"/> to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
public class DataSetConverter : JsonConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified value type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="valueType">Type of the value.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool CanConvert(Type valueType)
|
||||||
|
{
|
||||||
|
return typeof(DataSet).IsAssignableFrom(valueType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="DataTable"/> to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
public class DataTableConverter : JsonConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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<object?> o = new List<object?>();
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified value type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="valueType">Type of the value.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool CanConvert(Type valueType)
|
||||||
|
{
|
||||||
|
return typeof(DataTable).IsAssignableFrom(valueType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a base class for converting a <see cref="DateTime"/> to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class DateTimeConverterBase : JsonConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a F# discriminated union type to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
public class DiscriminatedUnionConverter : JsonConverter
|
||||||
|
{
|
||||||
|
#region UnionDefinition
|
||||||
|
internal class Union
|
||||||
|
{
|
||||||
|
public readonly FSharpFunction TagReader;
|
||||||
|
public readonly List<UnionCase> Cases;
|
||||||
|
|
||||||
|
public Union(FSharpFunction tagReader, List<UnionCase> 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<Type, Union> UnionCache = new ThreadSafeStore<Type, Union>(CreateUnion);
|
||||||
|
private static readonly ThreadSafeStore<Type, Type> UnionTypeLookupCache = new ThreadSafeStore<Type, Type>(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<UnionCase>());
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
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
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts an Entity Framework <see cref="T:System.Data.EntityKeyMember"/> to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return objectType.AssignableToTypeName(EntityKeyMemberFullTypeName, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts an <see cref="ExpandoObject"/> to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
public class ExpandoObjectConverter : JsonConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
// can write is set to false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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<object?> list = new List<object?>();
|
||||||
|
|
||||||
|
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<string, object?> 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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return (objectType == typeof(ExpandoObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
public override bool CanWrite => false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="DateTime"/> to and from the ISO 8601 date format (e.g. <c>"2008-04-12T12:53Z"</c>).
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the date time styles used when converting a date to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The date time styles used when converting a date to and from JSON.</value>
|
||||||
|
public DateTimeStyles DateTimeStyles
|
||||||
|
{
|
||||||
|
get => _dateTimeStyles;
|
||||||
|
set => _dateTimeStyles = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the date time format used when converting a date to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The date time format used when converting a date to and from JSON.</value>
|
||||||
|
public string? DateTimeFormat
|
||||||
|
{
|
||||||
|
get => _dateTimeFormat ?? string.Empty;
|
||||||
|
set => _dateTimeFormat = (StringUtils.IsNullOrEmpty(value)) ? null : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the culture used when converting a date to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The culture used when converting a date to and from JSON.</value>
|
||||||
|
public CultureInfo Culture
|
||||||
|
{
|
||||||
|
get => _culture ?? CultureInfo.CurrentCulture;
|
||||||
|
set => _culture = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="DateTime"/> to and from a JavaScript <c>Date</c> constructor (e.g. <c>new Date(52231943)</c>).
|
||||||
|
/// </summary>
|
||||||
|
public class JavaScriptDateTimeConverter : DateTimeConverterBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing property value of the JSON that is being converted.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="KeyValuePair{TKey,TValue}"/> to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
public class KeyValuePairConverter : JsonConverter
|
||||||
|
{
|
||||||
|
private const string KeyName = "Key";
|
||||||
|
private const string ValueName = "Value";
|
||||||
|
|
||||||
|
private static readonly ThreadSafeStore<Type, ReflectionObject> ReflectionObjectPerType = new ThreadSafeStore<Type, ReflectionObject>(InitializeReflectionObject);
|
||||||
|
|
||||||
|
private static ReflectionObject InitializeReflectionObject(Type t)
|
||||||
|
{
|
||||||
|
IList<Type> genericArguments = t.GetGenericArguments();
|
||||||
|
Type keyType = genericArguments[0];
|
||||||
|
Type valueType = genericArguments[1];
|
||||||
|
|
||||||
|
return ReflectionObject.Create(t, t.GetConstructor(new[] { keyType, valueType }), KeyName, ValueName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="Regex"/> to and from JSON and BSON.
|
||||||
|
/// </summary>
|
||||||
|
public class RegexConverter : JsonConverter
|
||||||
|
{
|
||||||
|
private const string PatternName = "Pattern";
|
||||||
|
private const string OptionsName = "Options";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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<RegexOptions>(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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts an <see cref="Enum"/> to and from its name string value.
|
||||||
|
/// </summary>
|
||||||
|
public class StringEnumConverter : JsonConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether the written enum text should be camel case.
|
||||||
|
/// The default value is <c>false</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</value>
|
||||||
|
[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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the naming strategy used to resolve how enum text is written.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The naming strategy used to resolve how enum text is written.</value>
|
||||||
|
public NamingStrategy? NamingStrategy { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether integer values are allowed when serializing and deserializing.
|
||||||
|
/// The default value is <c>true</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if integers are allowed when serializing and deserializing; otherwise, <c>false</c>.</value>
|
||||||
|
public bool AllowIntegerValues { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="StringEnumConverter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public StringEnumConverter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="StringEnumConverter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
|
||||||
|
[Obsolete("StringEnumConverter(bool) is obsolete. Create a converter with StringEnumConverter(NamingStrategy, bool) instead.")]
|
||||||
|
public StringEnumConverter(bool camelCaseText)
|
||||||
|
{
|
||||||
|
if (camelCaseText)
|
||||||
|
{
|
||||||
|
NamingStrategy = new CamelCaseNamingStrategy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="StringEnumConverter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="namingStrategy">The naming strategy used to resolve how enum text is written.</param>
|
||||||
|
/// <param name="allowIntegerValues"><c>true</c> if integers are allowed when serializing and deserializing; otherwise, <c>false</c>.</param>
|
||||||
|
public StringEnumConverter(NamingStrategy namingStrategy, bool allowIntegerValues = true)
|
||||||
|
{
|
||||||
|
NamingStrategy = namingStrategy;
|
||||||
|
AllowIntegerValues = allowIntegerValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="StringEnumConverter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="namingStrategyType">The <see cref="System.Type"/> of the <see cref="Newtonsoft.Json.Serialization.NamingStrategy"/> used to write enum text.</param>
|
||||||
|
public StringEnumConverter(Type namingStrategyType)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(namingStrategyType, nameof(namingStrategyType));
|
||||||
|
|
||||||
|
NamingStrategy = JsonTypeReflector.CreateNamingStrategyInstance(namingStrategyType, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="StringEnumConverter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="namingStrategyType">The <see cref="System.Type"/> of the <see cref="Newtonsoft.Json.Serialization.NamingStrategy"/> used to write enum text.</param>
|
||||||
|
/// <param name="namingStrategyParameters">
|
||||||
|
/// The parameter list to use when constructing the <see cref="Newtonsoft.Json.Serialization.NamingStrategy"/> described by <paramref name="namingStrategyType"/>.
|
||||||
|
/// If <c>null</c>, the default constructor is used.
|
||||||
|
/// When non-<c>null</c>, there must be a constructor defined in the <see cref="Newtonsoft.Json.Serialization.NamingStrategy"/> that exactly matches the number,
|
||||||
|
/// order, and type of these parameters.
|
||||||
|
/// </param>
|
||||||
|
public StringEnumConverter(Type namingStrategyType, object[] namingStrategyParameters)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(namingStrategyType, nameof(namingStrategyType));
|
||||||
|
|
||||||
|
NamingStrategy = JsonTypeReflector.CreateNamingStrategyInstance(namingStrategyType, namingStrategyParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="StringEnumConverter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="namingStrategyType">The <see cref="System.Type"/> of the <see cref="Newtonsoft.Json.Serialization.NamingStrategy"/> used to write enum text.</param>
|
||||||
|
/// <param name="namingStrategyParameters">
|
||||||
|
/// The parameter list to use when constructing the <see cref="Newtonsoft.Json.Serialization.NamingStrategy"/> described by <paramref name="namingStrategyType"/>.
|
||||||
|
/// If <c>null</c>, the default constructor is used.
|
||||||
|
/// When non-<c>null</c>, there must be a constructor defined in the <see cref="Newtonsoft.Json.Serialization.NamingStrategy"/> that exactly matches the number,
|
||||||
|
/// order, and type of these parameters.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="allowIntegerValues"><c>true</c> if integers are allowed when serializing and deserializing; otherwise, <c>false</c>.</param>
|
||||||
|
public StringEnumConverter(Type namingStrategyType, object[] namingStrategyParameters, bool allowIntegerValues)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(namingStrategyType, nameof(namingStrategyType));
|
||||||
|
|
||||||
|
NamingStrategy = JsonTypeReflector.CreateNamingStrategyInstance(namingStrategyType, namingStrategyParameters);
|
||||||
|
AllowIntegerValues = allowIntegerValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
Type t = (ReflectionUtils.IsNullableType(objectType))
|
||||||
|
? Nullable.GetUnderlyingType(objectType)
|
||||||
|
: objectType;
|
||||||
|
|
||||||
|
return t.IsEnum();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="DateTime"/> to and from Unix epoch time
|
||||||
|
/// </summary>
|
||||||
|
public class UnixDateTimeConverter : DateTimeConverterBase
|
||||||
|
{
|
||||||
|
internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing property value of the JSON that is being converted.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="Version"/> to and from a string (e.g. <c>"1.2.3.4"</c>).
|
||||||
|
/// </summary>
|
||||||
|
public class VersionConverter : JsonConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing property value of the JSON that is being converted.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return objectType == typeof(Version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies how dates are formatted when writing JSON text.
|
||||||
|
/// </summary>
|
||||||
|
public enum DateFormatHandling
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Dates are written in the ISO 8601 format, e.g. <c>"2012-03-21T05:40Z"</c>.
|
||||||
|
/// </summary>
|
||||||
|
IsoDateFormat,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dates are written in the Microsoft JSON format, e.g. <c>"\/Date(1198908717056)\/"</c>.
|
||||||
|
/// </summary>
|
||||||
|
MicrosoftDateFormat
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies how date formatted strings, e.g. <c>"\/Date(1198908717056)\/"</c> and <c>"2012-03-21T05:40Z"</c>, are parsed when reading JSON text.
|
||||||
|
/// </summary>
|
||||||
|
public enum DateParseHandling
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Date formatted strings are not parsed to a date type and are read as strings.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Date formatted strings, e.g. <c>"\/Date(1198908717056)\/"</c> and <c>"2012-03-21T05:40Z"</c>, are parsed to <see cref="System.DateTime"/>.
|
||||||
|
/// </summary>
|
||||||
|
DateTime = 1,
|
||||||
|
#if HAVE_DATE_TIME_OFFSET
|
||||||
|
/// <summary>
|
||||||
|
/// Date formatted strings, e.g. <c>"\/Date(1198908717056)\/"</c> and <c>"2012-03-21T05:40Z"</c>, are parsed to <see cref="System.DateTimeOffset"/>.
|
||||||
|
/// </summary>
|
||||||
|
DateTimeOffset = 2
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies how to treat the time value when converting between string and <see cref="DateTime"/>.
|
||||||
|
/// </summary>
|
||||||
|
public enum DateTimeZoneHandling
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Treat as local time. If the <see cref="DateTime"/> object represents a Coordinated Universal Time (UTC), it is converted to the local time.
|
||||||
|
/// </summary>
|
||||||
|
Local = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Treat as a UTC. If the <see cref="DateTime"/> object represents a local time, it is converted to a UTC.
|
||||||
|
/// </summary>
|
||||||
|
Utc = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Treat as a local time if a <see cref="DateTime"/> is being converted to a string.
|
||||||
|
/// If a string is being converted to <see cref="DateTime"/>, convert to a local time if a time zone is specified.
|
||||||
|
/// </summary>
|
||||||
|
Unspecified = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time zone information should be preserved when converting.
|
||||||
|
/// </summary>
|
||||||
|
RoundtripKind = 3
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The default JSON name table implementation.
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DefaultJsonNameTable"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public DefaultJsonNameTable()
|
||||||
|
{
|
||||||
|
_entries = new Entry[_mask + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a string containing the same characters as the specified range of characters in the given array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The character array containing the name to find.</param>
|
||||||
|
/// <param name="start">The zero-based index into the array specifying the first character of the name.</param>
|
||||||
|
/// <param name="length">The number of characters in the name.</param>
|
||||||
|
/// <returns>A string containing the same characters as the specified range of characters in the given array.</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the specified string into name table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The string to add.</param>
|
||||||
|
/// <remarks>This method is not thread-safe.</remarks>
|
||||||
|
/// <returns>The resolved string.</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies default value handling options for the <see cref="JsonSerializer"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>
|
||||||
|
/// <code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\SerializationTests.cs" region="ReducingSerializedJsonSizeDefaultValueHandlingObject" title="DefaultValueHandling Class" />
|
||||||
|
/// <code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\SerializationTests.cs" region="ReducingSerializedJsonSizeDefaultValueHandlingExample" title="DefaultValueHandling Ignore Example" />
|
||||||
|
/// </example>
|
||||||
|
[Flags]
|
||||||
|
public enum DefaultValueHandling
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
Include = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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. <c>null</c> for objects and nullable types; <c>0</c> for integers,
|
||||||
|
/// decimals and floating point numbers; and <c>false</c> for booleans). The default value ignored can be changed by
|
||||||
|
/// placing the <see cref="DefaultValueAttribute"/> on the property.
|
||||||
|
/// </summary>
|
||||||
|
Ignore = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Members with a default value but no JSON will be set to their default value when deserializing.
|
||||||
|
/// </summary>
|
||||||
|
Populate = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
IgnoreAndPopulate = Ignore | Populate
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies float format handling options when writing special floating point numbers, e.g. <see cref="Double.NaN"/>,
|
||||||
|
/// <see cref="Double.PositiveInfinity"/> and <see cref="Double.NegativeInfinity"/> with <see cref="JsonWriter"/>.
|
||||||
|
/// </summary>
|
||||||
|
public enum FloatFormatHandling
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Write special floating point values as strings in JSON, e.g. <c>"NaN"</c>, <c>"Infinity"</c>, <c>"-Infinity"</c>.
|
||||||
|
/// </summary>
|
||||||
|
String = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write special floating point values as symbols in JSON, e.g. <c>NaN</c>, <c>Infinity</c>, <c>-Infinity</c>.
|
||||||
|
/// Note that this will produce non-valid JSON.
|
||||||
|
/// </summary>
|
||||||
|
Symbol = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write special floating point values as the property's default value in JSON, e.g. 0.0 for a <see cref="Double"/> property, <c>null</c> for a <see cref="Nullable{T}"/> of <see cref="Double"/> property.
|
||||||
|
/// </summary>
|
||||||
|
DefaultValue = 2
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies how floating point numbers, e.g. 1.0 and 9.9, are parsed when reading JSON text.
|
||||||
|
/// </summary>
|
||||||
|
public enum FloatParseHandling
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Floating point numbers are parsed to <see cref="Double"/>.
|
||||||
|
/// </summary>
|
||||||
|
Double = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Floating point numbers are parsed to <see cref="Decimal"/>.
|
||||||
|
/// </summary>
|
||||||
|
Decimal = 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
#if HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE
|
||||||
|
|
||||||
|
namespace System.Runtime.Serialization.Formatters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the method that will be used during deserialization for locating and loading assemblies.
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("FormatterAssemblyStyle is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
|
||||||
|
public enum FormatterAssemblyStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 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 <see cref="M:System.Reflection.Assembly.LoadWithPartialName(String)"/> method is used to load the assembly.
|
||||||
|
/// </summary>
|
||||||
|
Simple = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// In full mode, the assembly used during deserialization must match exactly the assembly used during serialization. The <see cref="System.Reflection.Assembly.Load"/> is used to load the assembly.
|
||||||
|
/// </summary>
|
||||||
|
Full = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies formatting options for the <see cref="JsonTextWriter"/>.
|
||||||
|
/// </summary>
|
||||||
|
public enum Formatting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// No special formatting is applied. This is the default.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Causes child objects to be indented according to the <see cref="JsonTextWriter.Indentation"/> and <see cref="JsonTextWriter.IndentChar"/> settings.
|
||||||
|
/// </summary>
|
||||||
|
Indented = 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
namespace LC.Newtonsoft.Json
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides an interface for using pooled arrays.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The array type content.</typeparam>
|
||||||
|
public interface IArrayPool<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Rent an array from the pool. This array must be returned when it is no longer needed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="minimumLength">The minimum required length of the array. The returned array may be longer.</param>
|
||||||
|
/// <returns>The rented array from the pool. This array must be returned when it is no longer needed.</returns>
|
||||||
|
T[] Rent(int minimumLength);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return an array to the pool.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">The array that is being returned.</param>
|
||||||
|
void Return(T[]? array);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides an interface to enable a class to return line and position information.
|
||||||
|
/// </summary>
|
||||||
|
public interface IJsonLineInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the class can return line information.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if <see cref="LineNumber"/> and <see cref="LinePosition"/> can be provided; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
bool HasLineInfo();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current line number.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The current line number or 0 if no line information is available (for example, when <see cref="HasLineInfo"/> returns <c>false</c>).</value>
|
||||||
|
int LineNumber { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current line position.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The current line position or 0 if no line information is available (for example, when <see cref="HasLineInfo"/> returns <c>false</c>).</value>
|
||||||
|
int LinePosition { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instructs the <see cref="JsonSerializer"/> how to serialize the collection.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
|
||||||
|
public sealed class JsonArrayAttribute : JsonContainerAttribute
|
||||||
|
{
|
||||||
|
private bool _allowNullItems;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether null items are allowed in the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if null items are allowed in the collection; otherwise, <c>false</c>.</value>
|
||||||
|
public bool AllowNullItems
|
||||||
|
{
|
||||||
|
get => _allowNullItems;
|
||||||
|
set => _allowNullItems = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonArrayAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JsonArrayAttribute()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonObjectAttribute"/> class with a flag indicating whether the array can contain null items.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="allowNullItems">A flag indicating whether the array can contain null items.</param>
|
||||||
|
public JsonArrayAttribute(bool allowNullItems)
|
||||||
|
{
|
||||||
|
_allowNullItems = allowNullItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonArrayAttribute"/> class with the specified container Id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The container Id.</param>
|
||||||
|
public JsonArrayAttribute(string id)
|
||||||
|
: base(id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instructs the <see cref="JsonSerializer"/> to use the specified constructor when deserializing that object.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)]
|
||||||
|
public sealed class JsonConstructorAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instructs the <see cref="JsonSerializer"/> how to serialize the object.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
|
||||||
|
public abstract class JsonContainerAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the id.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The id.</value>
|
||||||
|
public string? Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the title.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The title.</value>
|
||||||
|
public string? Title { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the description.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The description.</value>
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the collection's items converter.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The collection's items converter.</value>
|
||||||
|
public Type? ItemConverterType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The parameter list to use when constructing the <see cref="JsonConverter"/> described by <see cref="ItemConverterType"/>.
|
||||||
|
/// If <c>null</c>, the default constructor is used.
|
||||||
|
/// When non-<c>null</c>, there must be a constructor defined in the <see cref="JsonConverter"/> that exactly matches the number,
|
||||||
|
/// order, and type of these parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>
|
||||||
|
/// <code>
|
||||||
|
/// [JsonContainer(ItemConverterType = typeof(MyContainerConverter), ItemConverterParameters = new object[] { 123, "Four" })]
|
||||||
|
/// </code>
|
||||||
|
/// </example>
|
||||||
|
public object[]? ItemConverterParameters { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="Type"/> of the <see cref="NamingStrategy"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The <see cref="Type"/> of the <see cref="NamingStrategy"/>.</value>
|
||||||
|
public Type? NamingStrategyType
|
||||||
|
{
|
||||||
|
get => _namingStrategyType;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_namingStrategyType = value;
|
||||||
|
NamingStrategyInstance = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The parameter list to use when constructing the <see cref="NamingStrategy"/> described by <see cref="NamingStrategyType"/>.
|
||||||
|
/// If <c>null</c>, the default constructor is used.
|
||||||
|
/// When non-<c>null</c>, there must be a constructor defined in the <see cref="NamingStrategy"/> that exactly matches the number,
|
||||||
|
/// order, and type of these parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>
|
||||||
|
/// <code>
|
||||||
|
/// [JsonContainer(NamingStrategyType = typeof(MyNamingStrategy), NamingStrategyParameters = new object[] { 123, "Four" })]
|
||||||
|
/// </code>
|
||||||
|
/// </example>
|
||||||
|
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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that indicates whether to preserve object references.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> to keep object reference; otherwise, <c>false</c>. The default is <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
public bool IsReference
|
||||||
|
{
|
||||||
|
get => _isReference ?? default;
|
||||||
|
set => _isReference = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that indicates whether to preserve collection's items references.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> to keep collection's items object references; otherwise, <c>false</c>. The default is <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
public bool ItemIsReference
|
||||||
|
{
|
||||||
|
get => _itemIsReference ?? default;
|
||||||
|
set => _itemIsReference = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the reference loop handling used when serializing the collection's items.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The reference loop handling.</value>
|
||||||
|
public ReferenceLoopHandling ItemReferenceLoopHandling
|
||||||
|
{
|
||||||
|
get => _itemReferenceLoopHandling ?? default;
|
||||||
|
set => _itemReferenceLoopHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the type name handling used when serializing the collection's items.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type name handling.</value>
|
||||||
|
public TypeNameHandling ItemTypeNameHandling
|
||||||
|
{
|
||||||
|
get => _itemTypeNameHandling ?? default;
|
||||||
|
set => _itemTypeNameHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonContainerAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
protected JsonContainerAttribute()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonContainerAttribute"/> class with the specified container Id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The container Id.</param>
|
||||||
|
protected JsonContainerAttribute(string id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts an object to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class JsonConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public abstract bool CanConvert(Type objectType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this <see cref="JsonConverter"/> can read JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this <see cref="JsonConverter"/> can read JSON; otherwise, <c>false</c>.</value>
|
||||||
|
public virtual bool CanRead => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>.</value>
|
||||||
|
public virtual bool CanWrite => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts an object to and from JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The object type to convert.</typeparam>
|
||||||
|
public abstract class JsonConverter<T> : JsonConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read. If there is no existing value then <c>null</c> will be used.</param>
|
||||||
|
/// <param name="hasExistingValue">The existing value has a value.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>The object value.</returns>
|
||||||
|
public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public sealed override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return typeof(T).IsAssignableFrom(objectType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instructs the <see cref="JsonSerializer"/> to use the specified <see cref="JsonConverter"/> when serializing the member or class.
|
||||||
|
/// </summary>
|
||||||
|
[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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Type"/> of the <see cref="JsonConverter"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The <see cref="Type"/> of the <see cref="JsonConverter"/>.</value>
|
||||||
|
public Type ConverterType => _converterType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The parameter list to use when constructing the <see cref="JsonConverter"/> described by <see cref="ConverterType"/>.
|
||||||
|
/// If <c>null</c>, the default constructor is used.
|
||||||
|
/// </summary>
|
||||||
|
public object[]? ConverterParameters { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonConverterAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="converterType">Type of the <see cref="JsonConverter"/>.</param>
|
||||||
|
public JsonConverterAttribute(Type converterType)
|
||||||
|
{
|
||||||
|
if (converterType == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(converterType));
|
||||||
|
}
|
||||||
|
|
||||||
|
_converterType = converterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonConverterAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="converterType">Type of the <see cref="JsonConverter"/>.</param>
|
||||||
|
/// <param name="converterParameters">Parameter list to use when constructing the <see cref="JsonConverter"/>. Can be <c>null</c>.</param>
|
||||||
|
public JsonConverterAttribute(Type converterType, params object[] converterParameters)
|
||||||
|
: this(converterType)
|
||||||
|
{
|
||||||
|
ConverterParameters = converterParameters;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a collection of <see cref="JsonConverter"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class JsonConverterCollection : Collection<JsonConverter>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instructs the <see cref="JsonSerializer"/> how to serialize the collection.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
|
||||||
|
public sealed class JsonDictionaryAttribute : JsonContainerAttribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonDictionaryAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JsonDictionaryAttribute()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonDictionaryAttribute"/> class with the specified container Id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The container Id.</param>
|
||||||
|
public JsonDictionaryAttribute(string id)
|
||||||
|
: base(id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The exception thrown when an error occurs during JSON serialization or deserialization.
|
||||||
|
/// </summary>
|
||||||
|
#if HAVE_BINARY_EXCEPTION_SERIALIZATION
|
||||||
|
[Serializable]
|
||||||
|
#endif
|
||||||
|
public class JsonException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JsonException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonException"/> class
|
||||||
|
/// with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
public JsonException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonException"/> class
|
||||||
|
/// with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or <c>null</c> if no inner exception is specified.</param>
|
||||||
|
public JsonException(string message, Exception? innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_BINARY_EXCEPTION_SERIALIZATION
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
|
||||||
|
/// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">The <paramref name="info"/> parameter is <c>null</c>.</exception>
|
||||||
|
/// <exception cref="SerializationException">The class name is <c>null</c> or <see cref="Exception.HResult"/> is zero (0).</exception>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instructs the <see cref="JsonSerializer"/> to deserialize properties with no matching class member into the specified collection
|
||||||
|
/// and write values during serialization.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
|
||||||
|
public class JsonExtensionDataAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that indicates whether to write extension data when serializing the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> to write extension data when serializing the object; otherwise, <c>false</c>. The default is <c>true</c>.
|
||||||
|
/// </value>
|
||||||
|
public bool WriteData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that indicates whether to read extension data when deserializing the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> to read extension data when deserializing the object; otherwise, <c>false</c>. The default is <c>true</c>.
|
||||||
|
/// </value>
|
||||||
|
public bool ReadData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonExtensionDataAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JsonExtensionDataAttribute()
|
||||||
|
{
|
||||||
|
WriteData = true;
|
||||||
|
ReadData = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instructs the <see cref="JsonSerializer"/> not to serialize the public field or public read/write property value.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
|
||||||
|
public sealed class JsonIgnoreAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
namespace LC.Newtonsoft.Json
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for a table of atomized string objects.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class JsonNameTable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a string containing the same characters as the specified range of characters in the given array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The character array containing the name to find.</param>
|
||||||
|
/// <param name="start">The zero-based index into the array specifying the first character of the name.</param>
|
||||||
|
/// <param name="length">The number of characters in the name.</param>
|
||||||
|
/// <returns>A string containing the same characters as the specified range of characters in the given array.</returns>
|
||||||
|
public abstract string? Get(char[] key, int start, int length);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instructs the <see cref="JsonSerializer"/> how to serialize the object.
|
||||||
|
/// </summary>
|
||||||
|
[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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the member serialization.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The member serialization.</value>
|
||||||
|
public MemberSerialization MemberSerialization
|
||||||
|
{
|
||||||
|
get => _memberSerialization;
|
||||||
|
set => _memberSerialization = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the missing member handling used when deserializing this object.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The missing member handling.</value>
|
||||||
|
public MissingMemberHandling MissingMemberHandling
|
||||||
|
{
|
||||||
|
get => _missingMemberHandling ?? default;
|
||||||
|
set => _missingMemberHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how the object's properties with null values are handled during serialization and deserialization.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>How the object's properties with null values are handled during serialization and deserialization.</value>
|
||||||
|
public NullValueHandling ItemNullValueHandling
|
||||||
|
{
|
||||||
|
get => _itemNullValueHandling ?? default;
|
||||||
|
set => _itemNullValueHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that indicates whether the object's properties are required.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A value indicating whether the object's properties are required.
|
||||||
|
/// </value>
|
||||||
|
public Required ItemRequired
|
||||||
|
{
|
||||||
|
get => _itemRequired ?? default;
|
||||||
|
set => _itemRequired = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonObjectAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JsonObjectAttribute()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonObjectAttribute"/> class with the specified member serialization.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="memberSerialization">The member serialization.</param>
|
||||||
|
public JsonObjectAttribute(MemberSerialization memberSerialization)
|
||||||
|
{
|
||||||
|
MemberSerialization = memberSerialization;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonObjectAttribute"/> class with the specified container Id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The container Id.</param>
|
||||||
|
public JsonObjectAttribute(string id)
|
||||||
|
: base(id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<JsonPosition> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instructs the <see cref="JsonSerializer"/> to always serialize the member with the specified name.
|
||||||
|
/// </summary>
|
||||||
|
[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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="JsonConverter"/> type used when serializing the property's collection items.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The collection's items <see cref="JsonConverter"/> type.</value>
|
||||||
|
public Type? ItemConverterType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The parameter list to use when constructing the <see cref="JsonConverter"/> described by <see cref="ItemConverterType"/>.
|
||||||
|
/// If <c>null</c>, the default constructor is used.
|
||||||
|
/// When non-<c>null</c>, there must be a constructor defined in the <see cref="JsonConverter"/> that exactly matches the number,
|
||||||
|
/// order, and type of these parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>
|
||||||
|
/// <code>
|
||||||
|
/// [JsonProperty(ItemConverterType = typeof(MyContainerConverter), ItemConverterParameters = new object[] { 123, "Four" })]
|
||||||
|
/// </code>
|
||||||
|
/// </example>
|
||||||
|
public object[]? ItemConverterParameters { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="Type"/> of the <see cref="NamingStrategy"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The <see cref="Type"/> of the <see cref="NamingStrategy"/>.</value>
|
||||||
|
public Type? NamingStrategyType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The parameter list to use when constructing the <see cref="NamingStrategy"/> described by <see cref="JsonPropertyAttribute.NamingStrategyType"/>.
|
||||||
|
/// If <c>null</c>, the default constructor is used.
|
||||||
|
/// When non-<c>null</c>, there must be a constructor defined in the <see cref="NamingStrategy"/> that exactly matches the number,
|
||||||
|
/// order, and type of these parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>
|
||||||
|
/// <code>
|
||||||
|
/// [JsonProperty(NamingStrategyType = typeof(MyNamingStrategy), NamingStrategyParameters = new object[] { 123, "Four" })]
|
||||||
|
/// </code>
|
||||||
|
/// </example>
|
||||||
|
public object[]? NamingStrategyParameters { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the null value handling used when serializing this property.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The null value handling.</value>
|
||||||
|
public NullValueHandling NullValueHandling
|
||||||
|
{
|
||||||
|
get => _nullValueHandling ?? default;
|
||||||
|
set => _nullValueHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default value handling used when serializing this property.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The default value handling.</value>
|
||||||
|
public DefaultValueHandling DefaultValueHandling
|
||||||
|
{
|
||||||
|
get => _defaultValueHandling ?? default;
|
||||||
|
set => _defaultValueHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the reference loop handling used when serializing this property.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The reference loop handling.</value>
|
||||||
|
public ReferenceLoopHandling ReferenceLoopHandling
|
||||||
|
{
|
||||||
|
get => _referenceLoopHandling ?? default;
|
||||||
|
set => _referenceLoopHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the object creation handling used when deserializing this property.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The object creation handling.</value>
|
||||||
|
public ObjectCreationHandling ObjectCreationHandling
|
||||||
|
{
|
||||||
|
get => _objectCreationHandling ?? default;
|
||||||
|
set => _objectCreationHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the type name handling used when serializing this property.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type name handling.</value>
|
||||||
|
public TypeNameHandling TypeNameHandling
|
||||||
|
{
|
||||||
|
get => _typeNameHandling ?? default;
|
||||||
|
set => _typeNameHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether this property's value is serialized as a reference.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>Whether this property's value is serialized as a reference.</value>
|
||||||
|
public bool IsReference
|
||||||
|
{
|
||||||
|
get => _isReference ?? default;
|
||||||
|
set => _isReference = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the order of serialization of a member.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The numeric order of serialization.</value>
|
||||||
|
public int Order
|
||||||
|
{
|
||||||
|
get => _order ?? default;
|
||||||
|
set => _order = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this property is required.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A value indicating whether this property is required.
|
||||||
|
/// </value>
|
||||||
|
public Required Required
|
||||||
|
{
|
||||||
|
get => _required ?? Required.Default;
|
||||||
|
set => _required = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the name of the property.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name of the property.</value>
|
||||||
|
public string? PropertyName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the reference loop handling used when serializing the property's collection items.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The collection's items reference loop handling.</value>
|
||||||
|
public ReferenceLoopHandling ItemReferenceLoopHandling
|
||||||
|
{
|
||||||
|
get => _itemReferenceLoopHandling ?? default;
|
||||||
|
set => _itemReferenceLoopHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the type name handling used when serializing the property's collection items.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The collection's items type name handling.</value>
|
||||||
|
public TypeNameHandling ItemTypeNameHandling
|
||||||
|
{
|
||||||
|
get => _itemTypeNameHandling ?? default;
|
||||||
|
set => _itemTypeNameHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether this property's collection items are serialized as a reference.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>Whether this property's collection items are serialized as a reference.</value>
|
||||||
|
public bool ItemIsReference
|
||||||
|
{
|
||||||
|
get => _itemIsReference ?? default;
|
||||||
|
set => _itemIsReference = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonPropertyAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JsonPropertyAttribute()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonPropertyAttribute"/> class with the specified name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyName">Name of the property.</param>
|
||||||
|
public JsonPropertyAttribute(string propertyName)
|
||||||
|
{
|
||||||
|
PropertyName = propertyName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously reads the next JSON token from the source.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns <c>true</c> if the next token was read successfully; <c>false</c> if there are no more tokens to read.</returns>
|
||||||
|
/// <remarks>The default behaviour is to execute synchronously, returning an already-completed task. Derived
|
||||||
|
/// classes can override this behaviour for true asynchronicity.</remarks>
|
||||||
|
public virtual Task<bool> ReadAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return cancellationToken.CancelIfRequestedAsync<bool>() ?? Read().ToAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously skips the children of the current token.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> that represents the asynchronous operation.</returns>
|
||||||
|
/// <remarks>The default behaviour is to execute synchronously, returning an already-completed task. Derived
|
||||||
|
/// classes can override this behaviour for true asynchronicity.</remarks>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="bool"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns the <see cref="Nullable{T}"/> of <see cref="bool"/>. This result will be <c>null</c> at the end of an array.</returns>
|
||||||
|
/// <remarks>The default behaviour is to execute synchronously, returning an already-completed task. Derived
|
||||||
|
/// classes can override this behaviour for true asynchronicity.</remarks>
|
||||||
|
public virtual Task<bool?> ReadAsBooleanAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return cancellationToken.CancelIfRequestedAsync<bool?>() ?? Task.FromResult(ReadAsBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously reads the next JSON token from the source as a <see cref="byte"/>[].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns the <see cref="byte"/>[]. This result will be <c>null</c> at the end of an array.</returns>
|
||||||
|
/// <remarks>The default behaviour is to execute synchronously, returning an already-completed task. Derived
|
||||||
|
/// classes can override this behaviour for true asynchronicity.</remarks>
|
||||||
|
public virtual Task<byte[]?> ReadAsBytesAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return cancellationToken.CancelIfRequestedAsync<byte[]?>() ?? Task.FromResult(ReadAsBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<byte[]?> ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
List<byte> buffer = new List<byte>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="DateTime"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns the <see cref="Nullable{T}"/> of <see cref="DateTime"/>. This result will be <c>null</c> at the end of an array.</returns>
|
||||||
|
/// <remarks>The default behaviour is to execute synchronously, returning an already-completed task. Derived
|
||||||
|
/// classes can override this behaviour for true asynchronicity.</remarks>
|
||||||
|
public virtual Task<DateTime?> ReadAsDateTimeAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return cancellationToken.CancelIfRequestedAsync<DateTime?>() ?? Task.FromResult(ReadAsDateTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns the <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/>. This result will be <c>null</c> at the end of an array.</returns>
|
||||||
|
/// <remarks>The default behaviour is to execute synchronously, returning an already-completed task. Derived
|
||||||
|
/// classes can override this behaviour for true asynchronicity.</remarks>
|
||||||
|
public virtual Task<DateTimeOffset?> ReadAsDateTimeOffsetAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return cancellationToken.CancelIfRequestedAsync<DateTimeOffset?>() ?? Task.FromResult(ReadAsDateTimeOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="decimal"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns the <see cref="Nullable{T}"/> of <see cref="decimal"/>. This result will be <c>null</c> at the end of an array.</returns>
|
||||||
|
/// <remarks>The default behaviour is to execute synchronously, returning an already-completed task. Derived
|
||||||
|
/// classes can override this behaviour for true asynchronicity.</remarks>
|
||||||
|
public virtual Task<decimal?> ReadAsDecimalAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return cancellationToken.CancelIfRequestedAsync<decimal?>() ?? Task.FromResult(ReadAsDecimal());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="double"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns the <see cref="Nullable{T}"/> of <see cref="double"/>. This result will be <c>null</c> at the end of an array.</returns>
|
||||||
|
/// <remarks>The default behaviour is to execute synchronously, returning an already-completed task. Derived
|
||||||
|
/// classes can override this behaviour for true asynchronicity.</remarks>
|
||||||
|
public virtual Task<double?> ReadAsDoubleAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return Task.FromResult(ReadAsDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="int"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns the <see cref="Nullable{T}"/> of <see cref="int"/>. This result will be <c>null</c> at the end of an array.</returns>
|
||||||
|
/// <remarks>The default behaviour is to execute synchronously, returning an already-completed task. Derived
|
||||||
|
/// classes can override this behaviour for true asynchronicity.</remarks>
|
||||||
|
public virtual Task<int?> ReadAsInt32Async(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return cancellationToken.CancelIfRequestedAsync<int?>() ?? Task.FromResult(ReadAsInt32());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously reads the next JSON token from the source as a <see cref="string"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns the <see cref="string"/>. This result will be <c>null</c> at the end of an array.</returns>
|
||||||
|
/// <remarks>The default behaviour is to execute synchronously, returning an already-completed task. Derived
|
||||||
|
/// classes can override this behaviour for true asynchronicity.</remarks>
|
||||||
|
public virtual Task<string?> ReadAsStringAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return cancellationToken.CancelIfRequestedAsync<string?>() ?? Task.FromResult(ReadAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<bool> ReadAndMoveToContentAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await ReadAsync(cancellationToken).ConfigureAwait(false) && await MoveToContentAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Task<bool> MoveToContentAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
switch (TokenType)
|
||||||
|
{
|
||||||
|
case JsonToken.None:
|
||||||
|
case JsonToken.Comment:
|
||||||
|
return MoveToContentFromNonContentAsync(cancellationToken);
|
||||||
|
default:
|
||||||
|
return AsyncUtils.True;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> 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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The exception thrown when an error occurs while reading JSON text.
|
||||||
|
/// </summary>
|
||||||
|
#if HAVE_BINARY_EXCEPTION_SERIALIZATION
|
||||||
|
[Serializable]
|
||||||
|
#endif
|
||||||
|
public class JsonReaderException : JsonException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the line number indicating where the error occurred.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The line number indicating where the error occurred.</value>
|
||||||
|
public int LineNumber { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the line position indicating where the error occurred.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The line position indicating where the error occurred.</value>
|
||||||
|
public int LinePosition { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the JSON where the error occurred.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The path to the JSON where the error occurred.</value>
|
||||||
|
public string? Path { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonReaderException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JsonReaderException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonReaderException"/> class
|
||||||
|
/// with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
public JsonReaderException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonReaderException"/> class
|
||||||
|
/// with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or <c>null</c> if no inner exception is specified.</param>
|
||||||
|
public JsonReaderException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_BINARY_EXCEPTION_SERIALIZATION
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonReaderException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
|
||||||
|
/// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">The <paramref name="info"/> parameter is <c>null</c>.</exception>
|
||||||
|
/// <exception cref="SerializationException">The class name is <c>null</c> or <see cref="Exception.HResult"/> is zero (0).</exception>
|
||||||
|
public JsonReaderException(SerializationInfo info, StreamingContext context)
|
||||||
|
: base(info, context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonReaderException"/> 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="path">The path to the JSON where the error occurred.</param>
|
||||||
|
/// <param name="lineNumber">The line number indicating where the error occurred.</param>
|
||||||
|
/// <param name="linePosition">The line position indicating where the error occurred.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or <c>null</c> if no inner exception is specified.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instructs the <see cref="JsonSerializer"/> to always serialize the member, and to require that the member has a value.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
|
||||||
|
public sealed class JsonRequiredAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The exception thrown when an error occurs during JSON serialization or deserialization.
|
||||||
|
/// </summary>
|
||||||
|
#if HAVE_BINARY_EXCEPTION_SERIALIZATION
|
||||||
|
[Serializable]
|
||||||
|
#endif
|
||||||
|
public class JsonSerializationException : JsonException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the line number indicating where the error occurred.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The line number indicating where the error occurred.</value>
|
||||||
|
public int LineNumber { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the line position indicating where the error occurred.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The line position indicating where the error occurred.</value>
|
||||||
|
public int LinePosition { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the JSON where the error occurred.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The path to the JSON where the error occurred.</value>
|
||||||
|
public string? Path { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonSerializationException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JsonSerializationException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonSerializationException"/> class
|
||||||
|
/// with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
public JsonSerializationException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonSerializationException"/> class
|
||||||
|
/// with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or <c>null</c> if no inner exception is specified.</param>
|
||||||
|
public JsonSerializationException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_BINARY_EXCEPTION_SERIALIZATION
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonSerializationException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
|
||||||
|
/// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">The <paramref name="info"/> parameter is <c>null</c>.</exception>
|
||||||
|
/// <exception cref="SerializationException">The class name is <c>null</c> or <see cref="Exception.HResult"/> is zero (0).</exception>
|
||||||
|
public JsonSerializationException(SerializationInfo info, StreamingContext context)
|
||||||
|
: base(info, context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonSerializationException"/> 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="path">The path to the JSON where the error occurred.</param>
|
||||||
|
/// <param name="lineNumber">The line number indicating where the error occurred.</param>
|
||||||
|
/// <param name="linePosition">The line position indicating where the error occurred.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or <c>null</c> if no inner exception is specified.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the settings on a <see cref="JsonSerializer"/> object.
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how reference loops (e.g. a class referencing itself) are handled.
|
||||||
|
/// The default value is <see cref="Json.ReferenceLoopHandling.Error" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>Reference loop handling.</value>
|
||||||
|
public ReferenceLoopHandling ReferenceLoopHandling
|
||||||
|
{
|
||||||
|
get => _referenceLoopHandling ?? DefaultReferenceLoopHandling;
|
||||||
|
set => _referenceLoopHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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 <see cref="Json.MissingMemberHandling.Ignore" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>Missing member handling.</value>
|
||||||
|
public MissingMemberHandling MissingMemberHandling
|
||||||
|
{
|
||||||
|
get => _missingMemberHandling ?? DefaultMissingMemberHandling;
|
||||||
|
set => _missingMemberHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how objects are created during deserialization.
|
||||||
|
/// The default value is <see cref="Json.ObjectCreationHandling.Auto" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The object creation handling.</value>
|
||||||
|
public ObjectCreationHandling ObjectCreationHandling
|
||||||
|
{
|
||||||
|
get => _objectCreationHandling ?? DefaultObjectCreationHandling;
|
||||||
|
set => _objectCreationHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how null values are handled during serialization and deserialization.
|
||||||
|
/// The default value is <see cref="Json.NullValueHandling.Include" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>Null value handling.</value>
|
||||||
|
public NullValueHandling NullValueHandling
|
||||||
|
{
|
||||||
|
get => _nullValueHandling ?? DefaultNullValueHandling;
|
||||||
|
set => _nullValueHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how default values are handled during serialization and deserialization.
|
||||||
|
/// The default value is <see cref="Json.DefaultValueHandling.Include" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The default value handling.</value>
|
||||||
|
public DefaultValueHandling DefaultValueHandling
|
||||||
|
{
|
||||||
|
get => _defaultValueHandling ?? DefaultDefaultValueHandling;
|
||||||
|
set => _defaultValueHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a <see cref="JsonConverter"/> collection that will be used during serialization.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The converters.</value>
|
||||||
|
public IList<JsonConverter> Converters { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how object references are preserved by the serializer.
|
||||||
|
/// The default value is <see cref="Json.PreserveReferencesHandling.None" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The preserve references handling.</value>
|
||||||
|
public PreserveReferencesHandling PreserveReferencesHandling
|
||||||
|
{
|
||||||
|
get => _preserveReferencesHandling ?? DefaultPreserveReferencesHandling;
|
||||||
|
set => _preserveReferencesHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how type name writing and reading is handled by the serializer.
|
||||||
|
/// The default value is <see cref="Json.TypeNameHandling.None" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <see cref="JsonSerializerSettings.TypeNameHandling"/> should be used with caution when your application deserializes JSON from an external source.
|
||||||
|
/// Incoming types should be validated with a custom <see cref="JsonSerializerSettings.SerializationBinder"/>
|
||||||
|
/// when deserializing with a value other than <see cref="Json.TypeNameHandling.None"/>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <value>The type name handling.</value>
|
||||||
|
public TypeNameHandling TypeNameHandling
|
||||||
|
{
|
||||||
|
get => _typeNameHandling ?? DefaultTypeNameHandling;
|
||||||
|
set => _typeNameHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how metadata properties are used during deserialization.
|
||||||
|
/// The default value is <see cref="Json.MetadataPropertyHandling.Default" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The metadata properties handling.</value>
|
||||||
|
public MetadataPropertyHandling MetadataPropertyHandling
|
||||||
|
{
|
||||||
|
get => _metadataPropertyHandling ?? DefaultMetadataPropertyHandling;
|
||||||
|
set => _metadataPropertyHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how a type name assembly is written and resolved by the serializer.
|
||||||
|
/// The default value is <see cref="FormatterAssemblyStyle.Simple" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type name assembly format.</value>
|
||||||
|
[Obsolete("TypeNameAssemblyFormat is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
|
||||||
|
public FormatterAssemblyStyle TypeNameAssemblyFormat
|
||||||
|
{
|
||||||
|
get => (FormatterAssemblyStyle)TypeNameAssemblyFormatHandling;
|
||||||
|
set => TypeNameAssemblyFormatHandling = (TypeNameAssemblyFormatHandling)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how a type name assembly is written and resolved by the serializer.
|
||||||
|
/// The default value is <see cref="Json.TypeNameAssemblyFormatHandling.Simple" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type name assembly format.</value>
|
||||||
|
public TypeNameAssemblyFormatHandling TypeNameAssemblyFormatHandling
|
||||||
|
{
|
||||||
|
get => _typeNameAssemblyFormatHandling ?? DefaultTypeNameAssemblyFormatHandling;
|
||||||
|
set => _typeNameAssemblyFormatHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how constructors are used during deserialization.
|
||||||
|
/// The default value is <see cref="Json.ConstructorHandling.Default" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The constructor handling.</value>
|
||||||
|
public ConstructorHandling ConstructorHandling
|
||||||
|
{
|
||||||
|
get => _constructorHandling ?? DefaultConstructorHandling;
|
||||||
|
set => _constructorHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the contract resolver used by the serializer when
|
||||||
|
/// serializing .NET objects to JSON and vice versa.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The contract resolver.</value>
|
||||||
|
public IContractResolver? ContractResolver { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the equality comparer used by the serializer when comparing references.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The equality comparer.</value>
|
||||||
|
public IEqualityComparer? EqualityComparer { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="IReferenceResolver"/> used by the serializer when resolving references.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The reference resolver.</value>
|
||||||
|
[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<IReferenceResolver?>?)null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a function that creates the <see cref="IReferenceResolver"/> used by the serializer when resolving references.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>A function that creates the <see cref="IReferenceResolver"/> used by the serializer when resolving references.</value>
|
||||||
|
public Func<IReferenceResolver?>? ReferenceResolverProvider { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="ITraceWriter"/> used by the serializer when writing trace messages.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The trace writer.</value>
|
||||||
|
public ITraceWriter? TraceWriter { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="SerializationBinder"/> used by the serializer when resolving type names.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The binder.</value>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="ISerializationBinder"/> used by the serializer when resolving type names.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The binder.</value>
|
||||||
|
public ISerializationBinder? SerializationBinder { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the error handler called during serialization and deserialization.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The error handler called during serialization and deserialization.</value>
|
||||||
|
public EventHandler<ErrorEventArgs>? Error { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="StreamingContext"/> used by the serializer when invoking serialization callback methods.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The context.</value>
|
||||||
|
public StreamingContext Context
|
||||||
|
{
|
||||||
|
get => _context ?? DefaultContext;
|
||||||
|
set => _context = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how <see cref="DateTime"/> and <see cref="DateTimeOffset"/> values are formatted when writing JSON text,
|
||||||
|
/// and the expected date format when reading JSON text.
|
||||||
|
/// The default value is <c>"yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"</c>.
|
||||||
|
/// </summary>
|
||||||
|
public string DateFormatString
|
||||||
|
{
|
||||||
|
get => _dateFormatString ?? DefaultDateFormatString;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_dateFormatString = value;
|
||||||
|
_dateFormatStringSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a <see cref="JsonReaderException"/>.
|
||||||
|
/// A null value means there is no maximum.
|
||||||
|
/// The default value is <c>128</c>.
|
||||||
|
/// </summary>
|
||||||
|
public int? MaxDepth
|
||||||
|
{
|
||||||
|
get => _maxDepthSet ? _maxDepth : DefaultMaxDepth;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Value must be positive.", nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_maxDepth = value;
|
||||||
|
_maxDepthSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates how JSON text output is formatted.
|
||||||
|
/// The default value is <see cref="Json.Formatting.None" />.
|
||||||
|
/// </summary>
|
||||||
|
public Formatting Formatting
|
||||||
|
{
|
||||||
|
get => _formatting ?? DefaultFormatting;
|
||||||
|
set => _formatting = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how dates are written to JSON text.
|
||||||
|
/// The default value is <see cref="Json.DateFormatHandling.IsoDateFormat" />.
|
||||||
|
/// </summary>
|
||||||
|
public DateFormatHandling DateFormatHandling
|
||||||
|
{
|
||||||
|
get => _dateFormatHandling ?? DefaultDateFormatHandling;
|
||||||
|
set => _dateFormatHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how <see cref="DateTime"/> time zones are handled during serialization and deserialization.
|
||||||
|
/// The default value is <see cref="Json.DateTimeZoneHandling.RoundtripKind" />.
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeZoneHandling DateTimeZoneHandling
|
||||||
|
{
|
||||||
|
get => _dateTimeZoneHandling ?? DefaultDateTimeZoneHandling;
|
||||||
|
set => _dateTimeZoneHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how date formatted strings, e.g. <c>"\/Date(1198908717056)\/"</c> and <c>"2012-03-21T05:40Z"</c>, are parsed when reading JSON.
|
||||||
|
/// The default value is <see cref="Json.DateParseHandling.DateTime" />.
|
||||||
|
/// </summary>
|
||||||
|
public DateParseHandling DateParseHandling
|
||||||
|
{
|
||||||
|
get => _dateParseHandling ?? DefaultDateParseHandling;
|
||||||
|
set => _dateParseHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how special floating point numbers, e.g. <see cref="Double.NaN"/>,
|
||||||
|
/// <see cref="Double.PositiveInfinity"/> and <see cref="Double.NegativeInfinity"/>,
|
||||||
|
/// are written as JSON.
|
||||||
|
/// The default value is <see cref="Json.FloatFormatHandling.String" />.
|
||||||
|
/// </summary>
|
||||||
|
public FloatFormatHandling FloatFormatHandling
|
||||||
|
{
|
||||||
|
get => _floatFormatHandling ?? DefaultFloatFormatHandling;
|
||||||
|
set => _floatFormatHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how floating point numbers, e.g. 1.0 and 9.9, are parsed when reading JSON text.
|
||||||
|
/// The default value is <see cref="Json.FloatParseHandling.Double" />.
|
||||||
|
/// </summary>
|
||||||
|
public FloatParseHandling FloatParseHandling
|
||||||
|
{
|
||||||
|
get => _floatParseHandling ?? DefaultFloatParseHandling;
|
||||||
|
set => _floatParseHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how strings are escaped when writing JSON text.
|
||||||
|
/// The default value is <see cref="Json.StringEscapeHandling.Default" />.
|
||||||
|
/// </summary>
|
||||||
|
public StringEscapeHandling StringEscapeHandling
|
||||||
|
{
|
||||||
|
get => _stringEscapeHandling ?? DefaultStringEscapeHandling;
|
||||||
|
set => _stringEscapeHandling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the culture used when reading JSON.
|
||||||
|
/// The default value is <see cref="CultureInfo.InvariantCulture"/>.
|
||||||
|
/// </summary>
|
||||||
|
public CultureInfo Culture
|
||||||
|
{
|
||||||
|
get => _culture ?? DefaultCulture;
|
||||||
|
set => _culture = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether there will be a check for additional content after deserializing an object.
|
||||||
|
/// The default value is <c>false</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if there will be a check for additional content after deserializing an object; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
public bool CheckAdditionalContent
|
||||||
|
{
|
||||||
|
get => _checkAdditionalContent ?? DefaultCheckAdditionalContent;
|
||||||
|
set => _checkAdditionalContent = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JsonSerializerSettings()
|
||||||
|
{
|
||||||
|
DefaultContext = new StreamingContext();
|
||||||
|
DefaultCulture = CultureInfo.InvariantCulture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonSerializerSettings"/> class.
|
||||||
|
/// </summary>
|
||||||
|
[DebuggerStepThrough]
|
||||||
|
public JsonSerializerSettings()
|
||||||
|
{
|
||||||
|
Converters = new List<JsonConverter>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
|
||||||
|
/// </summary>
|
||||||
|
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<char>? _arrayPool;
|
||||||
|
private char[]? _indentChars;
|
||||||
|
|
||||||
|
private Base64Encoder Base64Encoder
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_base64Encoder == null)
|
||||||
|
{
|
||||||
|
_base64Encoder = new Base64Encoder(_writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _base64Encoder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the writer's character array pool.
|
||||||
|
/// </summary>
|
||||||
|
public IArrayPool<char>? ArrayPool
|
||||||
|
{
|
||||||
|
get => _arrayPool;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_arrayPool = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how many <see cref="JsonTextWriter.IndentChar"/>s to write for each level in the hierarchy when <see cref="JsonWriter.Formatting"/> is set to <see cref="Formatting.Indented"/>.
|
||||||
|
/// </summary>
|
||||||
|
public int Indentation
|
||||||
|
{
|
||||||
|
get => _indentation;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Indentation value must be greater than 0.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_indentation = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets which character to use to quote attribute values.
|
||||||
|
/// </summary>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets which character to use for indenting when <see cref="JsonWriter.Formatting"/> is set to <see cref="Formatting.Indented"/>.
|
||||||
|
/// </summary>
|
||||||
|
public char IndentChar
|
||||||
|
{
|
||||||
|
get => _indentChar;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _indentChar)
|
||||||
|
{
|
||||||
|
_indentChar = value;
|
||||||
|
_indentChars = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether object names will be surrounded with quotes.
|
||||||
|
/// </summary>
|
||||||
|
public bool QuoteName
|
||||||
|
{
|
||||||
|
get => _quoteName;
|
||||||
|
set => _quoteName = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonTextWriter"/> class using the specified <see cref="TextWriter"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="textWriter">The <see cref="TextWriter"/> to write to.</param>
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flushes whatever is in the buffer to the underlying <see cref="TextWriter"/> and also flushes the underlying <see cref="TextWriter"/>.
|
||||||
|
/// </summary>
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
_writer.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Closes this writer.
|
||||||
|
/// If <see cref="JsonWriter.CloseOutput"/> is set to <c>true</c>, the underlying <see cref="TextWriter"/> is also closed.
|
||||||
|
/// If <see cref="JsonWriter.AutoCompleteOnClose"/> is set to <c>true</c>, the JSON is auto-completed.
|
||||||
|
/// </summary>
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the beginning of a JSON object.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteStartObject()
|
||||||
|
{
|
||||||
|
InternalWriteStart(JsonToken.StartObject, JsonContainerType.Object);
|
||||||
|
|
||||||
|
_writer.Write('{');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the beginning of a JSON array.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteStartArray()
|
||||||
|
{
|
||||||
|
InternalWriteStart(JsonToken.StartArray, JsonContainerType.Array);
|
||||||
|
|
||||||
|
_writer.Write('[');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the start of a constructor with the given name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the constructor.</param>
|
||||||
|
public override void WriteStartConstructor(string name)
|
||||||
|
{
|
||||||
|
InternalWriteStart(JsonToken.StartConstructor, JsonContainerType.Constructor);
|
||||||
|
|
||||||
|
_writer.Write("new ");
|
||||||
|
_writer.Write(name);
|
||||||
|
_writer.Write('(');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the specified end token.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">The end token to write.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the property name of a name/value pair on a JSON object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the property.</param>
|
||||||
|
public override void WritePropertyName(string name)
|
||||||
|
{
|
||||||
|
InternalWritePropertyName(name);
|
||||||
|
|
||||||
|
WriteEscapedString(name, _quoteName);
|
||||||
|
|
||||||
|
_writer.Write(':');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the property name of a name/value pair on a JSON object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the property.</param>
|
||||||
|
/// <param name="escape">A flag to indicate whether the text should be escaped when it is written as a JSON property name.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes indent characters.
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON value delimiter.
|
||||||
|
/// </summary>
|
||||||
|
protected override void WriteValueDelimiter()
|
||||||
|
{
|
||||||
|
_writer.Write(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an indent space.
|
||||||
|
/// </summary>
|
||||||
|
protected override void WriteIndentSpace()
|
||||||
|
{
|
||||||
|
_writer.Write(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteValueInternal(string value, JsonToken token)
|
||||||
|
{
|
||||||
|
_writer.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region WriteValue methods
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Object"/> value.
|
||||||
|
/// An error will raised if the value cannot be written as a single JSON token.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Object"/> value to write.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a null value.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteNull()
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Null);
|
||||||
|
WriteValueInternal(JsonConvert.Null, JsonToken.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an undefined value.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteUndefined()
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Undefined);
|
||||||
|
WriteValueInternal(JsonConvert.Undefined, JsonToken.Undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes raw JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">The raw JSON to write.</param>
|
||||||
|
public override void WriteRaw(string? json)
|
||||||
|
{
|
||||||
|
InternalWriteRaw();
|
||||||
|
|
||||||
|
_writer.Write(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="String"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="String"/> value to write.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Int32"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Int32"/> value to write.</param>
|
||||||
|
public override void WriteValue(int value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Integer);
|
||||||
|
WriteIntegerValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="UInt32"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="UInt32"/> value to write.</param>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void WriteValue(uint value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Integer);
|
||||||
|
WriteIntegerValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Int64"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Int64"/> value to write.</param>
|
||||||
|
public override void WriteValue(long value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Integer);
|
||||||
|
WriteIntegerValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="UInt64"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="UInt64"/> value to write.</param>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void WriteValue(ulong value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Integer);
|
||||||
|
WriteIntegerValue(value, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Single"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Single"/> value to write.</param>
|
||||||
|
public override void WriteValue(float value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Float);
|
||||||
|
WriteValueInternal(JsonConvert.ToString(value, FloatFormatHandling, QuoteChar, false), JsonToken.Float);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Nullable{T}"/> of <see cref="Single"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Single"/> value to write.</param>
|
||||||
|
public override void WriteValue(float? value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
WriteNull();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Float);
|
||||||
|
WriteValueInternal(JsonConvert.ToString(value.GetValueOrDefault(), FloatFormatHandling, QuoteChar, true), JsonToken.Float);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Double"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Double"/> value to write.</param>
|
||||||
|
public override void WriteValue(double value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Float);
|
||||||
|
WriteValueInternal(JsonConvert.ToString(value, FloatFormatHandling, QuoteChar, false), JsonToken.Float);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Nullable{T}"/> of <see cref="Double"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Double"/> value to write.</param>
|
||||||
|
public override void WriteValue(double? value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
WriteNull();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Float);
|
||||||
|
WriteValueInternal(JsonConvert.ToString(value.GetValueOrDefault(), FloatFormatHandling, QuoteChar, true), JsonToken.Float);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Boolean"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Boolean"/> value to write.</param>
|
||||||
|
public override void WriteValue(bool value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Boolean);
|
||||||
|
WriteValueInternal(JsonConvert.ToString(value), JsonToken.Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Int16"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Int16"/> value to write.</param>
|
||||||
|
public override void WriteValue(short value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Integer);
|
||||||
|
WriteIntegerValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="UInt16"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="UInt16"/> value to write.</param>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void WriteValue(ushort value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Integer);
|
||||||
|
WriteIntegerValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Char"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Char"/> value to write.</param>
|
||||||
|
public override void WriteValue(char value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.String);
|
||||||
|
WriteValueInternal(JsonConvert.ToString(value), JsonToken.String);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Byte"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Byte"/> value to write.</param>
|
||||||
|
public override void WriteValue(byte value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Integer);
|
||||||
|
WriteIntegerValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="SByte"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="SByte"/> value to write.</param>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void WriteValue(sbyte value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Integer);
|
||||||
|
WriteIntegerValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Decimal"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Decimal"/> value to write.</param>
|
||||||
|
public override void WriteValue(decimal value)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Float);
|
||||||
|
WriteValueInternal(JsonConvert.ToString(value), JsonToken.Float);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="DateTime"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="DateTime"/> value to write.</param>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Byte"/>[] value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Byte"/>[] value to write.</param>
|
||||||
|
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
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="DateTimeOffset"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="DateTimeOffset"/> value to write.</param>
|
||||||
|
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
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Guid"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Guid"/> value to write.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="TimeSpan"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="TimeSpan"/> value to write.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Uri"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Uri"/> value to write.</param>
|
||||||
|
public override void WriteValue(Uri? value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
WriteNull();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.String);
|
||||||
|
WriteEscapedString(value.OriginalString, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a comment <c>/*...*/</c> containing the specified text.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">Text to place inside the comment.</param>
|
||||||
|
public override void WriteComment(string? text)
|
||||||
|
{
|
||||||
|
InternalWriteComment();
|
||||||
|
|
||||||
|
_writer.Write("/*");
|
||||||
|
_writer.Write(text);
|
||||||
|
_writer.Write("*/");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the given white space.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ws">The string of white space characters.</param>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the type of JSON token.
|
||||||
|
/// </summary>
|
||||||
|
public enum JsonToken
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This is returned by the <see cref="JsonReader"/> if a read method has not been called.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An object start token.
|
||||||
|
/// </summary>
|
||||||
|
StartObject = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An array start token.
|
||||||
|
/// </summary>
|
||||||
|
StartArray = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A constructor start token.
|
||||||
|
/// </summary>
|
||||||
|
StartConstructor = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An object property name.
|
||||||
|
/// </summary>
|
||||||
|
PropertyName = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A comment.
|
||||||
|
/// </summary>
|
||||||
|
Comment = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raw JSON.
|
||||||
|
/// </summary>
|
||||||
|
Raw = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An integer.
|
||||||
|
/// </summary>
|
||||||
|
Integer = 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A float.
|
||||||
|
/// </summary>
|
||||||
|
Float = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A string.
|
||||||
|
/// </summary>
|
||||||
|
String = 9,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A boolean.
|
||||||
|
/// </summary>
|
||||||
|
Boolean = 10,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A null token.
|
||||||
|
/// </summary>
|
||||||
|
Null = 11,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An undefined token.
|
||||||
|
/// </summary>
|
||||||
|
Undefined = 12,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An object end token.
|
||||||
|
/// </summary>
|
||||||
|
EndObject = 13,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An array end token.
|
||||||
|
/// </summary>
|
||||||
|
EndArray = 14,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A constructor end token.
|
||||||
|
/// </summary>
|
||||||
|
EndConstructor = 15,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A Date.
|
||||||
|
/// </summary>
|
||||||
|
Date = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Byte data.
|
||||||
|
/// </summary>
|
||||||
|
Bytes = 17
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The exception thrown when an error occurs while writing JSON text.
|
||||||
|
/// </summary>
|
||||||
|
#if HAVE_BINARY_EXCEPTION_SERIALIZATION
|
||||||
|
[Serializable]
|
||||||
|
#endif
|
||||||
|
public class JsonWriterException : JsonException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the JSON where the error occurred.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The path to the JSON where the error occurred.</value>
|
||||||
|
public string? Path { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonWriterException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JsonWriterException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonWriterException"/> class
|
||||||
|
/// with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
public JsonWriterException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonWriterException"/> class
|
||||||
|
/// with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or <c>null</c> if no inner exception is specified.</param>
|
||||||
|
public JsonWriterException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_BINARY_EXCEPTION_SERIALIZATION
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonWriterException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
|
||||||
|
/// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">The <paramref name="info"/> parameter is <c>null</c>.</exception>
|
||||||
|
/// <exception cref="SerializationException">The class name is <c>null</c> or <see cref="Exception.HResult"/> is zero (0).</exception>
|
||||||
|
public JsonWriterException(SerializationInfo info, StreamingContext context)
|
||||||
|
: base(info, context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonWriterException"/> class
|
||||||
|
/// with a specified error message, JSON path and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="path">The path to the JSON where the error occurred.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or <c>null</c> if no inner exception is specified.</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<UnityBuild>AOT</UnityBuild>
|
||||||
|
<TargetFrameworks Condition="'$(LibraryFrameworks)'==''">netstandard2.0</TargetFrameworks>
|
||||||
|
<TargetFrameworks Condition="'$(LibraryFrameworks)'!=''">$(LibraryFrameworks)</TargetFrameworks>
|
||||||
|
<LangVersion>9.0</LangVersion>
|
||||||
|
<!-- version numbers will be updated by build -->
|
||||||
|
<AssemblyVersion>11.0.0.0</AssemblyVersion>
|
||||||
|
<FileVersion>11.0.1</FileVersion>
|
||||||
|
<VersionPrefix>11.0.1</VersionPrefix>
|
||||||
|
<VersionSuffix>beta2</VersionSuffix>
|
||||||
|
<Authors>James Newton-King</Authors>
|
||||||
|
<Company>Newtonsoft</Company>
|
||||||
|
<Product>Json.NET</Product>
|
||||||
|
<Description>Json.NET is a popular high-performance JSON framework for .NET</Description>
|
||||||
|
<Copyright>Copyright © James Newton-King 2008</Copyright>
|
||||||
|
<Summary>Json.NET is a popular high-performance JSON framework for .NET</Summary>
|
||||||
|
<NeutralLanguage>en-US</NeutralLanguage>
|
||||||
|
<Title>Json.NET for Unity</Title>
|
||||||
|
<PackageId>LC.Newtonsoft.Json</PackageId>
|
||||||
|
<PackageTags>json</PackageTags>
|
||||||
|
<PackageIcon>packageIcon.png</PackageIcon>
|
||||||
|
<PackageIconFullPath>$(MSBuildThisFileDirectory)packageIcon.png</PackageIconFullPath>
|
||||||
|
<PackageProjectUrl>https://www.newtonsoft.com/json</PackageProjectUrl>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
|
<RootNamespace>LC.Newtonsoft.Json</RootNamespace>
|
||||||
|
<AssemblyName>LC.Newtonsoft.Json</AssemblyName>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<MinClientVersion>2.12</MinClientVersion>
|
||||||
|
<!-- force legacy .pdb format for Mono's pdb2mdb -->
|
||||||
|
<DebugType>Full</DebugType>
|
||||||
|
<!-- including PDB files in NuGet for source link because symbolsource.org does not support portable PDBs -->
|
||||||
|
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<ReleaseVersion>0.7.1</ReleaseVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="**\*.orig" />
|
||||||
|
<EmbeddedResource Include="Resources\link.xml">
|
||||||
|
<LogicalName>Newtonsoft.Json.xml</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<None Include="..\..\LICENSE.md" Pack="true" PackagePath="LICENSE.md" />
|
||||||
|
<None Include="$(PackageIconFullPath)" Pack="true" PackagePath="\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="$(MicrosoftCodeAnalysisNetAnalyzersPackageVersion)" PrivateAssets="All" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Condition="'$(UnityBuild)'=='Tests' OR ('$(UnityBuild)'=='' AND '$(TargetFramework)'=='net46')">
|
||||||
|
<!-- Only used in Unity Tests & Newtonsoft.Json.Tests -->
|
||||||
|
<TargetFramework>net46</TargetFramework>
|
||||||
|
<AssemblyTitle>Json.NET for Unity tests (NOT FOR PRODUCTION)</AssemblyTitle>
|
||||||
|
<DefineConstants>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)</DefineConstants>
|
||||||
|
<OutputPath>bin\$(Configuration)\unity-tests</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(UnityBuild)'=='Editor' OR ('$(UnityBuild)'=='' AND '$(TargetFramework)'=='netstandard2.0')">
|
||||||
|
<!-- Only used in Editor -->
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<AssemblyTitle>Json.NET for Unity Editor (NOT FOR PRODUCTION)</AssemblyTitle>
|
||||||
|
<DefineConstants>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)</DefineConstants>
|
||||||
|
<OutputPath>bin\$(Configuration)\unity-editor</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(UnityBuild)'=='Standalone'">
|
||||||
|
<!-- Unity standalone build -->
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<AssemblyTitle>Json.NET for Unity standalone (Win, OS X, Linux)</AssemblyTitle>
|
||||||
|
<DefineConstants>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)</DefineConstants>
|
||||||
|
<OutputPath>bin\$(Configuration)\unity-standalone</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(UnityBuild)'=='AOT'">
|
||||||
|
<!-- Unity AOT (IL2CPP) build -->
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<AssemblyTitle>Json.NET for Unity AOT (IL2CPP)</AssemblyTitle>
|
||||||
|
<DefineConstants>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)</DefineConstants>
|
||||||
|
<OutputPath>bin\$(Configuration)\unity-aot</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DefineConstants>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)</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies how JSON comments are handled when loading JSON.
|
||||||
|
/// </summary>
|
||||||
|
public enum CommentHandling
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore comments.
|
||||||
|
/// </summary>
|
||||||
|
Ignore = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load comments as a <see cref="JValue"/> with type <see cref="JTokenType.Comment"/>.
|
||||||
|
/// </summary>
|
||||||
|
Load = 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies how duplicate property names are handled when loading JSON.
|
||||||
|
/// </summary>
|
||||||
|
public enum DuplicatePropertyNameHandling
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Replace the existing value when there is a duplicate property. The value of the last property in the JSON object will be used.
|
||||||
|
/// </summary>
|
||||||
|
Replace = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore the new value when there is a duplicate property. The value of the first property in the JSON object will be used.
|
||||||
|
/// </summary>
|
||||||
|
Ignore = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// Throw a <see cref="JsonReaderException"/> when a duplicate property is encountered.
|
||||||
|
/// </summary>
|
||||||
|
Error = 2
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the LINQ to JSON extension methods.
|
||||||
|
/// </summary>
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of tokens that contains the ancestors of every token in the source collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the objects in source, constrained to <see cref="JToken"/>.</typeparam>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the ancestors of every token in the source collection.</returns>
|
||||||
|
public static IJEnumerable<JToken> Ancestors<T>(this IEnumerable<T> source) where T : JToken
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(source, nameof(source));
|
||||||
|
|
||||||
|
return source.SelectMany(j => j.Ancestors()).AsJEnumerable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of tokens that contains every token in the source collection, and the ancestors of every token in the source collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the objects in source, constrained to <see cref="JToken"/>.</typeparam>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains every token in the source collection, the ancestors of every token in the source collection.</returns>
|
||||||
|
public static IJEnumerable<JToken> AncestorsAndSelf<T>(this IEnumerable<T> source) where T : JToken
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(source, nameof(source));
|
||||||
|
|
||||||
|
return source.SelectMany(j => j.AncestorsAndSelf()).AsJEnumerable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of tokens that contains the descendants of every token in the source collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the objects in source, constrained to <see cref="JContainer"/>.</typeparam>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the descendants of every token in the source collection.</returns>
|
||||||
|
public static IJEnumerable<JToken> Descendants<T>(this IEnumerable<T> source) where T : JContainer
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(source, nameof(source));
|
||||||
|
|
||||||
|
return source.SelectMany(j => j.Descendants()).AsJEnumerable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of tokens that contains every token in the source collection, and the descendants of every token in the source collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the objects in source, constrained to <see cref="JContainer"/>.</typeparam>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains every token in the source collection, and the descendants of every token in the source collection.</returns>
|
||||||
|
public static IJEnumerable<JToken> DescendantsAndSelf<T>(this IEnumerable<T> source) where T : JContainer
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(source, nameof(source));
|
||||||
|
|
||||||
|
return source.SelectMany(j => j.DescendantsAndSelf()).AsJEnumerable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of child properties of every object in the source collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JObject"/> that contains the source collection.</param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JProperty"/> that contains the properties of every object in the source collection.</returns>
|
||||||
|
public static IJEnumerable<JProperty> Properties(this IEnumerable<JObject> source)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(source, nameof(source));
|
||||||
|
|
||||||
|
return source.SelectMany(d => d.Properties()).AsJEnumerable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of child values of every object in the source collection with the given key.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <param name="key">The token key.</param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the values of every token in the source collection with the given key.</returns>
|
||||||
|
public static IJEnumerable<JToken> Values(this IEnumerable<JToken> source, object? key)
|
||||||
|
{
|
||||||
|
return Values<JToken, JToken>(source, key)!.AsJEnumerable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of child values of every object in the source collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the values of every token in the source collection.</returns>
|
||||||
|
public static IJEnumerable<JToken> Values(this IEnumerable<JToken> source)
|
||||||
|
{
|
||||||
|
return source.Values(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of converted child values of every object in the source collection with the given key.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="U">The type to convert the values to.</typeparam>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <param name="key">The token key.</param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> that contains the converted values of every token in the source collection with the given key.</returns>
|
||||||
|
public static IEnumerable<U?> Values<U>(this IEnumerable<JToken> source, object key)
|
||||||
|
{
|
||||||
|
return Values<JToken, U>(source, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of converted child values of every object in the source collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="U">The type to convert the values to.</typeparam>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> that contains the converted values of every token in the source collection.</returns>
|
||||||
|
public static IEnumerable<U?> Values<U>(this IEnumerable<JToken> source)
|
||||||
|
{
|
||||||
|
return Values<JToken, U>(source, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="U">The type to convert the value to.</typeparam>
|
||||||
|
/// <param name="value">A <see cref="JToken"/> cast as a <see cref="IEnumerable{T}"/> of <see cref="JToken"/>.</param>
|
||||||
|
/// <returns>A converted value.</returns>
|
||||||
|
public static U? Value<U>(this IEnumerable<JToken> value)
|
||||||
|
{
|
||||||
|
return value.Value<JToken, U>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The source collection type.</typeparam>
|
||||||
|
/// <typeparam name="U">The type to convert the value to.</typeparam>
|
||||||
|
/// <param name="value">A <see cref="JToken"/> cast as a <see cref="IEnumerable{T}"/> of <see cref="JToken"/>.</param>
|
||||||
|
/// <returns>A converted value.</returns>
|
||||||
|
public static U? Value<T, U>(this IEnumerable<T> 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<JToken, U>();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static IEnumerable<U?> Values<T, U>(this IEnumerable<T> 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<JValue, U>(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (JToken t in token.Children())
|
||||||
|
{
|
||||||
|
yield return t.Convert<JToken, U>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (T token in source)
|
||||||
|
{
|
||||||
|
JToken? value = token[key];
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
yield return value.Convert<JToken, U>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//public static IEnumerable<T> InDocumentOrder<T>(this IEnumerable<T> source) where T : JObject;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of child tokens of every array in the source collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The source collection type.</typeparam>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the values of every token in the source collection.</returns>
|
||||||
|
public static IJEnumerable<JToken> Children<T>(this IEnumerable<T> source) where T : JToken
|
||||||
|
{
|
||||||
|
return Children<T, JToken>(source)!.AsJEnumerable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of converted child tokens of every array in the source collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <typeparam name="U">The type to convert the values to.</typeparam>
|
||||||
|
/// <typeparam name="T">The source collection type.</typeparam>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> that contains the converted values of every token in the source collection.</returns>
|
||||||
|
public static IEnumerable<U?> Children<T, U>(this IEnumerable<T> source) where T : JToken
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(source, nameof(source));
|
||||||
|
|
||||||
|
return source.SelectMany(c => c.Children()).Convert<JToken, U>();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static IEnumerable<U?> Convert<T, U>(this IEnumerable<T> source) where T : JToken
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(source, nameof(source));
|
||||||
|
|
||||||
|
foreach (T token in source)
|
||||||
|
{
|
||||||
|
yield return Convert<JToken, U>(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static U? Convert<T, U>(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<T>(this IEnumerable<T> source) where T : JContainer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the input typed as <see cref="IJEnumerable{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <returns>The input typed as <see cref="IJEnumerable{T}"/>.</returns>
|
||||||
|
public static IJEnumerable<JToken> AsJEnumerable(this IEnumerable<JToken> source)
|
||||||
|
{
|
||||||
|
return source.AsJEnumerable<JToken>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the input typed as <see cref="IJEnumerable{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The source collection type.</typeparam>
|
||||||
|
/// <param name="source">An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the source collection.</param>
|
||||||
|
/// <returns>The input typed as <see cref="IJEnumerable{T}"/>.</returns>
|
||||||
|
public static IJEnumerable<T> AsJEnumerable<T>(this IEnumerable<T> source) where T : JToken
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
return null!;
|
||||||
|
}
|
||||||
|
else if (source is IJEnumerable<T> customEnumerable)
|
||||||
|
{
|
||||||
|
return customEnumerable;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new JEnumerable<T>(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.Collections.Generic;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a collection of <see cref="JToken"/> objects.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of token.</typeparam>
|
||||||
|
public interface IJEnumerable<
|
||||||
|
#if HAVE_VARIANT_TYPE_PARAMETERS
|
||||||
|
out
|
||||||
|
#endif
|
||||||
|
T> : IEnumerable<T> where T : JToken
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="IJEnumerable{T}"/> of <see cref="JToken"/> with the specified key.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
IJEnumerable<JToken> this[object key] { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
#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.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
public partial class JArray
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes this token to a <see cref="JsonWriter"/> asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
||||||
|
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> that represents the asynchronous write operation.</returns>
|
||||||
|
public override async Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
await writer.WriteStartArrayAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
for (int i = 0; i < _values.Count; i++)
|
||||||
|
{
|
||||||
|
await _values[i].WriteToAsync(writer, cancellationToken, converters).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
await writer.WriteEndArrayAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously loads a <see cref="JArray"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JArray"/>.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> representing the asynchronous load. The <see cref="Task{TResult}.Result"/> property contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static Task<JArray> LoadAsync(JsonReader reader, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return LoadAsync(reader, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously loads a <see cref="JArray"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JArray"/>.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> representing the asynchronous load. The <see cref="Task{TResult}.Result"/> property contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static async Task<JArray> LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonToken.None)
|
||||||
|
{
|
||||||
|
if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JArray from JsonReader.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await reader.MoveToContentAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (reader.TokenType != JsonToken.StartArray)
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JArray from JsonReader. Current JsonReader item is not an array: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||||
|
}
|
||||||
|
|
||||||
|
JArray a = new JArray();
|
||||||
|
a.SetLineInfo(reader as IJsonLineInfo, settings);
|
||||||
|
|
||||||
|
await a.ReadTokenFromAsync(reader, settings, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,403 @@
|
||||||
|
#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 LC.Newtonsoft.Json.Utilities;
|
||||||
|
using System.IO;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a JSON array.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>
|
||||||
|
/// <code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\LinqToJsonTests.cs" region="LinqToJsonCreateParseArray" title="Parsing a JSON Array from Text" />
|
||||||
|
/// </example>
|
||||||
|
public partial class JArray : JContainer, IList<JToken>
|
||||||
|
{
|
||||||
|
private readonly List<JToken> _values = new List<JToken>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the container's children tokens.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The container's children tokens.</value>
|
||||||
|
protected override IList<JToken> ChildrenTokens => _values;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the node type for this <see cref="JToken"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type.</value>
|
||||||
|
public override JTokenType Type => JTokenType.Array;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JArray"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JArray()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JArray"/> class from another <see cref="JArray"/> object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">A <see cref="JArray"/> object to copy from.</param>
|
||||||
|
public JArray(JArray other)
|
||||||
|
: base(other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JArray"/> class with the specified content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">The contents of the array.</param>
|
||||||
|
public JArray(params object[] content)
|
||||||
|
: this((object)content)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JArray"/> class with the specified content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">The contents of the array.</param>
|
||||||
|
public JArray(object content)
|
||||||
|
{
|
||||||
|
Add(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override bool DeepEquals(JToken node)
|
||||||
|
{
|
||||||
|
return (node is JArray t && ContentsEqual(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override JToken CloneToken()
|
||||||
|
{
|
||||||
|
return new JArray(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads an <see cref="JArray"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JArray"/>.</param>
|
||||||
|
/// <returns>A <see cref="JArray"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static JArray Load(JsonReader reader)
|
||||||
|
{
|
||||||
|
return Load(reader, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads an <see cref="JArray"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JArray"/>.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <returns>A <see cref="JArray"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static JArray Load(JsonReader reader, JsonLoadSettings? settings)
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonToken.None)
|
||||||
|
{
|
||||||
|
if (!reader.Read())
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JArray from JsonReader.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.MoveToContent();
|
||||||
|
|
||||||
|
if (reader.TokenType != JsonToken.StartArray)
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JArray from JsonReader. Current JsonReader item is not an array: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||||
|
}
|
||||||
|
|
||||||
|
JArray a = new JArray();
|
||||||
|
a.SetLineInfo(reader as IJsonLineInfo, settings);
|
||||||
|
|
||||||
|
a.ReadTokenFrom(reader, settings);
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load a <see cref="JArray"/> from a string that contains JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">A <see cref="String"/> that contains JSON.</param>
|
||||||
|
/// <returns>A <see cref="JArray"/> populated from the string that contains JSON.</returns>
|
||||||
|
/// <example>
|
||||||
|
/// <code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\LinqToJsonTests.cs" region="LinqToJsonCreateParseArray" title="Parsing a JSON Array from Text" />
|
||||||
|
/// </example>
|
||||||
|
public new static JArray Parse(string json)
|
||||||
|
{
|
||||||
|
return Parse(json, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load a <see cref="JArray"/> from a string that contains JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">A <see cref="String"/> that contains JSON.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <returns>A <see cref="JArray"/> populated from the string that contains JSON.</returns>
|
||||||
|
/// <example>
|
||||||
|
/// <code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\LinqToJsonTests.cs" region="LinqToJsonCreateParseArray" title="Parsing a JSON Array from Text" />
|
||||||
|
/// </example>
|
||||||
|
public new static JArray Parse(string json, JsonLoadSettings? settings)
|
||||||
|
{
|
||||||
|
using (JsonReader reader = new JsonTextReader(new StringReader(json)))
|
||||||
|
{
|
||||||
|
JArray a = Load(reader, settings);
|
||||||
|
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
// Any content encountered here other than a comment will throw in the reader.
|
||||||
|
}
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="JArray"/> from an object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="o">The object that will be used to create <see cref="JArray"/>.</param>
|
||||||
|
/// <returns>A <see cref="JArray"/> with the values of the specified object.</returns>
|
||||||
|
public new static JArray FromObject(object o)
|
||||||
|
{
|
||||||
|
return FromObject(o, JsonSerializer.CreateDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="JArray"/> from an object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="o">The object that will be used to create <see cref="JArray"/>.</param>
|
||||||
|
/// <param name="jsonSerializer">The <see cref="JsonSerializer"/> that will be used to read the object.</param>
|
||||||
|
/// <returns>A <see cref="JArray"/> with the values of the specified object.</returns>
|
||||||
|
public new static JArray FromObject(object o, JsonSerializer jsonSerializer)
|
||||||
|
{
|
||||||
|
JToken token = FromObjectInternal(o, jsonSerializer);
|
||||||
|
|
||||||
|
if (token.Type != JTokenType.Array)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Object serialized to {0}. JArray instance expected.".FormatWith(CultureInfo.InvariantCulture, token.Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (JArray)token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes this token to a <see cref="JsonWriter"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
|
||||||
|
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
|
||||||
|
public override void WriteTo(JsonWriter writer, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
writer.WriteStartArray();
|
||||||
|
|
||||||
|
for (int i = 0; i < _values.Count; i++)
|
||||||
|
{
|
||||||
|
_values[i].WriteTo(writer, converters);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="JToken"/> with the specified key.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The <see cref="JToken"/> with the specified key.</value>
|
||||||
|
public override JToken? this[object key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(key, nameof(key));
|
||||||
|
|
||||||
|
if (!(key is int))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Accessed JArray values with invalid key value: {0}. Int32 array index expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetItem((int)key);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(key, nameof(key));
|
||||||
|
|
||||||
|
if (!(key is int))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Set JArray values with invalid key value: {0}. Int32 array index expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
SetItem((int)key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="Newtonsoft.Json.Linq.JToken"/> at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public JToken this[int index]
|
||||||
|
{
|
||||||
|
get => GetItem(index);
|
||||||
|
set => SetItem(index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override int IndexOfItem(JToken? item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _values.IndexOfReference(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void MergeItem(object content, JsonMergeSettings? settings)
|
||||||
|
{
|
||||||
|
IEnumerable? a = (IsMultiContent(content) || content is JArray)
|
||||||
|
? (IEnumerable)content
|
||||||
|
: null;
|
||||||
|
if (a == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MergeEnumerableContent(this, a, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IList<JToken> Members
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the index of a specific item in the <see cref="JArray"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The object to locate in the <see cref="JArray"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The index of <paramref name="item"/> if found in the list; otherwise, -1.
|
||||||
|
/// </returns>
|
||||||
|
public int IndexOf(JToken item)
|
||||||
|
{
|
||||||
|
return IndexOfItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserts an item to the <see cref="JArray"/> at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
|
||||||
|
/// <param name="item">The object to insert into the <see cref="JArray"/>.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">
|
||||||
|
/// <paramref name="index"/> is not a valid index in the <see cref="JArray"/>.
|
||||||
|
/// </exception>
|
||||||
|
public void Insert(int index, JToken item)
|
||||||
|
{
|
||||||
|
InsertItem(index, item, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the <see cref="JArray"/> item at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The zero-based index of the item to remove.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">
|
||||||
|
/// <paramref name="index"/> is not a valid index in the <see cref="JArray"/>.
|
||||||
|
/// </exception>
|
||||||
|
public void RemoveAt(int index)
|
||||||
|
{
|
||||||
|
RemoveItemAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator that iterates through the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="IEnumerator{T}"/> of <see cref="JToken"/> that can be used to iterate through the collection.
|
||||||
|
/// </returns>
|
||||||
|
public IEnumerator<JToken> GetEnumerator()
|
||||||
|
{
|
||||||
|
return Children().GetEnumerator();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ICollection<JToken> Members
|
||||||
|
/// <summary>
|
||||||
|
/// Adds an item to the <see cref="JArray"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The object to add to the <see cref="JArray"/>.</param>
|
||||||
|
public void Add(JToken item)
|
||||||
|
{
|
||||||
|
Add((object)item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all items from the <see cref="JArray"/>.
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
ClearItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the <see cref="JArray"/> contains a specific value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The object to locate in the <see cref="JArray"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if <paramref name="item"/> is found in the <see cref="JArray"/>; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public bool Contains(JToken item)
|
||||||
|
{
|
||||||
|
return ContainsItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the elements of the <see cref="JArray"/> to an array, starting at a particular array index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">The array.</param>
|
||||||
|
/// <param name="arrayIndex">Index of the array.</param>
|
||||||
|
public void CopyTo(JToken[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
CopyItemsTo(array, arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the <see cref="JArray"/> is read-only.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><c>true</c> if the <see cref="JArray"/> is read-only; otherwise, <c>false</c>.</returns>
|
||||||
|
public bool IsReadOnly => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the first occurrence of a specific object from the <see cref="JArray"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The object to remove from the <see cref="JArray"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if <paramref name="item"/> was successfully removed from the <see cref="JArray"/>; otherwise, <c>false</c>. This method also returns <c>false</c> if <paramref name="item"/> is not found in the original <see cref="JArray"/>.
|
||||||
|
/// </returns>
|
||||||
|
public bool Remove(JToken item)
|
||||||
|
{
|
||||||
|
return RemoveItem(item);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
internal override int GetDeepHashCode()
|
||||||
|
{
|
||||||
|
return ContentsHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
#if HAVE_ASYNC
|
||||||
|
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
public partial class JConstructor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes this token to a <see cref="JsonWriter"/> asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
||||||
|
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> that represents the asynchronous write operation.</returns>
|
||||||
|
public override async Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
await writer.WriteStartConstructorAsync(_name ?? string.Empty, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
for (int i = 0; i < _values.Count; i++)
|
||||||
|
{
|
||||||
|
await _values[i].WriteToAsync(writer, cancellationToken, converters).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
await writer.WriteEndConstructorAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously loads a <see cref="JConstructor"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JConstructor"/>.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Task{TResult}"/> that represents the asynchronous load. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns a <see cref="JConstructor"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static Task<JConstructor> LoadAsync(JsonReader reader, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return LoadAsync(reader, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously loads a <see cref="JConstructor"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JConstructor"/>.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Task{TResult}"/> that represents the asynchronous load. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns a <see cref="JConstructor"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static async Task<JConstructor> LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonToken.None)
|
||||||
|
{
|
||||||
|
if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JConstructor from JsonReader.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await reader.MoveToContentAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (reader.TokenType != JsonToken.StartConstructor)
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JConstructor from JsonReader. Current JsonReader item is not a constructor: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||||
|
}
|
||||||
|
|
||||||
|
JConstructor c = new JConstructor((string)reader.Value!);
|
||||||
|
c.SetLineInfo(reader as IJsonLineInfo, settings);
|
||||||
|
|
||||||
|
await c.ReadTokenFromAsync(reader, settings, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,250 @@
|
||||||
|
#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 LC.Newtonsoft.Json.Utilities;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a JSON constructor.
|
||||||
|
/// </summary>
|
||||||
|
public partial class JConstructor : JContainer
|
||||||
|
{
|
||||||
|
private string? _name;
|
||||||
|
private readonly List<JToken> _values = new List<JToken>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the container's children tokens.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The container's children tokens.</value>
|
||||||
|
protected override IList<JToken> ChildrenTokens => _values;
|
||||||
|
|
||||||
|
internal override int IndexOfItem(JToken? item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _values.IndexOfReference(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void MergeItem(object content, JsonMergeSettings? settings)
|
||||||
|
{
|
||||||
|
if (!(content is JConstructor c))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.Name != null)
|
||||||
|
{
|
||||||
|
Name = c.Name;
|
||||||
|
}
|
||||||
|
MergeEnumerableContent(this, c, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the name of this constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The constructor name.</value>
|
||||||
|
public string? Name
|
||||||
|
{
|
||||||
|
get => _name;
|
||||||
|
set => _name = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the node type for this <see cref="JToken"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type.</value>
|
||||||
|
public override JTokenType Type => JTokenType.Constructor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JConstructor"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JConstructor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JConstructor"/> class from another <see cref="JConstructor"/> object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">A <see cref="JConstructor"/> object to copy from.</param>
|
||||||
|
public JConstructor(JConstructor other)
|
||||||
|
: base(other)
|
||||||
|
{
|
||||||
|
_name = other.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JConstructor"/> class with the specified name and content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The constructor name.</param>
|
||||||
|
/// <param name="content">The contents of the constructor.</param>
|
||||||
|
public JConstructor(string name, params object[] content)
|
||||||
|
: this(name, (object)content)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JConstructor"/> class with the specified name and content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The constructor name.</param>
|
||||||
|
/// <param name="content">The contents of the constructor.</param>
|
||||||
|
public JConstructor(string name, object content)
|
||||||
|
: this(name)
|
||||||
|
{
|
||||||
|
Add(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JConstructor"/> class with the specified name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The constructor name.</param>
|
||||||
|
public JConstructor(string name)
|
||||||
|
{
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.Length == 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Constructor name cannot be empty.", nameof(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override bool DeepEquals(JToken node)
|
||||||
|
{
|
||||||
|
return (node is JConstructor c && _name == c.Name && ContentsEqual(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override JToken CloneToken()
|
||||||
|
{
|
||||||
|
return new JConstructor(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes this token to a <see cref="JsonWriter"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
|
||||||
|
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
|
||||||
|
public override void WriteTo(JsonWriter writer, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
writer.WriteStartConstructor(_name!);
|
||||||
|
|
||||||
|
int count = _values.Count;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
_values[i].WriteTo(writer, converters);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndConstructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="JToken"/> with the specified key.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The <see cref="JToken"/> with the specified key.</value>
|
||||||
|
public override JToken? this[object key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(key, nameof(key));
|
||||||
|
|
||||||
|
if (!(key is int i))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Accessed JConstructor values with invalid key value: {0}. Argument position index expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetItem(i);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(key, nameof(key));
|
||||||
|
|
||||||
|
if (!(key is int i))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Set JConstructor values with invalid key value: {0}. Argument position index expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
SetItem(i, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override int GetDeepHashCode()
|
||||||
|
{
|
||||||
|
return (_name?.GetHashCode() ?? 0) ^ ContentsHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads a <see cref="JConstructor"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JConstructor"/>.</param>
|
||||||
|
/// <returns>A <see cref="JConstructor"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static JConstructor Load(JsonReader reader)
|
||||||
|
{
|
||||||
|
return Load(reader, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads a <see cref="JConstructor"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JConstructor"/>.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <returns>A <see cref="JConstructor"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static JConstructor Load(JsonReader reader, JsonLoadSettings? settings)
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonToken.None)
|
||||||
|
{
|
||||||
|
if (!reader.Read())
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JConstructor from JsonReader.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.MoveToContent();
|
||||||
|
|
||||||
|
if (reader.TokenType != JsonToken.StartConstructor)
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JConstructor from JsonReader. Current JsonReader item is not a constructor: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||||
|
}
|
||||||
|
|
||||||
|
JConstructor c = new JConstructor((string)reader.Value!);
|
||||||
|
c.SetLineInfo(reader as IJsonLineInfo, settings);
|
||||||
|
|
||||||
|
c.ReadTokenFrom(reader, settings);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
#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.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
public abstract partial class JContainer
|
||||||
|
{
|
||||||
|
internal async Task ReadTokenFromAsync(JsonReader reader, JsonLoadSettings? options, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(reader, nameof(reader));
|
||||||
|
int startDepth = reader.Depth;
|
||||||
|
|
||||||
|
if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading {0} from JsonReader.".FormatWith(CultureInfo.InvariantCulture, GetType().Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReadContentFromAsync(reader, options, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (reader.Depth > startDepth)
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Unexpected end of content while loading {0}.".FormatWith(CultureInfo.InvariantCulture, GetType().Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
IJsonLineInfo? lineInfo = reader as IJsonLineInfo;
|
||||||
|
|
||||||
|
JContainer? parent = this;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (parent is JProperty p && p.Value != null)
|
||||||
|
{
|
||||||
|
if (parent == this)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
MiscellaneousUtils.Assert(parent != null);
|
||||||
|
|
||||||
|
switch (reader.TokenType)
|
||||||
|
{
|
||||||
|
case JsonToken.None:
|
||||||
|
// new reader. move to actual content
|
||||||
|
break;
|
||||||
|
case JsonToken.StartArray:
|
||||||
|
JArray a = new JArray();
|
||||||
|
a.SetLineInfo(lineInfo, settings);
|
||||||
|
parent.Add(a);
|
||||||
|
parent = a;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonToken.EndArray:
|
||||||
|
if (parent == this)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent.Parent;
|
||||||
|
break;
|
||||||
|
case JsonToken.StartObject:
|
||||||
|
JObject o = new JObject();
|
||||||
|
o.SetLineInfo(lineInfo, settings);
|
||||||
|
parent.Add(o);
|
||||||
|
parent = o;
|
||||||
|
break;
|
||||||
|
case JsonToken.EndObject:
|
||||||
|
if (parent == this)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent.Parent;
|
||||||
|
break;
|
||||||
|
case JsonToken.StartConstructor:
|
||||||
|
JConstructor constructor = new JConstructor(reader.Value!.ToString());
|
||||||
|
constructor.SetLineInfo(lineInfo, settings);
|
||||||
|
parent.Add(constructor);
|
||||||
|
parent = constructor;
|
||||||
|
break;
|
||||||
|
case JsonToken.EndConstructor:
|
||||||
|
if (parent == this)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent.Parent;
|
||||||
|
break;
|
||||||
|
case JsonToken.String:
|
||||||
|
case JsonToken.Integer:
|
||||||
|
case JsonToken.Float:
|
||||||
|
case JsonToken.Date:
|
||||||
|
case JsonToken.Boolean:
|
||||||
|
case JsonToken.Bytes:
|
||||||
|
JValue v = new JValue(reader.Value);
|
||||||
|
v.SetLineInfo(lineInfo, settings);
|
||||||
|
parent.Add(v);
|
||||||
|
break;
|
||||||
|
case JsonToken.Comment:
|
||||||
|
if (settings != null && settings.CommentHandling == CommentHandling.Load)
|
||||||
|
{
|
||||||
|
v = JValue.CreateComment(reader.Value!.ToString());
|
||||||
|
v.SetLineInfo(lineInfo, settings);
|
||||||
|
parent.Add(v);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JsonToken.Null:
|
||||||
|
v = JValue.CreateNull();
|
||||||
|
v.SetLineInfo(lineInfo, settings);
|
||||||
|
parent.Add(v);
|
||||||
|
break;
|
||||||
|
case JsonToken.Undefined:
|
||||||
|
v = JValue.CreateUndefined();
|
||||||
|
v.SetLineInfo(lineInfo, settings);
|
||||||
|
parent.Add(v);
|
||||||
|
break;
|
||||||
|
case JsonToken.PropertyName:
|
||||||
|
JProperty? property = ReadProperty(reader, settings, lineInfo, parent);
|
||||||
|
if (property != null)
|
||||||
|
{
|
||||||
|
parent = property;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await reader.SkipAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("The JsonReader should not be on a token of type {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||||
|
}
|
||||||
|
} while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,140 @@
|
||||||
|
#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_LINQ
|
||||||
|
using LC.Newtonsoft.Json.Utilities.LinqBridge;
|
||||||
|
#else
|
||||||
|
using System.Linq;
|
||||||
|
#endif
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a collection of <see cref="JToken"/> objects.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of token.</typeparam>
|
||||||
|
public readonly struct JEnumerable<T> : IJEnumerable<T>, IEquatable<JEnumerable<T>> where T : JToken
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An empty collection of <see cref="JToken"/> objects.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly JEnumerable<T> Empty = new JEnumerable<T>(Enumerable.Empty<T>());
|
||||||
|
|
||||||
|
private readonly IEnumerable<T> _enumerable;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JEnumerable{T}"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enumerable">The enumerable.</param>
|
||||||
|
public JEnumerable(IEnumerable<T> enumerable)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(enumerable, nameof(enumerable));
|
||||||
|
|
||||||
|
_enumerable = enumerable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator that can be used to iterate through the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.
|
||||||
|
/// </returns>
|
||||||
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
{
|
||||||
|
return (_enumerable ?? Empty).GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="IJEnumerable{T}"/> of <see cref="JToken"/> with the specified key.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public IJEnumerable<JToken> this[object key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_enumerable == null)
|
||||||
|
{
|
||||||
|
return JEnumerable<JToken>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JEnumerable<JToken>(_enumerable.Values<T, JToken>(key)!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified <see cref="JEnumerable{T}"/> is equal to this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The <see cref="JEnumerable{T}"/> to compare with this instance.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if the specified <see cref="JEnumerable{T}"/> is equal to this instance; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public bool Equals(JEnumerable<T> other)
|
||||||
|
{
|
||||||
|
return Equals(_enumerable, other._enumerable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified <see cref="Object"/> is equal to this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The <see cref="Object"/> to compare with this instance.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if the specified <see cref="Object"/> is equal to this instance; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is JEnumerable<T> enumerable)
|
||||||
|
{
|
||||||
|
return Equals(enumerable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a hash code for this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
|
||||||
|
/// </returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
if (_enumerable == null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _enumerable.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
#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;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
public partial class JObject
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes this token to a <see cref="JsonWriter"/> asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
||||||
|
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> that represents the asynchronous write operation.</returns>
|
||||||
|
public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
Task t = writer.WriteStartObjectAsync(cancellationToken);
|
||||||
|
if (!t.IsCompletedSucessfully())
|
||||||
|
{
|
||||||
|
return AwaitProperties(t, 0, writer, cancellationToken, converters);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _properties.Count; i++)
|
||||||
|
{
|
||||||
|
t = _properties[i].WriteToAsync(writer, cancellationToken, converters);
|
||||||
|
if (!t.IsCompletedSucessfully())
|
||||||
|
{
|
||||||
|
return AwaitProperties(t, i + 1, writer, cancellationToken, converters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return writer.WriteEndObjectAsync(cancellationToken);
|
||||||
|
|
||||||
|
// Local functions, params renamed (capitalized) so as not to capture and allocate when calling async
|
||||||
|
async Task AwaitProperties(Task task, int i, JsonWriter Writer, CancellationToken CancellationToken, JsonConverter[] Converters)
|
||||||
|
{
|
||||||
|
await task.ConfigureAwait(false);
|
||||||
|
for (; i < _properties.Count; i++)
|
||||||
|
{
|
||||||
|
await _properties[i].WriteToAsync(Writer, CancellationToken, Converters).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Writer.WriteEndObjectAsync(CancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously loads a <see cref="JObject"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JObject"/>.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Task{TResult}"/> that represents the asynchronous load. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns a <see cref="JObject"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static Task<JObject> LoadAsync(JsonReader reader, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return LoadAsync(reader, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously loads a <see cref="JObject"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JObject"/>.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Task{TResult}"/> that represents the asynchronous load. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns a <see cref="JObject"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static async Task<JObject> LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(reader, nameof(reader));
|
||||||
|
|
||||||
|
if (reader.TokenType == JsonToken.None)
|
||||||
|
{
|
||||||
|
if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JObject from JsonReader.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await reader.MoveToContentAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (reader.TokenType != JsonToken.StartObject)
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JObject from JsonReader. Current JsonReader item is not an object: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||||
|
}
|
||||||
|
|
||||||
|
JObject o = new JObject();
|
||||||
|
o.SetLineInfo(reader as IJsonLineInfo, settings);
|
||||||
|
|
||||||
|
await o.ReadTokenFromAsync(reader, settings, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,857 @@
|
||||||
|
#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_INOTIFY_COLLECTION_CHANGED
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
#endif
|
||||||
|
using System.ComponentModel;
|
||||||
|
#if HAVE_DYNAMIC
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
#endif
|
||||||
|
using System.IO;
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
#if !HAVE_LINQ
|
||||||
|
using LC.Newtonsoft.Json.Utilities.LinqBridge;
|
||||||
|
#else
|
||||||
|
using System.Linq;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a JSON object.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>
|
||||||
|
/// <code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\LinqToJsonTests.cs" region="LinqToJsonCreateParse" title="Parsing a JSON Object from Text" />
|
||||||
|
/// </example>
|
||||||
|
public partial class JObject : JContainer, IDictionary<string, JToken?>, INotifyPropertyChanged
|
||||||
|
#if HAVE_COMPONENT_MODEL
|
||||||
|
, ICustomTypeDescriptor
|
||||||
|
#endif
|
||||||
|
#if HAVE_INOTIFY_PROPERTY_CHANGING
|
||||||
|
, INotifyPropertyChanging
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
private readonly JPropertyKeyedCollection _properties = new JPropertyKeyedCollection();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the container's children tokens.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The container's children tokens.</value>
|
||||||
|
protected override IList<JToken> ChildrenTokens => _properties;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a property value changes.
|
||||||
|
/// </summary>
|
||||||
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
|
#if HAVE_INOTIFY_PROPERTY_CHANGING
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a property value is changing.
|
||||||
|
/// </summary>
|
||||||
|
public event PropertyChangingEventHandler? PropertyChanging;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JObject"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JObject()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JObject"/> class from another <see cref="JObject"/> object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">A <see cref="JObject"/> object to copy from.</param>
|
||||||
|
public JObject(JObject other)
|
||||||
|
: base(other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JObject"/> class with the specified content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">The contents of the object.</param>
|
||||||
|
public JObject(params object[] content)
|
||||||
|
: this((object)content)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JObject"/> class with the specified content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">The contents of the object.</param>
|
||||||
|
public JObject(object content)
|
||||||
|
{
|
||||||
|
Add(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override bool DeepEquals(JToken node)
|
||||||
|
{
|
||||||
|
if (!(node is JObject t))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _properties.Compare(t._properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override int IndexOfItem(JToken? item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _properties.IndexOfReference(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override bool InsertItem(int index, JToken? item, bool skipParentCheck)
|
||||||
|
{
|
||||||
|
// don't add comments to JObject, no name to reference comment by
|
||||||
|
if (item != null && item.Type == JTokenType.Comment)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.InsertItem(index, item, skipParentCheck);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void ValidateToken(JToken o, JToken? existing)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(o, nameof(o));
|
||||||
|
|
||||||
|
if (o.Type != JTokenType.Property)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Can not add {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, o.GetType(), GetType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
JProperty newProperty = (JProperty)o;
|
||||||
|
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
JProperty existingProperty = (JProperty)existing;
|
||||||
|
|
||||||
|
if (newProperty.Name == existingProperty.Name)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_properties.TryGetValue(newProperty.Name, out existing))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Can not add property {0} to {1}. Property with the same name already exists on object.".FormatWith(CultureInfo.InvariantCulture, newProperty.Name, GetType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void MergeItem(object content, JsonMergeSettings? settings)
|
||||||
|
{
|
||||||
|
if (!(content is JObject o))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, JToken?> contentItem in o)
|
||||||
|
{
|
||||||
|
JProperty? existingProperty = Property(contentItem.Key, settings?.PropertyNameComparison ?? StringComparison.Ordinal);
|
||||||
|
|
||||||
|
if (existingProperty == null)
|
||||||
|
{
|
||||||
|
Add(contentItem.Key, contentItem.Value);
|
||||||
|
}
|
||||||
|
else if (contentItem.Value != null)
|
||||||
|
{
|
||||||
|
if (!(existingProperty.Value is JContainer existingContainer) || existingContainer.Type != contentItem.Value.Type)
|
||||||
|
{
|
||||||
|
if (!IsNull(contentItem.Value) || settings?.MergeNullValueHandling == MergeNullValueHandling.Merge)
|
||||||
|
{
|
||||||
|
existingProperty.Value = contentItem.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
existingContainer.Merge(contentItem.Value, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsNull(JToken token)
|
||||||
|
{
|
||||||
|
if (token.Type == JTokenType.Null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token is JValue v && v.Value == null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InternalPropertyChanged(JProperty childProperty)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(childProperty.Name);
|
||||||
|
#if HAVE_COMPONENT_MODEL
|
||||||
|
if (_listChanged != null)
|
||||||
|
{
|
||||||
|
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, IndexOfItem(childProperty)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if HAVE_INOTIFY_COLLECTION_CHANGED
|
||||||
|
if (_collectionChanged != null)
|
||||||
|
{
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, childProperty, childProperty, IndexOfItem(childProperty)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InternalPropertyChanging(JProperty childProperty)
|
||||||
|
{
|
||||||
|
#if HAVE_INOTIFY_PROPERTY_CHANGING
|
||||||
|
OnPropertyChanging(childProperty.Name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override JToken CloneToken()
|
||||||
|
{
|
||||||
|
return new JObject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the node type for this <see cref="JToken"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type.</value>
|
||||||
|
public override JTokenType Type => JTokenType.Object;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an <see cref="IEnumerable{T}"/> of <see cref="JProperty"/> of this object's properties.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JProperty"/> of this object's properties.</returns>
|
||||||
|
public IEnumerable<JProperty> Properties()
|
||||||
|
{
|
||||||
|
return _properties.Cast<JProperty>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="JProperty"/> with the specified name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The property name.</param>
|
||||||
|
/// <returns>A <see cref="JProperty"/> with the specified name or <c>null</c>.</returns>
|
||||||
|
public JProperty? Property(string name)
|
||||||
|
{
|
||||||
|
return Property(name, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="JProperty"/> with the specified name.
|
||||||
|
/// The exact name will be searched for first and if no matching property is found then
|
||||||
|
/// the <see cref="StringComparison"/> will be used to match a property.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The property name.</param>
|
||||||
|
/// <param name="comparison">One of the enumeration values that specifies how the strings will be compared.</param>
|
||||||
|
/// <returns>A <see cref="JProperty"/> matched with the specified name or <c>null</c>.</returns>
|
||||||
|
public JProperty? Property(string name, StringComparison comparison)
|
||||||
|
{
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_properties.TryGetValue(name, out JToken? property))
|
||||||
|
{
|
||||||
|
return (JProperty)property;
|
||||||
|
}
|
||||||
|
|
||||||
|
// test above already uses this comparison so no need to repeat
|
||||||
|
if (comparison != StringComparison.Ordinal)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _properties.Count; i++)
|
||||||
|
{
|
||||||
|
JProperty p = (JProperty)_properties[i];
|
||||||
|
if (string.Equals(p.Name, name, comparison))
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="JEnumerable{T}"/> of <see cref="JToken"/> of this object's property values.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A <see cref="JEnumerable{T}"/> of <see cref="JToken"/> of this object's property values.</returns>
|
||||||
|
public JEnumerable<JToken> PropertyValues()
|
||||||
|
{
|
||||||
|
return new JEnumerable<JToken>(Properties().Select(p => p.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="JToken"/> with the specified key.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The <see cref="JToken"/> with the specified key.</value>
|
||||||
|
public override JToken? this[object key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(key, nameof(key));
|
||||||
|
|
||||||
|
if (!(key is string propertyName))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Accessed JObject values with invalid key value: {0}. Object property name expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this[propertyName];
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(key, nameof(key));
|
||||||
|
|
||||||
|
if (!(key is string propertyName))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Set JObject values with invalid key value: {0}. Object property name expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
this[propertyName] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="JToken"/> with the specified property name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public JToken? this[string propertyName]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(propertyName, nameof(propertyName));
|
||||||
|
|
||||||
|
JProperty? property = Property(propertyName, StringComparison.Ordinal);
|
||||||
|
|
||||||
|
return property?.Value;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
JProperty? property = Property(propertyName, StringComparison.Ordinal);
|
||||||
|
if (property != null)
|
||||||
|
{
|
||||||
|
property.Value = value!;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if HAVE_INOTIFY_PROPERTY_CHANGING
|
||||||
|
OnPropertyChanging(propertyName);
|
||||||
|
#endif
|
||||||
|
Add(propertyName, value);
|
||||||
|
OnPropertyChanged(propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads a <see cref="JObject"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JObject"/>.</param>
|
||||||
|
/// <returns>A <see cref="JObject"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
/// <exception cref="JsonReaderException">
|
||||||
|
/// <paramref name="reader"/> is not valid JSON.
|
||||||
|
/// </exception>
|
||||||
|
public new static JObject Load(JsonReader reader)
|
||||||
|
{
|
||||||
|
return Load(reader, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads a <see cref="JObject"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JObject"/>.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <returns>A <see cref="JObject"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
/// <exception cref="JsonReaderException">
|
||||||
|
/// <paramref name="reader"/> is not valid JSON.
|
||||||
|
/// </exception>
|
||||||
|
public new static JObject Load(JsonReader reader, JsonLoadSettings? settings)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(reader, nameof(reader));
|
||||||
|
|
||||||
|
if (reader.TokenType == JsonToken.None)
|
||||||
|
{
|
||||||
|
if (!reader.Read())
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JObject from JsonReader.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.MoveToContent();
|
||||||
|
|
||||||
|
if (reader.TokenType != JsonToken.StartObject)
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JObject from JsonReader. Current JsonReader item is not an object: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||||
|
}
|
||||||
|
|
||||||
|
JObject o = new JObject();
|
||||||
|
o.SetLineInfo(reader as IJsonLineInfo, settings);
|
||||||
|
|
||||||
|
o.ReadTokenFrom(reader, settings);
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load a <see cref="JObject"/> from a string that contains JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">A <see cref="String"/> that contains JSON.</param>
|
||||||
|
/// <returns>A <see cref="JObject"/> populated from the string that contains JSON.</returns>
|
||||||
|
/// <exception cref="JsonReaderException">
|
||||||
|
/// <paramref name="json"/> is not valid JSON.
|
||||||
|
/// </exception>
|
||||||
|
/// <example>
|
||||||
|
/// <code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\LinqToJsonTests.cs" region="LinqToJsonCreateParse" title="Parsing a JSON Object from Text" />
|
||||||
|
/// </example>
|
||||||
|
public new static JObject Parse(string json)
|
||||||
|
{
|
||||||
|
return Parse(json, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load a <see cref="JObject"/> from a string that contains JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">A <see cref="String"/> that contains JSON.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <returns>A <see cref="JObject"/> populated from the string that contains JSON.</returns>
|
||||||
|
/// <exception cref="JsonReaderException">
|
||||||
|
/// <paramref name="json"/> is not valid JSON.
|
||||||
|
/// </exception>
|
||||||
|
/// <example>
|
||||||
|
/// <code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\LinqToJsonTests.cs" region="LinqToJsonCreateParse" title="Parsing a JSON Object from Text" />
|
||||||
|
/// </example>
|
||||||
|
public new static JObject Parse(string json, JsonLoadSettings? settings)
|
||||||
|
{
|
||||||
|
using (JsonReader reader = new JsonTextReader(new StringReader(json)))
|
||||||
|
{
|
||||||
|
JObject o = Load(reader, settings);
|
||||||
|
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
// Any content encountered here other than a comment will throw in the reader.
|
||||||
|
}
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="JObject"/> from an object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="o">The object that will be used to create <see cref="JObject"/>.</param>
|
||||||
|
/// <returns>A <see cref="JObject"/> with the values of the specified object.</returns>
|
||||||
|
public new static JObject FromObject(object o)
|
||||||
|
{
|
||||||
|
return FromObject(o, JsonSerializer.CreateDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="JObject"/> from an object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="o">The object that will be used to create <see cref="JObject"/>.</param>
|
||||||
|
/// <param name="jsonSerializer">The <see cref="JsonSerializer"/> that will be used to read the object.</param>
|
||||||
|
/// <returns>A <see cref="JObject"/> with the values of the specified object.</returns>
|
||||||
|
public new static JObject FromObject(object o, JsonSerializer jsonSerializer)
|
||||||
|
{
|
||||||
|
JToken token = FromObjectInternal(o, jsonSerializer);
|
||||||
|
|
||||||
|
if (token.Type != JTokenType.Object)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Object serialized to {0}. JObject instance expected.".FormatWith(CultureInfo.InvariantCulture, token.Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (JObject)token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes this token to a <see cref="JsonWriter"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
|
||||||
|
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
|
||||||
|
public override void WriteTo(JsonWriter writer, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
writer.WriteStartObject();
|
||||||
|
|
||||||
|
for (int i = 0; i < _properties.Count; i++)
|
||||||
|
{
|
||||||
|
_properties[i].WriteTo(writer, converters);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyName">Name of the property.</param>
|
||||||
|
/// <returns>The <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.</returns>
|
||||||
|
public JToken? GetValue(string? propertyName)
|
||||||
|
{
|
||||||
|
return GetValue(propertyName, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.
|
||||||
|
/// The exact property name will be searched for first and if no matching property is found then
|
||||||
|
/// the <see cref="StringComparison"/> will be used to match a property.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyName">Name of the property.</param>
|
||||||
|
/// <param name="comparison">One of the enumeration values that specifies how the strings will be compared.</param>
|
||||||
|
/// <returns>The <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.</returns>
|
||||||
|
public JToken? GetValue(string? propertyName, StringComparison comparison)
|
||||||
|
{
|
||||||
|
if (propertyName == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// attempt to get value via dictionary first for performance
|
||||||
|
var property = Property(propertyName, comparison);
|
||||||
|
|
||||||
|
return property?.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to get the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.
|
||||||
|
/// The exact property name will be searched for first and if no matching property is found then
|
||||||
|
/// the <see cref="StringComparison"/> will be used to match a property.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyName">Name of the property.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="comparison">One of the enumeration values that specifies how the strings will be compared.</param>
|
||||||
|
/// <returns><c>true</c> if a value was successfully retrieved; otherwise, <c>false</c>.</returns>
|
||||||
|
public bool TryGetValue(string propertyName, StringComparison comparison, [NotNullWhen(true)]out JToken? value)
|
||||||
|
{
|
||||||
|
value = GetValue(propertyName, comparison);
|
||||||
|
return (value != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDictionary<string,JToken> Members
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the specified property name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyName">Name of the property.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
public void Add(string propertyName, JToken? value)
|
||||||
|
{
|
||||||
|
Add(new JProperty(propertyName, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the JSON object has the specified property name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyName">Name of the property.</param>
|
||||||
|
/// <returns><c>true</c> if the JSON object has the specified property name; otherwise, <c>false</c>.</returns>
|
||||||
|
public bool ContainsKey(string propertyName)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(propertyName, nameof(propertyName));
|
||||||
|
|
||||||
|
return _properties.Contains(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
ICollection<string> IDictionary<string, JToken?>.Keys => _properties.Keys;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the property with the specified name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyName">Name of the property.</param>
|
||||||
|
/// <returns><c>true</c> if item was successfully removed; otherwise, <c>false</c>.</returns>
|
||||||
|
public bool Remove(string propertyName)
|
||||||
|
{
|
||||||
|
JProperty? property = Property(propertyName, StringComparison.Ordinal);
|
||||||
|
if (property == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
property.Remove();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to get the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyName">Name of the property.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <returns><c>true</c> if a value was successfully retrieved; otherwise, <c>false</c>.</returns>
|
||||||
|
public bool TryGetValue(string propertyName, [NotNullWhen(true)]out JToken? value)
|
||||||
|
{
|
||||||
|
JProperty? property = Property(propertyName, StringComparison.Ordinal);
|
||||||
|
if (property == null)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = property.Value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ICollection<JToken?> IDictionary<string, JToken?>.Values => throw new NotImplementedException();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ICollection<KeyValuePair<string,JToken>> Members
|
||||||
|
void ICollection<KeyValuePair<string, JToken?>>.Add(KeyValuePair<string, JToken?> item)
|
||||||
|
{
|
||||||
|
Add(new JProperty(item.Key, item.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICollection<KeyValuePair<string, JToken?>>.Clear()
|
||||||
|
{
|
||||||
|
RemoveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICollection<KeyValuePair<string, JToken?>>.Contains(KeyValuePair<string, JToken?> item)
|
||||||
|
{
|
||||||
|
JProperty? property = Property(item.Key, StringComparison.Ordinal);
|
||||||
|
if (property == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (property.Value == item.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICollection<KeyValuePair<string, JToken?>>.CopyTo(KeyValuePair<string, JToken?>[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
if (array == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(array));
|
||||||
|
}
|
||||||
|
if (arrayIndex < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(arrayIndex), "arrayIndex is less than 0.");
|
||||||
|
}
|
||||||
|
if (arrayIndex >= array.Length && arrayIndex != 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("arrayIndex is equal to or greater than the length of array.");
|
||||||
|
}
|
||||||
|
if (Count > array.Length - arrayIndex)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("The number of elements in the source JObject is greater than the available space from arrayIndex to the end of the destination array.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
foreach (JProperty property in _properties)
|
||||||
|
{
|
||||||
|
array[arrayIndex + index] = new KeyValuePair<string, JToken?>(property.Name, property.Value);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICollection<KeyValuePair<string, JToken?>>.IsReadOnly => false;
|
||||||
|
|
||||||
|
bool ICollection<KeyValuePair<string, JToken?>>.Remove(KeyValuePair<string, JToken?> item)
|
||||||
|
{
|
||||||
|
if (!((ICollection<KeyValuePair<string, JToken?>>)this).Contains(item))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
((IDictionary<string, JToken>)this).Remove(item.Key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
internal override int GetDeepHashCode()
|
||||||
|
{
|
||||||
|
return ContentsHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator that can be used to iterate through the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.
|
||||||
|
/// </returns>
|
||||||
|
public IEnumerator<KeyValuePair<string, JToken?>> GetEnumerator()
|
||||||
|
{
|
||||||
|
foreach (JProperty property in _properties)
|
||||||
|
{
|
||||||
|
yield return new KeyValuePair<string, JToken?>(property.Name, property.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the <see cref="PropertyChanged"/> event with the provided arguments.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyName">Name of the property.</param>
|
||||||
|
protected virtual void OnPropertyChanged(string propertyName)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_INOTIFY_PROPERTY_CHANGING
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the <see cref="PropertyChanging"/> event with the provided arguments.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyName">Name of the property.</param>
|
||||||
|
protected virtual void OnPropertyChanging(string propertyName)
|
||||||
|
{
|
||||||
|
PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_COMPONENT_MODEL
|
||||||
|
// include custom type descriptor on JObject rather than use a provider because the properties are specific to a type
|
||||||
|
|
||||||
|
#region ICustomTypeDescriptor
|
||||||
|
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
|
||||||
|
{
|
||||||
|
return ((ICustomTypeDescriptor)this).GetProperties(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
|
||||||
|
{
|
||||||
|
PropertyDescriptor[] propertiesArray = new PropertyDescriptor[Count];
|
||||||
|
int i = 0;
|
||||||
|
foreach (KeyValuePair<string, JToken?> propertyValue in this)
|
||||||
|
{
|
||||||
|
propertiesArray[i] = new JPropertyDescriptor(propertyValue.Key);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PropertyDescriptorCollection(propertiesArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeCollection ICustomTypeDescriptor.GetAttributes()
|
||||||
|
{
|
||||||
|
return AttributeCollection.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
string? ICustomTypeDescriptor.GetClassName()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string? ICustomTypeDescriptor.GetComponentName()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeConverter ICustomTypeDescriptor.GetConverter()
|
||||||
|
{
|
||||||
|
return new TypeConverter();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventDescriptor? ICustomTypeDescriptor.GetDefaultEvent()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyDescriptor? ICustomTypeDescriptor.GetDefaultProperty()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
object? ICustomTypeDescriptor.GetEditor(Type editorBaseType)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
|
||||||
|
{
|
||||||
|
return EventDescriptorCollection.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
|
||||||
|
{
|
||||||
|
return EventDescriptorCollection.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
object? ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
|
||||||
|
{
|
||||||
|
if (pd is JPropertyDescriptor)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_DYNAMIC
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the <see cref="DynamicMetaObject"/> responsible for binding operations performed on this object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameter">The expression tree representation of the runtime value.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The <see cref="DynamicMetaObject"/> to bind this object.
|
||||||
|
/// </returns>
|
||||||
|
protected override DynamicMetaObject GetMetaObject(Expression parameter)
|
||||||
|
{
|
||||||
|
return new DynamicProxyMetaObject<JObject>(parameter, this, new JObjectDynamicProxy());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class JObjectDynamicProxy : DynamicProxy<JObject>
|
||||||
|
{
|
||||||
|
public override bool TryGetMember(JObject instance, GetMemberBinder binder, out object? result)
|
||||||
|
{
|
||||||
|
// result can be null
|
||||||
|
result = instance[binder.Name];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool TrySetMember(JObject instance, SetMemberBinder binder, object value)
|
||||||
|
{
|
||||||
|
// this can throw an error if value isn't a valid for a JValue
|
||||||
|
if (!(value is JToken v))
|
||||||
|
{
|
||||||
|
v = new JValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
instance[binder.Name] = v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> GetDynamicMemberNames(JObject instance)
|
||||||
|
{
|
||||||
|
return instance.Properties().Select(p => p.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
#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.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
public partial class JProperty
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes this token to a <see cref="JsonWriter"/> asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
||||||
|
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> that represents the asynchronous write operation.</returns>
|
||||||
|
public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
Task task = writer.WritePropertyNameAsync(_name, cancellationToken);
|
||||||
|
if (task.IsCompletedSucessfully())
|
||||||
|
{
|
||||||
|
return WriteValueAsync(writer, cancellationToken, converters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WriteToAsync(task, writer, cancellationToken, converters);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task WriteToAsync(Task task, JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
await task.ConfigureAwait(false);
|
||||||
|
|
||||||
|
await WriteValueAsync(writer, cancellationToken, converters).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task WriteValueAsync(JsonWriter writer, CancellationToken cancellationToken, JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
JToken value = Value;
|
||||||
|
return value != null
|
||||||
|
? value.WriteToAsync(writer, cancellationToken, converters)
|
||||||
|
: writer.WriteNullAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously loads a <see cref="JProperty"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JProperty"/>.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> representing the asynchronous creation. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns a <see cref="JProperty"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static Task<JProperty> LoadAsync(JsonReader reader, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return LoadAsync(reader, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously loads a <see cref="JProperty"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JProperty"/>.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> representing the asynchronous creation. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns a <see cref="JProperty"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static async Task<JProperty> LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonToken.None)
|
||||||
|
{
|
||||||
|
if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JProperty from JsonReader.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await reader.MoveToContentAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (reader.TokenType != JsonToken.PropertyName)
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JProperty from JsonReader. Current JsonReader item is not a property: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||||
|
}
|
||||||
|
|
||||||
|
JProperty p = new JProperty((string)reader.Value!);
|
||||||
|
p.SetLineInfo(reader as IJsonLineInfo, settings);
|
||||||
|
|
||||||
|
await p.ReadTokenFromAsync(reader, settings, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,401 @@
|
||||||
|
#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 LC.Newtonsoft.Json.Utilities;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a JSON property.
|
||||||
|
/// </summary>
|
||||||
|
public partial class JProperty : JContainer
|
||||||
|
{
|
||||||
|
#region JPropertyList
|
||||||
|
private class JPropertyList : IList<JToken>
|
||||||
|
{
|
||||||
|
internal JToken? _token;
|
||||||
|
|
||||||
|
public IEnumerator<JToken> GetEnumerator()
|
||||||
|
{
|
||||||
|
if (_token != null)
|
||||||
|
{
|
||||||
|
yield return _token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(JToken item)
|
||||||
|
{
|
||||||
|
_token = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_token = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(JToken item)
|
||||||
|
{
|
||||||
|
return (_token == item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(JToken[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
if (_token != null)
|
||||||
|
{
|
||||||
|
array[arrayIndex] = _token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(JToken item)
|
||||||
|
{
|
||||||
|
if (_token == item)
|
||||||
|
{
|
||||||
|
_token = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count => (_token != null) ? 1 : 0;
|
||||||
|
|
||||||
|
public bool IsReadOnly => false;
|
||||||
|
|
||||||
|
public int IndexOf(JToken item)
|
||||||
|
{
|
||||||
|
return (_token == item) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Insert(int index, JToken item)
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
_token = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAt(int index)
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
_token = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JToken this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (index != 0)
|
||||||
|
{
|
||||||
|
throw new IndexOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
MiscellaneousUtils.Assert(_token != null);
|
||||||
|
return _token;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (index != 0)
|
||||||
|
{
|
||||||
|
throw new IndexOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
_token = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private readonly JPropertyList _content = new JPropertyList();
|
||||||
|
private readonly string _name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the container's children tokens.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The container's children tokens.</value>
|
||||||
|
protected override IList<JToken> ChildrenTokens => _content;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the property name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The property name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
[DebuggerStepThrough]
|
||||||
|
get { return _name; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the property value.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The property value.</value>
|
||||||
|
public JToken Value
|
||||||
|
{
|
||||||
|
[DebuggerStepThrough]
|
||||||
|
get { return _content._token!; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
CheckReentrancy();
|
||||||
|
|
||||||
|
JToken newValue = value ?? JValue.CreateNull();
|
||||||
|
|
||||||
|
if (_content._token == null)
|
||||||
|
{
|
||||||
|
InsertItem(0, newValue, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetItem(0, newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JProperty"/> class from another <see cref="JProperty"/> object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">A <see cref="JProperty"/> object to copy from.</param>
|
||||||
|
public JProperty(JProperty other)
|
||||||
|
: base(other)
|
||||||
|
{
|
||||||
|
_name = other.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override JToken GetItem(int index)
|
||||||
|
{
|
||||||
|
if (index != 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void SetItem(int index, JToken? item)
|
||||||
|
{
|
||||||
|
if (index != 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsTokenUnchanged(Value, item))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
((JObject?)Parent)?.InternalPropertyChanging(this);
|
||||||
|
|
||||||
|
base.SetItem(0, item);
|
||||||
|
|
||||||
|
((JObject?)Parent)?.InternalPropertyChanged(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override bool RemoveItem(JToken? item)
|
||||||
|
{
|
||||||
|
throw new JsonException("Cannot add or remove items from {0}.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty)));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void RemoveItemAt(int index)
|
||||||
|
{
|
||||||
|
throw new JsonException("Cannot add or remove items from {0}.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty)));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override int IndexOfItem(JToken? item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _content.IndexOf(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override bool InsertItem(int index, JToken? item, bool skipParentCheck)
|
||||||
|
{
|
||||||
|
// don't add comments to JProperty
|
||||||
|
if (item != null && item.Type == JTokenType.Comment)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Value != null)
|
||||||
|
{
|
||||||
|
throw new JsonException("{0} cannot have multiple values.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.InsertItem(0, item, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override bool ContainsItem(JToken? item)
|
||||||
|
{
|
||||||
|
return (Value == item);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void MergeItem(object content, JsonMergeSettings? settings)
|
||||||
|
{
|
||||||
|
JToken? value = (content as JProperty)?.Value;
|
||||||
|
|
||||||
|
if (value != null && value.Type != JTokenType.Null)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void ClearItems()
|
||||||
|
{
|
||||||
|
throw new JsonException("Cannot add or remove items from {0}.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty)));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override bool DeepEquals(JToken node)
|
||||||
|
{
|
||||||
|
return (node is JProperty t && _name == t.Name && ContentsEqual(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override JToken CloneToken()
|
||||||
|
{
|
||||||
|
return new JProperty(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the node type for this <see cref="JToken"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type.</value>
|
||||||
|
public override JTokenType Type
|
||||||
|
{
|
||||||
|
[DebuggerStepThrough]
|
||||||
|
get { return JTokenType.Property; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal JProperty(string name)
|
||||||
|
{
|
||||||
|
// called from JTokenWriter
|
||||||
|
ValidationUtils.ArgumentNotNull(name, nameof(name));
|
||||||
|
|
||||||
|
_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JProperty"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The property name.</param>
|
||||||
|
/// <param name="content">The property content.</param>
|
||||||
|
public JProperty(string name, params object[] content)
|
||||||
|
: this(name, (object)content)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JProperty"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The property name.</param>
|
||||||
|
/// <param name="content">The property content.</param>
|
||||||
|
public JProperty(string name, object? content)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(name, nameof(name));
|
||||||
|
|
||||||
|
_name = name;
|
||||||
|
|
||||||
|
Value = IsMultiContent(content)
|
||||||
|
? new JArray(content)
|
||||||
|
: CreateFromContent(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes this token to a <see cref="JsonWriter"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
|
||||||
|
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
|
||||||
|
public override void WriteTo(JsonWriter writer, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
writer.WritePropertyName(_name);
|
||||||
|
|
||||||
|
JToken value = Value;
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
value.WriteTo(writer, converters);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.WriteNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override int GetDeepHashCode()
|
||||||
|
{
|
||||||
|
return _name.GetHashCode() ^ (Value?.GetDeepHashCode() ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads a <see cref="JProperty"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JProperty"/>.</param>
|
||||||
|
/// <returns>A <see cref="JProperty"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static JProperty Load(JsonReader reader)
|
||||||
|
{
|
||||||
|
return Load(reader, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads a <see cref="JProperty"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JProperty"/>.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <returns>A <see cref="JProperty"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
|
||||||
|
public new static JProperty Load(JsonReader reader, JsonLoadSettings? settings)
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonToken.None)
|
||||||
|
{
|
||||||
|
if (!reader.Read())
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JProperty from JsonReader.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.MoveToContent();
|
||||||
|
|
||||||
|
if (reader.TokenType != JsonToken.PropertyName)
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JProperty from JsonReader. Current JsonReader item is not a property: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||||
|
}
|
||||||
|
|
||||||
|
JProperty p = new JProperty((string)reader.Value!);
|
||||||
|
p.SetLineInfo(reader as IJsonLineInfo, settings);
|
||||||
|
|
||||||
|
p.ReadTokenFrom(reader, settings);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,156 @@
|
||||||
|
#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_COMPONENT_MODEL
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a view of a <see cref="JProperty"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class JPropertyDescriptor : PropertyDescriptor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JPropertyDescriptor"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name.</param>
|
||||||
|
public JPropertyDescriptor(string name)
|
||||||
|
: base(name, null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JObject CastInstance(object instance)
|
||||||
|
{
|
||||||
|
return (JObject)instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When overridden in a derived class, returns whether resetting an object changes its value.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if resetting the component changes its value; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
/// <param name="component">The component to test for reset capability.</param>
|
||||||
|
public override bool CanResetValue(object component)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When overridden in a derived class, gets the current value of the property on a component.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// The value of a property for a given component.
|
||||||
|
/// </returns>
|
||||||
|
/// <param name="component">The component with the property for which to retrieve the value.</param>
|
||||||
|
public override object? GetValue(object component)
|
||||||
|
{
|
||||||
|
return (component as JObject)?[Name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When overridden in a derived class, resets the value for this property of the component to the default value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="component">The component with the property value that is to be reset to the default value.</param>
|
||||||
|
public override void ResetValue(object component)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When overridden in a derived class, sets the value of the component to a different value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="component">The component with the property value that is to be set.</param>
|
||||||
|
/// <param name="value">The new value.</param>
|
||||||
|
public override void SetValue(object component, object value)
|
||||||
|
{
|
||||||
|
if (component is JObject o)
|
||||||
|
{
|
||||||
|
JToken token = value as JToken ?? new JValue(value);
|
||||||
|
|
||||||
|
o[Name] = token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When overridden in a derived class, determines a value indicating whether the value of this property needs to be persisted.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if the property should be persisted; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
/// <param name="component">The component with the property to be examined for persistence.</param>
|
||||||
|
public override bool ShouldSerializeValue(object component)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When overridden in a derived class, gets the type of the component this property is bound to.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Type"/> that represents the type of component this property is bound to.
|
||||||
|
/// When the <see cref="PropertyDescriptor.GetValue(Object)"/> or
|
||||||
|
/// <see cref="PropertyDescriptor.SetValue(Object, Object)"/>
|
||||||
|
/// methods are invoked, the object specified might be an instance of this type.
|
||||||
|
/// </returns>
|
||||||
|
public override Type ComponentType => typeof(JObject);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When overridden in a derived class, gets a value indicating whether this property is read-only.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if the property is read-only; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool IsReadOnly => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When overridden in a derived class, gets the type of the property.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Type"/> that represents the type of the property.
|
||||||
|
/// </returns>
|
||||||
|
public override Type PropertyType => typeof(object);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the hash code for the name of the member.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
/// <returns>
|
||||||
|
/// The hash code for the name of the member.
|
||||||
|
/// </returns>
|
||||||
|
protected override int NameHashCode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// override property to fix up an error in its documentation
|
||||||
|
int nameHashCode = base.NameHashCode;
|
||||||
|
return nameHashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,284 @@
|
||||||
|
#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.Collections.ObjectModel;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
internal class JPropertyKeyedCollection : Collection<JToken>
|
||||||
|
{
|
||||||
|
private static readonly IEqualityComparer<string> Comparer = StringComparer.Ordinal;
|
||||||
|
|
||||||
|
private Dictionary<string, JToken>? _dictionary;
|
||||||
|
|
||||||
|
public JPropertyKeyedCollection() : base(new List<JToken>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddKey(string key, JToken item)
|
||||||
|
{
|
||||||
|
EnsureDictionary();
|
||||||
|
_dictionary![key] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ChangeItemKey(JToken item, string newKey)
|
||||||
|
{
|
||||||
|
if (!ContainsItem(item))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("The specified item does not exist in this KeyedCollection.");
|
||||||
|
}
|
||||||
|
|
||||||
|
string keyForItem = GetKeyForItem(item);
|
||||||
|
if (!Comparer.Equals(keyForItem, newKey))
|
||||||
|
{
|
||||||
|
if (newKey != null)
|
||||||
|
{
|
||||||
|
AddKey(newKey, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyForItem != null)
|
||||||
|
{
|
||||||
|
RemoveKey(keyForItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ClearItems()
|
||||||
|
{
|
||||||
|
base.ClearItems();
|
||||||
|
|
||||||
|
_dictionary?.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(string key)
|
||||||
|
{
|
||||||
|
if (key == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dictionary != null)
|
||||||
|
{
|
||||||
|
return _dictionary.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ContainsItem(JToken item)
|
||||||
|
{
|
||||||
|
if (_dictionary == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string key = GetKeyForItem(item);
|
||||||
|
return _dictionary.TryGetValue(key, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureDictionary()
|
||||||
|
{
|
||||||
|
if (_dictionary == null)
|
||||||
|
{
|
||||||
|
_dictionary = new Dictionary<string, JToken>(Comparer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetKeyForItem(JToken item)
|
||||||
|
{
|
||||||
|
return ((JProperty)item).Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void InsertItem(int index, JToken item)
|
||||||
|
{
|
||||||
|
AddKey(GetKeyForItem(item), item);
|
||||||
|
base.InsertItem(index, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(string key)
|
||||||
|
{
|
||||||
|
if (key == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dictionary != null)
|
||||||
|
{
|
||||||
|
return _dictionary.TryGetValue(key, out JToken value) && Remove(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void RemoveItem(int index)
|
||||||
|
{
|
||||||
|
string keyForItem = GetKeyForItem(Items[index]);
|
||||||
|
RemoveKey(keyForItem);
|
||||||
|
base.RemoveItem(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveKey(string key)
|
||||||
|
{
|
||||||
|
_dictionary?.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void SetItem(int index, JToken item)
|
||||||
|
{
|
||||||
|
string keyForItem = GetKeyForItem(item);
|
||||||
|
string keyAtIndex = GetKeyForItem(Items[index]);
|
||||||
|
|
||||||
|
if (Comparer.Equals(keyAtIndex, keyForItem))
|
||||||
|
{
|
||||||
|
if (_dictionary != null)
|
||||||
|
{
|
||||||
|
_dictionary[keyForItem] = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddKey(keyForItem, item);
|
||||||
|
|
||||||
|
if (keyAtIndex != null)
|
||||||
|
{
|
||||||
|
RemoveKey(keyAtIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base.SetItem(index, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JToken this[string key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (key == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dictionary != null)
|
||||||
|
{
|
||||||
|
return _dictionary[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new KeyNotFoundException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(string key, [NotNullWhen(true)]out JToken? value)
|
||||||
|
{
|
||||||
|
if (_dictionary == null)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _dictionary.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<string> Keys
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
EnsureDictionary();
|
||||||
|
return _dictionary!.Keys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<JToken> Values
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
EnsureDictionary();
|
||||||
|
return _dictionary!.Values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IndexOfReference(JToken t)
|
||||||
|
{
|
||||||
|
return ((List<JToken>)Items).IndexOfReference(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Compare(JPropertyKeyedCollection other)
|
||||||
|
{
|
||||||
|
if (this == other)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dictionaries in JavaScript aren't ordered
|
||||||
|
// ignore order when comparing properties
|
||||||
|
Dictionary<string, JToken>? d1 = _dictionary;
|
||||||
|
Dictionary<string, JToken>? d2 = other._dictionary;
|
||||||
|
|
||||||
|
if (d1 == null && d2 == null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d1 == null)
|
||||||
|
{
|
||||||
|
return (d2!.Count == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d2 == null)
|
||||||
|
{
|
||||||
|
return (d1.Count == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d1.Count != d2.Count)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, JToken> keyAndProperty in d1)
|
||||||
|
{
|
||||||
|
if (!d2.TryGetValue(keyAndProperty.Key, out JToken secondValue))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JProperty p1 = (JProperty)keyAndProperty.Value;
|
||||||
|
JProperty p2 = (JProperty)secondValue;
|
||||||
|
|
||||||
|
if (p1.Value == null)
|
||||||
|
{
|
||||||
|
return (p2.Value == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p1.Value.DeepEquals(p2.Value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
#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.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
public partial class JRaw
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously creates an instance of <see cref="JRaw"/> with the content of the reader's current token.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The reader.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> representing the asynchronous creation. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns an instance of <see cref="JRaw"/> with the content of the reader's current token.</returns>
|
||||||
|
public static async Task<JRaw> CreateAsync(JsonReader reader, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture))
|
||||||
|
using (JsonTextWriter jsonWriter = new JsonTextWriter(sw))
|
||||||
|
{
|
||||||
|
await jsonWriter.WriteTokenSyncReadingAsync(reader, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return new JRaw(sw.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,75 @@
|
||||||
|
#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.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a raw JSON string.
|
||||||
|
/// </summary>
|
||||||
|
public partial class JRaw : JValue
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JRaw"/> class from another <see cref="JRaw"/> object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">A <see cref="JRaw"/> object to copy from.</param>
|
||||||
|
public JRaw(JRaw other)
|
||||||
|
: base(other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JRaw"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rawJson">The raw json.</param>
|
||||||
|
public JRaw(object? rawJson)
|
||||||
|
: base(rawJson, JTokenType.Raw)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instance of <see cref="JRaw"/> with the content of the reader's current token.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The reader.</param>
|
||||||
|
/// <returns>An instance of <see cref="JRaw"/> with the content of the reader's current token.</returns>
|
||||||
|
public static JRaw Create(JsonReader reader)
|
||||||
|
{
|
||||||
|
using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture))
|
||||||
|
using (JsonTextWriter jsonWriter = new JsonTextWriter(sw))
|
||||||
|
{
|
||||||
|
jsonWriter.WriteToken(reader);
|
||||||
|
|
||||||
|
return new JRaw(sw.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override JToken CloneToken()
|
||||||
|
{
|
||||||
|
return new JRaw(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
#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;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
public abstract partial class JToken
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes this token to a <see cref="JsonWriter"/> asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
||||||
|
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> that represents the asynchronous write operation.</returns>
|
||||||
|
public virtual Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes this token to a <see cref="JsonWriter"/> asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
|
||||||
|
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> that represents the asynchronous write operation.</returns>
|
||||||
|
public Task WriteToAsync(JsonWriter writer, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
return WriteToAsync(writer, default, converters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously creates a <see cref="JToken"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">An <see cref="JsonReader"/> positioned at the token to read into this <see cref="JToken"/>.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Task{TResult}"/> that represents the asynchronous creation. The
|
||||||
|
/// <see cref="Task{TResult}.Result"/> property returns a <see cref="JToken"/> that contains
|
||||||
|
/// the token and its descendant tokens
|
||||||
|
/// that were read from the reader. The runtime type of the token is determined
|
||||||
|
/// by the token type of the first token encountered in the reader.
|
||||||
|
/// </returns>
|
||||||
|
public static Task<JToken> ReadFromAsync(JsonReader reader, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return ReadFromAsync(reader, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously creates a <see cref="JToken"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">An <see cref="JsonReader"/> positioned at the token to read into this <see cref="JToken"/>.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Task{TResult}"/> that represents the asynchronous creation. The
|
||||||
|
/// <see cref="Task{TResult}.Result"/> property returns a <see cref="JToken"/> that contains
|
||||||
|
/// the token and its descendant tokens
|
||||||
|
/// that were read from the reader. The runtime type of the token is determined
|
||||||
|
/// by the token type of the first token encountered in the reader.
|
||||||
|
/// </returns>
|
||||||
|
public static async Task<JToken> ReadFromAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(reader, nameof(reader));
|
||||||
|
|
||||||
|
if (reader.TokenType == JsonToken.None)
|
||||||
|
{
|
||||||
|
if (!await (settings != null && settings.CommentHandling == CommentHandling.Ignore ? reader.ReadAndMoveToContentAsync(cancellationToken) : reader.ReadAsync(cancellationToken)).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JToken from JsonReader.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IJsonLineInfo? lineInfo = reader as IJsonLineInfo;
|
||||||
|
|
||||||
|
switch (reader.TokenType)
|
||||||
|
{
|
||||||
|
case JsonToken.StartObject:
|
||||||
|
return await JObject.LoadAsync(reader, settings, cancellationToken).ConfigureAwait(false);
|
||||||
|
case JsonToken.StartArray:
|
||||||
|
return await JArray.LoadAsync(reader, settings, cancellationToken).ConfigureAwait(false);
|
||||||
|
case JsonToken.StartConstructor:
|
||||||
|
return await JConstructor.LoadAsync(reader, settings, cancellationToken).ConfigureAwait(false);
|
||||||
|
case JsonToken.PropertyName:
|
||||||
|
return await JProperty.LoadAsync(reader, settings, cancellationToken).ConfigureAwait(false);
|
||||||
|
case JsonToken.String:
|
||||||
|
case JsonToken.Integer:
|
||||||
|
case JsonToken.Float:
|
||||||
|
case JsonToken.Date:
|
||||||
|
case JsonToken.Boolean:
|
||||||
|
case JsonToken.Bytes:
|
||||||
|
JValue v = new JValue(reader.Value);
|
||||||
|
v.SetLineInfo(lineInfo, settings);
|
||||||
|
return v;
|
||||||
|
case JsonToken.Comment:
|
||||||
|
v = JValue.CreateComment(reader.Value?.ToString());
|
||||||
|
v.SetLineInfo(lineInfo, settings);
|
||||||
|
return v;
|
||||||
|
case JsonToken.Null:
|
||||||
|
v = JValue.CreateNull();
|
||||||
|
v.SetLineInfo(lineInfo, settings);
|
||||||
|
return v;
|
||||||
|
case JsonToken.Undefined:
|
||||||
|
v = JValue.CreateUndefined();
|
||||||
|
v.SetLineInfo(lineInfo, settings);
|
||||||
|
return v;
|
||||||
|
default:
|
||||||
|
throw JsonReaderException.Create(reader, "Error reading JToken from JsonReader. Unexpected token: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously creates a <see cref="JToken"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> positioned at the token to read into this <see cref="JToken"/>.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Task{TResult}"/> that represents the asynchronous creation. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns a <see cref="JToken"/> that contains the token and its descendant tokens
|
||||||
|
/// that were read from the reader. The runtime type of the token is determined
|
||||||
|
/// by the token type of the first token encountered in the reader.
|
||||||
|
/// </returns>
|
||||||
|
public static Task<JToken> LoadAsync(JsonReader reader, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return LoadAsync(reader, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously creates a <see cref="JToken"/> from a <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="JsonReader"/> positioned at the token to read into this <see cref="JToken"/>.</param>
|
||||||
|
/// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
|
||||||
|
/// If this is <c>null</c>, default load settings will be used.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Task{TResult}"/> that represents the asynchronous creation. The <see cref="Task{TResult}.Result"/>
|
||||||
|
/// property returns a <see cref="JToken"/> that contains the token and its descendant tokens
|
||||||
|
/// that were read from the reader. The runtime type of the token is determined
|
||||||
|
/// by the token type of the first token encountered in the reader.
|
||||||
|
/// </returns>
|
||||||
|
public static Task<JToken> LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return ReadFromAsync(reader, settings, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,64 @@
|
||||||
|
#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.Generic;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares tokens to determine whether they are equal.
|
||||||
|
/// </summary>
|
||||||
|
public class JTokenEqualityComparer : IEqualityComparer<JToken>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified objects are equal.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The first object of type <see cref="JToken"/> to compare.</param>
|
||||||
|
/// <param name="y">The second object of type <see cref="JToken"/> to compare.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if the specified objects are equal; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public bool Equals(JToken x, JToken y)
|
||||||
|
{
|
||||||
|
return JToken.DeepEquals(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a hash code for the specified object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The <see cref="System.Object"/> for which a hash code is to be returned.</param>
|
||||||
|
/// <returns>A hash code for the specified object.</returns>
|
||||||
|
/// <exception cref="System.ArgumentNullException">The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is <c>null</c>.</exception>
|
||||||
|
public int GetHashCode(JToken obj)
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.GetDeepHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,345 @@
|
||||||
|
#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;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a reader that provides fast, non-cached, forward-only access to serialized JSON data.
|
||||||
|
/// </summary>
|
||||||
|
public class JTokenReader : JsonReader, IJsonLineInfo
|
||||||
|
{
|
||||||
|
private readonly JToken _root;
|
||||||
|
private string? _initialPath;
|
||||||
|
private JToken? _parent;
|
||||||
|
private JToken? _current;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="JToken"/> at the reader's current position.
|
||||||
|
/// </summary>
|
||||||
|
public JToken? CurrentToken => _current;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JTokenReader"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">The token to read from.</param>
|
||||||
|
public JTokenReader(JToken token)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(token, nameof(token));
|
||||||
|
|
||||||
|
_root = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JTokenReader"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">The token to read from.</param>
|
||||||
|
/// <param name="initialPath">The initial path of the token. It is prepended to the returned <see cref="Path"/>.</param>
|
||||||
|
public JTokenReader(JToken token, string initialPath)
|
||||||
|
: this(token)
|
||||||
|
{
|
||||||
|
_initialPath = initialPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the next JSON token from the underlying <see cref="JToken"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if the next token was read successfully; <c>false</c> if there are no more tokens to read.
|
||||||
|
/// </returns>
|
||||||
|
public override bool Read()
|
||||||
|
{
|
||||||
|
if (CurrentState != State.Start)
|
||||||
|
{
|
||||||
|
if (_current == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_current is JContainer container && _parent != container)
|
||||||
|
{
|
||||||
|
return ReadInto(container);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ReadOver(_current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The current value could already be the root value if it is a comment
|
||||||
|
if (_current == _root)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_current = _root;
|
||||||
|
SetToken(_current);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ReadOver(JToken t)
|
||||||
|
{
|
||||||
|
if (t == _root)
|
||||||
|
{
|
||||||
|
return ReadToEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
JToken? next = t.Next;
|
||||||
|
if ((next == null || next == t) || t == t.Parent!.Last)
|
||||||
|
{
|
||||||
|
if (t.Parent == null)
|
||||||
|
{
|
||||||
|
return ReadToEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
return SetEnd(t.Parent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_current = next;
|
||||||
|
SetToken(_current);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ReadToEnd()
|
||||||
|
{
|
||||||
|
_current = null;
|
||||||
|
SetToken(JsonToken.None);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonToken? GetEndToken(JContainer c)
|
||||||
|
{
|
||||||
|
switch (c.Type)
|
||||||
|
{
|
||||||
|
case JTokenType.Object:
|
||||||
|
return JsonToken.EndObject;
|
||||||
|
case JTokenType.Array:
|
||||||
|
return JsonToken.EndArray;
|
||||||
|
case JTokenType.Constructor:
|
||||||
|
return JsonToken.EndConstructor;
|
||||||
|
case JTokenType.Property:
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
throw MiscellaneousUtils.CreateArgumentOutOfRangeException(nameof(c.Type), c.Type, "Unexpected JContainer type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ReadInto(JContainer c)
|
||||||
|
{
|
||||||
|
JToken? firstChild = c.First;
|
||||||
|
if (firstChild == null)
|
||||||
|
{
|
||||||
|
return SetEnd(c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetToken(firstChild);
|
||||||
|
_current = firstChild;
|
||||||
|
_parent = c;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SetEnd(JContainer c)
|
||||||
|
{
|
||||||
|
JsonToken? endToken = GetEndToken(c);
|
||||||
|
if (endToken != null)
|
||||||
|
{
|
||||||
|
SetToken(endToken.GetValueOrDefault());
|
||||||
|
_current = c;
|
||||||
|
_parent = c;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ReadOver(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetToken(JToken token)
|
||||||
|
{
|
||||||
|
switch (token.Type)
|
||||||
|
{
|
||||||
|
case JTokenType.Object:
|
||||||
|
SetToken(JsonToken.StartObject);
|
||||||
|
break;
|
||||||
|
case JTokenType.Array:
|
||||||
|
SetToken(JsonToken.StartArray);
|
||||||
|
break;
|
||||||
|
case JTokenType.Constructor:
|
||||||
|
SetToken(JsonToken.StartConstructor, ((JConstructor)token).Name);
|
||||||
|
break;
|
||||||
|
case JTokenType.Property:
|
||||||
|
SetToken(JsonToken.PropertyName, ((JProperty)token).Name);
|
||||||
|
break;
|
||||||
|
case JTokenType.Comment:
|
||||||
|
SetToken(JsonToken.Comment, ((JValue)token).Value);
|
||||||
|
break;
|
||||||
|
case JTokenType.Integer:
|
||||||
|
SetToken(JsonToken.Integer, ((JValue)token).Value);
|
||||||
|
break;
|
||||||
|
case JTokenType.Float:
|
||||||
|
SetToken(JsonToken.Float, ((JValue)token).Value);
|
||||||
|
break;
|
||||||
|
case JTokenType.String:
|
||||||
|
SetToken(JsonToken.String, ((JValue)token).Value);
|
||||||
|
break;
|
||||||
|
case JTokenType.Boolean:
|
||||||
|
SetToken(JsonToken.Boolean, ((JValue)token).Value);
|
||||||
|
break;
|
||||||
|
case JTokenType.Null:
|
||||||
|
SetToken(JsonToken.Null, ((JValue)token).Value);
|
||||||
|
break;
|
||||||
|
case JTokenType.Undefined:
|
||||||
|
SetToken(JsonToken.Undefined, ((JValue)token).Value);
|
||||||
|
break;
|
||||||
|
case JTokenType.Date:
|
||||||
|
{
|
||||||
|
object? v = ((JValue)token).Value;
|
||||||
|
if (v is DateTime dt)
|
||||||
|
{
|
||||||
|
v = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetToken(JsonToken.Date, v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JTokenType.Raw:
|
||||||
|
SetToken(JsonToken.Raw, ((JValue)token).Value);
|
||||||
|
break;
|
||||||
|
case JTokenType.Bytes:
|
||||||
|
SetToken(JsonToken.Bytes, ((JValue)token).Value);
|
||||||
|
break;
|
||||||
|
case JTokenType.Guid:
|
||||||
|
SetToken(JsonToken.String, SafeToString(((JValue)token).Value));
|
||||||
|
break;
|
||||||
|
case JTokenType.Uri:
|
||||||
|
{
|
||||||
|
object? v = ((JValue)token).Value;
|
||||||
|
SetToken(JsonToken.String, v is Uri uri ? uri.OriginalString : SafeToString(v));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JTokenType.TimeSpan:
|
||||||
|
SetToken(JsonToken.String, SafeToString(((JValue)token).Value));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw MiscellaneousUtils.CreateArgumentOutOfRangeException(nameof(token.Type), token.Type, "Unexpected JTokenType.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? SafeToString(object? value)
|
||||||
|
{
|
||||||
|
return value?.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IJsonLineInfo.HasLineInfo()
|
||||||
|
{
|
||||||
|
if (CurrentState == State.Start)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IJsonLineInfo? info = _current;
|
||||||
|
return (info != null && info.HasLineInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
int IJsonLineInfo.LineNumber
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (CurrentState == State.Start)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
IJsonLineInfo? info = _current;
|
||||||
|
if (info != null)
|
||||||
|
{
|
||||||
|
return info.LineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int IJsonLineInfo.LinePosition
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (CurrentState == State.Start)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
IJsonLineInfo? info = _current;
|
||||||
|
if (info != null)
|
||||||
|
{
|
||||||
|
return info.LinePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path of the current JSON token.
|
||||||
|
/// </summary>
|
||||||
|
public override string Path
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string path = base.Path;
|
||||||
|
|
||||||
|
if (_initialPath == null)
|
||||||
|
{
|
||||||
|
_initialPath = _root.Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!StringUtils.IsNullOrEmpty(_initialPath))
|
||||||
|
{
|
||||||
|
if (StringUtils.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
return _initialPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.StartsWith('['))
|
||||||
|
{
|
||||||
|
path = _initialPath + path;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path = _initialPath + "." + path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
#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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the type of token.
|
||||||
|
/// </summary>
|
||||||
|
public enum JTokenType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// No token type has been set.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A JSON object.
|
||||||
|
/// </summary>
|
||||||
|
Object = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A JSON array.
|
||||||
|
/// </summary>
|
||||||
|
Array = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A JSON constructor.
|
||||||
|
/// </summary>
|
||||||
|
Constructor = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A JSON object property.
|
||||||
|
/// </summary>
|
||||||
|
Property = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A comment.
|
||||||
|
/// </summary>
|
||||||
|
Comment = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An integer value.
|
||||||
|
/// </summary>
|
||||||
|
Integer = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A float value.
|
||||||
|
/// </summary>
|
||||||
|
Float = 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A string value.
|
||||||
|
/// </summary>
|
||||||
|
String = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A boolean value.
|
||||||
|
/// </summary>
|
||||||
|
Boolean = 9,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A null value.
|
||||||
|
/// </summary>
|
||||||
|
Null = 10,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An undefined value.
|
||||||
|
/// </summary>
|
||||||
|
Undefined = 11,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A date value.
|
||||||
|
/// </summary>
|
||||||
|
Date = 12,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A raw JSON value.
|
||||||
|
/// </summary>
|
||||||
|
Raw = 13,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A collection of bytes value.
|
||||||
|
/// </summary>
|
||||||
|
Bytes = 14,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A Guid value.
|
||||||
|
/// </summary>
|
||||||
|
Guid = 15,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A Uri value.
|
||||||
|
/// </summary>
|
||||||
|
Uri = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A TimeSpan value.
|
||||||
|
/// </summary>
|
||||||
|
TimeSpan = 17
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
#if HAVE_ASYNC
|
||||||
|
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
public partial class JTokenWriter
|
||||||
|
{
|
||||||
|
// This is the only method that can benefit from Task-based asynchronicity, and that only when
|
||||||
|
// the reader provides it.
|
||||||
|
internal override Task WriteTokenAsync(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Since JTokenReader is a common target (and with an optimised path) and since it can't
|
||||||
|
// read truly async, catch that case.
|
||||||
|
if (reader is JTokenReader)
|
||||||
|
{
|
||||||
|
WriteToken(reader, writeChildren, writeDateConstructorAsDate, writeComments);
|
||||||
|
return AsyncUtils.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WriteTokenSyncReadingAsync(reader, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,538 @@
|
||||||
|
#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.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
#if HAVE_BIG_INTEGER
|
||||||
|
using System.Numerics;
|
||||||
|
#endif
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
|
||||||
|
/// </summary>
|
||||||
|
public partial class JTokenWriter : JsonWriter
|
||||||
|
{
|
||||||
|
private JContainer? _token;
|
||||||
|
private JContainer? _parent;
|
||||||
|
// used when writer is writing single value and the value has no containing parent
|
||||||
|
private JValue? _value;
|
||||||
|
private JToken? _current;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="JToken"/> at the writer's current position.
|
||||||
|
/// </summary>
|
||||||
|
public JToken? CurrentToken => _current;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the token being written.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The token being written.</value>
|
||||||
|
public JToken? Token
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_token != null)
|
||||||
|
{
|
||||||
|
return _token;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JTokenWriter"/> class writing to the given <see cref="JContainer"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="container">The container being written to.</param>
|
||||||
|
public JTokenWriter(JContainer container)
|
||||||
|
{
|
||||||
|
ValidationUtils.ArgumentNotNull(container, nameof(container));
|
||||||
|
|
||||||
|
_token = container;
|
||||||
|
_parent = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JTokenWriter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JTokenWriter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flushes whatever is in the buffer to the underlying <see cref="JContainer"/>.
|
||||||
|
/// </summary>
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Closes this writer.
|
||||||
|
/// If <see cref="JsonWriter.AutoCompleteOnClose"/> is set to <c>true</c>, the JSON is auto-completed.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Setting <see cref="JsonWriter.CloseOutput"/> to <c>true</c> has no additional effect, since the underlying <see cref="JContainer"/> is a type that cannot be closed.
|
||||||
|
/// </remarks>
|
||||||
|
public override void Close()
|
||||||
|
{
|
||||||
|
base.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the beginning of a JSON object.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteStartObject()
|
||||||
|
{
|
||||||
|
base.WriteStartObject();
|
||||||
|
|
||||||
|
AddParent(new JObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddParent(JContainer container)
|
||||||
|
{
|
||||||
|
if (_parent == null)
|
||||||
|
{
|
||||||
|
_token = container;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_parent.AddAndSkipParentCheck(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
_parent = container;
|
||||||
|
_current = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveParent()
|
||||||
|
{
|
||||||
|
_current = _parent;
|
||||||
|
_parent = _parent!.Parent;
|
||||||
|
|
||||||
|
if (_parent != null && _parent.Type == JTokenType.Property)
|
||||||
|
{
|
||||||
|
_parent = _parent.Parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the beginning of a JSON array.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteStartArray()
|
||||||
|
{
|
||||||
|
base.WriteStartArray();
|
||||||
|
|
||||||
|
AddParent(new JArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the start of a constructor with the given name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the constructor.</param>
|
||||||
|
public override void WriteStartConstructor(string name)
|
||||||
|
{
|
||||||
|
base.WriteStartConstructor(name);
|
||||||
|
|
||||||
|
AddParent(new JConstructor(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the end.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">The token.</param>
|
||||||
|
protected override void WriteEnd(JsonToken token)
|
||||||
|
{
|
||||||
|
RemoveParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the property name of a name/value pair on a JSON object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the property.</param>
|
||||||
|
public override void WritePropertyName(string name)
|
||||||
|
{
|
||||||
|
// avoid duplicate property name exception
|
||||||
|
// last property name wins
|
||||||
|
(_parent as JObject)?.Remove(name);
|
||||||
|
|
||||||
|
AddParent(new JProperty(name));
|
||||||
|
|
||||||
|
// don't set state until after in case of an error
|
||||||
|
// incorrect state will cause issues if writer is disposed when closing open properties
|
||||||
|
base.WritePropertyName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddValue(object? value, JsonToken token)
|
||||||
|
{
|
||||||
|
AddValue(new JValue(value), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddValue(JValue? value, JsonToken token)
|
||||||
|
{
|
||||||
|
if (_parent != null)
|
||||||
|
{
|
||||||
|
// TryAdd will return false if an invalid JToken type is added.
|
||||||
|
// For example, a JComment can't be added to a JObject.
|
||||||
|
// If there is an invalid JToken type then skip it.
|
||||||
|
if (_parent.TryAdd(value))
|
||||||
|
{
|
||||||
|
_current = _parent.Last;
|
||||||
|
|
||||||
|
if (_parent.Type == JTokenType.Property)
|
||||||
|
{
|
||||||
|
_parent = _parent.Parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_value = value ?? JValue.CreateNull();
|
||||||
|
_current = _value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region WriteValue methods
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Object"/> value.
|
||||||
|
/// An error will be raised if the value cannot be written as a single JSON token.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Object"/> value to write.</param>
|
||||||
|
public override void WriteValue(object? value)
|
||||||
|
{
|
||||||
|
#if HAVE_BIG_INTEGER
|
||||||
|
if (value is BigInteger)
|
||||||
|
{
|
||||||
|
InternalWriteValue(JsonToken.Integer);
|
||||||
|
AddValue(value, JsonToken.Integer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a null value.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteNull()
|
||||||
|
{
|
||||||
|
base.WriteNull();
|
||||||
|
AddValue(null, JsonToken.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an undefined value.
|
||||||
|
/// </summary>
|
||||||
|
public override void WriteUndefined()
|
||||||
|
{
|
||||||
|
base.WriteUndefined();
|
||||||
|
AddValue(null, JsonToken.Undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes raw JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">The raw JSON to write.</param>
|
||||||
|
public override void WriteRaw(string? json)
|
||||||
|
{
|
||||||
|
base.WriteRaw(json);
|
||||||
|
AddValue(new JRaw(json), JsonToken.Raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a comment <c>/*...*/</c> containing the specified text.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">Text to place inside the comment.</param>
|
||||||
|
public override void WriteComment(string? text)
|
||||||
|
{
|
||||||
|
base.WriteComment(text);
|
||||||
|
AddValue(JValue.CreateComment(text), JsonToken.Comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="String"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="String"/> value to write.</param>
|
||||||
|
public override void WriteValue(string? value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.String);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Int32"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Int32"/> value to write.</param>
|
||||||
|
public override void WriteValue(int value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="UInt32"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="UInt32"/> value to write.</param>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void WriteValue(uint value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Int64"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Int64"/> value to write.</param>
|
||||||
|
public override void WriteValue(long value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="UInt64"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="UInt64"/> value to write.</param>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void WriteValue(ulong value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Single"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Single"/> value to write.</param>
|
||||||
|
public override void WriteValue(float value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Float);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Double"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Double"/> value to write.</param>
|
||||||
|
public override void WriteValue(double value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Float);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Boolean"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Boolean"/> value to write.</param>
|
||||||
|
public override void WriteValue(bool value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Int16"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Int16"/> value to write.</param>
|
||||||
|
public override void WriteValue(short value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="UInt16"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="UInt16"/> value to write.</param>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void WriteValue(ushort value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Char"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Char"/> value to write.</param>
|
||||||
|
public override void WriteValue(char value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
string s;
|
||||||
|
#if HAVE_CHAR_TO_STRING_WITH_CULTURE
|
||||||
|
s = value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
#else
|
||||||
|
s = value.ToString();
|
||||||
|
#endif
|
||||||
|
AddValue(s, JsonToken.String);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Byte"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Byte"/> value to write.</param>
|
||||||
|
public override void WriteValue(byte value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="SByte"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="SByte"/> value to write.</param>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void WriteValue(sbyte value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Decimal"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Decimal"/> value to write.</param>
|
||||||
|
public override void WriteValue(decimal value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Float);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="DateTime"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="DateTime"/> value to write.</param>
|
||||||
|
public override void WriteValue(DateTime value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling);
|
||||||
|
AddValue(value, JsonToken.Date);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_DATE_TIME_OFFSET
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="DateTimeOffset"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="DateTimeOffset"/> value to write.</param>
|
||||||
|
public override void WriteValue(DateTimeOffset value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Date);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Byte"/>[] value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Byte"/>[] value to write.</param>
|
||||||
|
public override void WriteValue(byte[]? value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="TimeSpan"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="TimeSpan"/> value to write.</param>
|
||||||
|
public override void WriteValue(TimeSpan value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.String);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Guid"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Guid"/> value to write.</param>
|
||||||
|
public override void WriteValue(Guid value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.String);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a <see cref="Uri"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="Uri"/> value to write.</param>
|
||||||
|
public override void WriteValue(Uri? value)
|
||||||
|
{
|
||||||
|
base.WriteValue(value);
|
||||||
|
AddValue(value, JsonToken.String);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
internal override void WriteToken(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments)
|
||||||
|
{
|
||||||
|
// cloning the token rather than reading then writing it doesn't lose some type information, e.g. Guid, byte[], etc
|
||||||
|
if (reader is JTokenReader tokenReader && writeChildren && writeDateConstructorAsDate && writeComments)
|
||||||
|
{
|
||||||
|
if (tokenReader.TokenType == JsonToken.None)
|
||||||
|
{
|
||||||
|
if (!tokenReader.Read())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JToken value = tokenReader.CurrentToken!.CloneToken();
|
||||||
|
|
||||||
|
if (_parent != null)
|
||||||
|
{
|
||||||
|
_parent.Add(value);
|
||||||
|
_current = _parent.Last;
|
||||||
|
|
||||||
|
// if the writer was in a property then move out of it and up to its parent object
|
||||||
|
if (_parent.Type == JTokenType.Property)
|
||||||
|
{
|
||||||
|
_parent = _parent.Parent;
|
||||||
|
InternalWriteValue(JsonToken.Null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_current = value;
|
||||||
|
|
||||||
|
if (_token == null && _value == null)
|
||||||
|
{
|
||||||
|
_token = value as JContainer;
|
||||||
|
_value = value as JValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenReader.Skip();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base.WriteToken(reader, writeChildren, writeDateConstructorAsDate, writeComments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
#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;
|
||||||
|
#if HAVE_BIG_INTEGER
|
||||||
|
using System.Numerics;
|
||||||
|
#endif
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
public partial class JValue
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes this token to a <see cref="JsonWriter"/> asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
|
||||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
||||||
|
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> that represents the asynchronous write operation.</returns>
|
||||||
|
public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
if (converters != null && converters.Length > 0 && _value != null)
|
||||||
|
{
|
||||||
|
JsonConverter? matchingConverter = JsonSerializer.GetMatchingConverter(converters, _value.GetType());
|
||||||
|
if (matchingConverter != null && matchingConverter.CanWrite)
|
||||||
|
{
|
||||||
|
// TODO: Call WriteJsonAsync when it exists.
|
||||||
|
matchingConverter.WriteJson(writer, _value, JsonSerializer.CreateDefault());
|
||||||
|
return AsyncUtils.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_valueType)
|
||||||
|
{
|
||||||
|
case JTokenType.Comment:
|
||||||
|
return writer.WriteCommentAsync(_value?.ToString(), cancellationToken);
|
||||||
|
case JTokenType.Raw:
|
||||||
|
return writer.WriteRawValueAsync(_value?.ToString(), cancellationToken);
|
||||||
|
case JTokenType.Null:
|
||||||
|
return writer.WriteNullAsync(cancellationToken);
|
||||||
|
case JTokenType.Undefined:
|
||||||
|
return writer.WriteUndefinedAsync(cancellationToken);
|
||||||
|
case JTokenType.Integer:
|
||||||
|
if (_value is int i)
|
||||||
|
{
|
||||||
|
return writer.WriteValueAsync(i, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_value is long l)
|
||||||
|
{
|
||||||
|
return writer.WriteValueAsync(l, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_value is ulong ul)
|
||||||
|
{
|
||||||
|
return writer.WriteValueAsync(ul, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_BIG_INTEGER
|
||||||
|
if (_value is BigInteger integer)
|
||||||
|
{
|
||||||
|
return writer.WriteValueAsync(integer, cancellationToken);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return writer.WriteValueAsync(Convert.ToInt64(_value, CultureInfo.InvariantCulture), cancellationToken);
|
||||||
|
case JTokenType.Float:
|
||||||
|
if (_value is decimal dec)
|
||||||
|
{
|
||||||
|
return writer.WriteValueAsync(dec, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_value is double d)
|
||||||
|
{
|
||||||
|
return writer.WriteValueAsync(d, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_value is float f)
|
||||||
|
{
|
||||||
|
return writer.WriteValueAsync(f, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
return writer.WriteValueAsync(Convert.ToDouble(_value, CultureInfo.InvariantCulture), cancellationToken);
|
||||||
|
case JTokenType.String:
|
||||||
|
return writer.WriteValueAsync(_value?.ToString(), cancellationToken);
|
||||||
|
case JTokenType.Boolean:
|
||||||
|
return writer.WriteValueAsync(Convert.ToBoolean(_value, CultureInfo.InvariantCulture), cancellationToken);
|
||||||
|
case JTokenType.Date:
|
||||||
|
if (_value is DateTimeOffset offset)
|
||||||
|
{
|
||||||
|
return writer.WriteValueAsync(offset, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
return writer.WriteValueAsync(Convert.ToDateTime(_value, CultureInfo.InvariantCulture), cancellationToken);
|
||||||
|
case JTokenType.Bytes:
|
||||||
|
return writer.WriteValueAsync((byte[]?)_value, cancellationToken);
|
||||||
|
case JTokenType.Guid:
|
||||||
|
return writer.WriteValueAsync(_value != null ? (Guid?)_value : null, cancellationToken);
|
||||||
|
case JTokenType.TimeSpan:
|
||||||
|
return writer.WriteValueAsync(_value != null ? (TimeSpan?)_value : null, cancellationToken);
|
||||||
|
case JTokenType.Uri:
|
||||||
|
return writer.WriteValueAsync((Uri?)_value, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw MiscellaneousUtils.CreateArgumentOutOfRangeException(nameof(Type), _valueType, "Unexpected token type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,81 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the settings used when loading JSON.
|
||||||
|
/// </summary>
|
||||||
|
public class JsonLoadSettings
|
||||||
|
{
|
||||||
|
private CommentHandling _commentHandling;
|
||||||
|
private LineInfoHandling _lineInfoHandling;
|
||||||
|
private DuplicatePropertyNameHandling _duplicatePropertyNameHandling;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonLoadSettings"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JsonLoadSettings()
|
||||||
|
{
|
||||||
|
_lineInfoHandling = LineInfoHandling.Load;
|
||||||
|
_commentHandling = CommentHandling.Ignore;
|
||||||
|
_duplicatePropertyNameHandling = DuplicatePropertyNameHandling.Replace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how JSON comments are handled when loading JSON.
|
||||||
|
/// The default value is <see cref="CommentHandling.Ignore" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The JSON comment handling.</value>
|
||||||
|
public CommentHandling CommentHandling
|
||||||
|
{
|
||||||
|
get => _commentHandling;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < CommentHandling.Ignore || value > CommentHandling.Load)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_commentHandling = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how JSON line info is handled when loading JSON.
|
||||||
|
/// The default value is <see cref="LineInfoHandling.Load" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The JSON line info handling.</value>
|
||||||
|
public LineInfoHandling LineInfoHandling
|
||||||
|
{
|
||||||
|
get => _lineInfoHandling;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < LineInfoHandling.Ignore || value > LineInfoHandling.Load)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_lineInfoHandling = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how duplicate property names in JSON objects are handled when loading JSON.
|
||||||
|
/// The default value is <see cref="DuplicatePropertyNameHandling.Replace" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The JSON duplicate property name handling.</value>
|
||||||
|
public DuplicatePropertyNameHandling DuplicatePropertyNameHandling
|
||||||
|
{
|
||||||
|
get => _duplicatePropertyNameHandling;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < DuplicatePropertyNameHandling.Replace || value > DuplicatePropertyNameHandling.Error)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_duplicatePropertyNameHandling = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
#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.Linq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the settings used when merging JSON.
|
||||||
|
/// </summary>
|
||||||
|
public class JsonMergeSettings
|
||||||
|
{
|
||||||
|
private MergeArrayHandling _mergeArrayHandling;
|
||||||
|
private MergeNullValueHandling _mergeNullValueHandling;
|
||||||
|
private StringComparison _propertyNameComparison;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonMergeSettings"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JsonMergeSettings()
|
||||||
|
{
|
||||||
|
_propertyNameComparison = StringComparison.Ordinal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the method used when merging JSON arrays.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The method used when merging JSON arrays.</value>
|
||||||
|
public MergeArrayHandling MergeArrayHandling
|
||||||
|
{
|
||||||
|
get => _mergeArrayHandling;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < MergeArrayHandling.Concat || value > MergeArrayHandling.Merge)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_mergeArrayHandling = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets how null value properties are merged.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>How null value properties are merged.</value>
|
||||||
|
public MergeNullValueHandling MergeNullValueHandling
|
||||||
|
{
|
||||||
|
get => _mergeNullValueHandling;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < MergeNullValueHandling.Ignore || value > MergeNullValueHandling.Merge)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_mergeNullValueHandling = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the comparison used to match property names while merging.
|
||||||
|
/// The exact property name will be searched for first and if no matching property is found then
|
||||||
|
/// the <see cref="StringComparison"/> will be used to match a property.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The comparison used to match property names while merging.</value>
|
||||||
|
public StringComparison PropertyNameComparison
|
||||||
|
{
|
||||||
|
get => _propertyNameComparison;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < StringComparison.CurrentCulture || value > StringComparison.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_propertyNameComparison = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using LC.Newtonsoft.Json.Utilities;
|
||||||
|
|
||||||
|
namespace LC.Newtonsoft.Json.Linq.JsonPath
|
||||||
|
{
|
||||||
|
internal class ArrayIndexFilter : PathFilter
|
||||||
|
{
|
||||||
|
public int? Index { get; set; }
|
||||||
|
|
||||||
|
public override IEnumerable<JToken> ExecuteFilter(JToken root, IEnumerable<JToken> current, JsonSelectSettings? settings)
|
||||||
|
{
|
||||||
|
foreach (JToken t in current)
|
||||||
|
{
|
||||||
|
if (Index != null)
|
||||||
|
{
|
||||||
|
JToken? v = GetTokenIndex(t, settings, Index.GetValueOrDefault());
|
||||||
|
|
||||||
|
if (v != null)
|
||||||
|
{
|
||||||
|
yield return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (t is JArray || t is JConstructor)
|
||||||
|
{
|
||||||
|
foreach (JToken v in t)
|
||||||
|
{
|
||||||
|
yield return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (settings?.ErrorWhenNoMatch ?? false)
|
||||||
|
{
|
||||||
|
throw new JsonException("Index * not valid on {0}.".FormatWith(CultureInfo.InvariantCulture, t.GetType().Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue