chore: 初始化北汽福田MES采集程序

This commit is contained in:
yexingqiang
2026-05-29 13:44:10 +08:00
commit c5e248e993
1399 changed files with 187196 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.IO;
namespace Newtonsoft.Json.Utilities
{
internal class Base64Encoder
{
private const int Base64LineSize = 76;
private const int LineSizeInBytes = 57;
private readonly char[] _charsLine = new char[Base64LineSize];
private readonly TextWriter _writer;
private byte[] _leftOverBytes;
private int _leftOverBytesCount;
public Base64Encoder(TextWriter writer)
{
ValidationUtils.ArgumentNotNull(writer, nameof(writer));
_writer = writer;
}
public void Encode(byte[] buffer, int index, int count)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
if (index < 0)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
if (count > (buffer.Length - index))
{
throw new ArgumentOutOfRangeException(nameof(count));
}
if (_leftOverBytesCount > 0)
{
int leftOverBytesCount = _leftOverBytesCount;
while (leftOverBytesCount < 3 && count > 0)
{
_leftOverBytes[leftOverBytesCount++] = buffer[index++];
count--;
}
if (count == 0 && leftOverBytesCount < 3)
{
_leftOverBytesCount = leftOverBytesCount;
return;
}
int num2 = Convert.ToBase64CharArray(_leftOverBytes, 0, 3, _charsLine, 0);
WriteChars(_charsLine, 0, num2);
}
_leftOverBytesCount = count % 3;
if (_leftOverBytesCount > 0)
{
count -= _leftOverBytesCount;
if (_leftOverBytes == null)
{
_leftOverBytes = new byte[3];
}
for (int i = 0; i < _leftOverBytesCount; i++)
{
_leftOverBytes[i] = buffer[(index + count) + i];
}
}
int num4 = index + count;
int length = LineSizeInBytes;
while (index < num4)
{
if ((index + length) > num4)
{
length = num4 - index;
}
int num6 = Convert.ToBase64CharArray(buffer, index, length, _charsLine, 0);
WriteChars(_charsLine, 0, num6);
index += length;
}
}
public void Flush()
{
if (_leftOverBytesCount > 0)
{
int count = Convert.ToBase64CharArray(_leftOverBytes, 0, _leftOverBytesCount, _charsLine, 0);
WriteChars(_charsLine, 0, count);
_leftOverBytesCount = 0;
}
}
private void WriteChars(char[] chars, int index, int count)
{
_writer.Write(chars, index, count);
}
}
}

View File

@@ -0,0 +1,97 @@
#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;
namespace Newtonsoft.Json.Utilities
{
internal class BidirectionalDictionary<TFirst, TSecond>
{
private readonly IDictionary<TFirst, TSecond> _firstToSecond;
private readonly IDictionary<TSecond, TFirst> _secondToFirst;
private readonly string _duplicateFirstErrorMessage;
private readonly string _duplicateSecondErrorMessage;
public BidirectionalDictionary()
: this(EqualityComparer<TFirst>.Default, EqualityComparer<TSecond>.Default)
{
}
public BidirectionalDictionary(IEqualityComparer<TFirst> firstEqualityComparer, IEqualityComparer<TSecond> secondEqualityComparer)
: this(
firstEqualityComparer,
secondEqualityComparer,
"Duplicate item already exists for '{0}'.",
"Duplicate item already exists for '{0}'.")
{
}
public BidirectionalDictionary(IEqualityComparer<TFirst> firstEqualityComparer, IEqualityComparer<TSecond> secondEqualityComparer,
string duplicateFirstErrorMessage, string duplicateSecondErrorMessage)
{
_firstToSecond = new Dictionary<TFirst, TSecond>(firstEqualityComparer);
_secondToFirst = new Dictionary<TSecond, TFirst>(secondEqualityComparer);
_duplicateFirstErrorMessage = duplicateFirstErrorMessage;
_duplicateSecondErrorMessage = duplicateSecondErrorMessage;
}
public void Set(TFirst first, TSecond second)
{
TFirst existingFirst;
TSecond existingSecond;
if (_firstToSecond.TryGetValue(first, out existingSecond))
{
if (!existingSecond.Equals(second))
{
throw new ArgumentException(_duplicateFirstErrorMessage.FormatWith(CultureInfo.InvariantCulture, first));
}
}
if (_secondToFirst.TryGetValue(second, out existingFirst))
{
if (!existingFirst.Equals(first))
{
throw new ArgumentException(_duplicateSecondErrorMessage.FormatWith(CultureInfo.InvariantCulture, second));
}
}
_firstToSecond.Add(first, second);
_secondToFirst.Add(second, first);
}
public bool TryGetByFirst(TFirst first, out TSecond second)
{
return _firstToSecond.TryGetValue(first, out second);
}
public bool TryGetBySecond(TSecond second, out TFirst first)
{
return _secondToFirst.TryGetValue(second, out first);
}
}
}

View File

@@ -0,0 +1,348 @@
#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.Reflection;
using System.Text;
using System.Collections;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
using System.Globalization;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Utilities
{
internal static class CollectionUtils
{
/// <summary>
/// Determines whether the collection is null or empty.
/// </summary>
/// <param name="collection">The collection.</param>
/// <returns>
/// <c>true</c> if the collection is null or empty; otherwise, <c>false</c>.
/// </returns>
public static bool IsNullOrEmpty<T>(ICollection<T> collection)
{
if (collection != null)
{
return (collection.Count == 0);
}
return true;
}
/// <summary>
/// Adds the elements of the specified collection to the specified generic IList.
/// </summary>
/// <param name="initial">The list to add to.</param>
/// <param name="collection">The collection of elements to add.</param>
public static void AddRange<T>(this IList<T> initial, IEnumerable<T> collection)
{
if (initial == null)
{
throw new ArgumentNullException(nameof(initial));
}
if (collection == null)
{
return;
}
foreach (T value in collection)
{
initial.Add(value);
}
}
#if (NET20 || NET35 || PORTABLE40)
public static void AddRange<T>(this IList<T> initial, IEnumerable collection)
{
ValidationUtils.ArgumentNotNull(initial, nameof(initial));
// because earlier versions of .NET didn't support covariant generics
initial.AddRange(collection.Cast<T>());
}
#endif
public static bool IsDictionaryType(Type type)
{
ValidationUtils.ArgumentNotNull(type, nameof(type));
if (typeof(IDictionary).IsAssignableFrom(type))
{
return true;
}
if (ReflectionUtils.ImplementsGenericDefinition(type, typeof(IDictionary<,>)))
{
return true;
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
if (ReflectionUtils.ImplementsGenericDefinition(type, typeof(IReadOnlyDictionary<,>)))
{
return true;
}
#endif
return false;
}
public static ConstructorInfo ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType)
{
Type genericEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionItemType);
ConstructorInfo match = null;
foreach (ConstructorInfo constructor in collectionType.GetConstructors(BindingFlags.Public | BindingFlags.Instance))
{
IList<ParameterInfo> parameters = constructor.GetParameters();
if (parameters.Count == 1)
{
if (genericEnumerable == parameters[0].ParameterType)
{
// exact match
match = constructor;
break;
}
// incase we can't find an exact match, use first inexact
if (match == null)
{
if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
{
match = constructor;
}
}
}
}
return match;
}
public static bool AddDistinct<T>(this IList<T> list, T value)
{
return list.AddDistinct(value, EqualityComparer<T>.Default);
}
public static bool AddDistinct<T>(this IList<T> list, T value, IEqualityComparer<T> comparer)
{
if (list.ContainsValue(value, comparer))
{
return false;
}
list.Add(value);
return true;
}
// this is here because LINQ Bridge doesn't support Contains with IEqualityComparer<T>
public static bool ContainsValue<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
{
if (comparer == null)
{
comparer = EqualityComparer<TSource>.Default;
}
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
foreach (TSource local in source)
{
if (comparer.Equals(local, value))
{
return true;
}
}
return false;
}
public static bool AddRangeDistinct<T>(this IList<T> list, IEnumerable<T> values, IEqualityComparer<T> comparer)
{
bool allAdded = true;
foreach (T value in values)
{
if (!list.AddDistinct(value, comparer))
{
allAdded = false;
}
}
return allAdded;
}
public static int IndexOf<T>(this IEnumerable<T> collection, Func<T, bool> predicate)
{
int index = 0;
foreach (T value in collection)
{
if (predicate(value))
{
return index;
}
index++;
}
return -1;
}
public static bool Contains(this IEnumerable list, object value, IEqualityComparer comparer)
{
foreach (object item in list)
{
if (comparer.Equals(item, value))
{
return true;
}
}
return false;
}
/// <summary>
/// Returns the index of the first occurrence in a sequence by using a specified IEqualityComparer{TSource}.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <param name="list">A sequence in which to locate a value.</param>
/// <param name="value">The object to locate in the sequence</param>
/// <param name="comparer">An equality comparer to compare values.</param>
/// <returns>The zero-based index of the first occurrence of value within the entire sequence, if found; otherwise, ?.</returns>
public static int IndexOf<TSource>(this IEnumerable<TSource> list, TSource value, IEqualityComparer<TSource> comparer)
{
int index = 0;
foreach (TSource item in list)
{
if (comparer.Equals(item, value))
{
return index;
}
index++;
}
return -1;
}
private static IList<int> GetDimensions(IList values, int dimensionsCount)
{
IList<int> dimensions = new List<int>();
IList currentArray = values;
while (true)
{
dimensions.Add(currentArray.Count);
// don't keep calculating dimensions for arrays inside the value array
if (dimensions.Count == dimensionsCount)
{
break;
}
if (currentArray.Count == 0)
{
break;
}
object v = currentArray[0];
if (v is IList)
{
currentArray = (IList)v;
}
else
{
break;
}
}
return dimensions;
}
private static void CopyFromJaggedToMultidimensionalArray(IList values, Array multidimensionalArray, int[] indices)
{
int dimension = indices.Length;
if (dimension == multidimensionalArray.Rank)
{
multidimensionalArray.SetValue(JaggedArrayGetValue(values, indices), indices);
return;
}
int dimensionLength = multidimensionalArray.GetLength(dimension);
IList list = (IList)JaggedArrayGetValue(values, indices);
int currentValuesLength = list.Count;
if (currentValuesLength != dimensionLength)
{
throw new Exception("Cannot deserialize non-cubical array as multidimensional array.");
}
int[] newIndices = new int[dimension + 1];
for (int i = 0; i < dimension; i++)
{
newIndices[i] = indices[i];
}
for (int i = 0; i < multidimensionalArray.GetLength(dimension); i++)
{
newIndices[dimension] = i;
CopyFromJaggedToMultidimensionalArray(values, multidimensionalArray, newIndices);
}
}
private static object JaggedArrayGetValue(IList values, int[] indices)
{
IList currentList = values;
for (int i = 0; i < indices.Length; i++)
{
int index = indices[i];
if (i == indices.Length - 1)
{
return currentList[index];
}
else
{
currentList = (IList)currentList[index];
}
}
return currentList;
}
public static Array ToMultidimensionalArray(IList values, Type type, int rank)
{
IList<int> dimensions = GetDimensions(values, rank);
while (dimensions.Count < rank)
{
dimensions.Add(0);
}
Array multidimensionalArray = Array.CreateInstance(type, dimensions.ToArray());
CopyFromJaggedToMultidimensionalArray(values, multidimensionalArray, new int[0]);
return multidimensionalArray;
}
}
}

View File

@@ -0,0 +1,348 @@
#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.Threading;
using System.Globalization;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
namespace Newtonsoft.Json.Utilities
{
internal interface IWrappedCollection : IList
{
object UnderlyingCollection { get; }
}
internal class CollectionWrapper<T> : ICollection<T>, IWrappedCollection
{
private readonly IList _list;
private readonly ICollection<T> _genericCollection;
private object _syncRoot;
public CollectionWrapper(IList list)
{
ValidationUtils.ArgumentNotNull(list, nameof(list));
if (list is ICollection<T>)
{
_genericCollection = (ICollection<T>)list;
}
else
{
_list = list;
}
}
public CollectionWrapper(ICollection<T> list)
{
ValidationUtils.ArgumentNotNull(list, nameof(list));
_genericCollection = list;
}
public virtual void Add(T item)
{
if (_genericCollection != null)
{
_genericCollection.Add(item);
}
else
{
_list.Add(item);
}
}
public virtual void Clear()
{
if (_genericCollection != null)
{
_genericCollection.Clear();
}
else
{
_list.Clear();
}
}
public virtual bool Contains(T item)
{
if (_genericCollection != null)
{
return _genericCollection.Contains(item);
}
else
{
return _list.Contains(item);
}
}
public virtual void CopyTo(T[] array, int arrayIndex)
{
if (_genericCollection != null)
{
_genericCollection.CopyTo(array, arrayIndex);
}
else
{
_list.CopyTo(array, arrayIndex);
}
}
public virtual int Count
{
get
{
if (_genericCollection != null)
{
return _genericCollection.Count;
}
else
{
return _list.Count;
}
}
}
public virtual bool IsReadOnly
{
get
{
if (_genericCollection != null)
{
return _genericCollection.IsReadOnly;
}
else
{
return _list.IsReadOnly;
}
}
}
public virtual bool Remove(T item)
{
if (_genericCollection != null)
{
return _genericCollection.Remove(item);
}
else
{
bool contains = _list.Contains(item);
if (contains)
{
_list.Remove(item);
}
return contains;
}
}
public virtual IEnumerator<T> GetEnumerator()
{
if (_genericCollection != null)
{
return _genericCollection.GetEnumerator();
}
return _list.Cast<T>().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
if (_genericCollection != null)
{
return _genericCollection.GetEnumerator();
}
else
{
return _list.GetEnumerator();
}
}
int IList.Add(object value)
{
VerifyValueType(value);
Add((T)value);
return (Count - 1);
}
bool IList.Contains(object value)
{
if (IsCompatibleObject(value))
{
return Contains((T)value);
}
return false;
}
int IList.IndexOf(object value)
{
if (_genericCollection != null)
{
throw new InvalidOperationException("Wrapped ICollection<T> does not support IndexOf.");
}
if (IsCompatibleObject(value))
{
return _list.IndexOf((T)value);
}
return -1;
}
void IList.RemoveAt(int index)
{
if (_genericCollection != null)
{
throw new InvalidOperationException("Wrapped ICollection<T> does not support RemoveAt.");
}
_list.RemoveAt(index);
}
void IList.Insert(int index, object value)
{
if (_genericCollection != null)
{
throw new InvalidOperationException("Wrapped ICollection<T> does not support Insert.");
}
VerifyValueType(value);
_list.Insert(index, (T)value);
}
bool IList.IsFixedSize
{
get
{
if (_genericCollection != null)
{
// ICollection<T> only has IsReadOnly
return _genericCollection.IsReadOnly;
}
else
{
return _list.IsFixedSize;
}
}
}
void IList.Remove(object value)
{
if (IsCompatibleObject(value))
{
Remove((T)value);
}
}
object IList.this[int index]
{
get
{
if (_genericCollection != null)
{
throw new InvalidOperationException("Wrapped ICollection<T> does not support indexer.");
}
return _list[index];
}
set
{
if (_genericCollection != null)
{
throw new InvalidOperationException("Wrapped ICollection<T> does not support indexer.");
}
VerifyValueType(value);
_list[index] = (T)value;
}
}
void ICollection.CopyTo(Array array, int arrayIndex)
{
CopyTo((T[])array, arrayIndex);
}
bool ICollection.IsSynchronized
{
get { return false; }
}
object ICollection.SyncRoot
{
get
{
if (_syncRoot == null)
{
Interlocked.CompareExchange(ref _syncRoot, new object(), null);
}
return _syncRoot;
}
}
private static void VerifyValueType(object value)
{
if (!IsCompatibleObject(value))
{
throw new ArgumentException("The value '{0}' is not of type '{1}' and cannot be used in this generic collection.".FormatWith(CultureInfo.InvariantCulture, value, typeof(T)), nameof(value));
}
}
private static bool IsCompatibleObject(object value)
{
if (!(value is T) && (value != null || (typeof(T).IsValueType() && !ReflectionUtils.IsNullableType(typeof(T)))))
{
return false;
}
return true;
}
public object UnderlyingCollection
{
get
{
if (_genericCollection != null)
{
return _genericCollection;
}
else
{
return _list;
}
}
}
}
}

View File

