blob: d2a1c0c275380b2db839f0e60e8c1a52f4673a61 [file] [log] [blame]
Radek Krejci1721c012015-07-08 12:52:33 +02001/**
2 * @file xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
22#include <assert.h>
Radek Krejci3e3affe2015-07-09 15:38:40 +020023#include <ctype.h>
Radek Krejci1721c012015-07-08 12:52:33 +020024#include <errno.h>
25#include <stdlib.h>
26#include <string.h>
Michal Vaskobe190a62015-07-13 16:14:20 +020027#include <sys/types.h>
28#include <regex.h>
Radek Krejci1721c012015-07-08 12:52:33 +020029
30#include "../libyang.h"
31#include "../common.h"
32#include "../context.h"
33#include "../xml.h"
Radek Krejciac8aac62015-07-10 15:36:35 +020034#include "../tree_internal.h"
Radek Krejci1721c012015-07-08 12:52:33 +020035
36#define LY_NSNC "urn:ietf:params:xml:ns:netconf:base:1.0"
37
Michal Vasko9286afd2015-07-14 15:27:59 +020038/* kind == 0 - unsigned (unum used), 1 - signed (snum used), 2 - floating point (fnum used) */
39static int
Michal Vasko07471a52015-07-16 11:18:48 +020040validate_length_range(uint8_t kind, uint64_t unum, int64_t snum, long double fnum, struct ly_type *type,
41 struct lyxml_elem *xml, const char *str_val, int log)
Michal Vasko9286afd2015-07-14 15:27:59 +020042{
Michal Vasko020404f2015-07-15 15:45:42 +020043 struct len_ran_intv *intv = NULL, *tmp_intv;
Michal Vasko9286afd2015-07-14 15:27:59 +020044 int ret = 1;
45
Michal Vasko020404f2015-07-15 15:45:42 +020046 assert(!get_len_ran_interval(NULL, type, 0, &intv));
47 if (!intv) {
48 return 0;
49 }
50
Michal Vasko9286afd2015-07-14 15:27:59 +020051 for (tmp_intv = intv; tmp_intv; tmp_intv = tmp_intv->next) {
52 if (((kind == 0) && (unum < tmp_intv->value.uval.min))
53 || ((kind == 1) && (snum < tmp_intv->value.sval.min))
54 || ((kind == 2) && (fnum < tmp_intv->value.fval.min))) {
55 break;
56 }
57
58 if (((kind == 0) && (unum >= tmp_intv->value.uval.min) && (unum <= tmp_intv->value.uval.max))
59 || ((kind == 1) && (snum >= tmp_intv->value.sval.min) && (snum <= tmp_intv->value.sval.max))
60 || ((kind == 2) && (fnum >= tmp_intv->value.fval.min) && (fnum <= tmp_intv->value.fval.max))) {
61 ret = 0;
62 break;
63 }
64 }
65
66 while (intv) {
67 tmp_intv = intv->next;
68 free(intv);
69 intv = tmp_intv;
70 }
71
Michal Vasko07471a52015-07-16 11:18:48 +020072 if (ret && log) {
73 ly_errno = LY_EVALID;
Michal Vasko0e60c832015-07-15 15:48:35 +020074 LOGVAL(DE_OORVAL, LOGLINE(xml), str_val);
75 }
Michal Vasko9286afd2015-07-14 15:27:59 +020076 return ret;
77}
78
Michal Vaskofbf7e482015-07-14 14:49:03 +020079static int
Michal Vasko07471a52015-07-16 11:18:48 +020080validate_pattern(const char *str, struct ly_type *type, struct lyxml_elem *xml, const char *str_val, int log)
Michal Vaskofbf7e482015-07-14 14:49:03 +020081{
82 int i;
83 regex_t preq;
84 char *posix_regex;
85
86 assert(type->base == LY_TYPE_STRING);
87
Michal Vasko07471a52015-07-16 11:18:48 +020088 if (type->der && validate_pattern(str, &type->der->type, xml, str_val, log)) {
Michal Vaskofbf7e482015-07-14 14:49:03 +020089 return 1;
90 }
91
92 for (i = 0; i < type->info.str.pat_count; ++i) {
93 /*
94 * adjust the expression to a POSIX.2 equivalent
95 *
96 * http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs
97 */
98 posix_regex = malloc((strlen(type->info.str.patterns[i].expr)+3) * sizeof(char));
99 posix_regex[0] = '\0';
100
101 if (strncmp(type->info.str.patterns[i].expr, ".*", 2)) {
102 strcat(posix_regex, "^");
103 }
104 strcat(posix_regex, type->info.str.patterns[i].expr);
105 if (strncmp(type->info.str.patterns[i].expr
106 + strlen(type->info.str.patterns[i].expr) - 2, ".*", 2)) {
107 strcat(posix_regex, "$");
108 }
109
110 /* must return 0, already checked during parsing */
111 assert(!regcomp(&preq, posix_regex, REG_EXTENDED | REG_NOSUB));
112 free(posix_regex);
113
114 if (regexec(&preq, str, 0, 0, 0)) {
115 regfree(&preq);
Michal Vasko07471a52015-07-16 11:18:48 +0200116 ly_errno = LY_EVALID;
117 if (log) {
118 LOGVAL(DE_INVAL, LOGLINE(xml), str_val, xml->name);
119 }
Michal Vaskofbf7e482015-07-14 14:49:03 +0200120 return 1;
121 }
122 regfree(&preq);
123 }
124
125 return 0;
126}
127
Radek Krejcie4748472015-07-08 18:00:22 +0200128static struct ly_mnode *
Radek Krejci1721c012015-07-08 12:52:33 +0200129xml_data_search_schemanode(struct lyxml_elem *xml, struct ly_mnode *start)
130{
131 struct ly_mnode *result, *aux;
132
133 LY_TREE_FOR(start, result) {
134 /* skip groupings */
135 if (result->nodetype == LY_NODE_GROUPING) {
136 continue;
137 }
138
139 /* go into cases, choices, uses */
140 if (result->nodetype & (LY_NODE_CHOICE | LY_NODE_CASE | LY_NODE_USES)) {
141 aux = xml_data_search_schemanode(xml, result->child);
142 if (aux) {
143 /* we have matching result */
144 return aux;
145 }
146 /* else, continue with next schema node */
147 continue;
148 }
149
150 /* match data nodes */
151 if (result->name == xml->name) {
152 /* names matches, what about namespaces? */
153 if (result->module->ns == xml->ns->value) {
154 /* we have matching result */
155 return result;
156 }
157 /* else, continue with next schema node */
158 continue;
159 }
160 }
161
162 /* no match */
163 return NULL;
164}
165
Radek Krejcie4748472015-07-08 18:00:22 +0200166static int
Michal Vasko07471a52015-07-16 11:18:48 +0200167parse_int(const char *str_val, struct lyxml_elem *xml, int64_t min, int64_t max, int base, int64_t *ret, int log)
Michal Vaskobdee69c2015-07-15 15:49:39 +0200168{
169 char *strptr;
170
171 /* convert to 64-bit integer, all the redundant characters are handled */
172 errno = 0;
173 strptr = NULL;
174 *ret = strtoll(str_val, &strptr, base);
175 if (errno || (*ret < min) || (*ret > max)) {
Michal Vasko07471a52015-07-16 11:18:48 +0200176 if (log) {
177 LOGVAL(DE_OORVAL, LOGLINE(xml), str_val, xml->name);
178 }
Michal Vaskobdee69c2015-07-15 15:49:39 +0200179 return 1;
180 } else if (strptr && *strptr) {
181 while (isspace(*strptr)) {
182 ++strptr;
183 }
184 if (*strptr) {
Michal Vasko07471a52015-07-16 11:18:48 +0200185 ly_errno = LY_EVALID;
186 if (log) {
187 LOGVAL(DE_INVAL, LOGLINE(xml), str_val, xml->name);
188 }
Michal Vaskobdee69c2015-07-15 15:49:39 +0200189 return 1;
190 }
191 }
192
193 return 0;
194}
195
196static int
Michal Vasko07471a52015-07-16 11:18:48 +0200197parse_uint(const char *str_val, struct lyxml_elem *xml, uint64_t max, int base, uint64_t *ret, int log)
Michal Vaskobdee69c2015-07-15 15:49:39 +0200198{
199 char *strptr;
200
201 errno = 0;
202 strptr = NULL;
203 *ret = strtoull(str_val, &strptr, base);
204 if (errno || (*ret > max)) {
Michal Vasko07471a52015-07-16 11:18:48 +0200205 if (log) {
206 LOGVAL(DE_OORVAL, LOGLINE(xml), str_val, xml->name);
207 }
Michal Vaskobdee69c2015-07-15 15:49:39 +0200208 return 1;
209 } else if (strptr && *strptr) {
210 while (isspace(*strptr)) {
211 ++strptr;
212 }
213 if (*strptr) {
Michal Vasko07471a52015-07-16 11:18:48 +0200214 ly_errno = LY_EVALID;
215 if (log) {
216 LOGVAL(DE_INVAL, LOGLINE(xml), str_val, xml->name);
217 }
Michal Vaskobdee69c2015-07-15 15:49:39 +0200218 return 1;
219 }
220 }
221
222 return 0;
223}
224
Michal Vasko07471a52015-07-16 11:18:48 +0200225static struct ly_type *
226get_next_union_type(struct ly_type *uni_type, int count, struct ly_type *prev_type, int *found)
Radek Krejcie4748472015-07-08 18:00:22 +0200227{
Michal Vasko07471a52015-07-16 11:18:48 +0200228 int i;
229 struct ly_type *type = NULL;
230
231 for (i = 0; i < count; ++i) {
232 if (uni_type[i].base == LY_TYPE_UNION) {
233 type = get_next_union_type(uni_type[i].info.uni.type, uni_type[i].info.uni.count, prev_type, found);
234 if (type) {
235 break;;
236 }
237 continue;
238 }
239
240 if (!prev_type || *found) {
241 type = &uni_type[i];
242 break;
243 }
244
245 if (&uni_type[i] == prev_type) {
246 *found = 1;
247 }
248 }
249
250 return type;
251}
252
253static int
254_xml_get_value(struct lyd_node *node, struct ly_type *node_type, struct lyxml_elem *xml,
Michal Vasko493bea72015-07-16 16:08:12 +0200255 struct leafref_instid **unres, int log)
Michal Vasko07471a52015-07-16 11:18:48 +0200256{
257 #define DECSIZE 21
Radek Krejci3e3affe2015-07-09 15:38:40 +0200258 struct lyd_node_leaf *leaf = (struct lyd_node_leaf *)node;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200259 struct ly_type *type;
Radek Krejciac8aac62015-07-10 15:36:35 +0200260 struct lyxml_ns *ns;
Radek Krejci7511f402015-07-10 09:56:30 +0200261 char dec[DECSIZE];
Michal Vaskofbf7e482015-07-14 14:49:03 +0200262 char *strptr;
Radek Krejciac8aac62015-07-10 15:36:35 +0200263 const char *name;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200264 int64_t num;
265 uint64_t unum;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200266 int len;
Radek Krejci7511f402015-07-10 09:56:30 +0200267 int c, i, j, d;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200268 int found;
Michal Vasko493bea72015-07-16 16:08:12 +0200269 struct leafref_instid *new_unres;
Radek Krejci5a988152015-07-15 11:16:26 +0200270
271 leaf->value_str = xml->content;
272 xml->content = NULL;
Radek Krejcie4748472015-07-08 18:00:22 +0200273
Michal Vasko07471a52015-07-16 11:18:48 +0200274 switch (node_type->base) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200275 case LY_TYPE_BINARY:
Radek Krejci5a988152015-07-15 11:16:26 +0200276 leaf->value.binary = leaf->value_str;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200277 leaf->value_type = LY_TYPE_BINARY;
278
Michal Vasko07471a52015-07-16 11:18:48 +0200279 if (node_type->info.binary.length
280 && validate_length_range(0, strlen(leaf->value.binary), 0, 0, node_type, xml, leaf->value_str, log)) {
Michal Vasko0e60c832015-07-15 15:48:35 +0200281 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200282 }
283 break;
284
Radek Krejci3e3affe2015-07-09 15:38:40 +0200285 case LY_TYPE_BITS:
286 leaf->value_type = LY_TYPE_BITS;
Radek Krejcie4748472015-07-08 18:00:22 +0200287
Radek Krejci3e3affe2015-07-09 15:38:40 +0200288 /* locate bits structure with the bits definitions */
Michal Vasko07471a52015-07-16 11:18:48 +0200289 for (type = node_type; type->der->type.der; type = &type->der->type);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200290
291 /* allocate the array of pointers to bits definition */
292 leaf->value.bit = calloc(type->info.bits.count, sizeof *leaf->value.bit);
293
Radek Krejci5a988152015-07-15 11:16:26 +0200294 if (!leaf->value_str) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200295 /* no bits set */
296 break;
297 }
298
299 c = 0;
300 i = 0;
Radek Krejci5a988152015-07-15 11:16:26 +0200301 while (leaf->value_str[c]) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200302 /* skip leading whitespaces */
Radek Krejci5a988152015-07-15 11:16:26 +0200303 while(isspace(leaf->value_str[c])) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200304 c++;
305 }
306
307 /* get the length of the bit identifier */
Radek Krejci5a988152015-07-15 11:16:26 +0200308 for (len = 0; leaf->value_str[c] && !isspace(leaf->value_str[c]); c++, len++);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200309
310 /* go back to the beginning of the identifier */
311 c = c - len;
312
313 /* find bit definition, identifiers appear ordered by their posititon */
314 for (found = 0; i < type->info.bits.count; i++) {
Radek Krejci5a988152015-07-15 11:16:26 +0200315 if (!strncmp(type->info.bits.bit[i].name, &leaf->value_str[c], len)
Radek Krejci3e3affe2015-07-09 15:38:40 +0200316 && !type->info.bits.bit[i].name[len]) {
317 /* we have match, store the pointer */
318 leaf->value.bit[i] = &type->info.bits.bit[i];
319
320 /* stop searching */
321 i++;
322 found = 1;
323 break;
324 }
325 }
326
327 if (!found) {
328 /* referenced bit value does not exists */
Michal Vasko07471a52015-07-16 11:18:48 +0200329 if (log) {
330 LOGVAL(DE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
331 }
Radek Krejci3e3affe2015-07-09 15:38:40 +0200332 return EXIT_FAILURE;
333 }
334
335 c = c + len;
336 }
337
338 break;
339
Radek Krejcib7384642015-07-09 16:08:45 +0200340 case LY_TYPE_BOOL:
Radek Krejci5a988152015-07-15 11:16:26 +0200341 if (!strcmp(leaf->value_str, "true")) {
Radek Krejcib7384642015-07-09 16:08:45 +0200342 leaf->value.bool = 1;
343 } /* else false, so keep it zero */
344 break;
345
Radek Krejci7511f402015-07-10 09:56:30 +0200346 case LY_TYPE_DEC64:
347 /* locate dec64 structure with the fraction-digits value */
Michal Vasko07471a52015-07-16 11:18:48 +0200348 for (type = node_type; type->der->type.der; type = &type->der->type);
Radek Krejci7511f402015-07-10 09:56:30 +0200349
Radek Krejci5a988152015-07-15 11:16:26 +0200350 for (c = 0; isspace(leaf->value_str[c]); c++);
351 for (len = 0; leaf->value_str[c] && !isspace(leaf->value_str[c]); c++, len++);
Radek Krejci7511f402015-07-10 09:56:30 +0200352 c = c - len;
353 if (len > DECSIZE) {
354 /* too long */
Michal Vasko07471a52015-07-16 11:18:48 +0200355 if (log) {
356 LOGVAL(DE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
357 }
Radek Krejci7511f402015-07-10 09:56:30 +0200358 return EXIT_FAILURE;
359 }
360
361 /* normalize the number */
362 dec[0] = '\0';
363 for (i = j = d = found = 0; i < DECSIZE; i++) {
Radek Krejci5a988152015-07-15 11:16:26 +0200364 if (leaf->value_str[c + i] == '.') {
Radek Krejci7511f402015-07-10 09:56:30 +0200365 found = 1;
366 j = type->info.dec64.dig;
367 i--;
368 c++;
369 continue;
370 }
Radek Krejci5a988152015-07-15 11:16:26 +0200371 if (leaf->value_str[c + i] == '\0') {
Radek Krejci7511f402015-07-10 09:56:30 +0200372 c--;
373 if (!found) {
374 j = type->info.dec64.dig;
375 found = 1;
376 }
377 if (!j) {
378 dec[i] = '\0';
379 break;
380 }
381 d++;
382 if (d > DECSIZE - 2) {
Michal Vasko07471a52015-07-16 11:18:48 +0200383 if (log) {
384 LOGVAL(DE_OORVAL, LOGLINE(xml), leaf->value_str, xml->name);
385 }
Radek Krejci7511f402015-07-10 09:56:30 +0200386 return EXIT_FAILURE;
387 }
388 dec[i] = '0';
389 } else {
Radek Krejci5a988152015-07-15 11:16:26 +0200390 if (!isdigit(leaf->value_str[c + i])) {
391 if (i || leaf->value_str[c] != '-') {
Michal Vasko07471a52015-07-16 11:18:48 +0200392 if (log) {
393 LOGVAL(DE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
394 }
Radek Krejci7511f402015-07-10 09:56:30 +0200395 return EXIT_FAILURE;
396 }
397 } else {
398 d++;
399 }
400 if (d > DECSIZE - 2 || (found && !j)) {
Michal Vasko07471a52015-07-16 11:18:48 +0200401 if (log) {
402 LOGVAL(DE_OORVAL, LOGLINE(xml), leaf->value_str, xml->name);
403 }
Radek Krejci7511f402015-07-10 09:56:30 +0200404 return EXIT_FAILURE;
405 }
Radek Krejci5a988152015-07-15 11:16:26 +0200406 dec[i] = leaf->value_str[c + i];
Radek Krejci7511f402015-07-10 09:56:30 +0200407 }
408 if (j) {
409 j--;
410 }
411 }
412
Michal Vasko07471a52015-07-16 11:18:48 +0200413 if (parse_int(dec, xml, -9223372036854775807L - 1L, 9223372036854775807L, 10, &num, log)
414 || validate_length_range(2, 0, 0, ((long double)num)/(1 << type->info.dec64.dig), node_type, xml, leaf->value_str, log)) {
Radek Krejci7511f402015-07-10 09:56:30 +0200415 return EXIT_FAILURE;
416 }
Michal Vaskobdee69c2015-07-15 15:49:39 +0200417 leaf->value.dec64 = num;
Radek Krejci7511f402015-07-10 09:56:30 +0200418 break;
419
Radek Krejcibce73742015-07-10 12:46:06 +0200420 case LY_TYPE_EMPTY:
421 /* just check that it is empty */
Radek Krejci5a988152015-07-15 11:16:26 +0200422 if (leaf->value_str && leaf->value_str[0]) {
Michal Vasko07471a52015-07-16 11:18:48 +0200423 if (log) {
424 LOGVAL(DE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
425 }
Radek Krejcibce73742015-07-10 12:46:06 +0200426 return EXIT_FAILURE;
427 }
428 break;
429
Radek Krejci5b315a92015-07-10 13:18:45 +0200430 case LY_TYPE_ENUM:
Radek Krejci5a988152015-07-15 11:16:26 +0200431 if (!leaf->value_str) {
Michal Vasko07471a52015-07-16 11:18:48 +0200432 if (log) {
433 LOGVAL(DE_INVAL, LOGLINE(xml), "", xml->name);
434 }
Radek Krejci5b315a92015-07-10 13:18:45 +0200435 return EXIT_FAILURE;
436 }
437
438 /* locate enums structure with the enumeration definitions */
Michal Vasko07471a52015-07-16 11:18:48 +0200439 for (type = node_type; type->der->type.der; type = &type->der->type);
Radek Krejci5b315a92015-07-10 13:18:45 +0200440
441 /* find matching enumeration value */
442 for (i = 0; i < type->info.enums.count; i++) {
443 if (!strcmp(xml->content, type->info.enums.list[i].name)) {
444 /* we have match, store pointer to the definition */
445 leaf->value.enm = &type->info.enums.list[i];
446 break;
447 }
448 }
449
450 if (!leaf->value.enm) {
Michal Vasko07471a52015-07-16 11:18:48 +0200451 if (log) {
452 LOGVAL(DE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
453 }
Radek Krejci5b315a92015-07-10 13:18:45 +0200454 return EXIT_FAILURE;
455 }
456
457 break;
458
Radek Krejciac8aac62015-07-10 15:36:35 +0200459 case LY_TYPE_IDENT:
Radek Krejci5a988152015-07-15 11:16:26 +0200460 if ((strptr = strchr(leaf->value_str, ':'))) {
461 len = strptr - leaf->value_str;
Radek Krejciac8aac62015-07-10 15:36:35 +0200462 if (!len) {
Michal Vasko07471a52015-07-16 11:18:48 +0200463 if (log) {
464 LOGVAL(DE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
465 }
Radek Krejciac8aac62015-07-10 15:36:35 +0200466 return EXIT_FAILURE;
467 }
Radek Krejci5a988152015-07-15 11:16:26 +0200468 strptr = strndup(leaf->value_str, len);
Radek Krejciac8aac62015-07-10 15:36:35 +0200469 }
470 ns = lyxml_get_ns(xml, strptr);
471 if (!ns) {
Michal Vasko07471a52015-07-16 11:18:48 +0200472 if (log) {
473 LOGVAL(DE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
474 }
Radek Krejciac8aac62015-07-10 15:36:35 +0200475 return EXIT_FAILURE;
476 }
477 if (strptr) {
478 free(strptr);
Radek Krejci5a988152015-07-15 11:16:26 +0200479 name = leaf->value_str + len + 1;
Radek Krejciac8aac62015-07-10 15:36:35 +0200480 } else {
Radek Krejci5a988152015-07-15 11:16:26 +0200481 name = leaf->value_str;
Radek Krejciac8aac62015-07-10 15:36:35 +0200482 }
483
Michal Vasko07471a52015-07-16 11:18:48 +0200484 leaf->value.ident = find_identityref(node_type->info.ident.ref, name, ns->value);
Radek Krejciac8aac62015-07-10 15:36:35 +0200485 if (!leaf->value.ident) {
Michal Vasko07471a52015-07-16 11:18:48 +0200486 if (log) {
487 LOGVAL(DE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
488 }
Radek Krejciac8aac62015-07-10 15:36:35 +0200489 return EXIT_FAILURE;
490 }
491 break;
492
Michal Vasko07471a52015-07-16 11:18:48 +0200493 case LY_TYPE_INST:
Michal Vasko493bea72015-07-16 16:08:12 +0200494 if (!leaf->value_str) {
495 if (log) {
496 LOGVAL(DE_INVAL, LOGLINE(xml), "", xml->name);
497 }
498 return EXIT_FAILURE;
499 }
500
501 /* validity checking is performed later, right now the data tree
502 * is not complete, so many instanceids cannot be resolved
503 */
504 /* remember the leaf for later checking */
505 new_unres = malloc(sizeof *new_unres);
506 new_unres->is_leafref = 0;
507 new_unres->dnode = node;
508 new_unres->next = *unres;
509 *unres = new_unres;
Michal Vasko07471a52015-07-16 11:18:48 +0200510 break;
511
Radek Krejci5a988152015-07-15 11:16:26 +0200512 case LY_TYPE_LEAFREF:
513 if (!leaf->value_str) {
Michal Vasko07471a52015-07-16 11:18:48 +0200514 if (log) {
515 LOGVAL(DE_INVAL, LOGLINE(xml), "", xml->name);
516 }
Radek Krejci5a988152015-07-15 11:16:26 +0200517 return EXIT_FAILURE;
518 }
519
520 /* validity checking is performed later, right now the data tree
521 * is not complete, so many leafrefs cannot be resolved
522 */
523 /* remember the leaf for later checking */
524 new_unres = malloc(sizeof *new_unres);
Michal Vasko493bea72015-07-16 16:08:12 +0200525 new_unres->is_leafref = 1;
526 new_unres->dnode = node;
Radek Krejci5a988152015-07-15 11:16:26 +0200527 new_unres->next = *unres;
528 *unres = new_unres;
529 break;
530
Radek Krejci3e3affe2015-07-09 15:38:40 +0200531 case LY_TYPE_STRING:
Radek Krejci5a988152015-07-15 11:16:26 +0200532 leaf->value.string = leaf->value_str;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200533 leaf->value_type = LY_TYPE_STRING;
534
Michal Vasko07471a52015-07-16 11:18:48 +0200535 if (node_type->info.str.length
536 && validate_length_range(0, strlen(leaf->value.string), 0, 0, node_type, xml, leaf->value_str, log)) {
Michal Vasko0e60c832015-07-15 15:48:35 +0200537 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200538 }
539
Michal Vasko07471a52015-07-16 11:18:48 +0200540 if (node_type->info.str.patterns
541 && validate_pattern(leaf->value.string, node_type, xml, leaf->value_str, log)) {
Michal Vasko0e60c832015-07-15 15:48:35 +0200542 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200543 }
544 break;
545
Michal Vasko58110162015-07-15 15:50:16 +0200546 case LY_TYPE_UNION:
Michal Vasko07471a52015-07-16 11:18:48 +0200547 found = 0;
548 type = get_next_union_type(node_type->info.uni.type, node_type->info.uni.count, NULL, &found);
549 for (; type; found = 0, type = get_next_union_type(node_type->info.uni.type, node_type->info.uni.count, type, &found)) {
550 xml->content = leaf->value_str;
551 if (!_xml_get_value(node, type, xml, unres, 0)) {
552 leaf->value_type = type->base;
553 break;
554 }
555 }
556
557 if (!type) {
558 if (log) {
559 LOGVAL(DE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
560 }
561 return EXIT_FAILURE;
562 }
Michal Vasko58110162015-07-15 15:50:16 +0200563 break;
564
565 case LY_TYPE_INT8:
Michal Vasko07471a52015-07-16 11:18:48 +0200566 if (parse_int(leaf->value_str, xml, -128, 127, 0, &num, log)
567 || validate_length_range(1, 0, num, 0, node_type, xml, leaf->value_str, log)) {
Michal Vasko58110162015-07-15 15:50:16 +0200568 return EXIT_FAILURE;
569 }
570 leaf->value.int8 = num;
571 break;
572
573 case LY_TYPE_INT16:
Michal Vasko07471a52015-07-16 11:18:48 +0200574 if (parse_int(leaf->value_str, xml, -32768, 32767, 0, &num, log)
575 || validate_length_range(1, 0, num, 0, node_type, xml, leaf->value_str, log)) {
Michal Vasko58110162015-07-15 15:50:16 +0200576 return EXIT_FAILURE;
577 }
578 leaf->value.int16 = num;
579 break;
580
581 case LY_TYPE_INT32:
Michal Vasko07471a52015-07-16 11:18:48 +0200582 if (parse_int(leaf->value_str, xml, -2147483648, 2147483647, 0, &num, log)
583 || validate_length_range(1, 0, num, 0, node_type, xml, leaf->value_str, log)) {
Michal Vasko58110162015-07-15 15:50:16 +0200584 return EXIT_FAILURE;
585 }
586 leaf->value.int32 = num;
587 break;
588
589 case LY_TYPE_INT64:
Michal Vasko07471a52015-07-16 11:18:48 +0200590 if (parse_int(leaf->value_str, xml, -9223372036854775807L - 1L, 9223372036854775807L, 0, &num, log)
591 || validate_length_range(1, 0, num, 0, node_type, xml, leaf->value_str, log)) {
Michal Vasko58110162015-07-15 15:50:16 +0200592 return EXIT_FAILURE;
593 }
594 leaf->value.int64 = num;
595 break;
596
597 case LY_TYPE_UINT8:
Michal Vasko07471a52015-07-16 11:18:48 +0200598 if (parse_uint(leaf->value_str, xml, 255, 0, &unum, log)
599 || validate_length_range(0, unum, 0, 0, node_type, xml, leaf->value_str, log)) {
Michal Vasko58110162015-07-15 15:50:16 +0200600 return EXIT_FAILURE;
601 }
602 leaf->value.uint8 = unum;
603 break;
604
605 case LY_TYPE_UINT16:
Michal Vasko07471a52015-07-16 11:18:48 +0200606 if (parse_uint(leaf->value_str, xml, 65535, 0, &unum, log)
607 || validate_length_range(0, unum, 0, 0, node_type, xml, leaf->value_str, log)) {
Michal Vasko58110162015-07-15 15:50:16 +0200608 return EXIT_FAILURE;
609 }
610 leaf->value.uint16 = unum;
611 break;
612
613 case LY_TYPE_UINT32:
Michal Vasko07471a52015-07-16 11:18:48 +0200614 if (parse_uint(leaf->value_str, xml, 4294967295, 0, &unum, log)
615 || validate_length_range(0, unum, 0, 0, node_type, xml, leaf->value_str, log)) {
Michal Vasko58110162015-07-15 15:50:16 +0200616 return EXIT_FAILURE;
617 }
618 leaf->value.uint32 = unum;
619 break;
620
621 case LY_TYPE_UINT64:
Michal Vasko07471a52015-07-16 11:18:48 +0200622 if (parse_uint(leaf->value_str, xml, 18446744073709551615UL, 0, &unum, log)
623 || validate_length_range(0, unum, 0, 0, node_type, xml, leaf->value_str, log)) {
Michal Vasko58110162015-07-15 15:50:16 +0200624 return EXIT_FAILURE;
625 }
626 leaf->value.uint64 = unum;
627 break;
628
Radek Krejcie4748472015-07-08 18:00:22 +0200629 default:
Michal Vasko493bea72015-07-16 16:08:12 +0200630 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200631 }
632
633 return EXIT_SUCCESS;
634}
635
Michal Vasko07471a52015-07-16 11:18:48 +0200636static int
Michal Vasko493bea72015-07-16 16:08:12 +0200637xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, struct leafref_instid **unres)
Michal Vasko07471a52015-07-16 11:18:48 +0200638{
639 return _xml_get_value(node, &((struct ly_mnode_leaf *)node->schema)->type, xml, unres, 1);
640}
641
Radek Krejci1721c012015-07-08 12:52:33 +0200642struct lyd_node *
Michal Vasko493bea72015-07-16 16:08:12 +0200643xml_parse_data(struct ly_ctx *ctx, struct lyxml_elem *xml, struct lyd_node *parent, struct lyd_node *prev,
644 struct leafref_instid **unres)
Radek Krejci1721c012015-07-08 12:52:33 +0200645{
646 struct lyd_node *result, *aux;
647 struct ly_mnode *schema = NULL;
648 int i;
Radek Krejcie4748472015-07-08 18:00:22 +0200649 int havechildren = 1;
Radek Krejci1721c012015-07-08 12:52:33 +0200650
651 if (!xml) {
652 return NULL;
653 }
654 if (!xml->ns || !xml->ns->value) {
655 LOGVAL(VE_XML_MISS, LOGLINE(xml), "element's", "namespace");
656 return NULL;
657 }
658
659 /* find schema node */
660 if (!parent) {
661 /* starting in root */
662 for (i = 0; i < ctx->models.used; i++) {
663 /* match data model based on namespace */
664 if (ctx->models.list[i]->ns == xml->ns->value) {
665 /* get the proper schema node */
666 LY_TREE_FOR(ctx->models.list[i]->data, schema) {
667 if (schema->name == xml->name) {
668 break;
669 }
670 }
671 break;
672 }
673 }
674 } else {
675 /* parsing some internal node, we start with parent's schema pointer */
676 schema = xml_data_search_schemanode(xml, parent->schema->child);
677 }
678 if (!schema) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200679 LOGVAL(DE_INELEM, LOGLINE(xml), xml->name);
Radek Krejci1721c012015-07-08 12:52:33 +0200680 return NULL;
681 }
682
683 /* TODO: fit this into different types of nodes */
Radek Krejcib9930252015-07-08 15:47:45 +0200684 switch (schema->nodetype) {
685 case LY_NODE_LIST:
686 result = calloc(1, sizeof(struct lyd_node_list));
687 break;
Radek Krejcie4748472015-07-08 18:00:22 +0200688 case LY_NODE_LEAF:
689 result = calloc(1, sizeof(struct lyd_node_leaf));
690 havechildren = 0;
691 break;
692 case LY_NODE_LEAFLIST:
693 result = calloc(1, sizeof(struct lyd_node_leaflist));
694 havechildren = 0;
695 break;
Radek Krejcib9930252015-07-08 15:47:45 +0200696 default:
697 result = calloc(1, sizeof *result);
698 }
Radek Krejci1721c012015-07-08 12:52:33 +0200699 result->parent = parent;
Radek Krejcib9930252015-07-08 15:47:45 +0200700 result->prev = prev;
Radek Krejci1721c012015-07-08 12:52:33 +0200701 result->schema = schema;
702
Radek Krejcib9930252015-07-08 15:47:45 +0200703 /* type specific processing */
704 if (schema->nodetype == LY_NODE_LIST) {
705 /* pointers to next and previous instances of the same list */
706 for (aux = result->prev; aux; aux = aux->prev) {
707 if (aux->schema == result->schema) {
708 /* instances of the same list */
709 ((struct lyd_node_list *)aux)->lnext = (struct lyd_node_list *)result;
710 ((struct lyd_node_list *)result)->lprev = (struct lyd_node_list *)aux;
711 break;
712 }
713 }
Radek Krejcie4748472015-07-08 18:00:22 +0200714 } else if (schema->nodetype == LY_NODE_LEAF) {
715 /* type detection and assigning the value */
Radek Krejci5a988152015-07-15 11:16:26 +0200716 if (xml_get_value(result, xml, unres)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200717 goto error;
718 }
Radek Krejcie4748472015-07-08 18:00:22 +0200719 } else if (schema->nodetype == LY_NODE_LEAFLIST) {
720 /* type detection and assigning the value */
Radek Krejci5a988152015-07-15 11:16:26 +0200721 if (xml_get_value(result, xml, unres)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200722 goto error;
723 }
Radek Krejcie4748472015-07-08 18:00:22 +0200724
725 /* pointers to next and previous instances of the same leaflist */
726 for (aux = result->prev; aux; aux = aux->prev) {
727 if (aux->schema == result->schema) {
728 /* instances of the same list */
729 ((struct lyd_node_leaflist *)aux)->lnext = (struct lyd_node_leaflist *)result;
730 ((struct lyd_node_leaflist *)result)->lprev = (struct lyd_node_leaflist *)aux;
731 break;
732 }
733 }
Radek Krejcib9930252015-07-08 15:47:45 +0200734 }
735
Radek Krejci1721c012015-07-08 12:52:33 +0200736 /* process children */
Radek Krejcie4748472015-07-08 18:00:22 +0200737 if (havechildren && xml->child) {
Radek Krejci5a988152015-07-15 11:16:26 +0200738 result->child = xml_parse_data(ctx, xml->child, result, NULL, unres);
Radek Krejci1721c012015-07-08 12:52:33 +0200739 if (!result->child) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200740 goto error;
Radek Krejci1721c012015-07-08 12:52:33 +0200741 }
742
Radek Krejci1721c012015-07-08 12:52:33 +0200743 }
744
745 /* process siblings */
746 if (xml->next) {
Radek Krejci5a988152015-07-15 11:16:26 +0200747 result->next = xml_parse_data(ctx, xml->next, parent, result, unres);
Radek Krejci1721c012015-07-08 12:52:33 +0200748 if (!result->next) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200749 goto error;
Radek Krejci1721c012015-07-08 12:52:33 +0200750 }
Radek Krejci1721c012015-07-08 12:52:33 +0200751 }
752
Radek Krejcib9930252015-07-08 15:47:45 +0200753 /* fix the "last" pointer */
754 if (!result->prev) {
755 for (aux = result; aux->next; aux = aux->next);
756 result->prev = aux;
757 }
Radek Krejci1721c012015-07-08 12:52:33 +0200758 return result;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200759
760error:
761
Radek Krejci7511f402015-07-10 09:56:30 +0200762 if (havechildren) {
763 result->child = NULL;
764 }
Radek Krejci3e3affe2015-07-09 15:38:40 +0200765 result->next = NULL;
766 result->parent = NULL;
767 result->prev = result;
768 lyd_node_free(result);
769
770 return NULL;
Radek Krejci1721c012015-07-08 12:52:33 +0200771}
772
Radek Krejci5a988152015-07-15 11:16:26 +0200773static int
Michal Vasko493bea72015-07-16 16:08:12 +0200774check_unres(struct leafref_instid **list)
Radek Krejci5a988152015-07-15 11:16:26 +0200775{
Radek Krejci5a988152015-07-15 11:16:26 +0200776 struct lyd_node_leaf *leaf;
777 struct ly_mnode_leaf *sleaf;
Michal Vasko493bea72015-07-16 16:08:12 +0200778 struct leafref_instid *item, *refset, *ref;
Radek Krejci5a988152015-07-15 11:16:26 +0200779
Michal Vasko493bea72015-07-16 16:08:12 +0200780 while (*list) {
Radek Krejci5a988152015-07-15 11:16:26 +0200781 /* resolve path and create a set of possible leafrefs (we need their values) */
Michal Vasko493bea72015-07-16 16:08:12 +0200782 if ((*list)->is_leafref) {
783 leaf = (struct lyd_node_leaf *)(*list)->dnode;
784 sleaf = (struct ly_mnode_leaf *)(*list)->dnode->schema;
785 refset = resolve_path((*list)->dnode, sleaf->type.info.lref.path);
786 if (!refset) {
787 LOGERR(LY_EVALID, "Leafref validation fail.");
788 goto error;
Radek Krejci5a988152015-07-15 11:16:26 +0200789 }
Michal Vasko493bea72015-07-16 16:08:12 +0200790
791 while (refset) {
792 if (leaf->value_str == ((struct lyd_node_leaf *)refset->dnode)->value_str) {
793 leaf->value.leafref = refset->dnode;
794 }
795 ref = refset->next;
796 free(refset);
797 refset = ref;
798 }
799
800 if (!leaf->value.leafref) {
801 /* reference not found */
802 LOGERR(LY_EVALID, "Leafref validation fail.");
803 goto error;
804 }
805
806 item = (*list)->next;
807 free(*list);
808 *list = item;
809
810 /* instance-identifier */
811 } else {
812 leaf = (struct lyd_node_leaf *)(*list)->dnode;
813 sleaf = (struct ly_mnode_leaf *)(*list)->dnode->schema;
814 refset = resolve_instid((*list)->dnode, ((struct lyd_node_leaf *)(*list)->dnode)->value_str);
815 if (!refset || refset->next) {
816 LOGERR(LY_EVALID, "Instance-identifier \"%s\" validation fail.", ((struct lyd_node_leaf *)(*list)->dnode)->value_str);
817 goto error;
818 }
819
Radek Krejci5a988152015-07-15 11:16:26 +0200820 free(refset);
Radek Krejci5a988152015-07-15 11:16:26 +0200821
Michal Vasko493bea72015-07-16 16:08:12 +0200822 item = (*list)->next;
823 free(*list);
824 *list = item;
Radek Krejci5a988152015-07-15 11:16:26 +0200825 }
Radek Krejci5a988152015-07-15 11:16:26 +0200826 }
827
828 return EXIT_SUCCESS;
829
830error:
831
832 while (*list) {
833 item = (*list)->next;
834 free(*list);
835 *list = item;
836 }
837
838 return EXIT_FAILURE;
839}
840
Michal Vasko520d4732015-07-13 15:53:33 +0200841API struct lyd_node *
Radek Krejci1721c012015-07-08 12:52:33 +0200842xml_read_data(struct ly_ctx *ctx, const char *data)
843{
844 struct lyxml_elem *xml;
845 struct lyd_node *result;
Michal Vasko493bea72015-07-16 16:08:12 +0200846 struct leafref_instid *unres = NULL;
Radek Krejci1721c012015-07-08 12:52:33 +0200847
848 xml = lyxml_read(ctx, data, 0);
849 if (!xml) {
850 return NULL;
851 }
852
853 /* check the returned data - the root must be config or data in NETCONF namespace */
854 if (!xml->ns || strcmp(xml->ns->value, LY_NSNC) || (strcmp(xml->name, "data") && strcmp(xml->name, "config"))) {
855 LOGERR(LY_EINVAL, "XML data parser expect <data> or <config> root in \"%s\" namespace.", LY_NSNC);
856 return NULL;
857 }
858
Radek Krejci5a988152015-07-15 11:16:26 +0200859 result = xml_parse_data(ctx, xml->child, NULL, NULL, &unres);
Michal Vasko493bea72015-07-16 16:08:12 +0200860 /* check leafrefs and/or instids if any */
861 if (check_unres(&unres)) {
862 /* leafref & instid checking failed */
Radek Krejci5a988152015-07-15 11:16:26 +0200863 lyd_node_free(result);
864 result = NULL;
865 }
866
867 /* free source XML tree */
Radek Krejci1721c012015-07-08 12:52:33 +0200868 lyxml_free_elem(ctx, xml);
869
870 return result;
871}