Coverage Report

Created: 2025-08-03 06:36

/src/libyang/src/parser_json.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * @file parser_json.c
3
 * @author Radek Krejci <rkrejci@cesnet.cz>
4
 * @brief JSON data parser for libyang
5
 *
6
 * Copyright (c) 2020 CESNET, z.s.p.o.
7
 *
8
 * 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
11
 *
12
 *     https://opensource.org/licenses/BSD-3-Clause
13
 */
14
15
#define _GNU_SOURCE
16
17
#include <assert.h>
18
#include <stdint.h>
19
#include <stdlib.h>
20
#include <string.h>
21
22
#include "common.h"
23
#include "context.h"
24
#include "dict.h"
25
#include "in_internal.h"
26
#include "json.h"
27
#include "log.h"
28
#include "parser_data.h"
29
#include "parser_internal.h"
30
#include "set.h"
31
#include "tree.h"
32
#include "tree_data.h"
33
#include "tree_data_internal.h"
34
#include "tree_schema.h"
35
#include "tree_schema_internal.h"
36
#include "validation.h"
37
38
/**
39
 * @brief Internal context for JSON YANG data parser.
40
 *
41
 * Note that the structure maps to the lyd_ctx which is common for all the data parsers
42
 */
43
struct lyd_json_ctx {
44
    const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
45
    uint32_t parse_opts;           /**< various @ref dataparseroptions. */
46
    uint32_t val_opts;             /**< various @ref datavalidationoptions. */
47
    uint32_t int_opts;             /**< internal data parser options */
48
    uint32_t path_len;             /**< used bytes in the path buffer */
49
    char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
50
    struct ly_set node_when;       /**< set of nodes with "when" conditions */
51
    struct ly_set node_exts;       /**< set of nodes and extensions connected with a plugin providing own validation callback */
52
    struct ly_set node_types;      /**< set of nodes validated with LY_EINCOMPLETE result */
53
    struct ly_set meta_types;      /**< set of metadata validated with LY_EINCOMPLETE result */
54
    struct lyd_node *op_node;      /**< if an RPC/action/notification is being parsed, store the pointer to it */
55
56
    /* callbacks */
57
    lyd_ctx_free_clb free;           /* destructor */
58
59
    struct lyjson_ctx *jsonctx;    /**< JSON context */
60
};
61
62
/**
63
 * @brief Free the JSON data parser context.
64
 *
65
 * JSON implementation of lyd_ctx_free_clb().
66
 */
67
static void
68
lyd_json_ctx_free(struct lyd_ctx *lydctx)
69
0
{
70
0
    struct lyd_json_ctx *ctx = (struct lyd_json_ctx *)lydctx;
71
72
0
    if (lydctx) {
73
0
        lyd_ctx_free(lydctx);
74
0
        lyjson_ctx_free(ctx->jsonctx);
75
0
        free(ctx);
76
0
    }
77
0
}
78
79
/**
80
 * @brief Parse JSON member-name as [\@][prefix:][name]
81
 *
82
 * \@ - metadata flag, maps to 1 in @p is_meta_p
83
 * prefix - name of the module of the data node
84
 * name - name of the data node
85
 *
86
 * All the output parameter are mandatory. Function only parse the member-name, all the appropriate checks are up to the caller.
87
 *
88
 * @param[in] value String to parse
89
 * @param[in] value_len Length of the @p str.
90
 * @param[out] name_p Pointer to the beginning of the parsed name.
91
 * @param[out] name_len_p Pointer to the length of the parsed name.
92
 * @param[out] prefix_p Pointer to the beginning of the parsed prefix. If the member-name does not contain prefix, result is NULL.
93
 * @param[out] prefix_len_p Pointer to the length of the parsed prefix. If the member-name does not contain prefix, result is 0.
94
 * @param[out] is_meta_p Pointer to the metadata flag, set to 1 if the member-name contains \@, 0 otherwise.
95
 */
96
static void
97
lydjson_parse_name(const char *value, size_t value_len, const char **name_p, size_t *name_len_p, const char **prefix_p,
98
        size_t *prefix_len_p, ly_bool *is_meta_p)
99
0
{
100
0
    const char *name, *prefix = NULL;
101
0
    size_t name_len, prefix_len = 0;
102
0
    ly_bool is_meta = 0;
103
104
0
    name = memchr(value, ':', value_len);
105
0
    if (name != NULL) {
106
0
        prefix = value;
107
0
        if (*prefix == '@') {
108
0
            is_meta = 1;
109
0
            prefix++;
110
0
        }
111
0
        prefix_len = name - prefix;
112
0
        name++;
113
0
        name_len = value_len - (prefix_len + 1) - is_meta;
114
0
    } else {
115
0
        name = value;
116
0
        if (name[0] == '@') {
117
0
            is_meta = 1;
118
0
            name++;
119
0
        }
120
0
        name_len = value_len - is_meta;
121
0
    }
122
123
0
    *name_p = name;
124
0
    *name_len_p = name_len;
125
0
    *prefix_p = prefix;
126
0
    *prefix_len_p = prefix_len;
127
0
    *is_meta_p = is_meta;
128
0
}
129
130
/**
131
 * @brief Get correct prefix (module_name) inside the @p node.
132
 *
133
 * @param[in] node Data node to get inherited prefix.
134
 * @param[in] local_prefix Local prefix to replace the inherited prefix.
135
 * @param[in] local_prefix_len Length of the @p local_prefix string. In case of 0, the inherited prefix is taken.
136
 * @param[out] prefix_p Pointer to the resulting prefix string, Note that the result can be NULL in case of no local prefix
137
 * and no context @p node to get inherited prefix.
138
 * @param[out] prefix_len_p Pointer to the length of the resulting @p prefix_p string. Note that the result can be 0 in case
139
 * of no local prefix and no context @p node to get inherited prefix.
140
 * @return LY_ERR value.
141
 */
142
static LY_ERR
143
lydjson_get_node_prefix(struct lyd_node *node, const char *local_prefix, size_t local_prefix_len, const char **prefix_p,
144
        size_t *prefix_len_p)
145
0
{
146
0
    struct lyd_node_opaq *onode;
147
0
    const char *module_name = NULL;
148
149
0
    assert(prefix_p && prefix_len_p);
150
151
0
    if (local_prefix_len) {
152
0
        *prefix_p = local_prefix;
153
0
        *prefix_len_p = local_prefix_len;
154
0
        return LY_SUCCESS;
155
0
    }
156
157
0
    *prefix_p = NULL;
158
0
    while (node) {
159
0
        if (node->schema) {
160
0
            *prefix_p = node->schema->module->name;
161
0
            break;
162
0
        }
163
0
        onode = (struct lyd_node_opaq *)node;
164
0
        if (onode->name.module_name) {
165
0
            *prefix_p = onode->name.module_name;
166
0
            break;
167
0
        } else if (onode->name.prefix) {
168
0
            *prefix_p = onode->name.prefix;
169
0
            break;
170
0
        }
171
0
        node = lyd_parent(node);
172
0
    }
173
0
    *prefix_len_p = ly_strlen(module_name);
174
175
0
    return LY_SUCCESS;
176
0
}
177
178
/**
179
 * @brief Get schema node corresponding to the input parameters.
180
 *
181
 * @param[in] lydctx JSON data parser context.
182
 * @param[in] is_attr Flag if the reference to the node is an attribute, for logging only.
183
 * @param[in] prefix Requested node's prefix (module name).
184
 * @param[in] prefix_len Length of the @p prefix.
185
 * @param[in] name Requested node's name.
186
 * @param[in] name_len Length of the @p name.
187
 * @param[in] parent Parent of the node being processed, can be NULL in case of top-level.
188
 * @param[out] snode_p Pointer to the found schema node corresponding to the input parameters.
189
 * @return LY_SUCCES on success, note that even in this case the returned value of @p snode_p can be NULL, so the data are expected to be parsed as opaq.
190
 * @return LY_EVALID on failure, error message is logged
191
 * @return LY_ENOT in case the input data are expected to be skipped
192
 */