@@ -0,0 +1,987 @@
#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.ComponentModel;
#if !(NET20 || NET35 || PORTABLE40 || PORTABLE)
using System.Numerics;
#endif
using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Serialization;
using System.Reflection;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#endif
#if !(DOTNET || PORTABLE40 || PORTABLE)
using System.Data.SqlTypes;
#endif
namespace Newtonsoft.Json.Utilities
{
internal enum PrimitiveTypeCode
{
Empty = 0,
Object = 1,
Char = 2,
CharNullable = 3,
Boolean = 4,
BooleanNullable = 5,
SByte = 6,
SByteNullable = 7,
Int16 = 8,
Int16Nullable = 9,
UInt16 = 10,
UInt16Nullable = 11,
Int32 = 12,
Int32Nullable = 13,
Byte = 14,
ByteNullable = 15,
UInt32 = 16,
UInt32Nullable = 17,
Int64 = 18,
Int64Nullable = 19,
UInt64 = 20,
UInt64Nullable = 21,
Single = 22,
SingleNullable = 23,
Double = 24,
DoubleNullable = 25,
DateTime = 26,
DateTimeNullable = 27,
DateTimeOffset = 28,
DateTimeOffsetNullable = 29,
Decimal = 30,
DecimalNullable = 31,
Guid = 32,
GuidNullable = 33,
TimeSpan = 34,
TimeSpanNullable = 35,
BigInteger = 36,
BigIntegerNullable = 37,
Uri = 38,
String = 39,
Bytes = 40,
DBNull = 41
}
internal class TypeInformation
{
public Type Type { get; set; }
public PrimitiveTypeCode TypeCode { get; set; }
}
internal enum ParseResult
{
None = 0,
Success = 1,
Overflow = 2,
Invalid = 3
}
internal static class ConvertUtils
{
private static readonly Dictionary<Type, PrimitiveTypeCode> TypeCodeMap =
new Dictionary<Type, PrimitiveTypeCode>
{
{ typeof(char), PrimitiveTypeCode.Char },
{ typeof(char?), PrimitiveTypeCode.CharNullable },
{ typeof(bool), PrimitiveTypeCode.Boolean },
{ typeof(bool?), PrimitiveTypeCode.BooleanNullable },
{ typeof(sbyte), PrimitiveTypeCode.SByte },
{ typeof(sbyte?), PrimitiveTypeCode.SByteNullable },
{ typeof(short), PrimitiveTypeCode.Int16 },
{ typeof(short?), PrimitiveTypeCode.Int16Nullable },
{ typeof(ushort), PrimitiveTypeCode.UInt16 },
{ typeof(ushort?), PrimitiveTypeCode.UInt16Nullable },
{ typeof(int), PrimitiveTypeCode.Int32 },
{ typeof(int?), PrimitiveTypeCode.Int32Nullable },
{ typeof(byte), PrimitiveTypeCode.Byte },
{ typeof(byte?), PrimitiveTypeCode.ByteNullable },
{ typeof(uint), PrimitiveTypeCode.UInt32 },
{ typeof(uint?), PrimitiveTypeCode.UInt32Nullable },
{ typeof(long), PrimitiveTypeCode.Int64 },
{ typeof(long?), PrimitiveTypeCode.Int64Nullable },
{ typeof(ulong), PrimitiveTypeCode.UInt64 },
{ typeof(ulong?), PrimitiveTypeCode.UInt64Nullable },
{ typeof(float), PrimitiveTypeCode.Single },
{ typeof(float?), PrimitiveTypeCode.SingleNullable },
{ typeof(double), PrimitiveTypeCode.Double },
{ typeof(double?), PrimitiveTypeCode.DoubleNullable },
{ typeof(DateTime), PrimitiveTypeCode.DateTime },
{ typeof(DateTime?), PrimitiveTypeCode.DateTimeNullable },
#if !NET20
{ typeof(DateTimeOffset), PrimitiveTypeCode.DateTimeOffset },
{ typeof(DateTimeOffset?), PrimitiveTypeCode.DateTimeOffsetNullable },
#endif
{ typeof(decimal), PrimitiveTypeCode.Decimal },
{ typeof(decimal?), PrimitiveTypeCode.DecimalNullable },
{ typeof(Guid), PrimitiveTypeCode.Guid },
{ typeof(Guid?), PrimitiveTypeCode.GuidNullable },
{ typeof(TimeSpan), PrimitiveTypeCode.TimeSpan },
{ typeof(TimeSpan?), PrimitiveTypeCode.TimeSpanNullable },
#if !(PORTABLE || PORTABLE40 || NET35 || NET20)
{ typeof(BigInteger), PrimitiveTypeCode.BigInteger },
{ typeof(BigInteger?), PrimitiveTypeCode.BigIntegerNullable },
#endif
{ typeof(Uri), PrimitiveTypeCode.Uri },
{ typeof(string), PrimitiveTypeCode.String },
{ typeof(byte[]), PrimitiveTypeCode.Bytes },
#if !(PORTABLE || PORTABLE40 || DOTNET)
{ typeof(DBNull), PrimitiveTypeCode.DBNull }
#endif
};
#if !PORTABLE
private static readonly TypeInformation[] PrimitiveTypeCodes =
{
// need all of these. lookup against the index with TypeCode value
new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Empty },
new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Object },
new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.DBNull },
new TypeInformation { Type = typeof(bool), TypeCode = PrimitiveTypeCode.Boolean },
new TypeInformation { Type = typeof(char), TypeCode = PrimitiveTypeCode.Char },
new TypeInformation { Type = typeof(sbyte), TypeCode = PrimitiveTypeCode.SByte },
new TypeInformation { Type = typeof(byte), TypeCode = PrimitiveTypeCode.Byte },
new TypeInformation { Type = typeof(short), TypeCode = PrimitiveTypeCode.Int16 },
new TypeInformation { Type = typeof(ushort), TypeCode = PrimitiveTypeCode.UInt16 },
new TypeInformation { Type = typeof(int), TypeCode = PrimitiveTypeCode.Int32 },
new TypeInformation { Type = typeof(uint), TypeCode = PrimitiveTypeCode.UInt32 },
new TypeInformation { Type = typeof(long), TypeCode = PrimitiveTypeCode.Int64 },
new TypeInformation { Type = typeof(ulong), TypeCode = PrimitiveTypeCode.UInt64 },
new TypeInformation { Type = typeof(float), TypeCode = PrimitiveTypeCode.Single },
new TypeInformation { Type = typeof(double), TypeCode = PrimitiveTypeCode.Double },
new TypeInformation { Type = typeof(decimal), TypeCode = PrimitiveTypeCode.Decimal },
new TypeInformation { Type = typeof(DateTime), TypeCode = PrimitiveTypeCode.DateTime },
new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Empty }, // no 17 in TypeCode for some reason
new TypeInformation { Type = typeof(string), TypeCode = PrimitiveTypeCode.String }
};
#endif
public static PrimitiveTypeCode GetTypeCode(Type t)
{
bool isEnum;
return GetTypeCode(t, out isEnum);
}
public static PrimitiveTypeCode GetTypeCode(Type t, out bool isEnum)
{
PrimitiveTypeCode typeCode;
if (TypeCodeMap.TryGetValue(t, out typeCode))
{
isEnum = false;
return typeCode;
}
if (t.IsEnum())
{
isEnum = true;
return GetTypeCode(Enum.GetUnderlyingType(t));
}
// performance?
if (ReflectionUtils.IsNullableType(t))
{
Type nonNullable = Nullable.GetUnderlyingType(t);
if (nonNullable.IsEnum())
{
Type nullableUnderlyingType = typeof(Nullable<>).MakeGenericType(Enum.GetUnderlyingType(nonNullable));
isEnum = true;
return GetTypeCode(nullableUnderlyingType);
}
}
isEnum = false;
return PrimitiveTypeCode.Object;
}
#if !PORTABLE
public static TypeInformation GetTypeInformation(IConvertible convertable)
{
TypeInformation typeInformation = PrimitiveTypeCodes[(int)convertable.GetTypeCode()];
return typeInformation;
}
#endif
public static bool IsConvertible(Type t)
{
#if !PORTABLE
return typeof(IConvertible).IsAssignableFrom(t);
#else
return (
t == typeof(bool) || t == typeof(byte) || t == typeof(char) || t == typeof(DateTime) || t == typeof(decimal) || t == typeof(double) || t == typeof(short) || t == typeof(int) ||
t == typeof(long) || t == typeof(sbyte) || t == typeof(float) || t == typeof(string) || t == typeof(ushort) || t == typeof(uint) || t == typeof(ulong) || t.IsEnum());
#endif
}
public static TimeSpan ParseTimeSpan(string input)
{
#if !(NET35 || NET20)
return TimeSpan.Parse(input, CultureInfo.InvariantCulture);
#else
return TimeSpan.Parse(input);
#endif
}
internal struct TypeConvertKey : IEquatable<TypeConvertKey>
{
private readonly Type _initialType;
private readonly Type _targetType;
public Type InitialType
{
get { return _initialType; }
}
public Type TargetType
{
get { return _targetType; }
}
public TypeConvertKey(Type initialType, Type targetType)
{
_initialType = initialType;
_targetType = targetType;
}
public override int GetHashCode()
{
return _initialType.GetHashCode() ^ _targetType.GetHashCode();
}
public override bool Equals(object obj)
{
if (!(obj is TypeConvertKey))
{
return false;
}
return Equals((TypeConvertKey)obj);
}
public bool Equals(TypeConvertKey other)
{
return (_initialType == other._initialType && _targetType == other._targetType);
}
}
private static readonly ThreadSafeStore<TypeConvertKey, Func<object, object>> CastConverters =
new ThreadSafeStore<TypeConvertKey, Func<object, object>>(CreateCastConverter);
private static Func<object, object> CreateCastConverter(TypeConvertKey t)
{
MethodInfo castMethodInfo = t.TargetType.GetMethod("op_Implicit", new[] { t.InitialType });
if (castMethodInfo == null)
{
castMethodInfo = t.TargetType.GetMethod("op_Explicit", new[] { t.InitialType });
}
if (castMethodInfo == null)
{
return null;
}
MethodCall<object, object> call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(castMethodInfo);
return o => call(null, o);
}
#if !(NET20 || NET35 || PORTABLE || PORTABLE40)
internal static BigInteger ToBigInteger(object value)
{
if (value is BigInteger)
{
return (BigInteger)value;
}
if (value is string)
{
return BigInteger.Parse((string)value, CultureInfo.InvariantCulture);
}
if (value is float)
{
return new BigInteger((float)value);
}
if (value is double)
{
return new BigInteger((double)value);
}
if (value is decimal)
{
return new BigInteger((decimal)value);
}
if (value is int)
{
return new BigInteger((int)value);
}
if (value is long)
{
return new BigInteger((long)value);
}
if (value is uint)
{
return new BigInteger((uint)value);
}
if (value is ulong)
{
return new BigInteger((ulong)value);
}
if (value is byte[])
{
return new BigInteger((byte[])value);
}
throw new InvalidCastException("Cannot convert {0} to BigInteger.".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
}
public static object FromBigInteger(BigInteger i, Type targetType)
{
if (targetType == typeof(decimal))
{
return (decimal)i;
}
if (targetType == typeof(double))
{
return (double)i;
}
if (targetType == typeof(float))
{
return (float)i;
}
if (targetType == typeof(ulong))
{
return (ulong)i;
}
if (targetType == typeof(bool))
{
return i != 0;
}
try
{
return System.Convert.ChangeType((long)i, targetType, CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
throw new InvalidOperationException("Can not convert from BigInteger to {0}.".FormatWith(CultureInfo.InvariantCulture, targetType), ex);
}
}
#endif
#region TryConvert
internal enum ConvertResult
{
Success = 0,
CannotConvertNull = 1,
NotInstantiableType = 2,
NoValidConversion = 3
}
public static object Convert(object initialValue, CultureInfo culture, Type targetType)
{
object value;
switch (TryConvertInternal(initialValue, culture, targetType, out value))
{
case ConvertResult.Success:
return value;
case ConvertResult.CannotConvertNull:
throw new Exception("Can not convert null {0} into non-nullable {1}.".FormatWith(CultureInfo.InvariantCulture, initialValue.GetType(), targetType));
case ConvertResult.NotInstantiableType:
throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), nameof(targetType));
case ConvertResult.NoValidConversion:
throw new InvalidOperationException("Can not convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, initialValue.GetType(), targetType));
default:
throw new InvalidOperationException("Unexpected conversion result.");
}
}
private static bool TryConvert(object initialValue, CultureInfo culture, Type targetType, out object value)
{
try
{
if (TryConvertInternal(initialValue, culture, targetType, out value) == ConvertResult.Success)
{
return true;
}
value = null;
return false;
}
catch
{
value = null;
return false;
}
}
private static ConvertResult TryConvertInternal(object initialValue, CultureInfo culture, Type targetType, out object value)
{
if (initialValue == null)
{
throw new ArgumentNullException(nameof(initialValue));
}
if (ReflectionUtils.IsNullableType(targetType))
{
targetType = Nullable.GetUnderlyingType(targetType);
}
Type initialType = initialValue.GetType();
if (targetType == initialType)
{
value = initialValue;
return ConvertResult.Success;
}
// use Convert.ChangeType if both types are IConvertible
if (ConvertUtils.IsConvertible(initialValue.GetType()) && ConvertUtils.IsConvertible(targetType))
{
if (targetType.IsEnum())
{
if (initialValue is string)
{
value = Enum.Parse(targetType, initialValue.ToString(), true);
return ConvertResult.Success;
}
else if (IsInteger(initialValue))
{
value = Enum.ToObject(targetType, initialValue);
return ConvertResult.Success;
}
}
value = System.Convert.ChangeType(initialValue, targetType, culture);
return ConvertResult.Success;
}
#if !NET20
if (initialValue is DateTime && targetType == typeof(DateTimeOffset))
{
value = new DateTimeOffset((DateTime)initialValue);
return ConvertResult.Success;
}
#endif
if (initialValue is byte[] && targetType == typeof(Guid))
{
value = new Guid((byte[])initialValue);
return ConvertResult.Success;
}
if (initialValue is Guid && targetType == typeof(byte[]))
{
value = ((Guid)initialValue).ToByteArray();
return ConvertResult.Success;
}
string s = initialValue as string;
if (s != null)
{
if (targetType == typeof(Guid))
{
value = new Guid(s);
return ConvertResult.Success;
}
if (targetType == typeof(Uri))
{
value = new Uri(s, UriKind.RelativeOrAbsolute);
return ConvertResult.Success;
}
if (targetType == typeof(TimeSpan))
{
value = ParseTimeSpan(s);
return ConvertResult.Success;
}
if (targetType == typeof(byte[]))
{
value = System.Convert.FromBase64String(s);
return ConvertResult.Success;
}
if (targetType == typeof(Version))
{
Version result;
if (VersionTryParse(s, out result))
{
value = result;
return ConvertResult.Success;
}
value = null;
return ConvertResult.NoValidConversion;
}
if (typeof(Type).IsAssignableFrom(targetType))
{
value = Type.GetType(s, true);
return ConvertResult.Success;
}
}
#if !(NET20 || NET35 || PORTABLE40 || PORTABLE)
if (targetType == typeof(BigInteger))
{
value = ToBigInteger(initialValue);
return ConvertResult.Success;
}
if (initialValue is BigInteger)
{
value = FromBigInteger((BigInteger)initialValue, targetType);
return ConvertResult.Success;
}
#endif
#if !(PORTABLE40 || PORTABLE)
// see if source or target types have a TypeConverter that converts between the two
TypeConverter toConverter = GetConverter(initialType);
if (toConverter != null && toConverter.CanConvertTo(targetType))
{
value = toConverter.ConvertTo(null, culture, initialValue, targetType);
return ConvertResult.Success;
}
TypeConverter fromConverter = GetConverter(targetType);
if (fromConverter != null && fromConverter.CanConvertFrom(initialType))
{
value = fromConverter.ConvertFrom(null, culture, initialValue);
return ConvertResult.Success;
}
#endif
#if !(DOTNET || PORTABLE40 || PORTABLE)
// handle DBNull and INullable
if (initialValue == DBNull.Value)
{
if (ReflectionUtils.IsNullable(targetType))
{
value = EnsureTypeAssignable(null, initialType, targetType);
return ConvertResult.Success;
}
// cannot convert null to non-nullable
value = null;
return ConvertResult.CannotConvertNull;
}
#endif
#if !(DOTNET || PORTABLE40 || PORTABLE)
if (initialValue is INullable)
{
value = EnsureTypeAssignable(ToValue((INullable)initialValue), initialType, targetType);
return ConvertResult.Success;
}
#endif
if (targetType.IsInterface() || targetType.IsGenericTypeDefinition() || targetType.IsAbstract())
{
value = null;
return ConvertResult.NotInstantiableType;
}
value = null;
return ConvertResult.NoValidConversion;
}
#endregion
#region ConvertOrCast
/// <summary>
/// Converts the value to the specified type. If the value is unable to be converted, the
/// value is checked whether it assignable to the specified type.
/// </summary>
/// <param name="initialValue">The value to convert.</param>
/// <param name="culture">The culture to use when converting.</param>
/// <param name="targetType">The type to convert or cast the value to.</param>
/// <returns>
/// The converted type. If conversion was unsuccessful, the initial value
/// is returned if assignable to the target type.
/// </returns>
public static object ConvertOrCast(object initialValue, CultureInfo culture, Type targetType)
{
object convertedValue;
if (targetType == typeof(object))
{
return initialValue;
}
if (initialValue == null && ReflectionUtils.IsNullable(targetType))
{
return null;
}
if (TryConvert(initialValue, culture, targetType, out convertedValue))
{
return convertedValue;
}
return EnsureTypeAssignable(initialValue, ReflectionUtils.GetObjectType(initialValue), targetType);
}
#endregion
private static object EnsureTypeAssignable(object value, Type initialType, Type targetType)
{
Type valueType = (value != null) ? value.GetType() : null;
if (value != null)
{
if (targetType.IsAssignableFrom(valueType))
{
return value;
}
Func<object, object> castConverter = CastConverters.Get(new TypeConvertKey(valueType, targetType));
if (castConverter != null)
{
return castConverter(value);
}
}
else
{
if (ReflectionUtils.IsNullable(targetType))
{
return null;
}
}
throw new ArgumentException("Could not cast or convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, (initialType != null) ? initialType.ToString() : "{null}", targetType));
}
#if !(DOTNET || PORTABLE40 || PORTABLE)
public static object ToValue(INullable nullableValue)
{
if (nullableValue == null)
{
return null;
}
else if (nullableValue is SqlInt32)
{
return ToValue((SqlInt32)nullableValue);
}
else if (nullableValue is SqlInt64)
{
return ToValue((SqlInt64)nullableValue);
}
else if (nullableValue is SqlBoolean)
{
return ToValue((SqlBoolean)nullableValue);
}
else if (nullableValue is SqlString)
{
return ToValue((SqlString)nullableValue);
}
else if (nullableValue is SqlDateTime)
{
return ToValue((SqlDateTime)nullableValue);
}
throw new ArgumentException("Unsupported INullable type: {0}".FormatWith(CultureInfo.InvariantCulture, nullableValue.GetType()));
}
#endif
#if !(PORTABLE40 || PORTABLE)
internal static TypeConverter GetConverter(Type t)
{
return JsonTypeReflector.GetTypeConverter(t);
}
#endif
public static bool VersionTryParse(string input, out Version result)
{
#if !(NET20 || NET35)
return Version.TryParse(input, out result);
#else
// improve failure performance with regex?
try
{
result = new Version(input);
return true;
}
catch
{
result = null;
return false;
}
#endif
}
public static bool IsInteger(object value)
{
switch (GetTypeCode(value.GetType()))
{
case PrimitiveTypeCode.SByte:
case PrimitiveTypeCode.Byte:
case PrimitiveTypeCode.Int16:
case PrimitiveTypeCode.UInt16:
case PrimitiveTypeCode.Int32:
case PrimitiveTypeCode.UInt32:
case PrimitiveTypeCode.Int64:
case PrimitiveTypeCode.UInt64:
return true;
default:
return false;
}
}
public static ParseResult Int32TryParse(char[] chars, int start, int length, out int value)
{
value = 0;
if (length == 0)
{
return ParseResult.Invalid;
}
bool isNegative = (chars[start] == '-');
if (isNegative)
{
// text just a negative sign
if (length == 1)
{
return ParseResult.Invalid;
}
start++;
length--;
}
int end = start + length;
// Int32.MaxValue and MinValue are 10 chars
// Or is 10 chars and start is greater than two
// Need to improve this!
if (length > 10 || (length == 10 && chars[start] - '0' > 2))
{
// invalid result takes precedence over overflow
for (int i = start; i < end; i++)
{
int c = chars[i] - '0';
if (c < 0 || c > 9)
{
return ParseResult.Invalid;
}
}
return ParseResult.Overflow;
}
for (int i = start; i < end; i++)
{
int c = chars[i] - '0';
if (c < 0 || c > 9)
{
return ParseResult.Invalid;
}
int newValue = (10 * value) - c;
// overflow has caused the number to loop around
if (newValue > value)
{
i++;
// double check the rest of the string that there wasn't anything invalid
// invalid result takes precedence over overflow result
for (; i < end; i++)
{
c = chars[i] - '0';
if (c < 0 || c > 9)
{
return ParseResult.Invalid;
}
}
return ParseResult.Overflow;
}
value = newValue;
}
// go from negative to positive to avoids overflow
// negative can be slightly bigger than positive
if (!isNegative)
{
// negative integer can be one bigger than positive
if (value == int.MinValue)
{
return ParseResult.Overflow;
}
value = -value;
}
return ParseResult.Success;
}
public static ParseResult Int64TryParse(char[] chars, int start, int length, out long value)
{
value = 0;
if (length == 0)
{
return ParseResult.Invalid;
}
bool isNegative = (chars[start] == '-');
if (isNegative)
{
// text just a negative sign
if (length == 1)
{
return ParseResult.Invalid;
}
start++;
length--;
}
int end = start + length;
// Int64.MaxValue and MinValue are 19 chars
if (length > 19)
{
// invalid result takes precedence over overflow
for (int i = start; i < end; i++)
{
int c = chars[i] - '0';
if (c < 0 || c > 9)
{
return ParseResult.Invalid;
}
}
return ParseResult.Overflow;
}
for (int i = start; i < end; i++)
{
int c = chars[i] - '0';
if (c < 0 || c > 9)
{
return ParseResult.Invalid;
}
long newValue = (10 * value) - c;
// overflow has caused the number to loop around
if (newValue > value)
{
i++;
// double check the rest of the string that there wasn't anything invalid
// invalid result takes precedence over overflow result
for (; i < end; i++)
{
c = chars[i] - '0';
if (c < 0 || c > 9)
{
return ParseResult.Invalid;
}
}
return ParseResult.Overflow;
}
value = newValue;
}
// go from negative to positive to avoids overflow
// negative can be slightly bigger than positive
if (!isNegative)
{
// negative integer can be one bigger than positive
if (value == long.MinValue)
{
return ParseResult.Overflow;
}
value = -value;
}
return ParseResult.Success;
}
public static bool TryConvertGuid(string s, out Guid g)
{
// GUID has to have format 00000000-0000-0000-0000-000000000000
#if NET20 || NET35
if (s == null)
{
throw new ArgumentNullException("s");
}
Regex format = new Regex("^[A-Fa-f0-9]{8}-([A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}$");
Match match = format.Match(s);
if (match.Success)
{
g = new Guid(s);
return true;
}
g = Guid.Empty;
return false;
#else
return Guid.TryParseExact(s, "D", out g);
#endif
}
public static int HexTextToInt(char[] text, int start, int end)
{
int value = 0;
for (int i = start; i < end; i++)
{
value += HexCharToInt(text[i]) << ((end - 1 - i) * 4);
}
return value;
}
private static int HexCharToInt(char ch)
{
if (ch <= 57 && ch >= 48)
{
return ch - 48;
}
if (ch <= 70 && ch >= 65)
{
return ch - 55;
}
if (ch <= 102 && ch >= 97)
{
return ch - 87;
}
throw new FormatException("Invalid hex character: " + ch);
}
}
}

View File

@@ -0,0 +1,277 @@
#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 Newtonsoft.Json.Utilities
{
internal enum ParserTimeZone
{
Unspecified = 0,
Utc = 1,
LocalWestOfUtc = 2,
LocalEastOfUtc = 3
}
internal struct DateTimeParser
{
static DateTimeParser()
{
Power10 = new[] { -1, 10, 100, 1000, 10000, 100000, 1000000 };
Lzyyyy = "yyyy".Length;
Lzyyyy_ = "yyyy-".Length;
Lzyyyy_MM = "yyyy-MM".Length;
Lzyyyy_MM_ = "yyyy-MM-".Length;
Lzyyyy_MM_dd = "yyyy-MM-dd".Length;
Lzyyyy_MM_ddT = "yyyy-MM-ddT".Length;
LzHH = "HH".Length;
LzHH_ = "HH:".Length;
LzHH_mm = "HH:mm".Length;
LzHH_mm_ = "HH:mm:".Length;
LzHH_mm_ss = "HH:mm:ss".Length;
Lz_ = "-".Length;
Lz_zz = "-zz".Length;
}
public int Year;
public int Month;
public int Day;
public int Hour;
public int Minute;
public int Second;
public int Fraction;
public int ZoneHour;
public int ZoneMinute;
public ParserTimeZone Zone;
private char[] _text;
private int _end;
private static readonly int[] Power10;
private static readonly int Lzyyyy;
private static readonly int Lzyyyy_;
private static readonly int Lzyyyy_MM;
private static readonly int Lzyyyy_MM_;
private static readonly int Lzyyyy_MM_dd;
private static readonly int Lzyyyy_MM_ddT;
private static readonly int LzHH;
private static readonly int LzHH_;
private static readonly int LzHH_mm;
private static readonly int LzHH_mm_;
private static readonly int LzHH_mm_ss;
private static readonly int Lz_;
private static readonly int Lz_zz;
private const short MaxFractionDigits = 7;
public bool Parse(char[] text, int startIndex, int length)
{
_text = text;
_end = startIndex + length;
if (ParseDate(startIndex) && ParseChar(Lzyyyy_MM_dd + startIndex, 'T') && ParseTimeAndZoneAndWhitespace(Lzyyyy_MM_ddT + startIndex))
{
return true;
}
return false;
}
private bool ParseDate(int start)
{
return (Parse4Digit(start, out Year)
&& 1 <= Year
&& ParseChar(start + Lzyyyy, '-')
&& Parse2Digit(start + Lzyyyy_, out Month)
&& 1 <= Month
&& Month <= 12
&& ParseChar(start + Lzyyyy_MM, '-')
&& Parse2Digit(start + Lzyyyy_MM_, out Day)
&& 1 <= Day
&& Day <= DateTime.DaysInMonth(Year, Month));
}
private bool ParseTimeAndZoneAndWhitespace(int start)
{
return (ParseTime(ref start) && ParseZone(start));
}
private bool ParseTime(ref int start)
{
if (!(Parse2Digit(start, out Hour)
&& Hour <= 24
&& ParseChar(start + LzHH, ':')
&& Parse2Digit(start + LzHH_, out Minute)
&& Minute < 60
&& ParseChar(start + LzHH_mm, ':')
&& Parse2Digit(start + LzHH_mm_, out Second)
&& Second < 60
&& (Hour != 24 || (Minute == 0 && Second == 0)))) // hour can be 24 if minute/second is zero)
{
return false;
}
start += LzHH_mm_ss;
if (ParseChar(start, '.'))
{
Fraction = 0;
int numberOfDigits = 0;
while (++start < _end && numberOfDigits < MaxFractionDigits)
{
int digit = _text[start] - '0';
if (digit < 0 || digit > 9)
{
break;
}
Fraction = (Fraction * 10) + digit;
numberOfDigits++;
}
if (numberOfDigits < MaxFractionDigits)
{
if (numberOfDigits == 0)
{
return false;
}
Fraction *= Power10[MaxFractionDigits - numberOfDigits];
}
if (Hour == 24 && Fraction != 0)
{
return false;
}
}
return true;
}
private bool ParseZone(int start)
{
if (start < _end)
{
char ch = _text[start];
if (ch == 'Z' || ch == 'z')
{
Zone = ParserTimeZone.Utc;
start++;
}
else
{
if (start + 2 < _end
&& Parse2Digit(start + Lz_, out ZoneHour)
&& ZoneHour <= 99)
{
switch (ch)
{
case '-':
Zone = ParserTimeZone.LocalWestOfUtc;
start += Lz_zz;
break;
case '+':
Zone = ParserTimeZone.LocalEastOfUtc;
start += Lz_zz;
break;
}
}
if (start < _end)
{
if (ParseChar(start, ':'))
{
start += 1;
if (start + 1 < _end
&& Parse2Digit(start, out ZoneMinute)
&& ZoneMinute <= 99)
{
start += 2;
}
}
else
{
if (start + 1 < _end
&& Parse2Digit(start, out ZoneMinute)
&& ZoneMinute <= 99)
{
start += 2;
}
}
}
}
}
return (start == _end);
}
private bool Parse4Digit(int start, out int num)
{
if (start + 3 < _end)
{
int digit1 = _text[start] - '0';
int digit2 = _text[start + 1] - '0';
int digit3 = _text[start + 2] - '0';
int digit4 = _text[start + 3] - '0';
if (0 <= digit1 && digit1 < 10
&& 0 <= digit2 && digit2 < 10
&& 0 <= digit3 && digit3 < 10
&& 0 <= digit4 && digit4 < 10)
{
num = (((((digit1 * 10) + digit2) * 10) + digit3) * 10) + digit4;
return true;
}
}
num = 0;
return false;
}
private bool Parse2Digit(int start, out int num)
{
if (start + 1 < _end)
{
int digit1 = _text[start] - '0';
int digit2 = _text[start + 1] - '0';
if (0 <= digit1 && digit1 < 10
&& 0 <= digit2 && digit2 < 10)
{
num = (digit1 * 10) + digit2;
return true;
}
}
num = 0;
return false;
}
private bool ParseChar(int start, char ch)
{
return (start < _end && _text[start] == ch);
}
}
}

