Coverage Report

Created: 2025-07-18 06:09

/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
 * @author Michal Vasko <mvasko@cesnet.cz>
5
 * @brief JSON data parser for libyang
6
 *
7
 * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
8
 *
9
 * This source code is licensed under BSD 3-Clause License (the "License").
10
 * You may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     https://opensource.org/licenses/BSD-3-Clause
14
 */
15
16
#define _GNU_SOURCE
17
18
#include <assert.h>
19
#include <stdint.h>
20
#include <stdlib.h>
21
#include <string.h>
22
23
#include "compat.h"
24
#include "context.h"
25
#include "dict.h"
26
#include "in_internal.h"
27
#include "json.h"
28
#include "log.h"
29
#include "ly_common.h"
30
#include "parser_data.h"
31
#include "parser_internal.h"
32
#include "plugins_exts.h"
33
#include "set.h"
34
#include "tree.h"
35
#include "tree_data.h"
36
#include "tree_data_internal.h"
37
#include "tree_schema.h"
38
#include "tree_schema_internal.h"
39
#include "validation.h"
40
41
/**
42
 * @brief Free the JSON data parser context.
43
 *
44
 * JSON implementation of lyd_ctx_free_clb().
45
 */
46
static void
47
lyd_json_ctx_free(struct lyd_ctx *lydctx)
48
5.99k
{
49
5.99k
    struct lyd_json_ctx *ctx = (struct lyd_json_ctx *)lydctx;
50
51
5.99k
    if (lydctx) {
52
5.84k
        lyd_ctx_free(lydctx);
53
5.84k
        lyjson_ctx_free(ctx->jsonctx);
54
5.84k
        free(ctx);
55
5.84k
    }
56
5.99k
}
57
58
/**
59
 * @brief Pass the responsibility for releasing the dynamic values to @p dst.
60
 *
61
 * @param[in] jsonctx JSON context which contains the dynamic value.
62
 * @param[in,out] dst Pointer to which the responsibility will be submited.
63
 * If the pointer is already pointing to some allocated memory, it is released beforehand.
64
 */
65
static void
66
lyjson_ctx_give_dynamic_value(struct lyjson_ctx *jsonctx, char **dst)
67
259k
{
68
259k
    assert(jsonctx && dst);
69
70
259k
    if (!jsonctx->dynamic) {
71
259k
        return;
72
259k
    }
73
74
719
    if (dst) {
75
719
        free(*dst);
76
719
    }
77
719
    *dst = NULL;
78
79
    /* give the dynamic value */
80
719
    *dst = (char *)jsonctx->value;
81
82
    /* responsibility for the release is now passed to dst */
83
719
    jsonctx->dynamic = 0;
84
719
}
85
86
/**
87
 * @brief Parse JSON member-name as [\@][prefix:][name]
88
 *
89
 * \@ - metadata flag, maps to 1 in @p is_meta_p
90
 * prefix - name of the module of the data node
91
 * name - name of the data node
92
 *
93
 * All the output parameter are mandatory. Function only parse the member-name, all the appropriate checks are up to the caller.
94
 *
95
 * @param[in] value String to parse
96
 * @param[in] value_len Length of the @p str.
97
 * @param[out] name_p Pointer to the beginning of the parsed name.
98
 * @param[out] name_len_p Pointer to the length of the parsed name.
99
 * @param[out] prefix_p Pointer to the beginning of the parsed prefix. If the member-name does not contain prefix, result is NULL.
100
 * @param[out] prefix_len_p Pointer to the length of the parsed prefix. If the member-name does not contain prefix, result is 0.
101
 * @param[out] is_meta_p Pointer to the metadata flag, set to 1 if the member-name contains \@, 0 otherwise.
102
 */
103
static void
104
lydjson_parse_name(const char *value, size_t value_len, const char **name_p, size_t *name_len_p, const char **prefix_p,
105
        size_t *prefix_len_p, ly_bool *is_meta_p)
106
291k
{
107
291k
    const char *name, *prefix = NULL;
108
291k
    size_t name_len, prefix_len = 0;
109
291k
    ly_bool is_meta = 0;
110
111
291k
    name = memchr(value, ':', value_len);
112
291k
    if (name != NULL) {
113
153k
        prefix = value;
114
153k
        if (*prefix == '@') {
115
15.3k
            is_meta = 1;
116
15.3k
            prefix++;
117
15.3k
        }
118
153k
        prefix_len = name - prefix;
119
153k
        name++;
120
153k
        name_len = value_len - (prefix_len + 1) - is_meta;
121
153k
    } else {
122
137k
        name = value;
123
137k
        if (name[0] == '@') {
124
30.7k
            is_meta = 1;
125
30.7k
            name++;
126
30.7k
        }
127
137k
        name_len = value_len - is_meta;
128
137k
    }
129
130
291k
    *name_p = name;
131
291k
    *name_len_p = name_len;
132
291k
    *prefix_p = prefix;
133
291k
    *prefix_len_p = prefix_len;
134
291k
    *is_meta_p = is_meta;
135
291k
}
136
137
/**
138
 * @brief Get correct prefix (module_name) inside the @p node.
139
 *
140
 * @param[in] node Data node to get inherited prefix.
141
 * @param[in] local_prefix Local prefix to replace the inherited prefix.
142
 * @param[in] local_prefix_len Length of the @p local_prefix string. In case of 0, the inherited prefix is taken.
143
 * @param[out] prefix_p Pointer to the resulting prefix string, Note that the result can be NULL in case of no local prefix
144
 * and no context @p node to get inherited prefix.
145
 * @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
146
 * of no local prefix and no context @p node to get inherited prefix.
147
 * @return LY_ERR value.
148
 */
149
static LY_ERR
150
lydjson_get_node_prefix(struct lyd_node *node, const char *local_prefix, size_t local_prefix_len, const char **prefix_p,
151
        size_t *prefix_len_p)
152
180k
{
153
180k
    struct lyd_node_opaq *onode;
154
180k
    const char *module_name = NULL;
155
156
180k
    assert(prefix_p && prefix_len_p);
157
158
180k
    if (local_prefix_len) {
159
71.2k
        *prefix_p = local_prefix;
160
71.2k
        *prefix_len_p = local_prefix_len;
161
71.2k
        return LY_SUCCESS;
162
71.2k
    }
163
164
191k
    while (node) {
165
101k
        if (node->schema) {
166
7.67k
            module_name = node->schema->module->name;
167
7.67k
            break;
168
7.67k
        }
169
94.0k
        onode = (struct lyd_node_opaq *)node;
170
94.0k
        if (onode->name.module_name) {
171
11.3k
            module_name = onode->name.module_name;
172
11.3k
            break;
173
82.6k
        } else if (onode->name.prefix) {
174
0
            module_name = onode->name.prefix;
175
0
            break;
176
0
        }
177
82.6k
        node = lyd_parent(node);
178
82.6k
    }
179
180
109k
    *prefix_p = module_name;
181
109k
    *prefix_len_p = ly_strlen(module_name);
182
109k
    return LY_SUCCESS;
183
180k
}
184
185
/**
186
 * @brief Skip the current JSON item (based on status).
187
 *
188
 * The JSON context is moved to the last "status" of the JSON item so to completely
189
 * finish the skip, one more JSON context move is required.
190
 *
191
 * @param[in] jsonctx JSON context with the input data to skip.
192
 * @return LY_ERR value.
193
 */
194
static LY_ERR
195
lydjson_data_skip(struct lyjson_ctx *jsonctx)
196
24.3k
{
197
24.3k
    enum LYJSON_PARSER_STATUS status, current;
198
24.3k
    uint32_t depth;
199
200
24.3k
    status = lyjson_ctx_status(jsonctx);
201
24.3k
    depth = lyjson_ctx_depth(jsonctx);
202
203
24.3k
    switch (status) {
204
859
    case LYJSON_OBJECT:
205
859
        ++depth;
206
207
        /* skip until object closes */
208
23.1k
        do {
209
23.1k
            LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
210
23.0k
        } while ((current != LYJSON_OBJECT_CLOSED) || (depth != lyjson_ctx_depth(jsonctx)));
211
812
        break;
212
898
    case LYJSON_ARRAY:
213
898
        ++depth;
214
215
        /* skip until array closes */
216
92.8k
        do {
217
92.8k
            LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
218
92.6k
        } while ((current != LYJSON_ARRAY_CLOSED) || (depth != lyjson_ctx_depth(jsonctx)));
219
701
        break;
220
22.5k
    case LYJSON_OBJECT_NAME:
221
        /* just get to the value */
222
22.5k
        LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
223
22.5k
        if ((current == LYJSON_OBJECT) || (current == LYJSON_ARRAY)) {
224
1.75k
            LY_CHECK_RET(lydjson_data_skip(jsonctx));
225
1.51k
        }
226
22.2k
        break;
227
22.2k
    default:
228
        /* no other status really expected, just go to next */
229
0
        LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
230
0
        break;
231
24.3k
    }
232
233
23.7k
    return LY_SUCCESS;
234
24.3k
}
235
236
/**
237
 * @brief Get schema node corresponding to the input parameters.
238
 *
239
 * @param[in] lydctx JSON data parser context.
240
 * @param[in] is_attr Flag if the reference to the node is an attribute, for logging only.
241
 * @param[in] prefix Requested node's prefix (module name).
242
 * @param[in] prefix_len Length of the @p prefix.
243
 * @param[in] name Requested node's name.
244
 * @param[in] name_len Length of the @p name.
245
 * @param[in] parent Parent of the node being processed, can be NULL in case of top-level.
246
 * @param[out] snode Found schema node corresponding to the input parameters. If NULL, parse as an opaque node.
247
 * @param[out] ext Extension instance that provided @p snode, if any.
248
 * @return LY_SUCCES on success.
249
 * @return LY_ENOT if the whole object was parsed (skipped or as an extension).
250
 * @return LY_ERR on error.
251
 */
252
static LY_ERR
253
lydjson_get_snode(struct lyd_json_ctx *lydctx, ly_bool is_attr, const char *prefix, size_t prefix_len, const char *name,
254
        size_t name_len, struct lyd_node *parent, const struct lysc_node **snode, struct lysc_ext_instance **ext)
255
283k
{
256
283k
    LY_ERR ret = LY_SUCCESS, r;
257
283k
    struct lys_module *mod = NULL;
258
283k
    uint32_t getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
259
260
283k
    *snode = NULL;
261
283k
    *ext = NULL;
262
263
    /* get the element module, prefer parent context because of extensions */
264
283k
    if (prefix_len) {
265
144k
        mod = ly_ctx_get_module_implemented2(parent ? LYD_CTX(parent) : lydctx->jsonctx->ctx, prefix, prefix_len);
266
144k
    } else if (parent) {
267
138k
        if (parent->schema) {
268
55.7k
            mod = parent->schema->module;
269
55.7k
        }
270
138k
    } else if (!(lydctx->int_opts & LYD_INTOPT_ANY)) {
271
39
        LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX_JSON, "Top-level JSON object member \"%.*s\" must be namespace-qualified.",
272
39
                (int)(is_attr ? name_len + 1 : name_len), is_attr ? name - 1 : name);
273
39
        ret = LY_EVALID;
274
39
        goto cleanup;
275
39
    }
276
283k
    if (!mod) {
277
        /* check for extension data */
278
105k
        r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_JSON, NULL, name, name_len, snode, ext);
279
105k
        if (r != LY_ENOT) {
280
            /* success or error */
281
0
            ret = r;
282
0
            goto cleanup;
283
0
        }
284
285
        /* unknown module */
286
105k
        if (lydctx->parse_opts & LYD_PARSE_STRICT) {
287
0
            LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "No module named \"%.*s\" in the context.", (int)prefix_len, prefix);
288
0
            ret = LY_EVALID;
289
0
            goto cleanup;
290
0
        }
291
105k
    }
292
293
    /* get the schema node */
