1 /**
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 *
8 * 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
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15 #define _GNU_SOURCE
16 #include <assert.h>
17 #include <ctype.h>
18 #include <limits.h>
19 #include <errno.h>
20 #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"
30 #include "xml_internal.h"
31
32 static int
lyjson_isspace(int c)33 lyjson_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
46 static unsigned int
skip_ws(const char * data)47 skip_ws(const char *data)
48 {
49 unsigned int len = 0;
50
51 /* skip leading whitespaces */
52 while (data[len] && lyjson_isspace(data[len])) {
53 len++;
54 }
55
56 return len;
57 }
58
59 static char *
lyjson_parse_text(struct ly_ctx * ctx,const char * data,unsigned int * len)60 lyjson_parse_text(struct ly_ctx *ctx, const char *data, unsigned int *len)
61 {
62 #define BUFSIZE 1024
63
64 char buf[BUFSIZE];
65 char *result = NULL, *aux;
66 int o, size = 0;
67 unsigned int r, i;
68 int32_t value;
69
70 for (*len = o = 0; data[*len] && data[*len] != '"'; o++) {
71 if (o > BUFSIZE - 4) {
72 /* add buffer into the result */
73 if (result) {
74 size = size + o;
75 aux = ly_realloc(result, size + 1);
76 LY_CHECK_ERR_RETURN(!aux, LOGMEM(ctx), NULL);
77 result = aux;
78 } else {
79 size = o;
80 result = malloc((size + 1) * sizeof *result);
81 LY_CHECK_ERR_RETURN(!result, LOGMEM(ctx), NULL);
82 }
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 */
142 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "character escape sequence");
143 goto error;
144
145 }
146 r = pututf8(ctx, &buf[o], value);
147 if (!r) {
148 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "character UTF8 character");
149 goto error;
150 }
151 o += r - 1; /* o is ++ in for loop */
152 (*len) += i; /* number of read characters */
153 } else if ((unsigned char)(data[*len]) < 0x20) {
154 /* In C, char != unsigned char != signed char, so let's work with ASCII explicitly */
155 /* control characters must be escaped */
156 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "control character (unescaped)");
157 goto error;
158 } else {
159 /* unescaped character */
160 r = copyutf8(ctx, &buf[o], &data[*len]);
161 if (!r) {
162 goto error;
163 }
164
165 o += r - 1; /* o is ++ in for loop */
166 (*len) += r;
167 }
168 }
169
170 #undef BUFSIZE
171
172 if (o) {
173 if (result) {
174 size = size + o;
175 aux = ly_realloc(result, size + 1);
176 LY_CHECK_ERR_RETURN(!aux, LOGMEM(ctx), NULL);
177 result = aux;
178 } else {
179 size = o;
180 result = malloc((size + 1) * sizeof *result);
181 LY_CHECK_ERR_RETURN(!result, LOGMEM(ctx), NULL);
182 }
183 memcpy(&result[size - o], buf, o);
184 }
185 if (result) {
186 result[size] = '\0';
187 } else {
188 size = 0;
189 result = strdup("");
190 LY_CHECK_ERR_RETURN(!result, LOGMEM(ctx), NULL);
191 }
192
193 return result;
194
195 error:
196 free(result);
197 return NULL;
198 }
199
200 static unsigned int
lyjson_parse_number(struct ly_ctx * ctx,const char * data)201 lyjson_parse_number(struct ly_ctx *ctx, const char *data)
202 {
203 unsigned int len = 0;
204
205 if (data[len] == '-') {
206 ++len;
207 }
208
209 if (data[len] == '0') {
210 ++len;
211 } else if (isdigit(data[len])) {
212 ++len;
213 while (isdigit(data[len])) {
214 ++len;
215 }
216 } else {
217 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid character in JSON Number value ('%c').", data[len]);
218 return 0;
219 }
220
221 if (data[len] == '.') {
222 ++len;
223 if (!isdigit(data[len])) {
224 if (data[len]) {
225 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid character in JSON Number value ('%c').", data[len]);
226 } else {
227 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid character in JSON Number value (EOF).");
228 }
229 return 0;
230 }
231 while (isdigit(data[len])) {
232 ++len;
233 }
234 }
235
236 if ((data[len] == 'e') || (data[len] == 'E')) {
237 ++len;
238 if ((data[len] == '+') || (data[len] == '-')) {
239 ++len;
240 }
241 while (isdigit(data[len])) {
242 ++len;
243 }
244 }
245
246 if (data[len] && (data[len] != ',') && (data[len] != ']') && (data[len] != '}') && !lyjson_isspace(data[len])) {
247 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid character in JSON Number value ('%c').", data[len]);
248 return 0;
249 }
250
251 return len;
252 }
253
254 static char *
lyjson_convert_enumber(struct ly_ctx * ctx,const char * number,unsigned int num_len,char * e_ptr)255 lyjson_convert_enumber(struct ly_ctx *ctx, const char *number, unsigned int num_len, char *e_ptr)
256 {
257 char *ptr, *num;
258 const char *number_ptr;
259 long int e_val;
260 int dot_pos, chars_to_dot, minus;
261 unsigned int num_len_no_e;
262
263 if (*number == '-') {
264 minus = 1;
265 ++number;
266 --num_len;
267 } else {
268 minus = 0;
269 }
270
271 num_len_no_e = e_ptr - number;
272
273 errno = 0;
274 ++e_ptr;
275 e_val = strtol(e_ptr, &ptr, 10);
276 if (errno) {
277 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Exponent out-of-bounds in a JSON Number value (%.*s).",
278 num_len - (e_ptr - number), e_ptr);
279 return NULL;
280 } else if (ptr != number + num_len) {
281 /* we checked this already */
282 LOGINT(ctx);
283 return NULL;
284 }
285
286 if ((ptr = strnchr(number, '.', num_len_no_e))) {
287 dot_pos = ptr - number;
288 } else {
289 dot_pos = num_len_no_e;
290 }
291
292 dot_pos += e_val;
293
294 /* allocate enough memory */
295 if (dot_pos < 1) {
296 /* (.XXX)XXX[.]XXXX */
297 num = malloc((minus ? 1 : 0) + -dot_pos + 2 + (num_len_no_e - (ptr ? 1 : 0)) + 1);
298 } else if (dot_pos < (signed)num_len_no_e) {
299 /* XXXX(.)XX.XXX */
300 num = malloc((minus ? 1 : 0) + num_len_no_e + (ptr ? 0 : 1) + 1);
301 } else {
302 /* XXX[.]XXXX(XXX.) */
303 num = malloc((minus ? 1 : 0) + (dot_pos - (ptr ? 2 : 1)) + 1);
304 }
305 LY_CHECK_ERR_RETURN(!num, LOGMEM(ctx), NULL);
306 if (minus) {
307 strcpy(num, "-");
308 } else {
309 num[0] = '\0';
310 }
311
312 if (dot_pos < 1) {
313 strcat(num, "0.");
314 }
315 if (dot_pos < 0) {
316 sprintf(num + strlen(num), "%0*d", -dot_pos, 0);
317 }
318
319 chars_to_dot = dot_pos;
320 for (ptr = num + strlen(num), number_ptr = number; (unsigned)(number_ptr - number) < num_len_no_e; ) {
321 if (!chars_to_dot) {
322 *ptr = '.';
323 ++ptr;
324 chars_to_dot = -1;
325 } else if (isdigit(*number_ptr)) {
326 *ptr = *number_ptr;
327 ++ptr;
328 ++number_ptr;
329 if (chars_to_dot > 0) {
330 --chars_to_dot;
331 }
332 } else if (*number_ptr == '.') {
333 ++number_ptr;
334 } else {
335 LOGINT(ctx);
336 free(num);
337 return NULL;
338 }
339 }
340 *ptr = '\0';
341
342 if (dot_pos > (signed)num_len_no_e) {
343 sprintf(num + strlen(num), "%0*d", dot_pos - num_len_no_e, 0);
344 }
345
346 return num;
347 }
348
349 static unsigned int
lyjson_parse_boolean(struct ly_ctx * ctx,const char * data)350 lyjson_parse_boolean(struct ly_ctx *ctx, const char *data)
351 {
352 unsigned int len = 0;
353
354 if (!strncmp(data, "false", 5)) {
355 len = 5;
356 } else if (!strncmp(data, "true", 4)) {
357 len = 4;
358 }
359
360 if (data[len] && data[len] != ',' && data[len] != ']' && data[len] != '}' && !lyjson_isspace(data[len])) {
361 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON literal value (expected true or false)");
362 return 0;
363 }
364
365 return len;
366 }
367
368 static unsigned int
json_get_anydata(struct lyd_node_anydata * any,const char * data)369 json_get_anydata(struct lyd_node_anydata *any, const char *data)
370 {
371 struct ly_ctx *ctx = any->schema->module->ctx;
372 unsigned int len = 0, c = 0, skip = 0;
373 char *str;
374
375 if (data[len] == '"') {
376 len = 1;
377 str = lyjson_parse_text(ctx, &data[len], &c);
378 if (!str) {
379 return 0;
380 }
381 if (data[len + c] != '"') {
382 free(str);
383 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, any,
384 "JSON data (missing quotation-mark at the end of string)");
385 return 0;
386 }
387
388 any->value.str = lydict_insert_zc(ctx, str);
389 any->value_type = LYD_ANYDATA_CONSTSTRING;
390 return len + c + 1;
391 } else if (data[len] != '{') {
392 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, any, "anydata/anyxml content (not an object nor string)");
393 return 0;
394 }
395
396 /* count opening '{' and closing '}' brackets to get the end of the object without its parsing */
397 c = len = 0;
398 do {
399 switch (data[len]) {
400 case '{':
401 if (!skip) {
402 c++;
403 }
404 break;
405 case '}':
406 if (!skip) {
407 c--;
408 }
409 break;
410 case '\\':
411 /* when parsing a string, ignore escaped quotes to not end it prematurely */
412 if (skip && data[len + 1]) {
413 len++;
414 }
415 break;
416 case '\"':
417 skip = !skip;
418 break;
419 default:
420 break;
421 }
422 len++;
423 } while (data[len] && c);
424 if (c) {
425 LOGVAL(ctx, LYE_EOF, LY_VLOG_LYD, any);
426 return 0;
427 }
428
429 any->value_type = LYD_ANYDATA_JSON;
430 any->value.str = lydict_insert(ctx, data, len);
431
432 return len;
433 }
434
435 static unsigned int
json_get_value(struct lyd_node_leaf_list * leaf,struct lyd_node ** first_sibling,const char * data,int options,struct unres_data * unres)436 json_get_value(struct lyd_node_leaf_list *leaf, struct lyd_node **first_sibling, const char *data, int options,
437 struct unres_data *unres)
438 {
439 struct lyd_node_leaf_list *new;
440 struct lys_type *stype;
441 struct ly_ctx *ctx;
442 unsigned int len = 0, r;
443 char *str;
444
445 assert(leaf && data);
446 ctx = leaf->schema->module->ctx;
447
448 stype = &((struct lys_node_leaf *)leaf->schema)->type;
449
450 if (leaf->schema->nodetype == LYS_LEAFLIST) {
451 /* expecting begin-array */
452 if (data[len++] != '[') {
453 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (expected begin-array)");
454 return 0;
455 }
456
457 repeat:
458 len += skip_ws(&data[len]);
459 }
460
461 /* will be changed in case of union */
462 leaf->value_type = stype->base;
463
464 if (data[len] == '"') {
465 if ((leaf->value_type == LY_TYPE_INT8) || (leaf->value_type == LY_TYPE_INT16) ||
466 (leaf->value_type == LY_TYPE_INT32) || (leaf->value_type == LY_TYPE_UINT8) ||
467 (leaf->value_type == LY_TYPE_UINT16) || (leaf->value_type == LY_TYPE_UINT32)) {
468 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (expected number, but found string)");
469 return 0;
470 }
471 if (leaf->value_type == LY_TYPE_BOOL) {
472 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (expected boolean, but found string)");
473 return 0;
474 }
475
476 /* string representations */
477 ++len;
478 str = lyjson_parse_text(ctx, &data[len], &r);
479 if (!str) {
480 LOGPATH(ctx, LY_VLOG_LYD, leaf);
481 return 0;
482 }
483 leaf->value_str = lydict_insert_zc(ctx, str);
484 if (data[len + r] != '"') {
485 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, leaf,
486 "JSON data (missing quotation-mark at the end of string)");
487 return 0;
488 }
489 len += r + 1;
490 } else if (data[len] == '-' || isdigit(data[len])) {
491 if ((leaf->value_type == LY_TYPE_INT64) || (leaf->value_type == LY_TYPE_UINT64) ||
492 (leaf->value_type == LY_TYPE_STRING)) {
493 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (expected string, but found number)");
494 return 0;
495 }
496
497 /* numeric type */
498 r = lyjson_parse_number(ctx, &data[len]);
499 if (!r) {
500 LOGPATH(ctx, LY_VLOG_LYD, leaf);
501 return 0;
502 }
503 /* if it's a number with 'e' or 'E', get rid of it first */
504 if ((str = strnchr(&data[len], 'e', r)) || (str = strnchr(&data[len], 'E', r))) {
505 str = lyjson_convert_enumber(ctx, &data[len], r, str);
506 if (!str) {
507 return 0;
508 }
509 leaf->value_str = lydict_insert_zc(ctx, str);
510 } else {
511 leaf->value_str = lydict_insert(ctx, &data[len], r);
512 }
513 len += r;
514 } else if (data[len] == 'f' || data[len] == 't') {
515 if (leaf->value_type == LY_TYPE_STRING) {
516 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (expected string, but found boolean)");
517 return 0;
518 }
519
520 /* boolean */
521 r = lyjson_parse_boolean(ctx, &data[len]);
522 if (!r) {
523 LOGPATH(ctx, LY_VLOG_LYD, leaf);
524 return 0;
525 }
526 leaf->value_str = lydict_insert(ctx, &data[len], r);
527 len += r;
528 } else if (data[len] == '[') {
529 /* empty '[' WSP 'null' WSP ']' */
530 for (r = len + 1; isspace(data[r]); ++r);
531 if (strncmp(&data[r], "null", 4)) {
532 goto inval;
533 }
534 for (r += 4; isspace(data[r]); ++r);
535 if (data[r] != ']') {
536 goto inval;
537 }
538 leaf->value_str = lydict_insert(ctx, "", 0);
539 len = r + 1;
540 } else {
541 inval:
542 /* error */
543 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (unexpected value)");
544 return 0;
545 }
546
547 /* the value is here converted to a JSON format if needed in case of LY_TYPE_IDENT and LY_TYPE_INST or to a
548 * canonical form of the value */
549 if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
550 return 0;
551 }
552
553 #ifdef LY_ENABLED_CACHE
554 /* calculate the hash and insert it into parent */
555 lyd_hash((struct lyd_node *)leaf);
556 lyd_insert_hash((struct lyd_node *)leaf);
557 #endif
558
559 if (leaf->schema->nodetype == LYS_LEAFLIST) {
560 /* repeat until end-array */
561 len += skip_ws(&data[len]);
562 if (data[len] == ',') {
563 /* various validation checks */
564 if (lyv_data_context((struct lyd_node*)leaf, options, 0, unres) ||
565 lyv_data_content((struct lyd_node*)leaf, options, unres) ||
566 lyv_multicases((struct lyd_node*)leaf, NULL, first_sibling, 0, NULL)) {
567 return 0;
568 }
569
570 /* another instance of the leaf-list */
571 new = calloc(1, sizeof(struct lyd_node_leaf_list));
572 LY_CHECK_ERR_RETURN(!new, LOGMEM(ctx), 0);
573
574 new->parent = leaf->parent;
575 new->prev = (struct lyd_node *)leaf;
576 leaf->next = (struct lyd_node *)new;
577
578 /* copy the validity and when flags */
579 new->validity = leaf->validity;
580 new->when_status = leaf->when_status;
581
582 /* fix the "last" pointer */
583 (*first_sibling)->prev = (struct lyd_node *)new;
584
585 new->schema = leaf->schema;
586
587 /* repeat value parsing */
588 leaf = new;
589 len++;
590 goto repeat;
591 } else if (data[len] == ']') {
592 len++;
593 len += skip_ws(&data[len]);
594 } else {
595 /* something unexpected */
596 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (expecting value-separator or end-array)");
597 return 0;
598 }
599 }
600
601 len += skip_ws(&data[len]);
602 return len;
603 }
604
605 static unsigned int
json_parse_attr(struct lys_module * parent_module,struct lyd_attr ** attr,const char * data,int options)606 json_parse_attr(struct lys_module *parent_module, struct lyd_attr **attr, const char *data, int options)
607 {
608 struct ly_ctx *ctx = parent_module->ctx;
609 unsigned int len = 0, r;
610 char *str = NULL, *name, *prefix = NULL, *value;
611 struct lys_module *module = parent_module;
612 struct lyd_attr *attr_new, *attr_last = NULL;
613 int ret;
614
615 *attr = NULL;
616
617 if (data[len] != '{') {
618 if (!strncmp(&data[len], "null", 4)) {
619 len += 4;
620 len += skip_ws(&data[len]);
621 return len;
622 }
623 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing begin-object)");
624 goto error;
625 }
626
627 repeat:
628 prefix = NULL;
629 len++;
630 len += skip_ws(&data[len]);
631
632 if (data[len] != '"') {
633 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the beginning of string)");
634 return 0;
635 }
636 len++;
637 str = lyjson_parse_text(ctx, &data[len], &r);
638 if (!r) {
639 goto error;
640 } else if (data[len + r] != '"') {
641 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the end of string)");
642 goto error;
643 }
644 if ((name = strchr(str, ':'))) {
645 *name = '\0';
646 name++;
647 prefix = str;
648 module = (struct lys_module *)ly_ctx_get_module(parent_module->ctx, prefix, NULL, 0);
649 if (!module) {
650 LOGVAL(ctx, LYE_INELEM, LY_VLOG_NONE, NULL, name);
651 goto error;
652 }
653 } else {
654 name = str;
655 }
656
657 /* prepare data for parsing node content */
658 len += r + 1;
659 len += skip_ws(&data[len]);
660 if (data[len] != ':') {
661 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing name-separator)");
662 goto error;
663 }
664 len++;
665 len += skip_ws(&data[len]);
666
667 if (data[len] != '"') {
668 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the beginning of string)");
669 goto error;
670 }
671 len++;
672 value = lyjson_parse_text(ctx, &data[len], &r);
673 if (!r) {
674 goto error;
675 } else if (data[len + r] != '"') {
676 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the end of string)");
677 free(value);
678 goto error;
679 }
680 len += r + 1;
681 len += skip_ws(&data[len]);
682
683 ret = lyp_fill_attr(parent_module->ctx, NULL, NULL, prefix, name, value, NULL, &attr_new);
684 if (ret == -1) {
685 free(value);
686 goto error;
687 } else if (ret == 1) {
688 if (options & LYD_OPT_STRICT) {
689 LOGVAL(ctx, LYE_INMETA, LY_VLOG_NONE, NULL, prefix, name, value);
690 free(value);
691 goto error;
692 }
693
694 LOGWRN(ctx, "Unknown \"%s:%s\" metadata with value \"%s\", ignoring.",
695 (prefix ? prefix : "<none>"), name, value);
696 free(value);
697 goto next;
698 }
699 free(value);
700
701 if (!attr_last) {
702 *attr = attr_last = attr_new;
703 } else {
704 attr_last->next = attr_new;
705 attr_last = attr_new;
706 }
707
708 next:
709 free(str);
710 str = NULL;
711
712 if (data[len] == ',') {
713 goto repeat;
714 } else if (data[len] != '}') {
715 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing end-object)");
716 goto error;
717 }
718 len++;
719 len += skip_ws(&data[len]);
720
721 return len;
722
723 error:
724 free(str);
725 if (*attr) {
726 lyd_free_attr(module->ctx, NULL, *attr, 1);
727 *attr = NULL;
728 }
729 return 0;
730 }
731
732 struct attr_cont {
733 struct attr_cont *next;
734 struct lyd_attr *attr;
735 struct lys_node *schema;
736 unsigned int index; /** non-zero only in case of leaf-list */
737 };
738
739 static int
store_attrs(struct ly_ctx * ctx,struct attr_cont * attrs,struct lyd_node * first,int options)740 store_attrs(struct ly_ctx *ctx, struct attr_cont *attrs, struct lyd_node *first, int options)
741 {
742 struct lyd_node *diter;
743 struct attr_cont *iter;
744 struct lyd_attr *aiter;
745 unsigned int flag_leaflist = 0;
746
747 while (attrs) {
748 iter = attrs;
749 attrs = attrs->next;
750
751 if (iter->index) {
752 flag_leaflist = 1;
753 } else {
754 flag_leaflist = 0;
755 }
756
757 LY_TREE_FOR(first, diter) {
758 if (iter->schema != diter->schema) {
759 continue;
760 }
761
762 if (flag_leaflist && flag_leaflist != iter->index) {
763 flag_leaflist++;
764 continue;
765 }
766
767 /* we have match */
768 if (diter->attr) {
769 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, diter,
770 "attribute (multiple attribute definitions belong to a single element)");
771 free(iter);
772 goto error;
773 }
774
775 diter->attr = iter->attr;
776 for (aiter = iter->attr; aiter; aiter = aiter->next) {
777 aiter->parent = diter;
778 }
779
780 break;
781 }
782
783 if (!diter) {
784 LOGVAL(ctx, LYE_XML_MISS, LY_VLOG_NONE, NULL, "element for the specified attribute", iter->attr->name);
785 lyd_free_attr(iter->schema->module->ctx, NULL, iter->attr, 1);
786 free(iter);
787 goto error;
788 }
789 free(iter);
790
791 /* check edit-config attribute correctness */
792 if ((options & LYD_OPT_EDIT) && lyp_check_edit_attr(ctx, diter->attr, diter, NULL)) {
793 goto error;
794 }
795 }
796
797 return 0;
798
799 error:
800
801 while (attrs) {
802 iter = attrs;
803 attrs = attrs->next;
804
805 lyd_free_attr(ctx, NULL, iter->attr, 1);
806 free(iter);
807 }
808
809 return -1;
810 }
811
812 /**
813 * @brief Skip subtree (find its end in the input data) of the current JSON item.
814 * @param[in] ctx libyang context for logging
815 * @param[in] parent parent node for logging
816 * @param[in] data input data (pointing to the beginning, @p len is used to go to the current position).
817 * @param[in, out] len Current position in the @p data, will be updated to the end of the element's subtree in the @p data
818 * @retun 0 on success
819 * @return -1 on error.
820 */
821 static int
json_skip_unknown(struct ly_ctx * ctx,struct lyd_node * parent,const char * data,unsigned int * len)822 json_skip_unknown(struct ly_ctx *ctx, struct lyd_node *parent, const char *data, unsigned int *len)
823 {
824 int qstr = 0;
825 int objects = 0;
826 int arrays = 0;
827
828 while (data[*len]) {
829 switch (data[*len]) {
830 case '\"':
831 if (qstr) {
832 if (data[(*len) - 1] != '\\') {
833 qstr = 0;
834 }
835 } else if (data[(*len) - 1] != '\\') {
836 qstr = 1;
837 } else {
838 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, parent, "JSON data (missing quotation mark for a string data) ");
839 return -1;
840 }
841 break;
842 case '[':
843 if (!qstr) {
844 arrays++;
845 }
846 break;
847 case '{':
848 if (!qstr) {
849 objects++;
850 }
851 break;
852 case ']':
853 if (!qstr) {
854 arrays--;
855 }
856 break;
857 case '}':
858 if (!qstr) {
859 objects--;
860 }
861 break;
862 case ',':
863 if (!qstr && !objects && !arrays) {
864 /* do not eat the comma character */
865 return 0;
866 }
867 }
868
869 if (objects < 0) {
870 if (arrays) {
871 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, parent, "JSON data (missing end-array)");
872 return -1;
873 }
874 return 0;
875 }
876 if (arrays < 0) {
877 if (objects) {
878 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, parent, "JSON data (missing end-object)");
879 return -1;
880 }
881 return 0;
882 }
883 (*len)++;
884 }
885
886 return 0;
887 }
888
889 static unsigned int
json_parse_data(struct ly_ctx * ctx,const char * data,const struct lys_node * schema_parent,struct lyd_node ** parent,struct lyd_node * first_sibling,struct lyd_node * prev,struct attr_cont ** attrs,int options,struct unres_data * unres,struct lyd_node ** act_notif,const char * yang_data_name)890 json_parse_data(struct ly_ctx *ctx, const char *data, const struct lys_node *schema_parent, struct lyd_node **parent,
891 struct lyd_node *first_sibling, struct lyd_node *prev, struct attr_cont **attrs, int options,
892 struct unres_data *unres, struct lyd_node **act_notif, const char *yang_data_name)
893 {
894 unsigned int len = 0;
895 unsigned int r;
896 unsigned int flag_leaflist = 0;
897 int i;
898 uint8_t pos;
899 char *name, *prefix = NULL, *str = NULL;
900 const struct lys_module *module = NULL;
901 struct lys_node *schema = NULL;
902 const struct lys_node *sparent = NULL;
903 struct lyd_node *result = NULL, *new, *list, *diter = NULL;
904 struct lyd_attr *attr;
905 struct attr_cont *attrs_aux;
906
907 /* each YANG data node representation starts with string (node identifier) */
908 if (data[len] != '"') {
909 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, (*parent),
910 "JSON data (missing quotation-mark at the beginning of string)");
911 return 0;
912 }
913 len++;
914
915 str = lyjson_parse_text(ctx, &data[len], &r);
916 if (!str) {
917 goto error;
918 }
919
920 if (!r) {
921 goto error;
922 } else if (data[len + r] != '"') {
923 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, (*parent),
924 "JSON data (missing quotation-mark at the end of string)");
925 goto error;
926 }
927 if ((name = strchr(str, ':'))) {
928 *name = '\0';
929 name++;
930 prefix = str;
931 if (prefix[0] == '@') {
932 prefix++;
933 }
934 } else {
935 name = str;
936 if (name[0] == '@') {
937 name++;
938 }
939 }
940
941 /* prepare data for parsing node content */
942 len += r + 1;
943 len += skip_ws(&data[len]);
944 if (data[len] != ':') {
945 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, (*parent), "JSON data (missing name-separator)");
946 goto error;
947 }
948 len++;
949 len += skip_ws(&data[len]);
950
951 if (str[0] == '@' && !str[1]) {
952 /* process attribute of the parent object (container or list) */
953 if (!(*parent)) {
954 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "attribute with no corresponding element to belongs to");
955 goto error;
956 }
957
958 r = json_parse_attr((*parent)->schema->module, &attr, &data[len], options);
959 if (!r) {
960 LOGPATH(ctx, LY_VLOG_LYD, *parent);
961 goto error;
962 }
963 len += r;
964
965 if ((*parent)->attr) {
966 lyd_free_attr(ctx, NULL, attr, 1);
967 } else {
968 (*parent)->attr = attr;
969 for (; attr; attr = attr->next) {
970 attr->parent = *parent;
971 }
972 }
973
974 /* check edit-config attribute correctness */
975 if ((options & LYD_OPT_EDIT) && lyp_check_edit_attr(ctx, (*parent)->attr, *parent, NULL)) {
976 goto error;
977 }
978
979 free(str);
980 return len;
981 }
982
983 /* find schema node */
984 if (!(*parent)) {
985 /* starting in root */
986 /* get the proper schema */
987 module = ly_ctx_get_module(ctx, prefix, NULL, 0);
988 if (ctx->data_clb) {
989 if (!module) {
990 module = ctx->data_clb(ctx, prefix, NULL, 0, ctx->data_clb_data);
991 } else if (!module->implemented) {
992 module = ctx->data_clb(ctx, module->name, module->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
993 }
994 }
995 if (module && module->implemented) {
996 if (yang_data_name) {
997 sparent = lyp_get_yang_data_template(module, yang_data_name, strlen(yang_data_name));
998 schema = NULL;
999 if (sparent) {
1000 /* get the proper schema node */
1001 while ((schema = (struct lys_node *) lys_getnext(schema, sparent, module, 0))) {
1002 if (!strcmp(schema->name, name)) {
1003 break;
1004 }
1005 }
1006 }
1007 } else {
1008 /* get the proper schema node */
1009 while ((schema = (struct lys_node *) lys_getnext(schema, NULL, module, 0))) {
1010 if (!strcmp(schema->name, name)) {
1011 break;
1012 }
1013 }
1014 }
1015 }
1016 } else {
1017 if (prefix) {
1018 /* get the proper module to give the chance to load/implement it */
1019 module = ly_ctx_get_module(ctx, prefix, NULL, 1);
1020 if (ctx->data_clb) {
1021 if (!module) {
1022 ctx->data_clb(ctx, prefix, NULL, 0, ctx->data_clb_data);
1023 } else if (!module->implemented) {
1024 ctx->data_clb(ctx, module->name, module->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
1025 }
1026 }
1027 }
1028
1029 /* go through RPC's input/output following the options' data type */
1030 if ((*parent)->schema->nodetype == LYS_RPC || (*parent)->schema->nodetype == LYS_ACTION) {
1031 while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, NULL, LYS_GETNEXT_WITHINOUT))) {
1032 if ((options & LYD_OPT_RPC) && (schema->nodetype == LYS_INPUT)) {
1033 break;
1034 } else if ((options & LYD_OPT_RPCREPLY) && (schema->nodetype == LYS_OUTPUT)) {
1035 break;
1036 }
1037 }
1038 schema_parent = schema;
1039 schema = NULL;
1040 }
1041
1042 if (schema_parent) {
1043 while ((schema = (struct lys_node *)lys_getnext(schema, schema_parent, NULL, 0))) {
1044 if (!strcmp(schema->name, name)
1045 && ((prefix && !strcmp(lys_node_module(schema)->name, prefix))
1046 || (!prefix && (lys_node_module(schema) == lys_node_module(schema_parent))))) {
1047 break;
1048 }
1049 }
1050 } else {
1051 while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, NULL, 0))) {
1052 if (!strcmp(schema->name, name)
1053 && ((prefix && !strcmp(lys_node_module(schema)->name, prefix))
1054 || (!prefix && (lys_node_module(schema) == lyd_node_module(*parent))))) {
1055 break;
1056 }
1057 }
1058 }
1059 }
1060
1061 module = lys_node_module(schema);
1062 if (!module || !module->implemented || module->disabled) {
1063 if (options & LYD_OPT_STRICT) {
1064 LOGVAL(ctx, LYE_INELEM, (*parent ? LY_VLOG_LYD : LY_VLOG_NONE), (*parent), name);
1065 goto error;
1066 } else {
1067 if (json_skip_unknown(ctx, *parent, data, &len)) {
1068 goto error;
1069 }
1070 free(str);
1071 return len;
1072 }
1073 }
1074
1075 if (str[0] == '@') {
1076 /* attribute for some sibling node */
1077 if (data[len] == '[') {
1078 flag_leaflist = 1;
1079 len++;
1080 len += skip_ws(&data[len]);
1081 }
1082
1083 attr_repeat:
1084 r = json_parse_attr((struct lys_module *)module, &attr, &data[len], options);
1085 if (!r) {
1086 LOGPATH(ctx, LY_VLOG_LYD, (*parent));
1087 goto error;
1088 }
1089 len += r;
1090
1091 if (attr) {
1092 attrs_aux = malloc(sizeof *attrs_aux);
1093 LY_CHECK_ERR_GOTO(!attrs_aux, LOGMEM(ctx), error);
1094 attrs_aux->attr = attr;
1095 attrs_aux->index = flag_leaflist;
1096 attrs_aux->schema = schema;
1097 attrs_aux->next = *attrs;
1098 *attrs = attrs_aux;
1099 }
1100
1101 if (flag_leaflist) {
1102 if (data[len] == ',') {
1103 len++;
1104 len += skip_ws(&data[len]);
1105 flag_leaflist++;
1106 goto attr_repeat;
1107 } else if (data[len] != ']') {
1108 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, (*parent), "JSON data (missing end-array)");
1109 goto error;
1110 }
1111 len++;
1112 len += skip_ws(&data[len]);
1113 }
1114
1115 free(str);
1116 return len;
1117 }
1118
1119 switch (schema->nodetype) {
1120 case LYS_CONTAINER:
1121 case LYS_LIST:
1122 case LYS_NOTIF:
1123 case LYS_RPC:
1124 case LYS_ACTION:
1125 result = calloc(1, sizeof *result);
1126 break;
1127 case LYS_LEAF:
1128 case LYS_LEAFLIST:
1129 result = calloc(1, sizeof(struct lyd_node_leaf_list));
1130 break;
1131 case LYS_ANYXML:
1132 case LYS_ANYDATA:
1133 result = calloc(1, sizeof(struct lyd_node_anydata));
1134 break;
1135 default:
1136 LOGINT(ctx);
1137 goto error;
1138 }
1139 LY_CHECK_ERR_GOTO(!result, LOGMEM(ctx), error);
1140
1141 result->prev = result;
1142 result->schema = schema;
1143 result->parent = *parent;
1144 diter = NULL;
1145 if (lys_is_key((struct lys_node_leaf *)schema, &pos)) {
1146 /* it is key and we need to insert it into a correct place (we must have parent then, a key cannot be top-level) */
1147 assert(*parent);
1148 for (i = 0, diter = (*parent)->child;
1149 diter && i < pos && diter->schema->nodetype == LYS_LEAF && lys_is_key((struct lys_node_leaf *)diter->schema, NULL);
1150 i++, diter = diter->next);
1151 if (diter) {
1152 /* out of order insertion - insert list's key to the correct position, before the diter */
1153 if ((*parent)->child == diter) {
1154 (*parent)->child = result;
1155 /* update first_sibling */
1156 first_sibling = result;
1157 }
1158 if (diter->prev->next) {
1159 diter->prev->next = result;
1160 }
1161 result->prev = diter->prev;
1162 diter->prev = result;
1163 result->next = diter;
1164 }
1165 }
1166 if (!diter) {
1167 /* simplified (faster) insert as the last node */
1168 if (*parent && !(*parent)->child) {
1169 (*parent)->child = result;
1170 }
1171 if (prev) {
1172 result->prev = prev;
1173 prev->next = result;
1174
1175 /* fix the "last" pointer */
1176 first_sibling->prev = result;
1177 } else {
1178 result->prev = result;
1179 first_sibling = result;
1180 }
1181 }
1182 result->validity = ly_new_node_validity(result->schema);
1183 if (resolve_applies_when(schema, 0, NULL)) {
1184 result->when_status = LYD_WHEN;
1185 }
1186
1187 /* type specific processing */
1188 switch (schema->nodetype) {
1189 case LYS_LEAF:
1190 case LYS_LEAFLIST:
1191 /* type detection and assigning the value */
1192 r = json_get_value((struct lyd_node_leaf_list *)result, &first_sibling, &data[len], options, unres);
1193 if (!r) {
1194 goto error;
1195 }
1196 /* only for leaf-list */
1197 while (result->next && (result->next->schema == result->schema)) {
1198 result = result->next;
1199 }
1200
1201 len += r;
1202 len += skip_ws(&data[len]);
1203 break;
1204 case LYS_ANYDATA:
1205 case LYS_ANYXML:
1206 r = json_get_anydata((struct lyd_node_anydata *)result, &data[len]);
1207 if (!r) {
1208 goto error;
1209 }
1210
1211 #ifdef LY_ENABLED_CACHE
1212 /* calculate the hash and insert it into parent */
1213 lyd_hash(result);
1214 lyd_insert_hash(result);
1215 #endif
1216
1217 len += r;
1218 len += skip_ws(&data[len]);
1219 break;
1220 case LYS_CONTAINER:
1221 case LYS_RPC:
1222 case LYS_ACTION:
1223 case LYS_NOTIF:
1224 if (schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1225 if (!(options & LYD_OPT_RPC) || *act_notif) {
1226 LOGVAL(ctx, LYE_INELEM, LY_VLOG_LYD, result, schema->name);
1227 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unexpected %s node \"%s\".",
1228 (schema->nodetype == LYS_RPC ? "rpc" : "action"), schema->name);
1229 goto error;
1230 }
1231 *act_notif = result;
1232 } else if (schema->nodetype == LYS_NOTIF) {
1233 if (!(options & LYD_OPT_NOTIF) || *act_notif) {
1234 LOGVAL(ctx, LYE_INELEM, LY_VLOG_LYD, result, schema->name);
1235 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unexpected notification node \"%s\".", schema->name);
1236 goto error;
1237 }
1238 *act_notif = result;
1239 }
1240
1241 #ifdef LY_ENABLED_CACHE
1242 /* calculate the hash and insert it into parent */
1243 lyd_hash(result);
1244 lyd_insert_hash(result);
1245 #endif
1246
1247 if (data[len] != '{') {
1248 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing begin-object)");
1249 goto error;
1250 }
1251 len++;
1252 len += skip_ws(&data[len]);
1253
1254 if (data[len] != '}') {
1255 /* non-empty container */
1256 len--;
1257 diter = NULL;
1258 attrs_aux = NULL;
1259 do {
1260 len++;
1261 len += skip_ws(&data[len]);
1262
1263 r = json_parse_data(ctx, &data[len], NULL, &result, result->child, diter, &attrs_aux, options, unres, act_notif, yang_data_name);
1264 if (!r) {
1265 goto error;
1266 }
1267 len += r;
1268
1269 if (result->child) {
1270 diter = result->child->prev;
1271 }
1272 } while(data[len] == ',');
1273
1274 /* store attributes */
1275 if (store_attrs(ctx, attrs_aux, result->child, options)) {
1276 goto error;
1277 }
1278 }
1279
1280 if (data[len] != '}') {
1281 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing end-object)");
1282 goto error;
1283 }
1284 len++;
1285 len += skip_ws(&data[len]);
1286
1287 /* if we have empty non-presence container, mark it as default */
1288 if (schema->nodetype == LYS_CONTAINER && !result->child &&
1289 !result->attr && !((struct lys_node_container *)schema)->presence) {
1290 result->dflt = 1;
1291 }
1292 break;
1293 case LYS_LIST:
1294 if (data[len] != '[') {
1295 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing begin-array)");
1296 goto error;
1297 }
1298
1299 list = result;
1300 do {
1301 len++;
1302 len += skip_ws(&data[len]);
1303
1304 if (data[len] != '{') {
1305 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, result,
1306 "JSON data (missing list instance's begin-object)");
1307 goto error;
1308 }
1309 diter = NULL;
1310 attrs_aux = NULL;
1311 do {
1312 len++;
1313 len += skip_ws(&data[len]);
1314
1315 r = json_parse_data(ctx, &data[len], NULL, &list, list->child, diter, &attrs_aux, options, unres, act_notif, yang_data_name);
1316 if (!r) {
1317 goto error;
1318 }
1319 len += r;
1320
1321 if (list->child) {
1322 diter = list->child->prev;
1323 }
1324 } while (data[len] == ',');
1325
1326 #ifdef LY_ENABLED_CACHE
1327 /* calculate the hash and insert it into parent */
1328 if (!((struct lys_node_list *)list->schema)->keys_size) {
1329 lyd_hash(list);
1330 lyd_insert_hash(list);
1331 }
1332 #endif
1333
1334 /* store attributes */
1335 if (store_attrs(ctx, attrs_aux, list->child, options)) {
1336 goto error;
1337 }
1338
1339 if (data[len] != '}') {
1340 /* expecting end-object */
1341 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, result,
1342 "JSON data (missing list instance's end-object)");
1343 goto error;
1344 }
1345 len++;
1346 len += skip_ws(&data[len]);
1347
1348 if (data[len] == ',') {
1349 /* various validation checks */
1350 if (lyv_data_context(list, options, 0, unres) ||
1351 lyv_data_content(list, options, unres) ||
1352 lyv_multicases(list, NULL, prev ? &first_sibling : NULL, 0, NULL)) {
1353 goto error;
1354 }
1355
1356 /* another instance of the list */
1357 new = calloc(1, sizeof *new);
1358 LY_CHECK_ERR_GOTO(!new, LOGMEM(ctx), error);
1359 new->parent = list->parent;
1360 new->prev = list;
1361 list->next = new;
1362
1363 /* copy the validity and when flags */
1364 new->validity = list->validity;
1365 new->when_status = list->when_status;
1366
1367 /* fix the "last" pointer */
1368 first_sibling->prev = new;
1369
1370 new->schema = list->schema;
1371 list = new;
1372 }
1373 } while (data[len] == ',');
1374 result = list;
1375
1376 if (data[len] != ']') {
1377 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing end-array)");
1378 goto error;
1379 }
1380 len++;
1381 len += skip_ws(&data[len]);
1382 break;
1383 default:
1384 LOGINT(ctx);
1385 goto error;
1386 }
1387
1388 /* various validation checks */
1389 if (lyv_data_context(result, options, 0, unres) ||
1390 lyv_data_content(result, options, unres) ||
1391 lyv_multicases(result, NULL, prev ? &first_sibling : NULL, 0, NULL)) {
1392 goto error;
1393 }
1394
1395 /* validation successful */
1396 if (result->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
1397 /* postpone checking of unique when there will be all list/leaflist instances */
1398 result->validity |= LYD_VAL_DUP;
1399 }
1400
1401 if (!(*parent)) {
1402 *parent = result;
1403 }
1404
1405 free(str);
1406 return len;
1407
1408 error:
1409 /* cleanup */
1410 for (i = unres->count - 1; i >= 0; i--) {
1411 /* remove unres items connected with the node being removed */
1412 if (unres->node[i] == result) {
1413 unres_data_del(unres, i);
1414 }
1415 }
1416 while (*attrs) {
1417 attrs_aux = *attrs;
1418 *attrs = (*attrs)->next;
1419
1420 lyd_free_attr(ctx, NULL, attrs_aux->attr, 1);
1421 free(attrs_aux);
1422 }
1423
1424 lyd_free(result);
1425 free(str);
1426
1427 return 0;
1428 }
1429
1430 struct lyd_node *
lyd_parse_json(struct ly_ctx * ctx,const char * data,int options,const struct lyd_node * rpc_act,const struct lyd_node * data_tree,const char * yang_data_name)1431 lyd_parse_json(struct ly_ctx *ctx, const char *data, int options, const struct lyd_node *rpc_act,
1432 const struct lyd_node *data_tree, const char *yang_data_name)
1433 {
1434 struct lyd_node *result = NULL, *next, *iter, *reply_parent = NULL, *reply_top = NULL, *act_notif = NULL;
1435 struct unres_data *unres = NULL;
1436 unsigned int len = 0, r;
1437 int act_cont = 0;
1438 struct attr_cont *attrs = NULL;
1439
1440 if (!ctx || !data) {
1441 LOGARG;
1442 return NULL;
1443 }
1444
1445 /* skip leading whitespaces */
1446 len += skip_ws(&data[len]);
1447
1448 /* expect top-level { */
1449 if (data[len] != '{') {
1450 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top level begin-object)");
1451 return NULL;
1452 }
1453
1454 /* check for empty object */
1455 r = len + 1;
1456 r += skip_ws(&data[r]);
1457 if (data[r] == '}') {
1458 if (options & LYD_OPT_DATA_ADD_YANGLIB) {
1459 result = ly_ctx_info(ctx);
1460 }
1461 lyd_validate(&result, options, ctx);
1462 return result;
1463 }
1464
1465 unres = calloc(1, sizeof *unres);
1466 LY_CHECK_ERR_RETURN(!unres, LOGMEM(ctx), NULL);
1467
1468 /* create RPC/action reply part that is not in the parsed data */
1469 if (rpc_act) {
1470 assert(options & LYD_OPT_RPCREPLY);
1471 if (rpc_act->schema->nodetype == LYS_RPC) {
1472 /* RPC request */
1473 reply_top = reply_parent = _lyd_new(NULL, rpc_act->schema, 0);
1474 } else {
1475 /* action request */
1476 reply_top = lyd_dup(rpc_act, 1);
1477 LY_TREE_DFS_BEGIN(reply_top, iter, reply_parent) {
1478 if (reply_parent->schema->nodetype == LYS_ACTION) {
1479 break;
1480 }
1481 LY_TREE_DFS_END(reply_top, iter, reply_parent);
1482 }
1483 if (!reply_parent) {
1484 LOGERR(ctx, LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *rpc_act).", __func__);
1485 goto error;
1486 }
1487 lyd_free_withsiblings(reply_parent->child);
1488 }
1489 }
1490
1491 iter = NULL;
1492 next = reply_parent;
1493 do {
1494 len++;
1495 len += skip_ws(&data[len]);
1496
1497 if (!act_cont) {
1498 if (!strncmp(&data[len], "\"yang:action\"", 13)) {
1499 len += 13;
1500 len += skip_ws(&data[len]);
1501 if (data[len] != ':') {
1502 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top-level begin-object)");
1503 goto error;
1504 }
1505 ++len;
1506 len += skip_ws(&data[len]);
1507 if (data[len] != '{') {
1508 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top level yang:action object)");
1509 goto error;
1510 }
1511 ++len;
1512 len += skip_ws(&data[len]);
1513
1514 act_cont = 1;
1515 } else {
1516 act_cont = -1;
1517 }
1518 }
1519
1520 r = json_parse_data(ctx, &data[len], NULL, &next, result, iter, &attrs, options, unres, &act_notif, yang_data_name);
1521 if (!r) {
1522 goto error;
1523 }
1524 len += r;
1525
1526 if (!result) {
1527 if (reply_parent) {
1528 result = next->child;
1529 iter = next->child ? next->child->prev : NULL;
1530 } else {
1531 for (iter = next; iter && iter->prev->next; iter = iter->prev);
1532 result = iter;
1533 if (iter && (options & LYD_OPT_DATA_ADD_YANGLIB) && iter->schema->module == ctx->models.list[ctx->internal_module_count - 1]) {
1534 /* ietf-yang-library data present, so ignore the option to add them */
1535 options &= ~LYD_OPT_DATA_ADD_YANGLIB;
1536 }
1537 iter = next;
1538 }
1539 } else {
1540 iter = result->prev;
1541 }
1542 if (!reply_parent) {
1543 next = NULL;
1544 }
1545 } while (data[len] == ',');
1546
1547 if (data[len] != '}') {
1548 /* expecting end-object */
1549 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top-level end-object)");
1550 goto error;
1551 }
1552 len++;
1553 len += skip_ws(&data[len]);
1554
1555 if (act_cont == 1) {
1556 if (data[len] != '}') {
1557 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top-level end-object)");
1558 goto error;
1559 }
1560 len++;
1561 len += skip_ws(&data[len]);
1562 }
1563
1564 /* store attributes */
1565 if (store_attrs(ctx, attrs, result, options)) {
1566 goto error;
1567 }
1568
1569 if (reply_top) {
1570 result = reply_top;
1571 }
1572
1573 if (!result && (options & LYD_OPT_STRICT)) {
1574 LOGERR(ctx, LY_EVALID, "Model for the data to be linked with not found.");
1575 goto error;
1576 }
1577
1578 /* order the elements by hand as it is not required of the JSON input */
1579 if ((options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY))) {
1580 if (lyd_schema_sort(result, 1)) {
1581 goto error;
1582 }
1583 }
1584
1585 if ((options & LYD_OPT_RPCREPLY) && (rpc_act->schema->nodetype != LYS_RPC)) {
1586 /* action reply */
1587 act_notif = reply_parent;
1588 } else if ((options & (LYD_OPT_RPC | LYD_OPT_NOTIF)) && !act_notif) {
1589 if (result) {
1590 LOGVAL(ctx, LYE_MISSELEM, LY_VLOG_LYD, result, (options & LYD_OPT_RPC ? "action" : "notification"),
1591 result->schema->name);
1592 } else {
1593 LOGVAL(ctx, LYE_MISSELEM, LY_VLOG_NONE, NULL, (options & LYD_OPT_RPC ? "action" : "notification"), "data");
1594 }
1595 goto error;
1596 }
1597
1598 /* add missing ietf-yang-library if requested */
1599 if (options & LYD_OPT_DATA_ADD_YANGLIB) {
1600 if (lyd_merge(result, ly_ctx_info(ctx), LYD_OPT_DESTRUCT | LYD_OPT_EXPLICIT)) {
1601 LOGERR(ctx, LY_EINT, "Adding ietf-yang-library data failed.");
1602 goto error;
1603 }
1604 }
1605
1606 /* check for uniquness of top-level lists/leaflists because
1607 * only the inner instances were tested in lyv_data_content() */
1608 LY_TREE_FOR(result, iter) {
1609 if (!(iter->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) || !(iter->validity & LYD_VAL_DUP)) {
1610 continue;
1611 }
1612
1613 if (lyv_data_dup(iter, result)) {
1614 goto error;
1615 }
1616 }
1617
1618 /* add/validate default values, unres */
1619 if (lyd_defaults_add_unres(&result, options, ctx, NULL, 0, data_tree, act_notif, unres, 1)) {
1620 goto error;
1621 }
1622
1623 /* check for missing top level mandatory nodes */
1624 if (!(options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER))
1625 && lyd_check_mandatory_tree((act_notif ? act_notif : result), ctx, NULL, 0, options)) {
1626 goto error;
1627 }
1628
1629 free(unres->node);
1630 free(unres->type);
1631 free(unres);
1632
1633 return result;
1634
1635 error:
1636 lyd_free_withsiblings(result);
1637 if (reply_top && result != reply_top) {
1638 lyd_free_withsiblings(reply_top);
1639 }
1640 free(unres->node);
1641 free(unres->type);
1642 free(unres);
1643
1644 return NULL;
1645 }
1646