View File

@@ -0,0 +1,824 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.IO;
using System.Xml;
using System.Globalization;
namespace Newtonsoft.Json.Utilities
{
internal static class DateTimeUtils
{
internal static readonly long InitialJavaScriptDateTicks = 621355968000000000;
private const string IsoDateFormat = "yyyy-MM-ddTHH:mm:ss.FFFFFFFK";
private const int DaysPer100Years = 36524;
private const int DaysPer400Years = 146097;
private const int DaysPer4Years = 1461;
private const int DaysPerYear = 365;
private const long TicksPerDay = 864000000000L;
private static readonly int[] DaysToMonth365;
private static readonly int[] DaysToMonth366;
static DateTimeUtils()
{
DaysToMonth365 = new[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
DaysToMonth366 = new[] { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
}
public static TimeSpan GetUtcOffset(this DateTime d)
{
#if NET20
return TimeZone.CurrentTimeZone.GetUtcOffset(d);
#else
return TimeZoneInfo.Local.GetUtcOffset(d);
#endif
}
#if !(PORTABLE40 || PORTABLE)
public static XmlDateTimeSerializationMode ToSerializationMode(DateTimeKind kind)
{
switch (kind)
{
case DateTimeKind.Local:
return XmlDateTimeSerializationMode.Local;
case DateTimeKind.Unspecified:
return XmlDateTimeSerializationMode.Unspecified;
case DateTimeKind.Utc:
return XmlDateTimeSerializationMode.Utc;
default:
throw MiscellaneousUtils.CreateArgumentOutOfRangeException("kind", kind, "Unexpected DateTimeKind value.");
}
}
#endif
internal static DateTime EnsureDateTime(DateTime value, DateTimeZoneHandling timeZone)
{
switch (timeZone)
{
case DateTimeZoneHandling.Local:
value = SwitchToLocalTime(value);
break;
case DateTimeZoneHandling.Utc:
value = SwitchToUtcTime(value);
break;
case DateTimeZoneHandling.Unspecified:
value = new DateTime(value.Ticks, DateTimeKind.Unspecified);
break;
case DateTimeZoneHandling.RoundtripKind:
break;
default:
throw new ArgumentException("Invalid date time handling value.");
}
return value;
}
private static DateTime SwitchToLocalTime(DateTime value)
{
switch (value.Kind)
{
case DateTimeKind.Unspecified:
return new DateTime(value.Ticks, DateTimeKind.Local);
case DateTimeKind.Utc:
return value.ToLocalTime();
case DateTimeKind.Local:
return value;
}
return value;
}
private static DateTime SwitchToUtcTime(DateTime value)
{
switch (value.Kind)
{
case DateTimeKind.Unspecified:
return new DateTime(value.Ticks, DateTimeKind.Utc);
case DateTimeKind.Utc:
return value;
case DateTimeKind.Local:
return value.ToUniversalTime();
}
return value;
}
private static long ToUniversalTicks(DateTime dateTime)
{
if (dateTime.Kind == DateTimeKind.Utc)
{
return dateTime.Ticks;
}
return ToUniversalTicks(dateTime, dateTime.GetUtcOffset());
}
private static long ToUniversalTicks(DateTime dateTime, TimeSpan offset)
{
// special case min and max value
// they never have a timezone appended to avoid issues
if (dateTime.Kind == DateTimeKind.Utc || dateTime == DateTime.MaxValue || dateTime == DateTime.MinValue)
{
return dateTime.Ticks;
}
long ticks = dateTime.Ticks - offset.Ticks;
if (ticks > 3155378975999999999L)
{
return 3155378975999999999L;
}
if (ticks < 0L)
{
return 0L;
}
return ticks;
}
internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, TimeSpan offset)
{
long universialTicks = ToUniversalTicks(dateTime, offset);
return UniversialTicksToJavaScriptTicks(universialTicks);
}
internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime)
{
return ConvertDateTimeToJavaScriptTicks(dateTime, true);
}
internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, bool convertToUtc)
{
long ticks = (convertToUtc) ? ToUniversalTicks(dateTime) : dateTime.Ticks;
return UniversialTicksToJavaScriptTicks(ticks);
}
private static long UniversialTicksToJavaScriptTicks(long universialTicks)
{
long javaScriptTicks = (universialTicks - InitialJavaScriptDateTicks) / 10000;
return javaScriptTicks;
}
internal static DateTime ConvertJavaScriptTicksToDateTime(long javaScriptTicks)
{
DateTime dateTime = new DateTime((javaScriptTicks * 10000) + InitialJavaScriptDateTicks, DateTimeKind.Utc);
return dateTime;
}
#region Parse
internal static bool TryParseDateTimeIso(StringReference text, DateTimeZoneHandling dateTimeZoneHandling, out DateTime dt)
{
DateTimeParser dateTimeParser = new DateTimeParser();
if (!dateTimeParser.Parse(text.Chars, text.StartIndex, text.Length))
{
dt = default(DateTime);
return false;
}
DateTime d = CreateDateTime(dateTimeParser);
long ticks;
switch (dateTimeParser.Zone)
{
case ParserTimeZone.Utc:
d = new DateTime(d.Ticks, DateTimeKind.Utc);
break;
case ParserTimeZone.LocalWestOfUtc:
{
TimeSpan offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0);
ticks = d.Ticks + offset.Ticks;
if (ticks <= DateTime.MaxValue.Ticks)
{
d = new DateTime(ticks, DateTimeKind.Utc).ToLocalTime();
}
else
{
ticks += d.GetUtcOffset().Ticks;
if (ticks > DateTime.MaxValue.Ticks)
{
ticks = DateTime.MaxValue.Ticks;
}
d = new DateTime(ticks, DateTimeKind.Local);
}
break;
}
case ParserTimeZone.LocalEastOfUtc:
{
TimeSpan offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0);
ticks = d.Ticks - offset.Ticks;
if (ticks >= DateTime.MinValue.Ticks)
{
d = new DateTime(ticks, DateTimeKind.Utc).ToLocalTime();
}
else
{
ticks += d.GetUtcOffset().Ticks;
if (ticks < DateTime.MinValue.Ticks)
{
ticks = DateTime.MinValue.Ticks;
}
d = new DateTime(ticks, DateTimeKind.Local);
}
break;
}
}
dt = EnsureDateTime(d, dateTimeZoneHandling);
return true;
}
#if !NET20
internal static bool TryParseDateTimeOffsetIso(StringReference text, out DateTimeOffset dt)
{
DateTimeParser dateTimeParser = new DateTimeParser();
if (!dateTimeParser.Parse(text.Chars, text.StartIndex, text.Length))
{
dt = default(DateTimeOffset);
return false;
}
DateTime d = CreateDateTime(dateTimeParser);
TimeSpan offset;
switch (dateTimeParser.Zone)
{
case ParserTimeZone.Utc:
offset = new TimeSpan(0L);
break;
case ParserTimeZone.LocalWestOfUtc:
offset = new TimeSpan(-dateTimeParser.ZoneHour, -dateTimeParser.ZoneMinute, 0);
break;
case ParserTimeZone.LocalEastOfUtc:
offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0);
break;
default:
offset = TimeZoneInfo.Local.GetUtcOffset(d);
break;
}
long ticks = d.Ticks - offset.Ticks;
if (ticks < 0 || ticks > 3155378975999999999)
{
dt = default(DateTimeOffset);
return false;
}
dt = new DateTimeOffset(d, offset);
return true;
}
#endif
private static DateTime CreateDateTime(DateTimeParser dateTimeParser)
{
bool is24Hour;
if (dateTimeParser.Hour == 24)
{
is24Hour = true;
dateTimeParser.Hour = 0;
}
else
{
is24Hour = false;
}
DateTime d = new DateTime(dateTimeParser.Year, dateTimeParser.Month, dateTimeParser.Day, dateTimeParser.Hour, dateTimeParser.Minute, dateTimeParser.Second);
d = d.AddTicks(dateTimeParser.Fraction);
if (is24Hour)
{
d = d.AddDays(1);
}
return d;
}
internal static bool TryParseDateTime(StringReference s, DateTimeZoneHandling dateTimeZoneHandling, string dateFormatString, CultureInfo culture, out DateTime dt)
{
if (s.Length > 0)
{
int i = s.StartIndex;
if (s[i] == '/')
{
if (s.Length >= 9 && s.StartsWith("/Date(") && s.EndsWith(")/"))
{
if (TryParseDateTimeMicrosoft(s, dateTimeZoneHandling, out dt))
{
return true;
}
}
}
else if (s.Length >= 19 && s.Length <= 40 && char.IsDigit(s[i]) && s[i + 10] == 'T')
{
if (TryParseDateTimeIso(s, dateTimeZoneHandling, out dt))
{
return true;
}
}
if (!string.IsNullOrEmpty(dateFormatString))
{
if (TryParseDateTimeExact(s.ToString(), dateTimeZoneHandling, dateFormatString, culture, out dt))
{
return true;
}
}
}
dt = default(DateTime);
return false;
}
internal static bool TryParseDateTime(string s, DateTimeZoneHandling dateTimeZoneHandling, string dateFormatString, CultureInfo culture, out DateTime dt)
{
if (s.Length > 0)
{
if (s[0] == '/')
{
if (s.Length >= 9 && s.StartsWith("/Date(", StringComparison.Ordinal) && s.EndsWith(")/", StringComparison.Ordinal))
{
if (TryParseDateTimeMicrosoft(new StringReference(s.ToCharArray(), 0, s.Length), dateTimeZoneHandling, out dt))
{
return true;
}
}
}
else if (s.Length >= 19 && s.Length <= 40 && char.IsDigit(s[0]) && s[10] == 'T')
{
if (DateTime.TryParseExact(s, IsoDateFormat, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dt))
{
dt = EnsureDateTime(dt, dateTimeZoneHandling);
return true;
}
}
if (!string.IsNullOrEmpty(dateFormatString))
{
if (TryParseDateTimeExact(s, dateTimeZoneHandling, dateFormatString, culture, out dt))
{
return true;
}
}
}
dt = default(DateTime);
return false;
}
#if !NET20
internal static bool TryParseDateTimeOffset(StringReference s, string dateFormatString, CultureInfo culture, out DateTimeOffset dt)
{
if (s.Length > 0)
{
int i = s.StartIndex;
if (s[i] == '/')
{
if (s.Length >= 9 && s.StartsWith("/Date(") && s.EndsWith(")/"))
{
if (TryParseDateTimeOffsetMicrosoft(s, out dt))
{
return true;
}
}
}
else if (s.Length >= 19 && s.Length <= 40 && char.IsDigit(s[i]) && s[i + 10] == 'T')
{
if (TryParseDateTimeOffsetIso(s, out dt))
{
return true;
}
}
if (!string.IsNullOrEmpty(dateFormatString))
{
if (TryParseDateTimeOffsetExact(s.ToString(), dateFormatString, culture, out dt))
{
return true;
}
}
}
dt = default(DateTimeOffset);
return false;
}
internal static bool TryParseDateTimeOffset(string s, string dateFormatString, CultureInfo culture, out DateTimeOffset dt)
{
if (s.Length > 0)
{
if (s[0] == '/')
{
if (s.Length >= 9 && s.StartsWith("/Date(", StringComparison.Ordinal) && s.EndsWith(")/", StringComparison.Ordinal))
{
if (TryParseDateTimeOffsetMicrosoft(new StringReference(s.ToCharArray(), 0, s.Length), out dt))
{
return true;
}
}
}
else if (s.Length >= 19 && s.Length <= 40 && char.IsDigit(s[0]) && s[10] == 'T')
{
if (DateTimeOffset.TryParseExact(s, IsoDateFormat, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dt))
{
if (TryParseDateTimeOffsetIso(new StringReference(s.ToCharArray(), 0, s.Length), out dt))
{
return true;
}
}
}
if (!string.IsNullOrEmpty(dateFormatString))
{
if (TryParseDateTimeOffsetExact(s, dateFormatString, culture, out dt))
{
return true;
}
}
}
dt = default(DateTimeOffset);
return false;
}
#endif
private static bool TryParseMicrosoftDate(StringReference text, out long ticks, out TimeSpan offset, out DateTimeKind kind)
{
kind = DateTimeKind.Utc;
int index = text.IndexOf('+', 7, text.Length - 8);
if (index == -1)
{
index = text.IndexOf('-', 7, text.Length - 8);
}
if (index != -1)
{
kind = DateTimeKind.Local;
if (!TryReadOffset(text, index + text.StartIndex, out offset))
{
ticks = 0;
return false;
}
}
else
{
offset = TimeSpan.Zero;
index = text.Length - 2;
}
return (ConvertUtils.Int64TryParse(text.Chars, 6 + text.StartIndex, index - 6, out ticks) == ParseResult.Success);
}
private static bool TryParseDateTimeMicrosoft(StringReference text, DateTimeZoneHandling dateTimeZoneHandling, out DateTime dt)
{
long ticks;
TimeSpan offset;
DateTimeKind kind;
if (!TryParseMicrosoftDate(text, out ticks, out offset, out kind))
{
dt = default(DateTime);
return false;
}
DateTime utcDateTime = ConvertJavaScriptTicksToDateTime(ticks);
switch (kind)
{
case DateTimeKind.Unspecified:
dt = DateTime.SpecifyKind(utcDateTime.ToLocalTime(), DateTimeKind.Unspecified);
break;
case DateTimeKind.Local:
dt = utcDateTime.ToLocalTime();
break;
default:
dt = utcDateTime;
break;
}
dt = EnsureDateTime(dt, dateTimeZoneHandling);
return true;
}
private static bool TryParseDateTimeExact(string text, DateTimeZoneHandling dateTimeZoneHandling, string dateFormatString, CultureInfo culture, out DateTime dt)
{
DateTime temp;
if (DateTime.TryParseExact(text, dateFormatString, culture, DateTimeStyles.RoundtripKind, out temp))
{
temp = EnsureDateTime(temp, dateTimeZoneHandling);
dt = temp;
return true;
}
dt = default(DateTime);
return false;
}
#if !NET20
private static bool TryParseDateTimeOffsetMicrosoft(StringReference text, out DateTimeOffset dt)
{
long ticks;
TimeSpan offset;
DateTimeKind kind;
if (!TryParseMicrosoftDate(text, out ticks, out offset, out kind))
{
dt = default(DateTime);
return false;
}
DateTime utcDateTime = ConvertJavaScriptTicksToDateTime(ticks);
dt = new DateTimeOffset(utcDateTime.Add(offset).Ticks, offset);
return true;
}
private static bool TryParseDateTimeOffsetExact(string text, string dateFormatString, CultureInfo culture, out DateTimeOffset dt)
{
DateTimeOffset temp;
if (DateTimeOffset.TryParseExact(text, dateFormatString, culture, DateTimeStyles.RoundtripKind, out temp))
{
dt = temp;
return true;
}
dt = default(DateTimeOffset);
return false;
}
#endif
private static bool TryReadOffset(StringReference offsetText, int startIndex, out TimeSpan offset)
{
bool negative = (offsetText[startIndex] == '-');
int hours;
if (ConvertUtils.Int32TryParse(offsetText.Chars, startIndex + 1, 2, out hours) != ParseResult.Success)
{
offset = default(TimeSpan);
return false;
}
int minutes = 0;
if (offsetText.Length - startIndex > 5)
{
if (ConvertUtils.Int32TryParse(offsetText.Chars, startIndex + 3, 2, out minutes) != ParseResult.Success)
{
offset = default(TimeSpan);
return false;
}
}
offset = TimeSpan.FromHours(hours) + TimeSpan.FromMinutes(minutes);
if (negative)
{
offset = offset.Negate();
}
return true;
}
#endregion
#region Write
internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format, string formatString, CultureInfo culture)
{
if (string.IsNullOrEmpty(formatString))
{
char[] chars = new char[64];
int pos = WriteDateTimeString(chars, 0, value, null, value.Kind, format);
writer.Write(chars, 0, pos);
}
else
{
writer.Write(value.ToString(formatString, culture));
}
}
internal static int WriteDateTimeString(char[] chars, int start, DateTime value, TimeSpan? offset, DateTimeKind kind, DateFormatHandling format)
{
int pos = start;
if (format == DateFormatHandling.MicrosoftDateFormat)
{
TimeSpan o = offset ?? value.GetUtcOffset();
long javaScriptTicks = ConvertDateTimeToJavaScriptTicks(value, o);
@"\/Date(".CopyTo(0, chars, pos, 7);
pos += 7;
string ticksText = javaScriptTicks.ToString(CultureInfo.InvariantCulture);
ticksText.CopyTo(0, chars, pos, ticksText.Length);
pos += ticksText.Length;
switch (kind)
{
case DateTimeKind.Unspecified:
if (value != DateTime.MaxValue && value != DateTime.MinValue)
{
pos = WriteDateTimeOffset(chars, pos, o, format);
}
break;
case DateTimeKind.Local:
pos = WriteDateTimeOffset(chars, pos, o, format);
break;
}
@")\/".CopyTo(0, chars, pos, 3);
pos += 3;
}
else
{
pos = WriteDefaultIsoDate(chars, pos, value);
switch (kind)
{
case DateTimeKind.Local:
pos = WriteDateTimeOffset(chars, pos, offset ?? value.GetUtcOffset(), format);
break;
case DateTimeKind.Utc:
chars[pos++] = 'Z';
break;
}
}
return pos;
}
internal static int WriteDefaultIsoDate(char[] chars, int start, DateTime dt)
{
int length = 19;
int year;
int month;
int day;
GetDateValues(dt, out year, out month, out day);
CopyIntToCharArray(chars, start, year, 4);
chars[start + 4] = '-';
CopyIntToCharArray(chars, start + 5, month, 2);
chars[start + 7] = '-';
CopyIntToCharArray(chars, start + 8, day, 2);
chars[start + 10] = 'T';
CopyIntToCharArray(chars, start + 11, dt.Hour, 2);
chars[start + 13] = ':';
CopyIntToCharArray(chars, start + 14, dt.Minute, 2);
chars[start + 16] = ':';
CopyIntToCharArray(chars, start + 17, dt.Second, 2);
int fraction = (int)(dt.Ticks % 10000000L);
if (fraction != 0)
{
int digits = 7;
while ((fraction % 10) == 0)
{
digits--;
fraction /= 10;
}
chars[start + 19] = '.';
CopyIntToCharArray(chars, start + 20, fraction, digits);
length += digits + 1;
}
return start + length;
}
private static void CopyIntToCharArray(char[] chars, int start, int value, int digits)
{
while (digits-- != 0)
{
chars[start + digits] = (char)((value % 10) + 48);
value /= 10;
}
}
internal static int WriteDateTimeOffset(char[] chars, int start, TimeSpan offset, DateFormatHandling format)
{
chars[start++] = (offset.Ticks >= 0L) ? '+' : '-';
int absHours = Math.Abs(offset.Hours);
CopyIntToCharArray(chars, start, absHours, 2);
start += 2;
if (format == DateFormatHandling.IsoDateFormat)
{
chars[start++] = ':';
}
int absMinutes = Math.Abs(offset.Minutes);
CopyIntToCharArray(chars, start, absMinutes, 2);
start += 2;
return start;
}
#if !NET20
internal static void WriteDateTimeOffsetString(TextWriter writer, DateTimeOffset value, DateFormatHandling format, string formatString, CultureInfo culture)
{
if (string.IsNullOrEmpty(formatString))
{
char[] chars = new char[64];
int pos = WriteDateTimeString(chars, 0, (format == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, format);
writer.Write(chars, 0, pos);
}
else
{
writer.Write(value.ToString(formatString, culture));
}
}
#endif
#endregion
private static void GetDateValues(DateTime td, out int year, out int month, out int day)
{
long ticks = td.Ticks;
// n = number of days since 1/1/0001
int n = (int)(ticks / TicksPerDay);
// y400 = number of whole 400-year periods since 1/1/0001
int y400 = n / DaysPer400Years;
// n = day number within 400-year period
n -= y400 * DaysPer400Years;
// y100 = number of whole 100-year periods within 400-year period
int y100 = n / DaysPer100Years;
// Last 100-year period has an extra day, so decrement result if 4
if (y100 == 4)
{
y100 = 3;
}
// n = day number within 100-year period
n -= y100 * DaysPer100Years;
// y4 = number of whole 4-year periods within 100-year period
int y4 = n / DaysPer4Years;
// n = day number within 4-year period
n -= y4 * DaysPer4Years;
// y1 = number of whole years within 4-year period
int y1 = n / DaysPerYear;
// Last year has an extra day, so decrement result if 4
if (y1 == 4)
{
y1 = 3;
}
year = y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1;
// n = day number within year
n -= y1 * DaysPerYear;
// Leap year calculation looks different from IsLeapYear since y1, y4,
// and y100 are relative to year 1, not year 0
bool leapYear = y1 == 3 && (y4 != 24 || y100 == 3);
int[] days = leapYear ? DaysToMonth366 : DaysToMonth365;
// All months have less than 32 days, so n >> 5 is a good conservative
// estimate for the month
int m = n >> 5 + 1;
// m = 1-based month number
while (n >= days[m])
{
m++;
}
month = m;
// Return 1-based day-of-month
day = n - days[m - 1] + 1;
}
}
}