294
283k
    if (mod && (!parent || parent->schema)) {
295
175k
        if (!parent && lydctx->ext) {
296
0
            *snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
297
175k
        } else {
298
175k
            *snode = lys_find_child(lyd_parser_node_schema(parent), mod, name, name_len, 0, getnext_opts);
299
175k
        }
300
175k
        if (!*snode) {
301
            /* check for extension data */
302
15.8k
            r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_JSON, NULL, name, name_len, snode, ext);
303
15.8k
            if (r != LY_ENOT) {
304
                /* success or error */
305
0
                ret = r;
306
0
                goto cleanup;
307
0
            }
308
309
            /* unknown data node */
310
15.8k
            if (lydctx->parse_opts & LYD_PARSE_STRICT) {
311
0
                if (parent) {
312
0
                    LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
313
0
                            (int)name_len, name, LYD_NAME(parent));
314
0
                } else if (lydctx->ext) {
315
0
                    if (lydctx->ext->argument) {
316
0
                        LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE,
317
0
                                "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
318
0
                                (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
319
0
                    } else {
320
0
                        LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
321
0
                                (int)name_len, name, lydctx->ext->def->name);
322
0
                    }
323
0
                } else {
324
0
                    LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
325
0
                            (int)name_len, name, mod->name);
326
0
                }
327
0
                ret = LY_EVALID;
328
0
                goto cleanup;
329
0
            }
330
159k
        } else {
331
            /* check that schema node is valid and can be used */
332
159k
            ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode);
333
159k
        }
334
175k
    }
335
336
283k
cleanup:
337
283k
    return ret;
338
283k
}
339
340
/**
341
 * @brief Get the hint for the data type parsers according to the current JSON parser context.
342
 *
343
 * @param[in] lydctx JSON data parser context.
344
 * @param[in,out] status Pointer to the current context status,
345
 * in some circumstances the function manipulates with the context so the status is updated.
346
 * @param[out] type_hint_p Pointer to the variable to store the result.
347
 * @return LY_SUCCESS in case of success.
348
 * @return LY_EINVAL in case of invalid context status not referring to a value.
349
 */
350
static LY_ERR
351
lydjson_value_type_hint(struct lyd_json_ctx *lydctx, enum LYJSON_PARSER_STATUS *status_p, uint32_t *type_hint_p)
352
759k
{
353
759k
    struct lyjson_ctx *jsonctx = lydctx->jsonctx;
354
355
759k
    *type_hint_p = 0;
356
357
759k
    if (*status_p == LYJSON_ARRAY) {
358
        /* only [null] */
359
87
        LY_CHECK_RET(lyjson_ctx_next(jsonctx, status_p));
360
84
        if (*status_p != LYJSON_NULL) {
361
3
            LOGVAL(jsonctx->ctx, LYVE_SYNTAX_JSON,
362
3
                    "Expected JSON name/value or special name/[null], but input data contains name/[%s].",
363
3
                    lyjson_token2str(*status_p));
364
3
            return LY_EINVAL;
365
3
        }
366
367
81
        LY_CHECK_RET(lyjson_ctx_next(jsonctx, NULL));
368
79
        if (lyjson_ctx_status(jsonctx) != LYJSON_ARRAY_CLOSED) {
369
0
            LOGVAL(jsonctx->ctx, LYVE_SYNTAX_JSON, "Expected array end, but input data contains %s.",
370
0
                    lyjson_token2str(*status_p));
371
0
            return LY_EINVAL;
372
0
        }
373
374
79
        *type_hint_p = LYD_VALHINT_EMPTY;
375
759k
    } else if (*status_p == LYJSON_STRING) {
376
101k
        *type_hint_p = LYD_VALHINT_STRING | LYD_VALHINT_NUM64;
377
657k
    } else if (*status_p == LYJSON_NUMBER) {
378
657k
        *type_hint_p = LYD_VALHINT_DECNUM;
379
657k
    } else if ((*status_p == LYJSON_FALSE) || (*status_p == LYJSON_TRUE)) {
380
177
        *type_hint_p = LYD_VALHINT_BOOLEAN;
381
177
    } else if (*status_p == LYJSON_NULL) {
382
38
        *type_hint_p = 0;
383
38
    } else {
384
7
        LOGVAL(jsonctx->ctx, LYVE_SYNTAX_JSON, "Unexpected input data %s.", lyjson_token2str(*status_p));
385
7
        return LY_EINVAL;
386
7
    }
387
388
759k
    if (lydctx->parse_opts & LYD_PARSE_JSON_STRING_DATATYPES) {
389
0
        *type_hint_p |= LYD_VALHINT_STRING_DATATYPES;
390
0
    }
391
392
759k
    return LY_SUCCESS;
393
759k
}
394
395
/**
396
 * @brief Check that the input data are parseable as the @p list.
397
 *
398
 * Checks for all the list's keys. Function does not revert the context state.
399
 *
400
 * @param[in] lydctx JSON data parser context.
401
 * @param[in] list List schema node corresponding to the input data object.
402
 * @return LY_SUCCESS in case the data are ok for the @p list
403
 * @return LY_ENOT in case the input data are not sufficient to fully parse the list instance.
404
 */
405
static LY_ERR
406
lydjson_check_list(struct lyd_json_ctx *lydctx, const struct lysc_node *list)
407
0
{
408
0
    LY_ERR rc = LY_SUCCESS;
409
0
    struct lyjson_ctx *jsonctx = lydctx->jsonctx;
410
0
    enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx);
411
0
    struct ly_set key_set = {0};
412
0
    const struct lysc_node *snode;
413
0
    uint32_t i, hints;
414
415
0
    assert(list && (list->nodetype == LYS_LIST));
416
417
    /* get all keys into a set (keys do not have if-features or anything) */
418
0
    snode = NULL;
419
0
    while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
420
0
        rc = ly_set_add(&key_set, (void *)snode, 1, NULL);
421
0
        LY_CHECK_GOTO(rc, cleanup);
422
0
    }
423
0
    if (!key_set.count) {
424
        /* no keys */
425
0
        goto cleanup;
426
0
    }
427
428
0
    if (status == LYJSON_OBJECT) {
429
0
        do {
430
0
            const char *name, *prefix;
431
0
            size_t name_len, prefix_len;
432
0
            ly_bool is_attr;
433
434
            /* match the key */
435
0
            LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
436
0
            if (status != LYJSON_OBJECT_NAME) {
437
0
                break;
438
0
            }
439
0
            snode = NULL;
440
0
            lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
441
442
0
            if (!is_attr && !prefix) {
443
0
                for (i = 0; i < key_set.count; ++i) {
444
0
                    if (!ly_strncmp(key_set.snodes[i]->name, name, name_len)) {
445
0
                        snode = key_set.snodes[i];
446
0
                        break;
447
0
                    }
448
0
                }
449
450
                /* get the value */
451
0
                LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
452
453
0
                if (snode) {
454
                    /* we have the key, validate the value */
455
0
                    if ((status < LYJSON_NUMBER) || (status > LYJSON_NULL)) {
456
                        /* not a terminal */
457
0
                        rc = LY_ENOT;
458
0
                        goto cleanup;
459
0
                    }
460
461
0
                    rc = lydjson_value_type_hint(lydctx, &status, &hints);
462
0
                    LY_CHECK_GOTO(rc, cleanup);
463
0
                    rc = ly_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL, hints);
464
0
                    LY_CHECK_GOTO(rc, cleanup);
465
466
                    /* key with a valid value, remove from the set */
467
0
                    ly_set_rm_index(&key_set, i, NULL);
468
0
                }
469
470
                /* next object */
471
0
                LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
472
0
            } else {
473
                /* skip the uninteresting object */
474
0
                LY_CHECK_GOTO(rc = lydjson_data_skip(jsonctx), cleanup);
475
0
                LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
476
0
            }
477
0
        } while (key_set.count && (status == LYJSON_OBJECT_NEXT));
478
0
    }
479
480
0
    if (key_set.count) {
481
        /* some keys are missing/did not validate */
482
0
        rc = LY_ENOT;
483
0
    }
484
485
0
cleanup:
486
0
    ly_set_erase(&key_set, NULL);
487
0
    return rc;
488
0
}
489
490
/**
491
 * @brief Check in advance if the input data are parsable according to the provided @p snode.
492
 *
493
 * Note that the checks are done only in case the LYD_PARSE_OPAQ is allowed. Otherwise the same checking
494
 * is naturally done when the data are really parsed.
495
 *
496
 * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
497
 * as before calling, despite it is necessary to process input data for checking.
498
 * @param[in] snode Schema node corresponding to the member currently being processed in the context.
499
 * @param[out] type_hint_p Pointer to a variable to store detected value type hint in case of leaf or leaf-list.
500
 * @return LY_SUCCESS in case the data are ok for the @p snode or the LYD_PARSE_OPAQ is not enabled.
501
 * @return LY_ENOT in case the input data are not sufficient to fully parse the list instance
502
 * @return LY_EINVAL in case of invalid leaf JSON encoding
503
 * and they are expected to be parsed as opaq nodes.
504
 */
505
static LY_ERR
506
lydjson_data_check_opaq(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, uint32_t *type_hint_p)
507
673k
{
508
673k
    LY_ERR ret = LY_SUCCESS;
509
673k
    struct lyjson_ctx *jsonctx = lydctx->jsonctx;
510
673k
    enum LYJSON_PARSER_STATUS status;
511
673k
    uint32_t *prev_lo, temp_lo = 0;
512
513
673k
    assert(snode);
514
515
673k
    if (!(snode->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
516
        /* can always be parsed as a data node if we have the schema node */
517
11.6k
        return LY_SUCCESS;
518
11.6k
    }
519
520
    /* backup parser */
521
661k
    lyjson_ctx_backup(jsonctx);
522
661k
    status = lyjson_ctx_status(jsonctx);
523
524
661k
    if (lydctx->parse_opts & LYD_PARSE_OPAQ) {
525
        /* check if the node is parseable. if not, NULL the snode to announce that it is supposed to be parsed
526
         * as an opaq node */
527
0
        switch (snode->nodetype) {
528
0
        case LYS_LEAFLIST:
529
0
        case LYS_LEAF:
530
            /* value may not be valid in which case we parse it as an opaque node */
531
0
            if ((ret = lydjson_value_type_hint(lydctx, &status, type_hint_p))) {
532
0
                break;
533
0
            }
534
535
0
            prev_lo = ly_temp_log_options(&temp_lo);
536
0
            if (ly_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL, *type_hint_p)) {
537
0
                ret = LY_ENOT;
538
0
            }
539
0
            ly_temp_log_options(prev_lo);
540
0
            break;
541
0
        case LYS_LIST:
542
            /* lists may not have all its keys */
543
0
            if (lydjson_check_list(lydctx, snode)) {
544
                /* invalid list, parse as opaque if it misses/has invalid some keys */
545
0
                ret = LY_ENOT;
546
0
            }
547
0
            break;
548
0
        }
549
661k
    } else if (snode->nodetype & LYD_NODE_TERM) {
550
655k
        ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
551
655k
    }
552
553
    /* restore parser */
554
661k
    lyjson_ctx_restore(jsonctx);
555
556
661k
    return ret;
557
661k
}
558
559
/**
560
 * @brief Join the forward-referencing metadata with their target data nodes.
561
 *
562
 * Note that JSON encoding for YANG data allows forward-referencing metadata only for leafs/leaf-lists.
563
 *
564
 * @param[in] lydctx JSON data parser context.
565
 * @param[in,out] first_p Pointer to the first sibling node variable (top-level or in a particular parent node)
566
 * as a starting point to search for the metadata's target data node
567
 * @return LY_SUCCESS on success
568
 * @return LY_EVALID in case there are some metadata with unresolved target data node instance
569
 */
