blob: 007d015c8b96748b0b414e56d11f497bbc9677d0 [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"
35#include "xml.h"
36#include "tree_internal.h"
37#include "validation.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 Vaskofb0873c2015-08-21 09:00:07 +020049 * @return Transformed data 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 Vaskofb0873c2015-08-21 09:00:07 +020093 if (log) {
94 LOGVAL(LYE_SPEC, LOGLINE(xml), "XML namespace with prefix \"%.*s\" not defined.", id_len, id);
95 }
Michal Vasko249e6b52015-08-19 11:08:52 +020096 free(out);
97 return NULL;
98 }
99 mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL);
100 if (!mod) {
Michal Vaskofb0873c2015-08-21 09:00:07 +0200101 if (log) {
102 LOGVAL(LYE_SPEC, LOGLINE(xml), "Module with the namespace \"%s\" could not be found.", ns->value);
103 }
Michal Vasko249e6b52015-08-19 11:08:52 +0200104 free(out);
105 return NULL;
106 }
107
108 /* adjust out size (it can even decrease in some strange cases) */
109 out_size += strlen(mod->name)-id_len;
110 out = realloc(out, out_size);
111
112 /* copy the data before prefix */
113 strncpy(&out[out_used], in, id-in);
114 out_used += id-in;
115
116 /* copy the model name */
117 strcpy(&out[out_used], mod->name);
118 out_used += strlen(mod->name);
119
120 /* copy ':' */
121 out[out_used] = ':';
122 ++out_used;
123
124 /* finally adjust in pointer for next round */
125 in = col+1;
126 }
127
128 /* unreachable */
129 assert(0);
130 return NULL;
131}
132
Michal Vasko0d343d12015-08-24 14:57:36 +0200133/* logs directly
134 *
135 * kind == 0 - unsigned (unum used), 1 - signed (snum used), 2 - floating point (fnum used)
136 */
Michal Vasko9286afd2015-07-14 15:27:59 +0200137static int
Radek Krejci1574a8d2015-08-03 14:16:52 +0200138validate_length_range(uint8_t kind, uint64_t unum, int64_t snum, long double fnum, struct lys_type *type,
Michal Vaskof2f45df2015-08-21 09:03:14 +0200139 const char *str_val, uint32_t line)
Michal Vasko9286afd2015-07-14 15:27:59 +0200140{
Michal Vasko020404f2015-07-15 15:45:42 +0200141 struct len_ran_intv *intv = NULL, *tmp_intv;
Michal Vaskof02e3742015-08-05 16:27:02 +0200142 int ret = EXIT_FAILURE;
Michal Vasko9286afd2015-07-14 15:27:59 +0200143
Michal Vasko9c1bc642015-08-05 16:25:53 +0200144 if (resolve_len_ran_interval(NULL, type, 0, &intv)) {
Michal Vasko0d343d12015-08-24 14:57:36 +0200145 /* already done during schema parsing */
146 LOGINT;
Michal Vasko9c1bc642015-08-05 16:25:53 +0200147 return EXIT_FAILURE;
148 }
Michal Vasko020404f2015-07-15 15:45:42 +0200149 if (!intv) {
Michal Vaskof02e3742015-08-05 16:27:02 +0200150 return EXIT_SUCCESS;
Michal Vasko020404f2015-07-15 15:45:42 +0200151 }
152
Michal Vasko9286afd2015-07-14 15:27:59 +0200153 for (tmp_intv = intv; tmp_intv; tmp_intv = tmp_intv->next) {
154 if (((kind == 0) && (unum < tmp_intv->value.uval.min))
155 || ((kind == 1) && (snum < tmp_intv->value.sval.min))
156 || ((kind == 2) && (fnum < tmp_intv->value.fval.min))) {
157 break;
158 }
159
160 if (((kind == 0) && (unum >= tmp_intv->value.uval.min) && (unum <= tmp_intv->value.uval.max))
161 || ((kind == 1) && (snum >= tmp_intv->value.sval.min) && (snum <= tmp_intv->value.sval.max))
162 || ((kind == 2) && (fnum >= tmp_intv->value.fval.min) && (fnum <= tmp_intv->value.fval.max))) {
Michal Vaskof02e3742015-08-05 16:27:02 +0200163 ret = EXIT_SUCCESS;
Michal Vasko9286afd2015-07-14 15:27:59 +0200164 break;
165 }
166 }
167
168 while (intv) {
169 tmp_intv = intv->next;
170 free(intv);
171 intv = tmp_intv;
172 }
173
Michal Vaskof2f45df2015-08-21 09:03:14 +0200174 if (ret) {
Michal Vasko24bfc632015-08-24 15:01:21 +0200175 LOGVAL(LYE_OORVAL, line, (str_val ? str_val : ""));
Michal Vasko0e60c832015-07-15 15:48:35 +0200176 }
Michal Vasko9286afd2015-07-14 15:27:59 +0200177 return ret;
178}
179
Michal Vasko0d343d12015-08-24 14:57:36 +0200180/* logs directly */
Michal Vaskofbf7e482015-07-14 14:49:03 +0200181static int
Michal Vaskof34abb12015-08-24 15:00:01 +0200182validate_pattern(const char *str_val, struct lys_type *type, struct lyxml_elem *xml, int log)
Michal Vaskofbf7e482015-07-14 14:49:03 +0200183{
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200184 int i, err_offset;
185 pcre *precomp;
186 char *perl_regex;
187 const char *err_ptr;
Michal Vaskofbf7e482015-07-14 14:49:03 +0200188
189 assert(type->base == LY_TYPE_STRING);
190
Michal Vasko24bfc632015-08-24 15:01:21 +0200191 if (!str_val) {
192 str_val = "";
193 }
194
Michal Vaskof34abb12015-08-24 15:00:01 +0200195 if (type->der && validate_pattern(str_val, &type->der->type, xml, log)) {
Michal Vaskof02e3742015-08-05 16:27:02 +0200196 return EXIT_FAILURE;
Michal Vaskofbf7e482015-07-14 14:49:03 +0200197 }
198
199 for (i = 0; i < type->info.str.pat_count; ++i) {
200 /*
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200201 * adjust the expression to a Perl equivalent
Michal Vaskofbf7e482015-07-14 14:49:03 +0200202 *
203 * http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs
204 */
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200205 perl_regex = malloc((strlen(type->info.str.patterns[i].expr)+2) * sizeof(char));
206 perl_regex[0] = '\0';
207 strcat(perl_regex, type->info.str.patterns[i].expr);
Michal Vaskofbf7e482015-07-14 14:49:03 +0200208 if (strncmp(type->info.str.patterns[i].expr
209 + strlen(type->info.str.patterns[i].expr) - 2, ".*", 2)) {
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200210 strcat(perl_regex, "$");
Michal Vaskofbf7e482015-07-14 14:49:03 +0200211 }
212
213 /* must return 0, already checked during parsing */
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200214 precomp = pcre_compile(perl_regex, PCRE_ANCHORED | PCRE_DOLLAR_ENDONLY | PCRE_NO_AUTO_CAPTURE,
215 &err_ptr, &err_offset, NULL);
216 if (!precomp) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200217 LOGINT;
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200218 free(perl_regex);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200219 return EXIT_FAILURE;
Michal Vasko88876dc2015-08-05 09:46:40 +0200220 }
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200221 free(perl_regex);
Michal Vaskofbf7e482015-07-14 14:49:03 +0200222
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200223 if (pcre_exec(precomp, NULL, str_val, strlen(str_val), 0, 0, NULL, 0)) {
224 free(precomp);
Michal Vasko07471a52015-07-16 11:18:48 +0200225 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200226 LOGVAL(LYE_INVAL, LOGLINE(xml), str_val, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200227 }
Michal Vaskof02e3742015-08-05 16:27:02 +0200228 return EXIT_FAILURE;
Michal Vaskofbf7e482015-07-14 14:49:03 +0200229 }
Michal Vaskoe4e8fbd2015-08-24 14:54:49 +0200230 free(precomp);
Michal Vaskofbf7e482015-07-14 14:49:03 +0200231 }
232
Michal Vaskof02e3742015-08-05 16:27:02 +0200233 return EXIT_SUCCESS;
Michal Vaskofbf7e482015-07-14 14:49:03 +0200234}
235
Michal Vasko0d343d12015-08-24 14:57:36 +0200236/* does not log */
Radek Krejci76512572015-08-04 09:47:08 +0200237static struct lys_node *
238xml_data_search_schemanode(struct lyxml_elem *xml, struct lys_node *start)
Radek Krejci1721c012015-07-08 12:52:33 +0200239{
Radek Krejci76512572015-08-04 09:47:08 +0200240 struct lys_node *result, *aux;
Radek Krejci1721c012015-07-08 12:52:33 +0200241
242 LY_TREE_FOR(start, result) {
243 /* skip groupings */
Radek Krejci76512572015-08-04 09:47:08 +0200244 if (result->nodetype == LYS_GROUPING) {
Radek Krejci1721c012015-07-08 12:52:33 +0200245 continue;
246 }
247
248 /* go into cases, choices, uses */
Radek Krejci76512572015-08-04 09:47:08 +0200249 if (result->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)) {
Radek Krejci1721c012015-07-08 12:52:33 +0200250 aux = xml_data_search_schemanode(xml, result->child);
251 if (aux) {
252 /* we have matching result */
253 return aux;
254 }
255 /* else, continue with next schema node */
256 continue;
257 }
258
259 /* match data nodes */
260 if (result->name == xml->name) {
261 /* names matches, what about namespaces? */
262 if (result->module->ns == xml->ns->value) {
263 /* we have matching result */
264 return result;
265 }
266 /* else, continue with next schema node */
267 continue;
268 }
269 }
270
271 /* no match */
272 return NULL;
273}
274
Michal Vasko0d343d12015-08-24 14:57:36 +0200275/* logs directly */
Radek Krejcie4748472015-07-08 18:00:22 +0200276static int
Michal Vasko07471a52015-07-16 11:18:48 +0200277parse_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 +0200278{
279 char *strptr;
280
Michal Vasko24bfc632015-08-24 15:01:21 +0200281 if (!str_val) {
282 if (log) {
283 LOGVAL(LYE_INVAL, LOGLINE(xml), "", xml->name);
284 }
285 return EXIT_FAILURE;
286 }
287
Michal Vaskobdee69c2015-07-15 15:49:39 +0200288 /* convert to 64-bit integer, all the redundant characters are handled */
289 errno = 0;
290 strptr = NULL;
291 *ret = strtoll(str_val, &strptr, base);
292 if (errno || (*ret < min) || (*ret > max)) {
Michal Vasko07471a52015-07-16 11:18:48 +0200293 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200294 LOGVAL(LYE_OORVAL, LOGLINE(xml), str_val, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200295 }
Michal Vaskof02e3742015-08-05 16:27:02 +0200296 return EXIT_FAILURE;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200297 } else if (strptr && *strptr) {
298 while (isspace(*strptr)) {
299 ++strptr;
300 }
301 if (*strptr) {
Michal Vasko07471a52015-07-16 11:18:48 +0200302 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200303 LOGVAL(LYE_INVAL, LOGLINE(xml), str_val, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200304 }
Michal Vaskof02e3742015-08-05 16:27:02 +0200305 return EXIT_FAILURE;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200306 }
307 }
308
Michal Vaskof02e3742015-08-05 16:27:02 +0200309 return EXIT_SUCCESS;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200310}
311
Michal Vasko0d343d12015-08-24 14:57:36 +0200312/* logs directly */
Michal Vaskobdee69c2015-07-15 15:49:39 +0200313static int
Michal Vasko07471a52015-07-16 11:18:48 +0200314parse_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 +0200315{
316 char *strptr;
317
Michal Vasko24bfc632015-08-24 15:01:21 +0200318 if (!str_val) {
319 if (log) {
320 LOGVAL(LYE_INVAL, LOGLINE(xml), "", xml->name);
321 }
322 return EXIT_FAILURE;
323 }
324
Michal Vaskobdee69c2015-07-15 15:49:39 +0200325 errno = 0;
326 strptr = NULL;
327 *ret = strtoull(str_val, &strptr, base);
328 if (errno || (*ret > max)) {
Michal Vasko07471a52015-07-16 11:18:48 +0200329 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200330 LOGVAL(LYE_OORVAL, LOGLINE(xml), str_val, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200331 }
Michal Vaskof02e3742015-08-05 16:27:02 +0200332 return EXIT_FAILURE;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200333 } else if (strptr && *strptr) {
334 while (isspace(*strptr)) {
335 ++strptr;
336 }
337 if (*strptr) {
Michal Vasko07471a52015-07-16 11:18:48 +0200338 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200339 LOGVAL(LYE_INVAL, LOGLINE(xml), str_val, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200340 }
Michal Vaskof02e3742015-08-05 16:27:02 +0200341 return EXIT_FAILURE;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200342 }
343 }
344
Michal Vaskof02e3742015-08-05 16:27:02 +0200345 return EXIT_SUCCESS;
Michal Vaskobdee69c2015-07-15 15:49:39 +0200346}
347
Michal Vasko0d343d12015-08-24 14:57:36 +0200348/* does not log, cannot fail */
Radek Krejci1574a8d2015-08-03 14:16:52 +0200349static struct lys_type *
350get_next_union_type(struct lys_type *type, struct lys_type *prev_type, int *found)
Radek Krejcie4748472015-07-08 18:00:22 +0200351{
Michal Vasko07471a52015-07-16 11:18:48 +0200352 int i;
Radek Krejci1574a8d2015-08-03 14:16:52 +0200353 struct lys_type *ret = NULL;
Michal Vasko07471a52015-07-16 11:18:48 +0200354
Michal Vasko6da1a372015-07-27 11:19:10 +0200355 for (i = 0; i < type->info.uni.count; ++i) {
Radek Krejci1574a8d2015-08-03 14:16:52 +0200356 if (type->info.uni.types[i].base == LY_TYPE_UNION) {
357 ret = get_next_union_type(&type->info.uni.types[i], prev_type, found);
Michal Vasko6da1a372015-07-27 11:19:10 +0200358 if (ret) {
Michal Vasko07471a52015-07-16 11:18:48 +0200359 break;;
360 }
361 continue;
362 }
363
364 if (!prev_type || *found) {
Radek Krejci1574a8d2015-08-03 14:16:52 +0200365 ret = &type->info.uni.types[i];
Michal Vasko07471a52015-07-16 11:18:48 +0200366 break;
367 }
368
Radek Krejci1574a8d2015-08-03 14:16:52 +0200369 if (&type->info.uni.types[i] == prev_type) {
Michal Vasko07471a52015-07-16 11:18:48 +0200370 *found = 1;
371 }
372 }
373
Michal Vasko6da1a372015-07-27 11:19:10 +0200374 if (!ret && type->der) {
375 ret = get_next_union_type(&type->der->type, prev_type, found);
376 }
377
378 return ret;
Michal Vasko07471a52015-07-16 11:18:48 +0200379}
380
Michal Vasko0d343d12015-08-24 14:57:36 +0200381/* logs directly */
Michal Vasko07471a52015-07-16 11:18:48 +0200382static int
Radek Krejci1574a8d2015-08-03 14:16:52 +0200383_xml_get_value(struct lyd_node *node, struct lys_type *node_type, struct lyxml_elem *xml,
Michal Vasko23b61ec2015-08-19 11:19:50 +0200384 int options, struct unres_data *unres, int log)
Michal Vasko07471a52015-07-16 11:18:48 +0200385{
386 #define DECSIZE 21
Radek Krejci3e3affe2015-07-09 15:38:40 +0200387 struct lyd_node_leaf *leaf = (struct lyd_node_leaf *)node;
Radek Krejci1574a8d2015-08-03 14:16:52 +0200388 struct lys_type *type;
Radek Krejci7511f402015-07-10 09:56:30 +0200389 char dec[DECSIZE];
Michal Vaskobdee69c2015-07-15 15:49:39 +0200390 int64_t num;
391 uint64_t unum;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200392 int len;
Radek Krejci7511f402015-07-10 09:56:30 +0200393 int c, i, j, d;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200394 int found;
Michal Vasko23b61ec2015-08-19 11:19:50 +0200395
396 assert(node && node_type && xml && unres);
Radek Krejci5a988152015-07-15 11:16:26 +0200397
398 leaf->value_str = xml->content;
399 xml->content = NULL;
Radek Krejcie4748472015-07-08 18:00:22 +0200400
Radek Krejcie3c33142015-08-10 15:04:36 +0200401 /* will be change in case of union */
402 leaf->value_type = node_type->base;
403
Radek Krejcie2cf7c12015-08-12 10:24:05 +0200404 if ((options & LYD_OPT_FILTER) && !leaf->value_str) {
405 /* no value in filter (selection) node -> nothing more is needed */
406 return EXIT_SUCCESS;
407 }
408
Michal Vasko07471a52015-07-16 11:18:48 +0200409 switch (node_type->base) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200410 case LY_TYPE_BINARY:
Radek Krejci5a988152015-07-15 11:16:26 +0200411 leaf->value.binary = leaf->value_str;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200412
Michal Vasko7490e622015-08-24 15:01:57 +0200413 if (validate_length_range(0, (leaf->value.binary ? strlen(leaf->value.binary) : 0), 0, 0, node_type,
414 leaf->value.binary, log ? LOGLINE(xml) : UINT_MAX)) {
Michal Vasko0e60c832015-07-15 15:48:35 +0200415 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200416 }
417 break;
418
Radek Krejci3e3affe2015-07-09 15:38:40 +0200419 case LY_TYPE_BITS:
Radek Krejci3e3affe2015-07-09 15:38:40 +0200420 /* locate bits structure with the bits definitions */
Michal Vasko07471a52015-07-16 11:18:48 +0200421 for (type = node_type; type->der->type.der; type = &type->der->type);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200422
423 /* allocate the array of pointers to bits definition */
424 leaf->value.bit = calloc(type->info.bits.count, sizeof *leaf->value.bit);
425
Radek Krejci5a988152015-07-15 11:16:26 +0200426 if (!leaf->value_str) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200427 /* no bits set */
428 break;
429 }
430
431 c = 0;
432 i = 0;
Radek Krejci5a988152015-07-15 11:16:26 +0200433 while (leaf->value_str[c]) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200434 /* skip leading whitespaces */
Radek Krejci5a988152015-07-15 11:16:26 +0200435 while(isspace(leaf->value_str[c])) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200436 c++;
437 }
438
439 /* get the length of the bit identifier */
Radek Krejci5a988152015-07-15 11:16:26 +0200440 for (len = 0; leaf->value_str[c] && !isspace(leaf->value_str[c]); c++, len++);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200441
442 /* go back to the beginning of the identifier */
443 c = c - len;
444
445 /* find bit definition, identifiers appear ordered by their posititon */
446 for (found = 0; i < type->info.bits.count; i++) {
Radek Krejci5a988152015-07-15 11:16:26 +0200447 if (!strncmp(type->info.bits.bit[i].name, &leaf->value_str[c], len)
Radek Krejci3e3affe2015-07-09 15:38:40 +0200448 && !type->info.bits.bit[i].name[len]) {
449 /* we have match, store the pointer */
450 leaf->value.bit[i] = &type->info.bits.bit[i];
451
452 /* stop searching */
453 i++;
454 found = 1;
455 break;
456 }
457 }
458
459 if (!found) {
460 /* referenced bit value does not exists */
Michal Vasko07471a52015-07-16 11:18:48 +0200461 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200462 LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200463 }
Radek Krejci3e3affe2015-07-09 15:38:40 +0200464 return EXIT_FAILURE;
465 }
466
467 c = c + len;
468 }
469
470 break;
471
Radek Krejcib7384642015-07-09 16:08:45 +0200472 case LY_TYPE_BOOL:
Radek Krejci5a988152015-07-15 11:16:26 +0200473 if (!strcmp(leaf->value_str, "true")) {
Radek Krejcib7384642015-07-09 16:08:45 +0200474 leaf->value.bool = 1;
475 } /* else false, so keep it zero */
476 break;
477
Radek Krejci7511f402015-07-10 09:56:30 +0200478 case LY_TYPE_DEC64:
479 /* locate dec64 structure with the fraction-digits value */
Michal Vasko07471a52015-07-16 11:18:48 +0200480 for (type = node_type; type->der->type.der; type = &type->der->type);
Radek Krejci7511f402015-07-10 09:56:30 +0200481
Radek Krejci5a988152015-07-15 11:16:26 +0200482 for (c = 0; isspace(leaf->value_str[c]); c++);
483 for (len = 0; leaf->value_str[c] && !isspace(leaf->value_str[c]); c++, len++);
Radek Krejci7511f402015-07-10 09:56:30 +0200484 c = c - len;
485 if (len > DECSIZE) {
486 /* too long */
Michal Vasko07471a52015-07-16 11:18:48 +0200487 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200488 LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200489 }
Radek Krejci7511f402015-07-10 09:56:30 +0200490 return EXIT_FAILURE;
491 }
492
493 /* normalize the number */
494 dec[0] = '\0';
495 for (i = j = d = found = 0; i < DECSIZE; i++) {
Radek Krejci5a988152015-07-15 11:16:26 +0200496 if (leaf->value_str[c + i] == '.') {
Radek Krejci7511f402015-07-10 09:56:30 +0200497 found = 1;
498 j = type->info.dec64.dig;
499 i--;
500 c++;
501 continue;
502 }
Radek Krejci5a988152015-07-15 11:16:26 +0200503 if (leaf->value_str[c + i] == '\0') {
Radek Krejci7511f402015-07-10 09:56:30 +0200504 c--;
505 if (!found) {
506 j = type->info.dec64.dig;
507 found = 1;
508 }
509 if (!j) {
510 dec[i] = '\0';
511 break;
512 }
513 d++;
514 if (d > DECSIZE - 2) {
Michal Vasko07471a52015-07-16 11:18:48 +0200515 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200516 LOGVAL(LYE_OORVAL, LOGLINE(xml), leaf->value_str, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200517 }
Radek Krejci7511f402015-07-10 09:56:30 +0200518 return EXIT_FAILURE;
519 }
520 dec[i] = '0';
521 } else {
Radek Krejci5a988152015-07-15 11:16:26 +0200522 if (!isdigit(leaf->value_str[c + i])) {
523 if (i || leaf->value_str[c] != '-') {
Michal Vasko07471a52015-07-16 11:18:48 +0200524 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200525 LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200526 }
Radek Krejci7511f402015-07-10 09:56:30 +0200527 return EXIT_FAILURE;
528 }
529 } else {
530 d++;
531 }
532 if (d > DECSIZE - 2 || (found && !j)) {
Michal Vasko07471a52015-07-16 11:18:48 +0200533 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200534 LOGVAL(LYE_OORVAL, LOGLINE(xml), leaf->value_str, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200535 }
Radek Krejci7511f402015-07-10 09:56:30 +0200536 return EXIT_FAILURE;
537 }
Radek Krejci5a988152015-07-15 11:16:26 +0200538 dec[i] = leaf->value_str[c + i];
Radek Krejci7511f402015-07-10 09:56:30 +0200539 }
540 if (j) {
541 j--;
542 }
543 }
544
Michal Vasko07471a52015-07-16 11:18:48 +0200545 if (parse_int(dec, xml, -9223372036854775807L - 1L, 9223372036854775807L, 10, &num, log)
Michal Vasko29fc0182015-08-24 15:02:39 +0200546 || validate_length_range(2, 0, 0, ((long double)num)/(1 << type->info.dec64.dig), node_type,
547 leaf->value_str, log ? LOGLINE(xml) : UINT_MAX)) {
Radek Krejci7511f402015-07-10 09:56:30 +0200548 return EXIT_FAILURE;
549 }
Michal Vaskobdee69c2015-07-15 15:49:39 +0200550 leaf->value.dec64 = num;
Radek Krejci7511f402015-07-10 09:56:30 +0200551 break;
552
Radek Krejcibce73742015-07-10 12:46:06 +0200553 case LY_TYPE_EMPTY:
554 /* just check that it is empty */
Radek Krejci5a988152015-07-15 11:16:26 +0200555 if (leaf->value_str && leaf->value_str[0]) {
Michal Vasko07471a52015-07-16 11:18:48 +0200556 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200557 LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200558 }
Radek Krejcibce73742015-07-10 12:46:06 +0200559 return EXIT_FAILURE;
560 }
561 break;
562
Radek Krejci5b315a92015-07-10 13:18:45 +0200563 case LY_TYPE_ENUM:
Radek Krejci5a988152015-07-15 11:16:26 +0200564 if (!leaf->value_str) {
Michal Vasko07471a52015-07-16 11:18:48 +0200565 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200566 LOGVAL(LYE_INVAL, LOGLINE(xml), "", xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200567 }
Radek Krejci5b315a92015-07-10 13:18:45 +0200568 return EXIT_FAILURE;
569 }
570
571 /* locate enums structure with the enumeration definitions */
Michal Vasko07471a52015-07-16 11:18:48 +0200572 for (type = node_type; type->der->type.der; type = &type->der->type);
Radek Krejci5b315a92015-07-10 13:18:45 +0200573
574 /* find matching enumeration value */
575 for (i = 0; i < type->info.enums.count; i++) {
Radek Krejci1574a8d2015-08-03 14:16:52 +0200576 if (!strcmp(leaf->value_str, type->info.enums.enm[i].name)) {
Radek Krejci5b315a92015-07-10 13:18:45 +0200577 /* we have match, store pointer to the definition */
Radek Krejci1574a8d2015-08-03 14:16:52 +0200578 leaf->value.enm = &type->info.enums.enm[i];
Radek Krejci5b315a92015-07-10 13:18:45 +0200579 break;
580 }
581 }
582
583 if (!leaf->value.enm) {
Michal Vasko07471a52015-07-16 11:18:48 +0200584 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200585 LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200586 }
Radek Krejci5b315a92015-07-10 13:18:45 +0200587 return EXIT_FAILURE;
588 }
589
590 break;
591
Radek Krejciac8aac62015-07-10 15:36:35 +0200592 case LY_TYPE_IDENT:
Michal Vaskofb0873c2015-08-21 09:00:07 +0200593 if (!leaf->value_str) {
Michal Vasko07471a52015-07-16 11:18:48 +0200594 if (log) {
Michal Vaskofb0873c2015-08-21 09:00:07 +0200595 LOGVAL(LYE_INVAL, LOGLINE(xml), "", xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200596 }
Radek Krejciac8aac62015-07-10 15:36:35 +0200597 return EXIT_FAILURE;
598 }
Michal Vaskofb0873c2015-08-21 09:00:07 +0200599
600 /* convert the path from the XML form using XML namespaces into the JSON format
601 * using module names as namespaces
602 */
603 xml->content = leaf->value_str;
604 leaf->value_str = transform_data_xml2json(node->schema->module->ctx, xml, log);
605 lydict_remove(node->schema->module->ctx, xml->content);
606 xml->content = NULL;
607 if (!leaf->value_str) {
608 return EXIT_FAILURE;
Radek Krejciac8aac62015-07-10 15:36:35 +0200609 }
610
Michal Vaskoc633ca02015-08-21 14:03:51 +0200611 leaf->value.ident = resolve_identref_json(node_type->info.ident.ref, leaf->value_str,
Michal Vaskof2f45df2015-08-21 09:03:14 +0200612 log ? LOGLINE(xml) : UINT_MAX);
Radek Krejciac8aac62015-07-10 15:36:35 +0200613 if (!leaf->value.ident) {
Radek Krejciac8aac62015-07-10 15:36:35 +0200614 return EXIT_FAILURE;
615 }
616 break;
617
Michal Vasko07471a52015-07-16 11:18:48 +0200618 case LY_TYPE_INST:
Michal Vasko493bea72015-07-16 16:08:12 +0200619 if (!leaf->value_str) {
620 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200621 LOGVAL(LYE_INVAL, LOGLINE(xml), "", xml->name);
Michal Vasko493bea72015-07-16 16:08:12 +0200622 }
623 return EXIT_FAILURE;
624 }
625
Radek Krejcic5090c32015-08-12 09:46:19 +0200626 /* convert the path from the XML form using XML namespaces into the JSON format
627 * using module names as namespaces
628 */
629 xml->content = leaf->value_str;
Michal Vaskofb0873c2015-08-21 09:00:07 +0200630 leaf->value_str = transform_data_xml2json(node->schema->module->ctx, xml, log);
Radek Krejcic5090c32015-08-12 09:46:19 +0200631 lydict_remove(node->schema->module->ctx, xml->content);
632 xml->content = NULL;
633 if (!leaf->value_str) {
634 return EXIT_FAILURE;
635 }
636
Radek Krejcib1c12512015-08-11 11:22:04 +0200637 if (options & (LYD_OPT_EDIT | LYD_OPT_FILTER)) {
638 leaf->value_type |= LY_TYPE_INST_UNRES;
639 } else {
640 /* validity checking is performed later, right now the data tree
641 * is not complete, so many instanceids cannot be resolved
642 */
643 /* remember the leaf for later checking */
Michal Vasko8bcdf292015-08-19 14:04:43 +0200644 if (unres_data_add(unres, node, (log ? LOGLINE(xml) : UINT_MAX))) {
645 return EXIT_FAILURE;
646 }
Radek Krejcib1c12512015-08-11 11:22:04 +0200647 }
Michal Vasko07471a52015-07-16 11:18:48 +0200648 break;
649
Radek Krejci5a988152015-07-15 11:16:26 +0200650 case LY_TYPE_LEAFREF:
651 if (!leaf->value_str) {
Michal Vasko07471a52015-07-16 11:18:48 +0200652 if (log) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200653 LOGVAL(LYE_INVAL, LOGLINE(xml), "", xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200654 }
Radek Krejci5a988152015-07-15 11:16:26 +0200655 return EXIT_FAILURE;
656 }
657
Radek Krejcib1c12512015-08-11 11:22:04 +0200658 if (options & (LYD_OPT_EDIT | LYD_OPT_FILTER)) {
659 do {
660 type = &((struct lys_node_leaf *)leaf->schema)->type.info.lref.target->type;
661 } while (type->base == LY_TYPE_LEAFREF);
662 leaf->value_type = type->base | LY_TYPE_LEAFREF_UNRES;
663 } else {
664 /* validity checking is performed later, right now the data tree
665 * is not complete, so many leafrefs cannot be resolved
666 */
667 /* remember the leaf for later checking */
Michal Vasko8bcdf292015-08-19 14:04:43 +0200668 if (unres_data_add(unres, node, (log ? LOGLINE(xml) : UINT_MAX))) {
669 return EXIT_FAILURE;
670 }
Radek Krejcib1c12512015-08-11 11:22:04 +0200671 }
Radek Krejci5a988152015-07-15 11:16:26 +0200672 break;
673
Radek Krejci3e3affe2015-07-09 15:38:40 +0200674 case LY_TYPE_STRING:
Radek Krejci5a988152015-07-15 11:16:26 +0200675 leaf->value.string = leaf->value_str;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200676
Michal Vasko24bfc632015-08-24 15:01:21 +0200677 if (validate_length_range(0, (leaf->value.string ? strlen(leaf->value.string) : 0), 0, 0, node_type,
678 leaf->value.string, log ? LOGLINE(xml) : UINT_MAX)) {
Michal Vasko0e60c832015-07-15 15:48:35 +0200679 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200680 }
681
Michal Vaskof34abb12015-08-24 15:00:01 +0200682 if (validate_pattern(leaf->value.string, node_type, xml, log)) {
Michal Vasko0e60c832015-07-15 15:48:35 +0200683 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200684 }
685 break;
686
Michal Vasko58110162015-07-15 15:50:16 +0200687 case LY_TYPE_UNION:
Michal Vasko07471a52015-07-16 11:18:48 +0200688 found = 0;
Michal Vasko6da1a372015-07-27 11:19:10 +0200689 type = get_next_union_type(node_type, NULL, &found);
690 for (; type; found = 0, type = get_next_union_type(node_type, type, &found)) {
Michal Vasko07471a52015-07-16 11:18:48 +0200691 xml->content = leaf->value_str;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200692 if (!_xml_get_value(node, type, xml, options, unres, 0)) {
Michal Vasko07471a52015-07-16 11:18:48 +0200693 leaf->value_type = type->base;
694 break;
695 }
696 }
697
698 if (!type) {
699 if (log) {
Michal Vasko24bfc632015-08-24 15:01:21 +0200700 LOGVAL(LYE_INVAL, LOGLINE(xml), (leaf->value_str ? leaf->value_str : ""), xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200701 }
702 return EXIT_FAILURE;
703 }
Michal Vasko58110162015-07-15 15:50:16 +0200704 break;
705
706 case LY_TYPE_INT8:
Michal Vasko07471a52015-07-16 11:18:48 +0200707 if (parse_int(leaf->value_str, xml, -128, 127, 0, &num, log)
Michal Vaskof2f45df2015-08-21 09:03:14 +0200708 || validate_length_range(1, 0, num, 0, node_type, leaf->value_str, log ? LOGLINE(xml) : UINT_MAX)) {
Michal Vasko58110162015-07-15 15:50:16 +0200709 return EXIT_FAILURE;
710 }
711 leaf->value.int8 = num;
712 break;
713
714 case LY_TYPE_INT16:
Michal Vasko07471a52015-07-16 11:18:48 +0200715 if (parse_int(leaf->value_str, xml, -32768, 32767, 0, &num, log)
Michal Vaskof2f45df2015-08-21 09:03:14 +0200716 || validate_length_range(1, 0, num, 0, node_type, leaf->value_str, log ? LOGLINE(xml) : UINT_MAX)) {
Michal Vasko58110162015-07-15 15:50:16 +0200717 return EXIT_FAILURE;
718 }
719 leaf->value.int16 = num;
720 break;
721
722 case LY_TYPE_INT32:
Michal Vasko07471a52015-07-16 11:18:48 +0200723 if (parse_int(leaf->value_str, xml, -2147483648, 2147483647, 0, &num, log)
Michal Vaskof2f45df2015-08-21 09:03:14 +0200724 || validate_length_range(1, 0, num, 0, node_type, leaf->value_str, log ? LOGLINE(xml) : UINT_MAX)) {
Michal Vasko58110162015-07-15 15:50:16 +0200725 return EXIT_FAILURE;
726 }
727 leaf->value.int32 = num;
728 break;
729
730 case LY_TYPE_INT64:
Michal Vasko07471a52015-07-16 11:18:48 +0200731 if (parse_int(leaf->value_str, xml, -9223372036854775807L - 1L, 9223372036854775807L, 0, &num, log)
Michal Vaskof2f45df2015-08-21 09:03:14 +0200732 || validate_length_range(1, 0, num, 0, node_type, leaf->value_str, log ? LOGLINE(xml) : UINT_MAX)) {
Michal Vasko58110162015-07-15 15:50:16 +0200733 return EXIT_FAILURE;
734 }
735 leaf->value.int64 = num;
736 break;
737
738 case LY_TYPE_UINT8:
Michal Vasko07471a52015-07-16 11:18:48 +0200739 if (parse_uint(leaf->value_str, xml, 255, 0, &unum, log)
Michal Vaskof2f45df2015-08-21 09:03:14 +0200740 || validate_length_range(0, unum, 0, 0, node_type, leaf->value_str, log ? LOGLINE(xml) : UINT_MAX)) {
Michal Vasko58110162015-07-15 15:50:16 +0200741 return EXIT_FAILURE;
742 }
743 leaf->value.uint8 = unum;
744 break;
745
746 case LY_TYPE_UINT16:
Michal Vasko07471a52015-07-16 11:18:48 +0200747 if (parse_uint(leaf->value_str, xml, 65535, 0, &unum, log)
Michal Vaskof2f45df2015-08-21 09:03:14 +0200748 || validate_length_range(0, unum, 0, 0, node_type, leaf->value_str, log ? LOGLINE(xml) : UINT_MAX)) {
Michal Vasko58110162015-07-15 15:50:16 +0200749 return EXIT_FAILURE;
750 }
751 leaf->value.uint16 = unum;
752 break;
753
754 case LY_TYPE_UINT32:
Michal Vasko07471a52015-07-16 11:18:48 +0200755 if (parse_uint(leaf->value_str, xml, 4294967295, 0, &unum, log)
Michal Vaskof2f45df2015-08-21 09:03:14 +0200756 || validate_length_range(0, unum, 0, 0, node_type, leaf->value_str, log ? LOGLINE(xml) : UINT_MAX)) {
Michal Vasko58110162015-07-15 15:50:16 +0200757 return EXIT_FAILURE;
758 }
759 leaf->value.uint32 = unum;
760 break;
761
762 case LY_TYPE_UINT64:
Michal Vasko07471a52015-07-16 11:18:48 +0200763 if (parse_uint(leaf->value_str, xml, 18446744073709551615UL, 0, &unum, log)
Michal Vaskof2f45df2015-08-21 09:03:14 +0200764 || validate_length_range(0, unum, 0, 0, node_type, leaf->value_str, log ? LOGLINE(xml) : UINT_MAX)) {
Michal Vasko58110162015-07-15 15:50:16 +0200765 return EXIT_FAILURE;
766 }
767 leaf->value.uint64 = unum;
768 break;
769
Radek Krejcie4748472015-07-08 18:00:22 +0200770 default:
Michal Vasko493bea72015-07-16 16:08:12 +0200771 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200772 }
773
774 return EXIT_SUCCESS;
775}
776
Michal Vasko0d343d12015-08-24 14:57:36 +0200777/* logs indirectly */
Michal Vasko07471a52015-07-16 11:18:48 +0200778static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200779xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int options, struct unres_data *unres)
Michal Vasko07471a52015-07-16 11:18:48 +0200780{
Radek Krejci25b9fd32015-08-10 15:06:07 +0200781 return _xml_get_value(node, &((struct lys_node_leaf *)node->schema)->type, xml, options, unres, 1);
Michal Vasko07471a52015-07-16 11:18:48 +0200782}
783
Michal Vasko0d343d12015-08-24 14:57:36 +0200784/* logs directly */
Radek Krejci1721c012015-07-08 12:52:33 +0200785struct lyd_node *
Michal Vasko493bea72015-07-16 16:08:12 +0200786xml_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 +0200787 int options, struct unres_data *unres)
Radek Krejci1721c012015-07-08 12:52:33 +0200788{
Radek Krejci7f40ce32015-08-12 20:38:46 +0200789 struct lyd_node *result = NULL, *diter;
Radek Krejcieab784a2015-08-27 09:56:53 +0200790 struct lys_node *schema = NULL;
Radek Krejcia5241e52015-08-19 15:09:31 +0200791 struct lyxml_attr *attr;
Michal Vasko60beecb2015-09-03 14:24:09 +0200792 struct lyxml_elem *tmp_xml, *child;
Michal Vaskoab8e4402015-07-17 12:54:28 +0200793 int i, havechildren;
Radek Krejci1721c012015-07-08 12:52:33 +0200794
795 if (!xml) {
Michal Vasko0d343d12015-08-24 14:57:36 +0200796 LOGINT;
Radek Krejci1721c012015-07-08 12:52:33 +0200797 return NULL;
798 }
799 if (!xml->ns || !xml->ns->value) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200800 LOGVAL(LYE_XML_MISS, LOGLINE(xml), "element's", "namespace");
Radek Krejci1721c012015-07-08 12:52:33 +0200801 return NULL;
802 }
803
804 /* find schema node */
805 if (!parent) {
806 /* starting in root */
807 for (i = 0; i < ctx->models.used; i++) {
808 /* match data model based on namespace */
809 if (ctx->models.list[i]->ns == xml->ns->value) {
810 /* get the proper schema node */
811 LY_TREE_FOR(ctx->models.list[i]->data, schema) {
812 if (schema->name == xml->name) {
813 break;
814 }
815 }
816 break;
817 }
818 }
819 } else {
820 /* parsing some internal node, we start with parent's schema pointer */
821 schema = xml_data_search_schemanode(xml, parent->schema->child);
822 }
823 if (!schema) {
Radek Krejci25b9fd32015-08-10 15:06:07 +0200824 if ((options & LYD_OPT_STRICT) || ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL)) {
825 LOGVAL(LYE_INELEM, LOGLINE(xml), xml->name);
826 return NULL;
827 } else {
828 goto siblings;
829 }
Radek Krejci1721c012015-07-08 12:52:33 +0200830 }
831
Radek Krejcieab784a2015-08-27 09:56:53 +0200832 if (lyv_data_context(schema, LOGLINE(xml), options)) {
Radek Krejci074bf852015-08-19 14:22:16 +0200833 return NULL;
834 }
Radek Krejcia5241e52015-08-19 15:09:31 +0200835
836 /* check insert attribute and its values */
837 if (options & LYD_OPT_EDIT) {
838 i = 0;
839 for (attr = xml->attr; attr; attr = attr->next) {
840 if (attr->type != LYXML_ATTR_STD || !attr->ns ||
841 strcmp(attr->name, "insert") || strcmp(attr->ns->value, LY_NSYANG)) {
842 continue;
843 }
844
845 /* insert attribute present */
846 if (!(schema->flags & LYS_USERORDERED)) {
847 /* ... but it is not expected */
848 LOGVAL(LYE_INATTR, LOGLINE(xml), "insert", schema->name);
849 return NULL;
850 }
851
852 if (i) {
853 LOGVAL(LYE_TOOMANY, LOGLINE(xml), "insert attributes", xml->name);
854 return NULL;
855 }
856 if (!strcmp(attr->value, "first") || !strcmp(attr->value, "last")) {
857 i = 1;
858 } else if (!strcmp(attr->value, "before") || !strcmp(attr->value, "after")) {
859 i = 2;
860 } else {
861 LOGVAL(LYE_INARG, LOGLINE(xml), attr->value, attr->name);
862 return NULL;
863 }
864 }
865
866 for (attr = xml->attr; attr; attr = attr->next) {
867 if (attr->type != LYXML_ATTR_STD || !attr->ns ||
868 strcmp(attr->name, "value") || strcmp(attr->ns->value, LY_NSYANG)) {
869 continue;
870 }
871
872 /* the value attribute is present */
873 if (i < 2) {
874 /* but it shouldn't */
875 LOGVAL(LYE_INATTR, LOGLINE(xml), "value", schema->name);
876 return NULL;
877 }
878 i++;
879 }
880 if (i == 2) {
881 /* missing value attribute for "before" or "after" */
882 LOGVAL(LYE_MISSATTR, LOGLINE(xml), "value", xml->name);
883 return NULL;
884 } else if (i > 3) {
885 /* more than one instance of the value attribute */
886 LOGVAL(LYE_TOOMANY, LOGLINE(xml), "value attributes", xml->name);
887 return NULL;
888 }
Radek Krejci074bf852015-08-19 14:22:16 +0200889 }
890
Radek Krejcib9930252015-07-08 15:47:45 +0200891 switch (schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200892 case LYS_CONTAINER:
Radek Krejci27aaa732015-09-04 15:24:04 +0200893 case LYS_LIST:
Michal Vaskoab8e4402015-07-17 12:54:28 +0200894 result = calloc(1, sizeof *result);
895 havechildren = 1;
Radek Krejcib9930252015-07-08 15:47:45 +0200896 break;
Radek Krejci76512572015-08-04 09:47:08 +0200897 case LYS_LEAF:
Radek Krejcie4748472015-07-08 18:00:22 +0200898 result = calloc(1, sizeof(struct lyd_node_leaf));
899 havechildren = 0;
900 break;
Radek Krejci76512572015-08-04 09:47:08 +0200901 case LYS_LEAFLIST:
Radek Krejcie4748472015-07-08 18:00:22 +0200902 result = calloc(1, sizeof(struct lyd_node_leaflist));
903 havechildren = 0;
904 break;
Radek Krejci76512572015-08-04 09:47:08 +0200905 case LYS_ANYXML:
Michal Vaskoab8e4402015-07-17 12:54:28 +0200906 result = calloc(1, sizeof(struct lyd_node_anyxml));
907 havechildren = 0;
908 break;
Radek Krejcib9930252015-07-08 15:47:45 +0200909 default:
Michal Vasko0c888fd2015-08-11 15:54:08 +0200910 LOGINT;
Michal Vaskoab8e4402015-07-17 12:54:28 +0200911 return NULL;
Radek Krejcib9930252015-07-08 15:47:45 +0200912 }
Radek Krejci1721c012015-07-08 12:52:33 +0200913 result->parent = parent;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200914 if (parent && !parent->child) {
915 parent->child = result;
916 }
917 if (prev) {
918 result->prev = prev;
919 prev->next = result;
920
921 /* fix the "last" pointer */
922 for (diter = prev; diter->prev != prev; diter = diter->prev);
923 diter->prev = result;
924 } else {
925 result->prev = result;
926 }
Radek Krejci1721c012015-07-08 12:52:33 +0200927 result->schema = schema;
928
Radek Krejcib9930252015-07-08 15:47:45 +0200929 /* type specific processing */
Radek Krejci27aaa732015-09-04 15:24:04 +0200930 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Radek Krejcie4748472015-07-08 18:00:22 +0200931 /* type detection and assigning the value */
Radek Krejci25b9fd32015-08-10 15:06:07 +0200932 if (xml_get_value(result, xml, options, unres)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200933 goto error;
934 }
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200935 } else if (schema->nodetype == LYS_ANYXML && !(options & LYD_OPT_FILTER)) {
Michal Vasko60beecb2015-09-03 14:24:09 +0200936 /* HACK unlink xml children and link them to a separate copy of xml */
937 tmp_xml = calloc(1, sizeof *tmp_xml);
938 memcpy(tmp_xml, xml, sizeof *tmp_xml);
939 /* keep attributes in the original */
940 tmp_xml->attr = NULL;
941 /* increase reference counters on strings */
942 tmp_xml->name = lydict_insert(ctx, tmp_xml->name, 0);
943 tmp_xml->content = lydict_insert(ctx, tmp_xml->content, 0);
944 xml->child = NULL;
945 /* xml is correct now */
946
947 tmp_xml->parent = NULL;
948 lyxml_unlink_elem(ctx, tmp_xml, 1);
949 /* tmp_xml is correct now */
950
951 LY_TREE_FOR(tmp_xml->child, child) {
952 child->parent = tmp_xml;
953 }
954 /* children are correct now */
955
956 ((struct lyd_node_anyxml *)result)->value = tmp_xml;
957 /* we can safely continue with xml, it's like it was, only without children */
Radek Krejcib9930252015-07-08 15:47:45 +0200958 }
959
Radek Krejci1721c012015-07-08 12:52:33 +0200960 /* process children */
Radek Krejcie4748472015-07-08 18:00:22 +0200961 if (havechildren && xml->child) {
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200962 xml_parse_data(ctx, xml->child, result, NULL, options, unres);
Radek Krejci25b9fd32015-08-10 15:06:07 +0200963 if (ly_errno) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200964 goto error;
Radek Krejci1721c012015-07-08 12:52:33 +0200965 }
Radek Krejci1721c012015-07-08 12:52:33 +0200966 }
967
Michal Vasko4ff7b072015-08-21 09:05:03 +0200968 result->attr = (struct lyd_attr *)xml->attr;
969 xml->attr = NULL;
970
Radek Krejcib1c12512015-08-11 11:22:04 +0200971 /* various validation checks */
Radek Krejcieab784a2015-08-27 09:56:53 +0200972 ly_errno = 0;
973 if (lyv_data_content(result, LOGLINE(xml), options)) {
974 if (ly_errno) {
Radek Krejcib1c12512015-08-11 11:22:04 +0200975 goto error;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200976 } else {
Radek Krejcieab784a2015-08-27 09:56:53 +0200977 goto cleargotosiblings;
Radek Krejcida374342015-08-19 13:33:22 +0200978 }
Radek Krejci78ce8612015-08-18 14:31:05 +0200979 }
980
Radek Krejci25b9fd32015-08-10 15:06:07 +0200981siblings:
Radek Krejci1721c012015-07-08 12:52:33 +0200982 /* process siblings */
983 if (xml->next) {
Radek Krejci25b9fd32015-08-10 15:06:07 +0200984 if (result) {
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200985 xml_parse_data(ctx, xml->next, parent, result, options, unres);
Radek Krejci25b9fd32015-08-10 15:06:07 +0200986 } else {
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200987 xml_parse_data(ctx, xml->next, parent, prev, options, unres);
Radek Krejci25b9fd32015-08-10 15:06:07 +0200988 }
989 if (ly_errno) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200990 goto error;
Radek Krejci1721c012015-07-08 12:52:33 +0200991 }
Radek Krejci1721c012015-07-08 12:52:33 +0200992 }
993
994 return result;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200995
996error:
997
Radek Krejcieab784a2015-08-27 09:56:53 +0200998 /* cleanup */
999 lyd_free(result);
Radek Krejci3e3affe2015-07-09 15:38:40 +02001000
1001 return NULL;
Radek Krejci1b0d01a2015-08-19 17:00:35 +02001002
1003cleargotosiblings:
1004
Radek Krejcieab784a2015-08-27 09:56:53 +02001005 /* remove the result ... */
Radek Krejci1b0d01a2015-08-19 17:00:35 +02001006 lyd_free(result);
1007 result = NULL;
1008
1009 /* ... and then go to siblings label */
1010 goto siblings;
Radek Krejci1721c012015-07-08 12:52:33 +02001011}
1012
Michal Vasko0d343d12015-08-24 14:57:36 +02001013/* logs indirectly */
Radek Krejci25b9fd32015-08-10 15:06:07 +02001014struct lyd_node *
1015xml_read_data(struct ly_ctx *ctx, const char *data, int options)
Radek Krejci1721c012015-07-08 12:52:33 +02001016{
1017 struct lyxml_elem *xml;
Radek Krejci0e1d1a62015-07-31 11:17:01 +02001018 struct lyd_node *result, *next, *iter;
Michal Vaskof02e3742015-08-05 16:27:02 +02001019 struct unres_data *unres = NULL;
Radek Krejci1721c012015-07-08 12:52:33 +02001020
1021 xml = lyxml_read(ctx, data, 0);
1022 if (!xml) {
1023 return NULL;
1024 }
1025
Michal Vasko23b61ec2015-08-19 11:19:50 +02001026 unres = calloc(1, sizeof *unres);
1027
Radek Krejci25b9fd32015-08-10 15:06:07 +02001028 ly_errno = 0;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001029 result = xml_parse_data(ctx, xml->child, NULL, NULL, options, unres);
Michal Vasko23d926a2015-08-21 09:05:36 +02001030
Michal Vasko493bea72015-07-16 16:08:12 +02001031 /* check leafrefs and/or instids if any */
Michal Vasko0bb747c2015-08-21 09:39:10 +02001032 if (result && resolve_unres_data(unres)) {
Michal Vasko493bea72015-07-16 16:08:12 +02001033 /* leafref & instid checking failed */
Radek Krejci0e1d1a62015-07-31 11:17:01 +02001034 LY_TREE_FOR_SAFE(result, next, iter) {
1035 lyd_free(iter);
1036 }
1037 result = NULL;
Radek Krejci5a988152015-07-15 11:16:26 +02001038 }
1039
Michal Vasko23b61ec2015-08-19 11:19:50 +02001040 free(unres->dnode);
1041#ifndef NDEBUG
1042 free(unres->line);
1043#endif
1044 free(unres);
1045
Radek Krejci5a988152015-07-15 11:16:26 +02001046 /* free source XML tree */
Radek Krejci1721c012015-07-08 12:52:33 +02001047 lyxml_free_elem(ctx, xml);
1048
1049 return result;
1050}