chore: Newtonsoft.Json.AOT

oneRain 2021-03-31 11:22:02 +08:00
parent c14ac61e59
commit 34955cd95b
242 changed files with 68041 additions and 9 deletions

View File

@ -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>

View File

@ -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
}
}

View File

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

View File

@ -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;
}
}
}

View File

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

View File

@ -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; }
}
}

View File

@ -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
}
}

View File

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

View File

@ -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
}
}

View File

@ -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

View File

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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

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

View File

@ -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();
}
}
}

View File

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

View File

@ -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

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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;
}
}
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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
}
}

View File

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

View File

@ -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; }
}
}

View File

@ -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)
{
}
}
}

View File

@ -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
{
}
}

View File

@ -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

View File

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

View File

@ -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;
}
}
}

View File

@ -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>
{
}
}

View File

@ -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)
{
}
}
}

View File

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

View File

@ -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;
}
}
}

View File

@ -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
{
}
}

View File

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

View File

@ -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)
{
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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

View File

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

View File

@ -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
{
}
}

View File

@ -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

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

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

View File

@ -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>

View File

@ -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
}
}

View File

@ -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
}
}

View File

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

View File

@ -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; }
}
}

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

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

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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
}
}

View File

@ -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

View File

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

View File

@ -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

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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