570
static LY_ERR
571
lydjson_metadata_finish(struct lyd_json_ctx *lydctx, struct lyd_node **first_p)
572
50.8k
{
573
50.8k
    LY_ERR ret = LY_SUCCESS;
574
50.8k
    struct lyd_node *node, *attr, *next, *meta_iter;
575
50.8k
    struct lysc_ext_instance *ext;
576
50.8k
    uint64_t instance = 0;
577
50.8k
    const char *prev = NULL;
578
50.8k
    uint32_t log_location_items = 0;
579
580
    /* finish linking metadata */
581
128k
    LY_LIST_FOR_SAFE(*first_p, next, attr) {
582
128k
        struct lyd_node_opaq *meta_container = (struct lyd_node_opaq *)attr;
583
128k
        uint64_t match = 0;
584
128k
        ly_bool is_attr;
585
128k
        const char *name, *prefix;
586
128k
        size_t name_len, prefix_len;
587
128k
        const struct lysc_node *snode;
588
589
128k
        if (attr->schema || (meta_container->name.name[0] != '@')) {
590
            /* not an opaq metadata node */
591
108k
            continue;
592
108k
        }
593
594
19.9k
        LOG_LOCSET(NULL, attr);
595
19.9k
        log_location_items++;
596
597
19.9k
        if (prev != meta_container->name.name) {
598
            /* metas' names are stored in dictionary, so checking pointers must works */
599
11.6k
            lydict_remove(lydctx->jsonctx->ctx, prev);
600
11.6k
            LY_CHECK_GOTO(ret = lydict_insert(lydctx->jsonctx->ctx, meta_container->name.name, 0, &prev), cleanup);
601
11.6k
            instance = 1;
602
11.6k
        } else {
603
8.34k
            instance++;
604
8.34k
        }
605
606
        /* find the corresponding data node */
607
2.06M
        LY_LIST_FOR(*first_p, node) {
608
2.06M
            if (!node->schema) {
609
                /* opaq node - we are going to put into it just a generic attribute. */
610
2.03M
                if (strcmp(&meta_container->name.name[1], ((struct lyd_node_opaq *)node)->name.name)) {
611
2.02M
                    continue;
612
2.02M
                }
613
614
3.08k
                if (((struct lyd_node_opaq *)node)->hints & LYD_NODEHINT_LIST) {
615
0
                    LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX, "Metadata container references a sibling list node %s.",
616
0
                            ((struct lyd_node_opaq *)node)->name.name);
617
0
                    ret = LY_EVALID;
618
0
                    goto cleanup;
619
0
                }
620
621
                /* match */
622
3.08k
                match++;
623
3.08k
                if (match != instance) {
624
680
                    continue;
625
680
                }
626
627
6.06k
                LY_LIST_FOR(meta_container->child, meta_iter) {
628
                    /* convert opaq node to a attribute of the opaq node */
629
6.06k
                    struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
630
631
6.06k
                    ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, meta->name.name, strlen(meta->name.name),
632
6.06k
                            meta->name.prefix, ly_strlen(meta->name.prefix), meta->name.module_name,
633
6.06k
                            ly_strlen(meta->name.module_name), meta->value, ly_strlen(meta->value), NULL, LY_VALUE_JSON,
634
6.06k
                            NULL, meta->hints);
635
6.06k
                    LY_CHECK_GOTO(ret, cleanup);
636
6.06k
                }
637
638
                /* done */
639
2.40k
                break;
640
31.5k
            } else {
641
                /* this is the second time we are resolving the schema node, so it must succeed,
642
                 * but remember that snode can be still NULL */
643
31.5k
                lydjson_parse_name(meta_container->name.name, strlen(meta_container->name.name), &name, &name_len,
644
31.5k
                        &prefix, &prefix_len, &is_attr);
645
31.5k
                assert(is_attr);
646
31.5k
                lydjson_get_snode(lydctx, is_attr, prefix, prefix_len, name, name_len, lyd_parent(*first_p), &snode, &ext);
647
648
31.5k
                if (snode != node->schema) {
649
21.9k
                    continue;
650
21.9k
                }
651
652
                /* match */
653
9.63k
                match++;
654
9.63k
                if (match != instance) {
655
4.06k
                    continue;
656
4.06k
                }
657
658
6.04k
                LY_LIST_FOR(meta_container->child, meta_iter) {
659
                    /* convert opaq node to a metadata of the node */
660
6.04k
                    struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
661
6.04k
                    struct lys_module *mod = NULL;
662
663
6.04k
                    mod = ly_ctx_get_module_implemented(lydctx->jsonctx->ctx, meta->name.prefix);
664
6.04k
                    if (mod) {
665
314
                        ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod,
666
314
                                meta->name.name, strlen(meta->name.name), meta->value, ly_strlen(meta->value),
667
314
                                NULL, LY_VALUE_JSON, NULL, meta->hints, node->schema);
668
314
                        LY_CHECK_GOTO(ret, cleanup);
669
5.73k
                    } else if (lydctx->parse_opts & LYD_PARSE_STRICT) {
670
0
                        if (meta->name.prefix) {
671
0
                            LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE,
672
0
                                    "Unknown (or not implemented) YANG module \"%s\" of metadata \"%s%s%s\".",
673
0
                                    meta->name.prefix, meta->name.prefix, ly_strlen(meta->name.prefix) ? ":" : "",
674
0
                                    meta->name.name);
675
0
                        } else {
676
0
                            LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Missing YANG module of metadata \"%s\".",
677
0
                                    meta->name.name);
678
0
                        }
679
0
                        ret = LY_EVALID;
680
0
                        goto cleanup;
681
0
                    }
682
6.04k
                }
683
684
                /* add/correct flags */
685
5.54k
                ret = lyd_parser_set_data_flags(node, &node->meta, (struct lyd_ctx *)lydctx, ext);
686
5.54k
                LY_CHECK_GOTO(ret, cleanup);
687
5.54k
                break;
688
5.54k
            }
689
2.06M
        }
690
691
19.9k
        if (match != instance) {
692
            /* there is no corresponding data node for the metadata */
693
11.9k
            if (instance > 1) {
694
8.03k
                LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE,
695
8.03k
                        "Missing JSON data instance #%" PRIu64 " to be coupled with %s metadata.",
696
8.03k
                        instance, meta_container->name.name);
697
8.03k
            } else {
698
3.96k
                LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Missing JSON data instance to be coupled with %s metadata.",
699
3.96k
                        meta_container->name.name);
700
3.96k
            }
701
11.9k
            ret = LY_EVALID;
702
11.9k
        } else {
703
            /* remove the opaq attr */
704
7.94k
            if (attr == (*first_p)) {
705
600
                *first_p = attr->next;
706
600
            }
707
7.94k
            lyd_free_tree(attr);
708
7.94k
        }
709
710
19.9k
        LOG_LOCBACK(0, log_location_items);
711
19.9k
        log_location_items = 0;
712
19.9k
    }
713
714
50.8k
cleanup:
715
50.8k
    lydict_remove(lydctx->jsonctx->ctx, prev);
716
717
50.8k
    LOG_LOCBACK(0, log_location_items);
718
50.8k
    return ret;
719
50.8k
}
720
721
/**
722
 * @brief Parse a metadata member.
723
 *
724
 * @param[in] lydctx JSON data parser context.
725
 * @param[in] snode Schema node of the metadata parent.
726
 * @param[in] node Parent node in case the metadata is not forward-referencing (only LYD_NODE_TERM)
727
 * so the data node does not exists. In such a case the metadata is stored in the context for the later
728
 * processing by lydjson_metadata_finish().
729
 * @return LY_SUCCESS on success
730
 * @return Various LY_ERR values in case of failure.
731
 */
732
static LY_ERR
733
lydjson_metadata(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, struct lyd_node *node)
734
360
{
735
360
    LY_ERR rc = LY_SUCCESS, r;
736
360
    enum LYJSON_PARSER_STATUS status;
737
360
    const char *expected;
738
360
    ly_bool in_parent = 0;
739
360
    const char *name, *prefix = NULL;
740
360
    char *dynamic_prefname = NULL;
741
360
    size_t name_len, prefix_len = 0;
742
360
    struct lys_module *mod;
743
360
    const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
744
360
    ly_bool is_attr = 0;
745
360
    struct lyd_node *prev = node;
746
360
    uint32_t instance = 0, val_hints;
747
360
    uint16_t nodetype;
748
749
360
    assert(snode || node);
750
751
360
    nodetype = snode ? snode->nodetype : LYS_CONTAINER;
752
360
    if (snode) {
753
179
        LOG_LOCSET(snode, NULL);
754
179
    }
755
756
    /* move to the second item in the name/X pair */
757
360
    LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
758
759
    /* check attribute encoding */
760
355
    switch (nodetype) {
761
14
    case LYS_LEAFLIST:
762
14
        expected = "@name/array of objects/nulls";
763
14
        LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
764
765
15
next_entry:
766
15
        if (status == LYJSON_ARRAY_CLOSED) {
767
            /* no more metadata */
768
0
            goto cleanup;
769
0
        }
770
771
        /* move into the array/next item */
772
15
        LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
773
13
        instance++;
774
13
        LY_CHECK_GOTO((status != LYJSON_OBJECT) && (status != LYJSON_NULL), representation_error);
775
776
10
        if (!node || (node->schema != prev->schema)) {
777
0
            LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Missing JSON data instance #%" PRIu32
778
0
                    " of %s:%s to be coupled with metadata.", instance, prev->schema->module->name, prev->schema->name);
779
0
            rc = LY_EVALID;
780
0
            goto cleanup;
781
0
        }
782
783
10
        if (status == LYJSON_NULL) {
784
            /* continue with the next entry in the leaf-list array */
785
0
            prev = node;
786
0
            node = node->next;
787
788
0
            LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
789
0
            goto next_entry;
790
0
        }
791
10
        break;
792
10
    case LYS_LEAF:
793
7
    case LYS_ANYXML:
794
7
        expected = "@name/object";
795
796
7
        LY_CHECK_GOTO(status != LYJSON_OBJECT, representation_error);
797
6
        break;
798
325
    case LYS_CONTAINER:
799
334
    case LYS_LIST:
800
334
    case LYS_ANYDATA:
801
334
    case LYS_NOTIF:
802
334
    case LYS_ACTION:
803
334
    case LYS_RPC:
804
334
        in_parent = 1;
805
334
        expected = "@/object";
806
334
        LY_CHECK_GOTO(status != LYJSON_OBJECT, representation_error);
807
333
        break;
808
0
    default:
809
0
        LOGINT(ctx);
810
0
        rc = LY_EINT;
811
0
        goto cleanup;
812
355
    }
813
814
    /* process all the members inside a single metadata object */
815
349
    assert(status == LYJSON_OBJECT);
