blob: 182e4ef33da328aa41adf4fe1f3c91358768cbcb [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
36#ifndef NDEBUG
37static unsigned int lineno;
38#endif
39
40static int
41lyjson_isspace(int c)
42{
43 switch(c) {
44 case 0x20: /* space */
45 case 0x09: /* horizontal tab */
46 case 0x0a: /* line feed or new line */
47 case 0x0d: /* carriage return */
48 return 1;
49 default:
50 return 0;
51 }
52}
53
54static unsigned int
55skip_ws(const char *data)
56{
57 unsigned int len = 0;
58
59 /* skip leading whitespaces */
60 while (data[len] && lyjson_isspace(data[len])) {
61 COUNTLINE(data[len]);
62 len++;
63 }
64
65 return len;
66}
67
68int lyjson_dump_string(struct lyout *out, const char *text)
69{
70 unsigned int i, n;
71
72 if (!text) {
73 return 0;
74 }
75
76 ly_write(out, "\"", 1);
77 for (i = n = 0; text[i]; i++) {
78 if (text[i] < 0x20) {
79 /* control character */
80 n += ly_print(out, "\\u%.4X");
81 } else {
82 switch (text[i]) {
83 case '"':
84 n += ly_print(out, "\\\"");
85 break;
86 case '\\':
87 n += ly_print(out, "\\\\");
88 break;
89 case '/':
90 n += ly_print(out, "\\/");
91 break;
92 default:
93 ly_write(out, &text[i], 1);
94 n++;
95 }
96 }
97 }
98 ly_write(out, "\"", 1);
99
100 return n + 2;
101}
102
103
104static char *
105lyjson_parse_text(const char *data, unsigned int *len)
106{
107#define BUFSIZE 1024
108
109 char buf[BUFSIZE];
110 char *result = NULL, *aux;
111 int o, size;
112 unsigned int r, i;
113 int32_t value;
114
115 for (*len = o = 0; data[*len] && data[*len] != '"'; o++) {
116 if (o > BUFSIZE - 3) {
117 /* add buffer into the result */
118 if (result) {
119 size = size + o;
120 aux = realloc(result, size + 1);
121 result = aux;
122 } else {
123 size = o;
124 result = malloc((size + 1) * sizeof *result);
125 }
126 memcpy(&result[size - o], buf, o);
127
128 /* write again into the beginning of the buffer */
129 o = 0;
130 }
131
132 if (data[*len] == '\\') {
133 /* parse escape sequence */
134 (*len)++;
135 i = 1;
136 switch (data[(*len)]) {
137 case '"':
138 /* quotation mark */
139 value = 0x22;
140 break;
141 case '\\':
142 /* reverse solidus */
143 value = 0x5c;
144 break;
145 case '/':
146 /* solidus */
147 value = 0x2f;
148 break;
149 case 'b':
150 /* backspace */
151 value = 0x08;
152 break;
153 case 'f':
154 /* form feed */
155 value = 0x0c;
156 break;
157 case 'n':
158 /* line feed */
159 value = 0x0a;
160 break;
161 case 'r':
162 /* carriage return */
163 value = 0x0d;
164 break;
165 case 't':
166 /* tab */
167 value = 0x09;
168 break;
169 case 'u':
170 /* Basic Multilingual Plane character \uXXXX */
171 (*len)++;
172 for (value = i = 0; i < 4; i++) {
173 if (isdigit(data[(*len) + i])) {
174 r = (data[(*len) + i] - '0');
175 } else if (data[(*len) + i] > 'F') {
176 r = 10 + (data[(*len) + i] - 'a');
177 } else {
178 r = 10 + (data[(*len) + i] - 'A');
179 }
180 value = (16 * value) + r;
181 }
182 break;
183 default:
184 /* invalid escape sequence */
185 LOGVAL(LYE_XML_INVAL, lineno, "character escape sequence");
186 goto error;
187
188 }
189 r = pututf8(&buf[o], value, lineno);
190 if (!r) {
191 LOGVAL(LYE_XML_INVAL, lineno, "character UTF8 character");
192 goto error;
193 }
194 o += r - 1; /* o is ++ in for loop */
195 (*len) += i; /* number of read characters */
196 } else if (data[*len] < 0x20 || data[*len] == 0x5c) {
197 /* control characters must be escaped */
198 LOGVAL(LYE_XML_INVAL, lineno, "control character (unescaped)");
199 goto error;
200 } else {
201 /* unescaped character */
202 buf[o] = data[*len];
203 COUNTLINE(buf[o]);
204 (*len)++;
205 }
206 }
207
208#undef BUFSIZE
209
210 if (o) {
211 if (result) {
212 size = size + o;
213 aux = realloc(result, size + 1);
214 result = aux;
215 } else {
216 size = o;
217 result = malloc((size + 1) * sizeof *result);
218 }
219 memcpy(&result[size - o], buf, o);
220 }
221 if (result) {
222 result[size] = '\0';
223 } else {
224 size = 0;
225 result = strdup("");
226 }
227
228 return result;
229
230error:
231 free(result);
232 return NULL;
233}
234
235static unsigned int
236lyjson_parse_number(const char *data)
237{
238 unsigned int len;
239 unsigned int i = 0;
240
241 for (len = 0;
242 data[len] && data[len] != ',' && data[len] != ']' && data[len] != '}' && !lyjson_isspace(data[len]);
243 len++) {
244
245 switch(data[len]) {
246 case '0':
Radek Krejci88f29302015-10-30 15:42:33 +0100247 if (!i && isdigit(data[len + 1])) {
Radek Krejci5449d472015-10-26 14:35:56 +0100248 /* leading 0 is not allowed */
249 LOGVAL(LYE_XML_INVAL, lineno, "JSON number (leading zero)");
250 return 0;
251 }
252 /* no break */
253 case '1':
254 case '2':
255 case '3':
256 case '4':
257 case '5':
258 case '6':
259 case '7':
260 case '8':
261 case '9':
262 i = 1;
263 /* no break */
264 case 0x2d: /* minus */
265 /* ok */
266 break;
267 default:
268 LOGVAL(LYE_XML_INVAL, lineno, "character in JSON Number value");
269 return 0;
270 }
271 }
272
273 return len;
274}
275
276static unsigned int
277lyjson_parse_boolean(const char *data)
278{
Radek Krejci6b47b502015-10-30 15:52:41 +0100279 unsigned int len = 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100280
281 if (!strncmp(data, "false", 5)) {
282 len = 5;
283 } else if (!strncmp(data, "true", 4)) {
284 len = 4;
285 }
286
287 if (data[len] && data[len] != ',' && data[len] != ']' && data[len] != '}' && !lyjson_isspace(data[len])) {
288 LOGVAL(LYE_XML_INVAL, lineno, "JSON literal value (expected true or false)");
289 return 0;
290 }
291
292 return len;
293}
294
295static unsigned int
296json_get_anyxml(struct lyd_node_anyxml *axml, const char *data)
297{
298 unsigned int len = 0;
299 char stop, start;
300 int level = 0;
301
302 switch (data[len]) {
303 case '"':
304 start = 0;
305 stop = '"';
306 level = 1;
307 break;
308 case '[':
309 start = '[';
310 stop = ']';
311 break;
312 case '{':
313 start = '{';
314 stop = '}';
315 break;
316 default:
317 /* number or one of literals */
318 while (!isspace(data[len])) {
319 len++;
320 }
321 axml->value = NULL; /* TODO ??? */
322 return len;
323 }
324
325 while (data[len]) {
326 if (start && data[len] == start) {
327 if (!len || data[len - 1] != '\\') {
328 level++;
329 }
330 } else if (data[len] == stop) {
331 if (!len || data[len - 1] != '\\') {
332 level--;
333 }
334 }
335 stop = len;
336 len++;
337 if (!level) {
338 /* we are done */
339 axml->value = NULL; /* TODO ??? */
340 return len;
341 }
342 }
343
344 return 0;
345}
346
347static unsigned int
Radek Krejci23238922015-10-27 17:13:34 +0100348json_get_value(struct lyd_node_leaf_list *leaf, const char *data, int options, struct unres_data *unres)
Radek Krejci5449d472015-10-26 14:35:56 +0100349{
350 struct lyd_node_leaf_list *new, *diter;
351 struct lys_type *stype, *type;
352 struct ly_ctx *ctx;
353 unsigned int len = 0, r;
Radek Krejci23238922015-10-27 17:13:34 +0100354 int found, resolve;
Radek Krejci5449d472015-10-26 14:35:56 +0100355 char *str;
356
357 assert(leaf && data && unres);
358 ctx = leaf->schema->module->ctx;
359
Radek Krejci23238922015-10-27 17:13:34 +0100360 if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT)) {
361 resolve = 0;
362 } else {
363 resolve = 1;
364 }
365
Radek Krejci5449d472015-10-26 14:35:56 +0100366 stype = &((struct lys_node_leaf *)leaf->schema)->type;
Radek Krejci23238922015-10-27 17:13:34 +0100367
368 if (options & LYD_OPT_FILTER) {
369 /* no value in filter (selection) node is accepted in this case */
370 if (!strncmp(&data[len], "null", 4)) {
371 leaf->value_type = stype->base;
372 len +=4;
373 goto end;
374 }
375 }
376
Radek Krejci5449d472015-10-26 14:35:56 +0100377 if (leaf->schema->nodetype == LYS_LEAFLIST) {
378 /* expecting begin-array */
379 if (data[len++] != '[') {
380 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (expected begin-array)");
381 return 0;
382 }
383
384repeat:
385 len += skip_ws(&data[len]);
386 }
387
388 /* will be changed in case of union */
389 leaf->value_type = stype->base;
390
391 if (data[len] == '"') {
392 /* string representations */
393 if (data[len++] != '"') {
394 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the beginning of string)");
395 return 0;
396 }
397 str = lyjson_parse_text(&data[len], &r);
Radek Krejci23238922015-10-27 17:13:34 +0100398 if (!str) {
Radek Krejci5449d472015-10-26 14:35:56 +0100399 return 0;
400 }
401 leaf->value_str = lydict_insert_zc(ctx, str);
402 if (data[len + r] != '"') {
403 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
404 return 0;
405 }
406 len += r + 1;
407 } else if (data[len] == '-' || isdigit(data[len])) {
408 /* numeric type */
409 r = lyjson_parse_number(&data[len]);
410 if (!r) {
411 return 0;
412 }
413 leaf->value_str = lydict_insert(ctx, &data[len], r);
414 len += r;
415 } else if (data[len] == 'f' || data[len] == 't') {
416 /* boolean */
417 r = lyjson_parse_boolean(&data[len]);
418 if (!r) {
419 return 0;
420 }
421 leaf->value_str = lydict_insert(ctx, &data[len], r);
422 len += r;
423 } else if (!strncmp(&data[len], "[null]", 6)) {
424 /* empty */
425 leaf->value_str = NULL;
426 len += 6;
427 } else {
428 /* error */
429 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (unexpected value)");
430 return 0;
431 }
432
433 if (stype->base == LY_TYPE_UNION) {
434 found = 0;
435 type = lyp_get_next_union_type(stype, NULL, &found);
436 while (type) {
437 leaf->value_type = type->base;
438
Radek Krejci23238922015-10-27 17:13:34 +0100439 if (!lyp_parse_value(leaf, type, resolve, unres, UINT_MAX)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100440 break;
441 }
442
443 found = 0;
444 type = lyp_get_next_union_type(stype, type, &found);
445 }
446
447 if (!type) {
448 LOGVAL(LYE_INVAL, lineno, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
Radek Krejci23238922015-10-27 17:13:34 +0100449 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100450 }
Radek Krejci23238922015-10-27 17:13:34 +0100451 } else if (lyp_parse_value(leaf, stype, resolve, unres, lineno)) {
452 ly_errno = LY_EVALID;
453 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100454 }
455
456 if (leaf->schema->nodetype == LYS_LEAFLIST) {
457 /* repeat until end-array */
458 len += skip_ws(&data[len]);
459 if (data[len] == ',') {
460 /* another instance of the leaf-list */
461 new = calloc(1, sizeof(struct lyd_node_leaf_list));
462 new->parent = leaf->parent;
463 new->prev = (struct lyd_node *)leaf;
464 leaf->next = (struct lyd_node *)new;
465
466 /* fix the "last" pointer */
467 for (diter = leaf; diter->prev != (struct lyd_node *)leaf; diter = (struct lyd_node_leaf_list *)diter->prev);
468 diter->prev = (struct lyd_node *)new;
469
470 new->schema = leaf->schema;
471
472 /* repeat value parsing */
473 leaf = new;
474 len++;
475 goto repeat;
476 } else if (data[len] == ']') {
477 len++;
478 len += skip_ws(&data[len]);
479 } else {
480 /* something unexpected */
481 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (expecting value-separator or end-array)");
482 return 0;
483 }
484 }
485
Radek Krejci23238922015-10-27 17:13:34 +0100486end:
Radek Krejci5449d472015-10-26 14:35:56 +0100487 len += skip_ws(&data[len]);
488 return len;
489}
490
491static unsigned int
Radek Krejci88f29302015-10-30 15:42:33 +0100492json_parse_attr(struct lys_module *parent_module, struct lyd_attr **attr, const char *data)
493{
494 unsigned int len = 0, r;
495 char *str = NULL, *name, *prefix, *value;
496 struct lys_module *module = parent_module;
497 struct lyd_attr *attr_new, *attr_last = NULL;
498
Radek Krejcide9d92c2015-10-30 15:59:59 +0100499 *attr = NULL;
500
Radek Krejci88f29302015-10-30 15:42:33 +0100501 if (data[len] != '{') {
502 if (!strncmp(&data[len], "null", 4)) {
Radek Krejci88f29302015-10-30 15:42:33 +0100503 len += 4;
504 len += skip_ws(&data[len]);
505 return len;
506 }
507 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing begin-object)");
508 goto error;
509 }
510
511repeat:
512 len++;
513 len += skip_ws(&data[len]);
514
515 if (data[len] != '"') {
516 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the begining of string)");
517 return 0;
518 }
519 len++;
520 str = lyjson_parse_text(&data[len], &r);
521 if (!r) {
522 goto error;
523 } else if (data[len + r] != '"') {
524 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
525 goto error;
526 }
527 if ((name = strchr(str, ':'))) {
528 *name = '\0';
529 name++;
530 prefix = str;
531 module = ly_ctx_get_module(parent_module->ctx, prefix, NULL);
532 if (!module) {
533 LOGVAL(LYE_INELEM, lineno, name);
534 goto error;
535 }
536 } else {
537 name = str;
538 }
539
540 /* prepare data for parsing node content */
541 len += r + 1;
542 len += skip_ws(&data[len]);
543 if (data[len] != ':') {
544 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing name-separator)");
545 goto error;
546 }
547 len++;
548 len += skip_ws(&data[len]);
549
550 if (data[len] != '"') {
551 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the beginning of string)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100552 goto error;
Radek Krejci88f29302015-10-30 15:42:33 +0100553 }
554 len++;
555 value = lyjson_parse_text(&data[len], &r);
556 if (!r) {
557 goto error;
558 } else if (data[len + r] != '"') {
559 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100560 free(value);
Radek Krejci88f29302015-10-30 15:42:33 +0100561 goto error;
562 }
563 len += r + 1;
564 len += skip_ws(&data[len]);
565
566 attr_new = malloc(sizeof **attr);
567 attr_new->module = module;
568 attr_new->next = NULL;
569 attr_new->name = lydict_insert(module->ctx, name, 0);
570 attr_new->value = lydict_insert_zc(module->ctx, value);
571 if (!attr_last) {
572 *attr = attr_last = attr_new;
573 } else {
574 attr_last->next = attr_new;
575 attr_last = attr_new;
576 }
577
578 free(str);
Radek Krejcide9d92c2015-10-30 15:59:59 +0100579 str = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100580
581 if (data[len] == ',') {
582 goto repeat;
583 } else if (data[len] != '}') {
584 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-object)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100585 goto error;
Radek Krejci88f29302015-10-30 15:42:33 +0100586 }
587 len++;
588 len += skip_ws(&data[len]);
589
590 return len;
591
592error:
593 free(str);
Radek Krejcide9d92c2015-10-30 15:59:59 +0100594 if (*attr) {
595 lyd_free_attr((*attr)->module->ctx, NULL, *attr, 1);
596 *attr = NULL;
597 }
Radek Krejci88f29302015-10-30 15:42:33 +0100598 return 0;
599}
600
601struct attr_cont {
602 struct attr_cont *next;
603 struct lyd_attr *attr;
604 struct lys_node *schema;
605 unsigned int index; /** non-zero only in case of leaf-list */
606};
607
Radek Krejcic4831272015-11-01 19:26:34 +0100608static int
609store_attrs(struct ly_ctx *ctx, struct attr_cont *attrs, struct lyd_node *first)
610{
611 struct lyd_node *diter;
612 struct attr_cont *iter;
613 unsigned int flag_leaflist = 0;
614
615 while (attrs) {
616 iter = attrs;
617 attrs = attrs->next;
618
619 if (iter->index) {
620 flag_leaflist = 1;
621 }
622
623 LY_TREE_FOR(first, diter) {
624 if (iter->schema != diter->schema) {
625 continue;
626 }
627
628 if (flag_leaflist && flag_leaflist != iter->index) {
629 flag_leaflist++;
630 continue;
631 }
632
633 /* we have match */
634 if (diter->attr) {
635 LOGVAL(LYE_XML_INVAL, lineno, "attribute (multiple attribute definitions belong to a single element)");
636 free(iter);
637 goto error;
638 }
639
640 diter->attr = iter->attr;
641 break;
642 }
643
644 if (!diter) {
645 LOGVAL(LYE_XML_INVAL, lineno, "attribute with no corresponding element to belongs to");
646 lyd_free_attr(iter->schema->module->ctx, NULL, iter->attr, 1);
647 free(iter);
648 goto error;
649 }
650 free(iter);
651 }
652
653 return 0;
654
655error:
656
657 while (attrs) {
658 iter = attrs;
659 attrs = attrs->next;
660
661 lyd_free_attr(ctx, NULL, iter->attr, 1);
662 free(iter);
663 }
664
665 return -1;
666}
667
Radek Krejci88f29302015-10-30 15:42:33 +0100668static unsigned int
Radek Krejci5449d472015-10-26 14:35:56 +0100669json_parse_data(struct ly_ctx *ctx, const char *data, struct lyd_node **parent, struct lyd_node *prev,
Radek Krejci88f29302015-10-30 15:42:33 +0100670 struct attr_cont **attrs, int options, struct unres_data *unres)
Radek Krejci5449d472015-10-26 14:35:56 +0100671{
672 unsigned int len = 0;
673 unsigned int r;
Radek Krejcic4831272015-11-01 19:26:34 +0100674 unsigned int flag_leaflist = 0;
Radek Krejci88f29302015-10-30 15:42:33 +0100675 char *name, *prefix = NULL, *str = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +0100676 struct lys_module *module = NULL;
677 struct lys_node *schema = NULL;
678 struct lyd_node *result = NULL, *new, *list, *diter = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100679 struct lyd_attr *attr;
Radek Krejcic4831272015-11-01 19:26:34 +0100680 struct attr_cont *attrs_aux;
Radek Krejci5449d472015-10-26 14:35:56 +0100681
682 /* each YANG data node representation starts with string (node identifier) */
683 if (data[len] != '"') {
Radek Krejci88f29302015-10-30 15:42:33 +0100684 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the beginning of string)");
685 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100686 }
687 len++;
688
Radek Krejci23238922015-10-27 17:13:34 +0100689 str = lyjson_parse_text(&data[len], &r);
Radek Krejci5449d472015-10-26 14:35:56 +0100690 if (!r) {
691 goto error;
692 } else if (data[len + r] != '"') {
693 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
694 goto error;
695 }
Radek Krejci23238922015-10-27 17:13:34 +0100696 if ((name = strchr(str, ':'))) {
697 *name = '\0';
698 name++;
699 prefix = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100700 if (prefix[0] == '@') {
701 prefix++;
702 }
Radek Krejci23238922015-10-27 17:13:34 +0100703 } else {
704 name = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100705 if (name[0] == '@') {
706 name++;
707 }
Radek Krejci5449d472015-10-26 14:35:56 +0100708 }
709
Radek Krejci5449d472015-10-26 14:35:56 +0100710 /* prepare data for parsing node content */
711 len += r + 1;
712 len += skip_ws(&data[len]);
713 if (data[len] != ':') {
714 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing name-separator)");
715 goto error;
716 }
717 len++;
718 len += skip_ws(&data[len]);
719
Radek Krejci88f29302015-10-30 15:42:33 +0100720 if (str[0] == '@' && !str[1]) {
721 /* process attribute of the parent object (container or list) */
722 if (!*parent) {
723 LOGVAL(LYE_XML_INVAL, lineno, "attribute with no corresponding element to belongs to");
724 goto error;
725 }
726
727 r = json_parse_attr((*parent)->schema->module, &attr, &data[len]);
728 if (!r) {
729 goto error;
730 }
731 len += r;
732
733 if ((*parent)->attr) {
734 lyd_free_attr(ctx, NULL, attr, 1);
735 } else {
736 (*parent)->attr = attr;
737 }
Radek Krejcic4831272015-11-01 19:26:34 +0100738 free(str);
739 return len;
Radek Krejci88f29302015-10-30 15:42:33 +0100740 }
741
Radek Krejci5449d472015-10-26 14:35:56 +0100742 /* find schema node */
743 if (!(*parent)) {
744 /* starting in root */
745 /* get the proper schema */
746 module = ly_ctx_get_module(ctx, prefix, NULL);
747 if (module) {
748 /* get the proper schema node */
749 LY_TREE_FOR(module->data, schema) {
750 if (!strcmp(schema->name, name)) {
751 break;
752 }
753 }
Radek Krejci88f29302015-10-30 15:42:33 +0100754 } else {
755 LOGVAL(LYE_INELEM, lineno, name);
756 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100757 }
758 } else {
759 /* parsing some internal node, we start with parent's schema pointer */
760 if (prefix) {
761 /* get the proper schema */
762 module = ly_ctx_get_module(ctx, prefix, NULL);
763 if (!module) {
764 LOGVAL(LYE_INELEM, lineno, name);
Radek Krejci88f29302015-10-30 15:42:33 +0100765 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100766 }
767 }
768 while ((schema = lys_getnext(schema, (*parent)->schema, module, 0))) {
769 if (!strcmp(schema->name, name)) {
770 break;
771 }
772 }
773 }
774 if (!schema) {
775 LOGVAL(LYE_INELEM, lineno, name);
Radek Krejci88f29302015-10-30 15:42:33 +0100776 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100777 }
Radek Krejci88f29302015-10-30 15:42:33 +0100778
779 if (str[0] == '@') {
Radek Krejci88f29302015-10-30 15:42:33 +0100780 /* attribute for some sibling node */
781 if (data[len] == '[') {
782 flag_leaflist = 1;
783 len++;
784 len += skip_ws(&data[len]);
785 }
786
787attr_repeat:
788 r = json_parse_attr(schema->module, &attr, &data[len]);
789 if (!r) {
790 goto error;
791 }
792 len += r;
793
794 if (attr) {
Radek Krejcic4831272015-11-01 19:26:34 +0100795 attrs_aux = malloc(sizeof *attrs_aux);
796 attrs_aux->attr = attr;
797 attrs_aux->index = flag_leaflist;
798 attrs_aux->schema = schema;
799 attrs_aux->next = *attrs;
800 *attrs = attrs_aux;
Radek Krejci88f29302015-10-30 15:42:33 +0100801 } else if (!flag_leaflist) {
802 /* error */
803 LOGVAL(LYE_XML_INVAL, lineno, "attribute data");
804 goto error;
805 }
806
807 if (flag_leaflist) {
808 if (data[len] == ',') {
809 len++;
810 len += skip_ws(&data[len]);
811 flag_leaflist++;
812 goto attr_repeat;
813 } else if (data[len] != ']') {
814 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-array)");
815 goto error;
816 }
817 len++;
818 len += skip_ws(&data[len]);
819 }
820
Radek Krejcic4831272015-11-01 19:26:34 +0100821 free(str);
822 return len;
Radek Krejci88f29302015-10-30 15:42:33 +0100823 }
824
Radek Krejci5449d472015-10-26 14:35:56 +0100825 switch (schema->nodetype) {
826 case LYS_CONTAINER:
827 case LYS_LIST:
828 case LYS_NOTIF:
829 case LYS_RPC:
830 result = calloc(1, sizeof *result);
831 break;
832 case LYS_LEAF:
833 case LYS_LEAFLIST:
834 result = calloc(1, sizeof(struct lyd_node_leaf_list));
835 break;
836 case LYS_ANYXML:
837 result = calloc(1, sizeof(struct lyd_node_anyxml));
838 break;
839 default:
840 LOGINT;
Radek Krejci595060f2015-10-30 16:29:58 +0100841 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100842 }
843 result->parent = *parent;
844 if (*parent && !(*parent)->child) {
845 (*parent)->child = result;
846 }
847 if (prev) {
848 result->prev = prev;
849 prev->next = result;
850
851 /* fix the "last" pointer */
852 for (diter = prev; diter->prev != prev; diter = diter->prev);
853 diter->prev = result;
854 } else {
855 result->prev = result;
856 }
857 result->schema = schema;
858
Radek Krejci23238922015-10-27 17:13:34 +0100859 if (lyv_data_context(result, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100860 goto error;
861 }
862
863 /* type specific processing */
864 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
865 /* type detection and assigning the value */
Radek Krejci23238922015-10-27 17:13:34 +0100866 r = json_get_value((struct lyd_node_leaf_list *)result, &data[len], options, unres);
Radek Krejci5449d472015-10-26 14:35:56 +0100867 if (!r) {
868 goto error;
869 }
Radek Krejci88f29302015-10-30 15:42:33 +0100870 while(result->next) {
871 result = result->next;
872 }
873
Radek Krejci5449d472015-10-26 14:35:56 +0100874 len += r;
875 len += skip_ws(&data[len]);
876 } else if (schema->nodetype == LYS_ANYXML) {
877 r = json_get_anyxml((struct lyd_node_anyxml *)result, &data[len]);
878 if (!r) {
879 goto error;
880 }
881 len += r;
882 len += skip_ws(&data[len]);
883 } else if (schema->nodetype == LYS_CONTAINER) {
884 if (data[len] != '{') {
885 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing begin-object)");
886 goto error;
887 }
888 len++;
889 len += skip_ws(&data[len]);
890
891 if (data[len] != '}') {
892 /* non-empty container */
Radek Krejcic4831272015-11-01 19:26:34 +0100893 len--;
894 diter = NULL;
895 attrs_aux = NULL;
896 do {
897 len++;
898 len += skip_ws(&data[len]);
899
900 r = json_parse_data(ctx, &data[len], &result, diter, &attrs_aux, options, unres);
901 if (!r) {
902 goto error;
903 }
904 len += r;
905
906 if (result->child) {
907 diter = result->child->prev;
908 }
909 } while(data[len] == ',');
910
911 /* store attributes */
912 if (store_attrs(ctx, attrs_aux, result->child)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100913 goto error;
914 }
Radek Krejci5449d472015-10-26 14:35:56 +0100915 }
916
917 if (data[len] != '}') {
918 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-object)");
919 goto error;
920 }
921 len++;
922 len += skip_ws(&data[len]);
923
924 } else if (schema->nodetype == LYS_LIST) {
925 if (data[len] != '[') {
926 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing begin-array)");
927 goto error;
928 }
929
930 list = result;
931 do {
932 len++;
933 len += skip_ws(&data[len]);
Radek Krejci23238922015-10-27 17:13:34 +0100934
935 if (options & LYD_OPT_FILTER) {
936 /* filter selection node ? */
937 if (data[len] == ']') {
938 break;
939 } else if (!strcmp(&data[len], "null")) {
940 len += 4;
941 len += skip_ws(&data[len]);
942 break;
943 }
944 }
945
Radek Krejcic4831272015-11-01 19:26:34 +0100946 if (data[len] != '{') {
947 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing list instance's begin-object)");
Radek Krejci5449d472015-10-26 14:35:56 +0100948 goto error;
949 }
Radek Krejcic4831272015-11-01 19:26:34 +0100950 diter = NULL;
951 attrs_aux = NULL;
952 do {
953 len++;
954 len += skip_ws(&data[len]);
955
956 r = json_parse_data(ctx, &data[len], &list, diter, &attrs_aux, options, unres);
957 if (!r) {
958 goto error;
959 }
960 len += r;
961
962 if (result->child) {
963 diter = list->child->prev;
964 }
965 } while(data[len] == ',');
966
967 /* store attributes */
968 if (store_attrs(ctx, attrs_aux, result->child)) {
969 goto error;
970 }
971
972 if (data[len] != '}') {
973 /* expecting end-object */
974 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing list instance's end-object)");
975 goto error;
976 }
977 len++;
Radek Krejci5449d472015-10-26 14:35:56 +0100978 len += skip_ws(&data[len]);
979
980 if (data[len] == ',') {
981 /* another instance of the list */
982 new = calloc(1, sizeof *new);
983 new->parent = list->parent;
984 new->prev = list;
985 list->next = new;
986
987 /* fix the "last" pointer */
988 for (diter = list; diter->prev != list; diter = diter->prev);
989 diter->prev = new;
990
991 new->schema = list->schema;
992
993 /* various validation checks */
994 ly_errno = 0;
Radek Krejci23238922015-10-27 17:13:34 +0100995 if (lyv_data_content(list, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100996 if (ly_errno) {
997 goto error;
998 }
999 }
1000 list = new;
1001 }
1002 } while (data[len] == ',');
1003 result = list;
1004
1005 if (data[len] != ']') {
1006 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-array)");
1007 goto error;
1008 }
1009 len++;
1010 len += skip_ws(&data[len]);
1011 }
1012
1013 /* various validation checks */
1014 ly_errno = 0;
Radek Krejci23238922015-10-27 17:13:34 +01001015 if (lyv_data_content(result, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +01001016 if (ly_errno) {
1017 goto error;
1018 }
1019 }
1020
Radek Krejci88f29302015-10-30 15:42:33 +01001021 if (!(*parent)) {
1022 *parent = result;
1023 }
1024
Radek Krejcide9d92c2015-10-30 15:59:59 +01001025 free(str);
Radek Krejci5449d472015-10-26 14:35:56 +01001026 return len;
1027
1028error:
Radek Krejci88f29302015-10-30 15:42:33 +01001029 if ((*parent) == result) {
1030 (*parent) = NULL;
1031 }
1032 while (*attrs) {
Radek Krejcic4831272015-11-01 19:26:34 +01001033 attrs_aux = *attrs;
Radek Krejci88f29302015-10-30 15:42:33 +01001034 *attrs = (*attrs)->next;
1035
Radek Krejcic4831272015-11-01 19:26:34 +01001036 lyd_free_attr(ctx, NULL, attrs_aux->attr, 1);
1037 free(attrs_aux);
Radek Krejci88f29302015-10-30 15:42:33 +01001038 }
1039
Radek Krejci5449d472015-10-26 14:35:56 +01001040 lyd_free(result);
Radek Krejci88f29302015-10-30 15:42:33 +01001041 free(str);
1042
Radek Krejci5449d472015-10-26 14:35:56 +01001043 return 0;
1044}
1045
1046struct lyd_node *
1047lyd_parse_json(struct ly_ctx *ctx, const char *data, int options)
1048{
Radek Krejcic4831272015-11-01 19:26:34 +01001049 struct lyd_node *result = NULL, *next = NULL, *iter = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +01001050 struct unres_data *unres = NULL;
Radek Krejcic4831272015-11-01 19:26:34 +01001051 unsigned int len = 0, r;
1052 struct attr_cont *attrs = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +01001053
1054 if (!ctx || !data) {
1055 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
1056 return NULL;
1057 }
1058
1059 unres = calloc(1, sizeof *unres);
1060
1061#ifndef NDEBUG
1062 lineno = 0;
1063#endif
1064 ly_errno = 0;
Radek Krejcic4831272015-11-01 19:26:34 +01001065
1066 /* skip leading whitespaces */
1067 len += skip_ws(&data[len]);
1068
1069 /* expect top-level { */
1070 if (data[len] != '{') {
1071 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing top level begin-object)");
1072 goto cleanup;
1073 }
1074
1075 do {
1076 len++;
1077 len += skip_ws(&data[len]);
1078
1079 r =json_parse_data(ctx, &data[len], &next, iter, &attrs, options, unres);
1080 if (!r) {
1081 result = NULL;
1082 goto cleanup;
1083 }
1084 len += r;
1085
1086 if (!result) {
1087 result = next;
1088 }
1089 if (next) {
1090 iter = next;
1091 }
1092 next = NULL;
1093 } while(data[len] == ',');
1094
1095 if (data[len] != '}') {
1096 /* expecting end-object */
1097 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing top-level end-object)");
1098 LY_TREE_FOR_SAFE(result, next, iter) {
1099 lyd_free(iter);
1100 }
1101 result = NULL;
1102 goto cleanup;
1103 }
1104 len++;
1105 len += skip_ws(&data[len]);
1106
1107 /* store attributes */
1108 if (store_attrs(ctx, attrs, result)) {
1109 LY_TREE_FOR_SAFE(result, next, iter) {
1110 lyd_free(iter);
1111 }
1112 result = NULL;
1113 goto cleanup;
1114 }
Radek Krejci5449d472015-10-26 14:35:56 +01001115
1116 /* check leafrefs and/or instids if any */
1117 if (result && resolve_unres_data(unres)) {
1118 /* leafref & instid checking failed */
Radek Krejcic4831272015-11-01 19:26:34 +01001119 LY_TREE_FOR_SAFE(result, next, iter) {
Radek Krejci5449d472015-10-26 14:35:56 +01001120 lyd_free(iter);
1121 }
1122 result = NULL;
1123 }
1124
Radek Krejcic4831272015-11-01 19:26:34 +01001125cleanup:
Radek Krejci5449d472015-10-26 14:35:56 +01001126 free(unres->node);
1127 free(unres->type);
1128#ifndef NDEBUG
1129 free(unres->line);
1130#endif
1131 free(unres);
1132
1133 return result;
1134}