blob: 019d73aea0f271e0b6efdbcff8692024df42de94 [file] [log] [blame]
Radek Krejci5449d472015-10-26 14:35:56 +01001/**
2 * @file parser_json.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief JSON data parser for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejci5449d472015-10-26 14:35:56 +010013 */
14
Radek Krejci9a5daea2016-03-02 16:49:40 +010015#define _GNU_SOURCE
Radek Krejci5449d472015-10-26 14:35:56 +010016#include <assert.h>
17#include <ctype.h>
18#include <limits.h>
Michal Vasko1e676ca2016-06-24 15:23:54 +020019#include <errno.h>
Radek Krejci5449d472015-10-26 14:35:56 +010020#include <stdlib.h>
21#include <string.h>
22
23#include "libyang.h"
24#include "common.h"
25#include "context.h"
26#include "parser.h"
27#include "printer.h"
28#include "tree_internal.h"
29#include "validation.h"
Radek Krejci9a5daea2016-03-02 16:49:40 +010030#include "xml_internal.h"
Radek Krejci5449d472015-10-26 14:35:56 +010031
Radek Krejci5449d472015-10-26 14:35:56 +010032static int
33lyjson_isspace(int c)
34{
35 switch(c) {
36 case 0x20: /* space */
37 case 0x09: /* horizontal tab */
38 case 0x0a: /* line feed or new line */
39 case 0x0d: /* carriage return */
40 return 1;
41 default:
42 return 0;
43 }
44}
45
46static unsigned int
47skip_ws(const char *data)
48{
49 unsigned int len = 0;
50
51 /* skip leading whitespaces */
52 while (data[len] && lyjson_isspace(data[len])) {
Radek Krejci5449d472015-10-26 14:35:56 +010053 len++;
54 }
55
56 return len;
57}
58
Radek Krejci5449d472015-10-26 14:35:56 +010059static char *
60lyjson_parse_text(const char *data, unsigned int *len)
61{
62#define BUFSIZE 1024
63
64 char buf[BUFSIZE];
65 char *result = NULL, *aux;
Radek Krejci967e4bf2015-11-28 10:06:40 +010066 int o, size = 0;
Radek Krejci5449d472015-10-26 14:35:56 +010067 unsigned int r, i;
68 int32_t value;
69
70 for (*len = o = 0; data[*len] && data[*len] != '"'; o++) {
71 if (o > BUFSIZE - 3) {
72 /* add buffer into the result */
73 if (result) {
74 size = size + o;
Michal Vasko253035f2015-12-17 16:58:13 +010075 aux = ly_realloc(result, size + 1);
Radek Krejcia8d111f2017-05-31 13:57:37 +020076 LY_CHECK_ERR_RETURN(!aux, LOGMEM, NULL);
Radek Krejci5449d472015-10-26 14:35:56 +010077 result = aux;
78 } else {
79 size = o;
80 result = malloc((size + 1) * sizeof *result);
Radek Krejcia8d111f2017-05-31 13:57:37 +020081 LY_CHECK_ERR_RETURN(!result, LOGMEM, NULL);
Radek Krejci5449d472015-10-26 14:35:56 +010082 }
83 memcpy(&result[size - o], buf, o);
84
85 /* write again into the beginning of the buffer */
86 o = 0;
87 }
88
89 if (data[*len] == '\\') {
90 /* parse escape sequence */
91 (*len)++;
92 i = 1;
93 switch (data[(*len)]) {
94 case '"':
95 /* quotation mark */
96 value = 0x22;
97 break;
98 case '\\':
99 /* reverse solidus */
100 value = 0x5c;
101 break;
102 case '/':
103 /* solidus */
104 value = 0x2f;
105 break;
106 case 'b':
107 /* backspace */
108 value = 0x08;
109 break;
110 case 'f':
111 /* form feed */
112 value = 0x0c;
113 break;
114 case 'n':
115 /* line feed */
116 value = 0x0a;
117 break;
118 case 'r':
119 /* carriage return */
120 value = 0x0d;
121 break;
122 case 't':
123 /* tab */
124 value = 0x09;
125 break;
126 case 'u':
127 /* Basic Multilingual Plane character \uXXXX */
128 (*len)++;
129 for (value = i = 0; i < 4; i++) {
130 if (isdigit(data[(*len) + i])) {
131 r = (data[(*len) + i] - '0');
132 } else if (data[(*len) + i] > 'F') {
133 r = 10 + (data[(*len) + i] - 'a');
134 } else {
135 r = 10 + (data[(*len) + i] - 'A');
136 }
137 value = (16 * value) + r;
138 }
139 break;
140 default:
141 /* invalid escape sequence */
Radek Krejci48464ed2016-03-17 15:44:09 +0100142 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "character escape sequence");
Radek Krejci5449d472015-10-26 14:35:56 +0100143 goto error;
144
145 }
Radek Krejci48464ed2016-03-17 15:44:09 +0100146 r = pututf8(&buf[o], value);
Radek Krejci5449d472015-10-26 14:35:56 +0100147 if (!r) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100148 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "character UTF8 character");
Radek Krejci5449d472015-10-26 14:35:56 +0100149 goto error;
150 }
151 o += r - 1; /* o is ++ in for loop */
152 (*len) += i; /* number of read characters */
zyinter20087fa65732016-11-17 10:55:12 +0800153 } else if ((data[*len] >= 0 && data[*len] < 0x20) || data[*len] == 0x5c) {
Radek Krejci5449d472015-10-26 14:35:56 +0100154 /* control characters must be escaped */
Radek Krejci48464ed2016-03-17 15:44:09 +0100155 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "control character (unescaped)");
Radek Krejci5449d472015-10-26 14:35:56 +0100156 goto error;
157 } else {
158 /* unescaped character */
Radek Krejcideee60e2016-09-23 15:21:14 +0200159 r = copyutf8(&buf[o], &data[*len]);
160 if (!r) {
161 goto error;
162 }
163
164 o += r - 1; /* o is ++ in for loop */
165 (*len) += r;
Radek Krejci5449d472015-10-26 14:35:56 +0100166 }
167 }
168
169#undef BUFSIZE
170
171 if (o) {
172 if (result) {
173 size = size + o;
Michal Vasko253035f2015-12-17 16:58:13 +0100174 aux = ly_realloc(result, size + 1);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200175 LY_CHECK_ERR_RETURN(!aux, LOGMEM, NULL);
Radek Krejci5449d472015-10-26 14:35:56 +0100176 result = aux;
177 } else {
178 size = o;
179 result = malloc((size + 1) * sizeof *result);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200180 LY_CHECK_ERR_RETURN(!result, LOGMEM, NULL);
Radek Krejci5449d472015-10-26 14:35:56 +0100181 }
182 memcpy(&result[size - o], buf, o);
183 }
184 if (result) {
185 result[size] = '\0';
186 } else {
187 size = 0;
188 result = strdup("");
Radek Krejcia8d111f2017-05-31 13:57:37 +0200189 LY_CHECK_ERR_RETURN(!result, LOGMEM, NULL);
Radek Krejci5449d472015-10-26 14:35:56 +0100190 }
191
192 return result;
193
194error:
195 free(result);
196 return NULL;
197}
198
199static unsigned int
200lyjson_parse_number(const char *data)
201{
Michal Vasko8f32c112016-05-18 13:22:59 +0200202 unsigned int len = 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100203
Michal Vasko8f32c112016-05-18 13:22:59 +0200204 if (data[len] == '-') {
205 ++len;
206 }
Radek Krejci5449d472015-10-26 14:35:56 +0100207
Michal Vasko8f32c112016-05-18 13:22:59 +0200208 if (data[len] == '0') {
209 ++len;
210 } else if (isdigit(data[len])) {
211 ++len;
212 while (isdigit(data[len])) {
213 ++len;
214 }
215 } else {
216 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid character in JSON Number value ('%c').", data[len]);
217 return 0;
218 }
219
220 if (data[len] == '.') {
221 ++len;
222 if (!isdigit(data[len])) {
223 if (data[len]) {
224 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid character in JSON Number value ('%c').", data[len]);
225 } else {
226 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid character in JSON Number value (EOF).");
Radek Krejci5449d472015-10-26 14:35:56 +0100227 }
Radek Krejci5449d472015-10-26 14:35:56 +0100228 return 0;
229 }
Michal Vasko8f32c112016-05-18 13:22:59 +0200230 while (isdigit(data[len])) {
231 ++len;
232 }
233 }
234
Michal Vasko1e676ca2016-06-24 15:23:54 +0200235 if ((data[len] == 'e') || (data[len] == 'E')) {
236 ++len;
237 if ((data[len] == '+') || (data[len] == '-')) {
238 ++len;
239 }
240 while (isdigit(data[len])) {
241 ++len;
242 }
243 }
244
Michal Vasko8f32c112016-05-18 13:22:59 +0200245 if (data[len] && (data[len] != ',') && (data[len] != ']') && (data[len] != '}') && !lyjson_isspace(data[len])) {
246 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid character in JSON Number value ('%c').", data[len]);
247 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100248 }
249
250 return len;
251}
252
Michal Vasko1e676ca2016-06-24 15:23:54 +0200253static char *
254lyjson_convert_enumber(const char *number, unsigned int num_len, char *e_ptr)
255{
256 char *ptr, *num;
257 const char *number_ptr;
258 long int e_val;
259 int dot_pos, chars_to_dot, minus;
260 unsigned int num_len_no_e;
261
262 if (*number == '-') {
263 minus = 1;
264 ++number;
265 --num_len;
266 } else {
267 minus = 0;
268 }
269
270 num_len_no_e = e_ptr - number;
271
272 errno = 0;
273 ++e_ptr;
274 e_val = strtol(e_ptr, &ptr, 10);
275 if (errno) {
276 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Exponent out-of-bounds in a JSON Number value (%.*s).",
277 num_len - (e_ptr - number), e_ptr);
278 return NULL;
279 } else if (ptr != number + num_len) {
280 /* we checked this already */
281 LOGINT;
282 return NULL;
283 }
284
285 if ((ptr = strnchr(number, '.', num_len_no_e))) {
286 dot_pos = ptr - number;
287 } else {
288 dot_pos = num_len_no_e;
289 }
290
291 dot_pos += e_val;
292
293 /* allocate enough memory */
294 if (dot_pos < 1) {
295 /* (.XXX)XXX[.]XXXX */
296 num = malloc((minus ? 1 : 0) + -dot_pos + 2 + (num_len_no_e - (ptr ? 1 : 0)) + 1);
297 } else if (dot_pos < (signed)num_len_no_e) {
298 /* XXXX(.)XX.XXX */
299 num = malloc((minus ? 1 : 0) + num_len_no_e + (ptr ? 0 : 1) + 1);
300 } else {
301 /* XXX[.]XXXX(XXX.) */
302 num = malloc((minus ? 1 : 0) + (dot_pos - (ptr ? 2 : 1)) + 1);
303 }
Radek Krejcia8d111f2017-05-31 13:57:37 +0200304 LY_CHECK_ERR_RETURN(!num, LOGMEM, NULL);
Michal Vasko1e676ca2016-06-24 15:23:54 +0200305 if (minus) {
306 strcpy(num, "-");
307 } else {
308 num[0] = '\0';
309 }
310
311 if (dot_pos < 1) {
312 strcat(num, "0.");
313 }
314 if (dot_pos < 0) {
315 sprintf(num + strlen(num), "%0*d", -dot_pos, 0);
316 }
317
318 chars_to_dot = dot_pos;
Michal Vasko9d1593d2016-09-30 12:33:34 +0200319 for (ptr = num + strlen(num), number_ptr = number; (unsigned)(number_ptr - number) < num_len_no_e; ) {
Michal Vasko1e676ca2016-06-24 15:23:54 +0200320 if (!chars_to_dot) {
321 *ptr = '.';
322 ++ptr;
323 chars_to_dot = -1;
324 } else if (isdigit(*number_ptr)) {
325 *ptr = *number_ptr;
326 ++ptr;
327 ++number_ptr;
328 if (chars_to_dot > 0) {
329 --chars_to_dot;
330 }
331 } else if (*number_ptr == '.') {
332 ++number_ptr;
333 } else {
334 LOGINT;
335 free(num);
336 return NULL;
337 }
338 }
339 *ptr = '\0';
340
341 if (dot_pos > (signed)num_len_no_e) {
342 sprintf(num + strlen(num), "%0*d", dot_pos - num_len_no_e, 0);
343 }
344
345 return num;
346}
347
Radek Krejci5449d472015-10-26 14:35:56 +0100348static unsigned int
349lyjson_parse_boolean(const char *data)
350{
Radek Krejci6b47b502015-10-30 15:52:41 +0100351 unsigned int len = 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100352
353 if (!strncmp(data, "false", 5)) {
354 len = 5;
355 } else if (!strncmp(data, "true", 4)) {
356 len = 4;
357 }
358
359 if (data[len] && data[len] != ',' && data[len] != ']' && data[len] != '}' && !lyjson_isspace(data[len])) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100360 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON literal value (expected true or false)");
Radek Krejci5449d472015-10-26 14:35:56 +0100361 return 0;
362 }
363
364 return len;
365}
366
367static unsigned int
Radek Krejci4ae82942016-09-19 16:41:06 +0200368json_get_anydata(struct lyd_node_anydata *any, const char *data)
Radek Krejci5449d472015-10-26 14:35:56 +0100369{
Radek Krejcia7177672016-11-17 14:53:03 +0900370 unsigned int len = 0, start, stop, c = 0;
371 char *str;
Radek Krejci5449d472015-10-26 14:35:56 +0100372
Radek Krejcia7177672016-11-17 14:53:03 +0900373 /* anydata (as well as meaningful anyxml) is supposed to be encoded as object,
374 * anyxml can be a string value, other JSON types are not supported since it is
375 * not clear how they are supposed to be represented/converted into an internal representation */
376 if (data[len] == '"' && any->schema->nodetype == LYS_ANYXML) {
377 len = 1;
378 str = lyjson_parse_text(&data[len], &c);
379 if (!str) {
380 return 0;
381 }
382 if (data[len + c] != '"') {
Radek Krejci7d6d2842016-11-28 11:21:38 +0100383 free(str);
Radek Krejcia7177672016-11-17 14:53:03 +0900384 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, any,
385 "JSON data (missing quotation-mark at the end of string)");
386 return 0;
387 }
388
389 any->value.str = lydict_insert_zc(any->schema->module->ctx, str);
390 any->value_type = LYD_ANYDATA_CONSTSTRING;
391 return len + c + 1;
392 } else if (data[len] != '{') {
393 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, any, "Unsupported Anydata/anyxml content (not an object nor string)");
Michal Vaskoa19f7d72016-05-18 13:24:08 +0200394 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100395 }
396
Radek Krejcia7177672016-11-17 14:53:03 +0900397 /* count opening '{' and closing '}' brackets to get the end of the object without its parsing */
398 c = len = 1;
Radek Krejci4ae82942016-09-19 16:41:06 +0200399 len += skip_ws(&data[len]);
Radek Krejcia7177672016-11-17 14:53:03 +0900400 start = len;
401 stop = start - 1;
Radek Krejci4ae82942016-09-19 16:41:06 +0200402 while (data[len] && c) {
403 switch (data[len]) {
404 case '{':
405 c++;
406 break;
407 case '}':
408 c--;
409 break;
410 default:
411 if (!isspace(data[len])) {
412 stop = len;
413 }
414 }
415 len++;
416 }
417 if (c) {
418 LOGVAL(LYE_EOF, LY_VLOG_LYD, any);
419 return 0;
420 }
421 any->value_type = LYD_ANYDATA_JSON;
Radek Krejcia7177672016-11-17 14:53:03 +0900422 if (stop >= start) {
423 any->value.str = lydict_insert(any->schema->module->ctx, &data[start], stop - start + 1);
424 } /* else no data */
Radek Krejci4ae82942016-09-19 16:41:06 +0200425
Michal Vaskoa19f7d72016-05-18 13:24:08 +0200426 return len;
Radek Krejci5449d472015-10-26 14:35:56 +0100427}
428
429static unsigned int
Radek Krejci45f41dd2017-02-09 14:11:09 +0100430json_get_value(struct lyd_node_leaf_list *leaf, struct lyd_node **first_sibling, const char *data, int options,
431 struct unres_data *unres)
Radek Krejci5449d472015-10-26 14:35:56 +0100432{
Radek Krejcibd930122016-08-10 13:28:26 +0200433 struct lyd_node_leaf_list *new;
Radek Krejci37b756f2016-01-18 10:15:03 +0100434 struct lys_type *stype;
Radek Krejci5449d472015-10-26 14:35:56 +0100435 struct ly_ctx *ctx;
436 unsigned int len = 0, r;
Radek Krejci5449d472015-10-26 14:35:56 +0100437 char *str;
438
Radek Krejci0b7704f2016-03-18 12:16:14 +0100439 assert(leaf && data);
Radek Krejci5449d472015-10-26 14:35:56 +0100440 ctx = leaf->schema->module->ctx;
441
442 stype = &((struct lys_node_leaf *)leaf->schema)->type;
Radek Krejci23238922015-10-27 17:13:34 +0100443
Radek Krejci5449d472015-10-26 14:35:56 +0100444 if (leaf->schema->nodetype == LYS_LEAFLIST) {
445 /* expecting begin-array */
446 if (data[len++] != '[') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100447 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (expected begin-array)");
Radek Krejci5449d472015-10-26 14:35:56 +0100448 return 0;
449 }
450
451repeat:
452 len += skip_ws(&data[len]);
453 }
454
455 /* will be changed in case of union */
456 leaf->value_type = stype->base;
457
458 if (data[len] == '"') {
459 /* string representations */
Michal Vasko6baed1c2016-05-18 13:24:44 +0200460 ++len;
Radek Krejci5449d472015-10-26 14:35:56 +0100461 str = lyjson_parse_text(&data[len], &r);
Radek Krejci23238922015-10-27 17:13:34 +0100462 if (!str) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100463 LOGPATH(LY_VLOG_LYD, leaf);
Radek Krejci5449d472015-10-26 14:35:56 +0100464 return 0;
465 }
466 leaf->value_str = lydict_insert_zc(ctx, str);
467 if (data[len + r] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100468 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, leaf,
Radek Krejciadb57612016-02-16 13:34:34 +0100469 "JSON data (missing quotation-mark at the end of string)");
Radek Krejci5449d472015-10-26 14:35:56 +0100470 return 0;
471 }
472 len += r + 1;
473 } else if (data[len] == '-' || isdigit(data[len])) {
474 /* numeric type */
475 r = lyjson_parse_number(&data[len]);
476 if (!r) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100477 LOGPATH(LY_VLOG_LYD, leaf);
Radek Krejci5449d472015-10-26 14:35:56 +0100478 return 0;
479 }
Michal Vasko1e676ca2016-06-24 15:23:54 +0200480 /* if it's a number with 'e' or 'E', get rid of it first */
481 if ((str = strnchr(&data[len], 'e', r)) || (str = strnchr(&data[len], 'E', r))) {
482 str = lyjson_convert_enumber(&data[len], r, str);
483 if (!str) {
484 return 0;
485 }
486 leaf->value_str = lydict_insert_zc(ctx, str);
487 } else {
488 leaf->value_str = lydict_insert(ctx, &data[len], r);
489 }
Radek Krejci5449d472015-10-26 14:35:56 +0100490 len += r;
491 } else if (data[len] == 'f' || data[len] == 't') {
492 /* boolean */
493 r = lyjson_parse_boolean(&data[len]);
494 if (!r) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100495 LOGPATH(LY_VLOG_LYD, leaf);
Radek Krejci5449d472015-10-26 14:35:56 +0100496 return 0;
497 }
498 leaf->value_str = lydict_insert(ctx, &data[len], r);
499 len += r;
500 } else if (!strncmp(&data[len], "[null]", 6)) {
501 /* empty */
Michal Vasko44913842016-04-13 14:20:41 +0200502 leaf->value_str = lydict_insert(ctx, "", 0);
Radek Krejci5449d472015-10-26 14:35:56 +0100503 len += 6;
504 } else {
505 /* error */
Radek Krejci48464ed2016-03-17 15:44:09 +0100506 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (unexpected value)");
Radek Krejci5449d472015-10-26 14:35:56 +0100507 return 0;
508 }
509
Radek Krejci1899d6a2016-11-03 13:48:07 +0100510 /* the value is here converted to a JSON format if needed in case of LY_TYPE_IDENT and LY_TYPE_INST or to a
511 * canonical form of the value */
Michal Vasko31a2d322018-01-12 13:36:12 +0100512 if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
Radek Krejci23238922015-10-27 17:13:34 +0100513 ly_errno = LY_EVALID;
514 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100515 }
516
517 if (leaf->schema->nodetype == LYS_LEAFLIST) {
518 /* repeat until end-array */
519 len += skip_ws(&data[len]);
520 if (data[len] == ',') {
Radek Krejci45f41dd2017-02-09 14:11:09 +0100521 /* various validation checks */
522 if (lyv_data_context((struct lyd_node*)leaf, options, unres)) {
523 return 0;
524 }
525
Radek Krejcicf748252017-09-04 11:11:14 +0200526 ly_err_clean(ly_parser_data.ctx, 1);
Radek Krejci45f41dd2017-02-09 14:11:09 +0100527 if (lyv_data_content((struct lyd_node*)leaf, options, unres) ||
528 lyv_multicases((struct lyd_node*)leaf, NULL, first_sibling, 0, NULL)) {
529 if (ly_errno) {
530 return 0;
531 }
532 }
533
Radek Krejci5449d472015-10-26 14:35:56 +0100534 /* another instance of the leaf-list */
535 new = calloc(1, sizeof(struct lyd_node_leaf_list));
Radek Krejcia8d111f2017-05-31 13:57:37 +0200536 LY_CHECK_ERR_RETURN(!new, LOGMEM, 0);
537
Radek Krejci5449d472015-10-26 14:35:56 +0100538 new->parent = leaf->parent;
539 new->prev = (struct lyd_node *)leaf;
540 leaf->next = (struct lyd_node *)new;
541
Radek Krejcie1794882017-02-08 13:23:38 +0100542 /* copy the validity and when flags */
543 new->validity = leaf->validity;
544 new->when_status = leaf->when_status;
545
Radek Krejci5449d472015-10-26 14:35:56 +0100546 /* fix the "last" pointer */
Radek Krejci45f41dd2017-02-09 14:11:09 +0100547 (*first_sibling)->prev = (struct lyd_node *)new;
Radek Krejci5449d472015-10-26 14:35:56 +0100548
549 new->schema = leaf->schema;
550
551 /* repeat value parsing */
552 leaf = new;
553 len++;
554 goto repeat;
555 } else if (data[len] == ']') {
556 len++;
557 len += skip_ws(&data[len]);
558 } else {
559 /* something unexpected */
Radek Krejci48464ed2016-03-17 15:44:09 +0100560 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (expecting value-separator or end-array)");
Radek Krejci5449d472015-10-26 14:35:56 +0100561 return 0;
562 }
563 }
564
565 len += skip_ws(&data[len]);
566 return len;
567}
568
569static unsigned int
Radek Krejci532e5e92017-02-22 12:59:24 +0100570json_parse_attr(struct lys_module *parent_module, struct lyd_attr **attr, const char *data, int options)
Radek Krejci88f29302015-10-30 15:42:33 +0100571{
572 unsigned int len = 0, r;
Radek Krejci532e5e92017-02-22 12:59:24 +0100573 char *str = NULL, *name, *prefix = NULL, *value;
Radek Krejci88f29302015-10-30 15:42:33 +0100574 struct lys_module *module = parent_module;
575 struct lyd_attr *attr_new, *attr_last = NULL;
Michal Vasko7675c622017-03-02 10:50:07 +0100576 int ret;
Radek Krejci88f29302015-10-30 15:42:33 +0100577
Radek Krejcide9d92c2015-10-30 15:59:59 +0100578 *attr = NULL;
579
Radek Krejci88f29302015-10-30 15:42:33 +0100580 if (data[len] != '{') {
581 if (!strncmp(&data[len], "null", 4)) {
Radek Krejci88f29302015-10-30 15:42:33 +0100582 len += 4;
583 len += skip_ws(&data[len]);
584 return len;
585 }
Radek Krejci48464ed2016-03-17 15:44:09 +0100586 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing begin-object)");
Radek Krejci88f29302015-10-30 15:42:33 +0100587 goto error;
588 }
589
590repeat:
Radek Krejci6a6326d2017-02-27 13:00:52 +0100591 prefix = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100592 len++;
593 len += skip_ws(&data[len]);
594
595 if (data[len] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100596 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the begining of string)");
Radek Krejci88f29302015-10-30 15:42:33 +0100597 return 0;
598 }
599 len++;
600 str = lyjson_parse_text(&data[len], &r);
601 if (!r) {
602 goto error;
603 } else if (data[len + r] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100604 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the end of string)");
Radek Krejci88f29302015-10-30 15:42:33 +0100605 goto error;
606 }
607 if ((name = strchr(str, ':'))) {
608 *name = '\0';
609 name++;
610 prefix = str;
Radek Krejcidfb00d62017-09-06 09:39:35 +0200611 module = (struct lys_module *)ly_ctx_get_module(parent_module->ctx, prefix, NULL, 1);
Radek Krejci88f29302015-10-30 15:42:33 +0100612 if (!module) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100613 LOGVAL(LYE_INELEM, LY_VLOG_NONE, NULL, name);
Radek Krejci88f29302015-10-30 15:42:33 +0100614 goto error;
615 }
616 } else {
617 name = str;
618 }
619
620 /* prepare data for parsing node content */
621 len += r + 1;
622 len += skip_ws(&data[len]);
623 if (data[len] != ':') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100624 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing name-separator)");
Radek Krejci88f29302015-10-30 15:42:33 +0100625 goto error;
626 }
627 len++;
628 len += skip_ws(&data[len]);
629
630 if (data[len] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100631 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the beginning of string)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100632 goto error;
Radek Krejci88f29302015-10-30 15:42:33 +0100633 }
634 len++;
635 value = lyjson_parse_text(&data[len], &r);
636 if (!r) {
637 goto error;
638 } else if (data[len + r] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100639 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the end of string)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100640 free(value);
Radek Krejci88f29302015-10-30 15:42:33 +0100641 goto error;
642 }
643 len += r + 1;
644 len += skip_ws(&data[len]);
645
Michal Vasko7675c622017-03-02 10:50:07 +0100646 ret = lyp_fill_attr(parent_module->ctx, NULL, NULL, prefix, name, value, NULL, &attr_new);
647 if (ret == -1) {
Radek Krejci532e5e92017-02-22 12:59:24 +0100648 free(value);
Michal Vasko253035f2015-12-17 16:58:13 +0100649 goto error;
Michal Vasko7675c622017-03-02 10:50:07 +0100650 } else if (ret == 1) {
651 if (options & LYD_OPT_STRICT) {
652 LOGVAL(LYE_INMETA, LY_VLOG_NONE, NULL, prefix, name, value);
653 free(value);
654 goto error;
655 }
Radek Krejci532e5e92017-02-22 12:59:24 +0100656
Michal Vasko7675c622017-03-02 10:50:07 +0100657 LOGWRN("Unknown \"%s:%s\" metadata with value \"%s\", ignoring.",
658 (prefix ? prefix : "<none>"), name, value);
659 free(value);
660 goto next;
Radek Krejci532e5e92017-02-22 12:59:24 +0100661 }
Michal Vasko7675c622017-03-02 10:50:07 +0100662 free(value);
Radek Krejcia571d942017-02-24 09:26:49 +0100663
Radek Krejci88f29302015-10-30 15:42:33 +0100664 if (!attr_last) {
665 *attr = attr_last = attr_new;
666 } else {
667 attr_last->next = attr_new;
668 attr_last = attr_new;
669 }
670
Radek Krejci532e5e92017-02-22 12:59:24 +0100671next:
Radek Krejci88f29302015-10-30 15:42:33 +0100672 free(str);
Radek Krejcide9d92c2015-10-30 15:59:59 +0100673 str = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100674
675 if (data[len] == ',') {
676 goto repeat;
677 } else if (data[len] != '}') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100678 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing end-object)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100679 goto error;
Radek Krejci88f29302015-10-30 15:42:33 +0100680 }
681 len++;
682 len += skip_ws(&data[len]);
683
684 return len;
685
686error:
687 free(str);
Radek Krejcide9d92c2015-10-30 15:59:59 +0100688 if (*attr) {
Radek Krejci532e5e92017-02-22 12:59:24 +0100689 lyd_free_attr(module->ctx, NULL, *attr, 1);
Radek Krejcide9d92c2015-10-30 15:59:59 +0100690 *attr = NULL;
691 }
Radek Krejci88f29302015-10-30 15:42:33 +0100692 return 0;
693}
694
695struct attr_cont {
696 struct attr_cont *next;
697 struct lyd_attr *attr;
698 struct lys_node *schema;
699 unsigned int index; /** non-zero only in case of leaf-list */
700};
701
Radek Krejcic4831272015-11-01 19:26:34 +0100702static int
Michal Vasko7675c622017-03-02 10:50:07 +0100703store_attrs(struct ly_ctx *ctx, struct attr_cont *attrs, struct lyd_node *first, int options)
Radek Krejcic4831272015-11-01 19:26:34 +0100704{
705 struct lyd_node *diter;
706 struct attr_cont *iter;
Radek Krejci532e5e92017-02-22 12:59:24 +0100707 struct lyd_attr *aiter;
Radek Krejcic4831272015-11-01 19:26:34 +0100708 unsigned int flag_leaflist = 0;
709
710 while (attrs) {
711 iter = attrs;
712 attrs = attrs->next;
713
714 if (iter->index) {
715 flag_leaflist = 1;
716 }
717
718 LY_TREE_FOR(first, diter) {
719 if (iter->schema != diter->schema) {
720 continue;
721 }
722
723 if (flag_leaflist && flag_leaflist != iter->index) {
724 flag_leaflist++;
725 continue;
726 }
727
728 /* we have match */
729 if (diter->attr) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100730 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, diter,
Radek Krejciadb57612016-02-16 13:34:34 +0100731 "attribute (multiple attribute definitions belong to a single element)");
Radek Krejcic4831272015-11-01 19:26:34 +0100732 free(iter);
733 goto error;
734 }
735
736 diter->attr = iter->attr;
Radek Krejci532e5e92017-02-22 12:59:24 +0100737 for (aiter = iter->attr; aiter; aiter = aiter->next) {
738 aiter->parent = diter;
739 }
Michal Vasko7675c622017-03-02 10:50:07 +0100740
Radek Krejcic4831272015-11-01 19:26:34 +0100741 break;
742 }
743
744 if (!diter) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100745 LOGVAL(LYE_XML_MISS, LY_VLOG_NONE, NULL, "element for the specified attribute", iter->attr->name);
Radek Krejcic4831272015-11-01 19:26:34 +0100746 lyd_free_attr(iter->schema->module->ctx, NULL, iter->attr, 1);
747 free(iter);
748 goto error;
749 }
750 free(iter);
Michal Vasko7675c622017-03-02 10:50:07 +0100751
752 /* check edit-config attribute correctness */
753 if ((options & LYD_OPT_EDIT) && lyp_check_edit_attr(ctx, diter->attr, diter, NULL)) {
754 goto error;
755 }
Radek Krejcic4831272015-11-01 19:26:34 +0100756 }
757
758 return 0;
759
760error:
761
762 while (attrs) {
763 iter = attrs;
764 attrs = attrs->next;
765
766 lyd_free_attr(ctx, NULL, iter->attr, 1);
767 free(iter);
768 }
769
770 return -1;
771}
772
Radek Krejci88f29302015-10-30 15:42:33 +0100773static unsigned int
Michal Vasko36ef6932015-12-01 14:30:17 +0100774json_parse_data(struct ly_ctx *ctx, const char *data, const struct lys_node *schema_parent, struct lyd_node **parent,
Radek Krejcibd930122016-08-10 13:28:26 +0200775 struct lyd_node *first_sibling, struct lyd_node *prev, struct attr_cont **attrs, int options,
Michal Vaskoafa7a642016-10-18 15:11:38 +0200776 struct unres_data *unres, struct lyd_node **act_notif)
Radek Krejci5449d472015-10-26 14:35:56 +0100777{
778 unsigned int len = 0;
779 unsigned int r;
Radek Krejcic4831272015-11-01 19:26:34 +0100780 unsigned int flag_leaflist = 0;
Radek Krejci65aca412018-01-24 11:23:06 +0100781 int i;
782 uint8_t pos;
Radek Krejci88f29302015-10-30 15:42:33 +0100783 char *name, *prefix = NULL, *str = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +0100784 const struct lys_module *module = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +0100785 struct lys_node *schema = NULL;
Radek Krejcibd930122016-08-10 13:28:26 +0200786 struct lyd_node *result = NULL, *new, *list, *diter = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100787 struct lyd_attr *attr;
Radek Krejcic4831272015-11-01 19:26:34 +0100788 struct attr_cont *attrs_aux;
Radek Krejci5449d472015-10-26 14:35:56 +0100789
790 /* each YANG data node representation starts with string (node identifier) */
791 if (data[len] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100792 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, (*parent),
Radek Krejciadb57612016-02-16 13:34:34 +0100793 "JSON data (missing quotation-mark at the beginning of string)");
Radek Krejci88f29302015-10-30 15:42:33 +0100794 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100795 }
796 len++;
797
Radek Krejci23238922015-10-27 17:13:34 +0100798 str = lyjson_parse_text(&data[len], &r);
Radek Krejci5449d472015-10-26 14:35:56 +0100799 if (!r) {
800 goto error;
801 } else if (data[len + r] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100802 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, (*parent),
Radek Krejciadb57612016-02-16 13:34:34 +0100803 "JSON data (missing quotation-mark at the end of string)");
Radek Krejci5449d472015-10-26 14:35:56 +0100804 goto error;
805 }
Radek Krejci23238922015-10-27 17:13:34 +0100806 if ((name = strchr(str, ':'))) {
807 *name = '\0';
808 name++;
809 prefix = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100810 if (prefix[0] == '@') {
811 prefix++;
812 }
Radek Krejci23238922015-10-27 17:13:34 +0100813 } else {
814 name = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100815 if (name[0] == '@') {
816 name++;
817 }
Radek Krejci5449d472015-10-26 14:35:56 +0100818 }
819
Radek Krejci5449d472015-10-26 14:35:56 +0100820 /* prepare data for parsing node content */
821 len += r + 1;
822 len += skip_ws(&data[len]);
823 if (data[len] != ':') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100824 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, (*parent), "JSON data (missing name-separator)");
Radek Krejci5449d472015-10-26 14:35:56 +0100825 goto error;
826 }
827 len++;
828 len += skip_ws(&data[len]);
829
Radek Krejci88f29302015-10-30 15:42:33 +0100830 if (str[0] == '@' && !str[1]) {
831 /* process attribute of the parent object (container or list) */
Radek Krejci2a0efef2016-03-24 15:10:40 +0100832 if (!(*parent)) {
833 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "attribute with no corresponding element to belongs to");
Radek Krejci88f29302015-10-30 15:42:33 +0100834 goto error;
835 }
836
Radek Krejci532e5e92017-02-22 12:59:24 +0100837 r = json_parse_attr((*parent)->schema->module, &attr, &data[len], options);
Radek Krejci88f29302015-10-30 15:42:33 +0100838 if (!r) {
Michal Vasko7675c622017-03-02 10:50:07 +0100839 LOGPATH(LY_VLOG_LYD, *parent);
Radek Krejci88f29302015-10-30 15:42:33 +0100840 goto error;
841 }
842 len += r;
843
844 if ((*parent)->attr) {
845 lyd_free_attr(ctx, NULL, attr, 1);
846 } else {
847 (*parent)->attr = attr;
Radek Krejci532e5e92017-02-22 12:59:24 +0100848 for (; attr; attr = attr->next) {
849 attr->parent = *parent;
850 }
Radek Krejci88f29302015-10-30 15:42:33 +0100851 }
Michal Vasko7675c622017-03-02 10:50:07 +0100852
853 /* check edit-config attribute correctness */
854 if ((options & LYD_OPT_EDIT) && lyp_check_edit_attr(ctx, (*parent)->attr, *parent, NULL)) {
855 goto error;
856 }
857
Radek Krejcic4831272015-11-01 19:26:34 +0100858 free(str);
859 return len;
Radek Krejci88f29302015-10-30 15:42:33 +0100860 }
861
Radek Krejci5449d472015-10-26 14:35:56 +0100862 /* find schema node */
863 if (!(*parent)) {
864 /* starting in root */
865 /* get the proper schema */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200866 module = ly_ctx_get_module(ctx, prefix, NULL, 1);
Michal Vaskof53187d2017-01-13 13:23:14 +0100867 if (ctx->data_clb) {
868 if (!module) {
869 module = ctx->data_clb(ctx, prefix, NULL, 0, ctx->data_clb_data);
870 } else if (!module->implemented) {
871 module = ctx->data_clb(ctx, module->name, module->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
872 }
873 }
874 if (module && module->implemented) {
Radek Krejci5449d472015-10-26 14:35:56 +0100875 /* get the proper schema node */
Radek Krejci919a9242016-07-27 08:17:13 +0200876 while ((schema = (struct lys_node *)lys_getnext(schema, NULL, module, 0))) {
Radek Krejci5449d472015-10-26 14:35:56 +0100877 if (!strcmp(schema->name, name)) {
878 break;
879 }
880 }
881 }
882 } else {
Radek Krejci5449d472015-10-26 14:35:56 +0100883 if (prefix) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100884 /* get the proper module to give the chance to load/implement it */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200885 module = ly_ctx_get_module(ctx, prefix, NULL, 1);
Michal Vaskof53187d2017-01-13 13:23:14 +0100886 if (ctx->data_clb) {
887 if (!module) {
Michal Vaskoad43c182017-01-23 09:55:28 +0100888 ctx->data_clb(ctx, prefix, NULL, 0, ctx->data_clb_data);
Michal Vaskof53187d2017-01-13 13:23:14 +0100889 } else if (!module->implemented) {
Michal Vaskoad43c182017-01-23 09:55:28 +0100890 ctx->data_clb(ctx, module->name, module->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
Michal Vaskof53187d2017-01-13 13:23:14 +0100891 }
Radek Krejci5449d472015-10-26 14:35:56 +0100892 }
893 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100894
895 /* go through RPC's input/output following the options' data type */
896 if ((*parent)->schema->nodetype == LYS_RPC) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100897 while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, NULL, LYS_GETNEXT_WITHINOUT))) {
Michal Vaskoafa7a642016-10-18 15:11:38 +0200898 if ((options & LYD_OPT_RPC) && (schema->nodetype == LYS_INPUT)) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100899 break;
Michal Vaskoafa7a642016-10-18 15:11:38 +0200900 } else if ((options & LYD_OPT_RPCREPLY) && (schema->nodetype == LYS_OUTPUT)) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100901 break;
902 }
903 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100904 schema_parent = schema;
905 schema = NULL;
906 }
907
Michal Vasko36ef6932015-12-01 14:30:17 +0100908 if (schema_parent) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100909 while ((schema = (struct lys_node *)lys_getnext(schema, schema_parent, NULL, 0))) {
910 if (!strcmp(schema->name, name)
911 && ((prefix && !strcmp(lys_node_module(schema)->name, prefix))
912 || (!prefix && (lys_node_module(schema) == lys_node_module(schema_parent))))) {
Michal Vasko36ef6932015-12-01 14:30:17 +0100913 break;
914 }
915 }
916 } else {
Michal Vaskof53187d2017-01-13 13:23:14 +0100917 while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, NULL, 0))) {
918 if (!strcmp(schema->name, name)
919 && ((prefix && !strcmp(lys_node_module(schema)->name, prefix))
920 || (!prefix && (lys_node_module(schema) == lyd_node_module(*parent))))) {
Michal Vasko36ef6932015-12-01 14:30:17 +0100921 break;
922 }
Radek Krejci5449d472015-10-26 14:35:56 +0100923 }
924 }
925 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100926
927 module = lys_node_module(schema);
928 if (!module || !module->implemented || module->disabled) {
929 LOGVAL(LYE_INELEM, (*parent ? LY_VLOG_LYD : LY_VLOG_NONE), (*parent), name);
Radek Krejci88f29302015-10-30 15:42:33 +0100930 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100931 }
Radek Krejci88f29302015-10-30 15:42:33 +0100932
933 if (str[0] == '@') {
Radek Krejci88f29302015-10-30 15:42:33 +0100934 /* attribute for some sibling node */
935 if (data[len] == '[') {
936 flag_leaflist = 1;
937 len++;
938 len += skip_ws(&data[len]);
939 }
940
941attr_repeat:
Radek Krejci532e5e92017-02-22 12:59:24 +0100942 r = json_parse_attr((struct lys_module *)module, &attr, &data[len], options);
Radek Krejci88f29302015-10-30 15:42:33 +0100943 if (!r) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100944 LOGPATH(LY_VLOG_LYD, (*parent));
Radek Krejci88f29302015-10-30 15:42:33 +0100945 goto error;
946 }
947 len += r;
948
949 if (attr) {
Radek Krejcic4831272015-11-01 19:26:34 +0100950 attrs_aux = malloc(sizeof *attrs_aux);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200951 LY_CHECK_ERR_GOTO(!attrs_aux, LOGMEM, error);
Radek Krejcic4831272015-11-01 19:26:34 +0100952 attrs_aux->attr = attr;
953 attrs_aux->index = flag_leaflist;
954 attrs_aux->schema = schema;
955 attrs_aux->next = *attrs;
956 *attrs = attrs_aux;
Radek Krejci88f29302015-10-30 15:42:33 +0100957 }
958
959 if (flag_leaflist) {
960 if (data[len] == ',') {
961 len++;
962 len += skip_ws(&data[len]);
963 flag_leaflist++;
964 goto attr_repeat;
965 } else if (data[len] != ']') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100966 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, (*parent), "JSON data (missing end-array)");
Radek Krejci88f29302015-10-30 15:42:33 +0100967 goto error;
968 }
969 len++;
970 len += skip_ws(&data[len]);
971 }
972
Radek Krejcic4831272015-11-01 19:26:34 +0100973 free(str);
974 return len;
Radek Krejci88f29302015-10-30 15:42:33 +0100975 }
976
Radek Krejci5449d472015-10-26 14:35:56 +0100977 switch (schema->nodetype) {
978 case LYS_CONTAINER:
979 case LYS_LIST:
980 case LYS_NOTIF:
981 case LYS_RPC:
Michal Vaskoafa7a642016-10-18 15:11:38 +0200982 case LYS_ACTION:
Radek Krejci5449d472015-10-26 14:35:56 +0100983 result = calloc(1, sizeof *result);
984 break;
985 case LYS_LEAF:
986 case LYS_LEAFLIST:
987 result = calloc(1, sizeof(struct lyd_node_leaf_list));
988 break;
989 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +0200990 case LYS_ANYDATA:
991 result = calloc(1, sizeof(struct lyd_node_anydata));
Radek Krejci5449d472015-10-26 14:35:56 +0100992 break;
993 default:
994 LOGINT;
Radek Krejci595060f2015-10-30 16:29:58 +0100995 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100996 }
Radek Krejcia8d111f2017-05-31 13:57:37 +0200997 LY_CHECK_ERR_GOTO(!result, LOGMEM, error);
Michal Vasko253035f2015-12-17 16:58:13 +0100998
Radek Krejci61767ca2016-09-19 14:21:55 +0200999 result->prev = result;
Radek Krejci5449d472015-10-26 14:35:56 +01001000 result->schema = schema;
Radek Krejci61767ca2016-09-19 14:21:55 +02001001 result->parent = *parent;
1002 diter = NULL;
Radek Krejci65aca412018-01-24 11:23:06 +01001003 if (schema->nodetype == LYS_LEAF && lys_is_key((struct lys_node_leaf *)schema, &pos)) {
Michal Vasko80389542018-02-08 14:35:32 +01001004 /* it is key and we need to insert it into a correct place (we must have parent then, a key cannot be top-level) */
1005 assert(*parent);
Radek Krejci61767ca2016-09-19 14:21:55 +02001006 for (i = 0, diter = (*parent)->child;
Radek Krejci65aca412018-01-24 11:23:06 +01001007 diter && i < pos && diter->schema->nodetype == LYS_LEAF && lys_is_key((struct lys_node_leaf *)diter->schema, NULL);
Radek Krejci61767ca2016-09-19 14:21:55 +02001008 i++, diter = diter->next);
1009 if (diter) {
1010 /* out of order insertion - insert list's key to the correct position, before the diter */
1011 if ((*parent)->child == diter) {
1012 (*parent)->child = result;
1013 /* update first_sibling */
1014 first_sibling = result;
1015 }
1016 if (diter->prev->next) {
1017 diter->prev->next = result;
1018 }
1019 result->prev = diter->prev;
1020 diter->prev = result;
1021 result->next = diter;
1022 }
1023 }
1024 if (!diter) {
1025 /* simplified (faster) insert as the last node */
1026 if (*parent && !(*parent)->child) {
1027 (*parent)->child = result;
1028 }
1029 if (prev) {
1030 result->prev = prev;
1031 prev->next = result;
1032
1033 /* fix the "last" pointer */
1034 first_sibling->prev = result;
1035 } else {
1036 result->prev = result;
1037 first_sibling = result;
1038 }
1039 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01001040 result->validity = ly_new_node_validity(result->schema);
Radek Krejci46165822016-08-26 14:06:27 +02001041 if (resolve_applies_when(schema, 0, NULL)) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01001042 result->when_status = LYD_WHEN;
1043 }
Radek Krejci5449d472015-10-26 14:35:56 +01001044
Radek Krejci5449d472015-10-26 14:35:56 +01001045 /* type specific processing */
1046 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
1047 /* type detection and assigning the value */
Radek Krejci45f41dd2017-02-09 14:11:09 +01001048 r = json_get_value((struct lyd_node_leaf_list *)result, &first_sibling, &data[len], options, unres);
Radek Krejci5449d472015-10-26 14:35:56 +01001049 if (!r) {
1050 goto error;
1051 }
Radek Krejci88f29302015-10-30 15:42:33 +01001052 while(result->next) {
1053 result = result->next;
1054 }
1055
Radek Krejci5449d472015-10-26 14:35:56 +01001056 len += r;
1057 len += skip_ws(&data[len]);
Radek Krejcibf2abff2016-08-23 15:51:52 +02001058 } else if (schema->nodetype & LYS_ANYDATA) {
Radek Krejci4ae82942016-09-19 16:41:06 +02001059 r = json_get_anydata((struct lyd_node_anydata *)result, &data[len]);
Radek Krejci5449d472015-10-26 14:35:56 +01001060 if (!r) {
1061 goto error;
1062 }
1063 len += r;
1064 len += skip_ws(&data[len]);
Michal Vaskoafa7a642016-10-18 15:11:38 +02001065 } else if (schema->nodetype & (LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
1066 if (schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1067 if (!(options & LYD_OPT_RPC) || *act_notif) {
1068 LOGVAL(LYE_INELEM, LY_VLOG_LYD, result, schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01001069 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unexpected %s node \"%s\".",
Michal Vaskoafa7a642016-10-18 15:11:38 +02001070 (schema->nodetype == LYS_RPC ? "rpc" : "action"), schema->name);
1071 goto error;
1072 }
1073 *act_notif = result;
1074 } else if (schema->nodetype == LYS_NOTIF) {
1075 if (!(options & LYD_OPT_NOTIF) || *act_notif) {
1076 LOGVAL(LYE_INELEM, LY_VLOG_LYD, result, schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01001077 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unexpected notification node \"%s\".", schema->name);
Michal Vaskoafa7a642016-10-18 15:11:38 +02001078 goto error;
1079 }
1080 *act_notif = result;
1081 }
1082
Radek Krejci5449d472015-10-26 14:35:56 +01001083 if (data[len] != '{') {
Radek Krejci48464ed2016-03-17 15:44:09 +01001084 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing begin-object)");
Radek Krejci5449d472015-10-26 14:35:56 +01001085 goto error;
1086 }
1087 len++;
1088 len += skip_ws(&data[len]);
1089
1090 if (data[len] != '}') {
1091 /* non-empty container */
Radek Krejcic4831272015-11-01 19:26:34 +01001092 len--;
1093 diter = NULL;
1094 attrs_aux = NULL;
1095 do {
1096 len++;
1097 len += skip_ws(&data[len]);
1098
Michal Vaskoafa7a642016-10-18 15:11:38 +02001099 r = json_parse_data(ctx, &data[len], NULL, &result, result->child, diter, &attrs_aux, options, unres, act_notif);
Radek Krejcic4831272015-11-01 19:26:34 +01001100 if (!r) {
1101 goto error;
1102 }
1103 len += r;
1104
1105 if (result->child) {
1106 diter = result->child->prev;
1107 }
1108 } while(data[len] == ',');
1109
1110 /* store attributes */
Michal Vasko7675c622017-03-02 10:50:07 +01001111 if (store_attrs(ctx, attrs_aux, result->child, options)) {
Radek Krejci5449d472015-10-26 14:35:56 +01001112 goto error;
1113 }
Radek Krejci5449d472015-10-26 14:35:56 +01001114 }
1115
1116 if (data[len] != '}') {
Radek Krejci48464ed2016-03-17 15:44:09 +01001117 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing end-object)");
Radek Krejci5449d472015-10-26 14:35:56 +01001118 goto error;
1119 }
1120 len++;
1121 len += skip_ws(&data[len]);
1122
Radek Krejcifb7156e2016-10-27 13:39:56 +02001123 /* if we have empty non-presence container, mark it as default */
Radek Krejci2537fd32016-09-07 16:22:41 +02001124 if (schema->nodetype == LYS_CONTAINER && !result->child &&
Radek Krejcid3e73722016-05-23 12:24:55 +02001125 !result->attr && !((struct lys_node_container *)schema)->presence) {
Radek Krejcifb7156e2016-10-27 13:39:56 +02001126 result->dflt = 1;
Radek Krejci0c0086a2016-03-24 15:20:28 +01001127 }
1128
Radek Krejci5449d472015-10-26 14:35:56 +01001129 } else if (schema->nodetype == LYS_LIST) {
1130 if (data[len] != '[') {
Radek Krejci48464ed2016-03-17 15:44:09 +01001131 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing begin-array)");
Radek Krejci5449d472015-10-26 14:35:56 +01001132 goto error;
1133 }
1134
1135 list = result;
1136 do {
1137 len++;
1138 len += skip_ws(&data[len]);
Radek Krejci23238922015-10-27 17:13:34 +01001139
Radek Krejcic4831272015-11-01 19:26:34 +01001140 if (data[len] != '{') {
Radek Krejci48464ed2016-03-17 15:44:09 +01001141 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result,
Radek Krejciadb57612016-02-16 13:34:34 +01001142 "JSON data (missing list instance's begin-object)");
Radek Krejci5449d472015-10-26 14:35:56 +01001143 goto error;
1144 }
Radek Krejcic4831272015-11-01 19:26:34 +01001145 diter = NULL;
1146 attrs_aux = NULL;
1147 do {
1148 len++;
1149 len += skip_ws(&data[len]);
1150
Michal Vaskoafa7a642016-10-18 15:11:38 +02001151 r = json_parse_data(ctx, &data[len], NULL, &list, list->child, diter, &attrs_aux, options, unres, act_notif);
Radek Krejcic4831272015-11-01 19:26:34 +01001152 if (!r) {
1153 goto error;
1154 }
1155 len += r;
1156
Radek Krejci52934692015-11-01 20:08:15 +01001157 if (list->child) {
Radek Krejcic4831272015-11-01 19:26:34 +01001158 diter = list->child->prev;
1159 }
1160 } while(data[len] == ',');
1161
1162 /* store attributes */
Michal Vasko7675c622017-03-02 10:50:07 +01001163 if (store_attrs(ctx, attrs_aux, list->child, options)) {
Radek Krejcic4831272015-11-01 19:26:34 +01001164 goto error;
1165 }
1166
1167 if (data[len] != '}') {
1168 /* expecting end-object */
Radek Krejci48464ed2016-03-17 15:44:09 +01001169 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result,
Radek Krejciadb57612016-02-16 13:34:34 +01001170 "JSON data (missing list instance's end-object)");
Radek Krejcic4831272015-11-01 19:26:34 +01001171 goto error;
1172 }
1173 len++;
Radek Krejci5449d472015-10-26 14:35:56 +01001174 len += skip_ws(&data[len]);
1175
1176 if (data[len] == ',') {
Radek Krejci93fab982016-02-03 15:58:19 +01001177 /* various validation checks */
Radek Krejci45f41dd2017-02-09 14:11:09 +01001178 if (lyv_data_context(list, options, unres)) {
1179 goto error;
1180 }
1181
Radek Krejcicf748252017-09-04 11:11:14 +02001182 ly_err_clean(ly_parser_data.ctx, 1);
Michal Vaskoad2e44a2017-01-03 10:31:35 +01001183 if (lyv_data_content(list, options, unres) ||
1184 lyv_multicases(list, NULL, prev ? &first_sibling : NULL, 0, NULL)) {
Radek Krejci93fab982016-02-03 15:58:19 +01001185 if (ly_errno) {
1186 goto error;
1187 }
1188 }
Radek Krejci93fab982016-02-03 15:58:19 +01001189
Radek Krejci5449d472015-10-26 14:35:56 +01001190 /* another instance of the list */
1191 new = calloc(1, sizeof *new);
Radek Krejcia8d111f2017-05-31 13:57:37 +02001192 LY_CHECK_ERR_GOTO(!new, LOGMEM, error);
Radek Krejci5449d472015-10-26 14:35:56 +01001193 new->parent = list->parent;
1194 new->prev = list;
1195 list->next = new;
1196
Radek Krejcie1794882017-02-08 13:23:38 +01001197 /* copy the validity and when flags */
1198 new->validity = list->validity;
1199 new->when_status = list->when_status;
1200
Radek Krejci5449d472015-10-26 14:35:56 +01001201 /* fix the "last" pointer */
Radek Krejci2d5525d2016-04-04 15:43:30 +02001202 first_sibling->prev = new;
Radek Krejci5449d472015-10-26 14:35:56 +01001203
1204 new->schema = list->schema;
Radek Krejci5449d472015-10-26 14:35:56 +01001205 list = new;
1206 }
1207 } while (data[len] == ',');
Radek Krejcib915fb92017-02-08 14:12:40 +01001208 result = list;
Radek Krejci5449d472015-10-26 14:35:56 +01001209
1210 if (data[len] != ']') {
Radek Krejci48464ed2016-03-17 15:44:09 +01001211 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing end-array)");
Radek Krejci5449d472015-10-26 14:35:56 +01001212 goto error;
1213 }
1214 len++;
1215 len += skip_ws(&data[len]);
1216 }
1217
1218 /* various validation checks */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01001219 if (lyv_data_context(result, options, unres)) {
Michal Vasko10e586f2016-05-18 13:25:30 +02001220 goto error;
1221 }
1222
Radek Krejcicf748252017-09-04 11:11:14 +02001223 ly_err_clean(ly_parser_data.ctx, 1);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01001224 if (lyv_data_content(result, options, unres) ||
1225 lyv_multicases(result, NULL, prev ? &first_sibling : NULL, 0, NULL)) {
Radek Krejci5449d472015-10-26 14:35:56 +01001226 if (ly_errno) {
1227 goto error;
1228 }
1229 }
1230
Radek Krejcica7efb72016-01-18 13:06:01 +01001231 /* validation successful */
Radek Krejci63b79c82016-08-10 10:09:33 +02001232 if (result->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01001233 /* postpone checking of unique when there will be all list/leaflist instances */
1234 result->validity |= LYD_VAL_UNIQUE;
Radek Krejci63b79c82016-08-10 10:09:33 +02001235 }
Radek Krejcica7efb72016-01-18 13:06:01 +01001236
Radek Krejci88f29302015-10-30 15:42:33 +01001237 if (!(*parent)) {
1238 *parent = result;
1239 }
1240
Radek Krejcide9d92c2015-10-30 15:59:59 +01001241 free(str);
Radek Krejci5449d472015-10-26 14:35:56 +01001242 return len;
1243
1244error:
Radek Krejci0c0086a2016-03-24 15:20:28 +01001245 len = 0;
Radek Krejci0c0086a2016-03-24 15:20:28 +01001246 /* cleanup */
1247 for (i = unres->count - 1; i >= 0; i--) {
1248 /* remove unres items connected with the node being removed */
1249 if (unres->node[i] == result) {
1250 unres_data_del(unres, i);
1251 }
Radek Krejci88f29302015-10-30 15:42:33 +01001252 }
1253 while (*attrs) {
Radek Krejcic4831272015-11-01 19:26:34 +01001254 attrs_aux = *attrs;
Radek Krejci88f29302015-10-30 15:42:33 +01001255 *attrs = (*attrs)->next;
1256
Radek Krejcic4831272015-11-01 19:26:34 +01001257 lyd_free_attr(ctx, NULL, attrs_aux->attr, 1);
1258 free(attrs_aux);
Radek Krejci88f29302015-10-30 15:42:33 +01001259 }
1260
Radek Krejci5449d472015-10-26 14:35:56 +01001261 lyd_free(result);
Radek Krejci88f29302015-10-30 15:42:33 +01001262 free(str);
1263
Radek Krejci0c0086a2016-03-24 15:20:28 +01001264 return len;
Radek Krejci5449d472015-10-26 14:35:56 +01001265}
1266
1267struct lyd_node *
Michal Vasko945b96b2016-10-18 11:49:12 +02001268lyd_parse_json(struct ly_ctx *ctx, const char *data, int options, const struct lyd_node *rpc_act,
1269 const struct lyd_node *data_tree)
Radek Krejci5449d472015-10-26 14:35:56 +01001270{
Michal Vaskoafa7a642016-10-18 15:11:38 +02001271 struct lyd_node *result = NULL, *next, *iter, *reply_parent = NULL, *reply_top = NULL, *act_notif = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +01001272 struct unres_data *unres = NULL;
Radek Krejcic4831272015-11-01 19:26:34 +01001273 unsigned int len = 0, r;
Michal Vaskoafa7a642016-10-18 15:11:38 +02001274 int i, act_cont = 0;
Radek Krejcic4831272015-11-01 19:26:34 +01001275 struct attr_cont *attrs = NULL;
Radek Krejci63b79c82016-08-10 10:09:33 +02001276 struct ly_set *set;
Radek Krejci5449d472015-10-26 14:35:56 +01001277
Radek Krejcicf748252017-09-04 11:11:14 +02001278 ly_err_clean(ly_parser_data.ctx, 1);
Radek Krejci2342cf62016-01-29 16:48:23 +01001279
Michal Vaskoafa7a642016-10-18 15:11:38 +02001280 if (!ctx || !data) {
Radek Krejci5449d472015-10-26 14:35:56 +01001281 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
1282 return NULL;
1283 }
1284
Radek Krejcic4831272015-11-01 19:26:34 +01001285 /* skip leading whitespaces */
1286 len += skip_ws(&data[len]);
1287
Michal Vasko24d982f2016-04-18 15:13:58 +02001288 /* no data (or whitespaces only) are fine */
1289 if (!data[len]) {
Michal Vasko85c63f42018-01-02 10:43:45 +01001290empty:
Radek Krejcib1ed7e52017-08-09 12:42:35 +02001291 if (options & LYD_OPT_DATA_ADD_YANGLIB) {
1292 result = ly_ctx_info(ctx);
1293 }
Michal Vasko24d982f2016-04-18 15:13:58 +02001294 lyd_validate(&result, options, ctx);
1295 return result;
1296 }
1297
Radek Krejcic4831272015-11-01 19:26:34 +01001298 /* expect top-level { */
1299 if (data[len] != '{') {
Radek Krejci48464ed2016-03-17 15:44:09 +01001300 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top level begin-object)");
Michal Vasko24d982f2016-04-18 15:13:58 +02001301 return NULL;
1302 }
1303
Michal Vasko85c63f42018-01-02 10:43:45 +01001304 /* check for empty object */
1305 r = len + 1;
1306 r += skip_ws(&data[r]);
1307 if (data[r] == '}') {
1308 goto empty;
1309 }
1310
Michal Vasko24d982f2016-04-18 15:13:58 +02001311 unres = calloc(1, sizeof *unres);
Radek Krejcia8d111f2017-05-31 13:57:37 +02001312 LY_CHECK_ERR_RETURN(!unres, LOGMEM, NULL);
Radek Krejcic4831272015-11-01 19:26:34 +01001313
Michal Vaskoafa7a642016-10-18 15:11:38 +02001314 /* create RPC/action reply part that is not in the parsed data */
1315 if (rpc_act) {
1316 assert(options & LYD_OPT_RPCREPLY);
1317 if (rpc_act->schema->nodetype == LYS_RPC) {
1318 /* RPC request */
1319 reply_top = reply_parent = _lyd_new(NULL, rpc_act->schema, 0);
1320 } else {
1321 /* action request */
1322 reply_top = lyd_dup(rpc_act, 1);
1323 LY_TREE_DFS_BEGIN(reply_top, iter, reply_parent) {
1324 if (reply_parent->schema->nodetype == LYS_ACTION) {
1325 break;
1326 }
1327 LY_TREE_DFS_END(reply_top, iter, reply_parent);
1328 }
1329 if (!reply_parent) {
1330 LOGERR(LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *rpc_act).", __func__);
Michal Vaskoafa7a642016-10-18 15:11:38 +02001331 goto error;
1332 }
1333 lyd_free_withsiblings(reply_parent->child);
1334 }
1335 }
1336
1337 iter = NULL;
1338 next = reply_parent;
Radek Krejcic4831272015-11-01 19:26:34 +01001339 do {
1340 len++;
1341 len += skip_ws(&data[len]);
1342
Michal Vaskoafa7a642016-10-18 15:11:38 +02001343 if (!act_cont) {
1344 if (!strncmp(&data[len], "\"yang:action\"", 13)) {
1345 len += 13;
1346 len += skip_ws(&data[len]);
1347 if (data[len] != ':') {
1348 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top-level begin-object)");
Michal Vaskoafa7a642016-10-18 15:11:38 +02001349 goto error;
1350 }
1351 ++len;
1352 len += skip_ws(&data[len]);
1353 if (data[len] != '{') {
1354 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top level yang:action object)");
Michal Vaskoafa7a642016-10-18 15:11:38 +02001355 goto error;
1356 }
1357 ++len;
1358 len += skip_ws(&data[len]);
1359
1360 act_cont = 1;
1361 } else {
1362 act_cont = -1;
1363 }
1364 }
1365
1366 r = json_parse_data(ctx, &data[len], NULL, &next, result, iter, &attrs, options, unres, &act_notif);
Radek Krejcic4831272015-11-01 19:26:34 +01001367 if (!r) {
Michal Vasko24d982f2016-04-18 15:13:58 +02001368 goto error;
Radek Krejcic4831272015-11-01 19:26:34 +01001369 }
1370 len += r;
1371
1372 if (!result) {
Radek Krejcie4f9dcd2017-10-27 15:22:41 +02001373 if (reply_parent) {
1374 result = next->child;
1375 iter = next->child;
1376 } else {
1377 for (iter = next; iter && iter->prev->next; iter = iter->prev);
1378 result = iter;
1379 if (iter && (options & LYD_OPT_DATA_ADD_YANGLIB) && iter->schema->module == ctx->models.list[ctx->internal_module_count - 1]) {
1380 /* ietf-yang-library data present, so ignore the option to add them */
1381 options &= ~LYD_OPT_DATA_ADD_YANGLIB;
1382 }
1383 iter = next;
Radek Krejci06f8bb92017-08-02 15:36:25 +02001384 }
Radek Krejcie4f9dcd2017-10-27 15:22:41 +02001385 } else {
1386 iter = result->prev;
Radek Krejcic4831272015-11-01 19:26:34 +01001387 }
Radek Krejcie4f9dcd2017-10-27 15:22:41 +02001388 if (!reply_parent) {
1389 next = NULL;
Radek Krejcic4831272015-11-01 19:26:34 +01001390 }
Michal Vaskoafa7a642016-10-18 15:11:38 +02001391 } while (data[len] == ',');
Radek Krejcic4831272015-11-01 19:26:34 +01001392
1393 if (data[len] != '}') {
1394 /* expecting end-object */
Radek Krejci48464ed2016-03-17 15:44:09 +01001395 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top-level end-object)");
Michal Vasko24d982f2016-04-18 15:13:58 +02001396 goto error;
Radek Krejcic4831272015-11-01 19:26:34 +01001397 }
1398 len++;
1399 len += skip_ws(&data[len]);
1400
Michal Vaskoafa7a642016-10-18 15:11:38 +02001401 if (act_cont == 1) {
1402 if (data[len] != '}') {
1403 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top-level end-object)");
1404 goto error;
1405 }
1406 len++;
1407 len += skip_ws(&data[len]);
1408 }
1409
Radek Krejcic4831272015-11-01 19:26:34 +01001410 /* store attributes */
Michal Vasko7675c622017-03-02 10:50:07 +01001411 if (store_attrs(ctx, attrs, result, options)) {
Michal Vasko24d982f2016-04-18 15:13:58 +02001412 goto error;
Radek Krejcic4831272015-11-01 19:26:34 +01001413 }
Radek Krejci5449d472015-10-26 14:35:56 +01001414
Michal Vaskoafa7a642016-10-18 15:11:38 +02001415 if (reply_top) {
1416 result = reply_top;
1417 }
1418
Michal Vaskoc1cf86f2015-11-04 09:54:51 +01001419 if (!result) {
1420 LOGERR(LY_EVALID, "Model for the data to be linked with not found.");
Michal Vasko24d982f2016-04-18 15:13:58 +02001421 goto error;
Michal Vaskoc1cf86f2015-11-04 09:54:51 +01001422 }
1423
Michal Vaskoafa7a642016-10-18 15:11:38 +02001424 if ((options & LYD_OPT_RPCREPLY) && (rpc_act->schema->nodetype != LYS_RPC)) {
1425 /* action reply */
1426 act_notif = reply_parent;
1427 } else if ((options & (LYD_OPT_RPC | LYD_OPT_NOTIF)) && !act_notif) {
1428 ly_vecode = LYVE_INELEM;
1429 LOGVAL(LYE_SPEC, LY_VLOG_LYD, result, "Missing %s node.", (options & LYD_OPT_RPC ? "action" : "notification"));
1430 goto error;
1431 }
1432
Radek Krejci06f8bb92017-08-02 15:36:25 +02001433 /* add missing ietf-yang-library if requested */
1434 if (options & LYD_OPT_DATA_ADD_YANGLIB) {
Radek Krejcib1ed7e52017-08-09 12:42:35 +02001435 if (lyd_merge(result, ly_ctx_info(ctx), LYD_OPT_DESTRUCT | LYD_OPT_EXPLICIT)) {
Radek Krejci06f8bb92017-08-02 15:36:25 +02001436 LOGERR(LY_EINT, "Adding ietf-yang-library data failed.");
1437 goto error;
1438 }
1439 }
1440
Radek Krejci63b79c82016-08-10 10:09:33 +02001441 /* check for uniquness of top-level lists/leaflists because
1442 * only the inner instances were tested in lyv_data_content() */
1443 set = ly_set_new();
1444 LY_TREE_FOR(result, iter) {
1445 if (!(iter->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) || !(iter->validity & LYD_VAL_UNIQUE)) {
1446 continue;
1447 }
1448
1449 /* check each list/leaflist only once */
1450 i = set->number;
1451 if (ly_set_add(set, iter->schema, 0) != i) {
1452 /* already checked */
1453 continue;
1454 }
1455
1456 if (lyv_data_unique(iter, result)) {
1457 ly_set_free(set);
1458 goto error;
1459 }
1460 }
1461 ly_set_free(set);
1462
Radek Krejci46165822016-08-26 14:06:27 +02001463 /* add/validate default values, unres */
Michal Vaskoafa7a642016-10-18 15:11:38 +02001464 if (lyd_defaults_add_unres(&result, options, ctx, data_tree, act_notif, unres)) {
Michal Vasko24d982f2016-04-18 15:13:58 +02001465 goto error;
Radek Krejci5c162452016-03-23 13:36:01 +01001466 }
1467
Radek Krejci46165822016-08-26 14:06:27 +02001468 /* check for missing top level mandatory nodes */
Michal Vaskoad2e44a2017-01-03 10:31:35 +01001469 if (!(options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER))
1470 && lyd_check_mandatory_tree((act_notif ? act_notif : result), ctx, options)) {
Michal Vasko24d982f2016-04-18 15:13:58 +02001471 goto error;
Radek Krejci5c162452016-03-23 13:36:01 +01001472 }
1473
Radek Krejci5449d472015-10-26 14:35:56 +01001474 free(unres->node);
1475 free(unres->type);
Radek Krejci5449d472015-10-26 14:35:56 +01001476 free(unres);
1477
1478 return result;
Michal Vasko24d982f2016-04-18 15:13:58 +02001479
1480error:
1481 lyd_free_withsiblings(result);
Radek Krejci1fe41792017-10-27 14:47:05 +02001482 if (reply_top && result != reply_top) {
1483 lyd_free_withsiblings(reply_top);
1484 }
Michal Vasko24d982f2016-04-18 15:13:58 +02001485 free(unres->node);
1486 free(unres->type);
1487 free(unres);
1488
1489 return NULL;
Radek Krejci5449d472015-10-26 14:35:56 +01001490}