816
8.09k
    do {
817
8.09k
        LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
818
8.05k
        LY_CHECK_GOTO(status != LYJSON_OBJECT_NAME, representation_error);
819
820
8.05k
        lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
821
8.05k
        lyjson_ctx_give_dynamic_value(lydctx->jsonctx, &dynamic_prefname);
822
823
8.05k
        if (!name_len) {
824
1
            LOGVAL(ctx, LYVE_SYNTAX_JSON, "Metadata in JSON found with an empty name, followed by: %.10s", name);
825
1
            rc = LY_EVALID;
826
1
            goto cleanup;
827
8.05k
        } else if (!prefix_len) {
828
8
            LOGVAL(ctx, LYVE_SYNTAX_JSON, "Metadata in JSON must be namespace-qualified, missing prefix for \"%.*s\".",
829
8
                    (int)lydctx->jsonctx->value_len, lydctx->jsonctx->value);
830
8
            rc = LY_EVALID;
831
8
            goto cleanup;
832
8.04k
        } else if (is_attr) {
833
1
            LOGVAL(ctx, LYVE_SYNTAX_JSON, "Invalid format of the Metadata identifier in JSON, unexpected '@' in \"%.*s\"",
834
1
                    (int)lydctx->jsonctx->value_len, lydctx->jsonctx->value);
835
1
            rc = LY_EVALID;
836
1
            goto cleanup;
837
1
        }
838
839
        /* get the element module */
840
8.04k
        mod = ly_ctx_get_module_implemented2(ctx, prefix, prefix_len);
841
8.04k
        if (!mod) {
842
508
            if (lydctx->parse_opts & LYD_PARSE_STRICT) {
843
0
                LOGVAL(ctx, LYVE_REFERENCE, "Prefix \"%.*s\" of the metadata \"%.*s\" does not match any module in the context.",
844
0
                        (int)prefix_len, prefix, (int)name_len, name);
845
0
                rc = LY_EVALID;
846
0
                goto cleanup;
847
0
            }
848
508
            if (node->schema) {
849
                /* skip element with children */
850
25
                LY_CHECK_GOTO(rc = lydjson_data_skip(lydctx->jsonctx), cleanup);
851
23
                status = lyjson_ctx_status(lydctx->jsonctx);
852
                /* end of the item */
853
23
                continue;
854
25
            }
855
483
            assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
856
483
        }
857
858
        /* get the value */
859
8.02k
        LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
860
861
        /* get value hints */
862
7.99k
        LY_CHECK_GOTO(rc = lydjson_value_type_hint(lydctx, &status, &val_hints), cleanup);
863
864
7.99k
        if (node->schema) {
865
            /* create metadata */
866
6.67k
            rc = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod, name, name_len, lydctx->jsonctx->value,
867
6.67k
                    lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL, val_hints, node->schema);
868
6.67k
            LY_CHECK_GOTO(rc, cleanup);
869
870
            /* add/correct flags */
871
6.62k
            rc = lyd_parser_set_data_flags(node, &node->meta, (struct lyd_ctx *)lydctx, NULL);
872
6.62k
            LY_CHECK_GOTO(rc, cleanup);
873
6.62k
        } else {
874
            /* create attribute */
875
1.31k
            const char *module_name;
876
1.31k
            size_t module_name_len;
877
878
1.31k
            lydjson_get_node_prefix(node, prefix, prefix_len, &module_name, &module_name_len);
879
880
            /* attr2 is always changed to the created attribute */
881
1.31k
            rc = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, module_name,
882
1.31k
                    module_name_len, lydctx->jsonctx->value, lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic,
883
1.31k
                    LY_VALUE_JSON, NULL, val_hints);
884
1.31k
            LY_CHECK_GOTO(rc, cleanup);
885
1.31k
        }
886
887
        /* next member */
888
7.93k
        LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
889
7.89k
    } while (status == LYJSON_OBJECT_NEXT);
890
142
    LY_CHECK_GOTO(status != LYJSON_OBJECT_CLOSED, representation_error);
891
892
137
    if (nodetype == LYS_LEAFLIST) {
893
        /* continue by processing another metadata object for the following
894
         * leaf-list instance since they are always instantiated in JSON array */
895
3
        prev = node;
896
3
        node = node->next;
897
898
3
        LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
899
2
        goto next_entry;
900
3
    }
901
902
    /* success */
903
134
    goto cleanup;
904
905
134
representation_error:
906
11
    LOGVAL(ctx, LYVE_SYNTAX_JSON,
907
11
            "The attribute(s) of %s \"%s\" is expected to be represented as JSON %s, but input data contains @%s/%s.",
908
11
            lys_nodetype2str(nodetype), node ? LYD_NAME(node) : LYD_NAME(prev), expected, lyjson_token2str(status),
909
11
            in_parent ? "" : "name");
910
11
    rc = LY_EVALID;
911
912
360
cleanup:
913
360
    if ((rc == LY_EVALID) && (lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR)) {
914
        /* try to skip the invalid data */
915
0
        if ((r = lydjson_data_skip(lydctx->jsonctx))) {
916
0
            rc = r;
917
0
        }
918
0
    }
919
360
    free(dynamic_prefname);
920
360
    LOG_LOCBACK(snode ? 1 : 0, 0);
921
360
    return rc;
922
11
}
923
924
/**
925
 * @brief Eat the node pointed by @p node_p by inserting it into @p parent and maintain the @p first_p pointing
926
 * to the first child node.
927
 *
928
 * @param[in] parent Parent node to insert to, can be NULL in case of top-level (or provided first_p).
929
 * @param[in,out] first_p Pointer to the first sibling node in case of top-level.
930
 * @param[in,out] node_p pointer to the new node to insert, after the insert is done, pointer is set to NULL.
931
 * @param[in] last If set, always insert at the end.
932
 * @param[in] ext Extension instance of @p node_p, if any.
933
 */
934
static void
935
lydjson_maintain_children(struct lyd_node *parent, struct lyd_node **first_p, struct lyd_node **node_p, ly_bool last,
936
        struct lysc_ext_instance *ext)
937
803k
{
938
803k
    if (!*node_p) {
939
32.2k
        return;
940
32.2k
    }
941
942
    /* insert, keep first pointer correct */
943
771k
    if (ext) {
944
0
        lyplg_ext_insert(parent, *node_p);
945
771k
    } else {
946
771k
        lyd_insert_node(parent, first_p, *node_p, last);
947
771k
    }
948
771k
    if (first_p) {
949
771k
        if (parent) {
950
661k
            *first_p = lyd_child(parent);
951
661k
        } else {
952
109k
            while ((*first_p)->prev->next) {
953
0
                *first_p = (*first_p)->prev;
954
0
            }
955
109k
        }
956
771k
    }
957
771k
    *node_p = NULL;
958
771k
}
959
960
/**
961
 * @brief Wrapper for ::lyd_create_opaq().
962
 *
963
 * @param[in] lydctx JSON data parser context.
964
 * @param[in] name Name of the opaq node to create.
965
 * @param[in] name_len Length of the @p name string.
966
 * @param[in] prefix Prefix of the opaq node to create.
967
 * @param[in] prefix_len Length of the @p prefx string.
968
 * @param[in] parent Data parent of the opaq node, to inherit module name from.
969
 * @param[in,out] status_inner_p In case of processing JSON array, this parameter points to a standalone
970
 * context status of the array content. Otherwise, it is supposed to be the same as @p status_p.
971
 * @param[out] node_p Pointer to the created opaq node.
972
 * @return LY_ERR value.
973
 */
974
static LY_ERR
975
lydjson_create_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
976
        struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_inner_p, struct lyd_node **node_p)
977
178k
{
978
178k
    LY_ERR ret = LY_SUCCESS;
979
178k
    const char *value = NULL, *module_name;
980
178k
    size_t value_len = 0, module_name_len = 0;
981
178k
    ly_bool dynamic = 0;
982
178k
    uint32_t type_hint = 0;
983
984
178k
    if (*status_inner_p != LYJSON_OBJECT) {
985
        /* prepare for creating opaq node with a value */
986
95.8k
        value = lydctx->jsonctx->value;
987
95.8k
        value_len = lydctx->jsonctx->value_len;
988
95.8k
        dynamic = lydctx->jsonctx->dynamic;
989
95.8k
        lydctx->jsonctx->dynamic = 0;
990
991
95.8k
        LY_CHECK_RET(lydjson_value_type_hint(lydctx, status_inner_p, &type_hint));
992
95.8k
    }
993
994
    /* get the module name */
995
178k
    lydjson_get_node_prefix(parent, prefix, prefix_len, &module_name, &module_name_len);
996
178k
    if (!module_name && !parent && lydctx->any_schema) {
997
        /* in an anyxml/anydata tree, parsing first node, use the previous any schema node */
998
0
        module_name = lydctx->any_schema->module->name;
999
0
        module_name_len = strlen(module_name);
1000
0
    }
1001
1002
    /* create node */
1003
178k
    ret = lyd_create_opaq(lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, module_name, module_name_len, value,
1004
178k
            value_len, &dynamic, LY_VALUE_JSON, NULL, type_hint, node_p);
1005
178k
    if (dynamic) {
1006
0
        free((char *)value);
1007
0
    }
1008
1009
178k
    return ret;
1010
178k
}
1011
1012
static LY_ERR lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p,
1013
        struct ly_set *parsed);
1014
1015
/**
1016
 * @brief Parse opaq node from the input.
1017
 *
1018
 * In case of processing array, the whole array is being processed and the resulting @p node_p is the last item of the array.
1019
 *
1020
 * @param[in] lydctx JSON data parser context.
1021
 * @param[in] name Name of the opaq node to create.
1022
 * @param[in] name_len Length of the @p name string.
1023
 * @param[in] prefix Prefix of the opaq node to create.
1024
 * @param[in] prefix_len Length of the @p prefx string.
1025
 * @param[in] parent Data parent of the opaq node to create, can be NULL in case of top level,
1026
 * but must be set if @p first is not.
1027
 * @param[in,out] status_p Pointer to the current status of the parser context,
1028
 * since the function manipulates with the context and process the input, the status can be updated.
1029
 * @param[in,out] status_inner_p In case of processing JSON array, this parameter points to a standalone
1030
 * context status of the array content. Otherwise, it is supposed to be the same as @p status_p.
1031
 * @param[in,out] first_p First top-level/parent sibling, must be set if @p parent is not.
1032
 * @param[out] node_p Pointer to the created opaq node.
1033
 * @return LY_ERR value.
1034
 */
1035
static LY_ERR
1036
lydjson_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
1037
        struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_p, enum LYJSON_PARSER_STATUS *status_inner_p,
1038
        struct lyd_node **first_p, struct lyd_node **node_p)
1039
110k
{
1040
110k
    LY_ERR ret = LY_SUCCESS;
1041
1042
110k
    LY_CHECK_GOTO(ret = lydjson_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_inner_p, node_p), cleanup);
1043
1044
110k
    assert(*node_p);
1045
110k
    LOG_LOCSET(NULL, *node_p);
1046
1047
110k
    if ((*status_p == LYJSON_ARRAY) && (*status_inner_p == LYJSON_NULL)) {
1048
        /* special array null value */
1049
34
        ((struct lyd_node_opaq *)*node_p)->hints |= LYD_VALHINT_EMPTY;
1050
1051
        /* must be the only item */
1052
34
        LY_CHECK_GOTO(ret = lyjson_ctx_next(lydctx->jsonctx, status_inner_p), cleanup);
1053
34
        if (*status_inner_p != LYJSON_ARRAY_CLOSED) {
1054
0
            LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX, "Array \"null\" member with another member.");
1055
0
            ret = LY_EVALID;
1056
0
            goto cleanup;
1057
0
        }
1058
1059
34
        goto finish;
1060
34
    }