193
static LY_ERR
194
lydjson_get_snode(const struct lyd_json_ctx *lydctx, ly_bool is_attr, const char *prefix, size_t prefix_len, const char *name,
195
        size_t name_len, const struct lyd_node_inner *parent, const struct lysc_node **snode_p)
196
0
{
197
0
    LY_ERR ret = LY_SUCCESS;
198
0
    struct lys_module *mod = NULL;
199
0
    uint32_t getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
200
201
    /* init return value */
202
0
    *snode_p = NULL;
203
204
0
    LOG_LOCSET(NULL, &parent->node, NULL, NULL);
205
206
    /* get the element module */
207
0
    if (prefix_len) {
208
0
        mod = ly_ctx_get_module_implemented2(lydctx->jsonctx->ctx, prefix, prefix_len);
209
0
    } else if (parent) {
210
0
        if (parent->schema) {
211
0
            mod = parent->schema->module;
212
0
        }
213
0
    } else {
214
0
        LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX_JSON, "Top-level JSON object member \"%.*s\" must be namespace-qualified.",
215
0
                (int)(is_attr ? name_len + 1 : name_len), is_attr ? name - 1 : name);
216
0
        ret = LY_EVALID;
217
0
        goto cleanup;
218
0
    }
219
0
    if (!mod) {
220
0
        if (lydctx->parse_opts & LYD_PARSE_STRICT) {
221
0
            LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "No module named \"%.*s\" in the context.", (int)prefix_len, prefix);
222
0
            ret = LY_EVALID;
223
0
            goto cleanup;
224
0
        }
225
0
        if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
226
0
            ret = LY_ENOT;
227
0
            goto cleanup;
228
0
        }
229
0
    }
230
231
    /* get the schema node */
232
0
    if (mod && (!parent || parent->schema)) {
233
0
        if (!parent && lydctx->ext) {
234
0
            *snode_p = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
235
0
        } else {
236
0
            *snode_p = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
237
0
        }
238
0
        if (!*snode_p) {
239
0
            if (lydctx->parse_opts & LYD_PARSE_STRICT) {
240
0
                if (lydctx->ext) {
241
0
                    if (lydctx->ext->argument) {
242
0
                        LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
243
0
                                (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
244
0
                    } else {
245
0
                        LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
246
0
                                (int)name_len, name, lydctx->ext->def->name);
247
0
                    }
248
0
                } else {
249
0
                    LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
250
0
                            (int)name_len, name, mod->name);
251
0
                }
252
0
                ret = LY_EVALID;
253
0
                goto cleanup;
254
0
            } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
255
                /* skip element with children */
256
0
                ret = LY_ENOT;
257
0
                goto cleanup;
258
0
            }
259
0
        } else {
260
            /* check that schema node is valid and can be used */
261
0
            ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode_p);
262
0
        }
263
0
    }
264
265
0
cleanup:
266
0
    LOG_LOCBACK(0, parent ? 1 : 0, 0, 0);
267
0
    return ret;
268
0
}
269
270
/**
271
 * @brief Skip the currently open JSON object/array
272
 * @param[in] jsonctx JSON context with the input data to skip.
273
 * @return LY_ERR value.
274
 */
275
static LY_ERR
276
lydjson_data_skip(struct lyjson_ctx *jsonctx)
277
0
{
278
0
    enum LYJSON_PARSER_STATUS status, current;
279
0
    size_t sublevels = 1;
280
281
0
    status = lyjson_ctx_status(jsonctx, 0);
282
283
    /* skip after the content */
284
0
    do {
285
0
        LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
286
0
        if (current == status) {
287
0
            sublevels++;
288
0
        } else if (current == status + 1) {
289
0
            sublevels--;
290
0
        }
291
0
    } while (current != status + 1 || sublevels);
292
    /* open the next sibling */
293
0
    LY_CHECK_RET(lyjson_ctx_next(jsonctx, NULL));
294
295
0
    return LY_SUCCESS;
296
0
}
297
298
/**
299
 * @brief Check that the input data are parseable as the @p list.
300
 *
301
 * Checks for all the list's keys. Function does not revert the context state.
302
 *
303
 * @param[in] jsonctx JSON parser context.
304
 * @param[in] list List schema node corresponding to the input data object.
305
 * @return LY_SUCCESS in case the data are ok for the @p list
306
 * @return LY_ENOT in case the input data are not sufficient to fully parse the list instance.
307
 */
308
static LY_ERR
309
lydjson_check_list(struct lyjson_ctx *jsonctx, const struct lysc_node *list)
310
0
{
311
0
    LY_ERR ret = LY_SUCCESS;
312
0
    enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx, 0);
313
0
    struct ly_set key_set = {0};
314
0
    const struct lysc_node *snode;
315
0
    uint32_t i, status_count;
316
317
0
    assert(list && (list->nodetype == LYS_LIST));
318
0
    assert(status == LYJSON_OBJECT);
319
320
    /* get all keys into a set (keys do not have if-features or anything) */
321
0
    snode = NULL;
322
0
    while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
323
0
        ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
324
0
        LY_CHECK_GOTO(ret, cleanup);
325
0
    }
326
327
0
    if (status != LYJSON_OBJECT_EMPTY) {
328
0
        status_count = jsonctx->status.count;
329
330
0
        while (key_set.count && status != LYJSON_OBJECT_CLOSED) {
331
0
            const char *name, *prefix;
332
0
            size_t name_len, prefix_len;
333
0
            ly_bool is_attr;
334
335
            /* match the key */
336
0
            snode = NULL;
337
0
            lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
338
339
0
            if (!is_attr && !prefix) {
340
0
                for (i = 0; i < key_set.count; ++i) {
341
0
                    snode = (const struct lysc_node *)key_set.objs[i];
342
0
                    if (!ly_strncmp(snode->name, name, name_len)) {
343
0
                        break;
344
0
                    }
345
0
                }
346
                /* go into the item to a) process it as a key or b) start skipping it as another list child */
347
0
                ret = lyjson_ctx_next(jsonctx, &status);
348
0
                LY_CHECK_GOTO(ret, cleanup);
349
350
0
                if (snode) {
351
                    /* we have the key, validate the value */
352
0
                    if (status < LYJSON_NUMBER) {
353
                        /* not a terminal */
354
0
                        ret = LY_ENOT;
355
0
                        goto cleanup;
356
0
                    }
357
358
0
                    ret = lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL);
359
0
                    LY_CHECK_GOTO(ret, cleanup);
360
361
                    /* key with a valid value, remove from the set */
362
0
                    ly_set_rm_index(&key_set, i, NULL);
363
0
                }
364
0
            } else {
365
                /* start skipping the member we are not interested in */
366
0
                ret = lyjson_ctx_next(jsonctx, &status);
367
0
                LY_CHECK_GOTO(ret, cleanup);
368
0
            }
369
            /* move to the next child */
370
0
            while (status_count < jsonctx->status.count) {
371
0
                ret = lyjson_ctx_next(jsonctx, &status);
372
0
                LY_CHECK_GOTO(ret, cleanup);
373
0
            }
374
0
        }
375
0
    }
376
377
0
    if (key_set.count) {
378
        /* some keys are missing/did not validate */
379
0
        ret = LY_ENOT;
380
0
    }
381
382
0
cleanup:
383
0
    ly_set_erase(&key_set, NULL);
384
0
    return ret;
385
0
}
386
387
/**
388
 * @brief Get the hint for the data type parsers according to the current JSON parser context.
389
 *
390
 * @param[in] lydctx JSON data parser context. The context is supposed to be on a value.
391
 * @param[in,out] status Pointer to the current context status,
392
 * in some circumstances the function manipulates with the context so the status is updated.
393
 * @param[out] type_hint_p Pointer to the variable to store the result.
394
 * @return LY_SUCCESS in case of success.
395
 * @return LY_EINVAL in case of invalid context status not referring to a value.
396
 */
397
static LY_ERR
398
lydjson_value_type_hint(struct lyd_json_ctx *lydctx, enum LYJSON_PARSER_STATUS *status_p, uint32_t *type_hint_p)
399
0
{
400
0
    *type_hint_p = 0;
401
402
0
    if (*status_p == LYJSON_ARRAY) {
403
        /* only [null] */
404
0
        LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_p));
