using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text.RegularExpressions;
using DPumpHydr.WinFrmUI.WenSkin.Json.Linq;
using DPumpHydr.WinFrmUI.WenSkin.Json.Schema;
using DPumpHydr.WinFrmUI.WenSkin.Json.Utilities;
namespace DPumpHydr.WinFrmUI.WenSkin.Json
{
///
///
/// Represents a reader that provides validation.
///
///
/// JSON Schema validation has been moved to its own package. See http://www.newtonsoft.com/jsonschema for more details.
///
///
[Obsolete("JSON Schema validation has been moved to its own package. See http://www.newtonsoft.com/jsonschema for more details.")]
public class JsonValidatingReader : JsonReader, IJsonLineInfo
{
private class SchemaScope
{
private readonly JTokenType _tokenType;
private readonly IList _schemas;
private readonly Dictionary _requiredProperties;
public string CurrentPropertyName { get; set; }
public int ArrayItemCount { get; set; }
public bool IsUniqueArray { get; set; }
public IList UniqueArrayItems { get; set; }
public JTokenWriter CurrentItemWriter { get; set; }
public IList Schemas => _schemas;
public Dictionary RequiredProperties => _requiredProperties;
public JTokenType TokenType => _tokenType;
public SchemaScope(JTokenType tokenType, IList schemas)
{
_tokenType = tokenType;
_schemas = schemas;
_requiredProperties = schemas.SelectMany(GetRequiredProperties).Distinct().ToDictionary((string p) => p, (string p) => false);
if (tokenType == JTokenType.Array && schemas.Any((JsonSchemaModel s) => s.UniqueItems))
{
IsUniqueArray = true;
UniqueArrayItems = new List();
}
}
private IEnumerable GetRequiredProperties(JsonSchemaModel schema)
{
if (schema == null || schema.Properties == null)
{
return Enumerable.Empty();
}
return from p in schema.Properties
where p.Value.Required
select p.Key;
}
}
private readonly JsonReader _reader;
private readonly Stack _stack;
private JsonSchema _schema;
private JsonSchemaModel _model;
private SchemaScope _currentScope;
private static readonly IList EmptySchemaList = new List();
///
/// Gets the text value of the current JSON token.
///
///
public override object Value => _reader.Value;
///
/// Gets the depth of the current token in the JSON document.
///
/// The depth of the current token in the JSON document.
public override int Depth => _reader.Depth;
///
/// Gets the path of the current JSON token.
///
public override string Path => _reader.Path;
///
/// Gets the quotation mark character used to enclose the value of a string.
///
///
public override char QuoteChar
{
get
{
return _reader.QuoteChar;
}
protected internal set
{
}
}
///
/// Gets the type of the current JSON token.
///
///
public override JsonToken TokenType => _reader.TokenType;
///
/// Gets the Common Language Runtime (CLR) type for the current JSON token.
///
///
public override Type ValueType => _reader.ValueType;
private IList CurrentSchemas => _currentScope.Schemas;
private IList CurrentMemberSchemas
{
get
{
if (_currentScope == null)
{
return new List(new JsonSchemaModel[1] { _model });
}
if (_currentScope.Schemas == null || _currentScope.Schemas.Count == 0)
{
return EmptySchemaList;
}
switch (_currentScope.TokenType)
{
case JTokenType.None:
return _currentScope.Schemas;
case JTokenType.Object:
{
if (_currentScope.CurrentPropertyName == null)
{
throw new JsonReaderException("CurrentPropertyName has not been set on scope.");
}
IList list2 = new List();
{
foreach (JsonSchemaModel currentSchema in CurrentSchemas)
{
if (currentSchema.Properties != null && currentSchema.Properties.TryGetValue(_currentScope.CurrentPropertyName, out var value))
{
list2.Add(value);
}
if (currentSchema.PatternProperties != null)
{
foreach (KeyValuePair patternProperty in currentSchema.PatternProperties)
{
if (Regex.IsMatch(_currentScope.CurrentPropertyName, patternProperty.Key))
{
list2.Add(patternProperty.Value);
}
}
}
if (list2.Count == 0 && currentSchema.AllowAdditionalProperties && currentSchema.AdditionalProperties != null)
{
list2.Add(currentSchema.AdditionalProperties);
}
}
return list2;
}
}
case JTokenType.Array:
{
IList list = new List();
{
foreach (JsonSchemaModel currentSchema2 in CurrentSchemas)
{
if (!currentSchema2.PositionalItemsValidation)
{
if (currentSchema2.Items != null && currentSchema2.Items.Count > 0)
{
list.Add(currentSchema2.Items[0]);
}
continue;
}
if (currentSchema2.Items != null && currentSchema2.Items.Count > 0 && currentSchema2.Items.Count > _currentScope.ArrayItemCount - 1)
{
list.Add(currentSchema2.Items[_currentScope.ArrayItemCount - 1]);
}
if (currentSchema2.AllowAdditionalItems && currentSchema2.AdditionalItems != null)
{
list.Add(currentSchema2.AdditionalItems);
}
}
return list;
}
}
case JTokenType.Constructor:
return EmptySchemaList;
default:
throw new ArgumentOutOfRangeException("TokenType", "Unexpected token type: {0}".FormatWith(CultureInfo.InvariantCulture, _currentScope.TokenType));
}
}
}
///
/// Gets or sets the schema.
///
/// The schema.
public JsonSchema Schema
{
get
{
return _schema;
}
set
{
if (TokenType != 0)
{
throw new InvalidOperationException("Cannot change schema while validating JSON.");
}
_schema = value;
_model = null;
}
}
///
/// Gets the used to construct this .
///
/// The specified in the constructor.
public JsonReader Reader => _reader;
int IJsonLineInfo.LineNumber => (_reader as IJsonLineInfo)?.LineNumber ?? 0;
int IJsonLineInfo.LinePosition => (_reader as IJsonLineInfo)?.LinePosition ?? 0;
///
/// Sets an event handler for receiving schema validation errors.
///
public event ValidationEventHandler ValidationEventHandler;
private void Push(SchemaScope scope)
{
_stack.Push(scope);
_currentScope = scope;
}
private SchemaScope Pop()
{
SchemaScope result = _stack.Pop();
_currentScope = ((_stack.Count != 0) ? _stack.Peek() : null);
return result;
}
private void RaiseError(string message, JsonSchemaModel schema)
{
string message2 = (((IJsonLineInfo)this).HasLineInfo() ? (message + " Line {0}, position {1}.".FormatWith(CultureInfo.InvariantCulture, ((IJsonLineInfo)this).LineNumber, ((IJsonLineInfo)this).LinePosition)) : message);
OnValidationEvent(new JsonSchemaException(message2, null, Path, ((IJsonLineInfo)this).LineNumber, ((IJsonLineInfo)this).LinePosition));
}
private void OnValidationEvent(JsonSchemaException exception)
{
ValidationEventHandler validationEventHandler = this.ValidationEventHandler;
if (validationEventHandler != null)
{
validationEventHandler(this, new ValidationEventArgs(exception));
return;
}
throw exception;
}
///
/// Initializes a new instance of the class that
/// validates the content returned from the given .
///
/// The to read from while validating.
public JsonValidatingReader(JsonReader reader)
{
ValidationUtils.ArgumentNotNull(reader, "reader");
_reader = reader;
_stack = new Stack();
}
private void ValidateNotDisallowed(JsonSchemaModel schema)
{
if (schema != null)
{
JsonSchemaType? currentNodeSchemaType = GetCurrentNodeSchemaType();
if (currentNodeSchemaType.HasValue && JsonSchemaGenerator.HasFlag(schema.Disallow, currentNodeSchemaType.GetValueOrDefault()))
{
RaiseError("Type {0} is disallowed.".FormatWith(CultureInfo.InvariantCulture, currentNodeSchemaType), schema);
}
}
}
private JsonSchemaType? GetCurrentNodeSchemaType()
{
return _reader.TokenType switch
{
JsonToken.StartObject => JsonSchemaType.Object,
JsonToken.StartArray => JsonSchemaType.Array,
JsonToken.Integer => JsonSchemaType.Integer,
JsonToken.Float => JsonSchemaType.Float,
JsonToken.String => JsonSchemaType.String,
JsonToken.Boolean => JsonSchemaType.Boolean,
JsonToken.Null => JsonSchemaType.Null,
_ => null,
};
}
///
/// Reads the next JSON token from the stream as a .
///
/// A .
public override int? ReadAsInt32()
{
int? result = _reader.ReadAsInt32();
ValidateCurrentToken();
return result;
}
///
/// Reads the next JSON token from the stream as a [].
///
///
/// A [] or a null reference if the next JSON token is null.
///
public override byte[] ReadAsBytes()
{
byte[] result = _reader.ReadAsBytes();
ValidateCurrentToken();
return result;
}
///
/// Reads the next JSON token from the stream as a .
///
/// A .
public override decimal? ReadAsDecimal()
{
decimal? result = _reader.ReadAsDecimal();
ValidateCurrentToken();
return result;
}
///
/// Reads the next JSON token from the stream as a .
///
/// A .
public override double? ReadAsDouble()
{
double? result = _reader.ReadAsDouble();
ValidateCurrentToken();
return result;
}
///
/// Reads the next JSON token from the stream as a .
///
/// A .
public override bool? ReadAsBoolean()
{
bool? result = _reader.ReadAsBoolean();
ValidateCurrentToken();
return result;
}
///
/// Reads the next JSON token from the stream as a .
///
/// A . This method will return null at the end of an array.
public override string ReadAsString()
{
string result = _reader.ReadAsString();
ValidateCurrentToken();
return result;
}
///
/// Reads the next JSON token from the stream as a .
///
/// A . This method will return null at the end of an array.
public override DateTime? ReadAsDateTime()
{
DateTime? result = _reader.ReadAsDateTime();
ValidateCurrentToken();
return result;
}
///
/// Reads the next JSON token from the stream as a .
///
/// A .
public override DateTimeOffset? ReadAsDateTimeOffset()
{
DateTimeOffset? result = _reader.ReadAsDateTimeOffset();
ValidateCurrentToken();
return result;
}
///
/// Reads the next JSON token from the stream.
///
///
/// true if the next token was read successfully; false if there are no more tokens to read.
///
public override bool Read()
{
if (!_reader.Read())
{
return false;
}
if (_reader.TokenType == JsonToken.Comment)
{
return true;
}
ValidateCurrentToken();
return true;
}
private void ValidateCurrentToken()
{
if (_model == null)
{
JsonSchemaModelBuilder jsonSchemaModelBuilder = new JsonSchemaModelBuilder();
_model = jsonSchemaModelBuilder.Build(_schema);
if (!JsonTokenUtils.IsStartToken(_reader.TokenType))
{
Push(new SchemaScope(JTokenType.None, CurrentMemberSchemas));
}
}
switch (_reader.TokenType)
{
case JsonToken.StartObject:
{
ProcessValue();
IList schemas2 = CurrentMemberSchemas.Where(ValidateObject).ToList();
Push(new SchemaScope(JTokenType.Object, schemas2));
WriteToken(CurrentSchemas);
break;
}
case JsonToken.StartArray:
{
ProcessValue();
IList schemas = CurrentMemberSchemas.Where(ValidateArray).ToList();
Push(new SchemaScope(JTokenType.Array, schemas));
WriteToken(CurrentSchemas);
break;
}
case JsonToken.StartConstructor:
ProcessValue();
Push(new SchemaScope(JTokenType.Constructor, null));
WriteToken(CurrentSchemas);
break;
case JsonToken.PropertyName:
WriteToken(CurrentSchemas);
foreach (JsonSchemaModel currentSchema in CurrentSchemas)
{
ValidatePropertyName(currentSchema);
}
break;
case JsonToken.Raw:
ProcessValue();
break;
case JsonToken.Integer:
ProcessValue();
WriteToken(CurrentMemberSchemas);
foreach (JsonSchemaModel currentMemberSchema in CurrentMemberSchemas)
{
ValidateInteger(currentMemberSchema);
}
break;
case JsonToken.Float:
ProcessValue();
WriteToken(CurrentMemberSchemas);
foreach (JsonSchemaModel currentMemberSchema2 in CurrentMemberSchemas)
{
ValidateFloat(currentMemberSchema2);
}
break;
case JsonToken.String:
ProcessValue();
WriteToken(CurrentMemberSchemas);
foreach (JsonSchemaModel currentMemberSchema3 in CurrentMemberSchemas)
{
ValidateString(currentMemberSchema3);
}
break;
case JsonToken.Boolean:
ProcessValue();
WriteToken(CurrentMemberSchemas);
foreach (JsonSchemaModel currentMemberSchema4 in CurrentMemberSchemas)
{
ValidateBoolean(currentMemberSchema4);
}
break;
case JsonToken.Null:
ProcessValue();
WriteToken(CurrentMemberSchemas);
foreach (JsonSchemaModel currentMemberSchema5 in CurrentMemberSchemas)
{
ValidateNull(currentMemberSchema5);
}
break;
case JsonToken.EndObject:
WriteToken(CurrentSchemas);
foreach (JsonSchemaModel currentSchema2 in CurrentSchemas)
{
ValidateEndObject(currentSchema2);
}
Pop();
break;
case JsonToken.EndArray:
WriteToken(CurrentSchemas);
foreach (JsonSchemaModel currentSchema3 in CurrentSchemas)
{
ValidateEndArray(currentSchema3);
}
Pop();
break;
case JsonToken.EndConstructor:
WriteToken(CurrentSchemas);
Pop();
break;
case JsonToken.Undefined:
case JsonToken.Date:
case JsonToken.Bytes:
WriteToken(CurrentMemberSchemas);
break;
default:
throw new ArgumentOutOfRangeException();
case JsonToken.None:
break;
}
}
private void WriteToken(IList schemas)
{
foreach (SchemaScope item in _stack)
{
bool flag = item.TokenType == JTokenType.Array && item.IsUniqueArray && item.ArrayItemCount > 0;
if (!flag && !schemas.Any((JsonSchemaModel s) => s.Enum != null))
{
continue;
}
if (item.CurrentItemWriter == null)
{
if (JsonTokenUtils.IsEndToken(_reader.TokenType))
{
continue;
}
item.CurrentItemWriter = new JTokenWriter();
}
item.CurrentItemWriter.WriteToken(_reader, writeChildren: false);
if (item.CurrentItemWriter.Top != 0 || _reader.TokenType == JsonToken.PropertyName)
{
continue;
}
JToken token = item.CurrentItemWriter.Token;
item.CurrentItemWriter = null;
if (flag)
{
if (item.UniqueArrayItems.Contains(token, JToken.EqualityComparer))
{
RaiseError("Non-unique array item at index {0}.".FormatWith(CultureInfo.InvariantCulture, item.ArrayItemCount - 1), item.Schemas.First((JsonSchemaModel s) => s.UniqueItems));
}
item.UniqueArrayItems.Add(token);
}
else
{
if (!schemas.Any((JsonSchemaModel s) => s.Enum != null))
{
continue;
}
foreach (JsonSchemaModel schema in schemas)
{
if (schema.Enum != null && !schema.Enum.ContainsValue(token, JToken.EqualityComparer))
{
StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
token.WriteTo(new JsonTextWriter(stringWriter));
RaiseError("Value {0} is not defined in enum.".FormatWith(CultureInfo.InvariantCulture, stringWriter.ToString()), schema);
}
}
}
}
}
private void ValidateEndObject(JsonSchemaModel schema)
{
if (schema == null)
{
return;
}
Dictionary requiredProperties = _currentScope.RequiredProperties;
if (requiredProperties != null)
{
List list = (from kv in requiredProperties
where !kv.Value
select kv.Key).ToList();
if (list.Count > 0)
{
RaiseError("Required properties are missing from object: {0}.".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", list.ToArray())), schema);
}
}
}
private void ValidateEndArray(JsonSchemaModel schema)
{
if (schema != null)
{
int arrayItemCount = _currentScope.ArrayItemCount;
if (schema.MaximumItems.HasValue && arrayItemCount > schema.MaximumItems)
{
RaiseError("Array item count {0} exceeds maximum count of {1}.".FormatWith(CultureInfo.InvariantCulture, arrayItemCount, schema.MaximumItems), schema);
}
if (schema.MinimumItems.HasValue && arrayItemCount < schema.MinimumItems)
{
RaiseError("Array item count {0} is less than minimum count of {1}.".FormatWith(CultureInfo.InvariantCulture, arrayItemCount, schema.MinimumItems), schema);
}
}
}
private void ValidateNull(JsonSchemaModel schema)
{
if (schema != null && TestType(schema, JsonSchemaType.Null))
{
ValidateNotDisallowed(schema);
}
}
private void ValidateBoolean(JsonSchemaModel schema)
{
if (schema != null && TestType(schema, JsonSchemaType.Boolean))
{
ValidateNotDisallowed(schema);
}
}
private void ValidateString(JsonSchemaModel schema)
{
if (schema == null || !TestType(schema, JsonSchemaType.String))
{
return;
}
ValidateNotDisallowed(schema);
string text = _reader.Value.ToString();
if (schema.MaximumLength.HasValue && text.Length > schema.MaximumLength)
{
RaiseError("String '{0}' exceeds maximum length of {1}.".FormatWith(CultureInfo.InvariantCulture, text, schema.MaximumLength), schema);
}
if (schema.MinimumLength.HasValue && text.Length < schema.MinimumLength)
{
RaiseError("String '{0}' is less than minimum length of {1}.".FormatWith(CultureInfo.InvariantCulture, text, schema.MinimumLength), schema);
}
if (schema.Patterns == null)
{
return;
}
foreach (string pattern in schema.Patterns)
{
if (!Regex.IsMatch(text, pattern))
{
RaiseError("String '{0}' does not match regex pattern '{1}'.".FormatWith(CultureInfo.InvariantCulture, text, pattern), schema);
}
}
}
private void ValidateInteger(JsonSchemaModel schema)
{
if (schema == null || !TestType(schema, JsonSchemaType.Integer))
{
return;
}
ValidateNotDisallowed(schema);
object value = _reader.Value;
if (schema.Maximum.HasValue)
{
if (JValue.Compare(JTokenType.Integer, value, schema.Maximum) > 0)
{
RaiseError("Integer {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Maximum), schema);
}
if (schema.ExclusiveMaximum && JValue.Compare(JTokenType.Integer, value, schema.Maximum) == 0)
{
RaiseError("Integer {0} equals maximum value of {1} and exclusive maximum is true.".FormatWith(CultureInfo.InvariantCulture, value, schema.Maximum), schema);
}
}
if (schema.Minimum.HasValue)
{
if (JValue.Compare(JTokenType.Integer, value, schema.Minimum) < 0)
{
RaiseError("Integer {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Minimum), schema);
}
if (schema.ExclusiveMinimum && JValue.Compare(JTokenType.Integer, value, schema.Minimum) == 0)
{
RaiseError("Integer {0} equals minimum value of {1} and exclusive minimum is true.".FormatWith(CultureInfo.InvariantCulture, value, schema.Minimum), schema);
}
}
if (schema.DivisibleBy.HasValue)
{
bool flag;
if (value is BigInteger)
{
BigInteger bigInteger = (BigInteger)value;
flag = (Math.Abs(schema.DivisibleBy.Value - Math.Truncate(schema.DivisibleBy.Value)).Equals(0.0) ? (bigInteger % new BigInteger(schema.DivisibleBy.Value) != 0L) : (bigInteger != 0L));
}
else
{
flag = !IsZero((double)Convert.ToInt64(value, CultureInfo.InvariantCulture) % schema.DivisibleBy.GetValueOrDefault());
}
if (flag)
{
RaiseError("Integer {0} is not evenly divisible by {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.DivisibleBy), schema);
}
}
}
private void ProcessValue()
{
if (_currentScope == null || _currentScope.TokenType != JTokenType.Array)
{
return;
}
_currentScope.ArrayItemCount++;
foreach (JsonSchemaModel currentSchema in CurrentSchemas)
{
if (currentSchema != null && currentSchema.PositionalItemsValidation && !currentSchema.AllowAdditionalItems && (currentSchema.Items == null || _currentScope.ArrayItemCount - 1 >= currentSchema.Items.Count))
{
RaiseError("Index {0} has not been defined and the schema does not allow additional items.".FormatWith(CultureInfo.InvariantCulture, _currentScope.ArrayItemCount), currentSchema);
}
}
}
private void ValidateFloat(JsonSchemaModel schema)
{
if (schema == null || !TestType(schema, JsonSchemaType.Float))
{
return;
}
ValidateNotDisallowed(schema);
double num = Convert.ToDouble(_reader.Value, CultureInfo.InvariantCulture);
if (schema.Maximum.HasValue)
{
if (num > schema.Maximum)
{
RaiseError("Float {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(num), schema.Maximum), schema);
}
if (schema.ExclusiveMaximum && num == schema.Maximum)
{
RaiseError("Float {0} equals maximum value of {1} and exclusive maximum is true.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(num), schema.Maximum), schema);
}
}
if (schema.Minimum.HasValue)
{
if (num < schema.Minimum)
{
RaiseError("Float {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(num), schema.Minimum), schema);
}
if (schema.ExclusiveMinimum && num == schema.Minimum)
{
RaiseError("Float {0} equals minimum value of {1} and exclusive minimum is true.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(num), schema.Minimum), schema);
}
}
if (schema.DivisibleBy.HasValue && !IsZero(FloatingPointRemainder(num, schema.DivisibleBy.GetValueOrDefault())))
{
RaiseError("Float {0} is not evenly divisible by {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(num), schema.DivisibleBy), schema);
}
}
private static double FloatingPointRemainder(double dividend, double divisor)
{
return dividend - Math.Floor(dividend / divisor) * divisor;
}
private static bool IsZero(double value)
{
return Math.Abs(value) < 4.4408920985006262E-15;
}
private void ValidatePropertyName(JsonSchemaModel schema)
{
if (schema != null)
{
string text = Convert.ToString(_reader.Value, CultureInfo.InvariantCulture);
if (_currentScope.RequiredProperties.ContainsKey(text))
{
_currentScope.RequiredProperties[text] = true;
}
if (!schema.AllowAdditionalProperties && !IsPropertyDefinied(schema, text))
{
RaiseError("Property '{0}' has not been defined and the schema does not allow additional properties.".FormatWith(CultureInfo.InvariantCulture, text), schema);
}
_currentScope.CurrentPropertyName = text;
}
}
private bool IsPropertyDefinied(JsonSchemaModel schema, string propertyName)
{
if (schema.Properties != null && schema.Properties.ContainsKey(propertyName))
{
return true;
}
if (schema.PatternProperties != null)
{
foreach (string key in schema.PatternProperties.Keys)
{
if (Regex.IsMatch(propertyName, key))
{
return true;
}
}
}
return false;
}
private bool ValidateArray(JsonSchemaModel schema)
{
if (schema == null)
{
return true;
}
return TestType(schema, JsonSchemaType.Array);
}
private bool ValidateObject(JsonSchemaModel schema)
{
if (schema == null)
{
return true;
}
return TestType(schema, JsonSchemaType.Object);
}
private bool TestType(JsonSchemaModel currentSchema, JsonSchemaType currentType)
{
if (!JsonSchemaGenerator.HasFlag(currentSchema.Type, currentType))
{
RaiseError("Invalid type. Expected {0} but got {1}.".FormatWith(CultureInfo.InvariantCulture, currentSchema.Type, currentType), currentSchema);
return false;
}
return true;
}
bool IJsonLineInfo.HasLineInfo()
{
return (_reader as IJsonLineInfo)?.HasLineInfo() ?? false;
}
}
}