View File

@@ -0,0 +1,700 @@
#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;
using System.Threading;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
namespace Newtonsoft.Json.Utilities
{
internal interface IWrappedDictionary
: IDictionary
{
object UnderlyingDictionary { get; }
}
internal class DictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>, IWrappedDictionary
{
private readonly IDictionary _dictionary;
private readonly IDictionary<TKey, TValue> _genericDictionary;
#if !(NET40 || NET35 || NET20 || PORTABLE40)
private readonly IReadOnlyDictionary<TKey, TValue> _readOnlyDictionary;
#endif
private object _syncRoot;
public DictionaryWrapper(IDictionary dictionary)
{
ValidationUtils.ArgumentNotNull(dictionary, nameof(dictionary));
_dictionary = dictionary;
}
public DictionaryWrapper(IDictionary<TKey, TValue> dictionary)
{
ValidationUtils.ArgumentNotNull(dictionary, nameof(dictionary));
_genericDictionary = dictionary;
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
public DictionaryWrapper(IReadOnlyDictionary<TKey, TValue> dictionary)
{
ValidationUtils.ArgumentNotNull(dictionary, nameof(dictionary));
_readOnlyDictionary = dictionary;
}
#endif
public void Add(TKey key, TValue value)
{
if (_dictionary != null)
{
_dictionary.Add(key, value);
}
else if (_genericDictionary != null)
{
_genericDictionary.Add(key, value);
}
else
{
throw new NotSupportedException();
}
}
public bool ContainsKey(TKey key)
{
if (_dictionary != null)
{
return _dictionary.Contains(key);
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary.ContainsKey(key);
}
#endif
else
{
return _genericDictionary.ContainsKey(key);
}
}
public ICollection<TKey> Keys
{
get
{
if (_dictionary != null)
{
return _dictionary.Keys.Cast<TKey>().ToList();
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary.Keys.ToList();
}
#endif
else
{
return _genericDictionary.Keys;
}
}
}
public bool Remove(TKey key)
{
if (_dictionary != null)
{
if (_dictionary.Contains(key))
{
_dictionary.Remove(key);
return true;
}
else
{
return false;
}
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
throw new NotSupportedException();
}
#endif
else
{
return _genericDictionary.Remove(key);
}
}
public bool TryGetValue(TKey key, out TValue value)
{
if (_dictionary != null)
{
if (!_dictionary.Contains(key))
{
value = default(TValue);
return false;
}
else
{
value = (TValue)_dictionary[key];
return true;
}
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
throw new NotSupportedException();
}
#endif
else
{
return _genericDictionary.TryGetValue(key, out value);
}
}
public ICollection<TValue> Values
{
get
{
if (_dictionary != null)
{
return _dictionary.Values.Cast<TValue>().ToList();
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary.Values.ToList();
}
#endif
else
{
return _genericDictionary.Values;
}
}
}
public TValue this[TKey key]
{
get
{
if (_dictionary != null)
{
return (TValue)_dictionary[key];
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary[key];
}
#endif
else
{
return _genericDictionary[key];
}
}
set
{
if (_dictionary != null)
{
_dictionary[key] = value;
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
throw new NotSupportedException();
}
#endif
else
{
_genericDictionary[key] = value;
}
}
}
public void Add(KeyValuePair<TKey, TValue> item)
{
if (_dictionary != null)
{
((IList)_dictionary).Add(item);
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
throw new NotSupportedException();
}
#endif
else if (_genericDictionary != null)
{
_genericDictionary.Add(item);
}
}
public void Clear()
{
if (_dictionary != null)
{
_dictionary.Clear();
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
throw new NotSupportedException();
}
#endif
else
{
_genericDictionary.Clear();
}
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
if (_dictionary != null)
{
return ((IList)_dictionary).Contains(item);
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary.Contains(item);
}
#endif
else
{
return _genericDictionary.Contains(item);
}
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
if (_dictionary != null)
{
foreach (DictionaryEntry item in _dictionary)
{
array[arrayIndex++] = new KeyValuePair<TKey, TValue>((TKey)item.Key, (TValue)item.Value);
}
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
throw new NotSupportedException();
}
#endif
else
{
_genericDictionary.CopyTo(array, arrayIndex);
}
}
public int Count
{
get
{
if (_dictionary != null)
{
return _dictionary.Count;
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary.Count;
}
#endif
else
{
return _genericDictionary.Count;
}
}
}
public bool IsReadOnly
{
get
{
if (_dictionary != null)
{
return _dictionary.IsReadOnly;
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return true;
}
#endif
else
{
return _genericDictionary.IsReadOnly;
}
}
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
if (_dictionary != null)
{
if (_dictionary.Contains(item.Key))
{
object value = _dictionary[item.Key];
if (object.Equals(value, item.Value))
{
_dictionary.Remove(item.Key);
return true;
}
else
{
return false;
}
}
else
{
return true;
}
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
throw new NotSupportedException();
}
#endif
else
{
return _genericDictionary.Remove(item);
}
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
if (_dictionary != null)
{
return _dictionary.Cast<DictionaryEntry>().Select(de => new KeyValuePair<TKey, TValue>((TKey)de.Key, (TValue)de.Value)).GetEnumerator();
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary.GetEnumerator();
}
#endif
else
{
return _genericDictionary.GetEnumerator();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
void IDictionary.Add(object key, object value)
{
if (_dictionary != null)
{
_dictionary.Add(key, value);
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
throw new NotSupportedException();
}
#endif
else
{
_genericDictionary.Add((TKey)key, (TValue)value);
}
}
object IDictionary.this[object key]
{
get
{
if (_dictionary != null)
{
return _dictionary[key];
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary[(TKey)key];
}
#endif
else
{
return _genericDictionary[(TKey)key];
}
}
set
{
if (_dictionary != null)
{
_dictionary[key] = value;
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
throw new NotSupportedException();
}
#endif
else
{
_genericDictionary[(TKey)key] = (TValue)value;
}
}
}
private struct DictionaryEnumerator<TEnumeratorKey, TEnumeratorValue> : IDictionaryEnumerator
{
private readonly IEnumerator<KeyValuePair<TEnumeratorKey, TEnumeratorValue>> _e;
public DictionaryEnumerator(IEnumerator<KeyValuePair<TEnumeratorKey, TEnumeratorValue>> e)
{
ValidationUtils.ArgumentNotNull(e, nameof(e));
_e = e;
}
public DictionaryEntry Entry
{
get { return (DictionaryEntry)Current; }
}
public object Key
{
get { return Entry.Key; }
}
public object Value
{
get { return Entry.Value; }
}
public object Current
{
get { return new DictionaryEntry(_e.Current.Key, _e.Current.Value); }
}
public bool MoveNext()
{
return _e.MoveNext();
}
public void Reset()
{
_e.Reset();
}
}
IDictionaryEnumerator IDictionary.GetEnumerator()
{
if (_dictionary != null)
{
return _dictionary.GetEnumerator();
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return new DictionaryEnumerator<TKey, TValue>(_readOnlyDictionary.GetEnumerator());
}
#endif
else
{
return new DictionaryEnumerator<TKey, TValue>(_genericDictionary.GetEnumerator());
}
}
bool IDictionary.Contains(object key)
{
if (_genericDictionary != null)
{
return _genericDictionary.ContainsKey((TKey)key);
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary.ContainsKey((TKey)key);
}
#endif
else
{
return _dictionary.Contains(key);
}
}
bool IDictionary.IsFixedSize
{
get
{
if (_genericDictionary != null)
{
return false;
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return true;
}
#endif
else
{
return _dictionary.IsFixedSize;
}
}
}
ICollection IDictionary.Keys
{
get
{
if (_genericDictionary != null)
{
return _genericDictionary.Keys.ToList();
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary.Keys.ToList();
}
#endif
else
{
return _dictionary.Keys;
}
}
}
public void Remove(object key)
{
if (_dictionary != null)
{
_dictionary.Remove(key);
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
throw new NotSupportedException();
}
#endif
else
{
_genericDictionary.Remove((TKey)key);
}
}
ICollection IDictionary.Values
{
get
{
if (_genericDictionary != null)
{
return _genericDictionary.Values.ToList();
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary.Values.ToList();
}
#endif
else
{
return _dictionary.Values;
}
}
}
void ICollection.CopyTo(Array array, int index)
{
if (_dictionary != null)
{
_dictionary.CopyTo(array, index);
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
throw new NotSupportedException();
}
#endif
else
{
_genericDictionary.CopyTo((KeyValuePair<TKey, TValue>[])array, index);
}
}
bool ICollection.IsSynchronized
{
get
{
if (_dictionary != null)
{
return _dictionary.IsSynchronized;
}
else
{
return false;
}
}
}
object ICollection.SyncRoot
{
get
{
if (_syncRoot == null)
{
Interlocked.CompareExchange(ref _syncRoot, new object(), null);
}
return _syncRoot;
}
}
public object UnderlyingDictionary
{
get
{
if (_dictionary != null)
{
return _dictionary;
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
else if (_readOnlyDictionary != null)
{
return _readOnlyDictionary;
}
#endif
else
{
return _genericDictionary;
}
}
}
}
}

View File

@@ -0,0 +1,113 @@
#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 !(NET35 || NET20 || PORTABLE40)
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace Newtonsoft.Json.Utilities
{
internal class DynamicProxy<T>
{
public virtual IEnumerable<string> GetDynamicMemberNames(T instance)
{
return new string[0];
}
public virtual bool TryBinaryOperation(T instance, BinaryOperationBinder binder, object arg, out object result)
{
result = null;
return false;
}
public virtual bool TryConvert(T instance, ConvertBinder binder, out object result)
{
result = null;
return false;
}
public virtual bool TryCreateInstance(T instance, CreateInstanceBinder binder, object[] args, out object result)
{
result = null;
return false;
}
public virtual bool TryDeleteIndex(T instance, DeleteIndexBinder binder, object[] indexes)
{
return false;
}
public virtual bool TryDeleteMember(T instance, DeleteMemberBinder binder)
{
return false;
}
public virtual bool TryGetIndex(T instance, GetIndexBinder binder, object[] indexes, out object result)
{
result = null;
return false;
}
public virtual bool TryGetMember(T instance, GetMemberBinder binder, out object result)
{
result = null;
return false;
}
public virtual bool TryInvoke(T instance, InvokeBinder binder, object[] args, out object result)
{
result = null;
return false;
}
public virtual bool TryInvokeMember(T instance, InvokeMemberBinder binder, object[] args, out object result)
{
result = null;
return false;
}
public virtual bool TrySetIndex(T instance, SetIndexBinder binder, object[] indexes, object value)
{
return false;
}
public virtual bool TrySetMember(T instance, SetMemberBinder binder, object value)
{
return false;
}
public virtual bool TryUnaryOperation(T instance, UnaryOperationBinder binder, out object result)
{
result = null;
return false;
}
}
}
#endif

View File

@@ -0,0 +1,427 @@
#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 !(NET35 || NET20 || PORTABLE40)
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Newtonsoft.Json.Utilities
{
internal sealed class DynamicProxyMetaObject<T> : DynamicMetaObject
{
private readonly DynamicProxy<T> _proxy;
private readonly bool _dontFallbackFirst;
internal DynamicProxyMetaObject(Expression expression, T value, DynamicProxy<T> proxy, bool dontFallbackFirst)
: base(expression, BindingRestrictions.Empty, value)
{
_proxy = proxy;
_dontFallbackFirst = dontFallbackFirst;
}
private new T Value
{
get { return (T)base.Value; }
}
private bool IsOverridden(string method)
{
return ReflectionUtils.IsMethodOverridden(_proxy.GetType(), typeof(DynamicProxy<T>), method);
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
return IsOverridden("TryGetMember")
? CallMethodWithResult("TryGetMember", binder, NoArgs, e => binder.FallbackGetMember(this, e))
: base.BindGetMember(binder);
}
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
{
return IsOverridden("TrySetMember")
? CallMethodReturnLast("TrySetMember", binder, GetArgs(value), e => binder.FallbackSetMember(this, value, e))
: base.BindSetMember(binder, value);
}
public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder)
{
return IsOverridden("TryDeleteMember")
? CallMethodNoResult("TryDeleteMember", binder, NoArgs, e => binder.FallbackDeleteMember(this, e))
: base.BindDeleteMember(binder);
}
public override DynamicMetaObject BindConvert(ConvertBinder binder)
{
return IsOverridden("TryConvert")
? CallMethodWithResult("TryConvert", binder, NoArgs, e => binder.FallbackConvert(this, e))
: base.BindConvert(binder);
}
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
{
if (!IsOverridden("TryInvokeMember"))
{
return base.BindInvokeMember(binder, args);
}
//
// Generate a tree like:
//
// {
// object result;
// TryInvokeMember(payload, out result)
// ? result
// : TryGetMember(payload, out result)
// ? FallbackInvoke(result)
// : fallbackResult
// }
//
// Then it calls FallbackInvokeMember with this tree as the
// "error", giving the language the option of using this
// tree or doing .NET binding.
//
Fallback fallback = e => binder.FallbackInvokeMember(this, args, e);
DynamicMetaObject call = BuildCallMethodWithResult(
"TryInvokeMember",
binder,
GetArgArray(args),
BuildCallMethodWithResult(
"TryGetMember",
new GetBinderAdapter(binder),
NoArgs,
fallback(null),
e => binder.FallbackInvoke(e, args, null)
),
null
);
return _dontFallbackFirst ? call : fallback(call);
}
public override DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args)
{
return IsOverridden("TryCreateInstance")
? CallMethodWithResult("TryCreateInstance", binder, GetArgArray(args), e => binder.FallbackCreateInstance(this, args, e))
: base.BindCreateInstance(binder, args);
}
public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args)
{
return IsOverridden("TryInvoke")
? CallMethodWithResult("TryInvoke", binder, GetArgArray(args), e => binder.FallbackInvoke(this, args, e))
: base.BindInvoke(binder, args);
}
public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
{
return IsOverridden("TryBinaryOperation")
? CallMethodWithResult("TryBinaryOperation", binder, GetArgs(arg), e => binder.FallbackBinaryOperation(this, arg, e))
: base.BindBinaryOperation(binder, arg);
}
public override DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder)
{
return IsOverridden("TryUnaryOperation")
? CallMethodWithResult("TryUnaryOperation", binder, NoArgs, e => binder.FallbackUnaryOperation(this, e))
: base.BindUnaryOperation(binder);
}
public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)
{
return IsOverridden("TryGetIndex")
? CallMethodWithResult("TryGetIndex", binder, GetArgArray(indexes), e => binder.FallbackGetIndex(this, indexes, e))
: base.BindGetIndex(binder, indexes);
}
public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)
{
return IsOverridden("TrySetIndex")
? CallMethodReturnLast("TrySetIndex", binder, GetArgArray(indexes, value), e => binder.FallbackSetIndex(this, indexes, value, e))
: base.BindSetIndex(binder, indexes, value);
}
public override DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes)
{
return IsOverridden("TryDeleteIndex")
? CallMethodNoResult("TryDeleteIndex", binder, GetArgArray(indexes), e => binder.FallbackDeleteIndex(this, indexes, e))
: base.BindDeleteIndex(binder, indexes);
}
private delegate DynamicMetaObject Fallback(DynamicMetaObject errorSuggestion);
private static readonly Expression[] NoArgs = new Expression[0];
private static Expression[] GetArgs(params DynamicMetaObject[] args)
{
return args.Select(arg => Expression.Convert(arg.Expression, typeof(object))).ToArray();
}
private static Expression[] GetArgArray(DynamicMetaObject[] args)
{
return new[] { Expression.NewArrayInit(typeof(object), GetArgs(args)) };
}
private static Expression[] GetArgArray(DynamicMetaObject[] args, DynamicMetaObject value)
{
return new Expression[]
{
Expression.NewArrayInit(typeof(object), GetArgs(args)),
Expression.Convert(value.Expression, typeof(object))
};
}
private static ConstantExpression Constant(DynamicMetaObjectBinder binder)
{
Type t = binder.GetType();
while (!t.IsVisible())
{
t = t.BaseType();
}
return Expression.Constant(binder, t);
}
/// <summary>
/// Helper method for generating a MetaObject which calls a
/// specific method on Dynamic that returns a result
/// </summary>
private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback, Fallback fallbackInvoke = null)
{
//
// First, call fallback to do default binding
// This produces either an error or a call to a .NET member
//
DynamicMetaObject fallbackResult = fallback(null);
DynamicMetaObject callDynamic = BuildCallMethodWithResult(methodName, binder, args, fallbackResult, fallbackInvoke);
//
// Now, call fallback again using our new MO as the error
// When we do this, one of two things can happen:
// 1. Binding will succeed, and it will ignore our call to
// the dynamic method, OR
// 2. Binding will fail, and it will use the MO we created
// above.
//
return _dontFallbackFirst ? callDynamic : fallback(callDynamic);
}
private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, DynamicMetaObject fallbackResult, Fallback fallbackInvoke)
{
//
// Build a new expression like:
// {
// object result;
// TryGetMember(payload, out result) ? fallbackInvoke(result) : fallbackResult
// }
//
ParameterExpression result = Expression.Parameter(typeof(object), null);
IList<Expression> callArgs = new List<Expression>();
callArgs.Add(Expression.Convert(Expression, typeof(T)));
callArgs.Add(Constant(binder));
callArgs.AddRange(args);
callArgs.Add(result);
DynamicMetaObject resultMetaObject = new DynamicMetaObject(result, BindingRestrictions.Empty);
// Need to add a conversion if calling TryConvert
if (binder.ReturnType != typeof(object))
{
UnaryExpression convert = Expression.Convert(resultMetaObject.Expression, binder.ReturnType);
// will always be a cast or unbox
resultMetaObject = new DynamicMetaObject(convert, resultMetaObject.Restrictions);
}
if (fallbackInvoke != null)
{
resultMetaObject = fallbackInvoke(resultMetaObject);
}
DynamicMetaObject callDynamic = new DynamicMetaObject(
Expression.Block(
new[] { result },
Expression.Condition(
Expression.Call(
Expression.Constant(_proxy),
typeof(DynamicProxy<T>).GetMethod(methodName),
callArgs
),
resultMetaObject.Expression,
fallbackResult.Expression,
binder.ReturnType
)
),
GetRestrictions().Merge(resultMetaObject.Restrictions).Merge(fallbackResult.Restrictions)
);
return callDynamic;
}
/// <summary>
/// Helper method for generating a MetaObject which calls a
/// specific method on Dynamic, but uses one of the arguments for
/// the result.
/// </summary>
private DynamicMetaObject CallMethodReturnLast(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback)
{
//
// First, call fallback to do default binding
// This produces either an error or a call to a .NET member
//
DynamicMetaObject fallbackResult = fallback(null);
//
// Build a new expression like:
// {
// object result;
// TrySetMember(payload, result = value) ? result : fallbackResult
// }
//
ParameterExpression result = Expression.Parameter(typeof(object), null);
IList<Expression> callArgs = new List<Expression>();
callArgs.Add(Expression.Convert(Expression, typeof(T)));
callArgs.Add(Constant(binder));
callArgs.AddRange(args);
callArgs[args.Length + 1] = Expression.Assign(result, callArgs[args.Length + 1]);
DynamicMetaObject callDynamic = new DynamicMetaObject(
Expression.Block(
new[] { result },
Expression.Condition(
Expression.Call(
Expression.Constant(_proxy),
typeof(DynamicProxy<T>).GetMethod(methodName),
callArgs
),
result,
fallbackResult.Expression,
typeof(object)
)
),
GetRestrictions().Merge(fallbackResult.Restrictions)
);
//
// Now, call fallback again using our new MO as the error
// When we do this, one of two things can happen:
// 1. Binding will succeed, and it will ignore our call to
// the dynamic method, OR
// 2. Binding will fail, and it will use the MO we created
// above.
//
return _dontFallbackFirst ? callDynamic : fallback(callDynamic);
}
/// <summary>
/// Helper method for generating a MetaObject which calls a
/// specific method on Dynamic, but uses one of the arguments for
/// the result.
/// </summary>
private DynamicMetaObject CallMethodNoResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback)
{
//
// First, call fallback to do default binding
// This produces either an error or a call to a .NET member
//
DynamicMetaObject fallbackResult = fallback(null);
IList<Expression> callArgs = new List<Expression>();
callArgs.Add(Expression.Convert(Expression, typeof(T)));
callArgs.Add(Constant(binder));
callArgs.AddRange(args);
//
// Build a new expression like:
// if (TryDeleteMember(payload)) { } else { fallbackResult }
//
DynamicMetaObject callDynamic = new DynamicMetaObject(
Expression.Condition(
Expression.Call(
Expression.Constant(_proxy),
typeof(DynamicProxy<T>).GetMethod(methodName),
callArgs
),
Expression.Empty(),
fallbackResult.Expression,
typeof(void)
),
GetRestrictions().Merge(fallbackResult.Restrictions)
);
//
// Now, call fallback again using our new MO as the error
// When we do this, one of two things can happen:
// 1. Binding will succeed, and it will ignore our call to
// the dynamic method, OR
// 2. Binding will fail, and it will use the MO we created
// above.
//
return _dontFallbackFirst ? callDynamic : fallback(callDynamic);
}
/// <summary>
/// Returns a Restrictions object which includes our current restrictions merged
/// with a restriction limiting our type
/// </summary>
private BindingRestrictions GetRestrictions()
{
return (Value == null && HasValue)
? BindingRestrictions.GetInstanceRestriction(Expression, null)
: BindingRestrictions.GetTypeRestriction(Expression, LimitType);
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return _proxy.GetDynamicMemberNames(Value);
}
// It is okay to throw NotSupported from this binder. This object
// is only used by DynamicObject.GetMember--it is not expected to
// (and cannot) implement binding semantics. It is just so the DO
// can use the Name and IgnoreCase properties.
private sealed class GetBinderAdapter : GetMemberBinder
{
internal GetBinderAdapter(InvokeMemberBinder binder) :
base(binder.Name, binder.IgnoreCase)
{
}
public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
{
throw new NotSupportedException();
}
}
}
}
#endif

View File

