blob: 20ac4d6670c2ece8810d21b74f9bdd29fba38ece [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
608static unsigned int
Radek Krejci5449d472015-10-26 14:35:56 +0100609json_parse_data(struct ly_ctx *ctx, const char *data, struct lyd_node **parent, struct lyd_node *prev,
Radek Krejci88f29302015-10-30 15:42:33 +0100610 struct attr_cont **attrs, int options, struct unres_data *unres)
Radek Krejci5449d472015-10-26 14:35:56 +0100611{
612 unsigned int len = 0;
613 unsigned int r;
Radek Krejci88f29302015-10-30 15:42:33 +0100614 unsigned int flag_object = 0, flag_leaflist = 0;
615 char *name, *prefix = NULL, *str = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +0100616 struct lys_module *module = NULL;
617 struct lys_node *schema = NULL;
618 struct lyd_node *result = NULL, *new, *list, *diter = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100619 struct lyd_attr *attr;
620 struct attr_cont *attrs_new, *attrs_start = NULL;
621
622 if (!attrs) {
623 attrs = &attrs_start;
624 }
Radek Krejci5449d472015-10-26 14:35:56 +0100625
626 /* skip leading whitespaces */
627 len += skip_ws(&data[len]);
628
629 /* skip top-level { if any */
630 if (data[len] == '{') {
631 flag_object = 1;
632 len++;
633 len += skip_ws(&data[len]);
634 }
635
636 /* each YANG data node representation starts with string (node identifier) */
637 if (data[len] != '"') {
Radek Krejci88f29302015-10-30 15:42:33 +0100638 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the beginning of string)");
639 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100640 }
641 len++;
642
Radek Krejci23238922015-10-27 17:13:34 +0100643 str = lyjson_parse_text(&data[len], &r);
Radek Krejci5449d472015-10-26 14:35:56 +0100644 if (!r) {
645 goto error;
646 } else if (data[len + r] != '"') {
647 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
648 goto error;
649 }
Radek Krejci23238922015-10-27 17:13:34 +0100650 if ((name = strchr(str, ':'))) {
651 *name = '\0';
652 name++;
653 prefix = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100654 if (prefix[0] == '@') {
655 prefix++;
656 }
Radek Krejci23238922015-10-27 17:13:34 +0100657 } else {
658 name = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100659 if (name[0] == '@') {
660 name++;
661 }
Radek Krejci5449d472015-10-26 14:35:56 +0100662 }
663
Radek Krejci5449d472015-10-26 14:35:56 +0100664 /* prepare data for parsing node content */
665 len += r + 1;
666 len += skip_ws(&data[len]);
667 if (data[len] != ':') {
668 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing name-separator)");
669 goto error;
670 }
671 len++;
672 len += skip_ws(&data[len]);
673
Radek Krejci88f29302015-10-30 15:42:33 +0100674 if (str[0] == '@' && !str[1]) {
675 /* process attribute of the parent object (container or list) */
676 if (!*parent) {
677 LOGVAL(LYE_XML_INVAL, lineno, "attribute with no corresponding element to belongs to");
678 goto error;
679 }
680
681 r = json_parse_attr((*parent)->schema->module, &attr, &data[len]);
682 if (!r) {
683 goto error;
684 }
685 len += r;
686
687 if ((*parent)->attr) {
688 lyd_free_attr(ctx, NULL, attr, 1);
689 } else {
690 (*parent)->attr = attr;
691 }
692 result = prev;
693 goto siblings;
694 }
695
Radek Krejci5449d472015-10-26 14:35:56 +0100696 /* find schema node */
697 if (!(*parent)) {
698 /* starting in root */
699 /* get the proper schema */
700 module = ly_ctx_get_module(ctx, prefix, NULL);
701 if (module) {
702 /* get the proper schema node */
703 LY_TREE_FOR(module->data, schema) {
704 if (!strcmp(schema->name, name)) {
705 break;
706 }
707 }
Radek Krejci88f29302015-10-30 15:42:33 +0100708 } else {
709 LOGVAL(LYE_INELEM, lineno, name);
710 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100711 }
712 } else {
713 /* parsing some internal node, we start with parent's schema pointer */
714 if (prefix) {
715 /* get the proper schema */
716 module = ly_ctx_get_module(ctx, prefix, NULL);
717 if (!module) {
718 LOGVAL(LYE_INELEM, lineno, name);
Radek Krejci88f29302015-10-30 15:42:33 +0100719 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100720 }
721 }
722 while ((schema = lys_getnext(schema, (*parent)->schema, module, 0))) {
723 if (!strcmp(schema->name, name)) {
724 break;
725 }
726 }
727 }
728 if (!schema) {
729 LOGVAL(LYE_INELEM, lineno, name);
Radek Krejci88f29302015-10-30 15:42:33 +0100730 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100731 }
Radek Krejci88f29302015-10-30 15:42:33 +0100732
733 if (str[0] == '@') {
Radek Krejci88f29302015-10-30 15:42:33 +0100734 /* attribute for some sibling node */
735 if (data[len] == '[') {
736 flag_leaflist = 1;
737 len++;
738 len += skip_ws(&data[len]);
739 }
740
741attr_repeat:
742 r = json_parse_attr(schema->module, &attr, &data[len]);
743 if (!r) {
744 goto error;
745 }
746 len += r;
747
748 if (attr) {
749 attrs_new = malloc(sizeof *attrs_new);
750 attrs_new->attr = attr;
751 attrs_new->index = flag_leaflist;
752 attrs_new->schema = schema;
753 attrs_new->next = *attrs;
754 *attrs = attrs_new;
755 } else if (!flag_leaflist) {
756 /* error */
757 LOGVAL(LYE_XML_INVAL, lineno, "attribute data");
758 goto error;
759 }
760
761 if (flag_leaflist) {
762 if (data[len] == ',') {
763 len++;
764 len += skip_ws(&data[len]);
765 flag_leaflist++;
766 goto attr_repeat;
767 } else if (data[len] != ']') {
768 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-array)");
769 goto error;
770 }
771 len++;
772 len += skip_ws(&data[len]);
773 }
774
775 result = prev;
776 goto siblings;
777 }
778
Radek Krejci5449d472015-10-26 14:35:56 +0100779 switch (schema->nodetype) {
780 case LYS_CONTAINER:
781 case LYS_LIST:
782 case LYS_NOTIF:
783 case LYS_RPC:
784 result = calloc(1, sizeof *result);
785 break;
786 case LYS_LEAF:
787 case LYS_LEAFLIST:
788 result = calloc(1, sizeof(struct lyd_node_leaf_list));
789 break;
790 case LYS_ANYXML:
791 result = calloc(1, sizeof(struct lyd_node_anyxml));
792 break;
793 default:
794 LOGINT;
795 return 0;
796 }
797 result->parent = *parent;
798 if (*parent && !(*parent)->child) {
799 (*parent)->child = result;
800 }
801 if (prev) {
802 result->prev = prev;
803 prev->next = result;
804
805 /* fix the "last" pointer */
806 for (diter = prev; diter->prev != prev; diter = diter->prev);
807 diter->prev = result;
808 } else {
809 result->prev = result;
810 }
811 result->schema = schema;
812
Radek Krejci23238922015-10-27 17:13:34 +0100813 if (lyv_data_context(result, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100814 goto error;
815 }
816
817 /* type specific processing */
818 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
819 /* type detection and assigning the value */
Radek Krejci23238922015-10-27 17:13:34 +0100820 r = json_get_value((struct lyd_node_leaf_list *)result, &data[len], options, unres);
Radek Krejci5449d472015-10-26 14:35:56 +0100821 if (!r) {
822 goto error;
823 }
Radek Krejci88f29302015-10-30 15:42:33 +0100824 while(result->next) {
825 result = result->next;
826 }
827
Radek Krejci5449d472015-10-26 14:35:56 +0100828 len += r;
829 len += skip_ws(&data[len]);
830 } else if (schema->nodetype == LYS_ANYXML) {
831 r = json_get_anyxml((struct lyd_node_anyxml *)result, &data[len]);
832 if (!r) {
833 goto error;
834 }
835 len += r;
836 len += skip_ws(&data[len]);
837 } else if (schema->nodetype == LYS_CONTAINER) {
838 if (data[len] != '{') {
839 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing begin-object)");
840 goto error;
841 }
842 len++;
843 len += skip_ws(&data[len]);
844
845 if (data[len] != '}') {
846 /* non-empty container */
Radek Krejci88f29302015-10-30 15:42:33 +0100847 r = json_parse_data(ctx, &data[len], &result, NULL, NULL, options, unres);
Radek Krejci5449d472015-10-26 14:35:56 +0100848 if (!r) {
849 goto error;
850 }
851 len += r;
852 }
853
854 if (data[len] != '}') {
855 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-object)");
856 goto error;
857 }
858 len++;
859 len += skip_ws(&data[len]);
860
861 } else if (schema->nodetype == LYS_LIST) {
862 if (data[len] != '[') {
863 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing begin-array)");
864 goto error;
865 }
866
867 list = result;
868 do {
869 len++;
870 len += skip_ws(&data[len]);
Radek Krejci23238922015-10-27 17:13:34 +0100871
872 if (options & LYD_OPT_FILTER) {
873 /* filter selection node ? */
874 if (data[len] == ']') {
875 break;
876 } else if (!strcmp(&data[len], "null")) {
877 len += 4;
878 len += skip_ws(&data[len]);
879 break;
880 }
881 }
882
Radek Krejci88f29302015-10-30 15:42:33 +0100883 r = json_parse_data(ctx, &data[len], &list, NULL, NULL, options, unres);
Radek Krejci5449d472015-10-26 14:35:56 +0100884 if (!r) {
885 goto error;
886 }
887 len += r;
888 len += skip_ws(&data[len]);
889
890 if (data[len] == ',') {
891 /* another instance of the list */
892 new = calloc(1, sizeof *new);
893 new->parent = list->parent;
894 new->prev = list;
895 list->next = new;
896
897 /* fix the "last" pointer */
898 for (diter = list; diter->prev != list; diter = diter->prev);
899 diter->prev = new;
900
901 new->schema = list->schema;
902
903 /* various validation checks */
904 ly_errno = 0;
Radek Krejci23238922015-10-27 17:13:34 +0100905 if (lyv_data_content(list, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100906 if (ly_errno) {
907 goto error;
908 }
909 }
910 list = new;
911 }
912 } while (data[len] == ',');
913 result = list;
914
915 if (data[len] != ']') {
916 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-array)");
917 goto error;
918 }
919 len++;
920 len += skip_ws(&data[len]);
921 }
922
923 /* various validation checks */
924 ly_errno = 0;
Radek Krejci23238922015-10-27 17:13:34 +0100925 if (lyv_data_content(result, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100926 if (ly_errno) {
927 goto error;
928 }
929 }
930
Radek Krejci88f29302015-10-30 15:42:33 +0100931 if (!(*parent)) {
932 *parent = result;
933 }
934
935siblings:
Radek Krejci5449d472015-10-26 14:35:56 +0100936 /* process siblings */
937 if (data[len] && data[len] == ',') {
938 /* have siblings */
939 len++;
940 len += skip_ws(&data[len]);
941
Radek Krejci88f29302015-10-30 15:42:33 +0100942 r = json_parse_data(ctx, &data[len], parent, result, attrs, options, unres);
Radek Krejci5449d472015-10-26 14:35:56 +0100943 if (!r) {
944 goto error;
945 }
946
947 len += r;
948 } else {
949 len += skip_ws(&data[len]);
950 }
951
Radek Krejci88f29302015-10-30 15:42:33 +0100952 if (!prev) {
953 /* first sibling - now process the sibling attributes since there must be a node for them */
954 while (*attrs) {
955 attrs_new = *attrs;
956 *attrs = (*attrs)->next;
957
958 if (attrs_new->index) {
959 flag_leaflist = 1;
960 }
961
962 LY_TREE_FOR(result, diter) {
963 if (attrs_new->schema != diter->schema) {
964 continue;
965 }
966
967 if (flag_leaflist && flag_leaflist != attrs_new->index) {
968 flag_leaflist++;
969 continue;
970 }
971
972 /* we have match */
973 if (diter->attr) {
974 LOGVAL(LYE_XML_INVAL, lineno, "attribute (multiple attribute definitions belong to a single element)");
975 free(attrs_new);
976 goto error;
977 }
978
979 diter->attr = attrs_new->attr;
980 break;
981 }
982
983 if (!diter) {
984 LOGVAL(LYE_XML_INVAL, lineno, "attribute with no corresponding element to belongs to");
985 lyd_free_attr(attrs_new->schema->module->ctx, NULL, attrs_new->attr, 1);
986 free(attrs_new);
987 goto error;
988 }
989 free(attrs_new);
990 }
991 }
992
Radek Krejci5449d472015-10-26 14:35:56 +0100993 if (flag_object) {
994 if (data[len] != '}') {
995 /* expecting end-object */
996 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-object)");
997 goto error;
998 }
999 len++;
1000 len += skip_ws(&data[len]);
1001 }
1002
Radek Krejcide9d92c2015-10-30 15:59:59 +01001003 free(str);
Radek Krejci5449d472015-10-26 14:35:56 +01001004 return len;
1005
1006error:
Radek Krejci88f29302015-10-30 15:42:33 +01001007 if ((*parent) == result) {
1008 (*parent) = NULL;
1009 }
1010 while (*attrs) {
1011 attrs_new = *attrs;
1012 *attrs = (*attrs)->next;
1013
1014 lyd_free_attr(ctx, NULL, attrs_new->attr, 1);
1015 free(attrs_new);
1016 }
1017
Radek Krejci5449d472015-10-26 14:35:56 +01001018 lyd_free(result);
Radek Krejci88f29302015-10-30 15:42:33 +01001019 free(str);
1020
Radek Krejci5449d472015-10-26 14:35:56 +01001021 return 0;
1022}
1023
1024struct lyd_node *
1025lyd_parse_json(struct ly_ctx *ctx, const char *data, int options)
1026{
1027 struct lyd_node *result, *next, *iter;
1028 struct unres_data *unres = NULL;
1029
1030 if (!ctx || !data) {
1031 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
1032 return NULL;
1033 }
1034
1035 unres = calloc(1, sizeof *unres);
1036
1037#ifndef NDEBUG
1038 lineno = 0;
1039#endif
1040 ly_errno = 0;
1041 result = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +01001042 json_parse_data(ctx, data, &result, NULL, NULL, options, unres);
Radek Krejci5449d472015-10-26 14:35:56 +01001043
1044 /* check leafrefs and/or instids if any */
1045 if (result && resolve_unres_data(unres)) {
1046 /* leafref & instid checking failed */
1047 LY_TREE_FOR_SAFE(result, next, iter)
1048 {
1049 lyd_free(iter);
1050 }
1051 result = NULL;
1052 }
1053
1054 free(unres->node);
1055 free(unres->type);
1056#ifndef NDEBUG
1057 free(unres->line);
1058#endif
1059 free(unres);
1060
1061 return result;
1062}