405
0
        LY_CHECK_RET(*status_p != LYJSON_NULL, LY_EINVAL);
406
407
0
        LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, NULL));
408
0
        LY_CHECK_RET(lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_ARRAY_CLOSED, LY_EINVAL);
409
410
0
        *type_hint_p = LYD_VALHINT_EMPTY;
411
0
    } else if (*status_p == LYJSON_STRING) {
412
0
        *type_hint_p = LYD_VALHINT_STRING | LYD_VALHINT_NUM64;
413
0
    } else if (*status_p == LYJSON_NUMBER) {
414
0
        *type_hint_p = LYD_VALHINT_DECNUM;
415
0
    } else if ((*status_p == LYJSON_FALSE) || (*status_p == LYJSON_TRUE)) {
416
0
        *type_hint_p = LYD_VALHINT_BOOLEAN;
417
0
    } else if (*status_p == LYJSON_NULL) {
418
0
        *type_hint_p = 0;
419
0
    } else {
420
0
        return LY_EINVAL;
421
0
    }
422
423
0
    return LY_SUCCESS;
424
0
}
425
426
/**
427
 * @brief Check in advance if the input data are parsable according to the provided @p snode.
428
 *
429
 * Note that the checks are done only in case the LYD_PARSE_OPAQ is allowed. Otherwise the same checking
430
 * is naturally done when the data are really parsed.
431
 *
432
 * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
433
 * as before calling, despite it is necessary to process input data for checking.
434
 * @param[in] snode Schema node corresponding to the member currently being processed in the context.
435
 * @param[out] type_hint_p Pointer to a variable to store detected value type hint in case of leaf or leaf-list.
436
 * @return LY_SUCCESS in case the data are ok for the @p snode or the LYD_PARSE_OPAQ is not enabled.
437
 * @return LY_ENOT in case the input data are not sufficient to fully parse the list instance
438
 * @return LY_EINVAL in case of invalid leaf JSON encoding
439
 * and they are expected to be parsed as opaq nodes.
440
 */
441
static LY_ERR
442
lydjson_data_check_opaq(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, uint32_t *type_hint_p)
443
0
{
444
0
    LY_ERR ret = LY_SUCCESS;
445
0
    struct lyjson_ctx *jsonctx = lydctx->jsonctx;
446
0
    enum LYJSON_PARSER_STATUS status;
447
448
0
    assert(snode);
449
450
0
    if (!(snode->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
451
        /* can always be parsed as a data node if we have the schema node */
452
0
        return LY_SUCCESS;
453
0
    }
454
455
0
    if (lydctx->parse_opts & LYD_PARSE_OPAQ) {
456
        /* backup parser */
457
0
        lyjson_ctx_backup(jsonctx);
458
0
        status = lyjson_ctx_status(jsonctx, 0);
459
460
        /* check if the node is parseable. if not, NULL the snode to announce that it is supposed to be parsed
461
         * as an opaq node */
462
0
        switch (snode->nodetype) {
463
0
        case LYS_LEAFLIST:
464
0
        case LYS_LEAF:
465
            /* value may not be valid in which case we parse it as an opaque node */
466
0
            ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
467
0
            if (ret) {
468
0
                break;
469
0
            }
470
471
0
            if (lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL)) {
472
0
                ret = LY_ENOT;
473
0
            }
474
0
            break;
475
0
        case LYS_LIST:
476
            /* lists may not have all its keys */
477
0
            if (lydjson_check_list(jsonctx, snode)) {
478
                /* invalid list, parse as opaque if it missing/has invalid some keys */
479
0
                ret = LY_ENOT;
480
0
            }
481
0
            break;
482
0
        }
483
484
        /* restore parser */
485
0
        lyjson_ctx_restore(jsonctx);
486
0
    } else if (snode->nodetype & LYD_NODE_TERM) {
487
0
        status = lyjson_ctx_status(jsonctx, 0);
488
0
        ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
489
0
    }
490
491
0
    return ret;
492
0
}
493
494
/**
495
 * @brief Join the forward-referencing metadata with their target data nodes.
496
 *
497
 * Note that JSON encoding for YANG data allows forward-referencing metadata only for leafs/leaf-lists.
498
 *
499
 * @param[in] lydctx JSON data parser context.
500
 * @param[in,out] first_p Pointer to the first sibling node variable (top-level or in a particular parent node)
501
 * as a starting point to search for the metadata's target data node
502
 * @return LY_SUCCESS on success
503
 * @return LY_EVALID in case there are some metadata with unresolved target data node instance
504
 */
505
static LY_ERR
506
lydjson_metadata_finish(struct lyd_json_ctx *lydctx, struct lyd_node **first_p)
507
0
{
508
0
    LY_ERR ret = LY_SUCCESS;
509
0
    struct lyd_node *node, *attr, *next, *start = *first_p, *meta_iter;
510
0
    uint64_t instance = 0;
511
0
    const char *prev = NULL;
512
0
    uint32_t log_location_items = 0;
513
514
    /* finish linking metadata */
515
0
    LY_LIST_FOR_SAFE(*first_p, next, attr) {
516
0
        struct lyd_node_opaq *meta_container = (struct lyd_node_opaq *)attr;
517
0
        uint64_t match = 0;
518
0
        ly_bool is_attr;
519
0
        const char *name, *prefix;
520
0
        size_t name_len, prefix_len;
521
0
        const struct lysc_node *snode;
522
523
0
        if (attr->schema || (meta_container->name.name[0] != '@')) {
524
            /* not an opaq metadata node */
525
0
            continue;
526
0
        }
527
528
0
        LOG_LOCSET(NULL, attr, NULL, NULL);
529
0
        log_location_items++;
530
531
0
        if (prev != meta_container->name.name) {
532
            /* metas' names are stored in dictionary, so checking pointers must works */
533
0
            lydict_remove(lydctx->jsonctx->ctx, prev);
534
0
            LY_CHECK_GOTO(ret = lydict_insert(lydctx->jsonctx->ctx, meta_container->name.name, 0, &prev), cleanup);
535
0
            instance = 1;
536
0
        } else {
537
0
            instance++;
538
0
        }
539
540
        /* find the correspnding data node */
541
0
        LY_LIST_FOR(start, node) {
542
0
            if (!node->schema) {
543
                /* opaq node - we are going to put into it just a generic attribute. */
544
0
                if (strcmp(&meta_container->name.name[1], ((struct lyd_node_opaq *)node)->name.name)) {
545
0
                    continue;
546
0
                }
547
548
0
                if (((struct lyd_node_opaq *)node)->hints & LYD_NODEHINT_LIST) {
549
0
                    LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX, "Metadata container references a sibling list node %s.",
550
0
                            ((struct lyd_node_opaq *)node)->name.name);
551
0
                    ret = LY_EVALID;
552
0
                    goto cleanup;
553
0
                }
554
555
                /* match */
556
0
                match++;
557
0
                if (match != instance) {
558
0
                    continue;
559
0
                }
560
561
0
                LY_LIST_FOR(meta_container->child, meta_iter) {
562
                    /* convert opaq node to a attribute of the opaq node */
563
0
                    struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
564
565
0
                    ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, meta->name.name, strlen(meta->name.name),
566
0
                            meta->name.prefix, ly_strlen(meta->name.prefix), meta->name.module_name,
567
0
                            ly_strlen(meta->name.module_name), meta->value, ly_strlen(meta->value), NULL, LY_VALUE_JSON,
568
0
                            NULL, meta->hints);
569
0
                    LY_CHECK_GOTO(ret, cleanup);
570
0
                }
571
572
                /* done */
573
0
                break;
574
0
            } else {
575
                /* this is the second time we are resolving the schema node, so it must succeed,
576
                 * but remember that snode can be still NULL */
577
0
                lydjson_parse_name(meta_container->name.name, strlen(meta_container->name.name), &name, &name_len,
578
0
                        &prefix, &prefix_len, &is_attr);
579
0
                assert(is_attr);
580
0
                ret = lydjson_get_snode(lydctx, is_attr, prefix, prefix_len, name, name_len, (*first_p)->parent, &snode);
581
0
                assert(ret == LY_SUCCESS);
582
583
0
                if (snode != node->schema) {
584
0
                    continue;
585
0
                }
586
587
                /* match */
588
0
                match++;
589
0
                if (match != instance) {
590
0
                    continue;
591
0
                }
592
593
0
                LY_LIST_FOR(meta_container->child, meta_iter) {
594
                    /* convert opaq node to a metadata of the node */
595
0
                    struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
596
0
                    struct lys_module *mod = NULL;
597
0
                    ly_bool dynamic = 0;
598
599
0
                    mod = ly_ctx_get_module_implemented(lydctx->jsonctx->ctx, meta->name.prefix);
600
0
                    if (mod) {
601
0
                        ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod,
602
0
                                meta->name.name, strlen(meta->name.name), meta->value, ly_strlen(meta->value),
603
0
                                &dynamic, LY_VALUE_JSON, NULL, meta->hints);
604
0
                        LY_CHECK_GOTO(ret, cleanup);
605
0
                    } else if (lydctx->parse_opts & LYD_PARSE_STRICT) {
606
0
                        LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE,
607
0
                                "Unknown (or not implemented) YANG module \"%s\" for metadata \"%s%s%s\".",
608
0
                                meta->name.prefix, meta->name.prefix, ly_strlen(meta->name.prefix) ? ":" : "", meta->name.name);
609
0
                        ret = LY_EVALID;
610
0
                        goto cleanup;
611
0
                    }
612
0
                }