@@ -0,0 +1,360 @@
#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 !(DOTNET || PORTABLE || PORTABLE40)
using System;
using System.Collections.Generic;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#endif
using System.Reflection;
using System.Reflection.Emit;
using Newtonsoft.Json.Serialization;
using System.Globalization;
namespace Newtonsoft.Json.Utilities
{
internal class DynamicReflectionDelegateFactory : ReflectionDelegateFactory
{
public static DynamicReflectionDelegateFactory Instance = new DynamicReflectionDelegateFactory();
private static DynamicMethod CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes, Type owner)
{
DynamicMethod dynamicMethod = !owner.IsInterface()
? new DynamicMethod(name, returnType, parameterTypes, owner, true)
: new DynamicMethod(name, returnType, parameterTypes, owner.Module, true);
return dynamicMethod;
}
public override ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
{
DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object[]) }, method.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
GenerateCreateMethodCallIL(method, generator, 0);
return (ObjectConstructor<object>)dynamicMethod.CreateDelegate(typeof(ObjectConstructor<object>));
}
public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method)
{
DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object), typeof(object[]) }, method.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
GenerateCreateMethodCallIL(method, generator, 1);
return (MethodCall<T, object>)dynamicMethod.CreateDelegate(typeof(MethodCall<T, object>));
}
private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator, int argsIndex)
{
ParameterInfo[] args = method.GetParameters();
Label argsOk = generator.DefineLabel();
// throw an error if the number of argument values doesn't match method parameters
generator.Emit(OpCodes.Ldarg, argsIndex);
generator.Emit(OpCodes.Ldlen);
generator.Emit(OpCodes.Ldc_I4, args.Length);
generator.Emit(OpCodes.Beq, argsOk);
generator.Emit(OpCodes.Newobj, typeof(TargetParameterCountException).GetConstructor(ReflectionUtils.EmptyTypes));
generator.Emit(OpCodes.Throw);
generator.MarkLabel(argsOk);
if (!method.IsConstructor && !method.IsStatic)
{
generator.PushInstance(method.DeclaringType);
}
int localVariableCount = 0;
for (int i = 0; i < args.Length; i++)
{
ParameterInfo parameter = args[i];
Type parameterType = parameter.ParameterType;
if (parameterType.IsByRef)
{
parameterType = parameterType.GetElementType();
LocalBuilder localVariable = generator.DeclareLocal(parameterType);
// don't need to set variable for 'out' parameter
if (!parameter.IsOut)
{
generator.PushArrayInstance(argsIndex, i);
if (parameterType.IsValueType())
{
Label skipSettingDefault = generator.DefineLabel();
Label finishedProcessingParameter = generator.DefineLabel();
// check if parameter is not null
generator.Emit(OpCodes.Brtrue_S, skipSettingDefault);
// parameter has no value, initialize to default
generator.Emit(OpCodes.Ldloca_S, localVariable);
generator.Emit(OpCodes.Initobj, parameterType);
generator.Emit(OpCodes.Br_S, finishedProcessingParameter);
// parameter has value, get value from array again and unbox and set to variable
generator.MarkLabel(skipSettingDefault);
generator.PushArrayInstance(argsIndex, i);
generator.UnboxIfNeeded(parameterType);
generator.Emit(OpCodes.Stloc, localVariableCount);
// parameter finished, we out!
generator.MarkLabel(finishedProcessingParameter);
}
else
{
generator.UnboxIfNeeded(parameterType);
generator.Emit(OpCodes.Stloc, localVariableCount);
}
}
generator.Emit(OpCodes.Ldloca_S, localVariable);
localVariableCount++;
}
else if (parameterType.IsValueType())
{
generator.PushArrayInstance(argsIndex, i);
// have to check that value type parameters aren't null
// otherwise they will error when unboxed
Label skipSettingDefault = generator.DefineLabel();
Label finishedProcessingParameter = generator.DefineLabel();
// check if parameter is not null
generator.Emit(OpCodes.Brtrue_S, skipSettingDefault);
// parameter has no value, initialize to default
LocalBuilder localVariable = generator.DeclareLocal(parameterType);
generator.Emit(OpCodes.Ldloca_S, localVariable);
generator.Emit(OpCodes.Initobj, parameterType);
generator.Emit(OpCodes.Ldloc, localVariableCount);
generator.Emit(OpCodes.Br_S, finishedProcessingParameter);
// parameter has value, get value from array again and unbox
generator.MarkLabel(skipSettingDefault);
generator.PushArrayInstance(argsIndex, i);
generator.UnboxIfNeeded(parameterType);
// parameter finished, we out!
generator.MarkLabel(finishedProcessingParameter);
localVariableCount++;
}
else
{
generator.PushArrayInstance(argsIndex, i);
generator.UnboxIfNeeded(parameterType);
}
}
if (method.IsConstructor)
{
generator.Emit(OpCodes.Newobj, (ConstructorInfo)method);
}
else
{
generator.CallMethod((MethodInfo)method);
}
Type returnType = method.IsConstructor
? method.DeclaringType
: ((MethodInfo)method).ReturnType;
if (returnType != typeof(void))
{
generator.BoxIfNeeded(returnType);
}
else
{
generator.Emit(OpCodes.Ldnull);
}
generator.Return();
}
public override Func<T> CreateDefaultConstructor<T>(Type type)
{
DynamicMethod dynamicMethod = CreateDynamicMethod("Create" + type.FullName, typeof(T), ReflectionUtils.EmptyTypes, type);
dynamicMethod.InitLocals = true;
ILGenerator generator = dynamicMethod.GetILGenerator();
GenerateCreateDefaultConstructorIL(type, generator);
return (Func<T>)dynamicMethod.CreateDelegate(typeof(Func<T>));
}
private void GenerateCreateDefaultConstructorIL(Type type, ILGenerator generator)
{
if (type.IsValueType())
{
generator.DeclareLocal(type);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Box, type);
}
else
{
ConstructorInfo constructorInfo =
type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null,
ReflectionUtils.EmptyTypes, null);
if (constructorInfo == null)
{
throw new ArgumentException("Could not get constructor for {0}.".FormatWith(CultureInfo.InvariantCulture, type));
}
generator.Emit(OpCodes.Newobj, constructorInfo);
}
generator.Return();
}
public override Func<T, object> CreateGet<T>(PropertyInfo propertyInfo)
{
DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + propertyInfo.Name, typeof(T), new[] { typeof(object) }, propertyInfo.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
GenerateCreateGetPropertyIL(propertyInfo, generator);
return (Func<T, object>)dynamicMethod.CreateDelegate(typeof(Func<T, object>));
}
private void GenerateCreateGetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator)
{
MethodInfo getMethod = propertyInfo.GetGetMethod(true);
if (getMethod == null)
{
throw new ArgumentException("Property '{0}' does not have a getter.".FormatWith(CultureInfo.InvariantCulture, propertyInfo.Name));
}
if (!getMethod.IsStatic)
{
generator.PushInstance(propertyInfo.DeclaringType);
}
generator.CallMethod(getMethod);
generator.BoxIfNeeded(propertyInfo.PropertyType);
generator.Return();
}
public override Func<T, object> CreateGet<T>(FieldInfo fieldInfo)
{
if (fieldInfo.IsLiteral)
{
object constantValue = fieldInfo.GetValue(null);
Func<T, object> getter = o => constantValue;
return getter;
}
DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + fieldInfo.Name, typeof(T), new[] { typeof(object) }, fieldInfo.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
GenerateCreateGetFieldIL(fieldInfo, generator);
return (Func<T, object>)dynamicMethod.CreateDelegate(typeof(Func<T, object>));
}
private void GenerateCreateGetFieldIL(FieldInfo fieldInfo, ILGenerator generator)
{
if (!fieldInfo.IsStatic)
{
generator.PushInstance(fieldInfo.DeclaringType);
generator.Emit(OpCodes.Ldfld, fieldInfo);
}
else
{
generator.Emit(OpCodes.Ldsfld, fieldInfo);
}
generator.BoxIfNeeded(fieldInfo.FieldType);
generator.Return();
}
public override Action<T, object> CreateSet<T>(FieldInfo fieldInfo)
{
DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + fieldInfo.Name, null, new[] { typeof(T), typeof(object) }, fieldInfo.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
GenerateCreateSetFieldIL(fieldInfo, generator);
return (Action<T, object>)dynamicMethod.CreateDelegate(typeof(Action<T, object>));
}
internal static void GenerateCreateSetFieldIL(FieldInfo fieldInfo, ILGenerator generator)
{
if (!fieldInfo.IsStatic)
{
generator.PushInstance(fieldInfo.DeclaringType);
}
generator.Emit(OpCodes.Ldarg_1);
generator.UnboxIfNeeded(fieldInfo.FieldType);
if (!fieldInfo.IsStatic)
{
generator.Emit(OpCodes.Stfld, fieldInfo);
}
else
{
generator.Emit(OpCodes.Stsfld, fieldInfo);
}
generator.Return();
}
public override Action<T, object> CreateSet<T>(PropertyInfo propertyInfo)
{
DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + propertyInfo.Name, null, new[] { typeof(T), typeof(object) }, propertyInfo.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
GenerateCreateSetPropertyIL(propertyInfo, generator);
return (Action<T, object>)dynamicMethod.CreateDelegate(typeof(Action<T, object>));
}
internal static void GenerateCreateSetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator)
{
MethodInfo setMethod = propertyInfo.GetSetMethod(true);
if (!setMethod.IsStatic)
{
generator.PushInstance(propertyInfo.DeclaringType);
}
generator.Emit(OpCodes.Ldarg_1);
generator.UnboxIfNeeded(propertyInfo.PropertyType);
generator.CallMethod(setMethod);
generator.Return();
}
}
}
#endif

View File

@@ -0,0 +1,210 @@
#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 !(NET35 || NET20 || PORTABLE40)
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
#if !(PORTABLE)
using System.Reflection;
#else
using Microsoft.CSharp.RuntimeBinder;
#endif
using System.Runtime.CompilerServices;
using System.Text;
using System.Globalization;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Utilities
{
internal static class DynamicUtils
{
internal static class BinderWrapper
{
#if !(PORTABLE)
public const string CSharpAssemblyName = "Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
private const string BinderTypeName = "Microsoft.CSharp.RuntimeBinder.Binder, " + CSharpAssemblyName;
private const string CSharpArgumentInfoTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo, " + CSharpAssemblyName;
private const string CSharpArgumentInfoFlagsTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, " + CSharpAssemblyName;
private const string CSharpBinderFlagsTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, " + CSharpAssemblyName;
private static object _getCSharpArgumentInfoArray;
private static object _setCSharpArgumentInfoArray;
private static MethodCall<object, object> _getMemberCall;
private static MethodCall<object, object> _setMemberCall;
private static bool _init;
private static void Init()
{
if (!_init)
{
Type binderType = Type.GetType(BinderTypeName, false);
if (binderType == null)
{
throw new InvalidOperationException("Could not resolve type '{0}'. You may need to add a reference to Microsoft.CSharp.dll to work with dynamic types.".FormatWith(CultureInfo.InvariantCulture, BinderTypeName));
}
// None
_getCSharpArgumentInfoArray = CreateSharpArgumentInfoArray(0);
// None, Constant | UseCompileTimeType
_setCSharpArgumentInfoArray = CreateSharpArgumentInfoArray(0, 3);
CreateMemberCalls();
_init = true;
}
}
private static object CreateSharpArgumentInfoArray(params int[] values)
{
Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName);
Type csharpArgumentInfoFlags = Type.GetType(CSharpArgumentInfoFlagsTypeName);
Array a = Array.CreateInstance(csharpArgumentInfoType, values.Length);
for (int i = 0; i < values.Length; i++)
{
MethodInfo createArgumentInfoMethod = csharpArgumentInfoType.GetMethod("Create", new[] { csharpArgumentInfoFlags, typeof(string) });
object arg = createArgumentInfoMethod.Invoke(null, new object[] { 0, null });
a.SetValue(arg, i);
}
return a;
}
private static void CreateMemberCalls()
{
Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName, true);
Type csharpBinderFlagsType = Type.GetType(CSharpBinderFlagsTypeName, true);
Type binderType = Type.GetType(BinderTypeName, true);
Type csharpArgumentInfoTypeEnumerableType = typeof(IEnumerable<>).MakeGenericType(csharpArgumentInfoType);
MethodInfo getMemberMethod = binderType.GetMethod("GetMember", new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType });
_getMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(getMemberMethod);
MethodInfo setMemberMethod = binderType.GetMethod("SetMember", new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType });
_setMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(setMemberMethod);
}
#endif
public static CallSiteBinder GetMember(string name, Type context)
{
#if !(PORTABLE)
Init();
return (CallSiteBinder)_getMemberCall(null, 0, name, context, _getCSharpArgumentInfoArray);
#else
return Binder.GetMember(
CSharpBinderFlags.None, name, context, new[] {CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)});
#endif
}
public static CallSiteBinder SetMember(string name, Type context)
{
#if !(PORTABLE)
Init();
return (CallSiteBinder)_setMemberCall(null, 0, name, context, _setCSharpArgumentInfoArray);
#else
return Binder.SetMember(
CSharpBinderFlags.None, name, context, new[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant, null)
});
#endif
}
}
public static IEnumerable<string> GetDynamicMemberNames(this IDynamicMetaObjectProvider dynamicProvider)
{
DynamicMetaObject metaObject = dynamicProvider.GetMetaObject(Expression.Constant(dynamicProvider));
return metaObject.GetDynamicMemberNames();
}
}
internal class NoThrowGetBinderMember : GetMemberBinder
{
private readonly GetMemberBinder _innerBinder;
public NoThrowGetBinderMember(GetMemberBinder innerBinder)
: base(innerBinder.Name, innerBinder.IgnoreCase)
{
_innerBinder = innerBinder;
}
public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
{
DynamicMetaObject retMetaObject = _innerBinder.Bind(target, new DynamicMetaObject[] { });
NoThrowExpressionVisitor noThrowVisitor = new NoThrowExpressionVisitor();
Expression resultExpression = noThrowVisitor.Visit(retMetaObject.Expression);
DynamicMetaObject finalMetaObject = new DynamicMetaObject(resultExpression, retMetaObject.Restrictions);
return finalMetaObject;
}
}
internal class NoThrowSetBinderMember : SetMemberBinder
{
private readonly SetMemberBinder _innerBinder;
public NoThrowSetBinderMember(SetMemberBinder innerBinder)
: base(innerBinder.Name, innerBinder.IgnoreCase)
{
_innerBinder = innerBinder;
}
public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
{
DynamicMetaObject retMetaObject = _innerBinder.Bind(target, new DynamicMetaObject[] { value });
NoThrowExpressionVisitor noThrowVisitor = new NoThrowExpressionVisitor();
Expression resultExpression = noThrowVisitor.Visit(retMetaObject.Expression);
DynamicMetaObject finalMetaObject = new DynamicMetaObject(resultExpression, retMetaObject.Restrictions);
return finalMetaObject;
}
}
internal class NoThrowExpressionVisitor : ExpressionVisitor
{
internal static readonly object ErrorResult = new object();
protected override Expression VisitConditional(ConditionalExpression node)
{
// if the result of a test is to throw an error, rewrite to result an error result value
if (node.IfFalse.NodeType == ExpressionType.Throw)
{
return Expression.Condition(node.Test, node.IfTrue, Expression.Constant(ErrorResult));
}
return base.VisitConditional(node);
}
}
}
#endif

View File

@@ -0,0 +1,257 @@
#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;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
using System.Reflection;
namespace Newtonsoft.Json.Utilities
{
internal static class EnumUtils
{
private static readonly ThreadSafeStore<Type, BidirectionalDictionary<string, string>> EnumMemberNamesPerType = new ThreadSafeStore<Type, BidirectionalDictionary<string, string>>(InitializeEnumType);
private static BidirectionalDictionary<string, string> InitializeEnumType(Type type)
{
BidirectionalDictionary<string, string> map = new BidirectionalDictionary<string, string>(
StringComparer.OrdinalIgnoreCase,
StringComparer.OrdinalIgnoreCase);
foreach (FieldInfo f in type.GetFields())
{
string n1 = f.Name;
string n2;
#if !NET20
n2 = f.GetCustomAttributes(typeof(EnumMemberAttribute), true)
.Cast<EnumMemberAttribute>()
.Select(a => a.Value)
.SingleOrDefault() ?? f.Name;
#else
n2 = f.Name;
#endif
string s;
if (map.TryGetBySecond(n2, out s))
{
throw new InvalidOperationException("Enum name '{0}' already exists on enum '{1}'.".FormatWith(CultureInfo.InvariantCulture, n2, type.Name));
}
map.Set(n1, n2);
}
return map;
}
public static IList<T> GetFlagsValues<T>(T value) where T : struct
{
Type enumType = typeof(T);
if (!enumType.IsDefined(typeof(FlagsAttribute), false))
{
throw new ArgumentException("Enum type {0} is not a set of flags.".FormatWith(CultureInfo.InvariantCulture, enumType));
}
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
ulong num = Convert.ToUInt64(value, CultureInfo.InvariantCulture);
IList<EnumValue<ulong>> enumNameValues = GetNamesAndValues<T>();
IList<T> selectedFlagsValues = new List<T>();
foreach (EnumValue<ulong> enumNameValue in enumNameValues)
{
if ((num & enumNameValue.Value) == enumNameValue.Value && enumNameValue.Value != 0)
{
selectedFlagsValues.Add((T)Convert.ChangeType(enumNameValue.Value, underlyingType, CultureInfo.CurrentCulture));
}
}
if (selectedFlagsValues.Count == 0 && enumNameValues.SingleOrDefault(v => v.Value == 0) != null)
{
selectedFlagsValues.Add(default(T));
}
return selectedFlagsValues;
}
/// <summary>
/// Gets a dictionary of the names and values of an Enum type.
/// </summary>
/// <returns></returns>
public static IList<EnumValue<ulong>> GetNamesAndValues<T>() where T : struct
{
return GetNamesAndValues<ulong>(typeof(T));
}
/// <summary>
/// Gets a dictionary of the names and values of an Enum type.
/// </summary>
/// <param name="enumType">The enum type to get names and values for.</param>
/// <returns></returns>
public static IList<EnumValue<TUnderlyingType>> GetNamesAndValues<TUnderlyingType>(Type enumType) where TUnderlyingType : struct
{
if (enumType == null)
{
throw new ArgumentNullException(nameof(enumType));
}
if (!enumType.IsEnum())
{
throw new ArgumentException("Type {0} is not an Enum.".FormatWith(CultureInfo.InvariantCulture, enumType), nameof(enumType));
}
IList<object> enumValues = GetValues(enumType);
IList<string> enumNames = GetNames(enumType);
IList<EnumValue<TUnderlyingType>> nameValues = new List<EnumValue<TUnderlyingType>>();
for (int i = 0; i < enumValues.Count; i++)
{
try
{
nameValues.Add(new EnumValue<TUnderlyingType>(enumNames[i], (TUnderlyingType)Convert.ChangeType(enumValues[i], typeof(TUnderlyingType), CultureInfo.CurrentCulture)));
}
catch (OverflowException e)
{
throw new InvalidOperationException(
string.Format(CultureInfo.InvariantCulture, "Value from enum with the underlying type of {0} cannot be added to dictionary with a value type of {1}. Value was too large: {2}",
Enum.GetUnderlyingType(enumType), typeof(TUnderlyingType), Convert.ToUInt64(enumValues[i], CultureInfo.InvariantCulture)), e);
}
}
return nameValues;
}
public static IList<object> GetValues(Type enumType)
{
if (!enumType.IsEnum())
{
throw new ArgumentException("Type '" + enumType.Name + "' is not an enum.");
}
List<object> values = new List<object>();
var fields = enumType.GetFields().Where(f => f.IsLiteral);
foreach (FieldInfo field in fields)
{
object value = field.GetValue(enumType);
values.Add(value);
}
return values;
}
public static IList<string> GetNames(Type enumType)
{
if (!enumType.IsEnum())
{
throw new ArgumentException("Type '" + enumType.Name + "' is not an enum.");
}
List<string> values = new List<string>();
var fields = enumType.GetFields().Where(f => f.IsLiteral);
foreach (FieldInfo field in fields)
{
values.Add(field.Name);
}
return values;
}
public static object ParseEnumName(string enumText, bool isNullable, Type t)
{
if (enumText == string.Empty && isNullable)
{
return null;
}
string finalEnumText;
BidirectionalDictionary<string, string> map = EnumMemberNamesPerType.Get(t);
if (enumText.IndexOf(',') != -1)
{
string[] names = enumText.Split(',');
for (int i = 0; i < names.Length; i++)
{
string name = names[i].Trim();
names[i] = ResolvedEnumName(map, name);
}
finalEnumText = string.Join(", ", names);
}
else
{
finalEnumText = ResolvedEnumName(map, enumText);
}
return Enum.Parse(t, finalEnumText, true);
}
public static string ToEnumName(Type enumType, string enumText, bool camelCaseText)
{
BidirectionalDictionary<string, string> map = EnumMemberNamesPerType.Get(enumType);
string[] names = enumText.Split(',');
for (int i = 0; i < names.Length; i++)
{
string name = names[i].Trim();
string resolvedEnumName;
map.TryGetByFirst(name, out resolvedEnumName);
resolvedEnumName = resolvedEnumName ?? name;
if (camelCaseText)
{
resolvedEnumName = StringUtils.ToCamelCase(resolvedEnumName);
}
names[i] = resolvedEnumName;
}
string finalName = string.Join(", ", names);
return finalName;
}
private static string ResolvedEnumName(BidirectionalDictionary<string, string> map, string enumText)
{
string resolvedEnumName;
map.TryGetBySecond(enumText, out resolvedEnumName);
resolvedEnumName = resolvedEnumName ?? enumText;
return resolvedEnumName;
}
}
}

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 Newtonsoft.Json.Utilities
{
internal class EnumValue<T> where T : struct
{
private readonly string _name;
private readonly T _value;
public string Name
{
get { return _name; }
}
public T Value
{
get { return _value; }
}
public EnumValue(string name, T value)
{
_name = name;
_value = value;
}
}
}

View File

