2 * Copyright (c) 2014, Vsevolod Stakhov
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "ucl_internal.h"
43 static bool ucl_schema_validate (const ucl_object_t *schema,
44 const ucl_object_t *obj, bool try_array,
45 struct ucl_schema_error *err,
46 const ucl_object_t *root);
49 ucl_string_to_type (const char *input, ucl_type_t *res)
51 if (strcasecmp (input, "object") == 0) {
54 else if (strcasecmp (input, "array") == 0) {
57 else if (strcasecmp (input, "integer") == 0) {
60 else if (strcasecmp (input, "number") == 0) {
63 else if (strcasecmp (input, "string") == 0) {
66 else if (strcasecmp (input, "boolean") == 0) {
69 else if (strcasecmp (input, "null") == 0) {
80 ucl_object_type_to_string (ucl_type_t type)
82 const char *res = "unknown";
114 * Create validation error
117 ucl_schema_create_error (struct ucl_schema_error *err,
118 enum ucl_schema_error_code code, const ucl_object_t *obj,
119 const char *fmt, ...)
127 vsnprintf (err->msg, sizeof (err->msg), fmt, va);
133 * Check whether we have a pattern specified
135 static const ucl_object_t *
136 ucl_schema_test_pattern (const ucl_object_t *obj, const char *pattern)
138 const ucl_object_t *res = NULL;
141 const ucl_object_t *elt;
142 ucl_object_iter_t iter = NULL;
144 if (regcomp (®, pattern, REG_EXTENDED | REG_NOSUB) == 0) {
145 while ((elt = ucl_iterate_object (obj, &iter, true)) != NULL) {
146 if (regexec (®, ucl_object_key (elt), 0, NULL, 0) == 0) {
158 * Check dependencies for an object
161 ucl_schema_validate_dependencies (const ucl_object_t *deps,
162 const ucl_object_t *obj, struct ucl_schema_error *err,
163 const ucl_object_t *root)
165 const ucl_object_t *elt, *cur, *cur_dep;
166 ucl_object_iter_t iter = NULL, piter;
169 while (ret && (cur = ucl_iterate_object (deps, &iter, true)) != NULL) {
170 elt = ucl_object_find_key (obj, ucl_object_key (cur));
172 /* Need to check dependencies */
173 if (cur->type == UCL_ARRAY) {
175 while (ret && (cur_dep = ucl_iterate_object (cur, &piter, true)) != NULL) {
176 if (ucl_object_find_key (obj, ucl_object_tostring (cur_dep)) == NULL) {
177 ucl_schema_create_error (err, UCL_SCHEMA_MISSING_DEPENDENCY, elt,
178 "dependency %s is missing for key %s",
179 ucl_object_tostring (cur_dep), ucl_object_key (cur));
185 else if (cur->type == UCL_OBJECT) {
186 ret = ucl_schema_validate (cur, obj, true, err, root);
198 ucl_schema_validate_object (const ucl_object_t *schema,
199 const ucl_object_t *obj, struct ucl_schema_error *err,
200 const ucl_object_t *root)
202 const ucl_object_t *elt, *prop, *found, *additional_schema = NULL,
203 *required = NULL, *pat, *pelt;
204 ucl_object_iter_t iter = NULL, piter = NULL;
205 bool ret = true, allow_additional = true;
208 while (ret && (elt = ucl_iterate_object (schema, &iter, true)) != NULL) {
209 if (elt->type == UCL_OBJECT &&
210 strcmp (ucl_object_key (elt), "properties") == 0) {
212 while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) {
213 found = ucl_object_find_key (obj, ucl_object_key (prop));
215 ret = ucl_schema_validate (prop, found, true, err, root);
219 else if (strcmp (ucl_object_key (elt), "additionalProperties") == 0) {
220 if (elt->type == UCL_BOOLEAN) {
221 if (!ucl_object_toboolean (elt)) {
222 /* Deny additional fields completely */
223 allow_additional = false;
226 else if (elt->type == UCL_OBJECT) {
227 /* Define validator for additional fields */
228 additional_schema = elt;
231 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
232 "additionalProperties attribute is invalid in schema");
237 else if (strcmp (ucl_object_key (elt), "required") == 0) {
238 if (elt->type == UCL_ARRAY) {
242 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
243 "required attribute is invalid in schema");
248 else if (strcmp (ucl_object_key (elt), "minProperties") == 0
249 && ucl_object_toint_safe (elt, &minmax)) {
250 if (obj->len < minmax) {
251 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
252 "object has not enough properties: %u, minimum is: %u",
253 obj->len, (unsigned)minmax);
258 else if (strcmp (ucl_object_key (elt), "maxProperties") == 0
259 && ucl_object_toint_safe (elt, &minmax)) {
260 if (obj->len > minmax) {
261 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
262 "object has too many properties: %u, maximum is: %u",
263 obj->len, (unsigned)minmax);
268 else if (strcmp (ucl_object_key (elt), "patternProperties") == 0) {
270 while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) {
271 found = ucl_schema_test_pattern (obj, ucl_object_key (prop));
273 ret = ucl_schema_validate (prop, found, true, err, root);
277 else if (elt->type == UCL_OBJECT &&
278 strcmp (ucl_object_key (elt), "dependencies") == 0) {
279 ret = ucl_schema_validate_dependencies (elt, obj, err, root);
284 /* Additional properties */
285 if (!allow_additional || additional_schema != NULL) {
286 /* Check if we have exactly the same properties in schema and object */
288 prop = ucl_object_find_key (schema, "properties");
289 while ((elt = ucl_iterate_object (obj, &iter, true)) != NULL) {
290 found = ucl_object_find_key (prop, ucl_object_key (elt));
292 /* Try patternProperties */
294 pat = ucl_object_find_key (schema, "patternProperties");
295 while ((pelt = ucl_iterate_object (pat, &piter, true)) != NULL) {
296 found = ucl_schema_test_pattern (obj, ucl_object_key (pelt));
303 if (!allow_additional) {
304 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
305 "object has non-allowed property %s",
306 ucl_object_key (elt));
310 else if (additional_schema != NULL) {
311 if (!ucl_schema_validate (additional_schema, elt, true, err, root)) {
319 /* Required properties */
320 if (required != NULL) {
322 while ((elt = ucl_iterate_object (required, &iter, true)) != NULL) {
323 if (ucl_object_find_key (obj, ucl_object_tostring (elt)) == NULL) {
324 ucl_schema_create_error (err, UCL_SCHEMA_MISSING_PROPERTY, obj,
325 "object has missing property %s",
326 ucl_object_tostring (elt));
339 ucl_schema_validate_number (const ucl_object_t *schema,
340 const ucl_object_t *obj, struct ucl_schema_error *err)
342 const ucl_object_t *elt, *test;
343 ucl_object_iter_t iter = NULL;
344 bool ret = true, exclusive = false;
345 double constraint, val;
346 const double alpha = 1e-16;
348 while (ret && (elt = ucl_iterate_object (schema, &iter, true)) != NULL) {
349 if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
350 strcmp (ucl_object_key (elt), "multipleOf") == 0) {
351 constraint = ucl_object_todouble (elt);
352 if (constraint <= 0) {
353 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
354 "multipleOf must be greater than zero");
358 val = ucl_object_todouble (obj);
359 if (fabs (remainder (val, constraint)) > alpha) {
360 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
361 "number %.4f is not multiple of %.4f, remainder is %.7f",
367 else if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
368 strcmp (ucl_object_key (elt), "maximum") == 0) {
369 constraint = ucl_object_todouble (elt);
370 test = ucl_object_find_key (schema, "exclusiveMaximum");
371 if (test && test->type == UCL_BOOLEAN) {
372 exclusive = ucl_object_toboolean (test);
374 val = ucl_object_todouble (obj);
375 if (val > constraint || (exclusive && val >= constraint)) {
376 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
377 "number is too big: %.3f, maximum is: %.3f",
383 else if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
384 strcmp (ucl_object_key (elt), "minimum") == 0) {
385 constraint = ucl_object_todouble (elt);
386 test = ucl_object_find_key (schema, "exclusiveMinimum");
387 if (test && test->type == UCL_BOOLEAN) {
388 exclusive = ucl_object_toboolean (test);
390 val = ucl_object_todouble (obj);
391 if (val < constraint || (exclusive && val <= constraint)) {
392 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
393 "number is too small: %.3f, minimum is: %.3f",
405 ucl_schema_validate_string (const ucl_object_t *schema,
406 const ucl_object_t *obj, struct ucl_schema_error *err)
408 const ucl_object_t *elt;
409 ucl_object_iter_t iter = NULL;
416 while (ret && (elt = ucl_iterate_object (schema, &iter, true)) != NULL) {
417 if (elt->type == UCL_INT &&
418 strcmp (ucl_object_key (elt), "maxLength") == 0) {
419 constraint = ucl_object_toint (elt);
420 if (obj->len > constraint) {
421 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
422 "string is too big: %.3f, maximum is: %.3f",
423 obj->len, constraint);
428 else if (elt->type == UCL_INT &&
429 strcmp (ucl_object_key (elt), "minLength") == 0) {
430 constraint = ucl_object_toint (elt);
431 if (obj->len < constraint) {
432 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
433 "string is too short: %.3f, minimum is: %.3f",
434 obj->len, constraint);
440 else if (elt->type == UCL_STRING &&
441 strcmp (ucl_object_key (elt), "pattern") == 0) {
442 if (regcomp (&re, ucl_object_tostring (elt),
443 REG_EXTENDED | REG_NOSUB) != 0) {
444 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
445 "cannot compile pattern %s", ucl_object_tostring (elt));
449 if (regexec (&re, ucl_object_tostring (obj), 0, NULL, 0) != 0) {
450 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
451 "string doesn't match regexp %s",
452 ucl_object_tostring (elt));
463 struct ucl_compare_node {
464 const ucl_object_t *obj;
465 TREE_ENTRY(ucl_compare_node) link;
466 struct ucl_compare_node *next;
469 typedef TREE_HEAD(_tree, ucl_compare_node) ucl_compare_tree_t;
471 TREE_DEFINE(ucl_compare_node, link)
474 ucl_schema_elt_compare (struct ucl_compare_node *n1, struct ucl_compare_node *n2)
476 const ucl_object_t *o1 = n1->obj, *o2 = n2->obj;
478 return ucl_object_compare (o1, o2);
482 ucl_schema_array_is_unique (const ucl_object_t *obj, struct ucl_schema_error *err)
484 ucl_compare_tree_t tree = TREE_INITIALIZER (ucl_schema_elt_compare);
485 ucl_object_iter_t iter = NULL;
486 const ucl_object_t *elt;
487 struct ucl_compare_node *node, test, *nodes = NULL, *tmp;
490 while ((elt = ucl_iterate_object (obj, &iter, true)) != NULL) {
492 node = TREE_FIND (&tree, ucl_compare_node, link, &test);
494 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, elt,
495 "duplicate values detected while uniqueItems is true");
499 node = calloc (1, sizeof (*node));
501 ucl_schema_create_error (err, UCL_SCHEMA_UNKNOWN, elt,
502 "cannot allocate tree node");
507 TREE_INSERT (&tree, ucl_compare_node, link, node);
508 LL_PREPEND (nodes, node);
511 LL_FOREACH_SAFE (nodes, node, tmp) {
519 ucl_schema_validate_array (const ucl_object_t *schema,
520 const ucl_object_t *obj, struct ucl_schema_error *err,
521 const ucl_object_t *root)
523 const ucl_object_t *elt, *it, *found, *additional_schema = NULL,
524 *first_unvalidated = NULL;
525 ucl_object_iter_t iter = NULL, piter = NULL;
526 bool ret = true, allow_additional = true, need_unique = false;
528 unsigned int idx = 0;
530 while (ret && (elt = ucl_iterate_object (schema, &iter, true)) != NULL) {
531 if (strcmp (ucl_object_key (elt), "items") == 0) {
532 if (elt->type == UCL_ARRAY) {
533 found = ucl_array_head (obj);
534 while (ret && (it = ucl_iterate_object (elt, &piter, true)) != NULL) {
536 ret = ucl_schema_validate (it, found, false, err, root);
537 found = ucl_array_find_index (obj, ++idx);
541 /* The first element that is not validated */
542 first_unvalidated = found;
545 else if (elt->type == UCL_OBJECT) {
546 /* Validate all items using the specified schema */
547 while (ret && (it = ucl_iterate_object (obj, &piter, true)) != NULL) {
548 ret = ucl_schema_validate (elt, it, false, err, root);
552 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
553 "items attribute is invalid in schema");
558 else if (strcmp (ucl_object_key (elt), "additionalItems") == 0) {
559 if (elt->type == UCL_BOOLEAN) {
560 if (!ucl_object_toboolean (elt)) {
561 /* Deny additional fields completely */
562 allow_additional = false;
565 else if (elt->type == UCL_OBJECT) {
566 /* Define validator for additional fields */
567 additional_schema = elt;
570 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
571 "additionalItems attribute is invalid in schema");
576 else if (elt->type == UCL_BOOLEAN &&
577 strcmp (ucl_object_key (elt), "uniqueItems") == 0) {
578 need_unique = ucl_object_toboolean (elt);
580 else if (strcmp (ucl_object_key (elt), "minItems") == 0
581 && ucl_object_toint_safe (elt, &minmax)) {
582 if (obj->len < minmax) {
583 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
584 "array has not enough items: %u, minimum is: %u",
585 obj->len, (unsigned)minmax);
590 else if (strcmp (ucl_object_key (elt), "maxItems") == 0
591 && ucl_object_toint_safe (elt, &minmax)) {
592 if (obj->len > minmax) {
593 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
594 "array has too many items: %u, maximum is: %u",
595 obj->len, (unsigned)minmax);
603 /* Additional properties */
604 if (!allow_additional || additional_schema != NULL) {
605 if (first_unvalidated != NULL) {
606 if (!allow_additional) {
607 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
608 "array has undefined item");
611 else if (additional_schema != NULL) {
612 elt = ucl_array_find_index (obj, idx);
614 if (!ucl_schema_validate (additional_schema, elt, false,
619 elt = ucl_array_find_index (obj, idx ++);
624 /* Required properties */
625 if (ret && need_unique) {
626 ret = ucl_schema_array_is_unique (obj, err);
634 * Returns whether this object is allowed for this type
637 ucl_schema_type_is_allowed (const ucl_object_t *type, const ucl_object_t *obj,
638 struct ucl_schema_error *err)
640 ucl_object_iter_t iter = NULL;
641 const ucl_object_t *elt;
642 const char *type_str;
646 /* Any type is allowed */
650 if (type->type == UCL_ARRAY) {
651 /* One of allowed types */
652 while ((elt = ucl_iterate_object (type, &iter, true)) != NULL) {
653 if (ucl_schema_type_is_allowed (elt, obj, err)) {
658 else if (type->type == UCL_STRING) {
659 type_str = ucl_object_tostring (type);
660 if (!ucl_string_to_type (type_str, &t)) {
661 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, type,
662 "Type attribute is invalid in schema");
665 if (obj->type != t) {
666 /* Some types are actually compatible */
667 if (obj->type == UCL_TIME && t == UCL_FLOAT) {
670 else if (obj->type == UCL_INT && t == UCL_FLOAT) {
674 ucl_schema_create_error (err, UCL_SCHEMA_TYPE_MISMATCH, obj,
675 "Invalid type of %s, expected %s",
676 ucl_object_type_to_string (obj->type),
677 ucl_object_type_to_string (t));
681 /* Types are equal */
690 * Check if object is equal to one of elements of enum
693 ucl_schema_validate_enum (const ucl_object_t *en, const ucl_object_t *obj,
694 struct ucl_schema_error *err)
696 ucl_object_iter_t iter = NULL;
697 const ucl_object_t *elt;
700 while ((elt = ucl_iterate_object (en, &iter, true)) != NULL) {
701 if (ucl_object_compare (elt, obj) == 0) {
708 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
709 "object is not one of enumerated patterns");
717 * Check a single ref component
719 static const ucl_object_t *
720 ucl_schema_resolve_ref_component (const ucl_object_t *cur,
721 const char *refc, int len,
722 struct ucl_schema_error *err)
724 const ucl_object_t *res = NULL;
728 if (cur->type == UCL_OBJECT) {
729 /* Find a key inside an object */
730 res = ucl_object_find_keyl (cur, refc, len);
732 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
733 "reference %s is invalid, missing path component", refc);
737 else if (cur->type == UCL_ARRAY) {
738 /* We must figure out a number inside array */
739 num = strtoul (refc, &err_str, 10);
740 if (err_str != NULL && *err_str != '/' && *err_str != '\0') {
741 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
742 "reference %s is invalid, invalid item number", refc);
745 res = ucl_array_head (cur);
747 while (res != NULL) {
754 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
755 "reference %s is invalid, item number %d does not exist",
761 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
762 "reference %s is invalid, contains primitive object in the path",
770 * Find reference schema
772 static const ucl_object_t *
773 ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
774 struct ucl_schema_error *err)
777 const ucl_object_t *res = NULL;
781 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
782 "reference %s is invalid, not started with #", ref);
788 else if (ref[1] == '\0') {
792 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
793 "reference %s is invalid, not started with #/", ref);
803 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
804 "reference %s is invalid, empty path component", ref);
807 /* Now we have some url part, so we need to figure out where we are */
808 res = ucl_schema_resolve_ref_component (res, c, p - c, err);
818 res = ucl_schema_resolve_ref_component (res, c, p - c, err);
821 if (res == NULL || res->type != UCL_OBJECT) {
822 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
823 "reference %s is invalid, cannot find specified object",
832 ucl_schema_validate_values (const ucl_object_t *schema, const ucl_object_t *obj,
833 struct ucl_schema_error *err)
835 const ucl_object_t *elt, *cur;
836 int64_t constraint, i;
838 elt = ucl_object_find_key (schema, "maxValues");
839 if (elt != NULL && elt->type == UCL_INT) {
840 constraint = ucl_object_toint (elt);
844 if (i > constraint) {
845 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
846 "object has more values than defined: %ld",
847 (long int)constraint);
854 elt = ucl_object_find_key (schema, "minValues");
855 if (elt != NULL && elt->type == UCL_INT) {
856 constraint = ucl_object_toint (elt);
860 if (i >= constraint) {
866 if (i < constraint) {
867 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
868 "object has less values than defined: %ld",
869 (long int)constraint);
878 ucl_schema_validate (const ucl_object_t *schema,
879 const ucl_object_t *obj, bool try_array,
880 struct ucl_schema_error *err,
881 const ucl_object_t *root)
883 const ucl_object_t *elt, *cur;
884 ucl_object_iter_t iter = NULL;
887 if (schema->type != UCL_OBJECT) {
888 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, schema,
889 "schema is %s instead of object", ucl_object_type_to_string (schema->type));
895 * Special case for multiple values
897 if (!ucl_schema_validate_values (schema, obj, err)) {
900 LL_FOREACH (obj, cur) {
901 if (!ucl_schema_validate (schema, cur, false, err, root)) {
908 elt = ucl_object_find_key (schema, "enum");
909 if (elt != NULL && elt->type == UCL_ARRAY) {
910 if (!ucl_schema_validate_enum (elt, obj, err)) {
915 elt = ucl_object_find_key (schema, "allOf");
916 if (elt != NULL && elt->type == UCL_ARRAY) {
918 while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
919 ret = ucl_schema_validate (cur, obj, true, err, root);
926 elt = ucl_object_find_key (schema, "anyOf");
927 if (elt != NULL && elt->type == UCL_ARRAY) {
929 while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
930 ret = ucl_schema_validate (cur, obj, true, err, root);
940 err->code = UCL_SCHEMA_OK;
944 elt = ucl_object_find_key (schema, "oneOf");
945 if (elt != NULL && elt->type == UCL_ARRAY) {
948 while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
950 ret = ucl_schema_validate (cur, obj, true, err, root);
952 else if (ucl_schema_validate (cur, obj, true, err, root)) {
962 elt = ucl_object_find_key (schema, "not");
963 if (elt != NULL && elt->type == UCL_OBJECT) {
964 if (ucl_schema_validate (elt, obj, true, err, root)) {
969 err->code = UCL_SCHEMA_OK;
973 elt = ucl_object_find_key (schema, "$ref");
975 cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt), err);
979 if (!ucl_schema_validate (cur, obj, try_array, err, root)) {
984 elt = ucl_object_find_key (schema, "type");
985 if (!ucl_schema_type_is_allowed (elt, obj, err)) {
991 return ucl_schema_validate_object (schema, obj, err, root);
994 return ucl_schema_validate_array (schema, obj, err, root);
998 return ucl_schema_validate_number (schema, obj, err);
1001 return ucl_schema_validate_string (schema, obj, err);
1011 ucl_object_validate (const ucl_object_t *schema,
1012 const ucl_object_t *obj, struct ucl_schema_error *err)
1014 return ucl_schema_validate (schema, obj, true, err, schema);