private void CompressData(Subschema schema) { object[] uncompressedData = (object[])schema.data; object data = null; long storedBits = (long)(schema.Flags & SchemaFlags.StoredProperties); int bitCount = BitCount(storedBits); if (bitCount > 1) { int index = 0; object[] compressedData = new object[bitCount]; while (storedBits != 0) { int lowestBit = IndexOfLowestBit(storedBits); compressedData[index++] = uncompressedData[lowestBit]; storedBits -= 1L << lowestBit; } data = compressedData; } else if (bitCount == 1) { data = uncompressedData[IndexOfLowestBit(storedBits)]; } schema.data = data; schema.Flags &= ~SchemaFlags.Uncompressed; }
private bool Validate(Subschema schema, object instance, Keyword keyword, string prop1, string prop2) { SchemaPointer.Push(keyword); if (prop1 != null) { SchemaPointer.Push(prop1); } if (prop2 != null) { InstancePointer.Push(prop2); } bool result = Validate(schema, instance); SchemaPointer.Pop(); if (prop1 != null) { SchemaPointer.Pop(); } if (prop2 != null) { InstancePointer.Pop(); } return(result); }
private bool HandleRequired(Subschema schema, KeyValuePair <string, object>[] map, string[] required, Keyword keyword, string prop) { bool result = true; SchemaPointer.Push(keyword); if (prop != null) { SchemaPointer.Push(prop); } for (int index = 0; index < required.Length; index++) { string s = required[index]; if (s == null || map.GetPropertyIndex(s) < 0) { SchemaPointer.Push(index); ReportError(Keyword.None, schema, actual: prop, expected: s, instance: map); SchemaPointer.Pop(); result = false; if (!IsRecordingErrors) { break; } } } if (prop != null) { SchemaPointer.Pop(); } SchemaPointer.Pop(); return(result); }
private void AddId(string uri, Subschema schema) { if (ids == null) { ids = new Dictionary <string, Subschema>(); } ids[uri] = schema; }
private bool Validate(Subschema schema, object instance, int index) { SchemaPointer.Push(index); bool result = Validate(schema, instance); SchemaPointer.Pop(); return(result); }
private bool Validate(Subschema schema, object instance, Keyword keyword) { SchemaPointer.Push(keyword); bool result = Validate(schema, instance); SchemaPointer.Pop(); return(result); }
private bool ValidateNumber(Subschema schema, double value) { bool finalResult = true; for (var mask = schema.Flags & SchemaFlags.NumberProperties; mask != 0; mask = (SchemaFlags)RemoveLowestBit((long)mask)) { Keyword keyword = (Keyword)IndexOfLowestBit((long)mask); bool? result = true; switch (keyword) { case Keyword.Minimum: result = value >= schema.Minimum; break; case Keyword.Maximum: result = value <= schema.Maximum; break; case Keyword.ExclusiveMaximum: result = value < schema.ExclusiveMaximum; break; case Keyword.ExclusiveMinimum: result = value > schema.ExclusiveMinimum; break; case Keyword.MultipleOf: double m = (double)schema.MultipleOf; double r = value % m; if (r != 0) { r = Math.Abs(r); r = Math.Min(m - r, r); result = r < 1e-14 * m; } break; } if (result == false) { finalResult = false; if (ReportError(keyword, schema, value)) { return(false); } } } return(finalResult); }
internal bool ReportError(ErrorType errorType, Subschema schema = null, object actual = null, object expected = null, object instance = null) { var result = ReportError((Keyword)errorType, schema, actual, expected, instance); if (errorType == ErrorType.TimeLimit) { CancelValidation(); } return(result); }
/// <summary> /// Pushes an error onto the errors list with the given parameters /// </summary> /// <param name="keyword"></param> /// <param name="key"></param> /// <param name="actual"></param> /// <param name="expected"></param> /// <param name="instancePath"></param> /// <param name="schemaPath"></param> internal bool ReportError(Keyword keyword, Subschema schema, object actual = null, object expected = null, object instance = null) { // Errors being suppressed don't directly affect success result if (suppressionLevel > 0 || errorAction == null) { return(true); } if (schema != null) { if (expected == null) { expected = schema.GetData(keyword); } } validationArgs.Actual = MPJson.From(actual); validationArgs.Instance = MPJson.From(instance ?? actual); validationArgs.Expected = expected; validationArgs.Schema = schema; validationArgs.ValidationError = null; if (keyword >= 0) { validationArgs.ErrorType = (ErrorType)keyword; SchemaPointer.Push(keyword); } else { validationArgs.ErrorType = (ErrorType)SchemaPointer.Keyword; } errorAction(this, validationArgs); if (keyword >= 0) { SchemaPointer.Pop(); } if (AbortOnError) { errorAction = null; } return(errorAction == null); }
private bool Validate(Subschema schema, object instance, int index, int instanceIndex) { if (index >= 0) { SchemaPointer.Push(index); } InstancePointer.Push(instanceIndex); bool result = Validate(schema, instance); InstancePointer.Pop(); if (index >= 0) { SchemaPointer.Pop(); } return(result); }
public bool Validate(Subschema root, MPJson json, EventHandler <ValidationArgs> eventHandler = null) { if (root == null) { return(false); } object jobject = json.Value; SchemaPointer.Clear(); InstancePointer.Clear(); suppressionLevel = 0; errorAction = eventHandler; timeToLive = MaxTimeToLive; Success = Validate(root, jobject); return(Success); }
private Subschema[] ReadSchemaList(object v, MPSchema doc) { object[] array = v as object[]; if (array == null) { return(null); } var list = new Subschema[array.Length]; for (int i = 0; i < array.Length; i++) { Subschema child = From(array[i], doc); if (child == null) { return(null); } list[i] = child; } return(list); }
public SchemaBuilder(MPSchema doc, MPJson json) { this.Document = doc; this.Json = json; // Find references GatherIdsAndReferences(json.Value); // Build schemas Root = From(json.Value, doc); string rootReference = doc.ConvertReference(""); References.Remove(rootReference); Definitions[rootReference] = new SchemaReference(rootReference, Root); foreach (string r in References) { if (!Ids.TryGetValue(r, out object value)) { value = JsonPointer.Find(json, r); } Definitions[r] = new SchemaReference(r, value != null ? From(value, doc) : null) { Id = Definitions.Count }; } // Fix up references foreach (var reference in Definitions.Values) { if (reference.Schema != null) { ReplaceReferences(reference.Schema); } } // Compression }
private void ReplaceReferences(Subschema schema) { var origRef = schema.Ref; if (origRef != null && !origRef.Resolved) { if (Definitions.TryGetValue(origRef.Uri, out SchemaReference newRef) && newRef.Schema != schema) { schema.Ref = newRef; // We will init this anyway, if any references still exist in memory origRef.Schema = newRef.Schema; origRef.Version = newRef.Version; } origRef.Resolved = true; } foreach (var subschema in schema.GetChildSchemas()) { ReplaceReferences(subschema); } }
private void AssignMetadata(Subschema schema, List <Pair> metadata) { metadata.Sort((a, b) => a.Key.CompareTo(b.Key)); schema.Metadata = metadata.ToArray(); }
/// <summary> /// /// </summary> /// <param name="map"></param> /// <param name="validator"></param> /// <param name="properties"></param> /// <param name="patternProperties"></param> /// <param name="additionalProperties"></param> /// <param name="recordErrors"></param> /// <returns></returns> private bool ValidateProperties( KeyValuePair <string, object>[] map, KeyValuePair <string, Subschema>[] properties, KeyValuePair <SchemaRegex, Subschema>[] patternProperties, Subschema additionalProperties) { if (properties == null) { properties = Array.Empty <KeyValuePair <string, Subschema> >(); } bool result = true; for (int i = 0, iprop = 0; i < map.Length; i++) { string prop = map[i].Key; object value = map[i].Value; // Match property int cmp = 1; bool found = false; for (; iprop < properties.Length; iprop++) { cmp = string.CompareOrdinal(properties[iprop].Key, prop); if (cmp >= 0) { break; } } if (cmp == 0) { found = true; if (!Validate(properties[iprop].Value, value, Keyword.Properties, prop, prop)) { result = false; if (!IsRecordingErrors) { return(false); } } } // Match patternProperty if (patternProperties != null) { foreach (var pp in patternProperties) { if (pp.Key.Matches(prop) == SchemaRegexSuccess.Success) { found = true; if (!Validate(pp.Value, value, Keyword.PatternProperties, pp.Key.Pattern, prop)) { result = false; if (!IsRecordingErrors) { return(false); } } } } } // Match additionalProperties if (found == false && additionalProperties != null) { if (!Validate(additionalProperties, value, Keyword.AdditionalProperties, null, prop)) { result = false; if (!IsRecordingErrors) { return(false); } } } } return(result); }
private bool ValidateObject(Subschema schema, KeyValuePair <string, object>[] map) { bool finalResult = true; bool propertyCheck = false; for (var mask = schema.Flags & SchemaFlags.ObjectProperties; mask != 0; mask = (SchemaFlags)RemoveLowestBit((long)mask)) { Keyword keyword = (Keyword)IndexOfLowestBit((long)mask); Subschema subschema; bool result = true; switch (keyword) { case Keyword.DependentSchemas: foreach (var kv in schema.DependentSchemas) { int index = map.GetPropertyIndex(kv.Key); if (index < 0) { continue; } if (!Validate(kv.Value, map, Keyword.DependentSchemas, kv.Key, null)) { finalResult = false; if (!IsRecordingErrors) { return(false); } } } break; case Keyword.DependentRequired: foreach (var kv in schema.DependentRequired) { int index = map.GetPropertyIndex(kv.Key); if (index >= 0 && !HandleRequired(schema, map, kv.Value, Keyword.DependentRequired, kv.Key)) { finalResult = false; if (!IsRecordingErrors) { return(false); } } } break; case Keyword.MaxProperties: result = map.Length <= schema.MaxProperties; break; case Keyword.MinProperties: result = map.Length >= schema.MinProperties; break; case Keyword.PropertyNames: subschema = schema.PropertyNames; for (int i = 0; i < map.Length; i++) { var kv = map[i]; if (!Validate(subschema, kv.Key, Keyword.PropertyNames, null, kv.Key)) { finalResult = false; if (!IsRecordingErrors) { return(false); } } } break; case Keyword.Required: if (!HandleRequired(schema, map, schema.Required, Keyword.Required, null)) { finalResult = false; if (!IsRecordingErrors) { return(false); } } break; case Keyword.AdditionalProperties: case Keyword.PatternProperties: case Keyword.Properties: propertyCheck = true; break; } if (!result) { finalResult = false; if (ReportError(keyword, schema, map)) { return(false); } } } if (propertyCheck && !ValidateProperties(map, schema.Properties, schema.PatternProperties, schema.AdditionalProperties)) { finalResult = false; } return(finalResult); }
private bool ValidateGeneric(Subschema schema, object instance) { bool finalResult = true; for (SchemaFlags mask = schema.Flags & (SchemaFlags.GenericProperties & SchemaFlags.AllProperties); mask != 0; mask = (SchemaFlags)RemoveLowestBit((long)mask)) { Keyword keyword = (Keyword)IndexOfLowestBit((long)mask); bool? result = null; Subschema[] schemaArray; int index; switch (keyword) { case Keyword.If: int level = TurnOffErrors(); result = Validate(schema.If, instance, Keyword.If); RestoreSuppressionLevel(level); result = result == true ? Validate(schema.Then, instance, Keyword.Then) : Validate(schema.Else, instance, Keyword.Else); break; case Keyword.Not: level = TurnOffErrors(); result = !Validate(schema.Not, instance, Keyword.Not); RestoreSuppressionLevel(level); break; case Keyword.AllOf: result = true; schemaArray = schema.AllOf; SchemaPointer.Push(keyword); for (index = 0; index < schemaArray.Length; index++) { if (!Validate(schemaArray[index], instance, index)) { finalResult = false; if (!IsRecordingErrors) { break; } } } SchemaPointer.Pop(); break; case Keyword.AnyOf: result = false; level = TurnOffErrors(); schemaArray = schema.AnyOf; SchemaPointer.Push(keyword); for (index = 0; index < schemaArray.Length; index++) { if (Validate(schemaArray[index], instance, index)) { result = true; break; } } SchemaPointer.Pop(); RestoreSuppressionLevel(level); break; case Keyword.OneOf: result = false; level = TurnOffErrors(); schemaArray = schema.OneOf; SchemaPointer.Push(keyword); for (index = 0; index < schemaArray.Length; index++) { if (Validate(schemaArray[index], instance, index)) { result = !result; if (result == false) { break; } } } SchemaPointer.Pop(); RestoreSuppressionLevel(level); break; case Keyword.Enum: result = false; // TODO: Provide support for type coercion foreach (object v in (object[])schema.Enum.Value) { if (MPJson.Matches(v, instance)) { result = true; break; } } break; case Keyword.Const: // TODO: Provide support for string to value coercion result = MPJson.Matches(schema.Const.Value, instance); break; case Keyword._Ref: var r = schema.Ref; if (r.Version != 0) { var draft = new MPSchema(MPJson.From(instance), r.Version); result = draft.IsValid; break; // This was checked on creation } var rSchema = r.Schema; result = rSchema != null && ReferenceUsageIsControlled(); if (result == true && !Validate(rSchema, instance, Keyword._Ref)) { finalResult = false; } break; case Keyword.Metadata: break; } if (result == false) { finalResult = false; if (ReportError(keyword, schema, instance)) { return(false); } } } return(finalResult); }
private bool ValidateType(Subschema schema, object value) { var type = MPJson.GetType(value); switch (type) { case JsonType.Object: if ((schema.Flags & SchemaFlags.TypeObject) == 0) { break; } return(ValidateObject(schema, (KeyValuePair <string, object>[])value)); case JsonType.Array: if ((schema.Flags & SchemaFlags.TypeArray) == 0) { break; } return(ValidateArray(schema, (object[])value)); case JsonType.Number: double d = Convert.ToDouble(value); if ((schema.Flags & SchemaFlags.TypeNumber) == 0 && ((schema.Flags & SchemaFlags.TypeInteger) == 0 || d != Math.Floor(d))) { break; } return(ValidateNumber(schema, d)); case JsonType.String: if ((schema.Flags & SchemaFlags.TypeString) != 0) { return(ValidateString(schema, (string)value)); } if (this.CoerceStringsToValues) { var str = (string)value; if ((schema.Flags & (SchemaFlags.TypeNumber | SchemaFlags.TypeInteger)) != 0 && double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out d) && (0 != (schema.Flags & SchemaFlags.TypeNumber) || d == Math.Floor(d))) { return(ValidateNumber(schema, d)); } if ((schema.Flags & SchemaFlags.TypeBoolean) != 0 && string.Equals(str, str.Length == 4 ? JsonParser.TrueKeyword : JsonParser.FalseKeyword, StringComparison.OrdinalIgnoreCase)) { return(true); } } break; case JsonType.Boolean: if ((schema.Flags & SchemaFlags.TypeBoolean) == 0) { break; } return(true); case JsonType.Null: if ((schema.Flags & SchemaFlags.TypeNull) == 0) { break; } return(true); } if (!IsRecordingErrors) { return(false); } return((schema.Flags & SchemaFlags.TypeAll) != 0 ? ReportError( ErrorType.Type, schema, actual: KeywordUtils.GetTypeText(type), expected: schema.GetValidTypes(), instance: value) : ReportError(ErrorType.None, actual: value)); }
/// <summary> /// Create a resolved schema reference /// </summary> /// <param name="s"></param> /// <param name="schema"></param> public SchemaReference(string s, Subschema schema) : this(s) { this.Schema = schema; this.Resolved = true; }
private bool ValidateArray(Subschema schema, object[] array) { bool finalResult = true; for (var mask = schema.Flags & (SchemaFlags.ArrayProperties & SchemaFlags.AllProperties); mask != 0; mask = (SchemaFlags)RemoveLowestBit((long)mask)) { Keyword keyword = (Keyword)IndexOfLowestBit((long)mask); Subschema subschema; Subschema[] schemaArray; bool result = true; bool respond = true; switch (keyword) { case Keyword.AdditionalItems: // https://json-schema.org/draft/2019-09/json-schema-core.html#rfc.section.8.2.4 // AdditionalItems is ignored if Items is not present subschema = schema.AdditionalItems; schemaArray = schema.Items as Subschema[]; respond = false; if (schemaArray != null && schemaArray.Length < array.Length) { SchemaPointer.Push(Keyword.AdditionalItems); for (int i = schemaArray.Length; i < array.Length; i++) { result &= Validate(subschema, array[i], -1, i); if (!result && !IsRecordingErrors) { break; } } SchemaPointer.Pop(); } break; case Keyword.Contains: subschema = schema.Contains; double minContains = schema.MinContains; double maxContains = schema.MaxContains; result = minContains == 0; int contains = 0; SchemaPointer.Push(Keyword.Contains); TurnOffErrors(); for (int i = 0; i < array.Length; i++) { bool elementResult = Validate(subschema, array[i], -1, i); if (elementResult) { contains++; if (contains >= minContains) { result = true; if (contains + (array.Length - i - 1) <= maxContains) { break; } } } } TurnOnErrors(); SchemaPointer.Pop(); if (contains > maxContains) { result = false; } break; case Keyword.Items: object items = schema.Items; SchemaPointer.Push(Keyword.Items); respond = false; if ((subschema = items as Subschema) != null) { for (int i = 0; i < array.Length; i++) { result &= Validate(subschema, array[i], -1, i); if (!result && !IsRecordingErrors) { break; } } } else { schemaArray = (Subschema[])items; result = true; for (int i = Math.Min(array.Length, schemaArray.Length) - 1; i >= 0; i--) { result &= Validate(schemaArray[i], array[i], i, i); if (!result && !IsRecordingErrors) { break; } } } SchemaPointer.Pop(); break; case Keyword.MaxItems: result = array.Length <= schema.MaxItems; break; case Keyword.MinItems: result = array.Length >= schema.MinItems; break; case Keyword.UniqueItems: var uniques = new HashSet <MPJson>(); foreach (object v in array) { if (!uniques.Add(MPJson.From(v))) { result = false; break; } } break; } if (!result) { finalResult = false; if (respond ? ReportError(keyword, schema, array) : !IsRecordingErrors) { return(false); } } } return(finalResult); }
/// <summary> /// Builds a schema document from a JsonLite object tree /// </summary> /// <param name="schema"></param> /// <param name="doc"></param> /// <returns></returns> public Subschema From(object json, MPSchema doc) { var map = json as KeyValuePair <string, object>[]; if (map == null || map.Length == 0) { if (map != null) { return(SchemaConstants.Everything); } if (json is bool b) { return(b ? SchemaConstants.Everything : SchemaConstants.Nothing); } return(null); } var subschema = new Subschema { data = new object[(int)Keyword.MAX_STORED], Flags = SchemaFlags.TypeAll | SchemaFlags.Uncompressed }; bool exclusiveMinimum = false; bool exclusiveMaximum = false; bool isNothing = false; List <Pair> metadata = null; foreach (var kv in map) { var k = KeywordUtils.ParseKeyword(kv.Key); object v = kv.Value; Subschema child; Subschema[] list; string name; object[] array; string[] stringList; double d; switch (k) { case Keyword.AllOf: list = ReadSchemaList(v, doc); if (list == null || list.Length < 1) { return(null); } subschema.AllOf = list; break; case Keyword.AnyOf: list = ReadSchemaList(v, doc); if (list == null || list.Length < 1) { return(null); } subschema.AnyOf = list; break; case Keyword.OneOf: list = ReadSchemaList(v, doc); if (list == null || list.Length < 1) { return(null); } subschema.OneOf = list; break; case Keyword.Const: if (!doc.LimitVersion(SchemaVersion.Draft6, true)) { return(null); } subschema.Const = MPJson.From(v); break; case Keyword.Enum: array = v as object[]; if (array == null || array.Length < 1) { return(null); } subschema.Enum = MPJson.From(array); break; case Keyword.Not: child = From(v, doc); if (child == null) { return(null); } subschema.Not = child; if (map.Length == 1) { if (child.Type == TypeFlags.None) { return(SchemaConstants.Everything); } if (child == SchemaConstants.Everything) { return(SchemaConstants.Nothing); } } break; case Keyword.Type: var flags = subschema.Flags & ~SchemaFlags.TypeAll; if (v is string) { flags = ToTypeFlag((string)v); if (flags == 0) { return(null); } } else { stringList = ReadStringList(v); if (stringList == null) { return(null); } foreach (string type in stringList) { var flag = ToTypeFlag(type); if (flag == 0) { return(null); } flags |= flag; } } subschema.Flags = (subschema.Flags & ~SchemaFlags.TypeAll) | flags; break; case Keyword.If: if (!doc.LimitVersion(SchemaVersion.Draft7, true)) { return(null); } child = From(v, doc); if (child == null) { return(null); } subschema.If = child; break; case Keyword.Then: if (!doc.LimitVersion(SchemaVersion.Draft7, true)) { return(null); } child = From(v, doc); if (child == null) { return(null); } subschema.Then = child; break; case Keyword.Else: if (!doc.LimitVersion(SchemaVersion.Draft7, true)) { return(null); } child = From(v, doc); if (child == null) { return(null); } subschema.Else = child; break; // Number attributes case Keyword.ExclusiveMaximum: if (v is double && doc.LimitVersion(SchemaVersion.Draft6, true)) { subschema.ExclusiveMaximum = (double)v; } else if (v is bool && doc.LimitVersion(SchemaVersion.Draft4, false)) { exclusiveMaximum = (bool)v; } else { return(null); } break; case Keyword.ExclusiveMinimum: if (v is double && doc.LimitVersion(SchemaVersion.Draft6, true)) { subschema.ExclusiveMinimum = (double)v; } else if (v is bool && doc.LimitVersion(SchemaVersion.Draft4, false)) { exclusiveMinimum = (bool)v; } else { return(null); } break; case Keyword.Maximum: if (!(v is double)) { return(null); } if (exclusiveMaximum) { subschema.ExclusiveMaximum = (double)v; } else { subschema.Maximum = (double)v; } break; case Keyword.Minimum: if (!(v is double)) { return(null); } if (exclusiveMinimum) { subschema.ExclusiveMinimum = (double)v; } else { subschema.Minimum = (double)v; } break; case Keyword.MultipleOf: if (!(v is double) || (d = (double)v) <= 0) { return(null); } subschema.MultipleOf = d; break; // String attributes case Keyword.Format: name = v as string; if (name == null) { return(null); } subschema.Format = name; break; case Keyword.MaxLength: if (!IsNonnegativeInteger(v)) { return(null); } subschema.MaxLength = (double)v; break; case Keyword.MinLength: if (!IsNonnegativeInteger(v)) { return(null); } subschema.MinLength = (double)v; break; case Keyword.Pattern: name = v as string; var regex = SchemaRegexCache.Lookup(name); if (regex == null) { return(null); } subschema.Pattern = regex; break; // Object attributes case Keyword.AdditionalProperties: child = From(v, doc); if (child == null) { return(null); } subschema.AdditionalProperties = child; break; case Keyword.Dependencies: KeyValuePair <string, string[]>[] depRequired; KeyValuePair <string, Subschema>[] schemas; if (!ReadDependencies(v, doc, out schemas, out depRequired)) { return(null); } if (depRequired != null) { subschema.DependentRequired = depRequired; } if (schemas != null) { subschema.DependentSchemas = schemas; } break; case Keyword.DependentRequired: if (!doc.LimitVersion(SchemaVersion.Draft201909, true)) { return(null); } if (!ReadDependencies(v, doc, out schemas, out depRequired)) { return(null); } if (schemas != null) { return(null); } subschema.DependentRequired = depRequired; break; case Keyword.DependentSchemas: if (!doc.LimitVersion(SchemaVersion.Draft201909, true)) { return(null); } schemas = ReadPropertySchemas(v, doc); if (schemas == null) { return(null); } subschema.DependentSchemas = schemas; break; case Keyword.PatternProperties: var patternSchemas = ReadPatternSchemas(v, doc); if (patternSchemas == null) { return(null); } subschema.PatternProperties = patternSchemas; break; case Keyword.Properties: schemas = ReadPropertySchemas(v, doc); if (schemas == null) { return(null); } subschema.Properties = schemas; break; case Keyword.MaxProperties: if (!IsNonnegativeInteger(v)) { return(null); } subschema.MaxProperties = (double)v; break; case Keyword.MinProperties: if (!IsNonnegativeInteger(v)) { return(null); } subschema.MinProperties = (double)v; break; case Keyword.PropertyNames: if (!doc.LimitVersion(SchemaVersion.Draft6, true)) { return(null); } child = From(v, doc); if (child == null) { return(null); } subschema.PropertyNames = child; break; case Keyword.Required: stringList = ReadStringList(v); if (stringList == null) { return(null); } subschema.Required = stringList; break; // Array attributes case Keyword.AdditionalItems: child = From(v, doc); if (child == null) { return(null); } subschema.AdditionalItems = child; break; case Keyword.Contains: if (!doc.LimitVersion(SchemaVersion.Draft6, true)) { return(null); } child = From(v, doc); if (child == null) { return(null); } subschema.Contains = child; break; case Keyword.Items: object result = v is object[]? ReadSchemaList(v, doc) : (object)From(v, doc); if (result == null) { return(null); } subschema.Items = result; break; case Keyword.MaxContains: if (!IsNonnegativeInteger(v)) { return(null); } subschema.MaxContains = (double)v; break; case Keyword.MinContains: if (!IsNonnegativeInteger(v)) { return(null); } subschema.MinContains = (double)v; break; case Keyword.MaxItems: if (!IsNonnegativeInteger(v)) { return(null); } subschema.MaxItems = (double)v; break; case Keyword.MinItems: if (!IsNonnegativeInteger(v)) { return(null); } subschema.MinItems = (double)v; break; case Keyword.UniqueItems: if (!(v is bool)) { return(null); } if ((bool)v) { subschema.UniqueItems = true; } break; // MORE case Keyword._Ref: name = v as string; if (name == null) { return(null); } string reference = doc.ConvertReference(name); var r = subschema.Ref = new SchemaReference(reference); break; case Keyword.Id: if (!doc.LimitVersion(SchemaVersion.Draft4, false)) { return(null); } goto DoId; case Keyword._Id: if (!doc.LimitVersion(SchemaVersion.Draft6, true)) { return(null); } DoId: name = v as string; if (name == null) { return(null); } AddMetadata(ref metadata, kv.Key, v); break; case Keyword.ContentSchema: case Keyword.Default: AddMetadata(ref metadata, kv.Key, v); break; case Keyword.Title: case Keyword.Description: case Keyword._Schema: name = v as string; if (name == null) { return(null); } AddMetadata(ref metadata, kv.Key, v); break; case Keyword.Examples: if (!(v is object[])) { return(null); } AddMetadata(ref metadata, kv.Key, v); break; case Keyword._Comment: case Keyword.ContentEncoding: case Keyword.ContentMediaType: if (!doc.LimitVersion(SchemaVersion.Draft7, true)) { return(null); } name = v as string; if (name == null) { return(null); } AddMetadata(ref metadata, kv.Key, v); break; case Keyword.Deprecated: case Keyword.ReadOnly: case Keyword.WriteOnly: if (!doc.LimitVersion(SchemaVersion.Draft7, true)) { return(null); } if (!(v is bool)) { return(null); } if ((bool)v) { AddMetadata(ref metadata, kv.Key, v); } break; case Keyword._Defs: if (!doc.LimitVersion(SchemaVersion.Draft201909, true)) { return(null); } goto case Keyword.Definitions; case Keyword.Definitions: schemas = ReadPropertySchemas(v, doc); if (schemas == null) { return(null); } AddMetadata(ref metadata, kv.Key, schemas); break; } } // Ignore all other keywords if ref is present // Draft8 might have changed this, // but it is not reflected in the standard test suite if ((subschema.Flags & SchemaFlags._Ref) != 0) { subschema.Flags &= ~SchemaFlags.StoredProperties; subschema.Flags |= SchemaFlags.TypeAll | SchemaFlags._Ref; } if (metadata != null) { AssignMetadata(subschema, metadata); } CompressData(subschema); return(subschema); }
private bool ValidateString(Subschema schema, string value) { bool finalResult = true; for (var mask = schema.Flags & SchemaFlags.StringProperties; mask != 0; mask = (SchemaFlags)RemoveLowestBit((long)mask)) { Keyword keyword = (Keyword)IndexOfLowestBit((long)mask); bool? result = true; switch (keyword) { case Keyword.MinLength: StringInfo si; result = value.Length >= schema.MinLength; if (result == true && Strict) { si = StringInfo; si.String = value; result = si.LengthInTextElements >= schema.MinLength; } break; case Keyword.MaxLength: result = value.Length <= schema.MaxLength; if (result == false && Strict) { si = StringInfo; si.String = value; result = si.LengthInTextElements <= schema.MaxLength; } break; case Keyword.Pattern: SchemaRegex pattern = schema.Pattern; var resultType = pattern.Matches(value); if (resultType != SchemaRegexSuccess.Success) { if (resultType == SchemaRegexSuccess.TimedOut) { SchemaPointer.Push(Keyword.Pattern); ReportError(ErrorType.TimeLimit, schema, value); SchemaPointer.Pop(); return(false); } finalResult = false; if (ReportError(keyword, schema, value, pattern.Pattern)) { return(false); } } continue; case Keyword.Format: result = Formats.IsValueOfFormat(value, schema.Format); break; } if (result == false) { finalResult = false; if (ReportError(keyword, schema, value)) { return(false); } } } return(finalResult); }
private bool Validate(Subschema schema, object instance) { return(!OutOfTime() && ValidateType(schema, instance) && ValidateGeneric(schema, instance)); }