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,
47 ucl_object_t *ext_ref);
50 * Create validation error
53 ucl_schema_create_error (struct ucl_schema_error *err,
54 enum ucl_schema_error_code code, const ucl_object_t *obj,
63 vsnprintf (err->msg, sizeof (err->msg), fmt, va);
69 * Check whether we have a pattern specified
71 static const ucl_object_t *
72 ucl_schema_test_pattern (const ucl_object_t *obj, const char *pattern, bool recursive)
74 const ucl_object_t *res = NULL;
77 const ucl_object_t *elt;
78 ucl_object_iter_t iter = NULL;
80 if (regcomp (®, pattern, REG_EXTENDED | REG_NOSUB) == 0) {
82 while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
83 if (regexec (®, ucl_object_key (elt), 0, NULL, 0) == 0) {
89 if (regexec (®, ucl_object_key (obj), 0, NULL, 0) == 0)
99 * Check dependencies for an object
102 ucl_schema_validate_dependencies (const ucl_object_t *deps,
103 const ucl_object_t *obj, struct ucl_schema_error *err,
104 const ucl_object_t *root,
105 ucl_object_t *ext_ref)
107 const ucl_object_t *elt, *cur, *cur_dep;
108 ucl_object_iter_t iter = NULL, piter;
111 while (ret && (cur = ucl_object_iterate (deps, &iter, true)) != NULL) {
112 elt = ucl_object_lookup (obj, ucl_object_key (cur));
114 /* Need to check dependencies */
115 if (cur->type == UCL_ARRAY) {
117 while (ret && (cur_dep = ucl_object_iterate (cur, &piter, true)) != NULL) {
118 if (ucl_object_lookup (obj, ucl_object_tostring (cur_dep)) == NULL) {
119 ucl_schema_create_error (err, UCL_SCHEMA_MISSING_DEPENDENCY, elt,
120 "dependency %s is missing for key %s",
121 ucl_object_tostring (cur_dep), ucl_object_key (cur));
127 else if (cur->type == UCL_OBJECT) {
128 ret = ucl_schema_validate (cur, obj, true, err, root, ext_ref);
140 ucl_schema_validate_object (const ucl_object_t *schema,
141 const ucl_object_t *obj, struct ucl_schema_error *err,
142 const ucl_object_t *root,
143 ucl_object_t *ext_ref)
145 const ucl_object_t *elt, *prop, *found, *additional_schema = NULL,
146 *required = NULL, *pat, *pelt;
147 ucl_object_iter_t iter = NULL, piter = NULL;
148 bool ret = true, allow_additional = true;
151 while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
152 if (elt->type == UCL_OBJECT &&
153 strcmp (ucl_object_key (elt), "properties") == 0) {
155 while (ret && (prop = ucl_object_iterate (elt, &piter, true)) != NULL) {
156 found = ucl_object_lookup (obj, ucl_object_key (prop));
158 ret = ucl_schema_validate (prop, found, true, err, root,
163 else if (strcmp (ucl_object_key (elt), "additionalProperties") == 0) {
164 if (elt->type == UCL_BOOLEAN) {
165 if (!ucl_object_toboolean (elt)) {
166 /* Deny additional fields completely */
167 allow_additional = false;
170 else if (elt->type == UCL_OBJECT) {
171 /* Define validator for additional fields */
172 additional_schema = elt;
175 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
176 "additionalProperties attribute is invalid in schema");
181 else if (strcmp (ucl_object_key (elt), "required") == 0) {
182 if (elt->type == UCL_ARRAY) {
186 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
187 "required attribute is invalid in schema");
192 else if (strcmp (ucl_object_key (elt), "minProperties") == 0
193 && ucl_object_toint_safe (elt, &minmax)) {
194 if (obj->len < minmax) {
195 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
196 "object has not enough properties: %u, minimum is: %u",
197 obj->len, (unsigned)minmax);
202 else if (strcmp (ucl_object_key (elt), "maxProperties") == 0
203 && ucl_object_toint_safe (elt, &minmax)) {
204 if (obj->len > minmax) {
205 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
206 "object has too many properties: %u, maximum is: %u",
207 obj->len, (unsigned)minmax);
212 else if (strcmp (ucl_object_key (elt), "patternProperties") == 0) {
213 const ucl_object_t *vobj;
214 ucl_object_iter_t viter;
216 while (ret && (prop = ucl_object_iterate (elt, &piter, true)) != NULL) {
218 while (ret && (vobj = ucl_object_iterate (obj, &viter, true)) != NULL) {
219 found = ucl_schema_test_pattern (vobj, ucl_object_key (prop), false);
221 ret = ucl_schema_validate (prop, found, true, err, root,
227 else if (elt->type == UCL_OBJECT &&
228 strcmp (ucl_object_key (elt), "dependencies") == 0) {
229 ret = ucl_schema_validate_dependencies (elt, obj, err, root,
235 /* Additional properties */
236 if (!allow_additional || additional_schema != NULL) {
237 /* Check if we have exactly the same properties in schema and object */
239 prop = ucl_object_lookup (schema, "properties");
240 while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
241 found = ucl_object_lookup (prop, ucl_object_key (elt));
243 /* Try patternProperties */
245 pat = ucl_object_lookup (schema, "patternProperties");
246 while ((pelt = ucl_object_iterate (pat, &piter, true)) != NULL) {
247 found = ucl_schema_test_pattern (obj, ucl_object_key (pelt), true);
254 if (!allow_additional) {
255 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
256 "object has non-allowed property %s",
257 ucl_object_key (elt));
261 else if (additional_schema != NULL) {
262 if (!ucl_schema_validate (additional_schema, elt,
263 true, err, root, ext_ref)) {
271 /* Required properties */
272 if (required != NULL) {
274 while ((elt = ucl_object_iterate (required, &iter, true)) != NULL) {
275 if (ucl_object_lookup (obj, ucl_object_tostring (elt)) == NULL) {
276 ucl_schema_create_error (err, UCL_SCHEMA_MISSING_PROPERTY, obj,
277 "object has missing property %s",
278 ucl_object_tostring (elt));
291 ucl_schema_validate_number (const ucl_object_t *schema,
292 const ucl_object_t *obj, struct ucl_schema_error *err)
294 const ucl_object_t *elt, *test;
295 ucl_object_iter_t iter = NULL;
296 bool ret = true, exclusive = false;
297 double constraint, val;
298 const double alpha = 1e-16;
300 while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
301 if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
302 strcmp (ucl_object_key (elt), "multipleOf") == 0) {
303 constraint = ucl_object_todouble (elt);
304 if (constraint <= 0) {
305 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
306 "multipleOf must be greater than zero");
310 val = ucl_object_todouble (obj);
311 if (fabs (remainder (val, constraint)) > alpha) {
312 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
313 "number %.4f is not multiple of %.4f, remainder is %.7f",
319 else if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
320 strcmp (ucl_object_key (elt), "maximum") == 0) {
321 constraint = ucl_object_todouble (elt);
322 test = ucl_object_lookup (schema, "exclusiveMaximum");
323 if (test && test->type == UCL_BOOLEAN) {
324 exclusive = ucl_object_toboolean (test);
326 val = ucl_object_todouble (obj);
327 if (val > constraint || (exclusive && val >= constraint)) {
328 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
329 "number is too big: %.3f, maximum is: %.3f",
335 else if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
336 strcmp (ucl_object_key (elt), "minimum") == 0) {
337 constraint = ucl_object_todouble (elt);
338 test = ucl_object_lookup (schema, "exclusiveMinimum");
339 if (test && test->type == UCL_BOOLEAN) {
340 exclusive = ucl_object_toboolean (test);
342 val = ucl_object_todouble (obj);
343 if (val < constraint || (exclusive && val <= constraint)) {
344 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
345 "number is too small: %.3f, minimum is: %.3f",
357 ucl_schema_validate_string (const ucl_object_t *schema,
358 const ucl_object_t *obj, struct ucl_schema_error *err)
360 const ucl_object_t *elt;
361 ucl_object_iter_t iter = NULL;
368 while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
369 if (elt->type == UCL_INT &&
370 strcmp (ucl_object_key (elt), "maxLength") == 0) {
371 constraint = ucl_object_toint (elt);
372 if (obj->len > constraint) {
373 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
374 "string is too big: %.3f, maximum is: %.3f",
375 obj->len, constraint);
380 else if (elt->type == UCL_INT &&
381 strcmp (ucl_object_key (elt), "minLength") == 0) {
382 constraint = ucl_object_toint (elt);
383 if (obj->len < constraint) {
384 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
385 "string is too short: %.3f, minimum is: %.3f",
386 obj->len, constraint);
392 else if (elt->type == UCL_STRING &&
393 strcmp (ucl_object_key (elt), "pattern") == 0) {
394 if (regcomp (&re, ucl_object_tostring (elt),
395 REG_EXTENDED | REG_NOSUB) != 0) {
396 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
397 "cannot compile pattern %s", ucl_object_tostring (elt));
401 if (regexec (&re, ucl_object_tostring (obj), 0, NULL, 0) != 0) {
402 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
403 "string doesn't match regexp %s",
404 ucl_object_tostring (elt));
415 struct ucl_compare_node {
416 const ucl_object_t *obj;
417 TREE_ENTRY(ucl_compare_node) link;
418 struct ucl_compare_node *next;
421 typedef TREE_HEAD(_tree, ucl_compare_node) ucl_compare_tree_t;
423 TREE_DEFINE(ucl_compare_node, link)
426 ucl_schema_elt_compare (struct ucl_compare_node *n1, struct ucl_compare_node *n2)
428 const ucl_object_t *o1 = n1->obj, *o2 = n2->obj;
430 return ucl_object_compare (o1, o2);
434 ucl_schema_array_is_unique (const ucl_object_t *obj, struct ucl_schema_error *err)
436 ucl_compare_tree_t tree = TREE_INITIALIZER (ucl_schema_elt_compare);
437 ucl_object_iter_t iter = NULL;
438 const ucl_object_t *elt;
439 struct ucl_compare_node *node, test, *nodes = NULL, *tmp;
442 while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
444 node = TREE_FIND (&tree, ucl_compare_node, link, &test);
446 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, elt,
447 "duplicate values detected while uniqueItems is true");
451 node = calloc (1, sizeof (*node));
453 ucl_schema_create_error (err, UCL_SCHEMA_UNKNOWN, elt,
454 "cannot allocate tree node");
459 TREE_INSERT (&tree, ucl_compare_node, link, node);
460 LL_PREPEND (nodes, node);
463 LL_FOREACH_SAFE (nodes, node, tmp) {
471 ucl_schema_validate_array (const ucl_object_t *schema,
472 const ucl_object_t *obj, struct ucl_schema_error *err,
473 const ucl_object_t *root,
474 ucl_object_t *ext_ref)
476 const ucl_object_t *elt, *it, *found, *additional_schema = NULL,
477 *first_unvalidated = NULL;
478 ucl_object_iter_t iter = NULL, piter = NULL;
479 bool ret = true, allow_additional = true, need_unique = false;
481 unsigned int idx = 0;
483 while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
484 if (strcmp (ucl_object_key (elt), "items") == 0) {
485 if (elt->type == UCL_ARRAY) {
486 found = ucl_array_head (obj);
487 while (ret && (it = ucl_object_iterate (elt, &piter, true)) != NULL) {
489 ret = ucl_schema_validate (it, found, false, err,
491 found = ucl_array_find_index (obj, ++idx);
495 /* The first element that is not validated */
496 first_unvalidated = found;
499 else if (elt->type == UCL_OBJECT) {
500 /* Validate all items using the specified schema */
501 while (ret && (it = ucl_object_iterate (obj, &piter, true)) != NULL) {
502 ret = ucl_schema_validate (elt, it, false, err, root,
507 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
508 "items attribute is invalid in schema");
513 else if (strcmp (ucl_object_key (elt), "additionalItems") == 0) {
514 if (elt->type == UCL_BOOLEAN) {
515 if (!ucl_object_toboolean (elt)) {
516 /* Deny additional fields completely */
517 allow_additional = false;
520 else if (elt->type == UCL_OBJECT) {
521 /* Define validator for additional fields */
522 additional_schema = elt;
525 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
526 "additionalItems attribute is invalid in schema");
531 else if (elt->type == UCL_BOOLEAN &&
532 strcmp (ucl_object_key (elt), "uniqueItems") == 0) {
533 need_unique = ucl_object_toboolean (elt);
535 else if (strcmp (ucl_object_key (elt), "minItems") == 0
536 && ucl_object_toint_safe (elt, &minmax)) {
537 if (obj->len < minmax) {
538 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
539 "array has not enough items: %u, minimum is: %u",
540 obj->len, (unsigned)minmax);
545 else if (strcmp (ucl_object_key (elt), "maxItems") == 0
546 && ucl_object_toint_safe (elt, &minmax)) {
547 if (obj->len > minmax) {
548 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
549 "array has too many items: %u, maximum is: %u",
550 obj->len, (unsigned)minmax);
558 /* Additional properties */
559 if (!allow_additional || additional_schema != NULL) {
560 if (first_unvalidated != NULL) {
561 if (!allow_additional) {
562 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
563 "array has undefined item");
566 else if (additional_schema != NULL) {
567 elt = ucl_array_find_index (obj, idx);
569 if (!ucl_schema_validate (additional_schema, elt, false,
570 err, root, ext_ref)) {
574 elt = ucl_array_find_index (obj, idx ++);
579 /* Required properties */
580 if (ret && need_unique) {
581 ret = ucl_schema_array_is_unique (obj, err);
589 * Returns whether this object is allowed for this type
592 ucl_schema_type_is_allowed (const ucl_object_t *type, const ucl_object_t *obj,
593 struct ucl_schema_error *err)
595 ucl_object_iter_t iter = NULL;
596 const ucl_object_t *elt;
597 const char *type_str;
601 /* Any type is allowed */
605 if (type->type == UCL_ARRAY) {
606 /* One of allowed types */
607 while ((elt = ucl_object_iterate (type, &iter, true)) != NULL) {
608 if (ucl_schema_type_is_allowed (elt, obj, err)) {
613 else if (type->type == UCL_STRING) {
614 type_str = ucl_object_tostring (type);
615 if (!ucl_object_string_to_type (type_str, &t)) {
616 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, type,
617 "Type attribute is invalid in schema");
620 if (obj->type != t) {
621 /* Some types are actually compatible */
622 if (obj->type == UCL_TIME && t == UCL_FLOAT) {
625 else if (obj->type == UCL_INT && t == UCL_FLOAT) {
629 ucl_schema_create_error (err, UCL_SCHEMA_TYPE_MISMATCH, obj,
630 "Invalid type of %s, expected %s",
631 ucl_object_type_to_string (obj->type),
632 ucl_object_type_to_string (t));
636 /* Types are equal */
645 * Check if object is equal to one of elements of enum
648 ucl_schema_validate_enum (const ucl_object_t *en, const ucl_object_t *obj,
649 struct ucl_schema_error *err)
651 ucl_object_iter_t iter = NULL;
652 const ucl_object_t *elt;
655 while ((elt = ucl_object_iterate (en, &iter, true)) != NULL) {
656 if (ucl_object_compare (elt, obj) == 0) {
663 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
664 "object is not one of enumerated patterns");
672 * Check a single ref component
674 static const ucl_object_t *
675 ucl_schema_resolve_ref_component (const ucl_object_t *cur,
676 const char *refc, int len,
677 struct ucl_schema_error *err)
679 const ucl_object_t *res = NULL;
683 if (cur->type == UCL_OBJECT) {
684 /* Find a key inside an object */
685 res = ucl_object_lookup_len (cur, refc, len);
687 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
688 "reference %s is invalid, missing path component", refc);
692 else if (cur->type == UCL_ARRAY) {
693 /* We must figure out a number inside array */
694 num = strtoul (refc, &err_str, 10);
695 if (err_str != NULL && *err_str != '/' && *err_str != '\0') {
696 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
697 "reference %s is invalid, invalid item number", refc);
700 res = ucl_array_head (cur);
702 while (res != NULL) {
709 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
710 "reference %s is invalid, item number %d does not exist",
716 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
717 "reference %s is invalid, contains primitive object in the path",
725 * Find reference schema
727 static const ucl_object_t *
728 ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
729 struct ucl_schema_error *err, ucl_object_t *ext_ref,
730 ucl_object_t const ** nroot)
732 UT_string *url_err = NULL;
733 struct ucl_parser *parser;
734 const ucl_object_t *res = NULL, *ext_obj = NULL;
735 ucl_object_t *url_obj;
736 const char *p, *c, *hash_ptr = NULL;
737 char *url_copy = NULL;
738 unsigned char *url_buf;
742 hash_ptr = strrchr (ref, '#');
745 url_copy = malloc (hash_ptr - ref + 1);
747 if (url_copy == NULL) {
748 ucl_schema_create_error (err, UCL_SCHEMA_INTERNAL_ERROR, root,
749 "cannot allocate memory");
753 ucl_strlcpy (url_copy, ref, hash_ptr - ref + 1);
761 ext_obj = ucl_object_lookup (ext_ref, p);
763 if (ext_obj == NULL) {
764 if (ucl_strnstr (p, "://", strlen (p)) != NULL) {
765 if (!ucl_fetch_url (p, &url_buf, &url_buflen, &url_err, true)) {
767 ucl_schema_create_error (err,
768 UCL_SCHEMA_INVALID_SCHEMA,
770 "cannot fetch reference %s: %s",
772 url_err != NULL ? utstring_body (url_err)
780 if (!ucl_fetch_file (p, &url_buf, &url_buflen, &url_err,
782 ucl_schema_create_error (err,
783 UCL_SCHEMA_INVALID_SCHEMA,
785 "cannot fetch reference %s: %s",
787 url_err != NULL ? utstring_body (url_err)
795 parser = ucl_parser_new (0);
797 if (!ucl_parser_add_chunk (parser, url_buf, url_buflen)) {
798 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
799 "cannot fetch reference %s: %s", p,
800 ucl_parser_get_error (parser));
801 ucl_parser_free (parser);
807 url_obj = ucl_parser_get_object (parser);
809 ucl_object_insert_key (ext_ref, url_obj, p, 0, true);
826 res = ext_obj != NULL ? ext_obj : root;
832 else if (*p == '\0') {
841 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
842 "reference %s is invalid, empty path component", ref);
845 /* Now we have some url part, so we need to figure out where we are */
846 res = ucl_schema_resolve_ref_component (res, c, p - c, err);
856 res = ucl_schema_resolve_ref_component (res, c, p - c, err);
859 if (res == NULL || res->type != UCL_OBJECT) {
860 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
861 "reference %s is invalid, cannot find specified object",
870 ucl_schema_validate_values (const ucl_object_t *schema, const ucl_object_t *obj,
871 struct ucl_schema_error *err)
873 const ucl_object_t *elt, *cur;
874 int64_t constraint, i;
876 elt = ucl_object_lookup (schema, "maxValues");
877 if (elt != NULL && elt->type == UCL_INT) {
878 constraint = ucl_object_toint (elt);
882 if (i > constraint) {
883 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
884 "object has more values than defined: %ld",
885 (long int)constraint);
892 elt = ucl_object_lookup (schema, "minValues");
893 if (elt != NULL && elt->type == UCL_INT) {
894 constraint = ucl_object_toint (elt);
898 if (i >= constraint) {
904 if (i < constraint) {
905 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
906 "object has less values than defined: %ld",
907 (long int)constraint);
916 ucl_schema_validate (const ucl_object_t *schema,
917 const ucl_object_t *obj, bool try_array,
918 struct ucl_schema_error *err,
919 const ucl_object_t *root,
920 ucl_object_t *external_refs)
922 const ucl_object_t *elt, *cur, *ref_root;
923 ucl_object_iter_t iter = NULL;
926 if (schema->type != UCL_OBJECT) {
927 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, schema,
928 "schema is %s instead of object",
929 ucl_object_type_to_string (schema->type));
935 * Special case for multiple values
937 if (!ucl_schema_validate_values (schema, obj, err)) {
940 LL_FOREACH (obj, cur) {
941 if (!ucl_schema_validate (schema, cur, false, err, root, external_refs)) {
948 elt = ucl_object_lookup (schema, "enum");
949 if (elt != NULL && elt->type == UCL_ARRAY) {
950 if (!ucl_schema_validate_enum (elt, obj, err)) {
955 elt = ucl_object_lookup (schema, "allOf");
956 if (elt != NULL && elt->type == UCL_ARRAY) {
958 while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
959 ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
966 elt = ucl_object_lookup (schema, "anyOf");
967 if (elt != NULL && elt->type == UCL_ARRAY) {
969 while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
970 ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
980 err->code = UCL_SCHEMA_OK;
984 elt = ucl_object_lookup (schema, "oneOf");
985 if (elt != NULL && elt->type == UCL_ARRAY) {
988 while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
990 ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
992 else if (ucl_schema_validate (cur, obj, true, err, root, external_refs)) {
1002 elt = ucl_object_lookup (schema, "not");
1003 if (elt != NULL && elt->type == UCL_OBJECT) {
1004 if (ucl_schema_validate (elt, obj, true, err, root, external_refs)) {
1009 err->code = UCL_SCHEMA_OK;
1013 elt = ucl_object_lookup (schema, "$ref");
1016 cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt),
1017 err, external_refs, &ref_root);
1022 if (!ucl_schema_validate (cur, obj, try_array, err, ref_root,
1028 elt = ucl_object_lookup (schema, "type");
1029 if (!ucl_schema_type_is_allowed (elt, obj, err)) {
1033 switch (obj->type) {
1035 return ucl_schema_validate_object (schema, obj, err, root, external_refs);
1038 return ucl_schema_validate_array (schema, obj, err, root, external_refs);
1042 return ucl_schema_validate_number (schema, obj, err);
1045 return ucl_schema_validate_string (schema, obj, err);
1055 ucl_object_validate (const ucl_object_t *schema,
1056 const ucl_object_t *obj, struct ucl_schema_error *err)
1058 return ucl_object_validate_root_ext (schema, obj, schema, NULL, err);
1062 ucl_object_validate_root (const ucl_object_t *schema,
1063 const ucl_object_t *obj,
1064 const ucl_object_t *root,
1065 struct ucl_schema_error *err)
1067 return ucl_object_validate_root_ext (schema, obj, root, NULL, err);
1071 ucl_object_validate_root_ext (const ucl_object_t *schema,
1072 const ucl_object_t *obj,
1073 const ucl_object_t *root,
1074 ucl_object_t *ext_refs,
1075 struct ucl_schema_error *err)
1077 bool ret, need_unref = false;
1079 if (ext_refs == NULL) {
1080 ext_refs = ucl_object_typed_new (UCL_OBJECT);
1084 ret = ucl_schema_validate (schema, obj, true, err, root, ext_refs);
1087 ucl_object_unref (ext_refs);