613
                /* add/correct flags */
614
0
                lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &node->meta, lydctx->parse_opts);
615
616
                /* done */
617
0
                break;
618
0
            }
619
0
        }
620
621
0
        if (match != instance) {
622
            /* there is no corresponding data node for the metadata */
623
0
            if (instance > 1) {
624
0
                LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Missing %d%s JSON data instance to be coupled with %s metadata.",
625
0
                        instance, instance == 2 ? "nd" : (instance == 3 ? "rd" : "th"), meta_container->name.name);
626
0
            } else {
627
0
                LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Missing JSON data instance to be coupled with %s metadata.",
628
0
                        meta_container->name.name);
629
0
            }
630
0
            ret = LY_EVALID;
631
0
        } else {
632
            /* remove the opaq attr */
633
0
            if (attr == (*first_p)) {
634
0
                *first_p = attr->next;
635
0
            }
636
0
            lyd_free_tree(attr);
637
0
        }
638
639
0
        LOG_LOCBACK(0, log_location_items, 0, 0);
640
0
        log_location_items = 0;
641
0
    }
642
643
0
cleanup:
644
0
    lydict_remove(lydctx->jsonctx->ctx, prev);
645
646
0
    LOG_LOCBACK(0, log_location_items, 0, 0);
647
0
    return ret;
648
0
}
649
650
/**
651
 * @brief Parse a metadata member.
652
 *
653
 * @param[in] lydctx JSON data parser context.
654
 * @param[in] snode Schema node of the metadata parent.
655
 * @param[in] node Parent node in case the metadata is not forward-referencing (only LYD_NODE_TERM)
656
 * so the data node does not exists. In such a case the metadata is stored in the context for the later
657
 * processing by lydjson_metadata_finish().
658
 * @return LY_SUCCESS on success
659
 * @return Various LY_ERR values in case of failure.
660
 */
661
static LY_ERR
662
lydjson_metadata(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, struct lyd_node *node)
663
0
{
664
0
    LY_ERR ret = LY_SUCCESS;
665
0
    enum LYJSON_PARSER_STATUS status;
666
0
    const char *expected;
667
0
    ly_bool in_parent = 0;
668
0
    const char *name, *prefix = NULL;
669
0
    size_t name_len, prefix_len = 0;
670
0
    struct lys_module *mod;
671
0
    struct lyd_meta *meta = NULL;
672
0
    const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
673
0
    ly_bool is_attr = 0;
674
0
    struct lyd_node *prev = node;
675
0
    uint32_t instance = 0;
676
0
    uint16_t nodetype;
677
678
0
    assert(snode || node);
679
680
0
    nodetype = snode ? snode->nodetype : LYS_CONTAINER;
681
682
    /* move to the second item in the name/X pair */
683
0
    ret = lyjson_ctx_next(lydctx->jsonctx, &status);
684
0
    LY_CHECK_GOTO(ret, cleanup);
685
686
    /* check attribute encoding */
687
0
    switch (nodetype) {
688
0
    case LYS_LEAFLIST:
689
0
        expected = "@name/array of objects/nulls";
690
691
0
        LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
692
693
0
next_entry:
694
0
        instance++;
695
696
        /* move into array / next entry */
697
0
        ret = lyjson_ctx_next(lydctx->jsonctx, &status);
698
0
        LY_CHECK_GOTO(ret, cleanup);
699
700
0
        if (status == LYJSON_ARRAY_CLOSED) {
701
            /* we are done, move after the array */
702
0
            ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
703
0
            goto cleanup;
704
0
        }
705
0
        LY_CHECK_GOTO(status != LYJSON_OBJECT && status != LYJSON_NULL, representation_error);
706
707
0
        if (!node || (node->schema != prev->schema)) {
708
0
            LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Missing JSON data instance no. %u of %s:%s to be coupled with metadata.",
709
0
                    instance, prev->schema->module->name, prev->schema->name);
710
0
            ret = LY_EVALID;
711
0
            goto cleanup;
712
0
        }
713
714
0
        if (status == LYJSON_NULL) {
715
            /* continue with the next entry in the leaf-list array */
716
0
            prev = node;
717
0
            node = node->next;
718
0
            goto next_entry;
719
0
        }
720
0
        break;
721
0
    case LYS_LEAF:
722
0
    case LYS_ANYXML:
723
0
        expected = "@name/object";
724
725
0
        LY_CHECK_GOTO(status != LYJSON_OBJECT && (nodetype != LYS_LEAFLIST || status != LYJSON_NULL), representation_error);
726
0
        break;
727
0
    case LYS_CONTAINER:
728
0
    case LYS_LIST:
729
0
    case LYS_ANYDATA:
730
0
    case LYS_NOTIF:
731
0
    case LYS_ACTION:
732
0
    case LYS_RPC:
733
0
        in_parent = 1;
734
0
        expected = "@/object";
735
0
        LY_CHECK_GOTO(status != LYJSON_OBJECT, representation_error);
736
0
        break;
737
0
    default:
738
0
        LOGINT_RET(ctx);
739
0
    }
740
741
    /* process all the members inside a single metadata object */
742
0
    assert(status == LYJSON_OBJECT);
743
744
0
    LOG_LOCSET(snode, NULL, NULL, NULL);
745
746
0
    while (status != LYJSON_OBJECT_CLOSED) {
747
0
        lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
748
0
        if (!prefix) {
749
0
            LOGVAL(ctx, LYVE_SYNTAX_JSON, "Metadata in JSON must be namespace-qualified, missing prefix for \"%.*s\".",
750
0
                    (int)lydctx->jsonctx->value_len, lydctx->jsonctx->value);
751
0
            ret = LY_EVALID;
752
0
            goto cleanup;
753
0
        } else if (is_attr) {
754
0
            LOGVAL(ctx, LYVE_SYNTAX_JSON, "Invalid format of the Metadata identifier in JSON, unexpected '@' in \"%.*s\"",
755
0
                    (int)lydctx->jsonctx->value_len, lydctx->jsonctx->value);
756
0
            ret = LY_EVALID;
757
0
            goto cleanup;
758
0
        }
759
760
        /* get the element module */
761
0
        mod = ly_ctx_get_module_implemented2(ctx, prefix, prefix_len);
762
0
        if (!mod) {
763
0
            if (lydctx->parse_opts & LYD_PARSE_STRICT) {
764
0
                LOGVAL(ctx, LYVE_REFERENCE, "Prefix \"%.*s\" of the metadata \"%.*s\" does not match any module in the context.",
765
0
                        (int)prefix_len, prefix, (int)name_len, name);
766
0
                ret = LY_EVALID;
767
0
                goto cleanup;
768
0
            }
769
0
            if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
770
                /* skip element with children */
771
0
                ret = lydjson_data_skip(lydctx->jsonctx);
772
0
                LY_CHECK_GOTO(ret, cleanup);
773
0
                status = lyjson_ctx_status(lydctx->jsonctx, 0);
774
                /* end of the item */
775
0
                continue;
776
0
            }
777
0
        }
