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)
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) {
81 while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
82 if (regexec (®, ucl_object_key (elt), 0, NULL, 0) == 0) {
94 * Check dependencies for an object
97 ucl_schema_validate_dependencies (const ucl_object_t *deps,
98 const ucl_object_t *obj, struct ucl_schema_error *err,
99 const ucl_object_t *root,
100 ucl_object_t *ext_ref)
102 const ucl_object_t *elt, *cur, *cur_dep;
103 ucl_object_iter_t iter = NULL, piter;
106 while (ret && (cur = ucl_object_iterate (deps, &iter, true)) != NULL) {
107 elt = ucl_object_lookup (obj, ucl_object_key (cur));
109 /* Need to check dependencies */
110 if (cur->type == UCL_ARRAY) {
112 while (ret && (cur_dep = ucl_object_iterate (cur, &piter, true)) != NULL) {
113 if (ucl_object_lookup (obj, ucl_object_tostring (cur_dep)) == NULL) {
114 ucl_schema_create_error (err, UCL_SCHEMA_MISSING_DEPENDENCY, elt,
115 "dependency %s is missing for key %s",
116 ucl_object_tostring (cur_dep), ucl_object_key (cur));
122 else if (cur->type == UCL_OBJECT) {
123 ret = ucl_schema_validate (cur, obj, true, err, root, ext_ref);
135 ucl_schema_validate_object (const ucl_object_t *schema,
136 const ucl_object_t *obj, struct ucl_schema_error *err,
137 const ucl_object_t *root,
138 ucl_object_t *ext_ref)
140 const ucl_object_t *elt, *prop, *found, *additional_schema = NULL,
141 *required = NULL, *pat, *pelt;
142 ucl_object_iter_t iter = NULL, piter = NULL;
143 bool ret = true, allow_additional = true;
146 while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
147 if (elt->type == UCL_OBJECT &&
148 strcmp (ucl_object_key (elt), "properties") == 0) {
150 while (ret && (prop = ucl_object_iterate (elt, &piter, true)) != NULL) {
151 found = ucl_object_lookup (obj, ucl_object_key (prop));
153 ret = ucl_schema_validate (prop, found, true, err, root,
158 else if (strcmp (ucl_object_key (elt), "additionalProperties") == 0) {
159 if (elt->type == UCL_BOOLEAN) {
160 if (!ucl_object_toboolean (elt)) {
161 /* Deny additional fields completely */
162 allow_additional = false;
165 else if (elt->type == UCL_OBJECT) {
166 /* Define validator for additional fields */
167 additional_schema = elt;
170 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
171 "additionalProperties attribute is invalid in schema");
176 else if (strcmp (ucl_object_key (elt), "required") == 0) {
177 if (elt->type == UCL_ARRAY) {
181 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
182 "required attribute is invalid in schema");
187 else if (strcmp (ucl_object_key (elt), "minProperties") == 0
188 && ucl_object_toint_safe (elt, &minmax)) {
189 if (obj->len < minmax) {
190 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
191 "object has not enough properties: %u, minimum is: %u",
192 obj->len, (unsigned)minmax);
197 else if (strcmp (ucl_object_key (elt), "maxProperties") == 0
198 && ucl_object_toint_safe (elt, &minmax)) {
199 if (obj->len > minmax) {
200 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
201 "object has too many properties: %u, maximum is: %u",
202 obj->len, (unsigned)minmax);
207 else if (strcmp (ucl_object_key (elt), "patternProperties") == 0) {
209 while (ret && (prop = ucl_object_iterate (elt, &piter, true)) != NULL) {
210 found = ucl_schema_test_pattern (obj, ucl_object_key (prop));
212 ret = ucl_schema_validate (prop, found, true, err, root,
217 else if (elt->type == UCL_OBJECT &&
218 strcmp (ucl_object_key (elt), "dependencies") == 0) {
219 ret = ucl_schema_validate_dependencies (elt, obj, err, root,
225 /* Additional properties */
226 if (!allow_additional || additional_schema != NULL) {
227 /* Check if we have exactly the same properties in schema and object */
229 prop = ucl_object_lookup (schema, "properties");
230 while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
231 found = ucl_object_lookup (prop, ucl_object_key (elt));
233 /* Try patternProperties */
235 pat = ucl_object_lookup (schema, "patternProperties");
236 while ((pelt = ucl_object_iterate (pat, &piter, true)) != NULL) {
237 found = ucl_schema_test_pattern (obj, ucl_object_key (pelt));
244 if (!allow_additional) {
245 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
246 "object has non-allowed property %s",
247 ucl_object_key (elt));
251 else if (additional_schema != NULL) {
252 if (!ucl_schema_validate (additional_schema, elt,
253 true, err, root, ext_ref)) {
261 /* Required properties */
262 if (required != NULL) {
264 while ((elt = ucl_object_iterate (required, &iter, true)) != NULL) {
265 if (ucl_object_lookup (obj, ucl_object_tostring (elt)) == NULL) {
266 ucl_schema_create_error (err, UCL_SCHEMA_MISSING_PROPERTY, obj,
267 "object has missing property %s",
268 ucl_object_tostring (elt));
281 ucl_schema_validate_number (const ucl_object_t *schema,
282 const ucl_object_t *obj, struct ucl_schema_error *err)
284 const ucl_object_t *elt, *test;
285 ucl_object_iter_t iter = NULL;
286 bool ret = true, exclusive = false;
287 double constraint, val;
288 const double alpha = 1e-16;
290 while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
291 if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
292 strcmp (ucl_object_key (elt), "multipleOf") == 0) {
293 constraint = ucl_object_todouble (elt);
294 if (constraint <= 0) {
295 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
296 "multipleOf must be greater than zero");
300 val = ucl_object_todouble (obj);
301 if (fabs (remainder (val, constraint)) > alpha) {
302 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
303 "number %.4f is not multiple of %.4f, remainder is %.7f",
309 else if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
310 strcmp (ucl_object_key (elt), "maximum") == 0) {
311 constraint = ucl_object_todouble (elt);
312 test = ucl_object_lookup (schema, "exclusiveMaximum");
313 if (test && test->type == UCL_BOOLEAN) {
314 exclusive = ucl_object_toboolean (test);
316 val = ucl_object_todouble (obj);
317 if (val > constraint || (exclusive && val >= constraint)) {
318 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
319 "number is too big: %.3f, maximum is: %.3f",
325 else if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
326 strcmp (ucl_object_key (elt), "minimum") == 0) {
327 constraint = ucl_object_todouble (elt);
328 test = ucl_object_lookup (schema, "exclusiveMinimum");
329 if (test && test->type == UCL_BOOLEAN) {
330 exclusive = ucl_object_toboolean (test);
332 val = ucl_object_todouble (obj);
333 if (val < constraint || (exclusive && val <= constraint)) {
334 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
335 "number is too small: %.3f, minimum is: %.3f",
347 ucl_schema_validate_string (const ucl_object_t *schema,
348 const ucl_object_t *obj, struct ucl_schema_error *err)
350 const ucl_object_t *elt;
351 ucl_object_iter_t iter = NULL;
358 while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
359 if (elt->type == UCL_INT &&
360 strcmp (ucl_object_key (elt), "maxLength") == 0) {
361 constraint = ucl_object_toint (elt);
362 if (obj->len > constraint) {
363 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
364 "string is too big: %.3f, maximum is: %.3f",
365 obj->len, constraint);
370 else if (elt->type == UCL_INT &&
371 strcmp (ucl_object_key (elt), "minLength") == 0) {
372 constraint = ucl_object_toint (elt);
373 if (obj->len < constraint) {
374 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
375 "string is too short: %.3f, minimum is: %.3f",
376 obj->len, constraint);
382 else if (elt->type == UCL_STRING &&
383 strcmp (ucl_object_key (elt), "pattern") == 0) {
384 if (regcomp (&re, ucl_object_tostring (elt),
385 REG_EXTENDED | REG_NOSUB) != 0) {
386 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
387 "cannot compile pattern %s", ucl_object_tostring (elt));
391 if (regexec (&re, ucl_object_tostring (obj), 0, NULL, 0) != 0) {
392 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
393 "string doesn't match regexp %s",
394 ucl_object_tostring (elt));
405 struct ucl_compare_node {
406 const ucl_object_t *obj;
407 TREE_ENTRY(ucl_compare_node) link;
408 struct ucl_compare_node *next;
411 typedef TREE_HEAD(_tree, ucl_compare_node) ucl_compare_tree_t;
413 TREE_DEFINE(ucl_compare_node, link)
416 ucl_schema_elt_compare (struct ucl_compare_node *n1, struct ucl_compare_node *n2)
418 const ucl_object_t *o1 = n1->obj, *o2 = n2->obj;
420 return ucl_object_compare (o1, o2);
424 ucl_schema_array_is_unique (const ucl_object_t *obj, struct ucl_schema_error *err)
426 ucl_compare_tree_t tree = TREE_INITIALIZER (ucl_schema_elt_compare);
427 ucl_object_iter_t iter = NULL;
428 const ucl_object_t *elt;
429 struct ucl_compare_node *node, test, *nodes = NULL, *tmp;
432 while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
434 node = TREE_FIND (&tree, ucl_compare_node, link, &test);
436 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, elt,
437 "duplicate values detected while uniqueItems is true");
441 node = calloc (1, sizeof (*node));
443 ucl_schema_create_error (err, UCL_SCHEMA_UNKNOWN, elt,
444 "cannot allocate tree node");
449 TREE_INSERT (&tree, ucl_compare_node, link, node);
450 LL_PREPEND (nodes, node);
453 LL_FOREACH_SAFE (nodes, node, tmp) {
461 ucl_schema_validate_array (const ucl_object_t *schema,
462 const ucl_object_t *obj, struct ucl_schema_error *err,
463 const ucl_object_t *root,
464 ucl_object_t *ext_ref)
466 const ucl_object_t *elt, *it, *found, *additional_schema = NULL,
467 *first_unvalidated = NULL;
468 ucl_object_iter_t iter = NULL, piter = NULL;
469 bool ret = true, allow_additional = true, need_unique = false;
471 unsigned int idx = 0;
473 while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
474 if (strcmp (ucl_object_key (elt), "items") == 0) {
475 if (elt->type == UCL_ARRAY) {
476 found = ucl_array_head (obj);
477 while (ret && (it = ucl_object_iterate (elt, &piter, true)) != NULL) {
479 ret = ucl_schema_validate (it, found, false, err,
481 found = ucl_array_find_index (obj, ++idx);
485 /* The first element that is not validated */
486 first_unvalidated = found;
489 else if (elt->type == UCL_OBJECT) {
490 /* Validate all items using the specified schema */
491 while (ret && (it = ucl_object_iterate (obj, &piter, true)) != NULL) {
492 ret = ucl_schema_validate (elt, it, false, err, root,
497 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
498 "items attribute is invalid in schema");
503 else if (strcmp (ucl_object_key (elt), "additionalItems") == 0) {
504 if (elt->type == UCL_BOOLEAN) {
505 if (!ucl_object_toboolean (elt)) {
506 /* Deny additional fields completely */
507 allow_additional = false;
510 else if (elt->type == UCL_OBJECT) {
511 /* Define validator for additional fields */
512 additional_schema = elt;
515 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
516 "additionalItems attribute is invalid in schema");
521 else if (elt->type == UCL_BOOLEAN &&
522 strcmp (ucl_object_key (elt), "uniqueItems") == 0) {
523 need_unique = ucl_object_toboolean (elt);
525 else if (strcmp (ucl_object_key (elt), "minItems") == 0
526 && ucl_object_toint_safe (elt, &minmax)) {
527 if (obj->len < minmax) {
528 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
529 "array has not enough items: %u, minimum is: %u",
530 obj->len, (unsigned)minmax);
535 else if (strcmp (ucl_object_key (elt), "maxItems") == 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 too many items: %u, maximum is: %u",
540 obj->len, (unsigned)minmax);
548 /* Additional properties */
549 if (!allow_additional || additional_schema != NULL) {
550 if (first_unvalidated != NULL) {
551 if (!allow_additional) {
552 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
553 "array has undefined item");
556 else if (additional_schema != NULL) {
557 elt = ucl_array_find_index (obj, idx);
559 if (!ucl_schema_validate (additional_schema, elt, false,
560 err, root, ext_ref)) {
564 elt = ucl_array_find_index (obj, idx ++);
569 /* Required properties */
570 if (ret && need_unique) {
571 ret = ucl_schema_array_is_unique (obj, err);
579 * Returns whether this object is allowed for this type
582 ucl_schema_type_is_allowed (const ucl_object_t *type, const ucl_object_t *obj,
583 struct ucl_schema_error *err)
585 ucl_object_iter_t iter = NULL;
586 const ucl_object_t *elt;
587 const char *type_str;
591 /* Any type is allowed */
595 if (type->type == UCL_ARRAY) {
596 /* One of allowed types */
597 while ((elt = ucl_object_iterate (type, &iter, true)) != NULL) {
598 if (ucl_schema_type_is_allowed (elt, obj, err)) {
603 else if (type->type == UCL_STRING) {
604 type_str = ucl_object_tostring (type);
605 if (!ucl_object_string_to_type (type_str, &t)) {
606 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, type,
607 "Type attribute is invalid in schema");
610 if (obj->type != t) {
611 /* Some types are actually compatible */
612 if (obj->type == UCL_TIME && t == UCL_FLOAT) {
615 else if (obj->type == UCL_INT && t == UCL_FLOAT) {
619 ucl_schema_create_error (err, UCL_SCHEMA_TYPE_MISMATCH, obj,
620 "Invalid type of %s, expected %s",
621 ucl_object_type_to_string (obj->type),
622 ucl_object_type_to_string (t));
626 /* Types are equal */
635 * Check if object is equal to one of elements of enum
638 ucl_schema_validate_enum (const ucl_object_t *en, const ucl_object_t *obj,
639 struct ucl_schema_error *err)
641 ucl_object_iter_t iter = NULL;
642 const ucl_object_t *elt;
645 while ((elt = ucl_object_iterate (en, &iter, true)) != NULL) {
646 if (ucl_object_compare (elt, obj) == 0) {
653 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
654 "object is not one of enumerated patterns");
662 * Check a single ref component
664 static const ucl_object_t *
665 ucl_schema_resolve_ref_component (const ucl_object_t *cur,
666 const char *refc, int len,
667 struct ucl_schema_error *err)
669 const ucl_object_t *res = NULL;
673 if (cur->type == UCL_OBJECT) {
674 /* Find a key inside an object */
675 res = ucl_object_lookup_len (cur, refc, len);
677 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
678 "reference %s is invalid, missing path component", refc);
682 else if (cur->type == UCL_ARRAY) {
683 /* We must figure out a number inside array */
684 num = strtoul (refc, &err_str, 10);
685 if (err_str != NULL && *err_str != '/' && *err_str != '\0') {
686 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
687 "reference %s is invalid, invalid item number", refc);
690 res = ucl_array_head (cur);
692 while (res != NULL) {
699 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
700 "reference %s is invalid, item number %d does not exist",
706 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
707 "reference %s is invalid, contains primitive object in the path",
715 * Find reference schema
717 static const ucl_object_t *
718 ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
719 struct ucl_schema_error *err, ucl_object_t *ext_ref,
720 ucl_object_t const ** nroot)
722 UT_string *url_err = NULL;
723 struct ucl_parser *parser;
724 const ucl_object_t *res = NULL, *ext_obj = NULL;
725 ucl_object_t *url_obj;
726 const char *p, *c, *hash_ptr = NULL;
727 char *url_copy = NULL;
728 unsigned char *url_buf;
732 hash_ptr = strrchr (ref, '#');
735 url_copy = malloc (hash_ptr - ref + 1);
737 if (url_copy == NULL) {
738 ucl_schema_create_error (err, UCL_SCHEMA_INTERNAL_ERROR, root,
739 "cannot allocate memory");
743 ucl_strlcpy (url_copy, ref, hash_ptr - ref + 1);
751 ext_obj = ucl_object_lookup (ext_ref, p);
753 if (ext_obj == NULL) {
754 if (ucl_strnstr (p, "://", strlen (p)) != NULL) {
755 if (!ucl_fetch_url (p, &url_buf, &url_buflen, &url_err, true)) {
757 ucl_schema_create_error (err,
758 UCL_SCHEMA_INVALID_SCHEMA,
760 "cannot fetch reference %s: %s",
762 url_err != NULL ? utstring_body (url_err)
770 if (!ucl_fetch_file (p, &url_buf, &url_buflen, &url_err,
772 ucl_schema_create_error (err,
773 UCL_SCHEMA_INVALID_SCHEMA,
775 "cannot fetch reference %s: %s",
777 url_err != NULL ? utstring_body (url_err)
785 parser = ucl_parser_new (0);
787 if (!ucl_parser_add_chunk (parser, url_buf, url_buflen)) {
788 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
789 "cannot fetch reference %s: %s", p,
790 ucl_parser_get_error (parser));
791 ucl_parser_free (parser);
797 url_obj = ucl_parser_get_object (parser);
799 ucl_object_insert_key (ext_ref, url_obj, p, 0, true);
816 res = ext_obj != NULL ? ext_obj : root;
822 else if (*p == '\0') {
831 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
832 "reference %s is invalid, empty path component", ref);
835 /* Now we have some url part, so we need to figure out where we are */
836 res = ucl_schema_resolve_ref_component (res, c, p - c, err);
846 res = ucl_schema_resolve_ref_component (res, c, p - c, err);
849 if (res == NULL || res->type != UCL_OBJECT) {
850 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
851 "reference %s is invalid, cannot find specified object",
860 ucl_schema_validate_values (const ucl_object_t *schema, const ucl_object_t *obj,
861 struct ucl_schema_error *err)
863 const ucl_object_t *elt, *cur;
864 int64_t constraint, i;
866 elt = ucl_object_lookup (schema, "maxValues");
867 if (elt != NULL && elt->type == UCL_INT) {
868 constraint = ucl_object_toint (elt);
872 if (i > constraint) {
873 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
874 "object has more values than defined: %ld",
875 (long int)constraint);
882 elt = ucl_object_lookup (schema, "minValues");
883 if (elt != NULL && elt->type == UCL_INT) {
884 constraint = ucl_object_toint (elt);
888 if (i >= constraint) {
894 if (i < constraint) {
895 ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
896 "object has less values than defined: %ld",
897 (long int)constraint);
906 ucl_schema_validate (const ucl_object_t *schema,
907 const ucl_object_t *obj, bool try_array,
908 struct ucl_schema_error *err,
909 const ucl_object_t *root,
910 ucl_object_t *external_refs)
912 const ucl_object_t *elt, *cur, *ref_root;
913 ucl_object_iter_t iter = NULL;
916 if (schema->type != UCL_OBJECT) {
917 ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, schema,
918 "schema is %s instead of object",
919 ucl_object_type_to_string (schema->type));
925 * Special case for multiple values
927 if (!ucl_schema_validate_values (schema, obj, err)) {
930 LL_FOREACH (obj, cur) {
931 if (!ucl_schema_validate (schema, cur, false, err, root, external_refs)) {
938 elt = ucl_object_lookup (schema, "enum");
939 if (elt != NULL && elt->type == UCL_ARRAY) {
940 if (!ucl_schema_validate_enum (elt, obj, err)) {
945 elt = ucl_object_lookup (schema, "allOf");
946 if (elt != NULL && elt->type == UCL_ARRAY) {
948 while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
949 ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
956 elt = ucl_object_lookup (schema, "anyOf");
957 if (elt != NULL && elt->type == UCL_ARRAY) {
959 while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
960 ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
970 err->code = UCL_SCHEMA_OK;
974 elt = ucl_object_lookup (schema, "oneOf");
975 if (elt != NULL && elt->type == UCL_ARRAY) {
978 while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
980 ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
982 else if (ucl_schema_validate (cur, obj, true, err, root, external_refs)) {
992 elt = ucl_object_lookup (schema, "not");
993 if (elt != NULL && elt->type == UCL_OBJECT) {
994 if (ucl_schema_validate (elt, obj, true, err, root, external_refs)) {
999 err->code = UCL_SCHEMA_OK;
1003 elt = ucl_object_lookup (schema, "$ref");
1006 cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt),
1007 err, external_refs, &ref_root);
1012 if (!ucl_schema_validate (cur, obj, try_array, err, ref_root,
1018 elt = ucl_object_lookup (schema, "type");
1019 if (!ucl_schema_type_is_allowed (elt, obj, err)) {
1023 switch (obj->type) {
1025 return ucl_schema_validate_object (schema, obj, err, root, external_refs);
1028 return ucl_schema_validate_array (schema, obj, err, root, external_refs);
1032 return ucl_schema_validate_number (schema, obj, err);
1035 return ucl_schema_validate_string (schema, obj, err);
1045 ucl_object_validate (const ucl_object_t *schema,
1046 const ucl_object_t *obj, struct ucl_schema_error *err)
1048 return ucl_object_validate_root_ext (schema, obj, schema, NULL, err);
1052 ucl_object_validate_root (const ucl_object_t *schema,
1053 const ucl_object_t *obj,
1054 const ucl_object_t *root,
1055 struct ucl_schema_error *err)
1057 return ucl_object_validate_root_ext (schema, obj, root, NULL, err);
1061 ucl_object_validate_root_ext (const ucl_object_t *schema,
1062 const ucl_object_t *obj,
1063 const ucl_object_t *root,
1064 ucl_object_t *ext_refs,
1065 struct ucl_schema_error *err)
1067 bool ret, need_unref = false;
1069 if (ext_refs == NULL) {
1070 ext_refs = ucl_object_typed_new (UCL_OBJECT);
1074 ret = ucl_schema_validate (schema, obj, true, err, root, ext_refs);
1077 ucl_object_unref (ext_refs);