1061
1062
178k
    while (*status_p == LYJSON_ARRAY) {
1063
        /* process another instance of the same node */
1064
69.7k
        if (*status_inner_p == LYJSON_OBJECT) {
1065
            /* array with objects, list */
1066
1.24k
            ((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LIST;
1067
1068
            /* but first process children of the object in the array */
1069
1.69k
            do {
1070
1.69k
                LY_CHECK_GOTO(ret = lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL), cleanup);
1071
673
                *status_inner_p = lyjson_ctx_status(lydctx->jsonctx);
1072
673
            } while (*status_inner_p == LYJSON_OBJECT_NEXT);
1073
68.4k
        } else {
1074
            /* array with values, leaf-list */
1075
68.4k
            ((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LEAFLIST;
1076
68.4k
        }
1077
1078
68.7k
        LY_CHECK_GOTO(ret = lyjson_ctx_next(lydctx->jsonctx, status_inner_p), cleanup);
1079
68.6k
        if (*status_inner_p == LYJSON_ARRAY_CLOSED) {
1080
686
            goto finish;
1081
686
        }
1082
67.9k
        assert(*status_inner_p == LYJSON_ARRAY_NEXT);
1083
1084
        /* continue with the next instance */
1085
67.9k
        LY_CHECK_GOTO(ret = lyjson_ctx_next(lydctx->jsonctx, status_inner_p), cleanup);
1086
67.9k
        assert(*node_p);
1087
67.9k
        lydjson_maintain_children(parent, first_p, node_p,
1088
67.9k
                lydctx->parse_opts & LYD_PARSE_ORDERED ? LYD_INSERT_NODE_LAST : LYD_INSERT_NODE_DEFAULT, NULL);
1089
1090
67.9k
        LOG_LOCBACK(0, 1);
1091
1092
67.9k
        LY_CHECK_GOTO(ret = lydjson_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_inner_p, node_p), cleanup);
1093
1094
67.9k
        assert(*node_p);
1095
67.9k
        LOG_LOCSET(NULL, *node_p);
1096
67.9k
    }
1097
1098
109k
    if (*status_p == LYJSON_OBJECT) {
1099
81.6k
        ((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_CONTAINER;
1100
        /* process children */
1101
100k
        do {
1102
100k
            LY_CHECK_GOTO(ret = lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL), cleanup);
1103
23.5k
            *status_p = lyjson_ctx_status(lydctx->jsonctx);
1104
23.5k
        } while (*status_p == LYJSON_OBJECT_NEXT);
1105
81.6k
    }
1106
1107
32.8k
finish:
1108
    /* finish linking metadata */
1109
32.8k
    ret = lydjson_metadata_finish(lydctx, lyd_node_child_p(*node_p));
1110
1111
110k
cleanup:
1112
110k
    if (*node_p) {
1113
110k
        LOG_LOCBACK(0, 1);
1114
110k
    }
1115
110k
    return ret;
1116
32.8k
}
1117
1118
/**
1119
 * @brief Move to the second item in the name/X pair and parse opaq node from the input.
1120
 *
1121
 * This function is basically the wrapper of the ::lydjson_parse_opaq().
1122
 * In addition, it calls the ::json_ctx_next() and prepares the status_inner_p parameter
1123
 * for ::lydjson_parse_opaq().
1124
 *
1125
 * @param[in] lydctx JSON data parser context.
1126
 * @param[in] name Name of the opaq node to create.
1127
 * @param[in] name_len Length of the @p name string.
1128
 * @param[in] prefix Prefix of the opaq node to create.
1129
 * @param[in] prefix_len Length of the @p prefx string.
1130
 * @param[in] parent Data parent of the opaq node to create, can be NULL in case of top level,
1131
 * but must be set if @p first is not.
1132
 * @param[in,out] status_p Pointer to the current status of the parser context,
1133
 * since the function manipulates with the context and process the input, the status can be updated.
1134
 * @param[in,out] first_p First top-level/parent sibling, must be set if @p parent is not.
1135
 * @param[out] node_p Pointer to the created opaq node.
1136
 * @return LY_ERR value.
1137
 */
1138
static LY_ERR
1139
lydjson_ctx_next_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len, const char *prefix,
1140
        size_t prefix_len, struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_p,
1141
        struct lyd_node **first_p, struct lyd_node **node_p)
1142
110k
{
1143
110k
    enum LYJSON_PARSER_STATUS status_inner = 0;
1144
1145
    /* move to the second item in the name/X pair */
1146
110k
    LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_p));
1147
1148
110k
    if (*status_p == LYJSON_ARRAY) {
1149
        /* move into the array */
1150
1.84k
        LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, &status_inner));
1151
109k
    } else {
1152
        /* just a flag to pass correct parameters into lydjson_parse_opaq() */
1153
109k
        status_inner = LYJSON_ERROR;
1154
109k
    }
1155
1156
110k
    if (status_inner == LYJSON_ERROR) {
1157
109k
        status_inner = *status_p;
1158
109k
    }
1159
1160
    /* parse opaq node from the input */
1161
110k
    LY_CHECK_RET(lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_p, &status_inner,
1162
32.6k
            first_p, node_p));
1163
1164
32.6k
    return LY_SUCCESS;
1165
110k
}
1166
1167
/**
1168
 * @brief Process the attribute container (starting by @)
1169
 *
1170
 * @param[in] lydctx JSON data parser context.
1171
 * @param[in] attr_node The data node referenced by the attribute container, if already known.
1172
 * @param[in] snode The schema node of the data node referenced by the attribute container, if known.
1173
 * @param[in] name Name of the opaq node to create.
1174
 * @param[in] name_len Length of the @p name string.
1175
 * @param[in] prefix Prefix of the opaq node to create.
1176
 * @param[in] prefix_len Length of the @p prefx string.
1177
 * @param[in] parent Data parent of the opaq node to create, can be NULL in case of top level,
1178
 * but must be set if @p first is not.
1179
 * @param[in,out] status_p Pointer to the current status of the parser context,
1180
 * since the function manipulates with the context and process the input, the status can be updated.
1181
 * @param[in,out] first_p First top-level/parent sibling, must be set if @p parent is not.
1182
 * @param[out] node_p Pointer to the created opaq node.
1183
 * @return LY_ERR value.
1184
 */
1185
static LY_ERR
1186
lydjson_parse_attribute(struct lyd_json_ctx *lydctx, struct lyd_node *attr_node, const struct lysc_node *snode,
1187
        const char *name, size_t name_len, const char *prefix, size_t prefix_len, struct lyd_node *parent,
1188
        enum LYJSON_PARSER_STATUS *status_p, struct lyd_node **first_p, struct lyd_node **node_p)
1189
9.86k
{
1190
9.86k
    LY_ERR r;
1191
9.86k
    const char *opaq_name, *mod_name;
1192
9.86k
    size_t opaq_name_len;
1193
1194
9.86k
    if (!snode && !prefix) {
1195
        /* set the prefix */
1196
180
        if (parent) {
1197
180
            lydjson_get_node_prefix(parent, NULL, 0, &prefix, &prefix_len);
1198
180
        } else {
1199
0
            prefix = "";
1200
0
            prefix_len = 0;
1201
0
        }
1202
180
    }
1203
1204
    /* parse as an attribute to a (opaque) node */
1205
9.86k
    if (!attr_node) {
1206
        /* try to find the instance */
1207
773k
        LY_LIST_FOR(parent ? lyd_child(parent) : *first_p, attr_node) {
1208
773k
            if (snode) {
1209
773k
                if (attr_node->schema) {
1210
2.64k
                    if (attr_node->schema == snode) {
1211
41
                        break;
1212
41
                    }
1213
770k
                } else {
1214
770k
                    mod_name = ((struct lyd_node_opaq *)attr_node)->name.module_name;
1215
770k
                    if (!strcmp(LYD_NAME(attr_node), snode->name) && mod_name && !strcmp(mod_name, snode->module->name)) {
1216
0
                        break;
1217
0
                    }
1218
770k
                }
1219
773k
            } else {
1220
0
                if (attr_node->schema) {
1221
0
                    if (!ly_strncmp(LYD_NAME(attr_node), name, name_len) &&
1222
0
                            !ly_strncmp(attr_node->schema->module->name, prefix, prefix_len)) {
1223
0
                        break;
1224
0
                    }
1225
0
                } else {
1226
0
                    mod_name = ((struct lyd_node_opaq *)attr_node)->name.module_name;
1227
0
                    if (!ly_strncmp(LYD_NAME(attr_node), name, name_len) && mod_name &&
1228
0
                            !ly_strncmp(mod_name, prefix, prefix_len)) {
1229
0
                        break;
1230
0
                    }
1231
0
                }
1232
0
            }
1233
773k
        }
1234
9.54k
    }
1235
9.86k
    if (!attr_node) {
1236
        /* parse just as an opaq node with the name beginning with @,
1237
         * later we have to check that it belongs to a standard node
1238
         * and it is supposed to be converted to a metadata */
1239
9.50k
        uint32_t prev_opts;
1240
1241
        /* backup parser options to parse unknown metadata as opaq nodes and try to resolve them later */
1242
9.50k
        prev_opts = lydctx->parse_opts;
1243
9.50k
        lydctx->parse_opts &= ~LYD_PARSE_STRICT;
1244
9.50k
        lydctx->parse_opts |= LYD_PARSE_OPAQ;
1245
1246
9.50k
        opaq_name = prefix ? prefix - 1 : name - 1;
1247
9.50k
        opaq_name_len = prefix ? prefix_len + name_len + 2 : name_len + 1;
1248
9.50k
        r = lydjson_ctx_next_parse_opaq(lydctx, opaq_name, opaq_name_len, NULL, 0, parent, status_p, first_p, node_p);
1249
1250
        /* restore the parser options */
1251
9.50k
        lydctx->parse_opts = prev_opts;
1252
9.50k
        LY_CHECK_RET(r);
1253
8.91k
    } else {
1254
360
        LY_CHECK_RET(lydjson_metadata(lydctx, snode, attr_node));
1255
134
    }
1256
1257
9.05k
    return LY_SUCCESS;
1258
9.86k
}
1259
1260
/**
1261
 * @brief Parse a single anydata/anyxml node.
1262
 *
1263
 * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
1264
 * as before calling, despite it is necessary to process input data for checking.
1265
 * @param[in] snode Schema node corresponding to the member currently being processed in the context.
1266
 * @param[in] ext Extension instance of @p snode, if any.
1267
 * @param[in,out] status JSON parser status, is updated.
1268
 * @param[out] node Parsed data (or opaque) node.
1269
 * @return LY_SUCCESS if a node was successfully parsed,
1270
 * @return LY_ENOT in case of invalid JSON encoding,
1271
 * @return LY_ERR on other errors.
1272
 */
1273
static LY_ERR
1274
lydjson_parse_any(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, struct lysc_ext_instance *ext,
1275
        enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
1276
0
{
1277
0
    LY_ERR r, rc = LY_SUCCESS;
1278
0
    uint32_t prev_parse_opts = lydctx->parse_opts, prev_int_opts = lydctx->int_opts;
1279
0
    struct ly_in in_start;
1280
0
    char *val = NULL;
1281
0
    const char *end;
1282
0
    struct lyd_node *child = NULL;
1283
0
    ly_bool log_node = 0;
1284
1285
0
    assert(snode->nodetype & LYD_NODE_ANY);
1286
1287
0
    *node = NULL;
1288
1289
    /* status check according to allowed JSON types */
1290
0
    if (snode->nodetype == LYS_ANYXML) {
1291
0
        LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_ARRAY) && (*status != LYJSON_NUMBER) &&
1292
0
                (*status != LYJSON_STRING) && (*status != LYJSON_FALSE) && (*status != LYJSON_TRUE) &&
1293
0
                (*status != LYJSON_NULL), LY_ENOT);
1294
0
    } else {
1295
0
        LY_CHECK_RET(*status != LYJSON_OBJECT, LY_ENOT);
1296
0
    }
1297
1298
    /* create any node */
1299
0
    switch (*status) {
1300
0
    case LYJSON_OBJECT:
1301
        /* create node */
1302
0
        r = lyd_create_any(snode, NULL, LYD_ANYDATA_DATATREE, 1, node);
1303
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1304
1305
0
        assert(*node);
1306
0
        LOG_LOCSET(NULL, *node);
1307
0
        log_node = 1;
1308
1309
        /* parse any data tree with correct options, first backup the current options and then make the parser
1310
         * process data as opaq nodes */
1311
0
        lydctx->parse_opts &= ~LYD_PARSE_STRICT;
1312
0
        lydctx->parse_opts |= LYD_PARSE_OPAQ | (ext ? LYD_PARSE_ONLY : 0);
1313
0
        lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
1314
0
        lydctx->any_schema = snode;
1315
1316
        /* process the anydata content */
1317
0
        do {
1318
0
            r = lydjson_subtree_r(lydctx, NULL, &child, NULL);
1319
0
            LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1320
1321
0
            *status = lyjson_ctx_status(lydctx->jsonctx);
1322
0
        } while (*status == LYJSON_OBJECT_NEXT);
1323
1324
        /* finish linking metadata */
1325
0
        r = lydjson_metadata_finish(lydctx, &child);
1326
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1327
1328
        /* assign the data tree */
1329
0
        ((struct lyd_node_any *)*node)->value.tree = child;
1330
0
        child = NULL;
1331
0
        break;
1332
0
    case LYJSON_ARRAY:
1333
        /* skip until the array end */
1334
0
        in_start = *lydctx->jsonctx->in;
1335
0
        LY_CHECK_GOTO(rc = lydjson_data_skip(lydctx->jsonctx), cleanup);
1336
1337
        /* return back by all the WS */
1338
0
        end = lydctx->jsonctx->in->current;
1339
0
        while (is_jsonws(end[-1])) {
1340
0
            --end;
1341
0
        }
1342
1343
        /* make a copy of the whole array and store it */
1344
0
        if (asprintf(&val, "[%.*s", (int)(end - in_start.current), in_start.current) == -1) {
1345
0
            LOGMEM(lydctx->jsonctx->ctx);
1346
0
            rc = LY_EMEM;
1347
0
            goto cleanup;
1348
0
        }
1349
0
        r = lyd_create_any(snode, val, LYD_ANYDATA_JSON, 1, node);
1350
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1351
0
        val = NULL;
1352
0
        break;
1353
0
    case LYJSON_STRING:
1354
        /* string value */
1355
0
        if (lydctx->jsonctx->dynamic) {
1356
0
            LY_CHECK_GOTO(rc = lyd_create_any(snode, lydctx->jsonctx->value, LYD_ANYDATA_STRING, 1, node), cleanup);
1357
0
            lydctx->jsonctx->dynamic = 0;
1358
0
        } else {
1359
0
            val = strndup(lydctx->jsonctx->value, lydctx->jsonctx->value_len);
1360
0
            LY_CHECK_ERR_GOTO(!val, LOGMEM(lydctx->jsonctx->ctx); rc = LY_EMEM, cleanup);
1361
1362
0
            r = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, node);
1363
0
            LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1364
0
            val = NULL;
1365
0
        }