778
779
        /* get the value */
780
0
        ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
781
0
        LY_CHECK_GOTO(ret, cleanup);
782
783
0
        if (node->schema) {
784
            /* create metadata */
785
0
            meta = NULL;
786
0
            ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, &meta, mod, name, name_len, lydctx->jsonctx->value,
787
0
                    lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL,
788
0
                    LYD_HINT_DATA);
789
0
            LY_CHECK_GOTO(ret, cleanup);
790
791
            /* add/correct flags */
792
0
            lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
793
0
        } else {
794
            /* create attribute */
795
0
            const char *module_name;
796
0
            size_t module_name_len;
797
798
0
            lydjson_get_node_prefix(node, prefix, prefix_len, &module_name, &module_name_len);
799
800
            /* attr2 is always changed to the created attribute */
801
0
            ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, module_name,
802
0
                    module_name_len, lydctx->jsonctx->value, lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic,
803
0
                    LY_VALUE_JSON, NULL, 0);
804
0
            LY_CHECK_GOTO(ret, cleanup);
805
0
        }
806
        /* next member */
807
0
        ret = lyjson_ctx_next(lydctx->jsonctx, &status);
808
0
        LY_CHECK_GOTO(ret, cleanup);
809
0
    }
810
811
0
    if (nodetype == LYS_LEAFLIST) {
812
        /* continue by processing another metadata object for the following
813
         * leaf-list instance since they are allways instantiated in JSON array */
814
0
        prev = node;
815
0
        node = node->next;
816
0
        goto next_entry;
817
0
    }
818
819
    /* move after the metadata */
820
0
    ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
821
0
    LY_CHECK_GOTO(ret, cleanup);
822
823
    /* success */
824
0
    goto cleanup;
825
826
0
representation_error:
827
0
    LOGVAL(ctx, LYVE_SYNTAX_JSON,
828
0
            "The attribute(s) of %s \"%s\" is expected to be represented as JSON %s, but input data contains @%s/%s.",
829
0
            lys_nodetype2str(nodetype), node->schema ? node->schema->name : ((struct lyd_node_opaq *)node)->name.name,
830
0
            expected, lyjson_token2str(status), in_parent ? "" : "name");
831
832
0
    ret = LY_EVALID;
833
834
0
cleanup:
835
0
    LOG_LOCBACK(1, 0, 0, 0);
836
0
    return ret;
837
0
}
838
839
/**
840
 * @brief Eat the node pointed by @p node_p by inserting it into @p parent and maintain the @p first_p pointing to the first child node.
841
 *
842
 * @param[in] parent Parent node to insert to, can be NULL in case of top-level (or provided first_p).
843
 * @param[in, out] first_p Pointer to the first sibling node in case of top-level.
844
 * @param[in, out] node_p pointer to the new node to insert, after the insert is done, pointer is set to NULL.
845
 */
846
static void
847
lydjson_maintain_children(struct lyd_node_inner *parent, struct lyd_node **first_p, struct lyd_node **node_p)
848
0
{
849
0
    if (*node_p) {
850
        /* insert, keep first pointer correct */
851
0
        lyd_insert_node(&parent->node, first_p, *node_p);
852
0
        if (first_p) {
853
0
            if (parent) {
854
0
                *first_p = parent->child;
855
0
            } else {
856
0
                while ((*first_p)->prev->next) {
857
0
                    *first_p = (*first_p)->prev;
858
0
                }
859
0
            }
860
0
        }
861
0
        *node_p = NULL;
862
0
    }
863
0
}
864
865
static LY_ERR lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p,
866
        struct ly_set *parsed);
867
868
/**
869
 * @brief Parse opaq node from the input.
870
 *
871
 * In case of processing array, the whole array is being processed and the resulting @p node_p is the last item of the array.
872
 *
873
 * @param[in] lydctx JSON data parser context.
874
 * @param[in] name Name of the opaq node to create.
875
 * @param[in] name_len Length of the @p name string.
876
 * @param[in] prefix Prefix of the opaq node to create.
877
 * @param[in] prefix_len Length of the @p prefx string.
878
 * @param[in] parent Data parent of the opaq node to create, can be NULL in case of top level,
879
 * but must be set if @p first is not.
880
 * @param[in,out] status_p Pointer to the current status of the parser context,
881
 * since the function manipulates with the context and process the input, the status can be updated.
882
 * @param[in,out] status_inner_p In case of processing JSON array, this parameter points to a standalone
883
 * context status of the array content. Otherwise, it is supposed to be the same as @p status_p.
884
 * @param[in,out] first_p First top-level/parent sibling, must be set if @p parent is not.
885
 * @param[out] node_p Pointer to the created opaq node.
886
 * @return LY_ERR value.
887
 */
888
static LY_ERR
889
lydjson_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
890
        struct lyd_node_inner *parent, enum LYJSON_PARSER_STATUS *status_p,
891
        enum LYJSON_PARSER_STATUS *status_inner_p, struct lyd_node **first_p, struct lyd_node **node_p)
892
0
{
893
0
    LY_ERR ret = LY_SUCCESS;
894
0
    const char *value = NULL, *module_name;
895
0
    size_t value_len = 0, module_name_len = 0;
896
0
    ly_bool dynamic = 0;
897
0
    uint32_t type_hint = 0;
898
899
0
    if ((*status_inner_p != LYJSON_OBJECT) && (*status_inner_p != LYJSON_OBJECT_EMPTY)) {
900
        /* prepare for creating opaq node with a value */
901
0
        value = lydctx->jsonctx->value;
902
0
        value_len = lydctx->jsonctx->value_len;
903
0
        dynamic = lydctx->jsonctx->dynamic;
904
0
        lydctx->jsonctx->dynamic = 0;
905
906
0
        LY_CHECK_RET(lydjson_value_type_hint(lydctx, status_inner_p, &type_hint));
907
0
    }
908
909
    /* create node */
910
0
    lydjson_get_node_prefix(&parent->node, prefix, prefix_len, &module_name, &module_name_len);
911
0
    ret = lyd_create_opaq(lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, module_name, module_name_len, value,
912
0
            value_len, &dynamic, LY_VALUE_JSON, NULL, type_hint, node_p);
913
0
    if (dynamic) {
914
0
        free((char *)value);
915
0
    }
916
0
    LY_CHECK_RET(ret);
917
918
0
    if ((*status_p == LYJSON_OBJECT) || (*status_p == LYJSON_OBJECT_EMPTY)) {
919
        /* process children */
920
0
        while (*status_p != LYJSON_OBJECT_CLOSED && *status_p != LYJSON_OBJECT_EMPTY) {
921
0
            LY_CHECK_RET(lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL));
922
0
            *status_p = lyjson_ctx_status(lydctx->jsonctx, 0);
923
0
        }
924
0
    } else if ((*status_p == LYJSON_ARRAY) || (*status_p == LYJSON_ARRAY_EMPTY)) {
925
        /* process another instance of the same node */
926
        /* but first mark the node to be expected a list or a leaf-list */
927
0
        ((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST;
928
929
0
        if ((*status_inner_p == LYJSON_OBJECT) || (*status_inner_p == LYJSON_OBJECT_EMPTY)) {
930
            /* but first process children of the object in the array */
931
0
            while (*status_inner_p != LYJSON_OBJECT_CLOSED && *status_inner_p != LYJSON_OBJECT_EMPTY) {
932
0
                LY_CHECK_RET(lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL));
933
0
                *status_inner_p = lyjson_ctx_status(lydctx->jsonctx, 0);
934
0
            }
935
0
        }
936
937
0
        LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_inner_p));
938
939
        /* continue with the next instance */
940
0
        if (*status_inner_p != LYJSON_ARRAY_CLOSED) {
941
0
            assert(node_p);
942
0
            lydjson_maintain_children(parent, first_p, node_p);
943
0
            return lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_p, status_inner_p,
944
0
                    first_p, node_p);
