Example #1
0
        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);
        }
Example #4
0
 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);
        }
Example #10
0
        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);
        }
Example #11
0
        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);
        }
Example #12
0
        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);
        }
Example #13
0
        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
        }
Example #14
0
        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);
            }
        }
Example #15
0
 private void AssignMetadata(Subschema schema, List <Pair> metadata)
 {
     metadata.Sort((a, b) => a.Key.CompareTo(b.Key));
     schema.Metadata = metadata.ToArray();
 }
Example #16
0
        /// <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);
        }
Example #17
0
        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);
        }
Example #18
0
        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);
        }
Example #19
0
        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;
 }
Example #21
0
        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);
        }
Example #22
0
        /// <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);
        }
Example #23
0
        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);
        }
Example #24
0
 private bool Validate(Subschema schema, object instance)
 {
     return(!OutOfTime() &&
            ValidateType(schema, instance) &&
            ValidateGeneric(schema, instance));
 }