blob: 85766a16c7b04732ac7f6ebd75d7c56e88f4b887 [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
Radek Krejci5449d472015-10-26 14:35:56 +010066static char *
67lyjson_parse_text(const char *data, unsigned int *len)
68{
69#define BUFSIZE 1024
70
71 char buf[BUFSIZE];
72 char *result = NULL, *aux;
Radek Krejci967e4bf2015-11-28 10:06:40 +010073 int o, size = 0;
Radek Krejci5449d472015-10-26 14:35:56 +010074 unsigned int r, i;
75 int32_t value;
76
77 for (*len = o = 0; data[*len] && data[*len] != '"'; o++) {
78 if (o > BUFSIZE - 3) {
79 /* add buffer into the result */
80 if (result) {
81 size = size + o;
Michal Vasko253035f2015-12-17 16:58:13 +010082 aux = ly_realloc(result, size + 1);
83 if (!aux) {
84 LOGMEM;
85 return NULL;
86 }
Radek Krejci5449d472015-10-26 14:35:56 +010087 result = aux;
88 } else {
89 size = o;
90 result = malloc((size + 1) * sizeof *result);
Michal Vasko253035f2015-12-17 16:58:13 +010091 if (!result) {
92 LOGMEM;
93 return NULL;
94 }
Radek Krejci5449d472015-10-26 14:35:56 +010095 }
96 memcpy(&result[size - o], buf, o);
97
98 /* write again into the beginning of the buffer */
99 o = 0;
100 }
101
102 if (data[*len] == '\\') {
103 /* parse escape sequence */
104 (*len)++;
105 i = 1;
106 switch (data[(*len)]) {
107 case '"':
108 /* quotation mark */
109 value = 0x22;
110 break;
111 case '\\':
112 /* reverse solidus */
113 value = 0x5c;
114 break;
115 case '/':
116 /* solidus */
117 value = 0x2f;
118 break;
119 case 'b':
120 /* backspace */
121 value = 0x08;
122 break;
123 case 'f':
124 /* form feed */
125 value = 0x0c;
126 break;
127 case 'n':
128 /* line feed */
129 value = 0x0a;
130 break;
131 case 'r':
132 /* carriage return */
133 value = 0x0d;
134 break;
135 case 't':
136 /* tab */
137 value = 0x09;
138 break;
139 case 'u':
140 /* Basic Multilingual Plane character \uXXXX */
141 (*len)++;
142 for (value = i = 0; i < 4; i++) {
143 if (isdigit(data[(*len) + i])) {
144 r = (data[(*len) + i] - '0');
145 } else if (data[(*len) + i] > 'F') {
146 r = 10 + (data[(*len) + i] - 'a');
147 } else {
148 r = 10 + (data[(*len) + i] - 'A');
149 }
150 value = (16 * value) + r;
151 }
152 break;
153 default:
154 /* invalid escape sequence */
155 LOGVAL(LYE_XML_INVAL, lineno, "character escape sequence");
156 goto error;
157
158 }
159 r = pututf8(&buf[o], value, lineno);
160 if (!r) {
161 LOGVAL(LYE_XML_INVAL, lineno, "character UTF8 character");
162 goto error;
163 }
164 o += r - 1; /* o is ++ in for loop */
165 (*len) += i; /* number of read characters */
166 } else if (data[*len] < 0x20 || data[*len] == 0x5c) {
167 /* control characters must be escaped */
168 LOGVAL(LYE_XML_INVAL, lineno, "control character (unescaped)");
169 goto error;
170 } else {
171 /* unescaped character */
172 buf[o] = data[*len];
173 COUNTLINE(buf[o]);
174 (*len)++;
175 }
176 }
177
178#undef BUFSIZE
179
180 if (o) {
181 if (result) {
182 size = size + o;
Michal Vasko253035f2015-12-17 16:58:13 +0100183 aux = ly_realloc(result, size + 1);
184 if (!aux) {
185 LOGMEM;
186 return NULL;
187 }
Radek Krejci5449d472015-10-26 14:35:56 +0100188 result = aux;
189 } else {
190 size = o;
191 result = malloc((size + 1) * sizeof *result);
Michal Vasko253035f2015-12-17 16:58:13 +0100192 if (!result) {
193 LOGMEM;
194 return NULL;
195 }
Radek Krejci5449d472015-10-26 14:35:56 +0100196 }
197 memcpy(&result[size - o], buf, o);
198 }
199 if (result) {
200 result[size] = '\0';
201 } else {
202 size = 0;
203 result = strdup("");
204 }
205
206 return result;
207
208error:
209 free(result);
210 return NULL;
211}
212
213static unsigned int
214lyjson_parse_number(const char *data)
215{
216 unsigned int len;
217 unsigned int i = 0;
218
219 for (len = 0;
220 data[len] && data[len] != ',' && data[len] != ']' && data[len] != '}' && !lyjson_isspace(data[len]);
221 len++) {
222
223 switch(data[len]) {
224 case '0':
Radek Krejci88f29302015-10-30 15:42:33 +0100225 if (!i && isdigit(data[len + 1])) {
Radek Krejci5449d472015-10-26 14:35:56 +0100226 /* leading 0 is not allowed */
227 LOGVAL(LYE_XML_INVAL, lineno, "JSON number (leading zero)");
228 return 0;
229 }
230 /* no break */
231 case '1':
232 case '2':
233 case '3':
234 case '4':
235 case '5':
236 case '6':
237 case '7':
238 case '8':
239 case '9':
240 i = 1;
241 /* no break */
242 case 0x2d: /* minus */
243 /* ok */
244 break;
245 default:
246 LOGVAL(LYE_XML_INVAL, lineno, "character in JSON Number value");
247 return 0;
248 }
249 }
250
251 return len;
252}
253
254static unsigned int
255lyjson_parse_boolean(const char *data)
256{
Radek Krejci6b47b502015-10-30 15:52:41 +0100257 unsigned int len = 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100258
259 if (!strncmp(data, "false", 5)) {
260 len = 5;
261 } else if (!strncmp(data, "true", 4)) {
262 len = 4;
263 }
264
265 if (data[len] && data[len] != ',' && data[len] != ']' && data[len] != '}' && !lyjson_isspace(data[len])) {
266 LOGVAL(LYE_XML_INVAL, lineno, "JSON literal value (expected true or false)");
267 return 0;
268 }
269
270 return len;
271}
272
273static unsigned int
274json_get_anyxml(struct lyd_node_anyxml *axml, const char *data)
275{
276 unsigned int len = 0;
277 char stop, start;
278 int level = 0;
279
280 switch (data[len]) {
281 case '"':
282 start = 0;
283 stop = '"';
284 level = 1;
285 break;
286 case '[':
287 start = '[';
288 stop = ']';
289 break;
290 case '{':
291 start = '{';
292 stop = '}';
293 break;
294 default:
295 /* number or one of literals */
296 while (!isspace(data[len])) {
297 len++;
298 }
299 axml->value = NULL; /* TODO ??? */
300 return len;
301 }
302
303 while (data[len]) {
304 if (start && data[len] == start) {
305 if (!len || data[len - 1] != '\\') {
306 level++;
307 }
308 } else if (data[len] == stop) {
309 if (!len || data[len - 1] != '\\') {
310 level--;
311 }
312 }
313 stop = len;
314 len++;
315 if (!level) {
316 /* we are done */
317 axml->value = NULL; /* TODO ??? */
318 return len;
319 }
320 }
321
322 return 0;
323}
324
325static unsigned int
Radek Krejci23238922015-10-27 17:13:34 +0100326json_get_value(struct lyd_node_leaf_list *leaf, const char *data, int options, struct unres_data *unres)
Radek Krejci5449d472015-10-26 14:35:56 +0100327{
328 struct lyd_node_leaf_list *new, *diter;
Radek Krejci37b756f2016-01-18 10:15:03 +0100329 struct lys_type *stype;
Radek Krejci5449d472015-10-26 14:35:56 +0100330 struct ly_ctx *ctx;
331 unsigned int len = 0, r;
Radek Krejci37b756f2016-01-18 10:15:03 +0100332 int resolve;
Radek Krejci5449d472015-10-26 14:35:56 +0100333 char *str;
334
335 assert(leaf && data && unres);
336 ctx = leaf->schema->module->ctx;
337
Radek Krejci20cdf632015-11-09 14:44:58 +0100338 if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
Radek Krejci23238922015-10-27 17:13:34 +0100339 resolve = 0;
340 } else {
341 resolve = 1;
342 }
343
Radek Krejci5449d472015-10-26 14:35:56 +0100344 stype = &((struct lys_node_leaf *)leaf->schema)->type;
Radek Krejci23238922015-10-27 17:13:34 +0100345
346 if (options & LYD_OPT_FILTER) {
347 /* no value in filter (selection) node is accepted in this case */
348 if (!strncmp(&data[len], "null", 4)) {
349 leaf->value_type = stype->base;
350 len +=4;
351 goto end;
352 }
353 }
354
Radek Krejci5449d472015-10-26 14:35:56 +0100355 if (leaf->schema->nodetype == LYS_LEAFLIST) {
356 /* expecting begin-array */
357 if (data[len++] != '[') {
358 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (expected begin-array)");
359 return 0;
360 }
361
362repeat:
363 len += skip_ws(&data[len]);
364 }
365
366 /* will be changed in case of union */
367 leaf->value_type = stype->base;
368
369 if (data[len] == '"') {
370 /* string representations */
371 if (data[len++] != '"') {
372 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the beginning of string)");
373 return 0;
374 }
375 str = lyjson_parse_text(&data[len], &r);
Radek Krejci23238922015-10-27 17:13:34 +0100376 if (!str) {
Radek Krejci5449d472015-10-26 14:35:56 +0100377 return 0;
378 }
379 leaf->value_str = lydict_insert_zc(ctx, str);
380 if (data[len + r] != '"') {
381 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
382 return 0;
383 }
384 len += r + 1;
385 } else if (data[len] == '-' || isdigit(data[len])) {
386 /* numeric type */
387 r = lyjson_parse_number(&data[len]);
388 if (!r) {
389 return 0;
390 }
391 leaf->value_str = lydict_insert(ctx, &data[len], r);
392 len += r;
393 } else if (data[len] == 'f' || data[len] == 't') {
394 /* boolean */
395 r = lyjson_parse_boolean(&data[len]);
396 if (!r) {
397 return 0;
398 }
399 leaf->value_str = lydict_insert(ctx, &data[len], r);
400 len += r;
401 } else if (!strncmp(&data[len], "[null]", 6)) {
402 /* empty */
403 leaf->value_str = NULL;
404 len += 6;
405 } else {
406 /* error */
407 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (unexpected value)");
408 return 0;
409 }
410
Radek Krejci37b756f2016-01-18 10:15:03 +0100411 if (lyp_parse_value(leaf, NULL, resolve, unres, lineno)) {
Radek Krejci23238922015-10-27 17:13:34 +0100412 ly_errno = LY_EVALID;
413 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100414 }
415
416 if (leaf->schema->nodetype == LYS_LEAFLIST) {
417 /* repeat until end-array */
418 len += skip_ws(&data[len]);
419 if (data[len] == ',') {
420 /* another instance of the leaf-list */
421 new = calloc(1, sizeof(struct lyd_node_leaf_list));
Michal Vasko253035f2015-12-17 16:58:13 +0100422 if (!new) {
423 LOGMEM;
424 return 0;
425 }
Radek Krejci5449d472015-10-26 14:35:56 +0100426 new->parent = leaf->parent;
427 new->prev = (struct lyd_node *)leaf;
428 leaf->next = (struct lyd_node *)new;
429
430 /* fix the "last" pointer */
431 for (diter = leaf; diter->prev != (struct lyd_node *)leaf; diter = (struct lyd_node_leaf_list *)diter->prev);
432 diter->prev = (struct lyd_node *)new;
433
434 new->schema = leaf->schema;
435
436 /* repeat value parsing */
437 leaf = new;
438 len++;
439 goto repeat;
440 } else if (data[len] == ']') {
441 len++;
442 len += skip_ws(&data[len]);
443 } else {
444 /* something unexpected */
445 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (expecting value-separator or end-array)");
446 return 0;
447 }
448 }
449
Radek Krejci23238922015-10-27 17:13:34 +0100450end:
Radek Krejci5449d472015-10-26 14:35:56 +0100451 len += skip_ws(&data[len]);
452 return len;
453}
454
455static unsigned int
Radek Krejci88f29302015-10-30 15:42:33 +0100456json_parse_attr(struct lys_module *parent_module, struct lyd_attr **attr, const char *data)
457{
458 unsigned int len = 0, r;
459 char *str = NULL, *name, *prefix, *value;
460 struct lys_module *module = parent_module;
461 struct lyd_attr *attr_new, *attr_last = NULL;
462
Radek Krejcide9d92c2015-10-30 15:59:59 +0100463 *attr = NULL;
464
Radek Krejci88f29302015-10-30 15:42:33 +0100465 if (data[len] != '{') {
466 if (!strncmp(&data[len], "null", 4)) {
Radek Krejci88f29302015-10-30 15:42:33 +0100467 len += 4;
468 len += skip_ws(&data[len]);
469 return len;
470 }
471 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing begin-object)");
472 goto error;
473 }
474
475repeat:
476 len++;
477 len += skip_ws(&data[len]);
478
479 if (data[len] != '"') {
480 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the begining of string)");
481 return 0;
482 }
483 len++;
484 str = lyjson_parse_text(&data[len], &r);
485 if (!r) {
486 goto error;
487 } else if (data[len + r] != '"') {
488 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
489 goto error;
490 }
491 if ((name = strchr(str, ':'))) {
492 *name = '\0';
493 name++;
494 prefix = str;
Michal Vasko1e62a092015-12-01 12:27:20 +0100495 module = (struct lys_module *)ly_ctx_get_module(parent_module->ctx, prefix, NULL);
Radek Krejci88f29302015-10-30 15:42:33 +0100496 if (!module) {
497 LOGVAL(LYE_INELEM, lineno, name);
498 goto error;
499 }
500 } else {
501 name = str;
502 }
503
504 /* prepare data for parsing node content */
505 len += r + 1;
506 len += skip_ws(&data[len]);
507 if (data[len] != ':') {
508 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing name-separator)");
509 goto error;
510 }
511 len++;
512 len += skip_ws(&data[len]);
513
514 if (data[len] != '"') {
515 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the beginning of string)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100516 goto error;
Radek Krejci88f29302015-10-30 15:42:33 +0100517 }
518 len++;
519 value = lyjson_parse_text(&data[len], &r);
520 if (!r) {
521 goto error;
522 } else if (data[len + r] != '"') {
523 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100524 free(value);
Radek Krejci88f29302015-10-30 15:42:33 +0100525 goto error;
526 }
527 len += r + 1;
528 len += skip_ws(&data[len]);
529
530 attr_new = malloc(sizeof **attr);
Michal Vasko253035f2015-12-17 16:58:13 +0100531 if (!attr_new) {
532 LOGMEM;
533 goto error;
534 }
Radek Krejci88f29302015-10-30 15:42:33 +0100535 attr_new->module = module;
536 attr_new->next = NULL;
537 attr_new->name = lydict_insert(module->ctx, name, 0);
538 attr_new->value = lydict_insert_zc(module->ctx, value);
539 if (!attr_last) {
540 *attr = attr_last = attr_new;
541 } else {
542 attr_last->next = attr_new;
543 attr_last = attr_new;
544 }
545
546 free(str);
Radek Krejcide9d92c2015-10-30 15:59:59 +0100547 str = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100548
549 if (data[len] == ',') {
550 goto repeat;
551 } else if (data[len] != '}') {
552 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-object)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100553 goto error;
Radek Krejci88f29302015-10-30 15:42:33 +0100554 }
555 len++;
556 len += skip_ws(&data[len]);
557
558 return len;
559
560error:
561 free(str);
Radek Krejcide9d92c2015-10-30 15:59:59 +0100562 if (*attr) {
563 lyd_free_attr((*attr)->module->ctx, NULL, *attr, 1);
564 *attr = NULL;
565 }
Radek Krejci88f29302015-10-30 15:42:33 +0100566 return 0;
567}
568
569struct attr_cont {
570 struct attr_cont *next;
571 struct lyd_attr *attr;
572 struct lys_node *schema;
573 unsigned int index; /** non-zero only in case of leaf-list */
574};
575
Radek Krejcic4831272015-11-01 19:26:34 +0100576static int
577store_attrs(struct ly_ctx *ctx, struct attr_cont *attrs, struct lyd_node *first)
578{
579 struct lyd_node *diter;
580 struct attr_cont *iter;
581 unsigned int flag_leaflist = 0;
582
583 while (attrs) {
584 iter = attrs;
585 attrs = attrs->next;
586
587 if (iter->index) {
588 flag_leaflist = 1;
589 }
590
591 LY_TREE_FOR(first, diter) {
592 if (iter->schema != diter->schema) {
593 continue;
594 }
595
596 if (flag_leaflist && flag_leaflist != iter->index) {
597 flag_leaflist++;
598 continue;
599 }
600
601 /* we have match */
602 if (diter->attr) {
603 LOGVAL(LYE_XML_INVAL, lineno, "attribute (multiple attribute definitions belong to a single element)");
604 free(iter);
605 goto error;
606 }
607
608 diter->attr = iter->attr;
609 break;
610 }
611
612 if (!diter) {
613 LOGVAL(LYE_XML_INVAL, lineno, "attribute with no corresponding element to belongs to");
614 lyd_free_attr(iter->schema->module->ctx, NULL, iter->attr, 1);
615 free(iter);
616 goto error;
617 }
618 free(iter);
619 }
620
621 return 0;
622
623error:
624
625 while (attrs) {
626 iter = attrs;
627 attrs = attrs->next;
628
629 lyd_free_attr(ctx, NULL, iter->attr, 1);
630 free(iter);
631 }
632
633 return -1;
634}
635
Radek Krejci88f29302015-10-30 15:42:33 +0100636static unsigned int
Michal Vasko36ef6932015-12-01 14:30:17 +0100637json_parse_data(struct ly_ctx *ctx, const char *data, const struct lys_node *schema_parent, struct lyd_node **parent,
638 struct lyd_node *prev, struct attr_cont **attrs, int options, struct unres_data *unres)
Radek Krejci5449d472015-10-26 14:35:56 +0100639{
640 unsigned int len = 0;
641 unsigned int r;
Radek Krejcic4831272015-11-01 19:26:34 +0100642 unsigned int flag_leaflist = 0;
Radek Krejci88f29302015-10-30 15:42:33 +0100643 char *name, *prefix = NULL, *str = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +0100644 const struct lys_module *module = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +0100645 struct lys_node *schema = NULL;
646 struct lyd_node *result = NULL, *new, *list, *diter = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100647 struct lyd_attr *attr;
Radek Krejcic4831272015-11-01 19:26:34 +0100648 struct attr_cont *attrs_aux;
Radek Krejci5449d472015-10-26 14:35:56 +0100649
650 /* each YANG data node representation starts with string (node identifier) */
651 if (data[len] != '"') {
Radek Krejci88f29302015-10-30 15:42:33 +0100652 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the beginning of string)");
653 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100654 }
655 len++;
656
Radek Krejci23238922015-10-27 17:13:34 +0100657 str = lyjson_parse_text(&data[len], &r);
Radek Krejci5449d472015-10-26 14:35:56 +0100658 if (!r) {
659 goto error;
660 } else if (data[len + r] != '"') {
661 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing quotation-mark at the end of string)");
662 goto error;
663 }
Radek Krejci23238922015-10-27 17:13:34 +0100664 if ((name = strchr(str, ':'))) {
665 *name = '\0';
666 name++;
667 prefix = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100668 if (prefix[0] == '@') {
669 prefix++;
670 }
Radek Krejci23238922015-10-27 17:13:34 +0100671 } else {
672 name = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100673 if (name[0] == '@') {
674 name++;
675 }
Radek Krejci5449d472015-10-26 14:35:56 +0100676 }
677
Radek Krejci5449d472015-10-26 14:35:56 +0100678 /* prepare data for parsing node content */
679 len += r + 1;
680 len += skip_ws(&data[len]);
681 if (data[len] != ':') {
682 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing name-separator)");
683 goto error;
684 }
685 len++;
686 len += skip_ws(&data[len]);
687
Radek Krejci88f29302015-10-30 15:42:33 +0100688 if (str[0] == '@' && !str[1]) {
689 /* process attribute of the parent object (container or list) */
690 if (!*parent) {
691 LOGVAL(LYE_XML_INVAL, lineno, "attribute with no corresponding element to belongs to");
692 goto error;
693 }
694
695 r = json_parse_attr((*parent)->schema->module, &attr, &data[len]);
696 if (!r) {
697 goto error;
698 }
699 len += r;
700
701 if ((*parent)->attr) {
702 lyd_free_attr(ctx, NULL, attr, 1);
703 } else {
704 (*parent)->attr = attr;
705 }
Radek Krejcic4831272015-11-01 19:26:34 +0100706 free(str);
707 return len;
Radek Krejci88f29302015-10-30 15:42:33 +0100708 }
709
Radek Krejci5449d472015-10-26 14:35:56 +0100710 /* find schema node */
711 if (!(*parent)) {
712 /* starting in root */
713 /* get the proper schema */
714 module = ly_ctx_get_module(ctx, prefix, NULL);
715 if (module) {
716 /* get the proper schema node */
717 LY_TREE_FOR(module->data, schema) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100718 /* skip nodes in module's data which are not expected here according to options' data type */
719 if (options & LYD_OPT_RPC) {
720 if (schema->nodetype != LYS_RPC) {
721 continue;
722 }
723 } else if (options & LYD_OPT_NOTIF) {
724 if (schema->nodetype != LYS_NOTIF) {
725 continue;
726 }
727 } else if (!(options & LYD_OPT_RPCREPLY)) {
728 /* rest of the data types except RPCREPLY which cannot be here */
729 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
730 continue;
731 }
732 }
Radek Krejci5449d472015-10-26 14:35:56 +0100733 if (!strcmp(schema->name, name)) {
734 break;
735 }
736 }
Radek Krejci88f29302015-10-30 15:42:33 +0100737 } else {
738 LOGVAL(LYE_INELEM, lineno, name);
739 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100740 }
741 } else {
742 /* parsing some internal node, we start with parent's schema pointer */
743 if (prefix) {
744 /* get the proper schema */
745 module = ly_ctx_get_module(ctx, prefix, NULL);
746 if (!module) {
747 LOGVAL(LYE_INELEM, lineno, name);
Radek Krejci88f29302015-10-30 15:42:33 +0100748 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100749 }
750 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100751
752 /* go through RPC's input/output following the options' data type */
753 if ((*parent)->schema->nodetype == LYS_RPC) {
754 while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, module, LYS_GETNEXT_WITHINOUT))) {
755 if ((options & LYD_OPT_RPC) && schema->nodetype == LYS_INPUT) {
756 break;
757 } else if ((options & LYD_OPT_RPCREPLY) && schema->nodetype == LYS_OUTPUT) {
758 break;
759 }
760 }
761 if (!schema) {
762 LOGVAL(LYE_INELEM, lineno, name);
763 goto error;
764 }
765 schema_parent = schema;
766 schema = NULL;
767 }
768
Michal Vasko36ef6932015-12-01 14:30:17 +0100769 if (schema_parent) {
770 while ((schema = (struct lys_node *)lys_getnext(schema, schema_parent, module, 0))) {
771 if (!strcmp(schema->name, name)) {
772 break;
773 }
774 }
775 } else {
776 while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, module, 0))) {
777 if (!strcmp(schema->name, name)) {
778 break;
779 }
Radek Krejci5449d472015-10-26 14:35:56 +0100780 }
781 }
782 }
783 if (!schema) {
784 LOGVAL(LYE_INELEM, lineno, name);
Radek Krejci88f29302015-10-30 15:42:33 +0100785 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100786 }
Radek Krejci88f29302015-10-30 15:42:33 +0100787
788 if (str[0] == '@') {
Radek Krejci88f29302015-10-30 15:42:33 +0100789 /* attribute for some sibling node */
790 if (data[len] == '[') {
791 flag_leaflist = 1;
792 len++;
793 len += skip_ws(&data[len]);
794 }
795
796attr_repeat:
797 r = json_parse_attr(schema->module, &attr, &data[len]);
798 if (!r) {
799 goto error;
800 }
801 len += r;
802
803 if (attr) {
Radek Krejcic4831272015-11-01 19:26:34 +0100804 attrs_aux = malloc(sizeof *attrs_aux);
Michal Vasko253035f2015-12-17 16:58:13 +0100805 if (!attrs_aux) {
806 LOGMEM;
807 goto error;
808 }
Radek Krejcic4831272015-11-01 19:26:34 +0100809 attrs_aux->attr = attr;
810 attrs_aux->index = flag_leaflist;
811 attrs_aux->schema = schema;
812 attrs_aux->next = *attrs;
813 *attrs = attrs_aux;
Radek Krejci88f29302015-10-30 15:42:33 +0100814 } else if (!flag_leaflist) {
815 /* error */
816 LOGVAL(LYE_XML_INVAL, lineno, "attribute data");
817 goto error;
818 }
819
820 if (flag_leaflist) {
821 if (data[len] == ',') {
822 len++;
823 len += skip_ws(&data[len]);
824 flag_leaflist++;
825 goto attr_repeat;
826 } else if (data[len] != ']') {
827 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-array)");
828 goto error;
829 }
830 len++;
831 len += skip_ws(&data[len]);
832 }
833
Radek Krejcic4831272015-11-01 19:26:34 +0100834 free(str);
835 return len;
Radek Krejci88f29302015-10-30 15:42:33 +0100836 }
837
Radek Krejci5449d472015-10-26 14:35:56 +0100838 switch (schema->nodetype) {
839 case LYS_CONTAINER:
840 case LYS_LIST:
841 case LYS_NOTIF:
842 case LYS_RPC:
843 result = calloc(1, sizeof *result);
844 break;
845 case LYS_LEAF:
846 case LYS_LEAFLIST:
847 result = calloc(1, sizeof(struct lyd_node_leaf_list));
848 break;
849 case LYS_ANYXML:
850 result = calloc(1, sizeof(struct lyd_node_anyxml));
851 break;
852 default:
853 LOGINT;
Radek Krejci595060f2015-10-30 16:29:58 +0100854 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100855 }
Michal Vasko253035f2015-12-17 16:58:13 +0100856 if (!result) {
857 LOGMEM;
858 goto error;
859 }
860
Radek Krejci5449d472015-10-26 14:35:56 +0100861 result->parent = *parent;
862 if (*parent && !(*parent)->child) {
863 (*parent)->child = result;
864 }
865 if (prev) {
866 result->prev = prev;
867 prev->next = result;
868
869 /* fix the "last" pointer */
870 for (diter = prev; diter->prev != prev; diter = diter->prev);
871 diter->prev = result;
872 } else {
873 result->prev = result;
874 }
875 result->schema = schema;
876
Radek Krejci23238922015-10-27 17:13:34 +0100877 if (lyv_data_context(result, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100878 goto error;
879 }
880
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100881 /* TODO handle notifications */
882
Radek Krejci5449d472015-10-26 14:35:56 +0100883 /* type specific processing */
884 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
885 /* type detection and assigning the value */
Radek Krejci23238922015-10-27 17:13:34 +0100886 r = json_get_value((struct lyd_node_leaf_list *)result, &data[len], options, unres);
Radek Krejci5449d472015-10-26 14:35:56 +0100887 if (!r) {
888 goto error;
889 }
Radek Krejci88f29302015-10-30 15:42:33 +0100890 while(result->next) {
891 result = result->next;
892 }
893
Radek Krejci5449d472015-10-26 14:35:56 +0100894 len += r;
895 len += skip_ws(&data[len]);
896 } else if (schema->nodetype == LYS_ANYXML) {
897 r = json_get_anyxml((struct lyd_node_anyxml *)result, &data[len]);
898 if (!r) {
899 goto error;
900 }
901 len += r;
902 len += skip_ws(&data[len]);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100903 } else if (schema->nodetype & (LYS_CONTAINER | LYS_RPC)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100904 if (data[len] != '{') {
905 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing begin-object)");
906 goto error;
907 }
908 len++;
909 len += skip_ws(&data[len]);
910
911 if (data[len] != '}') {
912 /* non-empty container */
Radek Krejcic4831272015-11-01 19:26:34 +0100913 len--;
914 diter = NULL;
915 attrs_aux = NULL;
916 do {
917 len++;
918 len += skip_ws(&data[len]);
919
Michal Vasko36ef6932015-12-01 14:30:17 +0100920 r = json_parse_data(ctx, &data[len], NULL, &result, diter, &attrs_aux, options, unres);
Radek Krejcic4831272015-11-01 19:26:34 +0100921 if (!r) {
922 goto error;
923 }
924 len += r;
925
926 if (result->child) {
927 diter = result->child->prev;
928 }
929 } while(data[len] == ',');
930
931 /* store attributes */
932 if (store_attrs(ctx, attrs_aux, result->child)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100933 goto error;
934 }
Radek Krejci5449d472015-10-26 14:35:56 +0100935 }
936
937 if (data[len] != '}') {
938 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-object)");
939 goto error;
940 }
941 len++;
942 len += skip_ws(&data[len]);
943
944 } else if (schema->nodetype == LYS_LIST) {
945 if (data[len] != '[') {
946 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing begin-array)");
947 goto error;
948 }
949
950 list = result;
951 do {
952 len++;
953 len += skip_ws(&data[len]);
Radek Krejci23238922015-10-27 17:13:34 +0100954
955 if (options & LYD_OPT_FILTER) {
956 /* filter selection node ? */
957 if (data[len] == ']') {
958 break;
959 } else if (!strcmp(&data[len], "null")) {
960 len += 4;
961 len += skip_ws(&data[len]);
962 break;
963 }
964 }
965
Radek Krejcic4831272015-11-01 19:26:34 +0100966 if (data[len] != '{') {
967 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing list instance's begin-object)");
Radek Krejci5449d472015-10-26 14:35:56 +0100968 goto error;
969 }
Radek Krejcic4831272015-11-01 19:26:34 +0100970 diter = NULL;
971 attrs_aux = NULL;
972 do {
973 len++;
974 len += skip_ws(&data[len]);
975
Michal Vasko36ef6932015-12-01 14:30:17 +0100976 r = json_parse_data(ctx, &data[len], NULL, &list, diter, &attrs_aux, options, unres);
Radek Krejcic4831272015-11-01 19:26:34 +0100977 if (!r) {
978 goto error;
979 }
980 len += r;
981
Radek Krejci52934692015-11-01 20:08:15 +0100982 if (list->child) {
Radek Krejcic4831272015-11-01 19:26:34 +0100983 diter = list->child->prev;
984 }
985 } while(data[len] == ',');
986
987 /* store attributes */
Radek Krejci52934692015-11-01 20:08:15 +0100988 if (store_attrs(ctx, attrs_aux, list->child)) {
Radek Krejcic4831272015-11-01 19:26:34 +0100989 goto error;
990 }
991
992 if (data[len] != '}') {
993 /* expecting end-object */
994 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing list instance's end-object)");
995 goto error;
996 }
997 len++;
Radek Krejci5449d472015-10-26 14:35:56 +0100998 len += skip_ws(&data[len]);
999
1000 if (data[len] == ',') {
1001 /* another instance of the list */
1002 new = calloc(1, sizeof *new);
Michal Vasko253035f2015-12-17 16:58:13 +01001003 if (!new) {
1004 goto error;
1005 }
Radek Krejci5449d472015-10-26 14:35:56 +01001006 new->parent = list->parent;
1007 new->prev = list;
1008 list->next = new;
1009
1010 /* fix the "last" pointer */
1011 for (diter = list; diter->prev != list; diter = diter->prev);
1012 diter->prev = new;
1013
1014 new->schema = list->schema;
1015
1016 /* various validation checks */
1017 ly_errno = 0;
Radek Krejci23238922015-10-27 17:13:34 +01001018 if (lyv_data_content(list, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +01001019 if (ly_errno) {
1020 goto error;
1021 }
1022 }
1023 list = new;
1024 }
1025 } while (data[len] == ',');
1026 result = list;
1027
1028 if (data[len] != ']') {
1029 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing end-array)");
1030 goto error;
1031 }
1032 len++;
1033 len += skip_ws(&data[len]);
1034 }
1035
1036 /* various validation checks */
1037 ly_errno = 0;
Radek Krejci23238922015-10-27 17:13:34 +01001038 if (lyv_data_content(result, options, lineno, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +01001039 if (ly_errno) {
1040 goto error;
1041 }
1042 }
1043
Radek Krejci88f29302015-10-30 15:42:33 +01001044 if (!(*parent)) {
1045 *parent = result;
1046 }
1047
Radek Krejcide9d92c2015-10-30 15:59:59 +01001048 free(str);
Radek Krejci5449d472015-10-26 14:35:56 +01001049 return len;
1050
1051error:
Radek Krejci88f29302015-10-30 15:42:33 +01001052 if ((*parent) == result) {
1053 (*parent) = NULL;
1054 }
1055 while (*attrs) {
Radek Krejcic4831272015-11-01 19:26:34 +01001056 attrs_aux = *attrs;
Radek Krejci88f29302015-10-30 15:42:33 +01001057 *attrs = (*attrs)->next;
1058
Radek Krejcic4831272015-11-01 19:26:34 +01001059 lyd_free_attr(ctx, NULL, attrs_aux->attr, 1);
1060 free(attrs_aux);
Radek Krejci88f29302015-10-30 15:42:33 +01001061 }
1062
Radek Krejci5449d472015-10-26 14:35:56 +01001063 lyd_free(result);
Radek Krejci88f29302015-10-30 15:42:33 +01001064 free(str);
1065
Radek Krejci5449d472015-10-26 14:35:56 +01001066 return 0;
1067}
1068
1069struct lyd_node *
Michal Vasko36ef6932015-12-01 14:30:17 +01001070lyd_parse_json(struct ly_ctx *ctx, const struct lys_node *parent, const char *data, int options)
Radek Krejci5449d472015-10-26 14:35:56 +01001071{
Radek Krejcic4831272015-11-01 19:26:34 +01001072 struct lyd_node *result = NULL, *next = NULL, *iter = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +01001073 struct unres_data *unres = NULL;
Radek Krejcic4831272015-11-01 19:26:34 +01001074 unsigned int len = 0, r;
1075 struct attr_cont *attrs = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +01001076
1077 if (!ctx || !data) {
1078 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
1079 return NULL;
1080 }
1081
1082 unres = calloc(1, sizeof *unres);
Michal Vasko253035f2015-12-17 16:58:13 +01001083 if (!unres) {
1084 LOGMEM;
1085 return NULL;
1086 }
Radek Krejci5449d472015-10-26 14:35:56 +01001087
1088#ifndef NDEBUG
1089 lineno = 0;
1090#endif
1091 ly_errno = 0;
Radek Krejcic4831272015-11-01 19:26:34 +01001092
1093 /* skip leading whitespaces */
1094 len += skip_ws(&data[len]);
1095
1096 /* expect top-level { */
1097 if (data[len] != '{') {
1098 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing top level begin-object)");
1099 goto cleanup;
1100 }
1101
1102 do {
1103 len++;
1104 len += skip_ws(&data[len]);
1105
Michal Vasko36ef6932015-12-01 14:30:17 +01001106 r = json_parse_data(ctx, &data[len], parent, &next, iter, &attrs, options, unres);
Radek Krejcic4831272015-11-01 19:26:34 +01001107 if (!r) {
1108 result = NULL;
1109 goto cleanup;
1110 }
1111 len += r;
1112
1113 if (!result) {
1114 result = next;
1115 }
1116 if (next) {
1117 iter = next;
1118 }
1119 next = NULL;
1120 } while(data[len] == ',');
1121
1122 if (data[len] != '}') {
1123 /* expecting end-object */
1124 LOGVAL(LYE_XML_INVAL, lineno, "JSON data (missing top-level end-object)");
1125 LY_TREE_FOR_SAFE(result, next, iter) {
1126 lyd_free(iter);
1127 }
1128 result = NULL;
1129 goto cleanup;
1130 }
1131 len++;
1132 len += skip_ws(&data[len]);
1133
1134 /* store attributes */
1135 if (store_attrs(ctx, attrs, result)) {
1136 LY_TREE_FOR_SAFE(result, next, iter) {
1137 lyd_free(iter);
1138 }
1139 result = NULL;
1140 goto cleanup;
1141 }
Radek Krejci5449d472015-10-26 14:35:56 +01001142
Michal Vaskoc1cf86f2015-11-04 09:54:51 +01001143 if (!result) {
1144 LOGERR(LY_EVALID, "Model for the data to be linked with not found.");
1145 goto cleanup;
1146 }
1147
Radek Krejci5449d472015-10-26 14:35:56 +01001148 /* check leafrefs and/or instids if any */
1149 if (result && resolve_unres_data(unres)) {
1150 /* leafref & instid checking failed */
Radek Krejcic4831272015-11-01 19:26:34 +01001151 LY_TREE_FOR_SAFE(result, next, iter) {
Radek Krejci5449d472015-10-26 14:35:56 +01001152 lyd_free(iter);
1153 }
1154 result = NULL;
1155 }
1156
Radek Krejcic4831272015-11-01 19:26:34 +01001157cleanup:
Radek Krejci5449d472015-10-26 14:35:56 +01001158 free(unres->node);
1159 free(unres->type);
1160#ifndef NDEBUG
1161 free(unres->line);
1162#endif
1163 free(unres);
1164
1165 return result;
1166}