945
0
        }
946
0
    }
947
948
    /* finish linking metadata */
949
0
    LY_CHECK_RET(lydjson_metadata_finish(lydctx, lyd_node_child_p(*node_p)));
950
951
    /* move after the item */
952
0
    return lyjson_ctx_next(lydctx->jsonctx, status_p);
953
0
}
954
955
/**
956
 * @brief Process the attribute container (starting by @)
957
 *
958
 * @param[in] lydctx JSON data parser context.
959
 * @param[in] attr_node The data node referenced by the attribute container, if already known.
960
 * @param[in] snode The schema node of the data node referenced by the attribute container, if known.
961
 * @param[in] name Name of the opaq node to create.
962
 * @param[in] name_len Length of the @p name string.
963
 * @param[in] prefix Prefix of the opaq node to create.
964
 * @param[in] prefix_len Length of the @p prefx string.
965
 * @param[in] parent Data parent of the opaq node to create, can be NULL in case of top level,
966
 * but must be set if @p first is not.
967
 * @param[in,out] status_p Pointer to the current status of the parser context,
968
 * since the function manipulates with the context and process the input, the status can be updated.
969
 * @param[in,out] first_p First top-level/parent sibling, must be set if @p parent is not.
970
 * @param[out] node_p Pointer to the created opaq node.
971
 * @return LY_ERR value.
972
 */
973
static LY_ERR
974
lydjson_parse_attribute(struct lyd_json_ctx *lydctx, struct lyd_node *attr_node, const struct lysc_node *snode,
975
        const char *name, size_t name_len, const char *prefix, size_t prefix_len, struct lyd_node *parent,
976
        enum LYJSON_PARSER_STATUS *status_p, struct lyd_node **first_p, struct lyd_node **node_p)
977
0
{
978
0
    LY_ERR ret = LY_SUCCESS;
979
0
    enum LYJSON_PARSER_STATUS status_inner;
980
981
    /* parse as an attribute to a node */
982
0
    if (!attr_node && snode) {
983
        /* try to find the instance */
984
0
        for (struct lyd_node *iter = *first_p; iter; iter = iter->next) {
985
0
            if (iter->schema == snode) {
986
0
                attr_node = iter;
987
0
                break;
988
0
            }
989
0
        }
990
0
    }
991
0
    if (!attr_node) {
992
        /* parse just as an opaq node with the name beginning with @,
993
         * later we have to check that it belongs to a standard node
994
         * and it is supposed to be converted to a metadata */
995
0
        uint32_t prev_opts;
996
997
        /* move into metadata */
998
0
        LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_p));
999
1000
0
        if (*status_p == LYJSON_ARRAY) {
1001
            /* move into the array */
1002
0
            LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, &status_inner));
1003
0
        } else {
1004
            /* just a flag to pass correct parameters into lydjson_parse_opaq() */
1005
0
            status_inner = LYJSON_ERROR;
1006
0
        }
1007
1008
        /* backup parser options to parse unknown metadata as opaq nodes and try to resolve them later */
1009
0
        prev_opts = lydctx->parse_opts;
1010
0
        lydctx->parse_opts &= ~LYD_PARSE_STRICT;
1011
0
        lydctx->parse_opts |= LYD_PARSE_OPAQ;
1012
1013
0
        ret = lydjson_parse_opaq(lydctx, prefix ? prefix - 1 : name - 1, prefix ? prefix_len + name_len + 2 : name_len + 1,
1014
0
                NULL, 0, (struct lyd_node_inner *)parent, status_p, status_inner == LYJSON_ERROR ? status_p : &status_inner,
1015
0
                first_p, node_p);
1016
1017
        /* restore the parser options */
1018
0
        lydctx->parse_opts = prev_opts;
1019
0
    } else {
1020
0
        ret = lydjson_metadata(lydctx, snode, attr_node);
1021
0
    }
1022
1023
0
    return ret;
1024
0
}
1025
1026
/**
1027
 * @brief Parse a single instance of a node.
1028
 *
1029
 * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
1030
 * as before calling, despite it is necessary to process input data for checking.
1031
 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
1032
 * @param[in,out] first_p Pointer to the variable holding the first top-level sibling, must be set if @p parent is not.
1033
 * @param[in] snode Schema node corresponding to the member currently being processed in the context.
1034
 * @param[in] name Parsed JSON node name.
1035
 * @param[in] name_len Lenght of @p name.
1036
 * @param[in] prefix Parsed JSON node prefix.
1037
 * @param[in] prefix_len Length of @p prefix.
1038
 * @param[in,out] status JSON parser status, is updated.
1039
 * @param[out] node Parsed data (or opaque) node.
1040
 * @return LY_SUCCESS if a node was successfully parsed,
1041
 * @return LY_EINVAL in case of invalid JSON encoding,
1042
 * @return LY_ERR on other errors.
1043
 */
1044
static LY_ERR
1045
lydjson_parse_instance(struct lyd_json_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p,
1046
        const struct lysc_node *snode, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
1047
        enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
1048
0
{
1049
0
    LY_ERR ret;
1050
0
    uint32_t type_hints = 0;
1051
0
    uint32_t prev_opts;
1052
0
    struct lyd_node *tree = NULL;
1053
1054
0
    ret = lydjson_data_check_opaq(lydctx, snode, &type_hints);
1055
0
    if (ret == LY_SUCCESS) {
1056
0
        assert(snode->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER | LYD_NODE_ANY));
1057
0
        if (snode->nodetype & LYD_NODE_TERM) {
1058
            /* create terminal node */
1059
0
            ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, lydctx->jsonctx->value,
1060
0
                    lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL,
1061
0
                    type_hints, node);
1062
0
            LY_CHECK_RET(ret);
1063
1064
            /* move JSON parser */
1065
0
            ret = lyjson_ctx_next(lydctx->jsonctx, status);
1066
0
            LY_CHECK_RET(ret);
1067
0
        } else if (snode->nodetype & LYD_NODE_INNER) {
1068
            /* create inner node */
1069
0
            LY_CHECK_RET(*status != LYJSON_OBJECT && *status != LYJSON_OBJECT_EMPTY, LY_EINVAL);
1070
1071
0
            ret = lyd_create_inner(snode, node);
1072
0
            LY_CHECK_RET(ret);
1073
1074
0
            LOG_LOCSET(snode, *node, NULL, NULL);
1075
1076
            /* process children */
1077
0
            while (*status != LYJSON_OBJECT_CLOSED && *status != LYJSON_OBJECT_EMPTY) {
1078
0
                ret = lydjson_subtree_r(lydctx, *node, lyd_node_child_p(*node), NULL);
1079
0
                LY_CHECK_ERR_RET(ret, LOG_LOCBACK(1, 1, 0, 0), ret);
1080
0
                *status = lyjson_ctx_status(lydctx->jsonctx, 0);
1081
0
            }
1082
1083
            /* finish linking metadata */
1084
0
            ret = lydjson_metadata_finish(lydctx, lyd_node_child_p(*node));
1085
0
            LY_CHECK_ERR_RET(ret, LOG_LOCBACK(1, 1, 0, 0), ret);
1086
1087
0
            if (snode->nodetype == LYS_LIST) {
1088
                /* check all keys exist */
1089
0
                ret = lyd_parse_check_keys(*node);
1090
0
                LY_CHECK_ERR_RET(ret, LOG_LOCBACK(1, 1, 0, 0), ret);
1091
0
            }
1092
1093
0
            if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
1094
                /* new node validation, autodelete CANNOT occur, all nodes are new */
1095
0
                ret = lyd_validate_new(lyd_node_child_p(*node), snode, NULL, NULL);
1096
0
                LY_CHECK_ERR_RET(ret, LOG_LOCBACK(1, 1, 0, 0), ret);
1097
1098
                /* add any missing default children */
1099
0
                ret = lyd_new_implicit_r(*node, lyd_node_child_p(*node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
1100
0
                        &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
1101
0
                LY_CHECK_ERR_RET(ret, LOG_LOCBACK(1, 1, 0, 0), ret);
1102
0
            }
1103
1104
0
            LOG_LOCBACK(1, 1, 0, 0);
1105
1106
            /* move JSON parser */
1107
0
            ret = lyjson_ctx_next(lydctx->jsonctx, status);
1108
0
            LY_CHECK_RET(ret);
1109
0
        } else if (snode->nodetype & LYD_NODE_ANY) {
1110
            /* create any node */
1111
0
            LY_CHECK_RET(*status != LYJSON_OBJECT && *status != LYJSON_OBJECT_EMPTY, LY_EINVAL);
1112
1113
            /* parse any data tree with correct options */
1114
            /* first backup the current options and then make the parser to process data as opaq nodes */
1115
0
            prev_opts = lydctx->parse_opts;
1116
0
            lydctx->parse_opts &= ~LYD_PARSE_STRICT;
1117
0
            lydctx->parse_opts |= LYD_PARSE_OPAQ;
1118
1119
            /* process the anydata content */
1120
0
            while (*status != LYJSON_OBJECT_CLOSED && *status != LYJSON_OBJECT_EMPTY) {
1121
0
                ret = lydjson_subtree_r(lydctx, NULL, &tree, NULL);
1122
0
                LY_CHECK_RET(ret);
1123
0
                *status = lyjson_ctx_status(lydctx->jsonctx, 0);
1124
0
            }
1125
1126
            /* restore parser options */
1127
0
            lydctx->parse_opts = prev_opts;
1128
1129
            /* finish linking metadata */
1130
0
            ret = lydjson_metadata_finish(lydctx, &tree);
1131
0
            LY_CHECK_RET(ret);
1132
1133
0
            ret = lyd_create_any(snode, tree, LYD_ANYDATA_DATATREE, 1, node);
1134
0
            LY_CHECK_RET(ret);
1135
0
        }
1136
0
    } else if (ret == LY_ENOT) {
1137
        /* parse it again as an opaq node */
1138
0
        ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent,
1139
0
                status, status, first_p, node);
1140
0
        LY_CHECK_RET(ret);
1141
1142
0
        if (snode->nodetype == LYS_LIST) {
1143
0
            ((struct lyd_node_opaq *)*node)->hints |= LYD_NODEHINT_LIST;
1144
0
        } else if (snode->nodetype == LYS_LEAFLIST) {
1145
0
            ((struct lyd_node_opaq *)*node)->hints |= LYD_NODEHINT_LEAFLIST;
1146
0
        }
1147
0
    }