1366
0
        break;
1367
0
    case LYJSON_NUMBER:
1368
0
    case LYJSON_FALSE:
1369
0
    case LYJSON_TRUE:
1370
        /* JSON value */
1371
0
        assert(!lydctx->jsonctx->dynamic);
1372
0
        val = strndup(lydctx->jsonctx->value, lydctx->jsonctx->value_len);
1373
0
        LY_CHECK_ERR_GOTO(!val, LOGMEM(lydctx->jsonctx->ctx); rc = LY_EMEM, cleanup);
1374
1375
0
        r = lyd_create_any(snode, val, LYD_ANYDATA_JSON, 1, node);
1376
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1377
0
        val = NULL;
1378
0
        break;
1379
0
    case LYJSON_NULL:
1380
        /* no value */
1381
0
        r = lyd_create_any(snode, NULL, LYD_ANYDATA_JSON, 1, node);
1382
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1383
0
        break;
1384
0
    default:
1385
0
        LOGINT(lydctx->jsonctx->ctx);
1386
0
        rc = LY_EINT;
1387
0
        goto cleanup;
1388
0
    }
1389
1390
0
cleanup:
1391
0
    if (log_node) {
1392
0
        LOG_LOCBACK(0, 1);
1393
0
    }
1394
0
    lydctx->parse_opts = prev_parse_opts;
1395
0
    lydctx->int_opts = prev_int_opts;
1396
0
    lydctx->any_schema = NULL;
1397
0
    free(val);
1398
0
    lyd_free_tree(child);
1399
0
    return rc;
1400
0
}
1401
1402
/**
1403
 * @brief Parse a single instance of an inner node.
1404
 *
1405
 * @param[in] lydctx JSON data parser context.
1406
 * @param[in] snode Schema node corresponding to the member currently being processed in the context.
1407
 * @param[in] ext Extension instance of @p snode, if any.
1408
 * @param[in,out] status JSON parser status, is updated.
1409
 * @param[out] node Parsed data (or opaque) node.
1410
 * @return LY_SUCCESS if a node was successfully parsed,
1411
 * @return LY_ENOT in case of invalid JSON encoding,
1412
 * @return LY_ERR on other errors.
1413
 */
1414
static LY_ERR
1415
lydjson_parse_instance_inner(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, struct lysc_ext_instance *ext,
1416
        enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
1417
18.3k
{
1418
18.3k
    LY_ERR r, rc = LY_SUCCESS;
1419
18.3k
    uint32_t prev_parse_opts = lydctx->parse_opts;
1420
1421
18.3k
    LY_CHECK_RET(*status != LYJSON_OBJECT, LY_ENOT);
1422
1423
    /* create inner node */
1424
18.2k
    LY_CHECK_RET(lyd_create_inner(snode, node));
1425
1426
    /* use it for logging */
1427
18.2k
    LOG_LOCSET(NULL, *node);
1428
1429
18.2k
    if (ext) {
1430
        /* only parse these extension data and validate afterwards */
1431
0
        lydctx->parse_opts |= LYD_PARSE_ONLY;
1432
0
    }
1433
1434
    /* process children */
1435
34.2k
    do {
1436
34.2k
        r = lydjson_subtree_r(lydctx, *node, lyd_node_child_p(*node), NULL);
1437
34.2k
        LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1438
1439
33.2k
        *status = lyjson_ctx_status(lydctx->jsonctx);
1440
33.2k
    } while (*status == LYJSON_OBJECT_NEXT);
1441
1442
    /* finish linking metadata */
1443
17.3k
    r = lydjson_metadata_finish(lydctx, lyd_node_child_p(*node));
1444
17.3k
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1445
1446
17.2k
    if (snode->nodetype == LYS_LIST) {
1447
        /* check all keys exist */
1448
6.42k
        r = lyd_parser_check_keys(*node);
1449
6.42k
        LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1450
6.41k
    }
1451
1452
17.2k
    if (!(lydctx->parse_opts & LYD_PARSE_ONLY) && !rc) {
1453
        /* new node validation */
1454
17.2k
        r = lyd_parser_validate_new_implicit((struct lyd_ctx *)lydctx, *node);
1455
17.2k
        LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1456
17.2k
    }
1457
1458
18.2k
cleanup:
1459
18.2k
    lydctx->parse_opts = prev_parse_opts;
1460
18.2k
    LOG_LOCBACK(0, 1);
1461
18.2k
    if (!(*node)->hash) {
1462
        /* list without keys is unusable */
1463
103
        lyd_free_tree(*node);
1464
103
        *node = NULL;
1465
103
    }
1466
18.2k
    return rc;
1467
17.2k
}
1468
1469
/**
1470
 * @brief Parse a single instance of a node.
1471
 *
1472
 * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
1473
 * as before calling, despite it is necessary to process input data for checking.
1474
 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
1475
 * @param[in,out] first_p Pointer to the variable holding the first top-level sibling, must be set if @p parent is not.
1476
 * @param[in] snode Schema node corresponding to the member currently being processed in the context.
1477
 * @param[in] ext Extension instance of @p snode, if any.
1478
 * @param[in] name Parsed JSON node name.
1479
 * @param[in] name_len Lenght of @p name.
1480
 * @param[in] prefix Parsed JSON node prefix.
1481
 * @param[in] prefix_len Length of @p prefix.
1482
 * @param[in,out] status JSON parser status, is updated.
1483
 * @param[out] node Parsed data (or opaque) node.
1484
 * @return LY_SUCCESS if a node was successfully parsed,
1485
 * @return LY_ENOT in case of invalid JSON encoding,
1486
 * @return LY_ERR on other errors.
1487
 */
1488
static LY_ERR
1489
lydjson_parse_instance(struct lyd_json_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p,
1490
        const struct lysc_node *snode, struct lysc_ext_instance *ext, const char *name, size_t name_len,
1491
        const char *prefix, size_t prefix_len, enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
1492
673k
{
1493
673k
    LY_ERR r, rc = LY_SUCCESS;
1494
673k
    uint32_t type_hints = 0;
1495
1496
673k
    LOG_LOCSET(snode, NULL);
1497
1498
673k
    r = lydjson_data_check_opaq(lydctx, snode, &type_hints);
1499
673k
    if (r == LY_SUCCESS) {
1500
673k
        assert(snode->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER | LYD_NODE_ANY));
1501
673k
        if ((lydctx->parse_opts & LYD_PARSE_JSON_NULL) && (*status == LYJSON_NULL)) {
1502
            /* do not do anything if value is JSON 'null' */
1503
0
            goto cleanup;
1504
673k
        } else if (snode->nodetype & LYD_NODE_TERM) {
1505
655k
            if ((*status != LYJSON_ARRAY) && (*status != LYJSON_NUMBER) && (*status != LYJSON_STRING) &&
1506
655k
                    (*status != LYJSON_FALSE) && (*status != LYJSON_TRUE) && (*status != LYJSON_NULL)) {
1507
0
                rc = LY_ENOT;
1508
0
                goto cleanup;
1509
0
            }
1510
1511
            /* create terminal node */
1512
655k
            r = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, lydctx->jsonctx->value,
1513
655k
                    lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL, type_hints, node);
1514
655k
            LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1515
1516
            /* move JSON parser */
1517
653k
            if (*status == LYJSON_ARRAY) {
1518
                /* only [null], 2 more moves are needed */
1519
0
                r = lyjson_ctx_next(lydctx->jsonctx, status);
1520
0
                LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1521
0
                assert(*status == LYJSON_NULL);
1522
1523
0
                r = lyjson_ctx_next(lydctx->jsonctx, status);
1524
0
                LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1525
0
                assert(*status == LYJSON_ARRAY_CLOSED);
1526
0
            }
1527
653k
        } else if (snode->nodetype & LYD_NODE_INNER) {
1528
            /* create inner node */
1529
18.3k
            r = lydjson_parse_instance_inner(lydctx, snode, ext, status, node);
1530
18.3k
            LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1531
17.2k
        } else {
1532
            /* create any node */
1533
0
            r = lydjson_parse_any(lydctx, snode, ext, status, node);
1534
0
            LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1535
0
        }
1536
670k
        LY_CHECK_GOTO(!*node, cleanup);
1537
1538
        /* add/correct flags */
1539
670k
        r = lyd_parser_set_data_flags(*node, &(*node)->meta, (struct lyd_ctx *)lydctx, ext);
1540
670k
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1541
1542
670k
        if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
1543
            /* store for ext instance node validation, if needed */
1544
670k
            r = lyd_validate_node_ext(*node, &lydctx->ext_node);
1545
670k
            LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1546
670k
        }
1547
670k
    } else if (r == LY_ENOT) {
1548
        /* parse it again as an opaq node */
1549
0
        r = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status, status, first_p, node);
1550
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1551
1552
0
        if (snode->nodetype == LYS_LIST) {
1553
0
            ((struct lyd_node_opaq *)*node)->hints |= LYD_NODEHINT_LIST;
1554
0
        } else if (snode->nodetype == LYS_LEAFLIST) {
1555
0
            ((struct lyd_node_opaq *)*node)->hints |= LYD_NODEHINT_LEAFLIST;
1556
0
        }
1557
10
    } else {
1558
        /* error */
1559
10
        rc = r;
1560
10
        goto cleanup;
1561
10
    }
1562
1563
673k
cleanup:
1564
673k
    LOG_LOCBACK(1, 0);
1565
673k
    return rc;
1566
673k
}
1567
1568
/**
1569
 * @brief Parse JSON subtree. All leaf-list and list instances of a node are considered one subtree.
1570
 *
1571
 * @param[in] lydctx JSON data parser context.
1572
 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
1573
 * @param[in,out] first_p Pointer to the variable holding the first top-level sibling, must be set if @p parent is not.
1574
 * @param[in,out] parsed Optional set to add all the parsed siblings into.
1575
 * @return LY_ERR value.
1576
 */
