示例#1
0
        private KeyValuePair <string, Subschema>[] ReadPropertySchemas(object v, MPSchema doc)
        {
            var map    = (KeyValuePair <string, object>[])v;
            var result = new KeyValuePair <string, Subschema> [map.Length];

            for (int i = 0; i < map.Length; i++)
            {
                string key = map[i].Key;
                var    v2  = From(map[i].Value, doc);
                if (v2 == null)
                {
                    return(null);
                }
                result[i] = new KeyValuePair <string, Subschema>(key, v2);
            }
            return(result);
        }
示例#2
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);
        }
示例#3
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
        }
示例#4
0
        private KeyValuePair <SchemaRegex, Subschema>[] ReadPatternSchemas(object v, MPSchema doc)
        {
            var map    = (KeyValuePair <string, object>[])v;
            var result = new KeyValuePair <SchemaRegex, Subschema> [map.Length];

            for (int i = 0; i < map.Length; i++)
            {
                string key   = map[i].Key;
                var    regex = SchemaRegexCache.Lookup(key);
                if (regex == null)
                {
                    return(null);
                }

                var v2 = From(map[i].Value, doc);
                if (v2 == null)
                {
                    return(null);
                }
                result[i] = new KeyValuePair <SchemaRegex, Subschema>(regex, v2);
            }
            return(result);
        }
示例#5
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);
        }
示例#6
0
 public bool Validate(MPSchema schema, MPJson json, EventHandler <ValidationArgs> eventHandler = null)
 {
     return(Validate(schema?.Root, json, eventHandler));
 }
示例#7
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);
        }
 /// <summary>
 /// Validate json using schema
 /// </summary>
 /// <param name="json"></param>
 /// <param name="schema"></param>
 /// <param name="args"></param>
 /// <returns></returns>
 public static bool Validate(this MPJson json,
                             MPSchema schema,
                             EventHandler <ValidationArgs> args)
 {
     return(schema.Validate(json, args));
 }