1148
1149
0
    return ret;
1150
0
}
1151
1152
/**
1153
 * @brief Parse JSON subtree. All leaf-list and list instances of a node are considered one subtree.
1154
 *
1155
 * @param[in] lydctx JSON data parser context.
1156
 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
1157
 * @param[in,out] first_p Pointer to the variable holding the first top-level sibling, must be set if @p parent is not.
1158
 * @param[in,out] parsed Optional set to add all the parsed siblings into.
1159
 * @return LY_ERR value.
1160
 */
1161
static LY_ERR
1162
lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
1163
0
{
1164
0
    LY_ERR ret = LY_SUCCESS;
1165
0
    enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(lydctx->jsonctx, 0);
1166
0
    enum LYJSON_PARSER_STATUS status_inner = 0;
1167
0
    const char *name, *prefix = NULL;
1168
0
    size_t name_len, prefix_len = 0;
1169
0
    ly_bool is_meta = 0;
1170
0
    const struct lysc_node *snode = NULL;
1171
0
    struct lyd_node *node = NULL, *attr_node = NULL;
1172
0
    const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
1173
0
    const char *expected = NULL;
1174
1175
0
    assert(parent || first_p);
1176
0
    assert(status == LYJSON_OBJECT);
1177
1178
    /* process the node name */
1179
0
    lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_meta);
1180
1181
0
    if (!is_meta || name_len || prefix_len) {
1182
        /* get the schema node */
1183
0
        ret = lydjson_get_snode(lydctx, is_meta, prefix, prefix_len, name, name_len, (struct lyd_node_inner *)parent, &snode);
1184
0
        if (ret == LY_ENOT) {
1185
            /* skip element with children */
1186
0
            ret = lydjson_data_skip(lydctx->jsonctx);
1187
0
            LY_CHECK_GOTO(ret, cleanup);
1188
0
            status = lyjson_ctx_status(lydctx->jsonctx, 0);
1189
            /* nothing for now, continue with another call of lydjson_subtree_r() */
1190
0
            goto cleanup;
1191
0
        }
1192
0
        LY_CHECK_GOTO(ret, cleanup);
1193
1194
0
        if (!snode) {
1195
            /* we will not be parsing it as metadata */
1196
0
            is_meta = 0;
1197
0
        }
1198
0
    }
1199
1200
0
    if (is_meta) {
1201
        /* parse as metadata */
1202
0
        if (!name_len && !prefix_len) {
1203
            /* parent's metadata without a name - use the schema from the parent */
1204
0
            if (!parent) {
1205
0
                LOGVAL(ctx, LYVE_SYNTAX_JSON,
1206
0
                        "Invalid metadata format - \"@\" can be used only inside anydata, container or list entries.");
1207
0
                ret = LY_EVALID;
1208
0
                goto cleanup;
1209
0
            }
1210
0
            attr_node = parent;
1211
0
            snode = attr_node->schema;
1212
0
        }
1213
0
        ret = lydjson_parse_attribute(lydctx, attr_node, snode, name, name_len, prefix, prefix_len, parent, &status,
1214
0
                first_p, &node);
1215
0
        LY_CHECK_GOTO(ret, cleanup);
1216
0
    } else if (!snode) {
1217
        /* parse as an opaq node */
1218
0
        assert((lydctx->parse_opts & LYD_PARSE_OPAQ) || (lydctx->int_opts));
1219
1220
        /* opaq node cannot have an empty string as the name. */
1221
0
        if (name_len == 0) {
1222
0
            LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX_JSON, "A JSON object member name cannot be a zero-length string.");
1223
0
            ret = LY_EVALID;
1224
0
            goto cleanup;
1225
0
        }
1226
1227
        /* move to the second item in the name/X pair */
1228
0
        ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1229
0
        LY_CHECK_GOTO(ret, cleanup);
1230
1231
0
        if (status == LYJSON_ARRAY) {
1232
            /* move into the array */
1233
0
            ret = lyjson_ctx_next(lydctx->jsonctx, &status_inner);
1234
0
            LY_CHECK_GOTO(ret, cleanup);
1235
0
        } else {
1236
            /* just a flag to pass correct parameters into lydjson_parse_opaq() */
1237
0
            status_inner = LYJSON_ERROR;
1238
0
        }
1239
1240
0
        ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, (struct lyd_node_inner *)parent, &status,
1241
0
                status_inner == LYJSON_ERROR ? &status : &status_inner, first_p, &node);
1242
0
        LY_CHECK_GOTO(ret, cleanup);
