blob: a5a8b1e002158f7a34c6367ad7bf33ea67f2873c [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 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
22#include <assert.h>
23#include <ctype.h>
24#include <limits.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "libyang.h"
29#include "common.h"
30#include "context.h"
31#include "parser.h"
32#include "printer.h"
33#include "tree_internal.h"
34#include "validation.h"
35
Radek Krejci967e4bf2015-11-28 10:06:40 +010036static unsigned int lineno = 0;
Radek Krejci5449d472015-10-26 14:35:56 +010037
38static int
39lyjson_isspace(int c)
40{
41 switch(c) {
42 case 0x20: /* space */
43 case 0x09: /* horizontal tab */
44 case 0x0a: /* line feed or new line */
45 case 0x0d: /* carriage return */
46 return 1;
47 default:
48 return 0;
49 }
50}
51
52static unsigned int
53skip_ws(const char *data)
54{
55 unsigned int len = 0;
56
57 /* skip leading whitespaces */
58 while (data[len] && lyjson_isspace(data[len])) {
59 COUNTLINE(data[len]);
60 len++;
61 }
62
63 return len;
64}
65
66int lyjson_dump_string(struct lyout *out, const char *text)
67{
68 unsigned int i, n;
69
70 if (!text) {
71 return 0;
72 }
73
74 ly_write(out, "\"", 1);
75 for (i = n = 0; text[i]; i++) {
76 if (text[i] < 0x20) {
77 /* control character */
78 n += ly_print(out, "\\u%.4X");
79 } else {
80 switch (text[i]) {
81 case '"':
82 n += ly_print(out, "\\\"");
83 break;
84 case '\\':
85 n += ly_print(out, "\\\\");
86 break;
87 case '/':
88 n += ly_print(out, "\\/");
89 break;
90 default:
91 ly_write(out, &text[i], 1);
92 n++;
93 }
94 }
95 }
96 ly_write(out, "\"", 1);
97
98 return n + 2;
99}
100
101
102static char *
103lyjson_parse_text(const char *data, unsigned int *len)
104{
105#define BUFSIZE 1024
106
107 char buf[BUFSIZE];
108 char *result = NULL, *aux;
Radek Krejci967e4bf2015-11-28 10:06:40 +0100109 int o, size = 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100110 unsigned int r, i;
111 int32_t value;
112
113 for (*len = o = 0; data[*len] && data[*len] != '"'; o++) {
114 if (o > BUFSIZE - 3) {
115 /* add buffer into the result */
116 if (result) {
117 size = size + o;
Michal Vasko253035f2015-12-17 16:58:13 +0100118 aux = ly_realloc(result, size + 1);
119 if (!aux) {
120 LOGMEM;
121 return NULL;
122 }
Radek Krejci5449d472015-10-26 14:35:56 +0100123 result = aux;
124 } else {
125 size = o;
126 result = malloc((size + 1) * sizeof *result);
Michal Vasko253035f2015-12-17 16:58:13 +0100127 if (!result) {
128 LOGMEM;
129 return NULL;
130 }
Radek Krejci5449d472015-10-26 14:35:56 +0100131 }
132 memcpy(&result[size - o], buf, o);
133
134 /* write again into the beginning of the buffer */
135 o = 0;
136 }
137
138 if (data[*len] == '\\') {
139 /* parse escape sequence */
140 (*len)++;
141 i = 1;
142 switch (data[(*len)]) {
143 case '"':
144 /* quotation mark */
145 value = 0x22;
146 break;
147 case '\\':
148 /* reverse solidus */
149 value = 0x5c;
150 break;
151 case '/':
152 /* solidus */
153 value = 0x2f;
154 break;
155 case 'b':
156 /* backspace */
157 value = 0x08;
158 break;
159 case 'f':
160 /* form feed */
161 value = 0x0c;
162 break;
163 case 'n':
164 /* line feed */
165 value = 0x0a;
166 break;
167 case 'r':
168 /* carriage return */
169 value = 0x0d;
170 break;
171 case 't':
172 /* tab */
173 value = 0x09;
174 break;
175 case 'u':
176 /* Basic Multilingual Plane character \uXXXX */
177 (*len)++;
178 for (value = i = 0; i < 4; i++) {
179 if (isdigit(data[(*len) + i])) {
180 r = (data[(*len) + i] - '0');
181 } else if (data[(*len) + i] > 'F') {
182 r = 10 + (data[(*len) + i] - 'a');
183 } else {
184 r = 10 + (data[(*len) + i] - 'A');
185 }
186 value = (16 * value) + r;
187 }
188 break;
189 default:
190 /* invalid escape sequence */
191 LOGVAL(LYE_XML_INVAL, lineno, "character escape sequence");
192 goto error;
193
194 }
195 r = pututf8(&buf[o], value, lineno);
196 if (!r) {
197 LOGVAL(LYE_XML_INVAL, lineno, "character UTF8 character");
198 goto error;
199 }
200 o += r - 1; /* o is ++ in for loop */
201 (*len) += i; /* number of read characters */
202 } else if (data[*len] < 0x20 || data[*len] == 0x5c) {
203 /* control characters must be escaped */
204 LOGVAL(LYE_XML_INVAL, lineno, "control character (unescaped)");
205 goto error;
206 } else {
207 /* unescaped character */
208 buf[o] = data[*len];
209 COUNTLINE(buf[o]);
210 (*len)++;
211 }
212 }
213
214#undef BUFSIZE
215
216 if (o) {
217 if (result) {
218 size = size + o;
Michal Vasko253035f2015-12-17 16:58:13 +0100219 aux = ly_realloc(result, size + 1);
220 if (!aux) {
221 LOGMEM;
222 return NULL;
223 }
Radek Krejci5449d472015-10-26 14:35:56 +0100224 result = aux;
225 } else {
226 size = o;
227 result = malloc((size + 1) * sizeof *result);
Michal Vasko253035f2015-12-17 16:58:13 +0100228 if (!result) {
229 LOGMEM;
230 return NULL;
231 }
Radek Krejci5449d472015-10-26 14:35:56 +0100232 }
233 memcpy(&result[size - o], buf, o);
234 }
235 if (result) {
236 result[size] = '\0';
237 } else {
238 size = 0;
239 result = strdup("");
240 }
241
242 return result;
243
244error:
245 free(result);
246 return NULL;
247}
248
249static unsigned int
250lyjson_parse_number(const char *data)
251{
252 unsigned int len;
253 unsigned int i = 0;
254
255 for (len = 0;
256 data[len] && data[len] != ',' && data[len] != ']' && data[len] != '}' && !lyjson_isspace(data[len]);
257 len++) {
258
259 switch(data[len]) {
260 case '0':
Radek Krejci88f29302015-10-30 15:42:33 +0100261 if (!i && isdigit(data[len + 1])) {
Radek Krejci5449d472015-10-26 14:35:56 +0100262 /* leading 0 is not allowed */
263 LOGVAL(LYE_XML_INVAL, lineno, "JSON number (leading zero)");
264 return 0;
265 }
266 /* no break */
267 case '1':
268 case '2':
269 case '3':
270 case '4':
271 case '5':
272 case '6':
273 case '7':
274 case '8':
275 case '9':
276 i = 1;
277 /* no break */
278 case 0x2d: /* minus */
279 /* ok */
280 break;
281 default:
282 LOGVAL(LYE_XML_INVAL, lineno, "character in JSON Number value");
283 return 0;
284 }
285 }
286
287 return len;
288}
289
290static unsigned int
291lyjson_parse_boolean(const char *data)
292{
Radek Krejci6b47b502015-10-30 15:52:41 +0100293 unsigned int len = 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100294
295 if (!strncmp(data, "false", 5)) {
296 len = 5;
297 } else if (!strncmp(data, "true", 4)) {
298 len = 4;
299 }
300
301 if (data[len] && data[len] != ',' && data[len] != ']' && data[len] != '}' && !lyjson_isspace(data[len])) {
302 LOGVAL(LYE_XML_INVAL, lineno, "JSON literal value (expected true or false)");
303 return 0;
304 }
305
306 return len;
307}
308
309static unsigned int
310json_get_anyxml(struct lyd_node_anyxml *axml, const char *data)
311{
312 unsigned int len = 0;
313 char stop, start;
314 int level = 0;
315
316 switch (data[len]) {
317 case '"':
318 start = 0;
319 stop = '"';
320 level = 1;
321 break;
322 case '[':
323 start = '[';
324 stop = ']';
325 break;
326 case '{':
327 start = '{';
328 stop = '}';
329 break;
330 default:
331 /* number or one of literals */
332 while (!isspace(data[len])) {
333 len++;
334 }
335 axml->value = NULL; /* TODO ??? */
336 return len;
337 }
338
339 while (data[len]) {
340 if (start && data[len] == start) {
341 if (!len || data[len - 1] != '\\') {
342 level++;
343 }
344 } else if (data[len] == stop) {
345 if (!len || data[len - 1] != '\\') {
346 level--;
347 }
348 }
349 stop = len;
350 len++;
351 if (!level) {
352 /* we are done */
353 axml->value = NULL; /* TODO ??? */
354 return len;
355 }
356 }
357
358 return 0;
359}
360
361static unsigned int
Radek Krejci23238922015-10-27 17:13:34 +0100362json_get_value(struct lyd_node_leaf_list *leaf, const char *data, int options, struct unres_data *unres)
Radek Krejci5449d472015-10-26 14:35:56 +0100363{
364 struct lyd_node_leaf_list *new, *diter;
365 struct lys_type *stype, *type;
366 struct ly_ctx *ctx;
367 unsigned int len = 0, r;
Radek Krejci23238922015-10-27 17:13:34 +0100368 int found, resolve;
Radek Krejci5449d472015-10-26 14:35:56 +0100369 char *str;
370
371 assert(leaf && data && unres);
372 ctx = leaf->schema->module->ctx;
373
Radek Krejci20cdf632015-11-09 14:44:58 +0100374 if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
Radek Krejci23238922015-10-27 17:13:34 +0100375 resolve = 0;
376 } else {
377 resolve = 1;
378 }
379
Radek Krejci5449d472015-10-26 14:35:56 +0100380 stype = &((struct lys_node_leaf *)leaf->schema)->type;
Radek Krejci23238922015-10-27 17:13:34 +0100381
382 if (options & LYD_OPT_FILTER) {
383 /* no value in filter (selection) node is accepted in this case */
384 if (!strncmp(&data[len], "null", 4)) {
385 leaf->value_type = stype->base;
386 len +=4;
387 goto end;
388 }
389 }
390
Radek Krejci5449d472015-10-26 14:35:56 +0100391 if (leaf->schema->nodetype == LYS_LEAFLIST) {
392 /* expecting begin-array */
393 if (data[len++] != '[') {
394 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (expected begin-array)");
395 return 0;
396 }
397
398repeat:
399 len += skip_ws(&data[len]);
400 }
401
402 /* will be changed in case of union */
403 leaf->value_type = stype->base;
404
405 if (data[len] == '"') {
406 /* string representations */
407 if (data[len++] != '"') {
408 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the beginning of string)");
409 return 0;
410 }
411 str = lyjson_parse_text(&data[len], &r);
Radek Krejci23238922015-10-27 17:13:34 +0100412 if (!str) {
Radek Krejci5449d472015-10-26 14:35:56 +0100413 return 0;
414 }
415 leaf->value_str = lydict_insert_zc(ctx, str);
416 if (data[len + r] != '"') {
417 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
418 return 0;
419 }
420 len += r + 1;
421 } else if (data[len] == '-' || isdigit(data[len])) {
422 /* numeric type */
423 r = lyjson_parse_number(&data[len]);
424 if (!r) {
425 return 0;
426 }
427 leaf->value_str = lydict_insert(ctx, &data[len], r);
428 len += r;
429 } else if (data[len] == 'f' || data[len] == 't') {
430 /* boolean */
431 r = lyjson_parse_boolean(&data[len]);
432 if (!r) {
433 return 0;
434 }
435 leaf->value_str = lydict_insert(ctx, &data[len], r);
436 len += r;
437 } else if (!strncmp(&data[len], "[null]", 6)) {
438 /* empty */
439 leaf->value_str = NULL;
440 len += 6;
441 } else {
442 /* error */
443 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (unexpected value)");
444 return 0;
445 }
446
447 if (stype->base == LY_TYPE_UNION) {
448 found = 0;
449 type = lyp_get_next_union_type(stype, NULL, &found);
450 while (type) {
451 leaf->value_type = type->base;
452
Radek Krejci23238922015-10-27 17:13:34 +0100453 if (!lyp_parse_value(leaf, type, resolve, unres, UINT_MAX)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100454 break;
455 }
456
457 found = 0;
458 type = lyp_get_next_union_type(stype, type, &found);
459 }
460
461 if (!type) {
462 LOGVAL(LYE_INVAL, lineno, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
Radek Krejci23238922015-10-27 17:13:34 +0100463 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100464 }
Radek Krejci23238922015-10-27 17:13:34 +0100465 } else if (lyp_parse_value(leaf, stype, resolve, unres, lineno)) {
466 ly_errno = LY_EVALID;
467 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100468 }
469
470 if (leaf->schema->nodetype == LYS_LEAFLIST) {
471 /* repeat until end-array */
472 len += skip_ws(&data[len]);
473 if (data[len] == ',') {
474 /* another instance of the leaf-list */
475 new = calloc(1, sizeof(struct lyd_node_leaf_list));
Michal Vasko253035f2015-12-17 16:58:13 +0100476 if (!new) {
477 LOGMEM;
478 return 0;
479 }
Radek Krejci5449d472015-10-26 14:35:56 +0100480 new->parent = leaf->parent;
481 new->prev = (struct lyd_node *)leaf;
482 leaf->next = (struct lyd_node *)new;
483
484 /* fix the "last" pointer */
485 for (diter = leaf; diter->prev != (struct lyd_node *)leaf; diter = (struct lyd_node_leaf_list *)diter->prev);
486 diter->prev = (struct lyd_node *)new;
487
488 new->schema = leaf->schema;
489
490 /* repeat value parsing */
491 leaf = new;
492 len++;
493 goto repeat;
494 } else if (data[len] == ']') {
495 len++;
496 len += skip_ws(&data[len]);
497 } else {
498 /* something unexpected */
499 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (expecting value-separator or end-array)");
500 return 0;
501 }
502 }
503
Radek Krejci23238922015-10-27 17:13:34 +0100504end:
Radek Krejci5449d472015-10-26 14:35:56 +0100505 len += skip_ws(&data[len]);
506 return len;
507}
508
509static unsigned int
Radek Krejci88f29302015-10-30 15:42:33 +0100510json_parse_attr(struct lys_module *parent_module, struct lyd_attr **attr, const char *data)
511{
512 unsigned int len = 0, r;
513 char *str = NULL, *name, *prefix, *value;
514 struct lys_module *module = parent_module;
515 struct lyd_attr *attr_new, *attr_last = NULL;
516
Radek Krejcide9d92c2015-10-30 15:59:59 +0100517 *attr = NULL;
518
Radek Krejci88f29302015-10-30 15:42:33 +0100519 if (data[len] != '{') {
520 if (!strncmp(&data[len], "null", 4)) {
Radek Krejci88f29302015-10-30 15:42:33 +0100521 len += 4;
522 len += skip_ws(&data[len]);
523 return len;
524 }
525 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing begin-object)");
526 goto error;
527 }
528
529repeat:
530 len++;
531 len += skip_ws(&data[len]);
532
533 if (data[len] != '"') {
534 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the begining of string)");
535 return 0;
536 }
537 len++;
538 str = lyjson_parse_text(&data[len], &r);
539 if (!r) {
540 goto error;
541 } else if (data[len + r] != '"') {
542 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
543 goto error;
544 }
545 if ((name = strchr(str, ':'))) {
546 *name = '\0';
547 name++;
548 prefix = str;
Michal Vasko1e62a092015-12-01 12:27:20 +0100549 module = (struct lys_module *)ly_ctx_get_module(parent_module->ctx, prefix, NULL);
Radek Krejci88f29302015-10-30 15:42:33 +0100550 if (!module) {
551 LOGVAL(LYE_INELEM, lineno, name);
552 goto error;
553 }
554 } else {
555 name = str;
556 }
557
558 /* prepare data for parsing node content */
559 len += r + 1;
560 len += skip_ws(&data[len]);
561 if (data[len] != ':') {
562 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing name-separator)");
563 goto error;
564 }
565 len++;
566 len += skip_ws(&data[len]);
567
568 if (data[len] != '"') {
569 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the beginning of string)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100570 goto error;
Radek Krejci88f29302015-10-30 15:42:33 +0100571 }
572 len++;
573 value = lyjson_parse_text(&data[len], &r);
574 if (!r) {
575 goto error;
576 } else if (data[len + r] != '"') {
577 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100578 free(value);
Radek Krejci88f29302015-10-30 15:42:33 +0100579 goto error;
580 }
581 len += r + 1;
582 len += skip_ws(&data[len]);
583
584 attr_new = malloc(sizeof **attr);
Michal Vasko253035f2015-12-17 16:58:13 +0100585 if (!attr_new) {
586 LOGMEM;
587 goto error;
588 }
Radek Krejci88f29302015-10-30 15:42:33 +0100589 attr_new->module = module;
590 attr_new->next = NULL;
591 attr_new->name = lydict_insert(module->ctx, name, 0);
592 attr_new->value = lydict_insert_zc(module->ctx, value);
593 if (!attr_last) {
594 *attr = attr_last = attr_new;
595 } else {
596 attr_last->next = attr_new;
597 attr_last = attr_new;
598 }
599
600 free(str);
Radek Krejcide9d92c2015-10-30 15:59:59 +0100601 str = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100602
603 if (data[len] == ',') {
604 goto repeat;
605 } else if (data[len] != '}') {
606 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-object)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100607 goto error;
Radek Krejci88f29302015-10-30 15:42:33 +0100608 }
609 len++;
610 len += skip_ws(&data[len]);
611
612 return len;
613
614error:
615 free(str);
Radek Krejcide9d92c2015-10-30 15:59:59 +0100616 if (*attr) {
617 lyd_free_attr((*attr)->module->ctx, NULL, *attr, 1);
618 *attr = NULL;
619 }
Radek Krejci88f29302015-10-30 15:42:33 +0100620 return 0;
621}
622
623struct attr_cont {
624 struct attr_cont *next;
625 struct lyd_attr *attr;
626 struct lys_node *schema;
627 unsigned int index; /** non-zero only in case of leaf-list */
628};
629
Radek Krejcic4831272015-11-01 19:26:34 +0100630static int
631store_attrs(struct ly_ctx *ctx, struct attr_cont *attrs, struct lyd_node *first)
632{
633 struct lyd_node *diter;
634 struct attr_cont *iter;
635 unsigned int flag_leaflist = 0;
636
637 while (attrs) {
638 iter = attrs;
639 attrs = attrs->next;
640
641 if (iter->index) {
642 flag_leaflist = 1;
643 }
644
645 LY_TREE_FOR(first, diter) {
646 if (iter->schema != diter->schema) {
647 continue;
648 }
649
650 if (flag_leaflist && flag_leaflist != iter->index) {
651 flag_leaflist++;
652 continue;
653 }
654
655 /* we have match */
656 if (diter->attr) {
657 LOGVAL(LYE_XML_INVAL, lineno, "attribute (multiple attribute definitions belong to a single element)");
658 free(iter);
659 goto error;
660 }
661
662 diter->attr = iter->attr;
663 break;
664 }
665
666 if (!diter) {
667 LOGVAL(LYE_XML_INVAL, lineno, "attribute with no corresponding element to belongs to");
668 lyd_free_attr(iter->schema->module->ctx, NULL, iter->attr, 1);
669 free(iter);
670 goto error;
671 }
672 free(iter);
673 }
674
675 return 0;
676
677error:
678
679 while (attrs) {
680 iter = attrs;
681 attrs = attrs->next;
682
683 lyd_free_attr(ctx, NULL, iter->attr, 1);
684 free(iter);
685 }
686
687 return -1;
688}
689
Radek Krejci88f29302015-10-30 15:42:33 +0100690static unsigned int
Michal Vasko36ef6932015-12-01 14:30:17 +0100691json_parse_data(struct ly_ctx *ctx, const char *data, const struct lys_node *schema_parent, struct lyd_node **parent,
692 struct lyd_node *prev, struct attr_cont **attrs, int options, struct unres_data *unres)
Radek Krejci5449d472015-10-26 14:35:56 +0100693{
694 unsigned int len = 0;
695 unsigned int r;
Radek Krejcic4831272015-11-01 19:26:34 +0100696 unsigned int flag_leaflist = 0;
Radek Krejci88f29302015-10-30 15:42:33 +0100697 char *name, *prefix = NULL, *str = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +0100698 const struct lys_module *module = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +0100699 struct lys_node *schema = NULL;
700 struct lyd_node *result = NULL, *new, *list, *diter = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100701 struct lyd_attr *attr;
Radek Krejcic4831272015-11-01 19:26:34 +0100702 struct attr_cont *attrs_aux;
Radek Krejci5449d472015-10-26 14:35:56 +0100703
704 /* each YANG data node representation starts with string (node identifier) */
705 if (data[len] != '"') {
Radek Krejci88f29302015-10-30 15:42:33 +0100706 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the beginning of string)");
707 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100708 }
709 len++;
710
Radek Krejci23238922015-10-27 17:13:34 +0100711 str = lyjson_parse_text(&data[len], &r);
Radek Krejci5449d472015-10-26 14:35:56 +0100712 if (!r) {
713 goto error;
714 } else if (data[len + r] != '"') {
715 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
716 goto error;
717 }
Radek Krejci23238922015-10-27 17:13:34 +0100718 if ((name = strchr(str, ':'))) {
719 *name = '\0';
720 name++;
721 prefix = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100722 if (prefix[0] == '@') {
723 prefix++;
724 }
Radek Krejci23238922015-10-27 17:13:34 +0100725 } else {
726 name = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100727 if (name[0] == '@') {
728 name++;
729 }
Radek Krejci5449d472015-10-26 14:35:56 +0100730 }
731
Radek Krejci5449d472015-10-26 14:35:56 +0100732 /* prepare data for parsing node content */
733 len += r + 1;
734 len += skip_ws(&data[len]);
735 if (data[len] != ':') {
736 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing name-separator)");
737 goto error;
738 }
739 len++;
740 len += skip_ws(&data[len]);
741
Radek Krejci88f29302015-10-30 15:42:33 +0100742 if (str[0] == '@' && !str[1]) {
743 /* process attribute of the parent object (container or list) */
744 if (!*parent) {
745 LOGVAL(LYE_XML_INVAL, lineno, "attribute with no corresponding element to belongs to");
746 goto error;
747 }
748
749 r = json_parse_attr((*parent)->schema->module, &attr, &data[len]);
750 if (!r) {
751 goto error;
752 }
753 len += r;
754
755 if ((*parent)->attr) {
756 lyd_free_attr(ctx, NULL, attr, 1);
757 } else {
758 (*parent)->attr = attr;
759 }
Radek Krejcic4831272015-11-01 19:26:34 +0100760 free(str);
761 return len;
Radek Krejci88f29302015-10-30 15:42:33 +0100762 }
763
Radek Krejci5449d472015-10-26 14:35:56 +0100764 /* find schema node */
765 if (!(*parent)) {
766 /* starting in root */
767 /* get the proper schema */
768 module = ly_ctx_get_module(ctx, prefix, NULL);
769 if (module) {
770 /* get the proper schema node */
771 LY_TREE_FOR(module->data, schema) {
772 if (!strcmp(schema->name, name)) {
773 break;
774 }
775 }
Radek Krejci88f29302015-10-30 15:42:33 +0100776 } else {
777 LOGVAL(LYE_INELEM, lineno, name);
778 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100779 }
780 } else {
781 /* parsing some internal node, we start with parent's schema pointer */
782 if (prefix) {
783 /* get the proper schema */
784 module = ly_ctx_get_module(ctx, prefix, NULL);
785 if (!module) {
786 LOGVAL(LYE_INELEM, lineno, name);
Radek Krejci88f29302015-10-30 15:42:33 +0100787 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100788 }
789 }
Michal Vasko36ef6932015-12-01 14:30:17 +0100790 if (schema_parent) {
791 while ((schema = (struct lys_node *)lys_getnext(schema, schema_parent, module, 0))) {
792 if (!strcmp(schema->name, name)) {
793 break;
794 }
795 }
796 } else {
797 while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, module, 0))) {
798 if (!strcmp(schema->name, name)) {
799 break;
800 }
Radek Krejci5449d472015-10-26 14:35:56 +0100801 }
802 }
803 }
804 if (!schema) {
805 LOGVAL(LYE_INELEM, lineno, name);
Radek Krejci88f29302015-10-30 15:42:33 +0100806 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100807 }
Radek Krejci88f29302015-10-30 15:42:33 +0100808
809 if (str[0] == '@') {
Radek Krejci88f29302015-10-30 15:42:33 +0100810 /* attribute for some sibling node */
811 if (data[len] == '[') {
812 flag_leaflist = 1;
813 len++;
814 len += skip_ws(&data[len]);
815 }
816
817attr_repeat:
818 r = json_parse_attr(schema->module, &attr, &data[len]);
819 if (!r) {
820 goto error;
821 }
822 len += r;
823
824 if (attr) {
Radek Krejcic4831272015-11-01 19:26:34 +0100825 attrs_aux = malloc(sizeof *attrs_aux);
Michal Vasko253035f2015-12-17 16:58:13 +0100826 if (!attrs_aux) {
827 LOGMEM;
828 goto error;
829 }
Radek Krejcic4831272015-11-01 19:26:34 +0100830 attrs_aux->attr = attr;
831 attrs_aux->index = flag_leaflist;
832 attrs_aux->schema = schema;
833 attrs_aux->next = *attrs;
834 *attrs = attrs_aux;
Radek Krejci88f29302015-10-30 15:42:33 +0100835 } else if (!flag_leaflist) {
836 /* error */
837 LOGVAL(LYE_XML_INVAL, lineno, "attribute data");
838 goto error;
839 }
840
841 if (flag_leaflist) {
842 if (data[len] == ',') {
843 len++;
844 len += skip_ws(&data[len]);
845 flag_leaflist++;
846 goto attr_repeat;
847 } else if (data[len] != ']') {
848 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-array)");
849 goto error;
850 }
851 len++;
852 len += skip_ws(&data[len]);
853 }
854
Radek Krejcic4831272015-11-01 19:26:34 +0100855 free(str);
856 return len;
Radek Krejci88f29302015-10-30 15:42:33 +0100857 }
858
Radek Krejci5449d472015-10-26 14:35:56 +0100859 switch (schema->nodetype) {
860 case LYS_CONTAINER:
861 case LYS_LIST:
862 case LYS_NOTIF:
863 case LYS_RPC:
864 result = calloc(1, sizeof *result);
865 break;
866 case LYS_LEAF:
867 case LYS_LEAFLIST:
868 result = calloc(1, sizeof(struct lyd_node_leaf_list));
869 break;
870 case LYS_ANYXML:
871 result = calloc(1, sizeof(struct lyd_node_anyxml));
872 break;
873 default:
874 LOGINT;
Radek Krejci595060f2015-10-30 16:29:58 +0100875 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100876 }
Michal Vasko253035f2015-12-17 16:58:13 +0100877 if (!result) {
878 LOGMEM;
879 goto error;
880 }
881
Radek Krejci5449d472015-10-26 14:35:56 +0100882 result->parent = *parent;
883 if (*parent && !(*parent)->child) {
884 (*parent)->child = result;
885 }
886 if (prev) {
887 result->prev = prev;
888 prev->next = result;
889
890 /* fix the "last" pointer */
891 for (diter = prev; diter->prev != prev; diter = diter->prev);
892 diter->prev = result;
893 } else {
894 result->prev = result;
895 }
896 result->schema = schema;
897
Radek Krejci23238922015-10-27 17:13:34 +0100898 if (lyv_data_context(result, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100899 goto error;
900 }
901
902 /* type specific processing */
903 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
904 /* type detection and assigning the value */
Radek Krejci23238922015-10-27 17:13:34 +0100905 r = json_get_value((struct lyd_node_leaf_list *)result, &data[len], options, unres);
Radek Krejci5449d472015-10-26 14:35:56 +0100906 if (!r) {
907 goto error;
908 }
Radek Krejci88f29302015-10-30 15:42:33 +0100909 while(result->next) {
910 result = result->next;
911 }
912
Radek Krejci5449d472015-10-26 14:35:56 +0100913 len += r;
914 len += skip_ws(&data[len]);
915 } else if (schema->nodetype == LYS_ANYXML) {
916 r = json_get_anyxml((struct lyd_node_anyxml *)result, &data[len]);
917 if (!r) {
918 goto error;
919 }
920 len += r;
921 len += skip_ws(&data[len]);
922 } else if (schema->nodetype == LYS_CONTAINER) {
923 if (data[len] != '{') {
924 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing begin-object)");
925 goto error;
926 }
927 len++;
928 len += skip_ws(&data[len]);
929
930 if (data[len] != '}') {
931 /* non-empty container */
Radek Krejcic4831272015-11-01 19:26:34 +0100932 len--;
933 diter = NULL;
934 attrs_aux = NULL;
935 do {
936 len++;
937 len += skip_ws(&data[len]);
938
Michal Vasko36ef6932015-12-01 14:30:17 +0100939 r = json_parse_data(ctx, &data[len], NULL, &result, diter, &attrs_aux, options, unres);
Radek Krejcic4831272015-11-01 19:26:34 +0100940 if (!r) {
941 goto error;
942 }
943 len += r;
944
945 if (result->child) {
946 diter = result->child->prev;
947 }
948 } while(data[len] == ',');
949
950 /* store attributes */
951 if (store_attrs(ctx, attrs_aux, result->child)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100952 goto error;
953 }
Radek Krejci5449d472015-10-26 14:35:56 +0100954 }
955
956 if (data[len] != '}') {
957 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-object)");
958 goto error;
959 }
960 len++;
961 len += skip_ws(&data[len]);
962
963 } else if (schema->nodetype == LYS_LIST) {
964 if (data[len] != '[') {
965 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing begin-array)");
966 goto error;
967 }
968
969 list = result;
970 do {
971 len++;
972 len += skip_ws(&data[len]);
Radek Krejci23238922015-10-27 17:13:34 +0100973
974 if (options & LYD_OPT_FILTER) {
975 /* filter selection node ? */
976 if (data[len] == ']') {
977 break;
978 } else if (!strcmp(&data[len], "null")) {
979 len += 4;
980 len += skip_ws(&data[len]);
981 break;
982 }
983 }
984
Radek Krejcic4831272015-11-01 19:26:34 +0100985 if (data[len] != '{') {
986 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing list instance's begin-object)");
Radek Krejci5449d472015-10-26 14:35:56 +0100987 goto error;
988 }
Radek Krejcic4831272015-11-01 19:26:34 +0100989 diter = NULL;
990 attrs_aux = NULL;
991 do {
992 len++;
993 len += skip_ws(&data[len]);
994
Michal Vasko36ef6932015-12-01 14:30:17 +0100995 r = json_parse_data(ctx, &data[len], NULL, &list, diter, &attrs_aux, options, unres);
Radek Krejcic4831272015-11-01 19:26:34 +0100996 if (!r) {
997 goto error;
998 }
999 len += r;
1000
Radek Krejci52934692015-11-01 20:08:15 +01001001 if (list->child) {
Radek Krejcic4831272015-11-01 19:26:34 +01001002 diter = list->child->prev;
1003 }
1004 } while(data[len] == ',');
1005
1006 /* store attributes */
Radek Krejci52934692015-11-01 20:08:15 +01001007 if (store_attrs(ctx, attrs_aux, list->child)) {
Radek Krejcic4831272015-11-01 19:26:34 +01001008 goto error;
1009 }
1010
1011 if (data[len] != '}') {
1012 /* expecting end-object */
1013 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing list instance's end-object)");
1014 goto error;
1015 }
1016 len++;
Radek Krejci5449d472015-10-26 14:35:56 +01001017 len += skip_ws(&data[len]);
1018
1019 if (data[len] == ',') {
1020 /* another instance of the list */
1021 new = calloc(1, sizeof *new);
Michal Vasko253035f2015-12-17 16:58:13 +01001022 if (!new) {
1023 goto error;
1024 }
Radek Krejci5449d472015-10-26 14:35:56 +01001025 new->parent = list->parent;
1026 new->prev = list;
1027 list->next = new;
1028
1029 /* fix the "last" pointer */
1030 for (diter = list; diter->prev != list; diter = diter->prev);
1031 diter->prev = new;
1032
1033 new->schema = list->schema;
1034
1035 /* various validation checks */
1036 ly_errno = 0;
Radek Krejci23238922015-10-27 17:13:34 +01001037 if (lyv_data_content(list, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +01001038 if (ly_errno) {
1039 goto error;
1040 }
1041 }
1042 list = new;
1043 }
1044 } while (data[len] == ',');
1045 result = list;
1046
1047 if (data[len] != ']') {
1048 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-array)");
1049 goto error;
1050 }
1051 len++;
1052 len += skip_ws(&data[len]);
1053 }
1054
1055 /* various validation checks */
1056 ly_errno = 0;
Radek Krejci23238922015-10-27 17:13:34 +01001057 if (lyv_data_content(result, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +01001058 if (ly_errno) {
1059 goto error;
1060 }
1061 }
1062
Radek Krejci88f29302015-10-30 15:42:33 +01001063 if (!(*parent)) {
1064 *parent = result;
1065 }
1066
Radek Krejcide9d92c2015-10-30 15:59:59 +01001067 free(str);
Radek Krejci5449d472015-10-26 14:35:56 +01001068 return len;
1069
1070error:
Radek Krejci88f29302015-10-30 15:42:33 +01001071 if ((*parent) == result) {
1072 (*parent) = NULL;
1073 }
1074 while (*attrs) {
Radek Krejcic4831272015-11-01 19:26:34 +01001075 attrs_aux = *attrs;
Radek Krejci88f29302015-10-30 15:42:33 +01001076 *attrs = (*attrs)->next;
1077
Radek Krejcic4831272015-11-01 19:26:34 +01001078 lyd_free_attr(ctx, NULL, attrs_aux->attr, 1);
1079 free(attrs_aux);
Radek Krejci88f29302015-10-30 15:42:33 +01001080 }
1081
Radek Krejci5449d472015-10-26 14:35:56 +01001082 lyd_free(result);
Radek Krejci88f29302015-10-30 15:42:33 +01001083 free(str);
1084
Radek Krejci5449d472015-10-26 14:35:56 +01001085 return 0;
1086}
1087
1088struct lyd_node *
Michal Vasko36ef6932015-12-01 14:30:17 +01001089lyd_parse_json(struct ly_ctx *ctx, const struct lys_node *parent, const char *data, int options)
Radek Krejci5449d472015-10-26 14:35:56 +01001090{
Radek Krejcic4831272015-11-01 19:26:34 +01001091 struct lyd_node *result = NULL, *next = NULL, *iter = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +01001092 struct unres_data *unres = NULL;
Radek Krejcic4831272015-11-01 19:26:34 +01001093 unsigned int len = 0, r;
1094 struct attr_cont *attrs = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +01001095
1096 if (!ctx || !data) {
1097 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
1098 return NULL;
1099 }
1100
1101 unres = calloc(1, sizeof *unres);
Michal Vasko253035f2015-12-17 16:58:13 +01001102 if (!unres) {
1103 LOGMEM;
1104 return NULL;
1105 }
Radek Krejci5449d472015-10-26 14:35:56 +01001106
1107#ifndef NDEBUG
1108 lineno = 0;
1109#endif
1110 ly_errno = 0;
Radek Krejcic4831272015-11-01 19:26:34 +01001111
1112 /* skip leading whitespaces */
1113 len += skip_ws(&data[len]);
1114
1115 /* expect top-level { */
1116 if (data[len] != '{') {
1117 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing top level begin-object)");
1118 goto cleanup;
1119 }
1120
1121 do {
1122 len++;
1123 len += skip_ws(&data[len]);
1124
Michal Vasko36ef6932015-12-01 14:30:17 +01001125 r = json_parse_data(ctx, &data[len], parent, &next, iter, &attrs, options, unres);
Radek Krejcic4831272015-11-01 19:26:34 +01001126 if (!r) {
1127 result = NULL;
1128 goto cleanup;
1129 }
1130 len += r;
1131
1132 if (!result) {
1133 result = next;
1134 }
1135 if (next) {
1136 iter = next;
1137 }
1138 next = NULL;
1139 } while(data[len] == ',');
1140
1141 if (data[len] != '}') {
1142 /* expecting end-object */
1143 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing top-level end-object)");
1144 LY_TREE_FOR_SAFE(result, next, iter) {
1145 lyd_free(iter);
1146 }
1147 result = NULL;
1148 goto cleanup;
1149 }
1150 len++;
1151 len += skip_ws(&data[len]);
1152
1153 /* store attributes */
1154 if (store_attrs(ctx, attrs, result)) {
1155 LY_TREE_FOR_SAFE(result, next, iter) {
1156 lyd_free(iter);
1157 }
1158 result = NULL;
1159 goto cleanup;
1160 }
Radek Krejci5449d472015-10-26 14:35:56 +01001161
Michal Vaskoc1cf86f2015-11-04 09:54:51 +01001162 if (!result) {
1163 LOGERR(LY_EVALID, "Model for the data to be linked with not found.");
1164 goto cleanup;
1165 }
1166
Radek Krejci5449d472015-10-26 14:35:56 +01001167 /* check leafrefs and/or instids if any */
1168 if (result && resolve_unres_data(unres)) {
1169 /* leafref & instid checking failed */
Radek Krejcic4831272015-11-01 19:26:34 +01001170 LY_TREE_FOR_SAFE(result, next, iter) {
Radek Krejci5449d472015-10-26 14:35:56 +01001171 lyd_free(iter);
1172 }
1173 result = NULL;
1174 }
1175
Radek Krejcic4831272015-11-01 19:26:34 +01001176cleanup:
Radek Krejci5449d472015-10-26 14:35:56 +01001177 free(unres->node);
1178 free(unres->type);
1179#ifndef NDEBUG
1180 free(unres->line);
1181#endif
1182 free(unres);
1183
1184 return result;
1185}