blob: 1da622e37c10b3c821fcf61572cad7d7a534739d [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 Vasko8bcdf292015-08-19 14:04:43 +020027#include <limits.h>
Michal Vaskobe190a62015-07-13 16:14:20 +020028#include <sys/types.h>
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +020029#include <pcre.h>
Radek Krejci1721c012015-07-08 12:52:33 +020030
Radek Krejci998a0b82015-08-17 13:14:36 +020031#include "libyang.h"
32#include "common.h"
33#include "context.h"
34#include "resolve.h"
Radek Krejci998a0b82015-08-17 13:14:36 +020035#include "tree_internal.h"
36#include "validation.h"
Radek Krejcic6704c82015-10-06 11:12:45 +020037#include "xml_private.h"
Radek Krejci1721c012015-07-08 12:52:33 +020038
39#define LY_NSNC "urn:ietf:params:xml:ns:netconf:base:1.0"
40
Michal Vasko249e6b52015-08-19 11:08:52 +020041/**
Michal Vaskofb0873c2015-08-21 09:00:07 +020042 * @brief Transform data from XML format (prefixes and separate NS definitions) to
43 * JSON format (prefixes are module names instead).
Michal Vasko249e6b52015-08-19 11:08:52 +020044 * Logs directly.
45 *
46 * @param[in] ctx Main context with the dictionary.
Michal Vaskofb0873c2015-08-21 09:00:07 +020047 * @param[in] xml XML data value.
Michal Vasko249e6b52015-08-19 11:08:52 +020048 *
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020049 * @return Transformed data in the dictionary or NULL on error.
Michal Vasko249e6b52015-08-19 11:08:52 +020050 */
51static const char *
Michal Vaskofb0873c2015-08-21 09:00:07 +020052transform_data_xml2json(struct ly_ctx *ctx, struct lyxml_elem *xml, int log)
Michal Vasko249e6b52015-08-19 11:08:52 +020053{
54 const char *in, *id;
55 char *out, *col, *prefix;
56 size_t out_size, out_used, id_len, rc;
57 struct lys_module *mod;
58 struct lyxml_ns *ns;
59
60 in = xml->content;
61 out_size = strlen(in)+1;
62 out = malloc(out_size);
63 out_used = 0;
64
65 while (1) {
66 col = strchr(in, ':');
67 /* we're finished, copy the remaining part */
68 if (!col) {
69 strcpy(&out[out_used], in);
70 out_used += strlen(in)+1;
71 assert(out_size == out_used);
72 return lydict_insert_zc(ctx, out);
73 }
74 id = strpbrk_backwards(col-1, "/ [", (col-in)-1);
Michal Vaskofb0873c2015-08-21 09:00:07 +020075 if ((id[0] == '/') || (id[0] == ' ') || (id[0] == '[')) {
76 ++id;
77 }
Michal Vasko249e6b52015-08-19 11:08:52 +020078 id_len = col-id;
79 rc = parse_identifier(id);
80 if (rc < id_len) {
Michal Vaskofb0873c2015-08-21 09:00:07 +020081 if (log) {
82 LOGVAL(LYE_INCHAR, LOGLINE(xml), id[rc], &id[rc]);
83 }
Michal Vasko249e6b52015-08-19 11:08:52 +020084 free(out);
85 return NULL;
86 }
87
88 /* get the module */
89 prefix = strndup(id, id_len);
90 ns = lyxml_get_ns(xml, prefix);
91 free(prefix);
92 if (!ns) {
Michal Vaskob26572e2015-09-09 15:11:29 +020093 /* TODO a valid case if replacing an XPath in an augment part from a different model (won't happen if namespaces used in the augment get copied over as well) */
Michal Vaskofb0873c2015-08-21 09:00:07 +020094 if (log) {
95 LOGVAL(LYE_SPEC, LOGLINE(xml), "XML namespace with prefix \"%.*s\" not defined.", id_len, id);
96 }
Michal Vasko249e6b52015-08-19 11:08:52 +020097 free(out);
98 return NULL;
99 }
100 mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL);
101 if (!mod) {
Michal Vaskofb0873c2015-08-21 09:00:07 +0200102 if (log) {
103 LOGVAL(LYE_SPEC, LOGLINE(xml), "Module with the namespace \"%s\" could not be found.", ns->value);
104 }
Michal Vasko249e6b52015-08-19 11:08:52 +0200105 free(out);
106 return NULL;
107 }
108
109 /* adjust out size (it can even decrease in some strange cases) */
110 out_size += strlen(mod->name)-id_len;
111 out = realloc(out, out_size);
112
113 /* copy the data before prefix */
114 strncpy(&out[out_used], in, id-in);
115 out_used += id-in;
116
117 /* copy the model name */
118 strcpy(&out[out_used], mod->name);
119 out_used += strlen(mod->name);
120
121 /* copy ':' */
122 out[out_used] = ':';
123 ++out_used;
124
125 /* finally adjust in pointer for next round */
126 in = col+1;
127 }
128
129 /* unreachable */
130 assert(0);
131 return NULL;
132}
133
Michal Vasko0d343d12015-08-24 14:57:36 +0200134/* logs directly
135 *
136 * kind == 0 - unsigned (unum used), 1 - signed (snum used), 2 - floating point (fnum used)
137 */
Michal Vasko9286afd2015-07-14 15:27:59 +0200138static int
Radek Krejci1574a8d2015-08-03 14:16:52 +0200139validate_length_range(uint8_t kind, uint64_t unum, int64_t snum, long double fnum, struct lys_type *type,
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200140 const char *val_str, uint32_t line)
Michal Vasko9286afd2015-07-14 15:27:59 +0200141{
Michal Vasko020404f2015-07-15 15:45:42 +0200142 struct len_ran_intv *intv = NULL, *tmp_intv;
Michal Vaskof02e3742015-08-05 16:27:02 +0200143 int ret = EXIT_FAILURE;
Michal Vasko9286afd2015-07-14 15:27:59 +0200144
Michal Vasko9c1bc642015-08-05 16:25:53 +0200145 if (resolve_len_ran_interval(NULL, type, 0, &intv)) {
Michal Vasko0d343d12015-08-24 14:57:36 +0200146 /* already done during schema parsing */
147 LOGINT;
Michal Vasko9c1bc642015-08-05 16:25:53 +0200148 return EXIT_FAILURE;
149 }
Michal Vasko020404f2015-07-15 15:45:42 +0200150 if (!intv) {
Michal Vaskof02e3742015-08-05 16:27:02 +0200151 return EXIT_SUCCESS;
Michal Vasko020404f2015-07-15 15:45:42 +0200152 }
153
Michal Vasko9286afd2015-07-14 15:27:59 +0200154 for (tmp_intv = intv; tmp_intv; tmp_intv = tmp_intv->next) {
155 if (((kind == 0) && (unum < tmp_intv->value.uval.min))
156 || ((kind == 1) && (snum < tmp_intv->value.sval.min))
157 || ((kind == 2) && (fnum < tmp_intv->value.fval.min))) {
158 break;
159 }
160
161 if (((kind == 0) && (unum >= tmp_intv->value.uval.min) && (unum <= tmp_intv->value.uval.max))
162 || ((kind == 1) && (snum >= tmp_intv->value.sval.min) && (snum <= tmp_intv->value.sval.max))
163 || ((kind == 2) && (fnum >= tmp_intv->value.fval.min) && (fnum <= tmp_intv->value.fval.max))) {
Michal Vaskof02e3742015-08-05 16:27:02 +0200164 ret = EXIT_SUCCESS;
Michal Vasko9286afd2015-07-14 15:27:59 +0200165 break;
166 }
167 }
168
169 while (intv) {
170 tmp_intv = intv->next;
171 free(intv);
172 intv = tmp_intv;
173 }
174
Michal Vaskof2f45df2015-08-21 09:03:14 +0200175 if (ret) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200176 LOGVAL(LYE_OORVAL, line, (val_str ? val_str : ""));
Michal Vasko0e60c832015-07-15 15:48:35 +0200177 }
Michal Vasko9286afd2015-07-14 15:27:59 +0200178 return ret;
179}
180
Michal Vasko0d343d12015-08-24 14:57:36 +0200181/* logs directly */
Michal Vaskofbf7e482015-07-14 14:49:03 +0200182static int
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200183validate_pattern(const char *val_str, struct lys_type *type, const char *node_name, uint32_t line)
Michal Vaskofbf7e482015-07-14 14:49:03 +0200184{
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200185 int i, err_offset;
186 pcre *precomp;
187 char *perl_regex;
188 const char *err_ptr;
Michal Vaskofbf7e482015-07-14 14:49:03 +0200189
190 assert(type->base == LY_TYPE_STRING);
191
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200192 if (!val_str) {
193 val_str = "";
Michal Vasko24bfc632015-08-24 15:01:21 +0200194 }
195
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200196 if (type->der && validate_pattern(val_str, &type->der->type, node_name, line)) {
Michal Vaskof02e3742015-08-05 16:27:02 +0200197 return EXIT_FAILURE;
Michal Vaskofbf7e482015-07-14 14:49:03 +0200198 }
199
200 for (i = 0; i < type->info.str.pat_count; ++i) {
201 /*
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200202 * adjust the expression to a Perl equivalent
Michal Vaskofbf7e482015-07-14 14:49:03 +0200203 *
204 * http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs
205 */
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200206 perl_regex = malloc((strlen(type->info.str.patterns[i].expr)+2) * sizeof(char));
207 perl_regex[0] = '\0';
208 strcat(perl_regex, type->info.str.patterns[i].expr);
Michal Vaskofbf7e482015-07-14 14:49:03 +0200209 if (strncmp(type->info.str.patterns[i].expr
210 + strlen(type->info.str.patterns[i].expr) - 2, ".*", 2)) {
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200211 strcat(perl_regex, "$");
Michal Vaskofbf7e482015-07-14 14:49:03 +0200212 }
213
214 /* must return 0, already checked during parsing */
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200215 precomp = pcre_compile(perl_regex, PCRE_ANCHORED | PCRE_DOLLAR_ENDONLY | PCRE_NO_AUTO_CAPTURE,
216 &err_ptr, &err_offset, NULL);
217 if (!precomp) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200218 LOGINT;
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200219 free(perl_regex);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200220 return EXIT_FAILURE;
Michal Vasko88876dc2015-08-05 09:46:40 +0200221 }
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200222 free(perl_regex);
Michal Vaskofbf7e482015-07-14 14:49:03 +0200223
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200224 if (pcre_exec(precomp, NULL, val_str, strlen(val_str), 0, 0, NULL, 0)) {
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200225 free(precomp);
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200226 LOGVAL(LYE_INVAL, line, val_str, node_name);
Michal Vaskof02e3742015-08-05 16:27:02 +0200227 return EXIT_FAILURE;
Michal Vaskofbf7e482015-07-14 14:49:03 +0200228 }
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200229 free(precomp);
Michal Vaskofbf7e482015-07-14 14:49:03 +0200230 }
231
Michal Vaskof02e3742015-08-05 16:27:02 +0200232 return EXIT_SUCCESS;
Michal Vaskofbf7e482015-07-14 14:49:03 +0200233}
234
Michal Vasko0d343d12015-08-24 14:57:36 +0200235/* does not log */
Radek Krejci76512572015-08-04 09:47:08 +0200236static struct lys_node *
237xml_data_search_schemanode(struct lyxml_elem *xml, struct lys_node *start)
Radek Krejci1721c012015-07-08 12:52:33 +0200238{
Radek Krejci76512572015-08-04 09:47:08 +0200239 struct lys_node *result, *aux;
Radek Krejci1721c012015-07-08 12:52:33 +0200240
241 LY_TREE_FOR(start, result) {
242 /* skip groupings */
Radek Krejci76512572015-08-04 09:47:08 +0200243 if (result->nodetype == LYS_GROUPING) {
Radek Krejci1721c012015-07-08 12:52:33 +0200244 continue;
245 }
246
Radek Krejcifb54be42015-10-02 15:21:16 +0200247 /* go into cases, choices, uses and in RPCs into input and output */
248 if (result->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES | LYS_INPUT | LYS_OUTPUT)) {
Radek Krejci1721c012015-07-08 12:52:33 +0200249 aux = xml_data_search_schemanode(xml, result->child);
250 if (aux) {
251 /* we have matching result */
252 return aux;
253 }
254 /* else, continue with next schema node */
255 continue;
256 }
257
258 /* match data nodes */
259 if (result->name == xml->name) {
260 /* names matches, what about namespaces? */
261 if (result->module->ns == xml->ns->value) {
262 /* we have matching result */
263 return result;
264 }
265 /* else, continue with next schema node */
266 continue;
267 }
268 }
269
270 /* no match */
271 return NULL;
272}
273
Michal Vasko0d343d12015-08-24 14:57:36 +0200274/* logs directly */
Radek Krejcie4748472015-07-08 18:00:22 +0200275static int
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200276parse_int(const char *val_str, int64_t min, int64_t max, int base, int64_t *ret, const char *node_name, uint32_t line)
Michal Vaskobdee69c2015-07-15 15:49:39 +0200277{
278 char *strptr;
279
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200280 if (!val_str) {
281 LOGVAL(LYE_INVAL, line, "", node_name);
Michal Vasko24bfc632015-08-24 15:01:21 +0200282 return EXIT_FAILURE;
283 }
284
Michal Vaskobdee69c2015-07-15 15:49:39 +0200285 /* convert to 64-bit integer, all the redundant characters are handled */
286 errno = 0;
287 strptr = NULL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200288 *ret = strtoll(val_str, &strptr, base);
Michal Vaskobdee69c2015-07-15 15:49:39 +0200289 if (errno || (*ret < min) || (*ret > max)) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200290 LOGVAL(LYE_OORVAL, line, val_str, node_name);
Michal Vaskof02e3742015-08-05 16:27:02 +0200291 return EXIT_FAILURE;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200292 } else if (strptr && *strptr) {
293 while (isspace(*strptr)) {
294 ++strptr;
295 }
296 if (*strptr) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200297 LOGVAL(LYE_INVAL, line, val_str, node_name);
Michal Vaskof02e3742015-08-05 16:27:02 +0200298 return EXIT_FAILURE;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200299 }
300 }
301
Michal Vaskof02e3742015-08-05 16:27:02 +0200302 return EXIT_SUCCESS;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200303}
304
Michal Vasko0d343d12015-08-24 14:57:36 +0200305/* logs directly */
Michal Vaskobdee69c2015-07-15 15:49:39 +0200306static int
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200307parse_uint(const char *val_str, uint64_t max, int base, uint64_t *ret, const char *node_name, uint32_t line)
Michal Vaskobdee69c2015-07-15 15:49:39 +0200308{
309 char *strptr;
310
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200311 if (!val_str) {
312 LOGVAL(LYE_INVAL, line, "", node_name);
Michal Vasko24bfc632015-08-24 15:01:21 +0200313 return EXIT_FAILURE;
314 }
315
Michal Vaskobdee69c2015-07-15 15:49:39 +0200316 errno = 0;
317 strptr = NULL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200318 *ret = strtoull(val_str, &strptr, base);
Michal Vaskobdee69c2015-07-15 15:49:39 +0200319 if (errno || (*ret > max)) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200320 LOGVAL(LYE_OORVAL, line, val_str, node_name);
Michal Vaskof02e3742015-08-05 16:27:02 +0200321 return EXIT_FAILURE;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200322 } else if (strptr && *strptr) {
323 while (isspace(*strptr)) {
324 ++strptr;
325 }
326 if (*strptr) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200327 LOGVAL(LYE_INVAL, line, val_str, node_name);
Michal Vaskof02e3742015-08-05 16:27:02 +0200328 return EXIT_FAILURE;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200329 }
330 }
331
Michal Vaskof02e3742015-08-05 16:27:02 +0200332 return EXIT_SUCCESS;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200333}
334
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200335/*
336 * logs directly
337 *
338 * resolve - whether resolve identityrefs and leafrefs (which must be in JSON form)
339 * unres - whether to try to resolve and on failure store it as unres or fail if resolving fails
340 */
341int
342lyp_parse_value(struct lyd_node_leaf_list *node, struct lys_type *stype, int resolve, struct unres_data *unres, uint32_t line)
343{
344 #define DECSIZE 21
345 struct lys_type *type;
346 char dec[DECSIZE];
347 int64_t num;
348 uint64_t unum;
349 int len;
350 int c, i, j, d;
351 int found;
352
353 assert(node && node->value_type && (node->value_type == stype->base));
354
355 switch (node->value_type) {
356 case LY_TYPE_BINARY:
357 if (validate_length_range(0, (node->value_str ? strlen(node->value_str) : 0), 0, 0, stype,
358 node->value_str, line)) {
359 return EXIT_FAILURE;
360 }
361
Radek Krejci0bfdbfd2015-10-02 14:11:14 +0200362 node->value.binary = node->value_str;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200363 break;
364
365 case LY_TYPE_BITS:
366 /* locate bits structure with the bits definitions */
367 for (type = stype; type->der->type.der; type = &type->der->type);
368
369 /* allocate the array of pointers to bits definition */
370 node->value.bit = calloc(type->info.bits.count, sizeof *node->value.bit);
371
372 if (!node->value_str) {
373 /* no bits set */
374 break;
375 }
376
377 c = 0;
378 i = 0;
379 while (node->value_str[c]) {
380 /* skip leading whitespaces */
381 while (isspace(node->value_str[c])) {
382 c++;
383 }
384
385 /* get the length of the bit identifier */
386 for (len = 0; node->value_str[c] && !isspace(node->value_str[c]); c++, len++);
387
388 /* go back to the beginning of the identifier */
389 c = c - len;
390
391 /* find bit definition, identifiers appear ordered by their posititon */
392 for (found = 0; i < type->info.bits.count; i++) {
393 if (!strncmp(type->info.bits.bit[i].name, &node->value_str[c], len)
394 && !type->info.bits.bit[i].name[len]) {
395 /* we have match, store the pointer */
396 node->value.bit[i] = &type->info.bits.bit[i];
397
398 /* stop searching */
399 i++;
400 found = 1;
401 break;
402 }
403 }
404
405 if (!found) {
406 /* referenced bit value does not exists */
407 LOGVAL(LYE_INVAL, line, node->value_str, node->schema->name);
408 return EXIT_FAILURE;
409 }
410
411 c = c + len;
412 }
413
414 break;
415
416 case LY_TYPE_BOOL:
417 if (!node->value_str) {
418 LOGVAL(LYE_INVAL, line, "", node->schema->name);
419 return EXIT_FAILURE;
420 }
421
422 if (!strcmp(node->value_str, "true")) {
423 node->value.bool = 1;
424 } /* else false, so keep it zero */
425 break;
426
427 case LY_TYPE_DEC64:
428 if (!node->value_str) {
429 LOGVAL(LYE_INVAL, line, "", node->schema->name);
430 return EXIT_FAILURE;
431 }
432
433 /* locate dec64 structure with the fraction-digits value */
434 for (type = stype; type->der->type.der; type = &type->der->type);
435
436 for (c = 0; isspace(node->value_str[c]); c++);
437 for (len = 0; node->value_str[c] && !isspace(node->value_str[c]); c++, len++);
438 c = c - len;
439 if (len > DECSIZE) {
440 /* too long */
441 LOGVAL(LYE_INVAL, line, node->value_str, node->schema->name);
442 return EXIT_FAILURE;
443 }
444
445 /* normalize the number */
446 dec[0] = '\0';
447 for (i = j = d = found = 0; i < DECSIZE; i++) {
448 if (node->value_str[c + i] == '.') {
449 found = 1;
450 j = type->info.dec64.dig;
451 i--;
452 c++;
453 continue;
454 }
455 if (node->value_str[c + i] == '\0') {
456 c--;
457 if (!found) {
458 j = type->info.dec64.dig;
459 found = 1;
460 }
461 if (!j) {
462 dec[i] = '\0';
463 break;
464 }
465 d++;
466 if (d > DECSIZE - 2) {
467 LOGVAL(LYE_OORVAL, line, node->value_str, node->schema->name);
468 return EXIT_FAILURE;
469 }
470 dec[i] = '0';
471 } else {
472 if (!isdigit(node->value_str[c + i])) {
473 if (i || node->value_str[c] != '-') {
474 LOGVAL(LYE_INVAL, line, node->value_str, node->schema->name);
475 return EXIT_FAILURE;
476 }
477 } else {
478 d++;
479 }
480 if (d > DECSIZE - 2 || (found && !j)) {
481 LOGVAL(LYE_OORVAL, line, node->value_str, node->schema->name);
482 return EXIT_FAILURE;
483 }
484 dec[i] = node->value_str[c + i];
485 }
486 if (j) {
487 j--;
488 }
489 }
490
491 if (parse_int(dec, -9223372036854775807L - 1L, 9223372036854775807L, 10, &num, node->schema->name, line)
492 || validate_length_range(2, 0, 0, ((long double)num)/(1 << type->info.dec64.dig), stype,
493 node->value_str, line)) {
494 return EXIT_FAILURE;
495 }
496 node->value.dec64 = num;
497 break;
498
499 case LY_TYPE_EMPTY:
500 /* just check that it is empty */
501 if (node->value_str && node->value_str[0]) {
502 LOGVAL(LYE_INVAL, line, node->value_str, node->schema->name);
503 return EXIT_FAILURE;
504 }
505 break;
506
507 case LY_TYPE_ENUM:
508 if (!node->value_str) {
509 LOGVAL(LYE_INVAL, line, "", node->schema->name);
510 return EXIT_FAILURE;
511 }
512
513 /* locate enums structure with the enumeration definitions */
514 for (type = stype; type->der->type.der; type = &type->der->type);
515
516 /* find matching enumeration value */
517 for (i = 0; i < type->info.enums.count; i++) {
518 if (!strcmp(node->value_str, type->info.enums.enm[i].name)) {
519 /* we have match, store pointer to the definition */
520 node->value.enm = &type->info.enums.enm[i];
521 break;
522 }
523 }
524
525 if (!node->value.enm) {
526 LOGVAL(LYE_INVAL, line, node->value_str, node->schema->name);
527 return EXIT_FAILURE;
528 }
529
530 break;
531
532 case LY_TYPE_IDENT:
533 if (!node->value_str) {
534 LOGVAL(LYE_INVAL, line, "", node->schema->name);
535 return EXIT_FAILURE;
536 }
537
538 node->value.ident = resolve_identref_json(stype->info.ident.ref, node->value_str, line);
539 if (!node->value.ident) {
540 return EXIT_FAILURE;
541 }
542 break;
543
544 case LY_TYPE_INST:
545 if (!node->value_str) {
546 LOGVAL(LYE_INVAL, line, "", node->schema->name);
547 return EXIT_FAILURE;
548 }
549
550 if (!resolve) {
551 node->value_type |= LY_TYPE_INST_UNRES;
552 } else {
553 /* validity checking is performed later, right now the data tree
554 * is not complete, so many instanceids cannot be resolved
555 */
556 if (unres) {
557 if (unres_data_add(unres, (struct lyd_node *)node, line)) {
558 return EXIT_FAILURE;
559 }
560 } else {
561 if (resolve_unres_data_item((struct lyd_node *)node, 0, line)) {
562 return EXIT_FAILURE;
563 }
564 }
565 }
566 break;
567
568 case LY_TYPE_LEAFREF:
569 if (!node->value_str) {
570 LOGVAL(LYE_INVAL, line, "", node->schema->name);
571 return EXIT_FAILURE;
572 }
573
574 if (!resolve) {
575 do {
576 type = &((struct lys_node_leaf *)node->schema)->type.info.lref.target->type;
577 } while (type->base == LY_TYPE_LEAFREF);
578 node->value_type = type->base | LY_TYPE_LEAFREF_UNRES;
579 } else {
580 /* validity checking is performed later, right now the data tree
581 * is not complete, so many noderefs cannot be resolved
582 */
583 if (unres) {
584 if (unres_data_add(unres, (struct lyd_node *)node, line)) {
585 return EXIT_FAILURE;
586 }
587 } else {
588 if (resolve_unres_data_item((struct lyd_node *)node, 0, line)) {
589 return EXIT_FAILURE;
590 }
591 }
592 }
593 break;
594
595 case LY_TYPE_STRING:
596 if (validate_length_range(0, (node->value_str ? strlen(node->value_str) : 0), 0, 0, stype,
Radek Krejci0bfdbfd2015-10-02 14:11:14 +0200597 node->value_str, line)) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200598 return EXIT_FAILURE;
599 }
600
601 if (validate_pattern(node->value_str, stype, node->schema->name, line)) {
602 return EXIT_FAILURE;
603 }
604
Radek Krejci0bfdbfd2015-10-02 14:11:14 +0200605 node->value.string = node->value_str;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200606 break;
607
608 case LY_TYPE_INT8:
609 if (parse_int(node->value_str, -128, 127, 0, &num, node->schema->name, line)
610 || validate_length_range(1, 0, num, 0, stype, node->value_str, line)) {
611 return EXIT_FAILURE;
612 }
613 node->value.int8 = num;
614 break;
615
616 case LY_TYPE_INT16:
617 if (parse_int(node->value_str, -32768, 32767, 0, &num, node->schema->name, line)
618 || validate_length_range(1, 0, num, 0, stype, node->value_str, line)) {
619 return EXIT_FAILURE;
620 }
621 node->value.int16 = num;
622 break;
623
624 case LY_TYPE_INT32:
625 if (parse_int(node->value_str, -2147483648, 2147483647, 0, &num, node->schema->name, line)
626 || validate_length_range(1, 0, num, 0, stype, node->value_str, line)) {
627 return EXIT_FAILURE;
628 }
629 node->value.int32 = num;
630 break;
631
632 case LY_TYPE_INT64:
633 if (parse_int(node->value_str, -9223372036854775807L - 1L, 9223372036854775807L, 0, &num,
634 node->schema->name, line)
635 || validate_length_range(1, 0, num, 0, stype, node->value_str, line)) {
636 return EXIT_FAILURE;
637 }
638 node->value.int64 = num;
639 break;
640
641 case LY_TYPE_UINT8:
642 if (parse_uint(node->value_str, 255, 0, &unum, node->schema->name, line)
643 || validate_length_range(0, unum, 0, 0, stype, node->value_str, line)) {
644 return EXIT_FAILURE;
645 }
646 node->value.uint8 = unum;
647 break;
648
649 case LY_TYPE_UINT16:
650 if (parse_uint(node->value_str, 65535, 0, &unum, node->schema->name, line)
651 || validate_length_range(0, unum, 0, 0, stype, node->value_str, line)) {
652 return EXIT_FAILURE;
653 }
654 node->value.uint16 = unum;
655 break;
656
657 case LY_TYPE_UINT32:
658 if (parse_uint(node->value_str, 4294967295, 0, &unum, node->schema->name, line)
659 || validate_length_range(0, unum, 0, 0, stype, node->value_str, line)) {
660 return EXIT_FAILURE;
661 }
662 node->value.uint32 = unum;
663 break;
664
665 case LY_TYPE_UINT64:
666 if (parse_uint(node->value_str, 18446744073709551615UL, 0, &unum, node->schema->name, line)
667 || validate_length_range(0, unum, 0, 0, stype, node->value_str, line)) {
668 return EXIT_FAILURE;
669 }
670 node->value.uint64 = unum;
671 break;
672
673 default:
674 return EXIT_FAILURE;
675 }
676
677 return EXIT_SUCCESS;
678}
679
Michal Vasko0d343d12015-08-24 14:57:36 +0200680/* does not log, cannot fail */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200681struct lys_type *
682lyp_get_next_union_type(struct lys_type *type, struct lys_type *prev_type, int *found)
Radek Krejcie4748472015-07-08 18:00:22 +0200683{
Michal Vasko07471a52015-07-16 11:18:48 +0200684 int i;
Radek Krejci1574a8d2015-08-03 14:16:52 +0200685 struct lys_type *ret = NULL;
Michal Vasko07471a52015-07-16 11:18:48 +0200686
Michal Vasko6da1a372015-07-27 11:19:10 +0200687 for (i = 0; i < type->info.uni.count; ++i) {
Radek Krejci1574a8d2015-08-03 14:16:52 +0200688 if (type->info.uni.types[i].base == LY_TYPE_UNION) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200689 ret = lyp_get_next_union_type(&type->info.uni.types[i], prev_type, found);
Michal Vasko6da1a372015-07-27 11:19:10 +0200690 if (ret) {
Michal Vasko07471a52015-07-16 11:18:48 +0200691 break;;
692 }
693 continue;
694 }
695
696 if (!prev_type || *found) {
Radek Krejci1574a8d2015-08-03 14:16:52 +0200697 ret = &type->info.uni.types[i];
Michal Vasko07471a52015-07-16 11:18:48 +0200698 break;
699 }
700
Radek Krejci1574a8d2015-08-03 14:16:52 +0200701 if (&type->info.uni.types[i] == prev_type) {
Michal Vasko07471a52015-07-16 11:18:48 +0200702 *found = 1;
703 }
704 }
705
Michal Vasko6da1a372015-07-27 11:19:10 +0200706 if (!ret && type->der) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200707 ret = lyp_get_next_union_type(&type->der->type, prev_type, found);
Michal Vasko6da1a372015-07-27 11:19:10 +0200708 }
709
710 return ret;
Michal Vasko07471a52015-07-16 11:18:48 +0200711}
712
Michal Vasko0d343d12015-08-24 14:57:36 +0200713/* logs directly */
Michal Vasko07471a52015-07-16 11:18:48 +0200714static int
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200715xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int options, struct unres_data *unres)
Michal Vasko07471a52015-07-16 11:18:48 +0200716{
Michal Vasko4c183312015-09-25 10:41:47 +0200717 struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200718 struct lys_type *type, *stype;
719 int resolve, found;
Michal Vasko23b61ec2015-08-19 11:19:50 +0200720
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200721 assert(node && (node->schema->nodetype & (LYS_LEAFLIST | LYS_LEAF)) && xml && unres);
Radek Krejci5a988152015-07-15 11:16:26 +0200722
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200723 stype = &((struct lys_node_leaf *)node->schema)->type;
Radek Krejci5a988152015-07-15 11:16:26 +0200724 leaf->value_str = xml->content;
725 xml->content = NULL;
Radek Krejcie4748472015-07-08 18:00:22 +0200726
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200727 /* will be changed in case of union */
728 leaf->value_type = stype->base;
Radek Krejcie3c33142015-08-10 15:04:36 +0200729
Radek Krejcie2cf7c12015-08-12 10:24:05 +0200730 if ((options & LYD_OPT_FILTER) && !leaf->value_str) {
731 /* no value in filter (selection) node -> nothing more is needed */
732 return EXIT_SUCCESS;
733 }
734
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200735 if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT)) {
736 resolve = 0;
737 } else {
738 resolve = 1;
739 }
Radek Krejci3e3affe2015-07-09 15:38:40 +0200740
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200741 if ((stype->base == LY_TYPE_IDENT) || (stype->base == LY_TYPE_INST)) {
Michal Vaskofb0873c2015-08-21 09:00:07 +0200742 /* convert the path from the XML form using XML namespaces into the JSON format
743 * using module names as namespaces
744 */
745 xml->content = leaf->value_str;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200746 leaf->value_str = transform_data_xml2json(leaf->schema->module->ctx, xml, 1);
747 lydict_remove(leaf->schema->module->ctx, xml->content);
Michal Vaskofb0873c2015-08-21 09:00:07 +0200748 xml->content = NULL;
749 if (!leaf->value_str) {
750 return EXIT_FAILURE;
Radek Krejciac8aac62015-07-10 15:36:35 +0200751 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200752 }
Radek Krejciac8aac62015-07-10 15:36:35 +0200753
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200754 if (stype->base == LY_TYPE_UNION) {
Michal Vasko07471a52015-07-16 11:18:48 +0200755 found = 0;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200756 /* TODO if type is IDENT | INST temporarily convert to JSON, convert back on fail */
757 type = lyp_get_next_union_type(stype, NULL, &found);
758 while (type) {
759 leaf->value_type = type->base;
760 if (!lyp_parse_value(leaf, type, resolve, unres, UINT_MAX)) {
Michal Vasko07471a52015-07-16 11:18:48 +0200761 break;
762 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200763
764 found = 0;
765 type = lyp_get_next_union_type(stype, type, &found);
Michal Vasko07471a52015-07-16 11:18:48 +0200766 }
767
768 if (!type) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200769 LOGVAL(LYE_INVAL, LOGLINE(xml), (leaf->value_str ? leaf->value_str : ""), xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200770 return EXIT_FAILURE;
771 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200772 } else if (lyp_parse_value(leaf, stype, resolve, unres, LOGLINE(xml))) {
Michal Vasko493bea72015-07-16 16:08:12 +0200773 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200774 }
775
776 return EXIT_SUCCESS;
777}
778
Michal Vasko0d343d12015-08-24 14:57:36 +0200779/* logs directly */
Michal Vasko24437552015-10-01 16:00:00 +0200780static struct lyd_node *
Michal Vasko493bea72015-07-16 16:08:12 +0200781xml_parse_data(struct ly_ctx *ctx, struct lyxml_elem *xml, struct lyd_node *parent, struct lyd_node *prev,
Michal Vasko23b61ec2015-08-19 11:19:50 +0200782 int options, struct unres_data *unres)
Radek Krejci1721c012015-07-08 12:52:33 +0200783{
Radek Krejci7f40ce32015-08-12 20:38:46 +0200784 struct lyd_node *result = NULL, *diter;
Radek Krejcieab784a2015-08-27 09:56:53 +0200785 struct lys_node *schema = NULL;
Radek Krejcia5241e52015-08-19 15:09:31 +0200786 struct lyxml_attr *attr;
Michal Vasko9f1ef592015-09-29 14:57:51 +0200787 struct lyxml_elem *first_child, *last_child, *child;
Michal Vaskoab8e4402015-07-17 12:54:28 +0200788 int i, havechildren;
Radek Krejci1721c012015-07-08 12:52:33 +0200789
790 if (!xml) {
Michal Vasko0d343d12015-08-24 14:57:36 +0200791 LOGINT;
Radek Krejci1721c012015-07-08 12:52:33 +0200792 return NULL;
793 }
794 if (!xml->ns || !xml->ns->value) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200795 LOGVAL(LYE_XML_MISS, LOGLINE(xml), "element's", "namespace");
Radek Krejci1721c012015-07-08 12:52:33 +0200796 return NULL;
797 }
798
799 /* find schema node */
800 if (!parent) {
801 /* starting in root */
802 for (i = 0; i < ctx->models.used; i++) {
803 /* match data model based on namespace */
804 if (ctx->models.list[i]->ns == xml->ns->value) {
805 /* get the proper schema node */
806 LY_TREE_FOR(ctx->models.list[i]->data, schema) {
807 if (schema->name == xml->name) {
808 break;
809 }
810 }
811 break;
812 }
813 }
814 } else {
815 /* parsing some internal node, we start with parent's schema pointer */
816 schema = xml_data_search_schemanode(xml, parent->schema->child);
817 }
818 if (!schema) {
Radek Krejci25b9fd32015-08-10 15:06:07 +0200819 if ((options & LYD_OPT_STRICT) || ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL)) {
820 LOGVAL(LYE_INELEM, LOGLINE(xml), xml->name);
821 return NULL;
822 } else {
823 goto siblings;
824 }
Radek Krejci1721c012015-07-08 12:52:33 +0200825 }
826
Radek Krejcieab784a2015-08-27 09:56:53 +0200827 if (lyv_data_context(schema, LOGLINE(xml), options)) {
Radek Krejci074bf852015-08-19 14:22:16 +0200828 return NULL;
829 }
Radek Krejcia5241e52015-08-19 15:09:31 +0200830
831 /* check insert attribute and its values */
832 if (options & LYD_OPT_EDIT) {
833 i = 0;
834 for (attr = xml->attr; attr; attr = attr->next) {
835 if (attr->type != LYXML_ATTR_STD || !attr->ns ||
836 strcmp(attr->name, "insert") || strcmp(attr->ns->value, LY_NSYANG)) {
837 continue;
838 }
839
840 /* insert attribute present */
841 if (!(schema->flags & LYS_USERORDERED)) {
842 /* ... but it is not expected */
843 LOGVAL(LYE_INATTR, LOGLINE(xml), "insert", schema->name);
844 return NULL;
845 }
846
847 if (i) {
848 LOGVAL(LYE_TOOMANY, LOGLINE(xml), "insert attributes", xml->name);
849 return NULL;
850 }
851 if (!strcmp(attr->value, "first") || !strcmp(attr->value, "last")) {
852 i = 1;
853 } else if (!strcmp(attr->value, "before") || !strcmp(attr->value, "after")) {
854 i = 2;
855 } else {
856 LOGVAL(LYE_INARG, LOGLINE(xml), attr->value, attr->name);
857 return NULL;
858 }
859 }
860
861 for (attr = xml->attr; attr; attr = attr->next) {
862 if (attr->type != LYXML_ATTR_STD || !attr->ns ||
863 strcmp(attr->name, "value") || strcmp(attr->ns->value, LY_NSYANG)) {
864 continue;
865 }
866
867 /* the value attribute is present */
868 if (i < 2) {
869 /* but it shouldn't */
870 LOGVAL(LYE_INATTR, LOGLINE(xml), "value", schema->name);
871 return NULL;
872 }
873 i++;
874 }
875 if (i == 2) {
876 /* missing value attribute for "before" or "after" */
877 LOGVAL(LYE_MISSATTR, LOGLINE(xml), "value", xml->name);
878 return NULL;
879 } else if (i > 3) {
880 /* more than one instance of the value attribute */
881 LOGVAL(LYE_TOOMANY, LOGLINE(xml), "value attributes", xml->name);
882 return NULL;
883 }
Radek Krejci074bf852015-08-19 14:22:16 +0200884 }
885
Radek Krejcib9930252015-07-08 15:47:45 +0200886 switch (schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200887 case LYS_CONTAINER:
Radek Krejci27aaa732015-09-04 15:24:04 +0200888 case LYS_LIST:
Michal Vasko2f30e572015-10-01 16:00:38 +0200889 case LYS_NOTIF:
890 case LYS_RPC:
Michal Vaskoab8e4402015-07-17 12:54:28 +0200891 result = calloc(1, sizeof *result);
892 havechildren = 1;
Radek Krejcib9930252015-07-08 15:47:45 +0200893 break;
Radek Krejci76512572015-08-04 09:47:08 +0200894 case LYS_LEAF:
Radek Krejci76512572015-08-04 09:47:08 +0200895 case LYS_LEAFLIST:
Michal Vasko4c183312015-09-25 10:41:47 +0200896 result = calloc(1, sizeof(struct lyd_node_leaf_list));
Radek Krejcie4748472015-07-08 18:00:22 +0200897 havechildren = 0;
898 break;
Radek Krejci76512572015-08-04 09:47:08 +0200899 case LYS_ANYXML:
Michal Vaskoab8e4402015-07-17 12:54:28 +0200900 result = calloc(1, sizeof(struct lyd_node_anyxml));
901 havechildren = 0;
902 break;
Radek Krejcib9930252015-07-08 15:47:45 +0200903 default:
Michal Vasko0c888fd2015-08-11 15:54:08 +0200904 LOGINT;
Michal Vaskoab8e4402015-07-17 12:54:28 +0200905 return NULL;
Radek Krejcib9930252015-07-08 15:47:45 +0200906 }
Radek Krejci1721c012015-07-08 12:52:33 +0200907 result->parent = parent;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200908 if (parent && !parent->child) {
909 parent->child = result;
910 }
911 if (prev) {
912 result->prev = prev;
913 prev->next = result;
914
915 /* fix the "last" pointer */
916 for (diter = prev; diter->prev != prev; diter = diter->prev);
917 diter->prev = result;
918 } else {
919 result->prev = result;
920 }
Radek Krejci1721c012015-07-08 12:52:33 +0200921 result->schema = schema;
922
Radek Krejcib9930252015-07-08 15:47:45 +0200923 /* type specific processing */
Radek Krejci27aaa732015-09-04 15:24:04 +0200924 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Radek Krejcie4748472015-07-08 18:00:22 +0200925 /* type detection and assigning the value */
Radek Krejci25b9fd32015-08-10 15:06:07 +0200926 if (xml_get_value(result, xml, options, unres)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200927 goto error;
928 }
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200929 } else if (schema->nodetype == LYS_ANYXML && !(options & LYD_OPT_FILTER)) {
Michal Vasko9f1ef592015-09-29 14:57:51 +0200930 /* unlink xml children, they will be the anyxml value */
931 first_child = NULL;
932 LY_TREE_FOR(xml->child, child) {
933 lyxml_unlink_elem(ctx, child, 1);
934 if (!first_child) {
935 first_child = child;
936 last_child = child;
937 } else {
938 last_child->next = child;
939 child->prev = last_child;
940 last_child = child;
941 }
Michal Vasko60beecb2015-09-03 14:24:09 +0200942 }
Michal Vasko9f1ef592015-09-29 14:57:51 +0200943 first_child->prev = last_child;
Michal Vasko60beecb2015-09-03 14:24:09 +0200944
Michal Vasko9f1ef592015-09-29 14:57:51 +0200945 ((struct lyd_node_anyxml *)result)->value = first_child;
Michal Vasko60beecb2015-09-03 14:24:09 +0200946 /* we can safely continue with xml, it's like it was, only without children */
Radek Krejcib9930252015-07-08 15:47:45 +0200947 }
948
Radek Krejci1721c012015-07-08 12:52:33 +0200949 /* process children */
Radek Krejcie4748472015-07-08 18:00:22 +0200950 if (havechildren && xml->child) {
Michal Vasko2f30e572015-10-01 16:00:38 +0200951 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
952 xml_parse_data(ctx, xml->child, result, NULL, 0, unres);
953 } else {
954 xml_parse_data(ctx, xml->child, result, NULL, options, unres);
955 }
Radek Krejci25b9fd32015-08-10 15:06:07 +0200956 if (ly_errno) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200957 goto error;
Radek Krejci1721c012015-07-08 12:52:33 +0200958 }
Radek Krejci1721c012015-07-08 12:52:33 +0200959 }
960
Michal Vasko4ff7b072015-08-21 09:05:03 +0200961 result->attr = (struct lyd_attr *)xml->attr;
962 xml->attr = NULL;
963
Radek Krejcib1c12512015-08-11 11:22:04 +0200964 /* various validation checks */
Radek Krejcieab784a2015-08-27 09:56:53 +0200965 ly_errno = 0;
966 if (lyv_data_content(result, LOGLINE(xml), options)) {
967 if (ly_errno) {
Radek Krejcib1c12512015-08-11 11:22:04 +0200968 goto error;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200969 } else {
Radek Krejcieab784a2015-08-27 09:56:53 +0200970 goto cleargotosiblings;
Radek Krejcida374342015-08-19 13:33:22 +0200971 }
Radek Krejci78ce8612015-08-18 14:31:05 +0200972 }
973
Radek Krejci25b9fd32015-08-10 15:06:07 +0200974siblings:
Radek Krejci1721c012015-07-08 12:52:33 +0200975 /* process siblings */
976 if (xml->next) {
Radek Krejci25b9fd32015-08-10 15:06:07 +0200977 if (result) {
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200978 xml_parse_data(ctx, xml->next, parent, result, options, unres);
Radek Krejci25b9fd32015-08-10 15:06:07 +0200979 } else {
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200980 xml_parse_data(ctx, xml->next, parent, prev, options, unres);
Radek Krejci25b9fd32015-08-10 15:06:07 +0200981 }
982 if (ly_errno) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200983 goto error;
Radek Krejci1721c012015-07-08 12:52:33 +0200984 }
Radek Krejci1721c012015-07-08 12:52:33 +0200985 }
986
987 return result;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200988
989error:
990
Radek Krejcieab784a2015-08-27 09:56:53 +0200991 /* cleanup */
992 lyd_free(result);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200993
994 return NULL;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200995
996cleargotosiblings:
997
Radek Krejcieab784a2015-08-27 09:56:53 +0200998 /* remove the result ... */
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200999 lyd_free(result);
1000 result = NULL;
1001
1002 /* ... and then go to siblings label */
1003 goto siblings;
Radek Krejci1721c012015-07-08 12:52:33 +02001004}
1005
Radek Krejcic6704c82015-10-06 11:12:45 +02001006API struct lyd_node *
1007lyd_parse_xml(struct ly_ctx *ctx, struct lyxml_elem *root, int options)
1008{
1009 struct lyd_node *result, *next, *iter;
1010 struct unres_data *unres = NULL;
1011
1012 if (!ctx || !root) {
1013 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
1014 return NULL;
1015 }
1016
1017 unres = calloc(1, sizeof *unres);
1018
1019 ly_errno = 0;
1020 result = xml_parse_data(ctx, root->child, NULL, NULL, options, unres);
1021
1022 /* check leafrefs and/or instids if any */
1023 if (result && resolve_unres_data(unres)) {
1024 /* leafref & instid checking failed */
1025 LY_TREE_FOR_SAFE(result, next, iter) {
1026 lyd_free(iter);
1027 }
1028 result = NULL;
1029 }
1030
1031 free(unres->dnode);
1032#ifndef NDEBUG
1033 free(unres->line);
1034#endif
1035 free(unres);
1036
1037 return result;
1038}
1039
Michal Vasko0d343d12015-08-24 14:57:36 +02001040/* logs indirectly */
Radek Krejci25b9fd32015-08-10 15:06:07 +02001041struct lyd_node *
1042xml_read_data(struct ly_ctx *ctx, const char *data, int options)
Radek Krejci1721c012015-07-08 12:52:33 +02001043{
1044 struct lyxml_elem *xml;
Radek Krejci0e1d1a62015-07-31 11:17:01 +02001045 struct lyd_node *result, *next, *iter;
Michal Vaskof02e3742015-08-05 16:27:02 +02001046 struct unres_data *unres = NULL;
Radek Krejci1721c012015-07-08 12:52:33 +02001047
1048 xml = lyxml_read(ctx, data, 0);
1049 if (!xml) {
1050 return NULL;
1051 }
1052
Michal Vasko23b61ec2015-08-19 11:19:50 +02001053 unres = calloc(1, sizeof *unres);
1054
Radek Krejci25b9fd32015-08-10 15:06:07 +02001055 ly_errno = 0;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001056 result = xml_parse_data(ctx, xml->child, NULL, NULL, options, unres);
Michal Vasko23d926a2015-08-21 09:05:36 +02001057
Michal Vasko493bea72015-07-16 16:08:12 +02001058 /* check leafrefs and/or instids if any */
Michal Vasko0bb747c2015-08-21 09:39:10 +02001059 if (result && resolve_unres_data(unres)) {
Michal Vasko493bea72015-07-16 16:08:12 +02001060 /* leafref & instid checking failed */
Radek Krejci0e1d1a62015-07-31 11:17:01 +02001061 LY_TREE_FOR_SAFE(result, next, iter) {
1062 lyd_free(iter);
1063 }
1064 result = NULL;
Radek Krejci5a988152015-07-15 11:16:26 +02001065 }
1066
Michal Vasko23b61ec2015-08-19 11:19:50 +02001067 free(unres->dnode);
1068#ifndef NDEBUG
1069 free(unres->line);
1070#endif
1071 free(unres);
1072
Radek Krejci5a988152015-07-15 11:16:26 +02001073 /* free source XML tree */
Radek Krejci1721c012015-07-08 12:52:33 +02001074 lyxml_free_elem(ctx, xml);
1075
1076 return result;
1077}