@@ -0,0 +1,368 @@
#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 !(NET20 || NET35)
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Linq.Expressions;
using System.Reflection;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Utilities
{
internal class ExpressionReflectionDelegateFactory : ReflectionDelegateFactory
{
private static readonly ExpressionReflectionDelegateFactory _instance = new ExpressionReflectionDelegateFactory();
internal static ReflectionDelegateFactory Instance
{
get { return _instance; }
}
public override ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
{
ValidationUtils.ArgumentNotNull(method, nameof(method));
Type type = typeof(object);
ParameterExpression argsParameterExpression = Expression.Parameter(typeof(object[]), "args");
Expression callExpression = BuildMethodCall(method, type, null, argsParameterExpression);
LambdaExpression lambdaExpression = Expression.Lambda(typeof(ObjectConstructor<object>), callExpression, argsParameterExpression);
ObjectConstructor<object> compiled = (ObjectConstructor<object>)lambdaExpression.Compile();
return compiled;
}
public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method)
{
ValidationUtils.ArgumentNotNull(method, nameof(method));
Type type = typeof(object);
ParameterExpression targetParameterExpression = Expression.Parameter(type, "target");
ParameterExpression argsParameterExpression = Expression.Parameter(typeof(object[]), "args");
Expression callExpression = BuildMethodCall(method, type, targetParameterExpression, argsParameterExpression);
LambdaExpression lambdaExpression = Expression.Lambda(typeof(MethodCall<T, object>), callExpression, targetParameterExpression, argsParameterExpression);
MethodCall<T, object> compiled = (MethodCall<T, object>)lambdaExpression.Compile();
return compiled;
}
private class ByRefParameter
{
public Expression Value;
public ParameterExpression Variable;
public bool IsOut;
}
private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpression targetParameterExpression, ParameterExpression argsParameterExpression)
{
ParameterInfo[] parametersInfo = method.GetParameters();
Expression[] argsExpression = new Expression[parametersInfo.Length];
IList<ByRefParameter> refParameterMap = new List<ByRefParameter>();
for (int i = 0; i < parametersInfo.Length; i++)
{
ParameterInfo parameter = parametersInfo[i];
Type parameterType = parameter.ParameterType;
bool isByRef = false;
if (parameterType.IsByRef)
{
parameterType = parameterType.GetElementType();
isByRef = true;
}
Expression indexExpression = Expression.Constant(i);
Expression paramAccessorExpression = Expression.ArrayIndex(argsParameterExpression, indexExpression);
Expression argExpression;
if (parameterType.IsValueType())
{
BinaryExpression ensureValueTypeNotNull = Expression.Coalesce(paramAccessorExpression, Expression.New(parameterType));
argExpression = EnsureCastExpression(ensureValueTypeNotNull, parameterType);
}
else
{
argExpression = EnsureCastExpression(paramAccessorExpression, parameterType);
}
if (isByRef)
{
ParameterExpression variable = Expression.Variable(parameterType);
refParameterMap.Add(new ByRefParameter
{
Value = argExpression,
Variable = variable,
IsOut = parameter.IsOut
});
argExpression = variable;
}
argsExpression[i] = argExpression;
}
Expression callExpression;
if (method.IsConstructor)
{
callExpression = Expression.New((ConstructorInfo)method, argsExpression);
}
else if (method.IsStatic)
{
callExpression = Expression.Call((MethodInfo)method, argsExpression);
}
else
{
Expression readParameter = EnsureCastExpression(targetParameterExpression, method.DeclaringType);
callExpression = Expression.Call(readParameter, (MethodInfo)method, argsExpression);
}
if (method is MethodInfo)
{
MethodInfo m = (MethodInfo)method;
if (m.ReturnType != typeof(void))
{
callExpression = EnsureCastExpression(callExpression, type);
}
else
{
callExpression = Expression.Block(callExpression, Expression.Constant(null));
}
}
else
{
callExpression = EnsureCastExpression(callExpression, type);
}
if (refParameterMap.Count > 0)
{
IList<ParameterExpression> variableExpressions = new List<ParameterExpression>();
IList<Expression> bodyExpressions = new List<Expression>();
foreach (ByRefParameter p in refParameterMap)
{
if (!p.IsOut)
{
bodyExpressions.Add(Expression.Assign(p.Variable, p.Value));
}
variableExpressions.Add(p.Variable);
}
bodyExpressions.Add(callExpression);
callExpression = Expression.Block(variableExpressions, bodyExpressions);
}
return callExpression;
}
public override Func<T> CreateDefaultConstructor<T>(Type type)
{
ValidationUtils.ArgumentNotNull(type, "type");
// avoid error from expressions compiler because of abstract class
if (type.IsAbstract())
{
return () => (T)Activator.CreateInstance(type);
}
try
{
Type resultType = typeof(T);
Expression expression = Expression.New(type);
expression = EnsureCastExpression(expression, resultType);
LambdaExpression lambdaExpression = Expression.Lambda(typeof(Func<T>), expression);
Func<T> compiled = (Func<T>)lambdaExpression.Compile();
return compiled;
}
catch
{
// an error can be thrown if constructor is not valid on Win8
// will have INVOCATION_FLAGS_NON_W8P_FX_API invocation flag
return () => (T)Activator.CreateInstance(type);
}
}
public override Func<T, object> CreateGet<T>(PropertyInfo propertyInfo)
{
ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
Type instanceType = typeof(T);
Type resultType = typeof(object);
ParameterExpression parameterExpression = Expression.Parameter(instanceType, "instance");
Expression resultExpression;
MethodInfo getMethod = propertyInfo.GetGetMethod(true);
if (getMethod.IsStatic)
{
resultExpression = Expression.MakeMemberAccess(null, propertyInfo);
}
else
{
Expression readParameter = EnsureCastExpression(parameterExpression, propertyInfo.DeclaringType);
resultExpression = Expression.MakeMemberAccess(readParameter, propertyInfo);
}
resultExpression = EnsureCastExpression(resultExpression, resultType);
LambdaExpression lambdaExpression = Expression.Lambda(typeof(Func<T, object>), resultExpression, parameterExpression);
Func<T, object> compiled = (Func<T, object>)lambdaExpression.Compile();
return compiled;
}
public override Func<T, object> CreateGet<T>(FieldInfo fieldInfo)
{
ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo));
ParameterExpression sourceParameter = Expression.Parameter(typeof(T), "source");
Expression fieldExpression;
if (fieldInfo.IsStatic)
{
fieldExpression = Expression.Field(null, fieldInfo);
}
else
{
Expression sourceExpression = EnsureCastExpression(sourceParameter, fieldInfo.DeclaringType);
fieldExpression = Expression.Field(sourceExpression, fieldInfo);
}
fieldExpression = EnsureCastExpression(fieldExpression, typeof(object));
Func<T, object> compiled = Expression.Lambda<Func<T, object>>(fieldExpression, sourceParameter).Compile();
return compiled;
}
public override Action<T, object> CreateSet<T>(FieldInfo fieldInfo)
{
ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo));
// use reflection for structs
// expression doesn't correctly set value
if (fieldInfo.DeclaringType.IsValueType() || fieldInfo.IsInitOnly)
{
return LateBoundReflectionDelegateFactory.Instance.CreateSet<T>(fieldInfo);
}
ParameterExpression sourceParameterExpression = Expression.Parameter(typeof(T), "source");
ParameterExpression valueParameterExpression = Expression.Parameter(typeof(object), "value");
Expression fieldExpression;
if (fieldInfo.IsStatic)
{
fieldExpression = Expression.Field(null, fieldInfo);
}
else
{
Expression sourceExpression = EnsureCastExpression(sourceParameterExpression, fieldInfo.DeclaringType);
fieldExpression = Expression.Field(sourceExpression, fieldInfo);
}
Expression valueExpression = EnsureCastExpression(valueParameterExpression, fieldExpression.Type);
BinaryExpression assignExpression = Expression.Assign(fieldExpression, valueExpression);
LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action<T, object>), assignExpression, sourceParameterExpression, valueParameterExpression);
Action<T, object> compiled = (Action<T, object>)lambdaExpression.Compile();
return compiled;
}
public override Action<T, object> CreateSet<T>(PropertyInfo propertyInfo)
{
ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
// use reflection for structs
// expression doesn't correctly set value
if (propertyInfo.DeclaringType.IsValueType())
{
return LateBoundReflectionDelegateFactory.Instance.CreateSet<T>(propertyInfo);
}
Type instanceType = typeof(T);
Type valueType = typeof(object);
ParameterExpression instanceParameter = Expression.Parameter(instanceType, "instance");
ParameterExpression valueParameter = Expression.Parameter(valueType, "value");
Expression readValueParameter = EnsureCastExpression(valueParameter, propertyInfo.PropertyType);
MethodInfo setMethod = propertyInfo.GetSetMethod(true);
Expression setExpression;
if (setMethod.IsStatic)
{
setExpression = Expression.Call(setMethod, readValueParameter);
}
else
{
Expression readInstanceParameter = EnsureCastExpression(instanceParameter, propertyInfo.DeclaringType);
setExpression = Expression.Call(readInstanceParameter, setMethod, readValueParameter);
}
LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action<T, object>), setExpression, instanceParameter, valueParameter);
Action<T, object> compiled = (Action<T, object>)lambdaExpression.Compile();
return compiled;
}
private Expression EnsureCastExpression(Expression expression, Type targetType)
{
Type expressionType = expression.Type;
// check if a cast or conversion is required
if (expressionType == targetType || (!expressionType.IsValueType() && targetType.IsAssignableFrom(expressionType)))
{
return expression;
}
return Expression.Convert(expression, targetType);
}
}
}
#endif

View File

@@ -0,0 +1,195 @@
#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 !(NET35 || NET20)
using System.Threading;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Utilities
{
internal class FSharpFunction
{
private readonly object _instance;
private readonly MethodCall<object, object> _invoker;
public FSharpFunction(object instance, MethodCall<object, object> invoker)
{
_instance = instance;
_invoker = invoker;
}
public object Invoke(params object[] args)
{
object o = _invoker(_instance, args);
return o;
}
}
internal static class FSharpUtils
{
private static readonly object Lock = new object();
private static bool _initialized;
private static MethodInfo _ofSeq;
private static Type _mapType;
public static Assembly FSharpCoreAssembly { get; private set; }
public static MethodCall<object, object> IsUnion { get; private set; }
public static MethodCall<object, object> GetUnionCases { get; private set; }
public static MethodCall<object, object> PreComputeUnionTagReader { get; private set; }
public static MethodCall<object, object> PreComputeUnionReader { get; private set; }
public static MethodCall<object, object> PreComputeUnionConstructor { get; private set; }
public static Func<object, object> GetUnionCaseInfoDeclaringType { get; private set; }
public static Func<object, object> GetUnionCaseInfoName { get; private set; }
public static Func<object, object> GetUnionCaseInfoTag { get; private set; }
public static MethodCall<object, object> GetUnionCaseInfoFields { get; private set; }
public const string FSharpSetTypeName = "FSharpSet`1";
public const string FSharpListTypeName = "FSharpList`1";
public const string FSharpMapTypeName = "FSharpMap`2";
public static void EnsureInitialized(Assembly fsharpCoreAssembly)
{
if (!_initialized)
{
lock (Lock)
{
if (!_initialized)
{
FSharpCoreAssembly = fsharpCoreAssembly;
Type fsharpType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpType");
MethodInfo isUnionMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "IsUnion", BindingFlags.Public | BindingFlags.Static);
IsUnion = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(isUnionMethodInfo);
MethodInfo getUnionCasesMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "GetUnionCases", BindingFlags.Public | BindingFlags.Static);
GetUnionCases = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(getUnionCasesMethodInfo);
Type fsharpValue = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpValue");
PreComputeUnionTagReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionTagReader");
PreComputeUnionReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionReader");
PreComputeUnionConstructor = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionConstructor");
Type unionCaseInfo = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.UnionCaseInfo");
GetUnionCaseInfoName = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("Name"));
GetUnionCaseInfoTag = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("Tag"));
GetUnionCaseInfoDeclaringType = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("DeclaringType"));
GetUnionCaseInfoFields = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(unionCaseInfo.GetMethod("GetFields"));
Type listModule = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.ListModule");
_ofSeq = listModule.GetMethod("OfSeq");
_mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2");
#if !(DOTNET || PORTABLE)
Thread.MemoryBarrier();
#endif
_initialized = true;
}
}
}
}
private static MethodInfo GetMethodWithNonPublicFallback(Type type, string methodName, BindingFlags bindingFlags)
{
MethodInfo methodInfo = type.GetMethod(methodName, bindingFlags);
// if no matching method then attempt to find with nonpublic flag
// this is required because in WinApps some methods are private but always using NonPublic breaks medium trust
// https://github.com/JamesNK/Newtonsoft.Json/pull/649
// https://github.com/JamesNK/Newtonsoft.Json/issues/821
if (methodInfo == null && (bindingFlags & BindingFlags.NonPublic) != BindingFlags.NonPublic)
{
methodInfo = type.GetMethod(methodName, bindingFlags | BindingFlags.NonPublic);
}
return methodInfo;
}
private static MethodCall<object, object> CreateFSharpFuncCall(Type type, string methodName)
{
MethodInfo innerMethodInfo = GetMethodWithNonPublicFallback(type, methodName, BindingFlags.Public | BindingFlags.Static);
MethodInfo invokeFunc = innerMethodInfo.ReturnType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance);
MethodCall<object, object> call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(innerMethodInfo);
MethodCall<object, object> invoke = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(invokeFunc);
MethodCall<object, object> createFunction = (target, args) =>
{
object result = call(target, args);
FSharpFunction f = new FSharpFunction(result, invoke);
return f;
};
return createFunction;
}
public static ObjectConstructor<object> CreateSeq(Type t)
{
MethodInfo seqType = _ofSeq.MakeGenericMethod(t);
return JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(seqType);
}
public static ObjectConstructor<object> CreateMap(Type keyType, Type valueType)
{
MethodInfo creatorDefinition = typeof(FSharpUtils).GetMethod("BuildMapCreator");
MethodInfo creatorGeneric = creatorDefinition.MakeGenericMethod(keyType, valueType);
return (ObjectConstructor<object>)creatorGeneric.Invoke(null, null);
}
public static ObjectConstructor<object> BuildMapCreator<TKey, TValue>()
{
Type genericMapType = _mapType.MakeGenericType(typeof(TKey), typeof(TValue));
ConstructorInfo ctor = genericMapType.GetConstructor(new[] { typeof(IEnumerable<Tuple<TKey, TValue>>) });
ObjectConstructor<object> ctorDelegate = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(ctor);
ObjectConstructor<object> creator = args =>
{
// convert dictionary KeyValuePairs to Tuples
IEnumerable<KeyValuePair<TKey, TValue>> values = (IEnumerable<KeyValuePair<TKey, TValue>>)args[0];
IEnumerable<Tuple<TKey, TValue>> tupleValues = values.Select(kv => new Tuple<TKey, TValue>(kv.Key, kv.Value));
return ctorDelegate(tupleValues);
};
return creator;
}
}
}
#endif

View File

@@ -0,0 +1,98 @@
#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 !(DOTNET || PORTABLE40 || PORTABLE)
using System;
using System.Reflection.Emit;
using System.Reflection;
namespace Newtonsoft.Json.Utilities
{
internal static class ILGeneratorExtensions
{
public static void PushInstance(this ILGenerator generator, Type type)
{
generator.Emit(OpCodes.Ldarg_0);
if (type.IsValueType())
{
generator.Emit(OpCodes.Unbox, type);
}
else
{
generator.Emit(OpCodes.Castclass, type);
}
}
public static void PushArrayInstance(this ILGenerator generator, int argsIndex, int arrayIndex)
{
generator.Emit(OpCodes.Ldarg, argsIndex);
generator.Emit(OpCodes.Ldc_I4, arrayIndex);
generator.Emit(OpCodes.Ldelem_Ref);
}
public static void BoxIfNeeded(this ILGenerator generator, Type type)
{
if (type.IsValueType())
{
generator.Emit(OpCodes.Box, type);
}
else
{
generator.Emit(OpCodes.Castclass, type);
}
}
public static void UnboxIfNeeded(this ILGenerator generator, Type type)
{
if (type.IsValueType())
{
generator.Emit(OpCodes.Unbox_Any, type);
}
else
{
generator.Emit(OpCodes.Castclass, type);
}
}
public static void CallMethod(this ILGenerator generator, MethodInfo methodInfo)
{
if (methodInfo.IsFinal || !methodInfo.IsVirtual)
{
generator.Emit(OpCodes.Call, methodInfo);
}
else
{
generator.Emit(OpCodes.Callvirt, methodInfo);
}
}
public static void Return(this ILGenerator generator)
{
generator.Emit(OpCodes.Ret);
}
}
}
#endif

View File

