Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2014, Vsevolod Stakhov
3 : : *
4 : : * All rights reserved.
5 : : *
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.
13 : : *
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.
24 : : */
25 : :
26 : : #include "ucl.h"
27 : : #include "ucl_internal.h"
28 : : #include "tree.h"
29 : : #include "utlist.h"
30 : : #ifdef HAVE_STDARG_H
31 : : #include <stdarg.h>
32 : : #endif
33 : : #ifdef HAVE_STDIO_H
34 : : #include <stdio.h>
35 : : #endif
36 : : #ifdef HAVE_REGEX_H
37 : : #include <regex.h>
38 : : #endif
39 : : #ifdef HAVE_MATH_H
40 : : #include <math.h>
41 : : #endif
42 : :
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);
48 : :
49 : : /*
50 : : * Create validation error
51 : : */
52 : :
53 : : #ifdef __GNUC__
54 : : static inline void
55 : : ucl_schema_create_error (struct ucl_schema_error *err,
56 : : enum ucl_schema_error_code code, const ucl_object_t *obj,
57 : : const char *fmt, ...)
58 : : __attribute__ (( format( printf, 4, 5) ));
59 : : #endif
60 : :
61 : : static inline void
62 : 0 : ucl_schema_create_error (struct ucl_schema_error *err,
63 : : enum ucl_schema_error_code code, const ucl_object_t *obj,
64 : : const char *fmt, ...)
65 : : {
66 : : va_list va;
67 : :
68 [ # # ]: 0 : if (err != NULL) {
69 : 0 : err->code = code;
70 : 0 : err->obj = obj;
71 : 0 : va_start (va, fmt);
72 : 0 : vsnprintf (err->msg, sizeof (err->msg), fmt, va);
73 : 0 : va_end (va);
74 : 0 : }
75 : 0 : }
76 : :
77 : : /*
78 : : * Check whether we have a pattern specified
79 : : */
80 : : static const ucl_object_t *
81 : 0 : ucl_schema_test_pattern (const ucl_object_t *obj, const char *pattern, bool recursive)
82 : : {
83 : 0 : const ucl_object_t *res = NULL;
84 : : #ifdef HAVE_REGEX_H
85 : : regex_t reg;
86 : : const ucl_object_t *elt;
87 : 0 : ucl_object_iter_t iter = NULL;
88 : :
89 [ # # ]: 0 : if (regcomp (®, pattern, REG_EXTENDED | REG_NOSUB) == 0) {
90 [ # # ]: 0 : if (recursive) {
91 [ # # ]: 0 : while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
92 [ # # ]: 0 : if (regexec (®, ucl_object_key (elt), 0, NULL, 0) == 0) {
93 : 0 : res = elt;
94 : 0 : break;
95 : : }
96 : : }
97 : 0 : } else {
98 [ # # ]: 0 : if (regexec (®, ucl_object_key (obj), 0, NULL, 0) == 0)
99 : 0 : res = obj;
100 : : }
101 : 0 : regfree (®);
102 : 0 : }
103 : : #endif
104 : 0 : return res;
105 : : }
106 : :
107 : : /*
108 : : * Check dependencies for an object
109 : : */
110 : : static bool
111 : 0 : ucl_schema_validate_dependencies (const ucl_object_t *deps,
112 : : const ucl_object_t *obj, struct ucl_schema_error *err,
113 : : const ucl_object_t *root,
114 : : ucl_object_t *ext_ref)
115 : : {
116 : : const ucl_object_t *elt, *cur, *cur_dep;
117 : 0 : ucl_object_iter_t iter = NULL, piter;
118 : 0 : bool ret = true;
119 : :
120 [ # # # # ]: 0 : while (ret && (cur = ucl_object_iterate (deps, &iter, true)) != NULL) {
121 : 0 : elt = ucl_object_lookup (obj, ucl_object_key (cur));
122 [ # # ]: 0 : if (elt != NULL) {
123 : : /* Need to check dependencies */
124 [ # # ]: 0 : if (cur->type == UCL_ARRAY) {
125 : 0 : piter = NULL;
126 [ # # # # ]: 0 : while (ret && (cur_dep = ucl_object_iterate (cur, &piter, true)) != NULL) {
127 [ # # ]: 0 : if (ucl_object_lookup (obj, ucl_object_tostring (cur_dep)) == NULL) {
128 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_MISSING_DEPENDENCY, elt,
129 : : "dependency %s is missing for key %s",
130 : 0 : ucl_object_tostring (cur_dep), ucl_object_key (cur));
131 : 0 : ret = false;
132 : 0 : break;
133 : : }
134 : : }
135 : 0 : }
136 [ # # ]: 0 : else if (cur->type == UCL_OBJECT) {
137 : 0 : ret = ucl_schema_validate (cur, obj, true, err, root, ext_ref);
138 : 0 : }
139 : 0 : }
140 : : }
141 : :
142 : 0 : return ret;
143 : : }
144 : :
145 : : /*
146 : : * Validate object
147 : : */
148 : : static bool
149 : 5631 : ucl_schema_validate_object (const ucl_object_t *schema,
150 : : const ucl_object_t *obj, struct ucl_schema_error *err,
151 : : const ucl_object_t *root,
152 : : ucl_object_t *ext_ref)
153 : : {
154 : 5631 : const ucl_object_t *elt, *prop, *found, *additional_schema = NULL,
155 : 5631 : *required = NULL, *pat, *pelt;
156 : 5631 : ucl_object_iter_t iter = NULL, piter = NULL;
157 : 5631 : bool ret = true, allow_additional = true;
158 : : int64_t minmax;
159 : :
160 [ - + + + ]: 20318 : while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
161 [ + + + + ]: 14687 : if (elt->type == UCL_OBJECT &&
162 : 7725 : strcmp (ucl_object_key (elt), "properties") == 0) {
163 : 1407 : piter = NULL;
164 [ - + + + ]: 23875 : while (ret && (prop = ucl_object_iterate (elt, &piter, true)) != NULL) {
165 : 22468 : found = ucl_object_lookup (obj, ucl_object_key (prop));
166 [ + + ]: 22468 : if (found) {
167 : 16156 : ret = ucl_schema_validate (prop, found, true, err, root,
168 : 8078 : ext_ref);
169 : 8078 : }
170 : : }
171 : 1407 : }
172 [ + - ]: 13280 : else if (strcmp (ucl_object_key (elt), "additionalProperties") == 0) {
173 [ # # ]: 0 : if (elt->type == UCL_BOOLEAN) {
174 [ # # ]: 0 : if (!ucl_object_toboolean (elt)) {
175 : : /* Deny additional fields completely */
176 : 0 : allow_additional = false;
177 : 0 : }
178 : 0 : }
179 [ # # ]: 0 : else if (elt->type == UCL_OBJECT) {
180 : : /* Define validator for additional fields */
181 : 0 : additional_schema = elt;
182 : 0 : }
183 : : else {
184 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
185 : : "additionalProperties attribute is invalid in schema");
186 : 0 : ret = false;
187 : 0 : break;
188 : : }
189 : 0 : }
190 [ + + ]: 13280 : else if (strcmp (ucl_object_key (elt), "required") == 0) {
191 [ + - ]: 1331 : if (elt->type == UCL_ARRAY) {
192 : 1331 : required = elt;
193 : 1331 : }
194 : : else {
195 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
196 : : "required attribute is invalid in schema");
197 : 0 : ret = false;
198 : 0 : break;
199 : : }
200 : 1331 : }
201 [ # # ]: 11949 : else if (strcmp (ucl_object_key (elt), "minProperties") == 0
202 [ - + ]: 11949 : && ucl_object_toint_safe (elt, &minmax)) {
203 [ # # ]: 0 : if (obj->len < minmax) {
204 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
205 : : "object has not enough properties: %u, minimum is: %u",
206 : 0 : obj->len, (unsigned)minmax);
207 : 0 : ret = false;
208 : 0 : break;
209 : : }
210 : 0 : }
211 [ # # ]: 11949 : else if (strcmp (ucl_object_key (elt), "maxProperties") == 0
212 [ - + ]: 11949 : && ucl_object_toint_safe (elt, &minmax)) {
213 [ # # ]: 0 : if (obj->len > minmax) {
214 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
215 : : "object has too many properties: %u, maximum is: %u",
216 : 0 : obj->len, (unsigned)minmax);
217 : 0 : ret = false;
218 : 0 : break;
219 : : }
220 : 0 : }
221 [ + - ]: 11949 : else if (strcmp (ucl_object_key (elt), "patternProperties") == 0) {
222 : : const ucl_object_t *vobj;
223 : : ucl_object_iter_t viter;
224 : 0 : piter = NULL;
225 [ # # # # ]: 0 : while (ret && (prop = ucl_object_iterate (elt, &piter, true)) != NULL) {
226 : 0 : viter = NULL;
227 [ # # # # ]: 0 : while (ret && (vobj = ucl_object_iterate (obj, &viter, true)) != NULL) {
228 : 0 : found = ucl_schema_test_pattern (vobj, ucl_object_key (prop), false);
229 [ # # ]: 0 : if (found) {
230 : 0 : ret = ucl_schema_validate (prop, found, true, err, root,
231 : 0 : ext_ref);
232 : 0 : }
233 : : }
234 : : }
235 : 0 : }
236 [ + + + - ]: 11949 : else if (elt->type == UCL_OBJECT &&
237 : 6318 : strcmp (ucl_object_key (elt), "dependencies") == 0) {
238 : 0 : ret = ucl_schema_validate_dependencies (elt, obj, err, root,
239 : 0 : ext_ref);
240 : 0 : }
241 : : }
242 : :
243 [ - + ]: 5631 : if (ret) {
244 : : /* Additional properties */
245 [ + - - + ]: 5631 : if (!allow_additional || additional_schema != NULL) {
246 : : /* Check if we have exactly the same properties in schema and object */
247 : 0 : iter = NULL;
248 : 0 : prop = ucl_object_lookup (schema, "properties");
249 [ # # ]: 0 : while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
250 : 0 : found = ucl_object_lookup (prop, ucl_object_key (elt));
251 [ # # ]: 0 : if (found == NULL) {
252 : : /* Try patternProperties */
253 : 0 : piter = NULL;
254 : 0 : pat = ucl_object_lookup (schema, "patternProperties");
255 [ # # ]: 0 : while ((pelt = ucl_object_iterate (pat, &piter, true)) != NULL) {
256 : 0 : found = ucl_schema_test_pattern (obj, ucl_object_key (pelt), true);
257 [ # # ]: 0 : if (found != NULL) {
258 : 0 : break;
259 : : }
260 : : }
261 : 0 : }
262 [ # # ]: 0 : if (found == NULL) {
263 [ # # ]: 0 : if (!allow_additional) {
264 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
265 : : "object has non-allowed property %s",
266 : 0 : ucl_object_key (elt));
267 : 0 : ret = false;
268 : 0 : break;
269 : : }
270 [ # # ]: 0 : else if (additional_schema != NULL) {
271 [ # # # # ]: 0 : if (!ucl_schema_validate (additional_schema, elt,
272 : 0 : true, err, root, ext_ref)) {
273 : 0 : ret = false;
274 : 0 : break;
275 : : }
276 : 0 : }
277 : 0 : }
278 : : }
279 : 0 : }
280 : : /* Required properties */
281 [ + + ]: 5631 : if (required != NULL) {
282 : 1331 : iter = NULL;
283 [ + + ]: 2662 : while ((elt = ucl_object_iterate (required, &iter, true)) != NULL) {
284 [ + - ]: 1331 : if (ucl_object_lookup (obj, ucl_object_tostring (elt)) == NULL) {
285 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_MISSING_PROPERTY, obj,
286 : : "object has missing property %s",
287 : 0 : ucl_object_tostring (elt));
288 : 0 : ret = false;
289 : 0 : break;
290 : : }
291 : : }
292 : 1331 : }
293 : 5631 : }
294 : :
295 : :
296 : 5631 : return ret;
297 : : }
298 : :
299 : : static bool
300 : 1319 : ucl_schema_validate_number (const ucl_object_t *schema,
301 : : const ucl_object_t *obj, struct ucl_schema_error *err)
302 : : {
303 : : const ucl_object_t *elt, *test;
304 : 1319 : ucl_object_iter_t iter = NULL;
305 : 1319 : bool ret = true, exclusive = false;
306 : : double constraint, val;
307 : 1319 : const double alpha = 1e-16;
308 : :
309 [ - + + + ]: 2638 : while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
310 [ + - + - ]: 1319 : if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
311 : 1319 : strcmp (ucl_object_key (elt), "multipleOf") == 0) {
312 : 0 : constraint = ucl_object_todouble (elt);
313 [ # # ]: 0 : if (constraint <= 0) {
314 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
315 : : "multipleOf must be greater than zero");
316 : 0 : ret = false;
317 : 0 : break;
318 : : }
319 : 0 : val = ucl_object_todouble (obj);
320 [ # # ]: 0 : if (fabs (remainder (val, constraint)) > alpha) {
321 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
322 : : "number %.4f is not multiple of %.4f, remainder is %.7f",
323 : 0 : val, constraint, remainder (val, constraint));
324 : 0 : ret = false;
325 : 0 : break;
326 : : }
327 : 0 : }
328 [ + - + - ]: 1319 : else if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
329 : 1319 : strcmp (ucl_object_key (elt), "maximum") == 0) {
330 : 0 : constraint = ucl_object_todouble (elt);
331 : 0 : test = ucl_object_lookup (schema, "exclusiveMaximum");
332 [ # # # # ]: 0 : if (test && test->type == UCL_BOOLEAN) {
333 : 0 : exclusive = ucl_object_toboolean (test);
334 : 0 : }
335 : 0 : val = ucl_object_todouble (obj);
336 [ # # # # : 0 : if (val > constraint || (exclusive && val >= constraint)) {
# # ]
337 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
338 : : "number is too big: %.3f, maximum is: %.3f",
339 : 0 : val, constraint);
340 : 0 : ret = false;
341 : 0 : break;
342 : : }
343 : 0 : }
344 [ + - + - ]: 1319 : else if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
345 : 1319 : strcmp (ucl_object_key (elt), "minimum") == 0) {
346 : 0 : constraint = ucl_object_todouble (elt);
347 : 0 : test = ucl_object_lookup (schema, "exclusiveMinimum");
348 [ # # # # ]: 0 : if (test && test->type == UCL_BOOLEAN) {
349 : 0 : exclusive = ucl_object_toboolean (test);
350 : 0 : }
351 : 0 : val = ucl_object_todouble (obj);
352 [ # # # # : 0 : if (val < constraint || (exclusive && val <= constraint)) {
# # ]
353 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
354 : : "number is too small: %.3f, minimum is: %.3f",
355 : 0 : val, constraint);
356 : 0 : ret = false;
357 : 0 : break;
358 : : }
359 : 0 : }
360 : : }
361 : :
362 : 1319 : return ret;
363 : : }
364 : :
365 : : static bool
366 : 6647 : ucl_schema_validate_string (const ucl_object_t *schema,
367 : : const ucl_object_t *obj, struct ucl_schema_error *err)
368 : : {
369 : : const ucl_object_t *elt;
370 : 6647 : ucl_object_iter_t iter = NULL;
371 : 6647 : bool ret = true;
372 : : int64_t constraint;
373 : : #ifdef HAVE_REGEX_H
374 : : regex_t re;
375 : : #endif
376 : :
377 [ - + + + ]: 13294 : while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
378 [ - + # # ]: 6647 : if (elt->type == UCL_INT &&
379 : 0 : strcmp (ucl_object_key (elt), "maxLength") == 0) {
380 : 0 : constraint = ucl_object_toint (elt);
381 [ # # ]: 0 : if (obj->len > constraint) {
382 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
383 : : "string is too big: %u, maximum is: %" PRId64,
384 : 0 : obj->len, constraint);
385 : 0 : ret = false;
386 : 0 : break;
387 : : }
388 : 0 : }
389 [ - + # # ]: 6647 : else if (elt->type == UCL_INT &&
390 : 0 : strcmp (ucl_object_key (elt), "minLength") == 0) {
391 : 0 : constraint = ucl_object_toint (elt);
392 [ # # ]: 0 : if (obj->len < constraint) {
393 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
394 : : "string is too short: %u, minimum is: %" PRId64,
395 : 0 : obj->len, constraint);
396 : 0 : ret = false;
397 : 0 : break;
398 : : }
399 : 0 : }
400 : : #ifdef HAVE_REGEX_H
401 [ + + + - ]: 6647 : else if (elt->type == UCL_STRING &&
402 : 5328 : strcmp (ucl_object_key (elt), "pattern") == 0) {
403 [ # # # # ]: 0 : if (regcomp (&re, ucl_object_tostring (elt),
404 : 0 : REG_EXTENDED | REG_NOSUB) != 0) {
405 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
406 : 0 : "cannot compile pattern %s", ucl_object_tostring (elt));
407 : 0 : ret = false;
408 : 0 : break;
409 : : }
410 [ # # ]: 0 : if (regexec (&re, ucl_object_tostring (obj), 0, NULL, 0) != 0) {
411 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
412 : : "string doesn't match regexp %s",
413 : 0 : ucl_object_tostring (elt));
414 : 0 : ret = false;
415 : 0 : }
416 : 0 : regfree (&re);
417 : 0 : }
418 : : #endif
419 : : }
420 : :
421 : 6647 : return ret;
422 : : }
423 : :
424 : : struct ucl_compare_node {
425 : : const ucl_object_t *obj;
426 : : TREE_ENTRY(ucl_compare_node) link;
427 : : struct ucl_compare_node *next;
428 : : };
429 : :
430 : : typedef TREE_HEAD(_tree, ucl_compare_node) ucl_compare_tree_t;
431 : :
432 [ + + + - : 72 : TREE_DEFINE(ucl_compare_node, link)
+ - + + +
- + - - +
- + # # #
# # # - +
# # # # #
# + - + -
- + # # ]
433 : :
434 : : static int
435 : 24 : ucl_schema_elt_compare (struct ucl_compare_node *n1, struct ucl_compare_node *n2)
436 : : {
437 : 24 : const ucl_object_t *o1 = n1->obj, *o2 = n2->obj;
438 : :
439 : 24 : return ucl_object_compare (o1, o2);
440 : : }
441 : :
442 : : static bool
443 : 60 : ucl_schema_array_is_unique (const ucl_object_t *obj, struct ucl_schema_error *err)
444 : : {
445 : 60 : ucl_compare_tree_t tree = TREE_INITIALIZER (ucl_schema_elt_compare);
446 : 60 : ucl_object_iter_t iter = NULL;
447 : : const ucl_object_t *elt;
448 : 60 : struct ucl_compare_node *node, test, *nodes = NULL, *tmp;
449 : 60 : bool ret = true;
450 : :
451 [ + + ]: 80 : while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
452 : 20 : test.obj = elt;
453 : 20 : node = TREE_FIND (&tree, ucl_compare_node, link, &test);
454 [ + - ]: 20 : if (node != NULL) {
455 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, elt,
456 : : "duplicate values detected while uniqueItems is true");
457 : 0 : ret = false;
458 : 0 : break;
459 : : }
460 : 20 : node = calloc (1, sizeof (*node));
461 [ - + ]: 20 : if (node == NULL) {
462 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_UNKNOWN, elt,
463 : : "cannot allocate tree node");
464 : 0 : ret = false;
465 : 0 : break;
466 : : }
467 : 20 : node->obj = elt;
468 : 20 : TREE_INSERT (&tree, ucl_compare_node, link, node);
469 : 20 : LL_PREPEND (nodes, node);
470 : : }
471 : :
472 [ + + + + ]: 80 : LL_FOREACH_SAFE (nodes, node, tmp) {
473 : 20 : free (node);
474 : 20 : }
475 : :
476 : 60 : return ret;
477 : : }
478 : :
479 : : static bool
480 : 64 : ucl_schema_validate_array (const ucl_object_t *schema,
481 : : const ucl_object_t *obj, struct ucl_schema_error *err,
482 : : const ucl_object_t *root,
483 : : ucl_object_t *ext_ref)
484 : : {
485 : 64 : const ucl_object_t *elt, *it, *found, *additional_schema = NULL,
486 : 64 : *first_unvalidated = NULL;
487 : 64 : ucl_object_iter_t iter = NULL, piter = NULL;
488 : 64 : bool ret = true, allow_additional = true, need_unique = false;
489 : : int64_t minmax;
490 : 64 : unsigned int idx = 0;
491 : :
492 [ - + + + ]: 252 : while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
493 [ + + ]: 188 : if (strcmp (ucl_object_key (elt), "items") == 0) {
494 [ - + ]: 64 : if (elt->type == UCL_ARRAY) {
495 : 0 : found = ucl_array_head (obj);
496 [ # # # # ]: 0 : while (ret && (it = ucl_object_iterate (elt, &piter, true)) != NULL) {
497 [ # # ]: 0 : if (found) {
498 : 0 : ret = ucl_schema_validate (it, found, false, err,
499 : 0 : root, ext_ref);
500 : 0 : found = ucl_array_find_index (obj, ++idx);
501 : 0 : }
502 : : }
503 [ # # ]: 0 : if (found != NULL) {
504 : : /* The first element that is not validated */
505 : 0 : first_unvalidated = found;
506 : 0 : }
507 : 0 : }
508 [ + - ]: 64 : else if (elt->type == UCL_OBJECT) {
509 : : /* Validate all items using the specified schema */
510 [ - + + + ]: 96 : while (ret && (it = ucl_object_iterate (obj, &piter, true)) != NULL) {
511 : 64 : ret = ucl_schema_validate (elt, it, false, err, root,
512 : 32 : ext_ref);
513 : : }
514 : 64 : }
515 : : else {
516 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
517 : : "items attribute is invalid in schema");
518 : 0 : ret = false;
519 : 0 : break;
520 : : }
521 : 64 : }
522 [ + - ]: 124 : else if (strcmp (ucl_object_key (elt), "additionalItems") == 0) {
523 [ # # ]: 0 : if (elt->type == UCL_BOOLEAN) {
524 [ # # ]: 0 : if (!ucl_object_toboolean (elt)) {
525 : : /* Deny additional fields completely */
526 : 0 : allow_additional = false;
527 : 0 : }
528 : 0 : }
529 [ # # ]: 0 : else if (elt->type == UCL_OBJECT) {
530 : : /* Define validator for additional fields */
531 : 0 : additional_schema = elt;
532 : 0 : }
533 : : else {
534 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt,
535 : : "additionalItems attribute is invalid in schema");
536 : 0 : ret = false;
537 : 0 : break;
538 : : }
539 : 0 : }
540 [ + + - + ]: 124 : else if (elt->type == UCL_BOOLEAN &&
541 : 60 : strcmp (ucl_object_key (elt), "uniqueItems") == 0) {
542 : 60 : need_unique = ucl_object_toboolean (elt);
543 : 60 : }
544 [ # # ]: 64 : else if (strcmp (ucl_object_key (elt), "minItems") == 0
545 [ - + ]: 64 : && ucl_object_toint_safe (elt, &minmax)) {
546 [ # # ]: 0 : if (obj->len < minmax) {
547 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
548 : : "array has not enough items: %u, minimum is: %u",
549 : 0 : obj->len, (unsigned)minmax);
550 : 0 : ret = false;
551 : 0 : break;
552 : : }
553 : 0 : }
554 [ # # ]: 64 : else if (strcmp (ucl_object_key (elt), "maxItems") == 0
555 [ - + ]: 64 : && ucl_object_toint_safe (elt, &minmax)) {
556 [ # # ]: 0 : if (obj->len > minmax) {
557 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
558 : : "array has too many items: %u, maximum is: %u",
559 : 0 : obj->len, (unsigned)minmax);
560 : 0 : ret = false;
561 : 0 : break;
562 : : }
563 : 0 : }
564 : : }
565 : :
566 [ - + ]: 64 : if (ret) {
567 : : /* Additional properties */
568 [ + - - + ]: 64 : if (!allow_additional || additional_schema != NULL) {
569 [ # # ]: 0 : if (first_unvalidated != NULL) {
570 [ # # ]: 0 : if (!allow_additional) {
571 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
572 : : "array has undefined item");
573 : 0 : ret = false;
574 : 0 : }
575 [ # # ]: 0 : else if (additional_schema != NULL) {
576 : 0 : elt = ucl_array_find_index (obj, idx);
577 [ # # ]: 0 : while (elt) {
578 [ # # # # ]: 0 : if (!ucl_schema_validate (additional_schema, elt, false,
579 : 0 : err, root, ext_ref)) {
580 : 0 : ret = false;
581 : 0 : break;
582 : : }
583 : 0 : elt = ucl_array_find_index (obj, idx ++);
584 : : }
585 : 0 : }
586 : 0 : }
587 : 0 : }
588 : : /* Required properties */
589 [ + - + + ]: 64 : if (ret && need_unique) {
590 : 60 : ret = ucl_schema_array_is_unique (obj, err);
591 : 60 : }
592 : 64 : }
593 : :
594 : 64 : return ret;
595 : : }
596 : :
597 : : /*
598 : : * Returns whether this object is allowed for this type
599 : : */
600 : : static bool
601 : 13737 : ucl_schema_type_is_allowed (const ucl_object_t *type, const ucl_object_t *obj,
602 : : struct ucl_schema_error *err)
603 : : {
604 : 13737 : ucl_object_iter_t iter = NULL;
605 : : const ucl_object_t *elt;
606 : : const char *type_str;
607 : : ucl_type_t t;
608 : :
609 [ + + ]: 13737 : if (type == NULL) {
610 : : /* Any type is allowed */
611 : 5543 : return true;
612 : : }
613 : :
614 [ - + ]: 8194 : if (type->type == UCL_ARRAY) {
615 : : /* One of allowed types */
616 [ # # ]: 0 : while ((elt = ucl_object_iterate (type, &iter, true)) != NULL) {
617 [ # # ]: 0 : if (ucl_schema_type_is_allowed (elt, obj, err)) {
618 : 0 : return true;
619 : : }
620 : : }
621 : 0 : }
622 [ - + ]: 8194 : else if (type->type == UCL_STRING) {
623 : 8194 : type_str = ucl_object_tostring (type);
624 [ + - ]: 8194 : if (!ucl_object_string_to_type (type_str, &t)) {
625 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, type,
626 : : "Type attribute is invalid in schema");
627 : 0 : return false;
628 : : }
629 [ - + ]: 8194 : if (obj->type != t) {
630 : : /* Some types are actually compatible */
631 [ # # # # ]: 0 : if (obj->type == UCL_TIME && t == UCL_FLOAT) {
632 : 0 : return true;
633 : : }
634 [ # # # # ]: 0 : else if (obj->type == UCL_INT && t == UCL_FLOAT) {
635 : 0 : return true;
636 : : }
637 : : else {
638 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_TYPE_MISMATCH, obj,
639 : : "Invalid type of %s, expected %s",
640 : 0 : ucl_object_type_to_string (obj->type),
641 : 0 : ucl_object_type_to_string (t));
642 : : }
643 : 0 : }
644 : : else {
645 : : /* Types are equal */
646 : 8194 : return true;
647 : : }
648 : 0 : }
649 : :
650 : 0 : return false;
651 : 13737 : }
652 : :
653 : : /*
654 : : * Check if object is equal to one of elements of enum
655 : : */
656 : : static bool
657 : 1319 : ucl_schema_validate_enum (const ucl_object_t *en, const ucl_object_t *obj,
658 : : struct ucl_schema_error *err)
659 : : {
660 : 1319 : ucl_object_iter_t iter = NULL;
661 : : const ucl_object_t *elt;
662 : 1319 : bool ret = false;
663 : :
664 [ - + ]: 2630 : while ((elt = ucl_object_iterate (en, &iter, true)) != NULL) {
665 [ + + ]: 2630 : if (ucl_object_compare (elt, obj) == 0) {
666 : 1319 : ret = true;
667 : 1319 : break;
668 : : }
669 : : }
670 : :
671 [ + - ]: 1319 : if (!ret) {
672 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
673 : : "object is not one of enumerated patterns");
674 : 0 : }
675 : :
676 : 1319 : return ret;
677 : : }
678 : :
679 : :
680 : : /*
681 : : * Check a single ref component
682 : : */
683 : : static const ucl_object_t *
684 : 0 : ucl_schema_resolve_ref_component (const ucl_object_t *cur,
685 : : const char *refc, int len,
686 : : struct ucl_schema_error *err)
687 : : {
688 : 0 : const ucl_object_t *res = NULL;
689 : : char *err_str;
690 : : int num, i;
691 : :
692 [ # # ]: 0 : if (cur->type == UCL_OBJECT) {
693 : : /* Find a key inside an object */
694 : 0 : res = ucl_object_lookup_len (cur, refc, len);
695 [ # # ]: 0 : if (res == NULL) {
696 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
697 : 0 : "reference %s is invalid, missing path component", refc);
698 : 0 : return NULL;
699 : : }
700 : 0 : }
701 [ # # ]: 0 : else if (cur->type == UCL_ARRAY) {
702 : : /* We must figure out a number inside array */
703 : 0 : num = strtoul (refc, &err_str, 10);
704 [ # # # # : 0 : if (err_str != NULL && *err_str != '/' && *err_str != '\0') {
# # ]
705 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
706 : 0 : "reference %s is invalid, invalid item number", refc);
707 : 0 : return NULL;
708 : : }
709 : 0 : res = ucl_array_head (cur);
710 : 0 : i = 0;
711 [ # # ]: 0 : while (res != NULL) {
712 [ # # ]: 0 : if (i == num) {
713 : 0 : break;
714 : : }
715 : 0 : res = res->next;
716 : : }
717 [ # # ]: 0 : if (res == NULL) {
718 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
719 : : "reference %s is invalid, item number %d does not exist",
720 : 0 : refc, num);
721 : 0 : return NULL;
722 : : }
723 : 0 : }
724 : : else {
725 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
726 : : "reference %s is invalid, contains primitive object in the path",
727 : 0 : refc);
728 : 0 : return NULL;
729 : : }
730 : :
731 : 0 : return res;
732 : 0 : }
733 : : /*
734 : : * Find reference schema
735 : : */
736 : : static const ucl_object_t *
737 : 0 : ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
738 : : struct ucl_schema_error *err, ucl_object_t *ext_ref,
739 : : ucl_object_t const ** nroot)
740 : : {
741 : 0 : UT_string *url_err = NULL;
742 : : struct ucl_parser *parser;
743 : 0 : const ucl_object_t *res = NULL, *ext_obj = NULL;
744 : : ucl_object_t *url_obj;
745 : 0 : const char *p, *c, *hash_ptr = NULL;
746 : 0 : char *url_copy = NULL;
747 : : unsigned char *url_buf;
748 : : size_t url_buflen;
749 : :
750 [ # # ]: 0 : if (ref[0] != '#') {
751 : 0 : hash_ptr = strrchr (ref, '#');
752 : :
753 [ # # ]: 0 : if (hash_ptr) {
754 : 0 : url_copy = malloc (hash_ptr - ref + 1);
755 : :
756 [ # # ]: 0 : if (url_copy == NULL) {
757 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INTERNAL_ERROR, root,
758 : : "cannot allocate memory");
759 : 0 : return NULL;
760 : : }
761 : :
762 : 0 : ucl_strlcpy (url_copy, ref, hash_ptr - ref + 1);
763 : 0 : p = url_copy;
764 : 0 : }
765 : : else {
766 : : /* Full URL */
767 : 0 : p = ref;
768 : : }
769 : :
770 : 0 : ext_obj = ucl_object_lookup (ext_ref, p);
771 : :
772 [ # # ]: 0 : if (ext_obj == NULL) {
773 [ # # ]: 0 : if (ucl_strnstr (p, "://", strlen (p)) != NULL) {
774 [ # # ]: 0 : if (!ucl_fetch_url (p, &url_buf, &url_buflen, &url_err, true)) {
775 : :
776 : 0 : ucl_schema_create_error (err,
777 : : UCL_SCHEMA_INVALID_SCHEMA,
778 : 0 : root,
779 : : "cannot fetch reference %s: %s",
780 : 0 : p,
781 [ # # ]: 0 : url_err != NULL ? utstring_body (url_err)
782 : : : "unknown");
783 : 0 : free (url_copy);
784 : :
785 : 0 : return NULL;
786 : : }
787 : 0 : }
788 : : else {
789 [ # # ]: 0 : if (!ucl_fetch_file (p, &url_buf, &url_buflen, &url_err,
790 : : true)) {
791 : 0 : ucl_schema_create_error (err,
792 : : UCL_SCHEMA_INVALID_SCHEMA,
793 : 0 : root,
794 : : "cannot fetch reference %s: %s",
795 : 0 : p,
796 [ # # ]: 0 : url_err != NULL ? utstring_body (url_err)
797 : : : "unknown");
798 : 0 : free (url_copy);
799 : :
800 : 0 : return NULL;
801 : : }
802 : : }
803 : :
804 : 0 : parser = ucl_parser_new (0);
805 : :
806 [ # # ]: 0 : if (!ucl_parser_add_chunk (parser, url_buf, url_buflen)) {
807 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
808 : 0 : "cannot fetch reference %s: %s", p,
809 : 0 : ucl_parser_get_error (parser));
810 : 0 : ucl_parser_free (parser);
811 : 0 : free (url_copy);
812 : :
813 : 0 : return NULL;
814 : : }
815 : :
816 : 0 : url_obj = ucl_parser_get_object (parser);
817 : 0 : ext_obj = url_obj;
818 : 0 : ucl_object_insert_key (ext_ref, url_obj, p, 0, true);
819 : 0 : free (url_buf);
820 : 0 : }
821 : :
822 : 0 : free (url_copy);
823 : :
824 [ # # ]: 0 : if (hash_ptr) {
825 : 0 : p = hash_ptr + 1;
826 : 0 : }
827 : : else {
828 : 0 : p = "";
829 : : }
830 : 0 : }
831 : : else {
832 : 0 : p = ref + 1;
833 : : }
834 : :
835 [ # # ]: 0 : res = ext_obj != NULL ? ext_obj : root;
836 : 0 : *nroot = res;
837 : :
838 [ # # ]: 0 : if (*p == '/') {
839 : 0 : p++;
840 : 0 : }
841 [ # # ]: 0 : else if (*p == '\0') {
842 : 0 : return res;
843 : : }
844 : :
845 : 0 : c = p;
846 : :
847 [ # # ]: 0 : while (*p != '\0') {
848 [ # # ]: 0 : if (*p == '/') {
849 [ # # ]: 0 : if (p - c == 0) {
850 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
851 : 0 : "reference %s is invalid, empty path component", ref);
852 : 0 : return NULL;
853 : : }
854 : : /* Now we have some url part, so we need to figure out where we are */
855 : 0 : res = ucl_schema_resolve_ref_component (res, c, p - c, err);
856 [ # # ]: 0 : if (res == NULL) {
857 : 0 : return NULL;
858 : : }
859 : 0 : c = p + 1;
860 : 0 : }
861 : 0 : p ++;
862 : : }
863 : :
864 [ # # ]: 0 : if (p - c != 0) {
865 : 0 : res = ucl_schema_resolve_ref_component (res, c, p - c, err);
866 : 0 : }
867 : :
868 [ # # # # ]: 0 : if (res == NULL || res->type != UCL_OBJECT) {
869 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, res,
870 : : "reference %s is invalid, cannot find specified object",
871 : 0 : ref);
872 : 0 : return NULL;
873 : : }
874 : :
875 : 0 : return res;
876 : 0 : }
877 : :
878 : : static bool
879 : 13697 : ucl_schema_validate_values (const ucl_object_t *schema, const ucl_object_t *obj,
880 : : struct ucl_schema_error *err)
881 : : {
882 : : const ucl_object_t *elt, *cur;
883 : : int64_t constraint, i;
884 : :
885 : 13697 : elt = ucl_object_lookup (schema, "maxValues");
886 [ - + # # ]: 13697 : if (elt != NULL && elt->type == UCL_INT) {
887 : 0 : constraint = ucl_object_toint (elt);
888 : 0 : cur = obj;
889 : 0 : i = 0;
890 [ # # ]: 0 : while (cur) {
891 [ # # ]: 0 : if (i > constraint) {
892 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
893 : : "object has more values than defined: %ld",
894 : 0 : (long int)constraint);
895 : 0 : return false;
896 : : }
897 : 0 : i ++;
898 : 0 : cur = cur->next;
899 : : }
900 : 0 : }
901 : 13697 : elt = ucl_object_lookup (schema, "minValues");
902 [ - + # # ]: 13697 : if (elt != NULL && elt->type == UCL_INT) {
903 : 0 : constraint = ucl_object_toint (elt);
904 : 0 : cur = obj;
905 : 0 : i = 0;
906 [ # # ]: 0 : while (cur) {
907 [ # # ]: 0 : if (i >= constraint) {
908 : 0 : break;
909 : : }
910 : 0 : i ++;
911 : 0 : cur = cur->next;
912 : : }
913 [ # # ]: 0 : if (i < constraint) {
914 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
915 : : "object has less values than defined: %ld",
916 : 0 : (long int)constraint);
917 : 0 : return false;
918 : : }
919 : 0 : }
920 : :
921 : 13697 : return true;
922 : 13697 : }
923 : :
924 : : static bool
925 : 27434 : ucl_schema_validate (const ucl_object_t *schema,
926 : : const ucl_object_t *obj, bool try_array,
927 : : struct ucl_schema_error *err,
928 : : const ucl_object_t *root,
929 : : ucl_object_t *external_refs)
930 : : {
931 : : const ucl_object_t *elt, *cur, *ref_root;
932 : 27434 : ucl_object_iter_t iter = NULL;
933 : : bool ret;
934 : :
935 [ - + ]: 27434 : if (schema->type != UCL_OBJECT) {
936 : 0 : ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, schema,
937 : : "schema is %s instead of object",
938 : 0 : ucl_object_type_to_string (schema->type));
939 : 0 : return false;
940 : : }
941 : :
942 [ + + ]: 27434 : if (try_array) {
943 : : /*
944 : : * Special case for multiple values
945 : : */
946 [ + - ]: 13697 : if (!ucl_schema_validate_values (schema, obj, err)) {
947 : 0 : return false;
948 : : }
949 [ + + ]: 27402 : LL_FOREACH (obj, cur) {
950 [ + - ]: 13705 : if (!ucl_schema_validate (schema, cur, false, err, root, external_refs)) {
951 : 0 : return false;
952 : : }
953 : 13705 : }
954 : 13697 : return true;
955 : : }
956 : :
957 : 13737 : elt = ucl_object_lookup (schema, "enum");
958 [ + + - + ]: 13737 : if (elt != NULL && elt->type == UCL_ARRAY) {
959 [ + - ]: 1319 : if (!ucl_schema_validate_enum (elt, obj, err)) {
960 : 0 : return false;
961 : : }
962 : 1319 : }
963 : :
964 : 13737 : elt = ucl_object_lookup (schema, "allOf");
965 [ - + # # ]: 13737 : if (elt != NULL && elt->type == UCL_ARRAY) {
966 : 0 : iter = NULL;
967 [ # # ]: 0 : while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
968 : 0 : ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
969 [ # # ]: 0 : if (!ret) {
970 : 0 : return false;
971 : : }
972 : : }
973 : 0 : }
974 : :
975 : 13737 : elt = ucl_object_lookup (schema, "anyOf");
976 [ - + # # ]: 13737 : if (elt != NULL && elt->type == UCL_ARRAY) {
977 : 0 : iter = NULL;
978 [ # # ]: 0 : while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
979 : 0 : ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
980 [ # # ]: 0 : if (ret) {
981 : 0 : break;
982 : : }
983 : : }
984 [ # # ]: 0 : if (!ret) {
985 : 0 : return false;
986 : : }
987 : : else {
988 : : /* Reset error */
989 : 0 : err->code = UCL_SCHEMA_OK;
990 : : }
991 : 0 : }
992 : :
993 : 13737 : elt = ucl_object_lookup (schema, "oneOf");
994 [ - + # # ]: 13737 : if (elt != NULL && elt->type == UCL_ARRAY) {
995 : 0 : iter = NULL;
996 : 0 : ret = false;
997 [ # # ]: 0 : while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
998 [ # # ]: 0 : if (!ret) {
999 : 0 : ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
1000 : 0 : }
1001 [ # # ]: 0 : else if (ucl_schema_validate (cur, obj, true, err, root, external_refs)) {
1002 : 0 : ret = false;
1003 : 0 : break;
1004 : : }
1005 : : }
1006 [ # # ]: 0 : if (!ret) {
1007 : 0 : return false;
1008 : : }
1009 : 0 : }
1010 : :
1011 : 13737 : elt = ucl_object_lookup (schema, "not");
1012 [ - + # # ]: 13737 : if (elt != NULL && elt->type == UCL_OBJECT) {
1013 [ # # ]: 0 : if (ucl_schema_validate (elt, obj, true, err, root, external_refs)) {
1014 : 0 : return false;
1015 : : }
1016 : : else {
1017 : : /* Reset error */
1018 : 0 : err->code = UCL_SCHEMA_OK;
1019 : : }
1020 : 0 : }
1021 : :
1022 : 13737 : elt = ucl_object_lookup (schema, "$ref");
1023 [ + - ]: 13737 : if (elt != NULL) {
1024 : 0 : ref_root = root;
1025 : 0 : cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt),
1026 : 0 : err, external_refs, &ref_root);
1027 : :
1028 [ # # ]: 0 : if (cur == NULL) {
1029 : 0 : return false;
1030 : : }
1031 [ # # # # ]: 0 : if (!ucl_schema_validate (cur, obj, try_array, err, ref_root,
1032 : 0 : external_refs)) {
1033 : 0 : return false;
1034 : : }
1035 : 0 : }
1036 : :
1037 : 13737 : elt = ucl_object_lookup (schema, "type");
1038 [ + - ]: 13737 : if (!ucl_schema_type_is_allowed (elt, obj, err)) {
1039 : 0 : return false;
1040 : : }
1041 : :
1042 [ + + + + : 13737 : switch (obj->type) {
+ ]
1043 : : case UCL_OBJECT:
1044 : 5631 : return ucl_schema_validate_object (schema, obj, err, root, external_refs);
1045 : : break;
1046 : : case UCL_ARRAY:
1047 : 64 : return ucl_schema_validate_array (schema, obj, err, root, external_refs);
1048 : : break;
1049 : : case UCL_INT:
1050 : : case UCL_FLOAT:
1051 : 1319 : return ucl_schema_validate_number (schema, obj, err);
1052 : : break;
1053 : : case UCL_STRING:
1054 : 6647 : return ucl_schema_validate_string (schema, obj, err);
1055 : : break;
1056 : : default:
1057 : 76 : break;
1058 : : }
1059 : :
1060 : 76 : return true;
1061 : 27434 : }
1062 : :
1063 : : bool
1064 : 5619 : ucl_object_validate (const ucl_object_t *schema,
1065 : : const ucl_object_t *obj, struct ucl_schema_error *err)
1066 : : {
1067 : 5619 : return ucl_object_validate_root_ext (schema, obj, schema, NULL, err);
1068 : : }
1069 : :
1070 : : bool
1071 : 0 : ucl_object_validate_root (const ucl_object_t *schema,
1072 : : const ucl_object_t *obj,
1073 : : const ucl_object_t *root,
1074 : : struct ucl_schema_error *err)
1075 : : {
1076 : 0 : return ucl_object_validate_root_ext (schema, obj, root, NULL, err);
1077 : : }
1078 : :
1079 : : bool
1080 : 5619 : ucl_object_validate_root_ext (const ucl_object_t *schema,
1081 : : const ucl_object_t *obj,
1082 : : const ucl_object_t *root,
1083 : : ucl_object_t *ext_refs,
1084 : : struct ucl_schema_error *err)
1085 : : {
1086 : 5619 : bool ret, need_unref = false;
1087 : :
1088 [ + - ]: 5619 : if (ext_refs == NULL) {
1089 : 5619 : ext_refs = ucl_object_typed_new (UCL_OBJECT);
1090 : 5619 : need_unref = true;
1091 : 5619 : }
1092 : :
1093 : 5619 : ret = ucl_schema_validate (schema, obj, true, err, root, ext_refs);
1094 : :
1095 [ - + ]: 5619 : if (need_unref) {
1096 : 5619 : ucl_object_unref (ext_refs);
1097 : 5619 : }
1098 : :
1099 : 5619 : return ret;
1100 : : }
|