1577
static LY_ERR
1578
lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
1579
254k
{
1580
254k
    LY_ERR r, rc = LY_SUCCESS;
1581
254k
    enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(lydctx->jsonctx);
1582
254k
    const char *name, *prefix = NULL, *expected = NULL;
1583
254k
    size_t name_len, prefix_len = 0;
1584
254k
    ly_bool is_meta = 0, parse_subtree;
1585
254k
    const struct lysc_node *snode = NULL;
1586
254k
    struct lysc_ext_instance *ext = NULL;
1587
254k
    struct lyd_node *node = NULL, *attr_node = NULL;
1588
254k
    const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
1589
254k
    char *value = NULL;
1590
1591
254k
    assert(parent || first_p);
1592
254k
    assert((status == LYJSON_OBJECT) || (status == LYJSON_OBJECT_NEXT));
1593
1594
254k
    parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
1595
    /* all descendants should be parsed */
1596
254k
    lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
1597
1598
254k
    r = lyjson_ctx_next(lydctx->jsonctx, &status);
1599
254k
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1600
253k
    if (status == LYJSON_OBJECT_CLOSED) {
1601
        /* empty object, fine... */
1602
1.24k
        goto cleanup;
1603
1.24k
    }
1604
1605
    /* process the node name */
1606
251k
    assert(status == LYJSON_OBJECT_NAME);
1607
251k
    lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_meta);
1608
251k
    lyjson_ctx_give_dynamic_value(lydctx->jsonctx, &value);
1609
1610
251k
    if ((lydctx->int_opts & LYD_INTOPT_EVENTTIME) && !parent && !is_meta && name_len && !prefix_len &&
1611
251k
            !ly_strncmp("eventTime", name, name_len)) {
1612
        /* parse eventTime */
1613
0
        r = lyjson_ctx_next(lydctx->jsonctx, &status);
1614
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1615
1616
0
        if (status != LYJSON_STRING) {
1617
0
            LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX_JSON, "Expecting JSON %s but %s found.", lyjson_token2str(LYJSON_STRING),
1618
0
                    lyjson_token2str(status));
1619
0
            rc = LY_EVALID;
1620
0
            goto cleanup;
1621
0
        }
1622
1623
        /* create node */
1624
0
        r = lyd_create_opaq(lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, prefix, prefix_len,
1625
0
                lydctx->jsonctx->value, lydctx->jsonctx->value_len, NULL, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, &node);
1626
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1627
1628
        /* validate the value */
1629
0
        r = lyd_parser_notif_eventtime_validate(node);
1630
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1631
1632
0
        goto node_parsed;
1633
251k
    } else if (!is_meta || name_len || prefix_len) {
1634
        /* get the schema node */
1635
251k
        r = lydjson_get_snode(lydctx, is_meta, prefix, prefix_len, name, name_len, parent, &snode, &ext);
1636
251k
        if (r == LY_ENOT) {
1637
            /* data parsed */
1638
0
            goto cleanup;
1639
251k
        } else if ((r == LY_EVALID) && (lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR)) {
1640
0
            rc = r;
1641
1642
            /* skip the invalid data */
1643
0
            if ((r = lydjson_data_skip(lydctx->jsonctx))) {
1644
0
                rc = r;
1645
0
            }
1646
0
            r = lyjson_ctx_next(lydctx->jsonctx, &status);
1647
0
            LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1648
0
            goto cleanup;
1649
251k
        } else if (r) {
1650
            /* error */
1651
40
            rc = r;
1652
40
            goto cleanup;
1653
40
        }
1654
1655
251k
        if (!snode) {
1656
            /* we will not be parsing it as metadata */
1657
124k
            is_meta = 0;
1658
124k
        }
1659
251k
    }
1660
1661
251k
    if (is_meta) {
1662
        /* parse as metadata */
1663
9.86k
        if (!name_len && !prefix_len && !parent) {
1664
0
            LOGVAL(ctx, LYVE_SYNTAX_JSON,
1665
0
                    "Invalid metadata format - \"@\" can be used only inside anydata, container or list entries.");
1666
0
            r = LY_EVALID;
1667
0
            LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1668
9.86k
        } else if (!name_len && !prefix_len) {
1669
            /* parent's metadata without a name - use the schema from the parent */
1670
319
            attr_node = parent;
1671
319
            snode = attr_node->schema;
1672
319
        }
1673
9.86k
        r = lydjson_parse_attribute(lydctx, attr_node, snode, name, name_len, prefix, prefix_len, parent, &status,
1674
9.86k
                first_p, &node);
1675
9.86k
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1676
242k
    } else if (!snode) {
1677
124k
        if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
1678
            /* skip element with children */
1679
22.5k
            r = lydjson_data_skip(lydctx->jsonctx);
1680
22.5k
            LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1681
101k
        } else {
1682
            /* parse as an opaq node */
1683
1684
            /* opaq node cannot have an empty string as the name. */
1685
101k
            if (name_len == 0) {
1686
13
                LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX_JSON, "JSON object member name cannot be a zero-length string.");
1687
13
                r = LY_EVALID;
1688
13
                LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1689
0
            }
1690
1691
            /* move to the second item in the name/X pair and parse opaq */
1692
101k
            r = lydjson_ctx_next_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent, &status, first_p, &node);
1693
101k
            LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1694
23.7k
        }
1695
124k
    } else {
1696
        /* parse as a standard lyd_node but it can still turn out to be an opaque node */
1697
1698
        /* move to the second item in the name/X pair */
1699
118k
        r = lyjson_ctx_next(lydctx->jsonctx, &status);
1700
118k
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1701
1702
        /* set expected representation */
1703
117k
        switch (snode->nodetype) {
1704
10.2k
        case LYS_LEAFLIST:
1705
10.2k
            expected = "name/array of values";
1706
10.2k
            break;
1707
269
        case LYS_LIST:
1708
269
            expected = "name/array of objects";
1709
269
            break;
1710
95.6k
        case LYS_LEAF:
1711
95.6k
            if (status == LYJSON_ARRAY) {
1712
3
                expected = "name/[null]";
1713
95.6k
            } else {
1714
95.6k
                expected = "name/value";
1715
95.6k
            }
1716
95.6k
            break;
1717
11.6k
        case LYS_CONTAINER:
1718
11.6k
        case LYS_NOTIF:
1719
11.6k
        case LYS_ACTION:
1720
11.6k
        case LYS_RPC:
1721
11.6k
        case LYS_ANYDATA:
1722
11.6k
            expected = "name/object";
1723
11.6k
            break;
1724
0
        case LYS_ANYXML:
1725
0
            if (status == LYJSON_ARRAY) {
1726
0
                expected = "name/array";
1727
0
            } else {
1728
0
                expected = "name/value";
1729
0
            }
1730
0
            break;
1731
117k
        }
1732
1733
        /* check the representation according to the nodetype and then continue with the content */
1734
117k
        switch (snode->nodetype) {
1735
10.2k
        case LYS_LEAFLIST:
1736
10.4k
        case LYS_LIST:
1737
10.4k
            LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
1738
1739
            /* process all the values/objects */
1740
566k
            do {
1741
                /* move into array/next value */
1742
566k
                r = lyjson_ctx_next(lydctx->jsonctx, &status);
1743
566k
                LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1744
566k
                if (status == LYJSON_ARRAY_CLOSED) {
1745
                    /* empty array, fine... */
1746
198
                    break;
1747
198
                }
1748
1749
566k
                r = lydjson_parse_instance(lydctx, parent, first_p, snode, ext, name, name_len, prefix, prefix_len,
1750
566k
                        &status, &node);
1751
566k
                if (r == LY_ENOT) {
1752
2
                    goto representation_error;
1753
2
                }
1754
566k
                LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1755
1756
566k
                lydjson_maintain_children(parent, first_p, &node,
1757
566k
                        lydctx->parse_opts & LYD_PARSE_ORDERED ? LYD_INSERT_NODE_LAST : LYD_INSERT_NODE_DEFAULT, ext);
1758
1759
                /* move after the item(s) */
1760
566k
                r = lyjson_ctx_next(lydctx->jsonctx, &status);
1761
566k
                LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1762
565k
            } while (status == LYJSON_ARRAY_NEXT);
1763
1764
9.88k
            break;
1765
95.6k
        case LYS_LEAF:
1766
107k
        case LYS_CONTAINER:
1767
107k
        case LYS_NOTIF:
1768
107k
        case LYS_ACTION:
1769
107k
        case LYS_RPC:
1770
107k
        case LYS_ANYDATA:
1771
107k
        case LYS_ANYXML:
1772
            /* process the value/object */
1773
107k
            r = lydjson_parse_instance(lydctx, parent, first_p, snode, ext, name, name_len, prefix, prefix_len,
1774
107k
                    &status, &node);
1775
107k
            if (r == LY_ENOT) {
1776
1
                goto representation_error;
1777
1
            }
1778
107k
            LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1779
1780
104k
            if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
1781
                /* rememeber the RPC/action/notification */
1782
0
                lydctx->op_node = node;
1783
0
            }
1784
104k
            break;
1785
117k
        }
1786
117k
    }
1787
1788
169k
node_parsed:
1789
    /* rememeber a successfully parsed node */
1790
169k
    if (parsed && node) {
1791
99.8k
        ly_set_add(parsed, node, 1, NULL);
1792
99.8k
    }
1793
1794
    /* finally connect the parsed node, is zeroed */
1795
169k
    lydjson_maintain_children(parent, first_p, &node,
1796
169k
            lydctx->parse_opts & LYD_PARSE_ORDERED ? LYD_INSERT_NODE_LAST : LYD_INSERT_NODE_DEFAULT, ext);
1797
1798
169k
    if (!parse_subtree) {
1799
        /* move after the item(s) */
1800
169k
        r = lyjson_ctx_next(lydctx->jsonctx, &status);
1801
169k
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1802
168k
    }
1803
1804
    /* success */
1805
168k
    goto cleanup;
1806
1807
168k
representation_error:
1808
4
    LOGVAL(ctx, LYVE_SYNTAX_JSON, "Expecting JSON %s but %s \"%s\" is represented in input data as name/%s.",
1809
4
            expected, lys_nodetype2str(snode->nodetype), snode->name, lyjson_token2str(status));
1810
4
    rc = LY_EVALID;
1811
4
    if (lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR) {
1812
        /* try to skip the invalid data */
1813
0
        if ((r = lydjson_data_skip(lydctx->jsonctx))) {
1814
0
            rc = r;
1815
0
        }
1816
0
    }
1817
1818
254k
cleanup:
1819
254k
    free(value);
1820
254k
    lyd_free_tree(node);
1821
254k
    return rc;
1822
4
}
1823
1824
/**
1825
 * @brief Common start of JSON parser processing different types of the input data.
1826
 *
1827
 * @param[in] ctx libyang context
1828
 * @param[in] in Input structure.
1829
 * @param[in] parse_opts Options for parser, see @ref dataparseroptions.
1830
 * @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
1831
 * @param[out] lydctx_p Data parser context to finish validation.
1832
 * @return LY_ERR value.
1833
 */
1834
static LY_ERR
1835
lyd_parse_json_init(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts,
1836
        struct lyd_json_ctx **lydctx_p)
1837
5.97k
{
1838
5.97k
    LY_ERR ret = LY_SUCCESS;
1839
5.97k
    struct lyd_json_ctx *lydctx;
1840
5.97k
    enum LYJSON_PARSER_STATUS status;
1841
1842
5.97k
    assert(lydctx_p);
1843
1844
    /* init context */
1845
5.97k
    lydctx = calloc(1, sizeof *lydctx);
1846
5.97k
    LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1847
5.97k
    lydctx->parse_opts = parse_opts;
1848
5.97k
    lydctx->val_opts = val_opts;
1849
5.97k
    lydctx->free = lyd_json_ctx_free;
1850
1851
5.97k
    LY_CHECK_ERR_RET(ret = lyjson_ctx_new(ctx, in, &lydctx->jsonctx), free(lydctx), ret);
1852
5.84k
    status = lyjson_ctx_status(lydctx->jsonctx);
1853
1854
    /* parse_opts & LYD_PARSE_SUBTREE not implemented */
1855
5.84k
    if (status != LYJSON_OBJECT) {
1856
        /* expecting top-level object */
1857
14
        LOGVAL(ctx, LYVE_SYNTAX_JSON, "Expected top-level JSON object, but %s found.", lyjson_token2str(status));
1858
14
        *lydctx_p = NULL;
1859
14
        lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1860
14
        return LY_EVALID;
1861
14
    }
1862
1863
5.83k
    *lydctx_p = lydctx;
1864
5.83k
    return LY_SUCCESS;
1865
5.84k
}
1866
1867
LY_ERR
1868
lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1869
        struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, uint32_t int_opts,
