blob: 9a63283c78ee368b9e91857515f252926743604f [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 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejci5449d472015-10-26 14:35:56 +010013 */
14
Radek Krejci9a5daea2016-03-02 16:49:40 +010015#define _GNU_SOURCE
Radek Krejci5449d472015-10-26 14:35:56 +010016#include <assert.h>
17#include <ctype.h>
18#include <limits.h>
19#include <stdlib.h>
20#include <string.h>
21
22#include "libyang.h"
23#include "common.h"
24#include "context.h"
25#include "parser.h"
26#include "printer.h"
27#include "tree_internal.h"
28#include "validation.h"
Radek Krejci9a5daea2016-03-02 16:49:40 +010029#include "xml_internal.h"
Radek Krejci5449d472015-10-26 14:35:56 +010030
Radek Krejci5449d472015-10-26 14:35:56 +010031static int
32lyjson_isspace(int c)
33{
34 switch(c) {
35 case 0x20: /* space */
36 case 0x09: /* horizontal tab */
37 case 0x0a: /* line feed or new line */
38 case 0x0d: /* carriage return */
39 return 1;
40 default:
41 return 0;
42 }
43}
44
45static unsigned int
46skip_ws(const char *data)
47{
48 unsigned int len = 0;
49
50 /* skip leading whitespaces */
51 while (data[len] && lyjson_isspace(data[len])) {
Radek Krejci5449d472015-10-26 14:35:56 +010052 len++;
53 }
54
55 return len;
56}
57
Radek Krejci5449d472015-10-26 14:35:56 +010058static char *
59lyjson_parse_text(const char *data, unsigned int *len)
60{
61#define BUFSIZE 1024
62
63 char buf[BUFSIZE];
64 char *result = NULL, *aux;
Radek Krejci967e4bf2015-11-28 10:06:40 +010065 int o, size = 0;
Radek Krejci5449d472015-10-26 14:35:56 +010066 unsigned int r, i;
67 int32_t value;
68
69 for (*len = o = 0; data[*len] && data[*len] != '"'; o++) {
70 if (o > BUFSIZE - 3) {
71 /* add buffer into the result */
72 if (result) {
73 size = size + o;
Michal Vasko253035f2015-12-17 16:58:13 +010074 aux = ly_realloc(result, size + 1);
75 if (!aux) {
76 LOGMEM;
77 return NULL;
78 }
Radek Krejci5449d472015-10-26 14:35:56 +010079 result = aux;
80 } else {
81 size = o;
82 result = malloc((size + 1) * sizeof *result);
Michal Vasko253035f2015-12-17 16:58:13 +010083 if (!result) {
84 LOGMEM;
85 return NULL;
86 }
Radek Krejci5449d472015-10-26 14:35:56 +010087 }
88 memcpy(&result[size - o], buf, o);
89
90 /* write again into the beginning of the buffer */
91 o = 0;
92 }
93
94 if (data[*len] == '\\') {
95 /* parse escape sequence */
96 (*len)++;
97 i = 1;
98 switch (data[(*len)]) {
99 case '"':
100 /* quotation mark */
101 value = 0x22;
102 break;
103 case '\\':
104 /* reverse solidus */
105 value = 0x5c;
106 break;
107 case '/':
108 /* solidus */
109 value = 0x2f;
110 break;
111 case 'b':
112 /* backspace */
113 value = 0x08;
114 break;
115 case 'f':
116 /* form feed */
117 value = 0x0c;
118 break;
119 case 'n':
120 /* line feed */
121 value = 0x0a;
122 break;
123 case 'r':
124 /* carriage return */
125 value = 0x0d;
126 break;
127 case 't':
128 /* tab */
129 value = 0x09;
130 break;
131 case 'u':
132 /* Basic Multilingual Plane character \uXXXX */
133 (*len)++;
134 for (value = i = 0; i < 4; i++) {
135 if (isdigit(data[(*len) + i])) {
136 r = (data[(*len) + i] - '0');
137 } else if (data[(*len) + i] > 'F') {
138 r = 10 + (data[(*len) + i] - 'a');
139 } else {
140 r = 10 + (data[(*len) + i] - 'A');
141 }
142 value = (16 * value) + r;
143 }
144 break;
145 default:
146 /* invalid escape sequence */
Radek Krejci48464ed2016-03-17 15:44:09 +0100147 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "character escape sequence");
Radek Krejci5449d472015-10-26 14:35:56 +0100148 goto error;
149
150 }
Radek Krejci48464ed2016-03-17 15:44:09 +0100151 r = pututf8(&buf[o], value);
Radek Krejci5449d472015-10-26 14:35:56 +0100152 if (!r) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100153 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "character UTF8 character");
Radek Krejci5449d472015-10-26 14:35:56 +0100154 goto error;
155 }
156 o += r - 1; /* o is ++ in for loop */
157 (*len) += i; /* number of read characters */
158 } else if (data[*len] < 0x20 || data[*len] == 0x5c) {
159 /* control characters must be escaped */
Radek Krejci48464ed2016-03-17 15:44:09 +0100160 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "control character (unescaped)");
Radek Krejci5449d472015-10-26 14:35:56 +0100161 goto error;
162 } else {
163 /* unescaped character */
164 buf[o] = data[*len];
Radek Krejci5449d472015-10-26 14:35:56 +0100165 (*len)++;
166 }
167 }
168
169#undef BUFSIZE
170
171 if (o) {
172 if (result) {
173 size = size + o;
Michal Vasko253035f2015-12-17 16:58:13 +0100174 aux = ly_realloc(result, size + 1);
175 if (!aux) {
176 LOGMEM;
177 return NULL;
178 }
Radek Krejci5449d472015-10-26 14:35:56 +0100179 result = aux;
180 } else {
181 size = o;
182 result = malloc((size + 1) * sizeof *result);
Michal Vasko253035f2015-12-17 16:58:13 +0100183 if (!result) {
184 LOGMEM;
185 return NULL;
186 }
Radek Krejci5449d472015-10-26 14:35:56 +0100187 }
188 memcpy(&result[size - o], buf, o);
189 }
190 if (result) {
191 result[size] = '\0';
192 } else {
193 size = 0;
194 result = strdup("");
195 }
196
197 return result;
198
199error:
200 free(result);
201 return NULL;
202}
203
204static unsigned int
205lyjson_parse_number(const char *data)
206{
207 unsigned int len;
208 unsigned int i = 0;
209
210 for (len = 0;
211 data[len] && data[len] != ',' && data[len] != ']' && data[len] != '}' && !lyjson_isspace(data[len]);
212 len++) {
213
214 switch(data[len]) {
215 case '0':
Radek Krejci88f29302015-10-30 15:42:33 +0100216 if (!i && isdigit(data[len + 1])) {
Radek Krejci5449d472015-10-26 14:35:56 +0100217 /* leading 0 is not allowed */
Radek Krejci48464ed2016-03-17 15:44:09 +0100218 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON number (leading zero)");
Radek Krejci5449d472015-10-26 14:35:56 +0100219 return 0;
220 }
221 /* no break */
222 case '1':
223 case '2':
224 case '3':
225 case '4':
226 case '5':
227 case '6':
228 case '7':
229 case '8':
230 case '9':
231 i = 1;
232 /* no break */
233 case 0x2d: /* minus */
234 /* ok */
235 break;
236 default:
Radek Krejci48464ed2016-03-17 15:44:09 +0100237 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "character in JSON Number value");
Radek Krejci5449d472015-10-26 14:35:56 +0100238 return 0;
239 }
240 }
241
242 return len;
243}
244
245static unsigned int
246lyjson_parse_boolean(const char *data)
247{
Radek Krejci6b47b502015-10-30 15:52:41 +0100248 unsigned int len = 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100249
250 if (!strncmp(data, "false", 5)) {
251 len = 5;
252 } else if (!strncmp(data, "true", 4)) {
253 len = 4;
254 }
255
256 if (data[len] && data[len] != ',' && data[len] != ']' && data[len] != '}' && !lyjson_isspace(data[len])) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100257 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON literal value (expected true or false)");
Radek Krejci5449d472015-10-26 14:35:56 +0100258 return 0;
259 }
260
261 return len;
262}
263
264static unsigned int
265json_get_anyxml(struct lyd_node_anyxml *axml, const char *data)
266{
Radek Krejci9a5daea2016-03-02 16:49:40 +0100267 unsigned int len = 0, x;
268 char stop, start, *xmlstr;
269 struct lyxml_elem *xml, *xmlnext;
Radek Krejci5449d472015-10-26 14:35:56 +0100270 int level = 0;
271
272 switch (data[len]) {
273 case '"':
274 start = 0;
275 stop = '"';
Radek Krejci8ce464b2016-03-02 15:39:54 +0100276 len++;
Radek Krejci5449d472015-10-26 14:35:56 +0100277 level = 1;
278 break;
279 case '[':
280 start = '[';
281 stop = ']';
282 break;
283 case '{':
284 start = '{';
285 stop = '}';
286 break;
287 default:
288 /* number or one of literals */
289 while (!isspace(data[len])) {
290 len++;
291 }
292 axml->value = NULL; /* TODO ??? */
293 return len;
294 }
295
296 while (data[len]) {
297 if (start && data[len] == start) {
298 if (!len || data[len - 1] != '\\') {
299 level++;
300 }
301 } else if (data[len] == stop) {
302 if (!len || data[len - 1] != '\\') {
303 level--;
304 }
305 }
Radek Krejci5449d472015-10-26 14:35:56 +0100306 len++;
307 if (!level) {
308 /* we are done */
Radek Krejci9a5daea2016-03-02 16:49:40 +0100309 if (!start) {
310 /* XML in string as we print it */
Radek Krejci15412ca2016-03-03 11:16:52 +0100311 if (asprintf(&xmlstr, "<%s xmlns=\"%s\"/>", axml->schema->name, axml->schema->module->ns) == -1) {
312 LOGMEM;
313 return 0;
314 }
Radek Krejci9a5daea2016-03-02 16:49:40 +0100315 axml->value = lyxml_parse_elem(axml->schema->module->ctx, xmlstr, &x, NULL);
316 free(xmlstr);
317
318 xmlstr = strndup(&data[1], len - 2);
319 xml = lyxml_parse_mem(axml->schema->module->ctx, xmlstr, LYXML_PARSE_MULTIROOT);
320 if (xml) {
321 LY_TREE_FOR_SAFE(xml, xmlnext, xml) {
322 lyxml_add_child(axml->schema->module->ctx, axml->value, xml);
323 }
324 }
325 free(xmlstr);
326 } else {
327 axml->value = NULL; /* TODO ??? */
328 }
Radek Krejci5449d472015-10-26 14:35:56 +0100329 return len;
330 }
331 }
332
333 return 0;
334}
335
336static unsigned int
Radek Krejci0b7704f2016-03-18 12:16:14 +0100337json_get_value(struct lyd_node_leaf_list *leaf, const char *data, int options)
Radek Krejci5449d472015-10-26 14:35:56 +0100338{
339 struct lyd_node_leaf_list *new, *diter;
Radek Krejci37b756f2016-01-18 10:15:03 +0100340 struct lys_type *stype;
Radek Krejci5449d472015-10-26 14:35:56 +0100341 struct ly_ctx *ctx;
342 unsigned int len = 0, r;
Radek Krejci37b756f2016-01-18 10:15:03 +0100343 int resolve;
Radek Krejci5449d472015-10-26 14:35:56 +0100344 char *str;
345
Radek Krejci0b7704f2016-03-18 12:16:14 +0100346 assert(leaf && data);
Radek Krejci5449d472015-10-26 14:35:56 +0100347 ctx = leaf->schema->module->ctx;
348
Radek Krejci20cdf632015-11-09 14:44:58 +0100349 if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
Radek Krejci23238922015-10-27 17:13:34 +0100350 resolve = 0;
351 } else {
352 resolve = 1;
353 }
354
Radek Krejci5449d472015-10-26 14:35:56 +0100355 stype = &((struct lys_node_leaf *)leaf->schema)->type;
Radek Krejci23238922015-10-27 17:13:34 +0100356
357 if (options & LYD_OPT_FILTER) {
358 /* no value in filter (selection) node is accepted in this case */
359 if (!strncmp(&data[len], "null", 4)) {
360 leaf->value_type = stype->base;
361 len +=4;
362 goto end;
363 }
364 }
365
Radek Krejci5449d472015-10-26 14:35:56 +0100366 if (leaf->schema->nodetype == LYS_LEAFLIST) {
367 /* expecting begin-array */
368 if (data[len++] != '[') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100369 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (expected begin-array)");
Radek Krejci5449d472015-10-26 14:35:56 +0100370 return 0;
371 }
372
373repeat:
374 len += skip_ws(&data[len]);
375 }
376
377 /* will be changed in case of union */
378 leaf->value_type = stype->base;
379
380 if (data[len] == '"') {
381 /* string representations */
382 if (data[len++] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100383 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, leaf,
Radek Krejciadb57612016-02-16 13:34:34 +0100384 "JSON data (missing quotation-mark at the beginning of string)");
Radek Krejci5449d472015-10-26 14:35:56 +0100385 return 0;
386 }
387 str = lyjson_parse_text(&data[len], &r);
Radek Krejci23238922015-10-27 17:13:34 +0100388 if (!str) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100389 LOGPATH(LY_VLOG_LYD, leaf);
Radek Krejci5449d472015-10-26 14:35:56 +0100390 return 0;
391 }
392 leaf->value_str = lydict_insert_zc(ctx, str);
393 if (data[len + r] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100394 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, leaf,
Radek Krejciadb57612016-02-16 13:34:34 +0100395 "JSON data (missing quotation-mark at the end of string)");
Radek Krejci5449d472015-10-26 14:35:56 +0100396 return 0;
397 }
398 len += r + 1;
399 } else if (data[len] == '-' || isdigit(data[len])) {
400 /* numeric type */
401 r = lyjson_parse_number(&data[len]);
402 if (!r) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100403 LOGPATH(LY_VLOG_LYD, leaf);
Radek Krejci5449d472015-10-26 14:35:56 +0100404 return 0;
405 }
406 leaf->value_str = lydict_insert(ctx, &data[len], r);
407 len += r;
408 } else if (data[len] == 'f' || data[len] == 't') {
409 /* boolean */
410 r = lyjson_parse_boolean(&data[len]);
411 if (!r) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100412 LOGPATH(LY_VLOG_LYD, leaf);
Radek Krejci5449d472015-10-26 14:35:56 +0100413 return 0;
414 }
415 leaf->value_str = lydict_insert(ctx, &data[len], r);
416 len += r;
417 } else if (!strncmp(&data[len], "[null]", 6)) {
418 /* empty */
419 leaf->value_str = NULL;
420 len += 6;
421 } else {
422 /* error */
Radek Krejci48464ed2016-03-17 15:44:09 +0100423 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (unexpected value)");
Radek Krejci5449d472015-10-26 14:35:56 +0100424 return 0;
425 }
426
Radek Krejci0b7704f2016-03-18 12:16:14 +0100427 if (lyp_parse_value(leaf, NULL, resolve)) {
Radek Krejci23238922015-10-27 17:13:34 +0100428 ly_errno = LY_EVALID;
429 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100430 }
431
432 if (leaf->schema->nodetype == LYS_LEAFLIST) {
433 /* repeat until end-array */
434 len += skip_ws(&data[len]);
435 if (data[len] == ',') {
436 /* another instance of the leaf-list */
437 new = calloc(1, sizeof(struct lyd_node_leaf_list));
Michal Vasko253035f2015-12-17 16:58:13 +0100438 if (!new) {
439 LOGMEM;
440 return 0;
441 }
Radek Krejci5449d472015-10-26 14:35:56 +0100442 new->parent = leaf->parent;
443 new->prev = (struct lyd_node *)leaf;
444 leaf->next = (struct lyd_node *)new;
445
446 /* fix the "last" pointer */
447 for (diter = leaf; diter->prev != (struct lyd_node *)leaf; diter = (struct lyd_node_leaf_list *)diter->prev);
448 diter->prev = (struct lyd_node *)new;
449
450 new->schema = leaf->schema;
451
452 /* repeat value parsing */
453 leaf = new;
454 len++;
455 goto repeat;
456 } else if (data[len] == ']') {
457 len++;
458 len += skip_ws(&data[len]);
459 } else {
460 /* something unexpected */
Radek Krejci48464ed2016-03-17 15:44:09 +0100461 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, leaf, "JSON data (expecting value-separator or end-array)");
Radek Krejci5449d472015-10-26 14:35:56 +0100462 return 0;
463 }
464 }
465
Radek Krejci23238922015-10-27 17:13:34 +0100466end:
Radek Krejci5449d472015-10-26 14:35:56 +0100467 len += skip_ws(&data[len]);
468 return len;
469}
470
471static unsigned int
Radek Krejci88f29302015-10-30 15:42:33 +0100472json_parse_attr(struct lys_module *parent_module, struct lyd_attr **attr, const char *data)
473{
474 unsigned int len = 0, r;
475 char *str = NULL, *name, *prefix, *value;
476 struct lys_module *module = parent_module;
477 struct lyd_attr *attr_new, *attr_last = NULL;
478
Radek Krejcide9d92c2015-10-30 15:59:59 +0100479 *attr = NULL;
480
Radek Krejci88f29302015-10-30 15:42:33 +0100481 if (data[len] != '{') {
482 if (!strncmp(&data[len], "null", 4)) {
Radek Krejci88f29302015-10-30 15:42:33 +0100483 len += 4;
484 len += skip_ws(&data[len]);
485 return len;
486 }
Radek Krejci48464ed2016-03-17 15:44:09 +0100487 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing begin-object)");
Radek Krejci88f29302015-10-30 15:42:33 +0100488 goto error;
489 }
490
491repeat:
492 len++;
493 len += skip_ws(&data[len]);
494
495 if (data[len] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100496 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the begining of string)");
Radek Krejci88f29302015-10-30 15:42:33 +0100497 return 0;
498 }
499 len++;
500 str = lyjson_parse_text(&data[len], &r);
501 if (!r) {
502 goto error;
503 } else if (data[len + r] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100504 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the end of string)");
Radek Krejci88f29302015-10-30 15:42:33 +0100505 goto error;
506 }
507 if ((name = strchr(str, ':'))) {
508 *name = '\0';
509 name++;
510 prefix = str;
Michal Vasko1e62a092015-12-01 12:27:20 +0100511 module = (struct lys_module *)ly_ctx_get_module(parent_module->ctx, prefix, NULL);
Radek Krejci88f29302015-10-30 15:42:33 +0100512 if (!module) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100513 LOGVAL(LYE_INELEM, LY_VLOG_NONE, NULL, name);
Radek Krejci88f29302015-10-30 15:42:33 +0100514 goto error;
515 }
516 } else {
517 name = str;
518 }
519
520 /* prepare data for parsing node content */
521 len += r + 1;
522 len += skip_ws(&data[len]);
523 if (data[len] != ':') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100524 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing name-separator)");
Radek Krejci88f29302015-10-30 15:42:33 +0100525 goto error;
526 }
527 len++;
528 len += skip_ws(&data[len]);
529
530 if (data[len] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100531 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the beginning of string)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100532 goto error;
Radek Krejci88f29302015-10-30 15:42:33 +0100533 }
534 len++;
535 value = lyjson_parse_text(&data[len], &r);
536 if (!r) {
537 goto error;
538 } else if (data[len + r] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100539 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing quotation-mark at the end of string)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100540 free(value);
Radek Krejci88f29302015-10-30 15:42:33 +0100541 goto error;
542 }
543 len += r + 1;
544 len += skip_ws(&data[len]);
545
546 attr_new = malloc(sizeof **attr);
Michal Vasko253035f2015-12-17 16:58:13 +0100547 if (!attr_new) {
548 LOGMEM;
549 goto error;
550 }
Radek Krejci88f29302015-10-30 15:42:33 +0100551 attr_new->module = module;
552 attr_new->next = NULL;
553 attr_new->name = lydict_insert(module->ctx, name, 0);
554 attr_new->value = lydict_insert_zc(module->ctx, value);
555 if (!attr_last) {
556 *attr = attr_last = attr_new;
557 } else {
558 attr_last->next = attr_new;
559 attr_last = attr_new;
560 }
561
562 free(str);
Radek Krejcide9d92c2015-10-30 15:59:59 +0100563 str = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100564
565 if (data[len] == ',') {
566 goto repeat;
567 } else if (data[len] != '}') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100568 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing end-object)");
Radek Krejcide9d92c2015-10-30 15:59:59 +0100569 goto error;
Radek Krejci88f29302015-10-30 15:42:33 +0100570 }
571 len++;
572 len += skip_ws(&data[len]);
573
574 return len;
575
576error:
577 free(str);
Radek Krejcide9d92c2015-10-30 15:59:59 +0100578 if (*attr) {
579 lyd_free_attr((*attr)->module->ctx, NULL, *attr, 1);
580 *attr = NULL;
581 }
Radek Krejci88f29302015-10-30 15:42:33 +0100582 return 0;
583}
584
585struct attr_cont {
586 struct attr_cont *next;
587 struct lyd_attr *attr;
588 struct lys_node *schema;
589 unsigned int index; /** non-zero only in case of leaf-list */
590};
591
Radek Krejcic4831272015-11-01 19:26:34 +0100592static int
593store_attrs(struct ly_ctx *ctx, struct attr_cont *attrs, struct lyd_node *first)
594{
595 struct lyd_node *diter;
596 struct attr_cont *iter;
597 unsigned int flag_leaflist = 0;
598
599 while (attrs) {
600 iter = attrs;
601 attrs = attrs->next;
602
603 if (iter->index) {
604 flag_leaflist = 1;
605 }
606
607 LY_TREE_FOR(first, diter) {
608 if (iter->schema != diter->schema) {
609 continue;
610 }
611
612 if (flag_leaflist && flag_leaflist != iter->index) {
613 flag_leaflist++;
614 continue;
615 }
616
617 /* we have match */
618 if (diter->attr) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100619 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, diter,
Radek Krejciadb57612016-02-16 13:34:34 +0100620 "attribute (multiple attribute definitions belong to a single element)");
Radek Krejcic4831272015-11-01 19:26:34 +0100621 free(iter);
622 goto error;
623 }
624
625 diter->attr = iter->attr;
626 break;
627 }
628
629 if (!diter) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100630 LOGVAL(LYE_XML_MISS, LY_VLOG_NONE, NULL, "element for the specified attribute", iter->attr->name);
Radek Krejcic4831272015-11-01 19:26:34 +0100631 lyd_free_attr(iter->schema->module->ctx, NULL, iter->attr, 1);
632 free(iter);
633 goto error;
634 }
635 free(iter);
636 }
637
638 return 0;
639
640error:
641
642 while (attrs) {
643 iter = attrs;
644 attrs = attrs->next;
645
646 lyd_free_attr(ctx, NULL, iter->attr, 1);
647 free(iter);
648 }
649
650 return -1;
651}
652
Radek Krejci88f29302015-10-30 15:42:33 +0100653static unsigned int
Michal Vasko36ef6932015-12-01 14:30:17 +0100654json_parse_data(struct ly_ctx *ctx, const char *data, const struct lys_node *schema_parent, struct lyd_node **parent,
655 struct lyd_node *prev, struct attr_cont **attrs, int options, struct unres_data *unres)
Radek Krejci5449d472015-10-26 14:35:56 +0100656{
657 unsigned int len = 0;
658 unsigned int r;
Radek Krejcic4831272015-11-01 19:26:34 +0100659 unsigned int flag_leaflist = 0;
Radek Krejci88f29302015-10-30 15:42:33 +0100660 char *name, *prefix = NULL, *str = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +0100661 const struct lys_module *module = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +0100662 struct lys_node *schema = NULL;
663 struct lyd_node *result = NULL, *new, *list, *diter = NULL;
Radek Krejci88f29302015-10-30 15:42:33 +0100664 struct lyd_attr *attr;
Radek Krejcic4831272015-11-01 19:26:34 +0100665 struct attr_cont *attrs_aux;
Radek Krejci5449d472015-10-26 14:35:56 +0100666
667 /* each YANG data node representation starts with string (node identifier) */
668 if (data[len] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100669 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, (*parent),
Radek Krejciadb57612016-02-16 13:34:34 +0100670 "JSON data (missing quotation-mark at the beginning of string)");
Radek Krejci88f29302015-10-30 15:42:33 +0100671 return 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100672 }
673 len++;
674
Radek Krejci23238922015-10-27 17:13:34 +0100675 str = lyjson_parse_text(&data[len], &r);
Radek Krejci5449d472015-10-26 14:35:56 +0100676 if (!r) {
677 goto error;
678 } else if (data[len + r] != '"') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100679 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, (*parent),
Radek Krejciadb57612016-02-16 13:34:34 +0100680 "JSON data (missing quotation-mark at the end of string)");
Radek Krejci5449d472015-10-26 14:35:56 +0100681 goto error;
682 }
Radek Krejci23238922015-10-27 17:13:34 +0100683 if ((name = strchr(str, ':'))) {
684 *name = '\0';
685 name++;
686 prefix = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100687 if (prefix[0] == '@') {
688 prefix++;
689 }
Radek Krejci23238922015-10-27 17:13:34 +0100690 } else {
691 name = str;
Radek Krejci88f29302015-10-30 15:42:33 +0100692 if (name[0] == '@') {
693 name++;
694 }
Radek Krejci5449d472015-10-26 14:35:56 +0100695 }
696
Radek Krejci5449d472015-10-26 14:35:56 +0100697 /* prepare data for parsing node content */
698 len += r + 1;
699 len += skip_ws(&data[len]);
700 if (data[len] != ':') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100701 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, (*parent), "JSON data (missing name-separator)");
Radek Krejci5449d472015-10-26 14:35:56 +0100702 goto error;
703 }
704 len++;
705 len += skip_ws(&data[len]);
706
Radek Krejci88f29302015-10-30 15:42:33 +0100707 if (str[0] == '@' && !str[1]) {
708 /* process attribute of the parent object (container or list) */
709 if (!*parent) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100710 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, (*parent), "attribute with no corresponding element to belongs to");
Radek Krejci88f29302015-10-30 15:42:33 +0100711 goto error;
712 }
713
714 r = json_parse_attr((*parent)->schema->module, &attr, &data[len]);
715 if (!r) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100716 LOGPATH(LY_VLOG_LYD, (*parent));
Radek Krejci88f29302015-10-30 15:42:33 +0100717 goto error;
718 }
719 len += r;
720
721 if ((*parent)->attr) {
722 lyd_free_attr(ctx, NULL, attr, 1);
723 } else {
724 (*parent)->attr = attr;
725 }
Radek Krejcic4831272015-11-01 19:26:34 +0100726 free(str);
727 return len;
Radek Krejci88f29302015-10-30 15:42:33 +0100728 }
729
Radek Krejci5449d472015-10-26 14:35:56 +0100730 /* find schema node */
731 if (!(*parent)) {
732 /* starting in root */
733 /* get the proper schema */
734 module = ly_ctx_get_module(ctx, prefix, NULL);
735 if (module) {
736 /* get the proper schema node */
737 LY_TREE_FOR(module->data, schema) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100738 /* skip nodes in module's data which are not expected here according to options' data type */
739 if (options & LYD_OPT_RPC) {
740 if (schema->nodetype != LYS_RPC) {
741 continue;
742 }
743 } else if (options & LYD_OPT_NOTIF) {
744 if (schema->nodetype != LYS_NOTIF) {
745 continue;
746 }
747 } else if (!(options & LYD_OPT_RPCREPLY)) {
748 /* rest of the data types except RPCREPLY which cannot be here */
749 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
750 continue;
751 }
752 }
Radek Krejci5449d472015-10-26 14:35:56 +0100753 if (!strcmp(schema->name, name)) {
754 break;
755 }
756 }
Radek Krejci88f29302015-10-30 15:42:33 +0100757 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +0100758 LOGVAL(LYE_INELEM, LY_VLOG_LYD, (*parent), name);
Radek Krejci88f29302015-10-30 15:42:33 +0100759 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100760 }
761 } else {
762 /* parsing some internal node, we start with parent's schema pointer */
763 if (prefix) {
764 /* get the proper schema */
765 module = ly_ctx_get_module(ctx, prefix, NULL);
766 if (!module) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100767 LOGVAL(LYE_INELEM, LY_VLOG_LYD, (*parent), name);
Radek Krejci88f29302015-10-30 15:42:33 +0100768 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100769 }
770 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100771
772 /* go through RPC's input/output following the options' data type */
773 if ((*parent)->schema->nodetype == LYS_RPC) {
774 while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, module, LYS_GETNEXT_WITHINOUT))) {
775 if ((options & LYD_OPT_RPC) && schema->nodetype == LYS_INPUT) {
776 break;
777 } else if ((options & LYD_OPT_RPCREPLY) && schema->nodetype == LYS_OUTPUT) {
778 break;
779 }
780 }
781 if (!schema) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100782 LOGVAL(LYE_INELEM, LY_VLOG_LYD, (*parent), name);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100783 goto error;
784 }
785 schema_parent = schema;
786 schema = NULL;
787 }
788
Michal Vasko36ef6932015-12-01 14:30:17 +0100789 if (schema_parent) {
790 while ((schema = (struct lys_node *)lys_getnext(schema, schema_parent, module, 0))) {
791 if (!strcmp(schema->name, name)) {
792 break;
793 }
794 }
795 } else {
796 while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, module, 0))) {
797 if (!strcmp(schema->name, name)) {
798 break;
799 }
Radek Krejci5449d472015-10-26 14:35:56 +0100800 }
801 }
802 }
803 if (!schema) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100804 LOGVAL(LYE_INELEM, LY_VLOG_LYD, (*parent), name);
Radek Krejci88f29302015-10-30 15:42:33 +0100805 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100806 }
Radek Krejci88f29302015-10-30 15:42:33 +0100807
808 if (str[0] == '@') {
Radek Krejci88f29302015-10-30 15:42:33 +0100809 /* attribute for some sibling node */
810 if (data[len] == '[') {
811 flag_leaflist = 1;
812 len++;
813 len += skip_ws(&data[len]);
814 }
815
816attr_repeat:
817 r = json_parse_attr(schema->module, &attr, &data[len]);
818 if (!r) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100819 LOGPATH(LY_VLOG_LYD, (*parent));
Radek Krejci88f29302015-10-30 15:42:33 +0100820 goto error;
821 }
822 len += r;
823
824 if (attr) {
Radek Krejcic4831272015-11-01 19:26:34 +0100825 attrs_aux = malloc(sizeof *attrs_aux);
Michal Vasko253035f2015-12-17 16:58:13 +0100826 if (!attrs_aux) {
827 LOGMEM;
828 goto error;
829 }
Radek Krejcic4831272015-11-01 19:26:34 +0100830 attrs_aux->attr = attr;
831 attrs_aux->index = flag_leaflist;
832 attrs_aux->schema = schema;
833 attrs_aux->next = *attrs;
834 *attrs = attrs_aux;
Radek Krejci88f29302015-10-30 15:42:33 +0100835 } else if (!flag_leaflist) {
836 /* error */
Radek Krejci48464ed2016-03-17 15:44:09 +0100837 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, (*parent), "attribute data");
Radek Krejci88f29302015-10-30 15:42:33 +0100838 goto error;
839 }
840
841 if (flag_leaflist) {
842 if (data[len] == ',') {
843 len++;
844 len += skip_ws(&data[len]);
845 flag_leaflist++;
846 goto attr_repeat;
847 } else if (data[len] != ']') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100848 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, (*parent), "JSON data (missing end-array)");
Radek Krejci88f29302015-10-30 15:42:33 +0100849 goto error;
850 }
851 len++;
852 len += skip_ws(&data[len]);
853 }
854
Radek Krejcic4831272015-11-01 19:26:34 +0100855 free(str);
856 return len;
Radek Krejci88f29302015-10-30 15:42:33 +0100857 }
858
Radek Krejci5449d472015-10-26 14:35:56 +0100859 switch (schema->nodetype) {
860 case LYS_CONTAINER:
861 case LYS_LIST:
862 case LYS_NOTIF:
863 case LYS_RPC:
864 result = calloc(1, sizeof *result);
865 break;
866 case LYS_LEAF:
867 case LYS_LEAFLIST:
868 result = calloc(1, sizeof(struct lyd_node_leaf_list));
869 break;
870 case LYS_ANYXML:
871 result = calloc(1, sizeof(struct lyd_node_anyxml));
872 break;
873 default:
874 LOGINT;
Radek Krejci595060f2015-10-30 16:29:58 +0100875 goto error;
Radek Krejci5449d472015-10-26 14:35:56 +0100876 }
Michal Vasko253035f2015-12-17 16:58:13 +0100877 if (!result) {
878 LOGMEM;
879 goto error;
880 }
881
Radek Krejci5449d472015-10-26 14:35:56 +0100882 result->parent = *parent;
883 if (*parent && !(*parent)->child) {
884 (*parent)->child = result;
885 }
886 if (prev) {
887 result->prev = prev;
888 prev->next = result;
889
890 /* fix the "last" pointer */
Radek Krejci93fab982016-02-03 15:58:19 +0100891 if (*parent) {
892 diter = (*parent)->child;
893 } else {
894 for (diter = prev; diter->prev != prev; diter = diter->prev);
895 }
Radek Krejci5449d472015-10-26 14:35:56 +0100896 diter->prev = result;
897 } else {
898 result->prev = result;
899 }
900 result->schema = schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100901 result->validity = LYD_VAL_NOT;
Radek Krejci0b7704f2016-03-18 12:16:14 +0100902 if (resolve_applies_when(result)) {
903 result->when_status = LYD_WHEN;
904 }
Radek Krejci5449d472015-10-26 14:35:56 +0100905
Radek Krejci48464ed2016-03-17 15:44:09 +0100906 if (!(options & LYD_OPT_TRUSTED) && lyv_data_context(result, options, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100907 goto error;
908 }
909
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100910 /* TODO handle notifications */
911
Radek Krejci5449d472015-10-26 14:35:56 +0100912 /* type specific processing */
913 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
914 /* type detection and assigning the value */
Radek Krejci0b7704f2016-03-18 12:16:14 +0100915 r = json_get_value((struct lyd_node_leaf_list *)result, &data[len], options);
Radek Krejci5449d472015-10-26 14:35:56 +0100916 if (!r) {
917 goto error;
918 }
Radek Krejci88f29302015-10-30 15:42:33 +0100919 while(result->next) {
920 result = result->next;
921 }
922
Radek Krejci5449d472015-10-26 14:35:56 +0100923 len += r;
924 len += skip_ws(&data[len]);
925 } else if (schema->nodetype == LYS_ANYXML) {
926 r = json_get_anyxml((struct lyd_node_anyxml *)result, &data[len]);
927 if (!r) {
928 goto error;
929 }
930 len += r;
931 len += skip_ws(&data[len]);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100932 } else if (schema->nodetype & (LYS_CONTAINER | LYS_RPC)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100933 if (data[len] != '{') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100934 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing begin-object)");
Radek Krejci5449d472015-10-26 14:35:56 +0100935 goto error;
936 }
937 len++;
938 len += skip_ws(&data[len]);
939
940 if (data[len] != '}') {
941 /* non-empty container */
Radek Krejcic4831272015-11-01 19:26:34 +0100942 len--;
943 diter = NULL;
944 attrs_aux = NULL;
945 do {
946 len++;
947 len += skip_ws(&data[len]);
948
Michal Vasko36ef6932015-12-01 14:30:17 +0100949 r = json_parse_data(ctx, &data[len], NULL, &result, diter, &attrs_aux, options, unres);
Radek Krejcic4831272015-11-01 19:26:34 +0100950 if (!r) {
951 goto error;
952 }
953 len += r;
954
955 if (result->child) {
956 diter = result->child->prev;
957 }
958 } while(data[len] == ',');
959
960 /* store attributes */
961 if (store_attrs(ctx, attrs_aux, result->child)) {
Radek Krejci5449d472015-10-26 14:35:56 +0100962 goto error;
963 }
Radek Krejci5449d472015-10-26 14:35:56 +0100964 }
965
966 if (data[len] != '}') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100967 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing end-object)");
Radek Krejci5449d472015-10-26 14:35:56 +0100968 goto error;
969 }
970 len++;
971 len += skip_ws(&data[len]);
972
973 } else if (schema->nodetype == LYS_LIST) {
974 if (data[len] != '[') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100975 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing begin-array)");
Radek Krejci5449d472015-10-26 14:35:56 +0100976 goto error;
977 }
978
979 list = result;
980 do {
981 len++;
982 len += skip_ws(&data[len]);
Radek Krejci23238922015-10-27 17:13:34 +0100983
984 if (options & LYD_OPT_FILTER) {
985 /* filter selection node ? */
986 if (data[len] == ']') {
987 break;
988 } else if (!strcmp(&data[len], "null")) {
989 len += 4;
990 len += skip_ws(&data[len]);
991 break;
992 }
993 }
994
Radek Krejcic4831272015-11-01 19:26:34 +0100995 if (data[len] != '{') {
Radek Krejci48464ed2016-03-17 15:44:09 +0100996 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result,
Radek Krejciadb57612016-02-16 13:34:34 +0100997 "JSON data (missing list instance's begin-object)");
Radek Krejci5449d472015-10-26 14:35:56 +0100998 goto error;
999 }
Radek Krejcic4831272015-11-01 19:26:34 +01001000 diter = NULL;
1001 attrs_aux = NULL;
1002 do {
1003 len++;
1004 len += skip_ws(&data[len]);
1005
Michal Vasko36ef6932015-12-01 14:30:17 +01001006 r = json_parse_data(ctx, &data[len], NULL, &list, diter, &attrs_aux, options, unres);
Radek Krejcic4831272015-11-01 19:26:34 +01001007 if (!r) {
1008 goto error;
1009 }
1010 len += r;
1011
Radek Krejci52934692015-11-01 20:08:15 +01001012 if (list->child) {
Radek Krejcic4831272015-11-01 19:26:34 +01001013 diter = list->child->prev;
1014 }
1015 } while(data[len] == ',');
1016
1017 /* store attributes */
Radek Krejci52934692015-11-01 20:08:15 +01001018 if (store_attrs(ctx, attrs_aux, list->child)) {
Radek Krejcic4831272015-11-01 19:26:34 +01001019 goto error;
1020 }
1021
1022 if (data[len] != '}') {
1023 /* expecting end-object */
Radek Krejci48464ed2016-03-17 15:44:09 +01001024 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result,
Radek Krejciadb57612016-02-16 13:34:34 +01001025 "JSON data (missing list instance's end-object)");
Radek Krejcic4831272015-11-01 19:26:34 +01001026 goto error;
1027 }
1028 len++;
Radek Krejci5449d472015-10-26 14:35:56 +01001029 len += skip_ws(&data[len]);
1030
1031 if (data[len] == ',') {
Radek Krejci93fab982016-02-03 15:58:19 +01001032 /* various validation checks */
1033 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01001034 if (!(options & LYD_OPT_TRUSTED) && lyv_data_content(list, options, unres)) {
Radek Krejci93fab982016-02-03 15:58:19 +01001035 if (ly_errno) {
1036 goto error;
1037 }
1038 }
1039 /* validation successful */
1040 list->validity = LYD_VAL_OK;
1041
Radek Krejci5449d472015-10-26 14:35:56 +01001042 /* another instance of the list */
1043 new = calloc(1, sizeof *new);
Michal Vasko253035f2015-12-17 16:58:13 +01001044 if (!new) {
1045 goto error;
1046 }
Radek Krejci5449d472015-10-26 14:35:56 +01001047 new->parent = list->parent;
1048 new->prev = list;
1049 list->next = new;
1050
1051 /* fix the "last" pointer */
Radek Krejci93fab982016-02-03 15:58:19 +01001052 if (*parent) {
1053 diter = (*parent)->child;
1054 } else {
1055 for (diter = prev; diter->prev != prev; diter = diter->prev);
1056 }
Radek Krejci5449d472015-10-26 14:35:56 +01001057 diter->prev = new;
1058
1059 new->schema = list->schema;
Radek Krejci5449d472015-10-26 14:35:56 +01001060 list = new;
1061 }
1062 } while (data[len] == ',');
1063 result = list;
1064
1065 if (data[len] != ']') {
Radek Krejci48464ed2016-03-17 15:44:09 +01001066 LOGVAL(LYE_XML_INVAL, LY_VLOG_LYD, result, "JSON data (missing end-array)");
Radek Krejci5449d472015-10-26 14:35:56 +01001067 goto error;
1068 }
1069 len++;
1070 len += skip_ws(&data[len]);
1071 }
1072
1073 /* various validation checks */
1074 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01001075 if (!(options & LYD_OPT_TRUSTED) && lyv_data_content(result, options, unres)) {
Radek Krejci5449d472015-10-26 14:35:56 +01001076 if (ly_errno) {
1077 goto error;
1078 }
1079 }
1080
Radek Krejcica7efb72016-01-18 13:06:01 +01001081 /* validation successful */
1082 result->validity = LYD_VAL_OK;
1083
Radek Krejci88f29302015-10-30 15:42:33 +01001084 if (!(*parent)) {
1085 *parent = result;
1086 }
1087
Radek Krejcide9d92c2015-10-30 15:59:59 +01001088 free(str);
Radek Krejci5449d472015-10-26 14:35:56 +01001089 return len;
1090
1091error:
Radek Krejci88f29302015-10-30 15:42:33 +01001092 if ((*parent) == result) {
1093 (*parent) = NULL;
1094 }
1095 while (*attrs) {
Radek Krejcic4831272015-11-01 19:26:34 +01001096 attrs_aux = *attrs;
Radek Krejci88f29302015-10-30 15:42:33 +01001097 *attrs = (*attrs)->next;
1098
Radek Krejcic4831272015-11-01 19:26:34 +01001099 lyd_free_attr(ctx, NULL, attrs_aux->attr, 1);
1100 free(attrs_aux);
Radek Krejci88f29302015-10-30 15:42:33 +01001101 }
1102
Radek Krejci5449d472015-10-26 14:35:56 +01001103 lyd_free(result);
Radek Krejci88f29302015-10-30 15:42:33 +01001104 free(str);
1105
Radek Krejci5449d472015-10-26 14:35:56 +01001106 return 0;
1107}
1108
1109struct lyd_node *
Michal Vasko36ef6932015-12-01 14:30:17 +01001110lyd_parse_json(struct ly_ctx *ctx, const struct lys_node *parent, const char *data, int options)
Radek Krejci5449d472015-10-26 14:35:56 +01001111{
Radek Krejcic4831272015-11-01 19:26:34 +01001112 struct lyd_node *result = NULL, *next = NULL, *iter = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +01001113 struct unres_data *unres = NULL;
Radek Krejcic4831272015-11-01 19:26:34 +01001114 unsigned int len = 0, r;
1115 struct attr_cont *attrs = NULL;
Radek Krejci5449d472015-10-26 14:35:56 +01001116
Radek Krejci2342cf62016-01-29 16:48:23 +01001117 ly_errno = LY_SUCCESS;
1118
Radek Krejci5449d472015-10-26 14:35:56 +01001119 if (!ctx || !data) {
1120 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
1121 return NULL;
1122 }
1123
1124 unres = calloc(1, sizeof *unres);
Michal Vasko253035f2015-12-17 16:58:13 +01001125 if (!unres) {
1126 LOGMEM;
1127 return NULL;
1128 }
Radek Krejci5449d472015-10-26 14:35:56 +01001129
Radek Krejcic4831272015-11-01 19:26:34 +01001130 /* skip leading whitespaces */
1131 len += skip_ws(&data[len]);
1132
1133 /* expect top-level { */
1134 if (data[len] != '{') {
Radek Krejci48464ed2016-03-17 15:44:09 +01001135 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top level begin-object)");
Radek Krejcic4831272015-11-01 19:26:34 +01001136 goto cleanup;
1137 }
1138
1139 do {
1140 len++;
1141 len += skip_ws(&data[len]);
1142
Michal Vasko36ef6932015-12-01 14:30:17 +01001143 r = json_parse_data(ctx, &data[len], parent, &next, iter, &attrs, options, unres);
Radek Krejcic4831272015-11-01 19:26:34 +01001144 if (!r) {
1145 result = NULL;
1146 goto cleanup;
1147 }
1148 len += r;
1149
1150 if (!result) {
1151 result = next;
1152 }
1153 if (next) {
1154 iter = next;
1155 }
1156 next = NULL;
1157 } while(data[len] == ',');
1158
1159 if (data[len] != '}') {
1160 /* expecting end-object */
Radek Krejci48464ed2016-03-17 15:44:09 +01001161 LOGVAL(LYE_XML_INVAL, LY_VLOG_NONE, NULL, "JSON data (missing top-level end-object)");
Radek Krejcic4831272015-11-01 19:26:34 +01001162 LY_TREE_FOR_SAFE(result, next, iter) {
1163 lyd_free(iter);
1164 }
1165 result = NULL;
1166 goto cleanup;
1167 }
1168 len++;
1169 len += skip_ws(&data[len]);
1170
1171 /* store attributes */
1172 if (store_attrs(ctx, attrs, result)) {
1173 LY_TREE_FOR_SAFE(result, next, iter) {
1174 lyd_free(iter);
1175 }
1176 result = NULL;
1177 goto cleanup;
1178 }
Radek Krejci5449d472015-10-26 14:35:56 +01001179
Michal Vaskoc1cf86f2015-11-04 09:54:51 +01001180 if (!result) {
1181 LOGERR(LY_EVALID, "Model for the data to be linked with not found.");
1182 goto cleanup;
1183 }
1184
Radek Krejci5449d472015-10-26 14:35:56 +01001185 /* check leafrefs and/or instids if any */
Radek Krejci03b71f72016-03-16 11:10:09 +01001186 if (result && resolve_unres_data(unres, (options & LYD_OPT_NOAUTODEL) ? NULL : &result)) {
Radek Krejci5449d472015-10-26 14:35:56 +01001187 /* leafref & instid checking failed */
Radek Krejcic4831272015-11-01 19:26:34 +01001188 LY_TREE_FOR_SAFE(result, next, iter) {
Radek Krejci5449d472015-10-26 14:35:56 +01001189 lyd_free(iter);
1190 }
1191 result = NULL;
1192 }
1193
Radek Krejcic4831272015-11-01 19:26:34 +01001194cleanup:
Radek Krejci5449d472015-10-26 14:35:56 +01001195 free(unres->node);
1196 free(unres->type);
Radek Krejci5449d472015-10-26 14:35:56 +01001197 free(unres);
1198
1199 return result;
1200}