@@ -0,0 +1,176 @@
#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 !(NET20 || NET35 || NET40)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Utilities
{
internal static class ImmutableCollectionsUtils
{
internal class ImmutableCollectionTypeInfo
{
public ImmutableCollectionTypeInfo(string contractTypeName, string createdTypeName, string builderTypeName)
{
ContractTypeName = contractTypeName;
CreatedTypeName = createdTypeName;
BuilderTypeName = builderTypeName;
}
public string ContractTypeName { get; set; }
public string CreatedTypeName { get; set; }
public string BuilderTypeName { get; set; }
}
private const string ImmutableListGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableList`1";
private const string ImmutableQueueGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableQueue`1";
private const string ImmutableStackGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableStack`1";
private const string ImmutableSetGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableSet`1";
private const string ImmutableArrayTypeName = "System.Collections.Immutable.ImmutableArray";
private const string ImmutableArrayGenericTypeName = "System.Collections.Immutable.ImmutableArray`1";
private const string ImmutableListTypeName = "System.Collections.Immutable.ImmutableList";
private const string ImmutableListGenericTypeName = "System.Collections.Immutable.ImmutableList`1";
private const string ImmutableQueueTypeName = "System.Collections.Immutable.ImmutableQueue";
private const string ImmutableQueueGenericTypeName = "System.Collections.Immutable.ImmutableQueue`1";
private const string ImmutableStackTypeName = "System.Collections.Immutable.ImmutableStack";
private const string ImmutableStackGenericTypeName = "System.Collections.Immutable.ImmutableStack`1";
private const string ImmutableSortedSetTypeName = "System.Collections.Immutable.ImmutableSortedSet";
private const string ImmutableSortedSetGenericTypeName = "System.Collections.Immutable.ImmutableSortedSet`1";
private const string ImmutableHashSetTypeName = "System.Collections.Immutable.ImmutableHashSet";
private const string ImmutableHashSetGenericTypeName = "System.Collections.Immutable.ImmutableHashSet`1";
private static readonly IList<ImmutableCollectionTypeInfo> ArrayContractImmutableCollectionDefinitions = new List<ImmutableCollectionTypeInfo>
{
new ImmutableCollectionTypeInfo(ImmutableListGenericInterfaceTypeName, ImmutableListGenericTypeName, ImmutableListTypeName),
new ImmutableCollectionTypeInfo(ImmutableListGenericTypeName, ImmutableListGenericTypeName, ImmutableListTypeName),
new ImmutableCollectionTypeInfo(ImmutableQueueGenericInterfaceTypeName, ImmutableQueueGenericTypeName, ImmutableQueueTypeName),
new ImmutableCollectionTypeInfo(ImmutableQueueGenericTypeName, ImmutableQueueGenericTypeName, ImmutableQueueTypeName),
new ImmutableCollectionTypeInfo(ImmutableStackGenericInterfaceTypeName, ImmutableStackGenericTypeName, ImmutableStackTypeName),
new ImmutableCollectionTypeInfo(ImmutableStackGenericTypeName, ImmutableStackGenericTypeName, ImmutableStackTypeName),
new ImmutableCollectionTypeInfo(ImmutableSetGenericInterfaceTypeName, ImmutableSortedSetGenericTypeName, ImmutableSortedSetTypeName),
new ImmutableCollectionTypeInfo(ImmutableSortedSetGenericTypeName, ImmutableSortedSetGenericTypeName, ImmutableSortedSetTypeName),
new ImmutableCollectionTypeInfo(ImmutableHashSetGenericTypeName, ImmutableHashSetGenericTypeName, ImmutableHashSetTypeName),
new ImmutableCollectionTypeInfo(ImmutableArrayGenericTypeName, ImmutableArrayGenericTypeName, ImmutableArrayTypeName)
};
private const string ImmutableDictionaryGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableDictionary`2";
private const string ImmutableDictionaryTypeName = "System.Collections.Immutable.ImmutableDictionary";
private const string ImmutableDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableDictionary`2";
private const string ImmutableSortedDictionaryTypeName = "System.Collections.Immutable.ImmutableSortedDictionary";
private const string ImmutableSortedDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableSortedDictionary`2";
private static readonly IList<ImmutableCollectionTypeInfo> DictionaryContractImmutableCollectionDefinitions = new List<ImmutableCollectionTypeInfo>
{
new ImmutableCollectionTypeInfo(ImmutableDictionaryGenericInterfaceTypeName, ImmutableSortedDictionaryGenericTypeName, ImmutableSortedDictionaryTypeName),
new ImmutableCollectionTypeInfo(ImmutableSortedDictionaryGenericTypeName, ImmutableSortedDictionaryGenericTypeName, ImmutableSortedDictionaryTypeName),
new ImmutableCollectionTypeInfo(ImmutableDictionaryGenericTypeName, ImmutableDictionaryGenericTypeName, ImmutableDictionaryTypeName)
};
internal static bool TryBuildImmutableForArrayContract(Type underlyingType, Type collectionItemType, out Type createdType, out ObjectConstructor<object> parameterizedCreator)
{
if (underlyingType.IsGenericType())
{
Type underlyingTypeDefinition = underlyingType.GetGenericTypeDefinition();
string name = underlyingTypeDefinition.FullName;
ImmutableCollectionTypeInfo definition = ArrayContractImmutableCollectionDefinitions.FirstOrDefault(d => d.ContractTypeName == name);
if (definition != null)
{
Type createdTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.CreatedTypeName);
Type builderTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.BuilderTypeName);
if (createdTypeDefinition != null && builderTypeDefinition != null)
{
MethodInfo mb = builderTypeDefinition.GetMethods().FirstOrDefault(m => m.Name == "CreateRange" && m.GetParameters().Length == 1);
if (mb != null)
{
createdType = createdTypeDefinition.MakeGenericType(collectionItemType);
MethodInfo method = mb.MakeGenericMethod(collectionItemType);
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(method);
return true;
}
}
}
}
createdType = null;
parameterizedCreator = null;
return false;
}
internal static bool TryBuildImmutableForDictionaryContract(Type underlyingType, Type keyItemType, Type valueItemType, out Type createdType, out ObjectConstructor<object> parameterizedCreator)
{
if (underlyingType.IsGenericType())
{
Type underlyingTypeDefinition = underlyingType.GetGenericTypeDefinition();
string name = underlyingTypeDefinition.FullName;
ImmutableCollectionTypeInfo definition = DictionaryContractImmutableCollectionDefinitions.FirstOrDefault(d => d.ContractTypeName == name);
if (definition != null)
{
Type createdTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.CreatedTypeName);
Type builderTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.BuilderTypeName);
if (createdTypeDefinition != null && builderTypeDefinition != null)
{
MethodInfo mb = builderTypeDefinition.GetMethods().FirstOrDefault(m =>
{
ParameterInfo[] parameters = m.GetParameters();
return m.Name == "CreateRange" && parameters.Length == 1 && parameters[0].ParameterType.IsGenericType() && parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>);
});
if (mb != null)
{
createdType = createdTypeDefinition.MakeGenericType(keyItemType, valueItemType);
MethodInfo method = mb.MakeGenericMethod(keyItemType, valueItemType);
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(method);
return true;
}
}
}
}
createdType = null;
parameterizedCreator = null;
return false;
}
}
}
#endif

View File

@@ -0,0 +1,318 @@
#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.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
namespace Newtonsoft.Json.Utilities
{
internal static class BufferUtils
{
public static char[] RentBuffer(IArrayPool<char> bufferPool, int minSize)
{
if (bufferPool == null)
{
return new char[minSize];
}
char[] buffer = bufferPool.Rent(minSize);
return buffer;
}
public static void ReturnBuffer(IArrayPool<char> bufferPool, char[] buffer)
{
if (bufferPool == null)
{
return;
}
bufferPool.Return(buffer);
}
public static char[] EnsureBufferSize(IArrayPool<char> bufferPool, int size, char[] buffer)
{
if (bufferPool == null)
{
return new char[size];
}
if (buffer != null)
{
bufferPool.Return(buffer);
}
return bufferPool.Rent(size);
}
}
internal static class JavaScriptUtils
{
internal static readonly bool[] SingleQuoteCharEscapeFlags = new bool[128];
internal static readonly bool[] DoubleQuoteCharEscapeFlags = new bool[128];
internal static readonly bool[] HtmlCharEscapeFlags = new bool[128];
private const int UnicodeTextLength = 6;
static JavaScriptUtils()
{
IList<char> escapeChars = new List<char>
{
'\n', '\r', '\t', '\\', '\f', '\b',
};
for (int i = 0; i < ' '; i++)
{
escapeChars.Add((char)i);
}
foreach (var escapeChar in escapeChars.Union(new[] { '\'' }))
{
SingleQuoteCharEscapeFlags[escapeChar] = true;
}
foreach (var escapeChar in escapeChars.Union(new[] { '"' }))
{
DoubleQuoteCharEscapeFlags[escapeChar] = true;
}
foreach (var escapeChar in escapeChars.Union(new[] { '"', '\'', '<', '>', '&' }))
{
HtmlCharEscapeFlags[escapeChar] = true;
}
}
private const string EscapedUnicodeText = "!";
public static bool[] GetCharEscapeFlags(StringEscapeHandling stringEscapeHandling, char quoteChar)
{
if (stringEscapeHandling == StringEscapeHandling.EscapeHtml)
{
return HtmlCharEscapeFlags;
}
if (quoteChar == '"')
{
return DoubleQuoteCharEscapeFlags;
}
return SingleQuoteCharEscapeFlags;
}
public static bool ShouldEscapeJavaScriptString(string s, bool[] charEscapeFlags)
{
if (s == null)
{
return false;
}
foreach (char c in s)
{
if (c >= charEscapeFlags.Length || charEscapeFlags[c])
{
return true;
}
}
return false;
}
public static void WriteEscapedJavaScriptString(TextWriter writer, string s, char delimiter, bool appendDelimiters,
bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, IArrayPool<char> bufferPool, ref char[] writeBuffer)
{
// leading delimiter
if (appendDelimiters)
{
writer.Write(delimiter);
}
if (s != null)
{
int lastWritePosition = 0;
for (int i = 0; i < s.Length; i++)
{
var c = s[i];
if (c < charEscapeFlags.Length && !charEscapeFlags[c])
{
continue;
}
string escapedValue;
switch (c)
{
case '\t':
escapedValue = @"\t";
break;
case '\n':
escapedValue = @"\n";
break;
case '\r':
escapedValue = @"\r";
break;
case '\f':
escapedValue = @"\f";
break;
case '\b':
escapedValue = @"\b";
break;
case '\\':
escapedValue = @"\\";
break;
case '\u0085': // Next Line
escapedValue = @"\u0085";
break;
case '\u2028': // Line Separator
escapedValue = @"\u2028";
break;
case '\u2029': // Paragraph Separator
escapedValue = @"\u2029";
break;
default:
if (c < charEscapeFlags.Length || stringEscapeHandling == StringEscapeHandling.EscapeNonAscii)
{
if (c == '\'' && stringEscapeHandling != StringEscapeHandling.EscapeHtml)
{
escapedValue = @"\'";
}
else if (c == '"' && stringEscapeHandling != StringEscapeHandling.EscapeHtml)
{
escapedValue = @"\""";
}
else
{
if (writeBuffer == null || writeBuffer.Length < UnicodeTextLength)
{
writeBuffer = BufferUtils.EnsureBufferSize(bufferPool, UnicodeTextLength, writeBuffer);
}
StringUtils.ToCharAsUnicode(c, writeBuffer);
// slightly hacky but it saves multiple conditions in if test
escapedValue = EscapedUnicodeText;
}
}
else
{
escapedValue = null;
}
break;
}
if (escapedValue == null)
{
continue;
}
bool isEscapedUnicodeText = string.Equals(escapedValue, EscapedUnicodeText);
if (i > lastWritePosition)
{
int length = i - lastWritePosition + ((isEscapedUnicodeText) ? UnicodeTextLength : 0);
int start = (isEscapedUnicodeText) ? UnicodeTextLength : 0;
if (writeBuffer == null || writeBuffer.Length < length)
{
char[] newBuffer = BufferUtils.RentBuffer(bufferPool, length);
// the unicode text is already in the buffer
// copy it over when creating new buffer
if (isEscapedUnicodeText)
{
Array.Copy(writeBuffer, newBuffer, UnicodeTextLength);
}
BufferUtils.ReturnBuffer(bufferPool, writeBuffer);
writeBuffer = newBuffer;
}
s.CopyTo(lastWritePosition, writeBuffer, start, length - start);
// write unchanged chars before writing escaped text
writer.Write(writeBuffer, start, length - start);
}
lastWritePosition = i + 1;
if (!isEscapedUnicodeText)
{
writer.Write(escapedValue);
}
else
{
writer.Write(writeBuffer, 0, UnicodeTextLength);
}
}
if (lastWritePosition == 0)
{
// no escaped text, write entire string
writer.Write(s);
}
else
{
int length = s.Length - lastWritePosition;
if (writeBuffer == null || writeBuffer.Length < length)
{
writeBuffer = BufferUtils.EnsureBufferSize(bufferPool, length, writeBuffer);
}
s.CopyTo(lastWritePosition, writeBuffer, 0, length);
// write remaining text
writer.Write(writeBuffer, 0, length);
}
}
// trailing delimiter
if (appendDelimiters)
{
writer.Write(delimiter);
}
}
public static string ToEscapedJavaScriptString(string value, char delimiter, bool appendDelimiters, StringEscapeHandling stringEscapeHandling)
{
bool[] charEscapeFlags = GetCharEscapeFlags(stringEscapeHandling, delimiter);
using (StringWriter w = StringUtils.CreateStringWriter(StringUtils.GetLength(value) ?? 16))
{
char[] buffer = null;
WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters, charEscapeFlags, stringEscapeHandling, null, ref buffer);
return w.ToString();
}
}
}
}

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 System.Text;
namespace Newtonsoft.Json.Utilities
{
internal static class JsonTokenUtils
{
internal static bool IsEndToken(JsonToken token)
{
switch (token)
{
case JsonToken.EndObject:
case JsonToken.EndArray:
case JsonToken.EndConstructor:
return true;
default:
return false;
}
}
internal static bool IsStartToken(JsonToken token)
{
switch (token)
{
case JsonToken.StartObject:
case JsonToken.StartArray:
case JsonToken.StartConstructor:
return true;
default:
return false;
}
}
internal static bool IsPrimitiveToken(JsonToken token)
{
switch (token)
{
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Undefined:
case JsonToken.Null:
case JsonToken.Date:
case JsonToken.Bytes:
return true;
default:
return false;
}
}
}
}

View File

@@ -0,0 +1,119 @@
#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 Newtonsoft.Json.Serialization;
using System.Reflection;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#endif
namespace Newtonsoft.Json.Utilities
{
internal class LateBoundReflectionDelegateFactory : ReflectionDelegateFactory
{
private static readonly LateBoundReflectionDelegateFactory _instance = new LateBoundReflectionDelegateFactory();
internal static ReflectionDelegateFactory Instance
{
get { return _instance; }
}
public override ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
{
ValidationUtils.ArgumentNotNull(method, nameof(method));
ConstructorInfo c = method as ConstructorInfo;
if (c != null)
{
// don't convert to method group to avoid medium trust issues
// https://github.com/JamesNK/Newtonsoft.Json/issues/476
return a =>
{
object[] args = a;
return c.Invoke(args);
};
}
return a => method.Invoke(null, a);
}
public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method)
{
ValidationUtils.ArgumentNotNull(method, nameof(method));
ConstructorInfo c = method as ConstructorInfo;
if (c != null)
{
return (o, a) => c.Invoke(a);
}
return (o, a) => method.Invoke(o, a);
}
public override Func<T> CreateDefaultConstructor<T>(Type type)
{
ValidationUtils.ArgumentNotNull(type, nameof(type));
if (type.IsValueType())
{
return () => (T)Activator.CreateInstance(type);
}
ConstructorInfo constructorInfo = ReflectionUtils.GetDefaultConstructor(type, true);
return () => (T)constructorInfo.Invoke(null);
}
public override Func<T, object> CreateGet<T>(PropertyInfo propertyInfo)
{
ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
return o => propertyInfo.GetValue(o, null);
}
public override Func<T, object> CreateGet<T>(FieldInfo fieldInfo)
{
ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo));
return o => fieldInfo.GetValue(o);
}
public override Action<T, object> CreateSet<T>(FieldInfo fieldInfo)
{
ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo));
return (o, v) => fieldInfo.SetValue(o, v);
}
public override Action<T, object> CreateSet<T>(PropertyInfo propertyInfo)
{
ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
return (o, v) => propertyInfo.SetValue(o, v, null);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,187 @@
#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 Newtonsoft.Json.Utilities
{
internal static class MathUtils
{
public static int IntLength(ulong i)
{
if (i < 10000000000)
{
if (i < 10)
{
return 1;
}
if (i < 100)
{
return 2;
}
if (i < 1000)
{
return 3;
}
if (i < 10000)
{
return 4;
}
if (i < 100000)
{
return 5;
}
if (i < 1000000)
{
return 6;
}
if (i < 10000000)
{
return 7;
}
if (i < 100000000)
{
return 8;
}
if (i < 1000000000)
{
return 9;
}
return 10;
}
else
{
if (i < 100000000000)
{
return 11;
}
if (i < 1000000000000)
{
return 12;
}
if (i < 10000000000000)
{
return 13;
}
if (i < 100000000000000)
{
return 14;
}
if (i < 1000000000000000)
{
return 15;
}
if (i < 10000000000000000)
{
return 16;
}
if (i < 100000000000000000)
{
return 17;
}
if (i < 1000000000000000000)
{
return 18;
}
if (i < 10000000000000000000)
{
return 19;
}
return 20;
}
}
public static char IntToHex(int n)
{
if (n <= 9)
{
return (char)(n + 48);
}
return (char)((n - 10) + 97);
}
public static int? Min(int? val1, int? val2)
{
if (val1 == null)
{
return val2;
}
if (val2 == null)
{
return val1;
}
return Math.Min(val1.GetValueOrDefault(), val2.GetValueOrDefault());
}
public static int? Max(int? val1, int? val2)
{
if (val1 == null)
{
return val2;
}
if (val2 == null)
{
return val1;
}
return Math.Max(val1.GetValueOrDefault(), val2.GetValueOrDefault());
}
public static double? Max(double? val1, double? val2)
{
if (val1 == null)
{
return val2;
}
if (val2 == null)
{
return val1;
}
return Math.Max(val1.GetValueOrDefault(), val2.GetValueOrDefault());
}
public static bool ApproxEquals(double d1, double d2)
{
const double epsilon = 2.2204460492503131E-16;
if (d1 == d2)
{
return true;
}
double tolerance = ((Math.Abs(d1) + Math.Abs(d2)) + 10.0) * epsilon;
double difference = d1 - d2;
return (-tolerance < difference && tolerance > difference);
}
}
}

View File

@@ -0,0 +1,29 @@
#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 Newtonsoft.Json.Utilities
{
internal delegate TResult MethodCall<T, TResult>(T target, params object[] args);
}

View File

@@ -0,0 +1,162 @@
#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.ComponentModel;
using System.Reflection;
using System.Text;
using System.Globalization;
namespace Newtonsoft.Json.Utilities
{
internal delegate T Creator<T>();
internal static class MiscellaneousUtils
{
public static bool ValueEquals(object objA, object objB)
{
if (objA == null && objB == null)
{
return true;
}
if (objA != null && objB == null)
{
return false;
}
if (objA == null && objB != null)
{
return false;
}
// comparing an Int32 and Int64 both of the same value returns false
// make types the same then compare
if (objA.GetType() != objB.GetType())
{
if (ConvertUtils.IsInteger(objA) && ConvertUtils.IsInteger(objB))
{
return Convert.ToDecimal(objA, CultureInfo.CurrentCulture).Equals(Convert.ToDecimal(objB, CultureInfo.CurrentCulture));
}
else if ((objA is double || objA is float || objA is decimal) && (objB is double || objB is float || objB is decimal))
{
return MathUtils.ApproxEquals(Convert.ToDouble(objA, CultureInfo.CurrentCulture), Convert.ToDouble(objB, CultureInfo.CurrentCulture));
}
else
{
return false;
}
}
return objA.Equals(objB);
}
public static ArgumentOutOfRangeException CreateArgumentOutOfRangeException(string paramName, object actualValue, string message)
{
string newMessage = message + Environment.NewLine + @"Actual value was {0}.".FormatWith(CultureInfo.InvariantCulture, actualValue);
return new ArgumentOutOfRangeException(paramName, newMessage);
}
public static string ToString(object value)
{
if (value == null)
{
return "{null}";
}
return (value is string) ? @"""" + value.ToString() + @"""" : value.ToString();
}
public static int ByteArrayCompare(byte[] a1, byte[] a2)
{
int lengthCompare = a1.Length.CompareTo(a2.Length);
if (lengthCompare != 0)
{
return lengthCompare;
}
for (int i = 0; i < a1.Length; i++)
{
int valueCompare = a1[i].CompareTo(a2[i]);
if (valueCompare != 0)
{
return valueCompare;
}
}
return 0;
}
public static string GetPrefix(string qualifiedName)
{
string prefix;
string localName;
GetQualifiedNameParts(qualifiedName, out prefix, out localName);
return prefix;
}
public static string GetLocalName(string qualifiedName)
{
string prefix;
string localName;
GetQualifiedNameParts(qualifiedName, out prefix, out localName);
return localName;
}
public static void GetQualifiedNameParts(string qualifiedName, out string prefix, out string localName)
{
int colonPosition = qualifiedName.IndexOf(':');
if ((colonPosition == -1 || colonPosition == 0) || (qualifiedName.Length - 1) == colonPosition)
{
prefix = null;
localName = qualifiedName;
}
else
{
prefix = qualifiedName.Substring(0, colonPosition);
localName = qualifiedName.Substring(colonPosition + 1);
}
}
internal static string FormatValueForPrint(object value)
{
if (value == null)
{
return "{null}";
}
if (value is string)
{
return @"""" + value + @"""";
}
return value.ToString();
}
}
}

View File

@@ -0,0 +1,173 @@
#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 Newtonsoft.Json.Utilities
{
internal class PropertyNameTable
{
// 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 PropertyNameTable()
{
HashCodeRandomizer = Environment.TickCount;
}
public PropertyNameTable()
{
_entries = new Entry[_mask + 1];
}
public 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;
for (Entry entry = _entries[hashCode & _mask]; entry != null; entry = entry.Next)
{
if (entry.HashCode == hashCode && TextEquals(entry.Value, key, start, length))
{
return entry.Value;
}
}
return null;
}
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))
{
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,81 @@
#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.Reflection;
using Newtonsoft.Json.Serialization;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#endif
namespace Newtonsoft.Json.Utilities
{
internal abstract class ReflectionDelegateFactory
{
public Func<T, object> CreateGet<T>(MemberInfo memberInfo)
{
PropertyInfo propertyInfo = memberInfo as PropertyInfo;
if (propertyInfo != null)
{
return CreateGet<T>(propertyInfo);
}
FieldInfo fieldInfo = memberInfo as FieldInfo;
if (fieldInfo != null)
{
return CreateGet<T>(fieldInfo);
}
throw new Exception("Could not create getter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo));
}
public Action<T, object> CreateSet<T>(MemberInfo memberInfo)
{
PropertyInfo propertyInfo = memberInfo as PropertyInfo;
if (propertyInfo != null)
{
return CreateSet<T>(propertyInfo);
}
FieldInfo fieldInfo = memberInfo as FieldInfo;
if (fieldInfo != null)
{
return CreateSet<T>(fieldInfo);
}
throw new Exception("Could not create setter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo));
}
public abstract MethodCall<T, object> CreateMethodCall<T>(MethodBase method);
public abstract ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method);
public abstract Func<T> CreateDefaultConstructor<T>(Type type);
public abstract Func<T, object> CreateGet<T>(PropertyInfo propertyInfo);
public abstract Func<T, object> CreateGet<T>(FieldInfo fieldInfo);
public abstract Action<T, object> CreateSet<T>(FieldInfo fieldInfo);
public abstract Action<T, object> CreateSet<T>(PropertyInfo propertyInfo);
}
}

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
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Globalization;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
namespace Newtonsoft.Json.Utilities
{
internal class ReflectionMember
{
public Type MemberType { get; set; }
public Func<object, object> Getter { get; set; }
public Action<object, object> Setter { get; set; }
}
internal class ReflectionObject
{
public ObjectConstructor<object> Creator { get; private set; }
public IDictionary<string, ReflectionMember> Members { get; private set; }
public ReflectionObject()
{
Members = new Dictionary<string, ReflectionMember>();
}
public object GetValue(object target, string member)
{
Func<object, object> getter = Members[member].Getter;
return getter(target);
}
public void SetValue(object target, string member, object value)
{
Action<object, object> setter = Members[member].Setter;
setter(target, value);
}
public Type GetType(string member)
{
return Members[member].MemberType;
}
public static ReflectionObject Create(Type t, params string[] memberNames)
{
return Create(t, null, memberNames);
}
public static ReflectionObject Create(Type t, MethodBase creator, params string[] memberNames)
{
ReflectionObject d = new ReflectionObject();
ReflectionDelegateFactory delegateFactory = JsonTypeReflector.ReflectionDelegateFactory;
if (creator != null)
{
d.Creator = delegateFactory.CreateParameterizedConstructor(creator);
}
else
{
if (ReflectionUtils.HasDefaultConstructor(t, false))
{
Func<object> ctor = delegateFactory.CreateDefaultConstructor<object>(t);
d.Creator = args => ctor();
}
}
foreach (string memberName in memberNames)
{
MemberInfo[] members = t.GetMember(memberName, BindingFlags.Instance | BindingFlags.Public);
if (members.Length != 1)
{
throw new ArgumentException("Expected a single member with the name '{0}'.".FormatWith(CultureInfo.InvariantCulture, memberName));
}
MemberInfo member = members.Single();
ReflectionMember reflectionMember = new ReflectionMember();
switch (member.MemberType())
{
case MemberTypes.Field:
case MemberTypes.Property:
if (ReflectionUtils.CanReadMemberValue(member, false))
{
reflectionMember.Getter = delegateFactory.CreateGet<object>(member);
}
if (ReflectionUtils.CanSetMemberValue(member, false, false))
{
reflectionMember.Setter = delegateFactory.CreateSet<object>(member);
}
break;
case MemberTypes.Method:
MethodInfo method = (MethodInfo)member;
if (method.IsPublic)
{
ParameterInfo[] parameters = method.GetParameters();
if (parameters.Length == 0 && method.ReturnType != typeof(void))
{
MethodCall<object, object> call = delegateFactory.CreateMethodCall<object>(method);
reflectionMember.Getter = target => call(target);
}
else if (parameters.Length == 1 && method.ReturnType == typeof(void))
{
MethodCall<object, object> call = delegateFactory.CreateMethodCall<object>(method);
reflectionMember.Setter = (target, arg) => call(target, arg);
}
}
break;
default:
throw new ArgumentException("Unexpected member type '{0}' for member '{1}'.".FormatWith(CultureInfo.InvariantCulture, member.MemberType(), member.Name));
}
if (ReflectionUtils.CanReadMemberValue(member, false))
{
reflectionMember.Getter = delegateFactory.CreateGet<object>(member);
}
if (ReflectionUtils.CanSetMemberValue(member, false, false))
{
reflectionMember.Setter = delegateFactory.CreateSet<object>(member);
}
reflectionMember.MemberType = ReflectionUtils.GetMemberUnderlyingType(member);
d.Members[memberName] = reflectionMember;
}
return d;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,122 @@
#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 Newtonsoft.Json.Utilities
{
/// <summary>
/// Builds a string. Unlike StringBuilder this class lets you reuse it's internal buffer.
/// </summary>
internal struct StringBuffer
{
private char[] _buffer;
private int _position;
public int Position
{
get { return _position; }
set { _position = value; }
}
public bool IsEmpty
{
get { return _buffer == null; }
}
public StringBuffer(IArrayPool<char> bufferPool, int initalSize) : this(BufferUtils.RentBuffer(bufferPool, initalSize))
{
}
private StringBuffer(char[] buffer)
{
_buffer = buffer;
_position = 0;
}
public void Append(IArrayPool<char> bufferPool, char value)
{
// test if the buffer array is large enough to take the value
if (_position == _buffer.Length)
{
EnsureSize(bufferPool, 1);
}
// set value and increment poisition
_buffer[_position++] = value;
}
public void Append(IArrayPool<char> bufferPool, char[] buffer, int startIndex, int count)
{
if (_position + count >= _buffer.Length)
{
EnsureSize(bufferPool, count);
}
Array.Copy(buffer, startIndex, _buffer, _position, count);
_position += count;
}
public void Clear(IArrayPool<char> bufferPool)
{
if (_buffer != null)
{
BufferUtils.ReturnBuffer(bufferPool, _buffer);
_buffer = null;
}
_position = 0;
}
private void EnsureSize(IArrayPool<char> bufferPool, int appendLength)
{
char[] newBuffer = BufferUtils.RentBuffer(bufferPool, (_position + appendLength) * 2);
if (_buffer != null)
{
Array.Copy(_buffer, newBuffer, _position);
BufferUtils.ReturnBuffer(bufferPool, _buffer);
}
_buffer = newBuffer;
}
public override string ToString()
{
return ToString(0, _position);
}
public string ToString(int start, int length)
{
// TODO: validation
return new string(_buffer, start, length);
}
public char[] InternalBuffer
{
get { return _buffer; }
}
}
}

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
using System;
namespace Newtonsoft.Json.Utilities
{
internal struct StringReference
{
private readonly char[] _chars;
private readonly int _startIndex;
private readonly int _length;
public char this[int i]
{
get { return _chars[i]; }
}
public char[] Chars
{
get { return _chars; }
}
public int StartIndex
{
get { return _startIndex; }
}
public int Length
{
get { return _length; }
}
public StringReference(char[] chars, int startIndex, int length)
{
_chars = chars;
_startIndex = startIndex;
_length = length;
}
public override string ToString()
{
return new string(_chars, _startIndex, _length);
}
}
internal static class StringReferenceExtensions
{
public static int IndexOf(this StringReference s, char c, int startIndex, int length)
{
int index = Array.IndexOf(s.Chars, c, s.StartIndex + startIndex, length);
if (index == -1)
{
return -1;
}
return index - s.StartIndex;
}
public static bool StartsWith(this StringReference s, string text)
{
if (text.Length > s.Length)
{
return false;
}
char[] chars = s.Chars;
for (int i = 0; i < text.Length; i++)
{
if (text[i] != chars[i + s.StartIndex])
{
return false;
}
}
return true;
}
public static bool EndsWith(this StringReference s, string text)
{
if (text.Length > s.Length)
{
return false;
}
char[] chars = s.Chars;
int start = s.StartIndex + s.Length - text.Length;
for (int i = 0; i < text.Length; i++)
{
if (text[i] != chars[i + start])
{
return false;
}
}
return true;
}
}
}

View File

@@ -0,0 +1,231 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Globalization;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Utilities
{
internal static class StringUtils
{
public const string CarriageReturnLineFeed = "\r\n";
public const string Empty = "";
public const char CarriageReturn = '\r';
public const char LineFeed = '\n';
public const char Tab = '\t';
public static string FormatWith(this string format, IFormatProvider provider, object arg0)
{
return format.FormatWith(provider, new[] { arg0 });
}
public static string FormatWith(this string format, IFormatProvider provider, object arg0, object arg1)
{
return format.FormatWith(provider, new[] { arg0, arg1 });
}
public static string FormatWith(this string format, IFormatProvider provider, object arg0, object arg1, object arg2)
{
return format.FormatWith(provider, new[] { arg0, arg1, arg2 });
}
public static string FormatWith(this string format, IFormatProvider provider, object arg0, object arg1, object arg2, object arg3)
{
return format.FormatWith(provider, new[] { arg0, arg1, arg2, arg3 });
}
private static string FormatWith(this string format, IFormatProvider provider, params object[] args)
{
// leave this a private to force code to use an explicit overload
// avoids stack memory being reserved for the object array
ValidationUtils.ArgumentNotNull(format, nameof(format));
return string.Format(provider, format, args);
}
/// <summary>
/// Determines whether the string is all white space. Empty string will return false.
/// </summary>
/// <param name="s">The string to test whether it is all white space.</param>
/// <returns>
/// <c>true</c> if the string is all white space; otherwise, <c>false</c>.
/// </returns>
public static bool IsWhiteSpace(string s)
{
if (s == null)
{
throw new ArgumentNullException(nameof(s));
}
if (s.Length == 0)
{
return false;
}
for (int i = 0; i < s.Length; i++)
{
if (!char.IsWhiteSpace(s[i]))
{
return false;
}
}
return true;
}
/// <summary>
/// Nulls an empty string.
/// </summary>
/// <param name="s">The string.</param>
/// <returns>Null if the string was null, otherwise the string unchanged.</returns>
public static string NullEmptyString(string s)
{
return (string.IsNullOrEmpty(s)) ? null : s;
}
public static StringWriter CreateStringWriter(int capacity)
{
StringBuilder sb = new StringBuilder(capacity);
StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture);
return sw;
}
public static int? GetLength(string value)
{
if (value == null)
{
return null;
}
else
{
return value.Length;
}
}
public static void ToCharAsUnicode(char c, char[] buffer)
{
buffer[0] = '\\';
buffer[1] = 'u';
buffer[2] = MathUtils.IntToHex((c >> 12) & '\x000f');
buffer[3] = MathUtils.IntToHex((c >> 8) & '\x000f');
buffer[4] = MathUtils.IntToHex((c >> 4) & '\x000f');
buffer[5] = MathUtils.IntToHex(c & '\x000f');
}
public static TSource ForgivingCaseSensitiveFind<TSource>(this IEnumerable<TSource> source, Func<TSource, string> valueSelector, string testValue)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (valueSelector == null)
{
throw new ArgumentNullException(nameof(valueSelector));
}
var caseInsensitiveResults = source.Where(s => string.Equals(valueSelector(s), testValue, StringComparison.OrdinalIgnoreCase));
if (caseInsensitiveResults.Count() <= 1)
{
return caseInsensitiveResults.SingleOrDefault();
}
else
{
// multiple results returned. now filter using case sensitivity
var caseSensitiveResults = source.Where(s => string.Equals(valueSelector(s), testValue, StringComparison.Ordinal));
return caseSensitiveResults.SingleOrDefault();
}
}
public static string ToCamelCase(string s)
{
if (string.IsNullOrEmpty(s) || !char.IsUpper(s[0]))
{
return s;
}
char[] chars = s.ToCharArray();
for (int i = 0; i < chars.Length; i++)
{
if (i == 1 && !char.IsUpper(chars[i]))
{
break;
}
bool hasNext = (i + 1 < chars.Length);
if (i > 0 && hasNext && !char.IsUpper(chars[i + 1]))
{
break;
}
#if !(DOTNET || PORTABLE)
chars[i] = char.ToLower(chars[i], CultureInfo.InvariantCulture);
#else
chars[i] = char.ToLowerInvariant(chars[i]);
#endif
}
return new string(chars);
}
public static bool IsHighSurrogate(char c)
{
#if !(PORTABLE40 || PORTABLE)
return char.IsHighSurrogate(c);
#else
return (c >= 55296 && c <= 56319);
#endif
}
public static bool IsLowSurrogate(char c)
{
#if !(PORTABLE40 || PORTABLE)
return char.IsLowSurrogate(c);
#else
return (c >= 56320 && c <= 57343);
#endif
}
public static bool StartsWith(this string source, char value)
{
return (source.Length > 0 && source[0] == value);
}
public static bool EndsWith(this string source, char value)
{
return (source.Length > 0 && source[source.Length - 1] == value);
}
}
}

View File

@@ -0,0 +1,97 @@
#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 NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#endif
using System.Threading;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Utilities
{
internal class ThreadSafeStore<TKey, TValue>
{
private readonly object _lock = new object();
private Dictionary<TKey, TValue> _store;
private readonly Func<TKey, TValue> _creator;
public ThreadSafeStore(Func<TKey, TValue> creator)
{
if (creator == null)
{
throw new ArgumentNullException(nameof(creator));
}
_creator = creator;
_store = new Dictionary<TKey, TValue>();
}
public TValue Get(TKey key)
{
TValue value;
if (!_store.TryGetValue(key, out value))
{
return AddValue(key);
}
return value;
}
private TValue AddValue(TKey key)
{
TValue value = _creator(key);
lock (_lock)
{
if (_store == null)
{
_store = new Dictionary<TKey, TValue>();
_store[key] = value;
}
else
{
// double check locking
TValue checkValue;
if (_store.TryGetValue(key, out checkValue))
{
return checkValue;
}
Dictionary<TKey, TValue> newStore = new Dictionary<TKey, TValue>(_store);
newStore[key] = value;
#if !(DOTNET || PORTABLE)
Thread.MemoryBarrier();
#endif
_store = newStore;
}
return value;
}
}
}
}

View File

@@ -0,0 +1,628 @@
#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.Reflection;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
namespace Newtonsoft.Json.Utilities
{
internal static class TypeExtensions
{
#if DOTNET || PORTABLE
#if !DOTNET
private static BindingFlags DefaultFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo)
{
return propertyInfo.GetGetMethod(false);
}
public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo, bool nonPublic)
{
MethodInfo getMethod = propertyInfo.GetMethod;
if (getMethod != null && (getMethod.IsPublic || nonPublic))
{
return getMethod;
}
return null;
}
public static MethodInfo GetSetMethod(this PropertyInfo propertyInfo)
{
return propertyInfo.GetSetMethod(false);
}
public static MethodInfo GetSetMethod(this PropertyInfo propertyInfo, bool nonPublic)
{
MethodInfo setMethod = propertyInfo.SetMethod;
if (setMethod != null && (setMethod.IsPublic || nonPublic))
{
return setMethod;
}
return null;
}
#endif
public static bool IsSubclassOf(this Type type, Type c)
{
return type.GetTypeInfo().IsSubclassOf(c);
}
#if !DOTNET
public static bool IsAssignableFrom(this Type type, Type c)
{
return type.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo());
}
#endif
public static bool IsInstanceOfType(this Type type, object o)
{
if (o == null)
{
return false;
}
return type.IsAssignableFrom(o.GetType());
}
#endif
public static MethodInfo Method(this Delegate d)
{
#if !(DOTNET || PORTABLE)
return d.Method;
#else
return d.GetMethodInfo();
#endif
}
public static MemberTypes MemberType(this MemberInfo memberInfo)
{
#if !(DOTNET || PORTABLE || PORTABLE40)
return memberInfo.MemberType;
#else
if (memberInfo is PropertyInfo)
{
return MemberTypes.Property;
}
else if (memberInfo is FieldInfo)
{
return MemberTypes.Field;
}
else if (memberInfo is EventInfo)
{
return MemberTypes.Event;
}
else if (memberInfo is MethodInfo)
{
return MemberTypes.Method;
}
else
{
return MemberTypes.Other;
}
#endif
}
public static bool ContainsGenericParameters(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.ContainsGenericParameters;
#else
return type.GetTypeInfo().ContainsGenericParameters;
#endif
}
public static bool IsInterface(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.IsInterface;
#else
return type.GetTypeInfo().IsInterface;
#endif
}
public static bool IsGenericType(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.IsGenericType;
#else
return type.GetTypeInfo().IsGenericType;
#endif
}
public static bool IsGenericTypeDefinition(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.IsGenericTypeDefinition;
#else
return type.GetTypeInfo().IsGenericTypeDefinition;
#endif
}
public static Type BaseType(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.BaseType;
#else
return type.GetTypeInfo().BaseType;
#endif
}
public static Assembly Assembly(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.Assembly;
#else
return type.GetTypeInfo().Assembly;
#endif
}
public static bool IsEnum(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.IsEnum;
#else
return type.GetTypeInfo().IsEnum;
#endif
}
public static bool IsClass(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.IsClass;
#else
return type.GetTypeInfo().IsClass;
#endif
}
public static bool IsSealed(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.IsSealed;
#else
return type.GetTypeInfo().IsSealed;
#endif
}
#if (PORTABLE40 || DOTNET || PORTABLE)
public static PropertyInfo GetProperty(this Type type, string name, BindingFlags bindingFlags, object placeholder1, Type propertyType, IList<Type> indexParameters, object placeholder2)
{
IEnumerable<PropertyInfo> propertyInfos = type.GetProperties(bindingFlags);
return propertyInfos.Where(p =>
{
if (name != null && name != p.Name)
{
return false;
}
if (propertyType != null && propertyType != p.PropertyType)
{
return false;
}
if (indexParameters != null)
{
if (!p.GetIndexParameters().Select(ip => ip.ParameterType).SequenceEqual(indexParameters))
{
return false;
}
}
return true;
}).SingleOrDefault();
}
public static IEnumerable<MemberInfo> GetMember(this Type type, string name, MemberTypes memberType, BindingFlags bindingFlags)
{
#if PORTABLE
return type.GetMemberInternal(name, memberType, bindingFlags);
#else
return type.GetMember(name, bindingFlags).Where(m =>
{
if (m.MemberType() != memberType)
{
return false;
}
return true;
});
#endif
}
#endif
#if (DOTNET || PORTABLE)
public static MethodInfo GetBaseDefinition(this MethodInfo method)
{
return method.GetRuntimeBaseDefinition();
}
#endif
#if (DOTNET || PORTABLE)
public static bool IsDefined(this Type type, Type attributeType, bool inherit)
{
return type.GetTypeInfo().CustomAttributes.Any(a => a.AttributeType == attributeType);
}
#if !DOTNET
public static MethodInfo GetMethod(this Type type, string name)
{
return type.GetMethod(name, DefaultFlags);
}
public static MethodInfo GetMethod(this Type type, string name, BindingFlags bindingFlags)
{
return type.GetTypeInfo().GetDeclaredMethod(name);
}
public static MethodInfo GetMethod(this Type type, IList<Type> parameterTypes)
{
return type.GetMethod(null, parameterTypes);
}
public static MethodInfo GetMethod(this Type type, string name, IList<Type> parameterTypes)
{
return type.GetMethod(name, DefaultFlags, null, parameterTypes, null);
}
public static MethodInfo GetMethod(this Type type, string name, BindingFlags bindingFlags, object placeHolder1, IList<Type> parameterTypes, object placeHolder2)
{
return type.GetTypeInfo().DeclaredMethods.Where(
m =>
{
if (name != null && m.Name != name)
{
return false;
}
if (!TestAccessibility(m, bindingFlags))
{
return false;
}
return m.GetParameters().Select(p => p.ParameterType).SequenceEqual(parameterTypes);
}).SingleOrDefault();
}
public static IEnumerable<ConstructorInfo> GetConstructors(this Type type)
{
return type.GetConstructors(DefaultFlags);
}
public static IEnumerable<ConstructorInfo> GetConstructors(this Type type, BindingFlags bindingFlags)
{
return type.GetConstructors(bindingFlags, null);
}
private static IEnumerable<ConstructorInfo> GetConstructors(this Type type, BindingFlags bindingFlags, IList<Type> parameterTypes)
{
return type.GetTypeInfo().DeclaredConstructors.Where(
c =>
{
if (!TestAccessibility(c, bindingFlags))
{
return false;
}
if (parameterTypes != null && !c.GetParameters().Select(p => p.ParameterType).SequenceEqual(parameterTypes))
{
return false;
}
return true;
});
}
public static ConstructorInfo GetConstructor(this Type type, IList<Type> parameterTypes)
{
return type.GetConstructor(DefaultFlags, null, parameterTypes, null);
}
public static ConstructorInfo GetConstructor(this Type type, BindingFlags bindingFlags, object placeholder1, IList<Type> parameterTypes, object placeholder2)
{
return type.GetConstructors(bindingFlags, parameterTypes).SingleOrDefault();
}
public static MemberInfo[] GetMember(this Type type, string member)
{
return type.GetMemberInternal(member, null, DefaultFlags);
}
public static MemberInfo[] GetMember(this Type type, string member, BindingFlags bindingFlags)
{
return type.GetMemberInternal(member, null, bindingFlags);
}
public static MemberInfo[] GetMemberInternal(this Type type, string member, MemberTypes? memberType, BindingFlags bindingFlags)
{
return type.GetTypeInfo().GetMembersRecursive().Where(m =>
m.Name == member &&
// test type before accessibility - accessibility doesn't support some types
(memberType == null || m.MemberType() == memberType) &&
TestAccessibility(m, bindingFlags)).ToArray();
}
public static MemberInfo GetField(this Type type, string member)
{
return type.GetField(member, DefaultFlags);
}
public static MemberInfo GetField(this Type type, string member, BindingFlags bindingFlags)
{
return type.GetTypeInfo().GetDeclaredField(member);
}
public static IEnumerable<PropertyInfo> GetProperties(this Type type, BindingFlags bindingFlags)
{
IList<PropertyInfo> properties = (bindingFlags.HasFlag(BindingFlags.DeclaredOnly))
? type.GetTypeInfo().DeclaredProperties.ToList()
: type.GetTypeInfo().GetPropertiesRecursive();
return properties.Where(p => TestAccessibility(p, bindingFlags));
}
private static IList<MemberInfo> GetMembersRecursive(this TypeInfo type)
{
TypeInfo t = type;
IList<MemberInfo> members = new List<MemberInfo>();
while (t != null)
{
foreach (MemberInfo member in t.DeclaredMembers)
{
if (!members.Any(p => p.Name == member.Name))
{
members.Add(member);
}
}
t = (t.BaseType != null) ? t.BaseType.GetTypeInfo() : null;
}
return members;
}
private static IList<PropertyInfo> GetPropertiesRecursive(this TypeInfo type)
{
TypeInfo t = type;
IList<PropertyInfo> properties = new List<PropertyInfo>();
while (t != null)
{
foreach (PropertyInfo member in t.DeclaredProperties)
{
if (!properties.Any(p => p.Name == member.Name))
{
properties.Add(member);
}
}
t = (t.BaseType != null) ? t.BaseType.GetTypeInfo() : null;
}
return properties;
}
private static IList<FieldInfo> GetFieldsRecursive(this TypeInfo type)
{
TypeInfo t = type;
IList<FieldInfo> fields = new List<FieldInfo>();
while (t != null)
{
foreach (FieldInfo member in t.DeclaredFields)
{
if (!fields.Any(p => p.Name == member.Name))
{
fields.Add(member);
}
}
t = (t.BaseType != null) ? t.BaseType.GetTypeInfo() : null;
}
return fields;
}
public static IEnumerable<MethodInfo> GetMethods(this Type type, BindingFlags bindingFlags)
{
return type.GetTypeInfo().DeclaredMethods;
}
public static PropertyInfo GetProperty(this Type type, string name)
{
return type.GetProperty(name, DefaultFlags);
}
public static PropertyInfo GetProperty(this Type type, string name, BindingFlags bindingFlags)
{
return type.GetTypeInfo().GetDeclaredProperty(name);
}
public static IEnumerable<FieldInfo> GetFields(this Type type)
{
return type.GetFields(DefaultFlags);
}
public static IEnumerable<FieldInfo> GetFields(this Type type, BindingFlags bindingFlags)
{
IList<FieldInfo> fields = (bindingFlags.HasFlag(BindingFlags.DeclaredOnly))
? type.GetTypeInfo().DeclaredFields.ToList()
: type.GetTypeInfo().GetFieldsRecursive();
return fields.Where(f => TestAccessibility(f, bindingFlags)).ToList();
}
private static bool TestAccessibility(PropertyInfo member, BindingFlags bindingFlags)
{
if (member.GetMethod != null && TestAccessibility(member.GetMethod, bindingFlags))
{
return true;
}
if (member.SetMethod != null && TestAccessibility(member.SetMethod, bindingFlags))
{
return true;
}
return false;
}
private static bool TestAccessibility(MemberInfo member, BindingFlags bindingFlags)
{
if (member is FieldInfo)
{
return TestAccessibility((FieldInfo) member, bindingFlags);
}
else if (member is MethodBase)
{
return TestAccessibility((MethodBase) member, bindingFlags);
}
else if (member is PropertyInfo)
{
return TestAccessibility((PropertyInfo) member, bindingFlags);
}
throw new Exception("Unexpected member type.");
}
private static bool TestAccessibility(FieldInfo member, BindingFlags bindingFlags)
{
bool visibility = (member.IsPublic && bindingFlags.HasFlag(BindingFlags.Public)) ||
(!member.IsPublic && bindingFlags.HasFlag(BindingFlags.NonPublic));
bool instance = (member.IsStatic && bindingFlags.HasFlag(BindingFlags.Static)) ||
(!member.IsStatic && bindingFlags.HasFlag(BindingFlags.Instance));
return visibility && instance;
}
private static bool TestAccessibility(MethodBase member, BindingFlags bindingFlags)
{
bool visibility = (member.IsPublic && bindingFlags.HasFlag(BindingFlags.Public)) ||
(!member.IsPublic && bindingFlags.HasFlag(BindingFlags.NonPublic));
bool instance = (member.IsStatic && bindingFlags.HasFlag(BindingFlags.Static)) ||
(!member.IsStatic && bindingFlags.HasFlag(BindingFlags.Instance));
return visibility && instance;
}
public static Type[] GetGenericArguments(this Type type)
{
return type.GetTypeInfo().GenericTypeArguments;
}
public static IEnumerable<Type> GetInterfaces(this Type type)
{
return type.GetTypeInfo().ImplementedInterfaces;
}
public static IEnumerable<MethodInfo> GetMethods(this Type type)
{
return type.GetTypeInfo().DeclaredMethods;
}
#endif
#endif
public static bool IsAbstract(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.IsAbstract;
#else
return type.GetTypeInfo().IsAbstract;
#endif
}
public static bool IsVisible(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.IsVisible;
#else
return type.GetTypeInfo().IsVisible;
#endif
}
public static bool IsValueType(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.IsValueType;
#else
return type.GetTypeInfo().IsValueType;
#endif
}
public static bool AssignableToTypeName(this Type type, string fullTypeName, out Type match)
{
Type current = type;
while (current != null)
{
if (string.Equals(current.FullName, fullTypeName, StringComparison.Ordinal))
{
match = current;
return true;
}
current = current.BaseType();
}
foreach (Type i in type.GetInterfaces())
{
if (string.Equals(i.Name, fullTypeName, StringComparison.Ordinal))
{
match = type;
return true;
}
}
match = null;
return false;
}
public static bool AssignableToTypeName(this Type type, string fullTypeName)
{
Type match;
return type.AssignableToTypeName(fullTypeName, out match);
}
public static bool ImplementInterface(this Type type, Type interfaceType)
{
for (Type currentType = type; currentType != null; currentType = currentType.BaseType())
{
IEnumerable<Type> interfaces = currentType.GetInterfaces();
foreach (Type i in interfaces)
{
if (i == interfaceType || (i != null && i.ImplementInterface(interfaceType)))
{
return true;
}
}
}
return false;
}
}
}

View File

@@ -0,0 +1,40 @@
#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 Newtonsoft.Json.Utilities
{
internal static class ValidationUtils
{
public static void ArgumentNotNull(object value, string parameterName)
{
if (value == null)
{
throw new ArgumentNullException(parameterName);
}
}
}
}