1870
        struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
1871
5.97k
{
1872
5.97k
    LY_ERR r, rc = LY_SUCCESS;
1873
5.97k
    struct lyd_json_ctx *lydctx = NULL;
1874
5.97k
    enum LYJSON_PARSER_STATUS status;
1875
1876
5.97k
    rc = lyd_parse_json_init(ctx, in, parse_opts, val_opts, &lydctx);
1877
5.97k
    LY_CHECK_GOTO(rc, cleanup);
1878
1879
5.83k
    lydctx->int_opts = int_opts;
1880
5.83k
    lydctx->ext = ext;
1881
1882
    /* find the operation node if it exists already */
1883
5.83k
    LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1884
1885
    /* read subtree(s) */
1886
117k
    do {
1887
117k
        r = lydjson_subtree_r(lydctx, parent, first_p, parsed);
1888
117k
        LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1889
1890
112k
        status = lyjson_ctx_status(lydctx->jsonctx);
1891
1892
112k
        if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1893
0
            break;
1894
0
        }
1895
112k
    } while (status == LYJSON_OBJECT_NEXT);
1896
1897
684
    if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && lydctx->jsonctx->in->current[0] && (status != LYJSON_OBJECT_CLOSED)) {
1898
0
        LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1899
0
        r = LY_EVALID;
1900
0
        LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1901
0
    }
1902
684
    if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1903
0
        LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1904
0
        r = LY_EVALID;
1905
0
        LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
1906
0
    }
1907
1908
    /* finish linking metadata */
1909
684
    r = lydjson_metadata_finish(lydctx, parent ? lyd_node_child_p(parent) : first_p);
1910
684
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1911
1912
553
    if (parse_opts & LYD_PARSE_SUBTREE) {
1913
        /* check for a sibling object */
1914
0
        assert(subtree_sibling);
1915
0
        if (status == LYJSON_OBJECT_NEXT) {
1916
0
            *subtree_sibling = 1;
1917
1918
            /* move to the next object */
1919
0
            ly_in_skip(lydctx->jsonctx->in, 1);
1920
0
        } else {
1921
0
            *subtree_sibling = 0;
1922
0
        }
1923
0
    }
1924
1925
5.97k
cleanup:
1926
    /* there should be no unresolved types stored */
1927
5.97k
    assert(!(parse_opts & LYD_PARSE_ONLY) || !lydctx || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1928
5.97k
            !lydctx->node_when.count));
1929
1930
5.97k
    if (rc && (!lydctx || !(lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR) || (rc != LY_EVALID))) {
1931
5.42k
        lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1932
5.42k
    } else {
1933
553
        *lydctx_p = (struct lyd_ctx *)lydctx;
1934
1935
        /* the JSON context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1936
553
        lyjson_ctx_free(lydctx->jsonctx);
1937
553
        lydctx->jsonctx = NULL;
1938
553
    }
1939
5.97k
    return rc;
1940
5.97k
}
1941
1942
/**
1943
 * @brief Parse a specific JSON object into an opaque node.
1944
 *
1945
 * @param[in] jsonctx JSON parser context.
1946
 * @param[in] name Name of the object.
1947
 * @param[in] module Module name of the object, NULL if none expected.
1948
 * @param[out] evnp Parsed envelope (opaque node).
1949
 * @return LY_SUCCESS on success.
1950
 * @return LY_ENOT if the specified object did not match.
1951
 * @return LY_ERR value on error.
1952
 */
1953
static LY_ERR
1954
lydjson_envelope(struct lyjson_ctx *jsonctx, const char *name, const char *module, struct lyd_node **envp)
1955
0
{
1956
0
    LY_ERR rc = LY_SUCCESS, r;
1957
0
    enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx);
1958
0
    const char *nam, *prefix;
1959
0
    size_t nam_len, prefix_len;
1960
0
    ly_bool is_meta;
1961
1962
0
    assert(status == LYJSON_OBJECT);
1963
1964
0
    *envp = NULL;
1965
1966
0
    r = lyjson_ctx_next(jsonctx, &status);
1967
0
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1968
0
    if (status == LYJSON_OBJECT_CLOSED) {
1969
0
        LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Empty JSON object.");
1970
0
        rc = LY_EVALID;
1971
0
        goto cleanup;
1972
0
    }
1973
1974
    /* process the name */
1975
0
    assert(status == LYJSON_OBJECT_NAME);
1976
0
    lydjson_parse_name(jsonctx->value, jsonctx->value_len, &nam, &nam_len, &prefix, &prefix_len, &is_meta);
1977
0
    if (is_meta) {
1978
0
        LOGVAL(jsonctx->ctx, LYVE_DATA, "Unexpected metadata.");
1979
0
        rc = LY_EVALID;
1980
0
        goto cleanup;
1981
0
    } else if (module && ly_strncmp(module, prefix, prefix_len)) {
1982
0
        LOGVAL(jsonctx->ctx, LYVE_DATA, "Unexpected module \"%.*s\" instead of \"%s\".", (int)prefix_len, prefix, module);
1983
0
        rc = LY_EVALID;
1984
0
        goto cleanup;
1985
0
    } else if (ly_strncmp(name, nam, nam_len)) {
1986
0
        LOGVAL(jsonctx->ctx, LYVE_DATA, "Unexpected object \"%.*s\" instead of \"%s\".", (int)nam_len, nam, name);
1987
0
        rc = LY_EVALID;
1988
0
        goto cleanup;
1989
0
    }
1990
1991
0
    r = lyjson_ctx_next(jsonctx, &status);
1992
0
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1993
1994
    /* create node */
1995
0
    rc = lyd_create_opaq(jsonctx->ctx, name, strlen(name), prefix, prefix_len, prefix, prefix_len, NULL, 0, NULL,
1996
0
            LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, envp);
1997
0
    LY_CHECK_GOTO(rc, cleanup);
1998
1999
0
cleanup:
2000
0
    if (rc) {
2001
0
        lyd_free_tree(*envp);
2002
0
        *envp = NULL;
2003
0
    }
2004
0
    return rc;
2005
0
}
2006
2007
LY_ERR
2008
lyd_parse_json_restconf(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
2009
        struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
2010
        struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
2011
0
{
2012
0
    LY_ERR rc = LY_SUCCESS, r;
2013
0
    struct lyd_json_ctx *lydctx = NULL;
2014
0
    struct lyd_node *node;
2015
0
    uint32_t i, int_opts = 0, close_elem = 0;
2016
2017
0
    assert(ctx && in && lydctx_p);
2018
0
    assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
2019
0
    assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
2020
2021
0
    assert((data_type == LYD_TYPE_RPC_RESTCONF) || (data_type == LYD_TYPE_NOTIF_RESTCONF) ||
2022
0
            (data_type == LYD_TYPE_REPLY_RESTCONF));
2023
0
    assert(!(parse_opts & LYD_PARSE_SUBTREE));
2024
2025
    /* init context */
2026
0
    rc = lyd_parse_json_init(ctx, in, parse_opts, val_opts, &lydctx);
2027
0
    LY_CHECK_GOTO(rc, cleanup);
2028
0
    lydctx->ext = ext;
2029
2030
0
    switch (data_type) {
2031
0
    case LYD_TYPE_RPC_RESTCONF:
2032
0
        assert(parent);
2033
2034
        /* parse "input" */
2035
0
        rc = lydjson_envelope(lydctx->jsonctx, "input", lyd_node_module(parent)->name, envp);
2036
0
        LY_CHECK_GOTO(rc, cleanup);
2037
2038
0
        int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_RPC | LYD_INTOPT_ACTION;
2039
0
        close_elem = 1;
2040
0
        break;
2041
0
    case LYD_TYPE_NOTIF_RESTCONF:
2042
0
        assert(!parent);
2043
2044
        /* parse "notification" */
2045
0
        rc = lydjson_envelope(lydctx->jsonctx, "notification", "ietf-restconf", envp);
2046
0
        LY_CHECK_GOTO(rc, cleanup);
2047
2048
        /* RESTCONF notification and eventTime */
2049
0
        int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_NOTIF | LYD_INTOPT_EVENTTIME;
2050
0
        close_elem = 1;
2051
0
        break;
2052
0
    case LYD_TYPE_REPLY_RESTCONF:
2053
0
        assert(parent);
2054
2055
        /* parse "output" */
2056
0
        rc = lydjson_envelope(lydctx->jsonctx, "output", lyd_node_module(parent)->name, envp);
2057
0
        LY_CHECK_GOTO(rc, cleanup);
2058
2059
0
        int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
2060
0
        close_elem = 1;
2061
0
        break;
2062
0
    default:
2063
0
        LOGINT(ctx);
2064
0
        rc = LY_EINT;
2065
0
        goto cleanup;
2066
0
    }
2067
2068
0
    lydctx->int_opts = int_opts;
2069
2070
    /* find the operation node if it exists already */
2071
0
    LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
2072
2073
    /* read subtree(s) */
2074
0
    do {
2075
0
        r = lydjson_subtree_r(lydctx, parent, first_p, parsed);
2076
0
        LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
2077
0
    } while (lyjson_ctx_status(lydctx->jsonctx) == LYJSON_OBJECT_NEXT);
2078
2079
    /* close all opened elements */
2080
0
    for (i = 0; i < close_elem; ++i) {
2081
0
        if (lyjson_ctx_status(lydctx->jsonctx) != LYJSON_OBJECT_CLOSED) {
2082
0
            LOGVAL(ctx, LYVE_SYNTAX_JSON, "Expecting JSON %s but %s found.", lyjson_token2str(LYJSON_OBJECT_CLOSED),
2083
0
                    lyjson_token2str(lyjson_ctx_status(lydctx->jsonctx)));
2084
0
            rc = LY_EVALID;
2085
0
            goto cleanup;
2086
0
        }
2087
2088
0
        r = lyjson_ctx_next(lydctx->jsonctx, NULL);
2089
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
2090
0
    }
2091
2092
0
    if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
2093
0
        LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
2094
0
        r = LY_EVALID;
2095
0
        LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
2096
0
    }
2097
0
    if (int_opts & LYD_INTOPT_EVENTTIME) {
2098
        /* parse as a child of the envelope */
2099
0
        node = (*first_p)->prev;
2100
0
        if (node->schema) {
2101
0
            LOGVAL(ctx, LYVE_DATA, "Missing notification \"eventTime\" node.");
2102
0
            r = LY_EVALID;
2103
0
            LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
2104
0
        } else {
2105
            /* can be the only opaque node and an operation had to be parsed */
2106
0
            assert(!strcmp(LYD_NAME(node), "eventTime") && (*first_p)->next);
2107
0
            lyd_unlink(node);
2108
0
            assert(*envp);
2109
0
            lyd_insert_child(*envp, node);
2110
0
        }
2111
0
    }
2112
2113
    /* finish linking metadata */
2114
0
    r = lydjson_metadata_finish(lydctx, parent ? lyd_node_child_p(parent) : first_p);
2115
0
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
2116
2117
0
cleanup:
2118
    /* there should be no unres stored if validation should be skipped */
2119
0
    assert(!(parse_opts & LYD_PARSE_ONLY) || !lydctx || (!lydctx->node_types.count && !lydctx->meta_types.count &&
2120
0
            !lydctx->node_when.count));
2121
2122
0
    if (rc) {
2123
0
        lyd_json_ctx_free((struct lyd_ctx *)lydctx);
2124
0
    } else {
2125
0
        *lydctx_p = (struct lyd_ctx *)lydctx;
2126
2127
        /* the JSON context is no more needed, freeing it also stops logging line numbers which would be confusing now */
2128
0
        lyjson_ctx_free(lydctx->jsonctx);
2129
0
        lydctx->jsonctx = NULL;
2130
0
    }
2131
0
    return rc;
2132
0
}