1243
0
    } else {
1244
        /* parse as a standard lyd_node but it can still turn out to be an opaque node */
1245
1246
        /* move to the second item in the name/X pair */
1247
0
        ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1248
0
        LY_CHECK_GOTO(ret, cleanup);
1249
1250
        /* first check the expected representation according to the nodetype and then continue with the content */
1251
0
        switch (snode->nodetype) {
1252
0
        case LYS_LEAFLIST:
1253
0
        case LYS_LIST:
1254
0
            if (snode->nodetype == LYS_LEAFLIST) {
1255
0
                expected = "name/array of values";
1256
0
            } else {
1257
0
                expected = "name/array of objects";
1258
0
            }
1259
1260
0
            LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
1261
1262
            /* move into array */
1263
0
            ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1264
0
            LY_CHECK_GOTO(ret, cleanup);
1265
1266
            /* process all the values/objects */
1267
0
            do {
1268
0
                lydjson_maintain_children((struct lyd_node_inner *)parent, first_p, &node);
1269
1270
0
                ret = lydjson_parse_instance(lydctx, (struct lyd_node_inner *)parent, first_p, snode, name, name_len,
1271
0
                        prefix, prefix_len, &status, &node);
1272
0
                if (ret == LY_EINVAL) {
1273
0
                    goto representation_error;
1274
0
                } else if (ret) {
1275
0
                    goto cleanup;
1276
0
                }
1277
0
            } while (status != LYJSON_ARRAY_CLOSED);
1278
1279
            /* move after the array */
1280
0
            ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1281
0
            LY_CHECK_GOTO(ret, cleanup);
1282
1283
0
            break;
1284
0
        case LYS_LEAF:
1285
0
        case LYS_CONTAINER:
1286
0
        case LYS_NOTIF:
1287
0
        case LYS_ACTION:
1288
0
        case LYS_RPC:
1289
0
        case LYS_ANYDATA:
1290
0
        case LYS_ANYXML:
1291
0
            if (snode->nodetype == LYS_LEAF) {
1292
0
                if (status == LYJSON_ARRAY) {
1293
0
                    expected = "name/[null]";
1294
0
                } else {
1295
0
                    expected = "name/value";
1296
0
                }
1297
0
            } else {
1298
0
                expected = "name/object";
1299
0
            }
1300
1301
            /* process the value/object */
1302
0
            ret = lydjson_parse_instance(lydctx, (struct lyd_node_inner *)parent, first_p, snode, name, name_len,
1303
0
                    prefix, prefix_len, &status, &node);
1304
0
            if (ret == LY_EINVAL) {
1305
0
                goto representation_error;
1306
0
            } else if (ret) {
1307
0
                goto cleanup;
1308
0
            }
1309
1310
0
            if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
1311
                /* rememeber the RPC/action/notification */
1312
0
                lydctx->op_node = node;
1313
0
            }
1314
1315
0
            break;
1316
0
        }
1317
0
    }
1318
1319
    /* finally connect the parsed node */
1320
0
    lydjson_maintain_children((struct lyd_node_inner *)parent, first_p, &node);
1321
1322
    /* rememeber a successfully parsed node */
1323
0
    if (parsed) {
1324
0
        ly_set_add(parsed, node, 1, NULL);
1325
0
    }
1326
1327
    /* success */
1328
0
    goto cleanup;
1329
1330
0
representation_error:
1331
0
    LOG_LOCSET(NULL, parent, NULL, NULL);
1332
0
    LOGVAL(ctx, LYVE_SYNTAX_JSON, "The %s \"%s\" is expected to be represented as JSON %s, but input data contains name/%s.",
1333
0
            lys_nodetype2str(snode->nodetype), snode->name, expected, lyjson_token2str(status));
1334
0
    LOG_LOCBACK(0, parent ? 1 : 0, 0, 0);
1335
0
    ret = LY_EVALID;
1336
1337
0
cleanup:
1338
0
    lyd_free_tree(node);
1339
0
    return ret;
1340
0
}
1341
1342
/**
1343
 * @brief Common start of JSON parser processing different types of the input data.
1344
 *
1345
 * @param[in] ctx libyang context
1346
 * @param[in] in Input structure.
1347
 * @param[in] parse_opts Options for parser, see @ref dataparseroptions.
1348
 * @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
1349
 * @param[out] lydctx_p Data parser context to finish validation.
1350
 * @param[out] status Storage for the current context's status
1351
 * @return LY_ERR value.
1352
 */
1353
static LY_ERR
1354
lyd_parse_json_init(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts,
1355
        struct lyd_json_ctx **lydctx_p, enum LYJSON_PARSER_STATUS *status)
1356
0
{
1357
0
    LY_ERR ret = LY_SUCCESS;
1358
0
    struct lyd_json_ctx *lydctx;
1359
0
    size_t i;
1360
1361
0
    assert(lydctx_p);
1362
0
    assert(status);
1363
1364
    /* init context */
1365
0
    lydctx = calloc(1, sizeof *lydctx);
1366
0
    LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1367
0
    lydctx->parse_opts = parse_opts;
1368
0
    lydctx->val_opts = val_opts;
1369
0
    lydctx->free = lyd_json_ctx_free;
1370
1371
    /* starting top-level */
1372
0
    for (i = 0; in->current[i] != '\0' && is_jsonws(in->current[i]); i++) {
1373
0
        if (in->current[i] == '\n') {
1374
            /* new line */
1375
0
            LY_IN_NEW_LINE(in);
1376
0
        }
1377
0
    }
1378
1379
0
    LY_CHECK_ERR_RET(ret = lyjson_ctx_new(ctx, in, &lydctx->jsonctx), free(lydctx), ret);
1380
0
    *status = lyjson_ctx_status(lydctx->jsonctx, 0);
1381
0
    if ((*status == LYJSON_END) || (*status == LYJSON_OBJECT_EMPTY) || (*status == LYJSON_OBJECT)) {
1382
0
        *lydctx_p = lydctx;
1383
0
        return LY_SUCCESS;
1384
0
    } else {
1385
        /* expecting top-level object */
1386
0
        LOGVAL(ctx, LYVE_SYNTAX_JSON, "Expected top-level JSON object, but %s found.",
1387
0
                lyjson_token2str(*status));
1388
0
        *lydctx_p = NULL;
1389
0
        lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1390
0
        return LY_EVALID;
1391
0
    }
1392
0
}
1393
1394
LY_ERR
1395
lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1396
        struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1397
        struct ly_set *parsed, struct lyd_ctx **lydctx_p)
1398
0
{
1399
0
    LY_ERR rc = LY_SUCCESS;
1400
0
    struct lyd_json_ctx *lydctx = NULL;
1401
0
    enum LYJSON_PARSER_STATUS status;
1402
0
    uint32_t int_opts;
1403
1404
0
    rc = lyd_parse_json_init(ctx, in, parse_opts, val_opts, &lydctx, &status);
1405
0
    LY_CHECK_GOTO(rc || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
1406
1407
0
    assert(status == LYJSON_OBJECT);
1408
1409
0
    switch (data_type) {
1410
0
    case LYD_TYPE_DATA_YANG:
1411
0
        int_opts = LYD_INTOPT_WITH_SIBLINGS;
1412
0
        break;
1413
0
    case LYD_TYPE_RPC_YANG:
1414
0
        int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1415
0
        break;
1416
0
    case LYD_TYPE_NOTIF_YANG:
1417
0
        int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1418
0
        break;
1419
0
    case LYD_TYPE_REPLY_YANG:
1420
0
        int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1421
0
        break;
1422
0
    default:
1423
0
        LOGINT(ctx);
1424
0
        rc = LY_EINT;
1425
0
        goto cleanup;
1426
0
    }
1427
0
    lydctx->int_opts = int_opts;
1428
0
    lydctx->ext = ext;
1429
1430
    /* find the operation node if it exists already */
1431
0
    LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1432
1433
    /* read subtree(s) */
1434
0
    while (lydctx->jsonctx->in->current[0] && (status != LYJSON_OBJECT_CLOSED)) {
1435
0
        rc = lydjson_subtree_r(lydctx, parent, first_p, parsed);
1436
0
        LY_CHECK_GOTO(rc, cleanup);
1437
1438
0
        status = lyjson_ctx_status(lydctx->jsonctx, 0);
1439
1440
0
        if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1441
0
            break;
1442
0
        }
1443
0
    }
1444
1445
0
    if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && lydctx->jsonctx->in->current[0] &&
1446
0
            (lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_OBJECT_CLOSED)) {
1447
0
        LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1448
0
        rc = LY_EVALID;
1449
0
        goto cleanup;
1450
0
    }
1451
0
    if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1452
0
        LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1453
0
        rc = LY_EVALID;
1454
0
        goto cleanup;
1455
0
    }
1456
1457
    /* finish linking metadata */
1458
0
    rc = lydjson_metadata_finish(lydctx, parent ? lyd_node_child_p(parent) : first_p);
1459
0
    LY_CHECK_GOTO(rc, cleanup);
1460
1461
0
cleanup:
1462
    /* there should be no unresolved types stored */
1463
0
    assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1464
0
            !lydctx->node_when.count));
1465
1466
0
    if (rc) {
1467
0
        lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1468
0
    } else {
1469
0
        *lydctx_p = (struct lyd_ctx *)lydctx;
1470
0
    }
1471
0
    return rc;
1472
0
}