blob: 930e90caab873b9f98b8a29ca5c0d9a4b012e20e [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
Michal Vasko59892dd2022-05-13 11:02:30 +02002 * @file tree_data_common.c
Radek Krejcie7b95092019-05-15 11:03:07 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vasko59892dd2022-05-13 11:02:30 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
5 * @brief Parsing and validation common functions for data trees
Radek Krejcie7b95092019-05-15 11:03:07 +02006 *
Michal Vasko8cc3f662022-03-29 11:25:51 +02007 * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
Radek Krejcie7b95092019-05-15 11:03:07 +02008 *
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 */
Michal Vasko43297a02021-05-19 11:12:37 +020015
16#define _GNU_SOURCE /* asprintf, strdup */
Radek Krejcie7b95092019-05-15 11:03:07 +020017
18#include <assert.h>
Michal Vasko43297a02021-05-19 11:12:37 +020019#include <ctype.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020022#include <string.h>
Michal Vasko43297a02021-05-19 11:12:37 +020023#include <time.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020024
Radek Krejci535ea9f2020-05-29 16:01:05 +020025#include "common.h"
Michal Vasko6b5cb2a2020-11-11 19:11:21 +010026#include "compat.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020027#include "context.h"
Radek Krejci47fab892020-11-05 17:02:41 +010028#include "dict.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020029#include "hash_table.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020030#include "log.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020031#include "lyb.h"
Radek Krejci7931b192020-06-25 17:05:03 +020032#include "parser_data.h"
Michal Vasko8cc3f662022-03-29 11:25:51 +020033#include "plugins_exts.h"
Michal Vaskoa820c312021-02-05 16:33:00 +010034#include "printer_data.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020035#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020036#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020037#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020038#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010039#include "tree_edit.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020040#include "tree_schema.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020041#include "tree_schema_internal.h"
Radek Krejci4f2e3e52021-03-30 14:20:28 +020042#include "validation.h"
Radek Krejci77114102021-03-10 15:21:57 +010043#include "xml.h"
aPiecekdf23eee2021-10-07 12:21:50 +020044#include "xpath.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020045
Michal Vaskod7c048c2021-05-18 16:12:55 +020046/**
47 * @brief Find an entry in duplicate instance cache for an instance. Create it if it does not exist.
48 *
49 * @param[in] first_inst Instance of the cache entry.
50 * @param[in,out] dup_inst_cache Duplicate instance cache.
51 * @return Instance cache entry.
52 */
53static struct lyd_dup_inst *
54lyd_dup_inst_get(const struct lyd_node *first_inst, struct lyd_dup_inst **dup_inst_cache)
55{
56 struct lyd_dup_inst *item;
57 LY_ARRAY_COUNT_TYPE u;
58
59 LY_ARRAY_FOR(*dup_inst_cache, u) {
60 if ((*dup_inst_cache)[u].inst_set->dnodes[0] == first_inst) {
61 return &(*dup_inst_cache)[u];
62 }
63 }
64
65 /* it was not added yet, add it now */
66 LY_ARRAY_NEW_RET(LYD_CTX(first_inst), *dup_inst_cache, item, NULL);
67
68 return item;
69}
70
71LY_ERR
72lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struct lyd_dup_inst **dup_inst_cache)
73{
74 struct lyd_dup_inst *dup_inst;
75
Michal Vasko83ae7772022-06-08 10:01:55 +020076 if (!*inst) {
77 /* no match, inst is unchanged */
Michal Vaskod7c048c2021-05-18 16:12:55 +020078 return LY_SUCCESS;
79 }
80
Michal Vasko83ae7772022-06-08 10:01:55 +020081 /* there can be more exact same instances (even if not allowed in invalid data) and we must make sure we do not
82 * match a single node more times */
Michal Vaskod7c048c2021-05-18 16:12:55 +020083 dup_inst = lyd_dup_inst_get(*inst, dup_inst_cache);
84 LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
85
86 if (!dup_inst->used) {
87 /* we did not cache these instances yet, do so */
88 lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->inst_set);
89 assert(dup_inst->inst_set->count && (dup_inst->inst_set->dnodes[0] == *inst));
90 }
91
92 if (dup_inst->used == dup_inst->inst_set->count) {
93 /* we have used all the instances */
94 *inst = NULL;
95 } else {
96 assert(dup_inst->used < dup_inst->inst_set->count);
97
98 /* use another instance */
99 *inst = dup_inst->inst_set->dnodes[dup_inst->used];
100 ++dup_inst->used;
101 }
102
103 return LY_SUCCESS;
104}
105
106void
107lyd_dup_inst_free(struct lyd_dup_inst *dup_inst)
108{
109 LY_ARRAY_COUNT_TYPE u;
110
111 LY_ARRAY_FOR(dup_inst, u) {
112 ly_set_free(dup_inst[u].inst_set, NULL);
113 }
114 LY_ARRAY_FREE(dup_inst);
115}
116
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200117struct lyd_node *
118lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +0200119 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200120{
121 const struct lysc_node *siter = NULL;
122 struct lyd_node *match = NULL;
123
124 assert(parent || module);
125 assert(!last || (slast && *slast));
126
127 if (slast) {
128 siter = *slast;
129 }
130
131 if (last && last->next && (last->next->schema == siter)) {
132 /* return next data instance */
133 return last->next;
134 }
135
136 /* find next schema node data instance */
137 while ((siter = lys_getnext(siter, parent, module, 0))) {
138 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
139 break;
140 }
141 }
142
143 if (slast) {
144 *slast = siter;
145 }
146 return match;
147}
148
Radek Krejcie7b95092019-05-15 11:03:07 +0200149struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +0100150lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200151{
152 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +0100153
154 if (!node->schema) {
155 return &((struct lyd_node_opaq *)node)->child;
156 } else {
157 switch (node->schema->nodetype) {
158 case LYS_CONTAINER:
159 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +0100160 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100161 case LYS_ACTION:
162 case LYS_NOTIF:
163 return &((struct lyd_node_inner *)node)->child;
164 default:
165 return NULL;
166 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200167 }
168}
169
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100170LIBYANG_API_DEF LY_ERR
aPiecekdf23eee2021-10-07 12:21:50 +0200171lyxp_vars_set(struct lyxp_var **vars, const char *name, const char *value)
172{
173 LY_ERR ret = LY_SUCCESS;
174 char *var_name = NULL, *var_value = NULL;
175 struct lyxp_var *item;
176
177 if (!vars || !name || !value) {
178 return LY_EINVAL;
179 }
180
181 /* If variable is already defined then change its value. */
182 if (*vars && !lyxp_vars_find(*vars, name, 0, &item)) {
183 var_value = strdup(value);
184 LY_CHECK_RET(!var_value, LY_EMEM);
185
186 /* Set new value. */
187 free(item->value);
188 item->value = var_value;
189 } else {
190 var_name = strdup(name);
191 var_value = strdup(value);
192 LY_CHECK_ERR_GOTO(!var_name || !var_value, ret = LY_EMEM, error);
193
194 /* Add new variable. */
195 LY_ARRAY_NEW_GOTO(NULL, *vars, item, ret, error);
196 item->name = var_name;
197 item->value = var_value;
198 }
199
200 return LY_SUCCESS;
201
202error:
203 free(var_name);
204 free(var_value);
205 return ret;
206}
207
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100208LIBYANG_API_DEF void
aPiecekdf23eee2021-10-07 12:21:50 +0200209lyxp_vars_free(struct lyxp_var *vars)
210{
211 LY_ARRAY_COUNT_TYPE u;
212
213 if (!vars) {
214 return;
215 }
216
217 LY_ARRAY_FOR(vars, u) {
218 free(vars[u].name);
219 free(vars[u].value);
220 }
221
222 LY_ARRAY_FREE(vars);
223}
224
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100225LIBYANG_API_DEF struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +0200226lyd_child_no_keys(const struct lyd_node *node)
227{
228 struct lyd_node **children;
229
230 if (!node) {
231 return NULL;
232 }
233
234 if (!node->schema) {
235 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100236 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200237 }
238
Michal Vaskoe0665742021-02-11 11:08:44 +0100239 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200240 if (children) {
241 struct lyd_node *child = *children;
242 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
243 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200244 }
245 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200246 } else {
247 return NULL;
248 }
249}
Michal Vasko9b368d32020-02-14 13:53:31 +0100250
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100251LIBYANG_API_DEF const struct lys_module *
Michal Vaskoc193ce92020-03-06 11:04:48 +0100252lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100253{
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100254 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100255
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100256 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100257 return NULL;
258 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100259
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100260 if (!node->schema) {
261 opaq = (struct lyd_node_opaq *)node;
262 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200263 case LY_VALUE_XML:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100264 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
Radek Krejci8df109d2021-04-23 12:19:08 +0200265 case LY_VALUE_JSON:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100266 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
267 default:
268 return NULL;
269 }
270 }
271
Michal Vaskoef53c812021-10-13 10:21:03 +0200272 return lysc_owner_module(node->schema);
Michal Vasko9b368d32020-02-14 13:53:31 +0100273}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100274
Michal Vasko598063b2021-07-19 11:39:05 +0200275void
276lyd_first_module_sibling(struct lyd_node **node, const struct lys_module *mod)
277{
278 int cmp;
279 struct lyd_node *first;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200280 const struct lys_module *own_mod;
Michal Vasko598063b2021-07-19 11:39:05 +0200281
282 assert(node && mod);
283
284 if (!*node) {
285 return;
286 }
287
288 first = *node;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200289 own_mod = lyd_owner_module(first);
290 cmp = own_mod ? strcmp(own_mod->name, mod->name) : 1;
Michal Vasko598063b2021-07-19 11:39:05 +0200291 if (cmp > 0) {
292 /* there may be some preceding data */
293 while (first->prev->next) {
294 first = first->prev;
295 if (lyd_owner_module(first) == mod) {
296 cmp = 0;
297 break;
298 }
299 }
300 }
301
302 if (cmp == 0) {
303 /* there may be some preceding data belonging to this module */
304 while (first->prev->next) {
305 if (lyd_owner_module(first->prev) != mod) {
306 break;
307 }
308 first = first->prev;
309 }
310 }
311
312 if (cmp < 0) {
313 /* there may be some following data */
314 LY_LIST_FOR(first, first) {
315 if (lyd_owner_module(first) == mod) {
316 cmp = 0;
317 break;
318 }
319 }
320 }
321
322 if (cmp == 0) {
323 /* we have found the first module data node */
324 *node = first;
325 }
326}
327
Michal Vaskob1b5c262020-03-05 14:29:47 +0100328const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200329lyd_mod_next_module(struct lyd_node *tree, const struct lys_module *module, const struct ly_ctx *ctx, uint32_t *i,
Radek Krejci0f969882020-08-21 16:56:47 +0200330 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100331{
332 struct lyd_node *iter;
333 const struct lys_module *mod;
334
335 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200336 if (module) {
337 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100338 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200339 } else {
340 mod = module;
341 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100342 }
343 } else {
344 do {
345 mod = ly_ctx_get_module_iter(ctx, i);
346 } while (mod && !mod->implemented);
347 }
348
349 /* find its data */
350 *first = NULL;
351 if (mod) {
352 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100353 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100354 *first = iter;
355 break;
356 }
357 }
358 }
359
360 return mod;
361}
362
363const struct lys_module *
364lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
365{
366 const struct lys_module *mod;
367
368 if (!*next) {
369 /* all data traversed */
370 *first = NULL;
371 return NULL;
372 }
373
374 *first = *next;
375
376 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100377 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100378 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100379 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100380 break;
381 }
382 }
383
384 return mod;
385}
Michal Vasko9f96a052020-03-10 09:41:45 +0100386
387LY_ERR
Michal Vasko59892dd2022-05-13 11:02:30 +0200388lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct lysc_type *type, const void *value,
389 size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
390 const struct lysc_node *ctx_node, ly_bool *incomplete)
391{
392 LY_ERR ret;
393 struct ly_err_item *err = NULL;
394 uint32_t options = (dynamic && *dynamic ? LYPLG_TYPE_STORE_DYNAMIC : 0);
395
396 if (!value) {
397 value = "";
398 }
399 if (incomplete) {
400 *incomplete = 0;
401 }
402
403 ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data, hints, ctx_node, val, NULL, &err);
404 if (dynamic) {
405 *dynamic = 0;
406 }
407
408 if (ret == LY_EINCOMPLETE) {
409 if (incomplete) {
410 *incomplete = 1;
411 }
412 } else if (ret) {
413 if (err) {
414 LOGVAL_ERRITEM(ctx, err);
415 ly_err_free(err);
416 } else {
417 LOGVAL(ctx, LYVE_OTHER, "Storing value failed.");
418 }
419 return ret;
420 }
421
422 return LY_SUCCESS;
423}
424
425LY_ERR
426lyd_value_validate_incomplete(const struct ly_ctx *ctx, const struct lysc_type *type, struct lyd_value *val,
427 const struct lyd_node *ctx_node, const struct lyd_node *tree)
428{
429 LY_ERR ret;
430 struct ly_err_item *err = NULL;
431
432 assert(type->plugin->validate);
433
434 ret = type->plugin->validate(ctx, type, ctx_node, tree, val, &err);
435 if (ret) {
436 if (err) {
437 LOGVAL_ERRITEM(ctx, err);
438 ly_err_free(err);
439 } else {
440 LOGVAL(ctx, LYVE_OTHER, "Resolving value \"%s\" failed.", type->plugin->print(ctx, val, LY_VALUE_CANON,
441 NULL, NULL, NULL));
442 }
443 return ret;
444 }
445
446 return LY_SUCCESS;
447}
448
449LY_ERR
450lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
451 LY_VALUE_FORMAT format, void *prefix_data)
452{
453 LY_ERR rc = LY_SUCCESS;
454 struct ly_err_item *err = NULL;
455 struct lyd_value storage;
456 struct lysc_type *type;
457
458 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
459
460 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
461 LOGARG(ctx, node);
462 return LY_EINVAL;
463 }
464
465 type = ((struct lysc_node_leaf *)node)->type;
466 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, 0, format, prefix_data,
467 LYD_HINT_SCHEMA, node, &storage, NULL, &err);
468 if (rc == LY_EINCOMPLETE) {
469 /* actually success since we do not provide the context tree and call validation with
470 * LY_TYPE_OPTS_INCOMPLETE_DATA */
471 rc = LY_SUCCESS;
472 } else if (rc && err) {
473 if (ctx) {
474 /* log only in case the ctx was provided as input parameter */
Michal Vaskof8da2682022-06-16 07:52:37 +0200475 if (err->path) {
476 LOG_LOCSET(NULL, NULL, err->path, NULL);
477 } else {
478 /* use at least the schema path */
479 LOG_LOCSET(node, NULL, NULL, NULL);
480 }
Michal Vasko59892dd2022-05-13 11:02:30 +0200481 LOGVAL_ERRITEM(ctx, err);
Michal Vaskof8da2682022-06-16 07:52:37 +0200482 if (err->path) {
483 LOG_LOCBACK(0, 0, 1, 0);
484 } else {
485 LOG_LOCBACK(1, 0, 0, 0);
486 }
Michal Vasko59892dd2022-05-13 11:02:30 +0200487 }
488 ly_err_free(err);
489 }
490
491 if (!rc) {
492 type->plugin->free(ctx ? ctx : node->module->ctx, &storage);
493 }
494 return rc;
495}
496
497LIBYANG_API_DEF LY_ERR
498lyd_value_validate(const struct ly_ctx *ctx, const struct lysc_node *schema, const char *value, size_t value_len,
499 const struct lyd_node *ctx_node, const struct lysc_type **realtype, const char **canonical)
500{
501 LY_ERR rc;
502 struct ly_err_item *err = NULL;
503 struct lysc_type *type;
504 struct lyd_value val = {0};
505 ly_bool stored = 0, log = 1;
506
Michal Vasko3dd16da2022-06-15 07:58:41 +0200507 LY_CHECK_ARG_RET(ctx, schema, !value_len || value, LY_EINVAL);
Michal Vasko59892dd2022-05-13 11:02:30 +0200508
509 if (!ctx) {
510 ctx = schema->module->ctx;
511 log = 0;
512 }
Michal Vasko3dd16da2022-06-15 07:58:41 +0200513 if (!value_len) {
514 value = "";
515 }
Michal Vasko59892dd2022-05-13 11:02:30 +0200516 type = ((struct lysc_node_leaf *)schema)->type;
517
518 /* store */
519 rc = type->plugin->store(ctx, type, value, value_len, 0, LY_VALUE_JSON, NULL,
520 LYD_HINT_DATA, schema, &val, NULL, &err);
521 if (!rc || (rc == LY_EINCOMPLETE)) {
522 stored = 1;
523 }
524
525 if (ctx_node && (rc == LY_EINCOMPLETE)) {
526 /* resolve */
527 rc = type->plugin->validate(ctx, type, ctx_node, ctx_node, &val, &err);
528 }
529
530 if (rc && (rc != LY_EINCOMPLETE) && err) {
531 if (log) {
532 /* log error */
533 if (err->path) {
534 LOG_LOCSET(NULL, NULL, err->path, NULL);
535 } else if (ctx_node) {
536 LOG_LOCSET(NULL, ctx_node, NULL, NULL);
537 } else {
538 LOG_LOCSET(schema, NULL, NULL, NULL);
539 }
540 LOGVAL_ERRITEM(ctx, err);
541 if (err->path) {
542 LOG_LOCBACK(0, 0, 1, 0);
543 } else if (ctx_node) {
544 LOG_LOCBACK(0, 1, 0, 0);
545 } else {
546 LOG_LOCBACK(1, 0, 0, 0);
547 }
548 }
549 ly_err_free(err);
550 }
551
552 if (!rc || (rc == LY_EINCOMPLETE)) {
553 if (realtype) {
554 /* return realtype */
555 if (val.realtype->basetype == LY_TYPE_UNION) {
556 *realtype = val.subvalue->value.realtype;
557 } else {
558 *realtype = val.realtype;
559 }
560 }
561
562 if (canonical) {
563 /* return canonical value */
564 lydict_insert(ctx, val.realtype->plugin->print(ctx, &val, LY_VALUE_CANON, NULL, NULL, NULL), 0, canonical);
565 }
566 }
567
568 if (stored) {
569 /* free value */
570 type->plugin->free(ctx ? ctx : schema->module->ctx, &val);
571 }
572 return rc;
573}
574
575LIBYANG_API_DEF LY_ERR
576lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len)
577{
578 LY_ERR ret = LY_SUCCESS;
579 struct ly_ctx *ctx;
580 struct lysc_type *type;
581 struct lyd_value val = {0};
582
583 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
584
585 ctx = node->schema->module->ctx;
586 type = ((struct lysc_node_leaf *)node->schema)->type;
587
588 /* store the value */
589 LOG_LOCSET(node->schema, &node->node, NULL, NULL);
590 ret = lyd_value_store(ctx, &val, type, value, value_len, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL);
591 LOG_LOCBACK(1, 1, 0, 0);
592 LY_CHECK_RET(ret);
593
594 /* compare values */
595 ret = type->plugin->compare(&node->value, &val);
596
597 type->plugin->free(ctx, &val);
598 return ret;
599}
600
601LIBYANG_API_DEF ly_bool
602lyd_is_default(const struct lyd_node *node)
603{
604 const struct lysc_node_leaf *leaf;
605 const struct lysc_node_leaflist *llist;
606 const struct lyd_node_term *term;
607 LY_ARRAY_COUNT_TYPE u;
608
609 if (!(node->schema->nodetype & LYD_NODE_TERM)) {
610 return 0;
611 }
612
613 term = (const struct lyd_node_term *)node;
614
615 if (node->schema->nodetype == LYS_LEAF) {
616 leaf = (const struct lysc_node_leaf *)node->schema;
617 if (!leaf->dflt) {
618 return 0;
619 }
620
621 /* compare with the default value */
622 if (!leaf->type->plugin->compare(&term->value, leaf->dflt)) {
623 return 1;
624 }
625 } else {
626 llist = (const struct lysc_node_leaflist *)node->schema;
627 if (!llist->dflts) {
628 return 0;
629 }
630
631 LY_ARRAY_FOR(llist->dflts, u) {
632 /* compare with each possible default value */
633 if (!llist->type->plugin->compare(&term->value, llist->dflts[u])) {
634 return 1;
635 }
636 }
637 }
638
639 return 0;
640}
641
642LIBYANG_API_DEF uint32_t
643lyd_list_pos(const struct lyd_node *instance)
644{
645 const struct lyd_node *iter = NULL;
646 uint32_t pos = 0;
647
648 if (!instance || !(instance->schema->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
649 return 0;
650 }
651
652 /* data instances are ordered, so we can stop when we found instance of other schema node */
653 for (iter = instance; iter->schema == instance->schema; iter = iter->prev) {
654 if (pos && (iter->next == NULL)) {
655 /* overrun to the end of the siblings list */
656 break;
657 }
658 ++pos;
659 }
660
661 return pos;
662}
663
664LIBYANG_API_DEF struct lyd_node *
665lyd_first_sibling(const struct lyd_node *node)
666{
667 struct lyd_node *start;
668
669 if (!node) {
670 return NULL;
671 }
672
673 /* get the first sibling */
674 if (node->parent) {
675 start = node->parent->child;
676 } else {
677 for (start = (struct lyd_node *)node; start->prev->next; start = start->prev) {}
678 }
679
680 return start;
681}
682
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100683/**
684 * @brief Check list node parsed into an opaque node for the reason.
685 *
686 * @param[in] node Opaque node.
687 * @param[in] snode Schema node of @p opaq.
688 * @return LY_SUCCESS if the node is valid;
689 * @return LY_ERR on error.
690 */
691static LY_ERR
692lyd_parse_opaq_list_error(const struct lyd_node *node, const struct lysc_node *snode)
693{
694 LY_ERR ret = LY_SUCCESS;
695 struct ly_set key_set = {0};
696 const struct lysc_node *key = NULL;
697 const struct lyd_node *child;
698 const struct lyd_node_opaq *opaq_k;
699 uint32_t i;
700
701 assert(!node->schema);
702
703 /* get all keys into a set */
704 while ((key = lys_getnext(key, snode, NULL, 0)) && (snode->flags & LYS_KEY)) {
705 LY_CHECK_GOTO(ret = ly_set_add(&key_set, (void *)snode, 1, NULL), cleanup);
706 }
707
708 LY_LIST_FOR(lyd_child(node), child) {
709 if (child->schema) {
710 LOGERR(LYD_CTX(node), LY_EINVAL, "Unexpected node %s \"%s\".", lys_nodetype2str(child->schema->nodetype),
711 LYD_NAME(child));
712 ret = LY_EINVAL;
713 goto cleanup;
714 }
715
716 opaq_k = (struct lyd_node_opaq *)child;
717
718 /* find the key schema node */
719 for (i = 0; i < key_set.count; ++i) {
720 key = key_set.snodes[i];
721 if (!strcmp(key->name, opaq_k->name.name)) {
722 break;
723 }
724 }
725 if (i == key_set.count) {
726 /* some other node, skip */
727 continue;
728 }
729
730 /* key found */
731 ly_set_rm_index(&key_set, i, NULL);
732
733 /* check value */
734 ret = lys_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
735 opaq_k->val_prefix_data);
736 LY_CHECK_GOTO(ret, cleanup);
737 }
738
739 if (key_set.count) {
740 /* missing keys */
741 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, key_set.snodes[0]->name);
742 ret = LY_EVALID;
743 goto cleanup;
744 }
745
746cleanup:
747 ly_set_erase(&key_set, NULL);
748 return ret;
749}
750
751LIBYANG_API_DEF LY_ERR
752lyd_parse_opaq_error(const struct lyd_node *node)
753{
754 const struct ly_ctx *ctx;
755 const struct lyd_node_opaq *opaq;
756 const struct lyd_node *parent;
757 const struct lys_module *mod;
758 const struct lysc_node *snode;
759
760 LY_CHECK_ARG_RET(LYD_CTX(node), node, !node->schema, !lyd_parent(node) || lyd_parent(node)->schema, LY_EINVAL);
761
762 ctx = LYD_CTX(node);
763 opaq = (struct lyd_node_opaq *)node;
764 parent = lyd_parent(node);
765
Michal Vaskof4e63922022-05-10 10:32:13 +0200766 if (!opaq->name.module_ns) {
767 LOGVAL(ctx, LYVE_REFERENCE, "Unknown module of node \"%s\".", opaq->name.name);
768 return LY_EVALID;
769 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100770
771 /* module */
772 switch (opaq->format) {
773 case LY_VALUE_XML:
774 if (!parent || strcmp(opaq->name.module_ns, parent->schema->module->ns)) {
775 mod = ly_ctx_get_module_implemented_ns(ctx, opaq->name.module_ns);
776 if (!mod) {
Michal Vasko959f8d82022-06-16 07:51:50 +0200777 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module with namespace \"%s\" of node \"%s\" in the context.",
778 opaq->name.module_ns, opaq->name.name);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100779 return LY_EVALID;
780 }
781 } else {
782 /* inherit */
783 mod = parent->schema->module;
784 }
785 break;
786 case LY_VALUE_JSON:
787 case LY_VALUE_LYB:
788 if (!parent || strcmp(opaq->name.module_name, parent->schema->module->name)) {
789 mod = ly_ctx_get_module_implemented(ctx, opaq->name.module_name);
790 if (!mod) {
Michal Vasko959f8d82022-06-16 07:51:50 +0200791 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module named \"%s\" of node \"%s\" in the context.",
792 opaq->name.module_name, opaq->name.name);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100793 return LY_EVALID;
794 }
795 } else {
796 /* inherit */
797 mod = parent->schema->module;
798 }
799 break;
800 default:
801 LOGERR(ctx, LY_EINVAL, "Unsupported value format.");
802 return LY_EINVAL;
803 }
804
805 /* schema */
806 snode = lys_find_child(parent ? parent->schema : NULL, mod, opaq->name.name, 0, 0, 0);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200807 if (!snode && parent && parent->schema && (parent->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
808 /* maybe output node */
Michal Vasko89afc6e2022-05-02 10:24:26 +0200809 snode = lys_find_child(parent->schema, mod, opaq->name.name, 0, 0, LYS_GETNEXT_OUTPUT);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200810 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100811 if (!snode) {
812 if (parent) {
813 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found as a child of \"%s\" node.", opaq->name.name,
814 LYD_NAME(parent));
815 } else {
816 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found in the \"%s\" module.", opaq->name.name, mod->name);
817 }
818 return LY_EVALID;
819 }
820
821 if (snode->nodetype & LYD_NODE_TERM) {
822 /* leaf / leaf-list */
823 LY_CHECK_RET(lys_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data));
824 } else if (snode->nodetype == LYS_LIST) {
825 /* list */
826 LY_CHECK_RET(lyd_parse_opaq_list_error(node, snode));
827 } else if (snode->nodetype & LYD_NODE_INNER) {
828 /* inner node */
829 if (opaq->value) {
830 LOGVAL(ctx, LYVE_DATA, "Invalid value \"%s\" for %s \"%s\".", opaq->value,
831 lys_nodetype2str(snode->nodetype), snode->name);
832 return LY_EVALID;
833 }
834 } else {
835 LOGERR(ctx, LY_EINVAL, "Unexpected opaque schema node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
836 return LY_EINVAL;
837 }
838
839 LOGERR(ctx, LY_EINVAL, "Unexpected valid opaque node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
840 return LY_EINVAL;
841}
842
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100843LIBYANG_API_DEF const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400844lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200845{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200846 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
847
Michal Vasko33876022021-04-27 16:42:24 +0200848 return value->_canonical ? value->_canonical :
849 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200850}
851
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100852LIBYANG_API_DEF LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100853lyd_any_value_str(const struct lyd_node *any, char **value_str)
854{
855 const struct lyd_node_any *a;
856 struct lyd_node *tree = NULL;
857 const char *str = NULL;
858 ly_bool dynamic = 0;
859 LY_ERR ret = LY_SUCCESS;
860
861 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200862 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100863
864 a = (struct lyd_node_any *)any;
865 *value_str = NULL;
866
867 if (!a->value.str) {
868 /* there is no value in the union */
869 return LY_SUCCESS;
870 }
871
872 switch (a->value_type) {
873 case LYD_ANYDATA_LYB:
874 /* parse into a data tree */
875 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
876 LY_CHECK_GOTO(ret, cleanup);
877 dynamic = 1;
878 break;
879 case LYD_ANYDATA_DATATREE:
880 tree = a->value.tree;
881 break;
882 case LYD_ANYDATA_STRING:
883 case LYD_ANYDATA_XML:
884 case LYD_ANYDATA_JSON:
885 /* simply use the string */
886 str = a->value.str;
887 break;
888 }
889
890 if (tree) {
891 /* print into a string */
892 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
893 LY_CHECK_GOTO(ret, cleanup);
894 } else {
895 assert(str);
896 *value_str = strdup(str);
897 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
898 }
899
900 /* success */
901
902cleanup:
903 if (dynamic) {
904 lyd_free_all(tree);
905 }
906 return ret;
907}
908
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100909LIBYANG_API_DEF LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200910lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
911{
912 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200913
Michal Vaskoa820c312021-02-05 16:33:00 +0100914 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200915 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200916
917 t = (struct lyd_node_any *)trg;
918
919 /* free trg */
920 switch (t->value_type) {
921 case LYD_ANYDATA_DATATREE:
922 lyd_free_all(t->value.tree);
923 break;
924 case LYD_ANYDATA_STRING:
925 case LYD_ANYDATA_XML:
926 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100927 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200928 break;
929 case LYD_ANYDATA_LYB:
930 free(t->value.mem);
931 break;
932 }
933 t->value.str = NULL;
934
935 if (!value) {
936 /* only free value in this case */
937 return LY_SUCCESS;
938 }
939
940 /* copy src */
941 t->value_type = value_type;
942 switch (value_type) {
943 case LYD_ANYDATA_DATATREE:
944 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200945 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200946 }
947 break;
948 case LYD_ANYDATA_STRING:
949 case LYD_ANYDATA_XML:
950 case LYD_ANYDATA_JSON:
951 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200952 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200953 }
954 break;
955 case LYD_ANYDATA_LYB:
956 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200957 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200958 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200959 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200960 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200961 memcpy(t->value.mem, value->mem, len);
962 }
963 break;
964 }
965
966 return LY_SUCCESS;
967}
968
Michal Vasko106f0862021-11-02 11:49:27 +0100969const struct lysc_node *
970lyd_node_schema(const struct lyd_node *node)
971{
972 const struct lysc_node *schema = NULL;
973 const struct lyd_node *prev_iter = NULL, *iter;
974 const struct lys_module *mod;
975
976 if (!node) {
977 return NULL;
978 } else if (node->schema) {
979 return node->schema;
980 }
981
982 /* get schema node of an opaque node */
983 do {
984 /* get next data node */
985 for (iter = node; lyd_parent(iter) != prev_iter; iter = lyd_parent(iter)) {}
986
987 /* get equivalent schema node */
988 if (iter->schema) {
989 schema = iter->schema;
990 } else {
991 /* get module */
992 mod = lyd_owner_module(iter);
Michal Vaskoa41826a2021-11-02 12:13:03 +0100993 if (!mod && !schema) {
994 /* top-level opaque node has unknown module */
995 break;
996 }
Michal Vasko106f0862021-11-02 11:49:27 +0100997
998 /* get schema node */
999 schema = lys_find_child(schema, mod ? mod : schema->module, LYD_NAME(iter), 0, 0, 0);
1000 }
Michal Vaskod2f404f2021-11-04 15:37:11 +01001001
1002 /* remember to move to the descendant */
1003 prev_iter = iter;
Michal Vasko106f0862021-11-02 11:49:27 +01001004 } while (schema && (iter != node));
1005
1006 return schema;
1007}
1008
Michal Vasko59892dd2022-05-13 11:02:30 +02001009/**
1010 * @brief Comparison callback to match schema node with a schema of a data node.
1011 *
1012 * @param[in] val1_p Pointer to the schema node
1013 * @param[in] val2_p Pointer to the data node
1014 * Implementation of ::lyht_value_equal_cb.
1015 */
1016static ly_bool
1017lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
1018{
1019 struct lysc_node *val1;
1020 struct lyd_node *val2;
1021
1022 val1 = *((struct lysc_node **)val1_p);
1023 val2 = *((struct lyd_node **)val2_p);
1024
1025 if (val1 == val2->schema) {
1026 /* schema match is enough */
1027 return 1;
1028 } else {
1029 return 0;
1030 }
1031}
1032
1033LY_ERR
1034lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
1035{
1036 struct lyd_node **match_p;
1037 struct lyd_node_inner *parent;
1038 uint32_t hash;
1039 lyht_value_equal_cb ht_cb;
1040
1041 assert(siblings && schema);
1042
1043 parent = siblings->parent;
1044 if (parent && parent->schema && parent->children_ht) {
1045 /* calculate our hash */
1046 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
1047 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
1048 hash = dict_hash_multi(hash, NULL, 0);
1049
1050 /* use special hash table function */
1051 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
1052
1053 /* find by hash */
1054 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
1055 siblings = *match_p;
1056 } else {
1057 /* not found */
1058 siblings = NULL;
1059 }
1060
1061 /* set the original hash table compare function back */
1062 lyht_set_cb(parent->children_ht, ht_cb);
1063 } else {
1064 /* find first sibling */
1065 if (siblings->parent) {
1066 siblings = siblings->parent->child;
1067 } else {
1068 while (siblings->prev->next) {
1069 siblings = siblings->prev;
1070 }
1071 }
1072
1073 /* search manually without hashes */
1074 for ( ; siblings; siblings = siblings->next) {
1075 if (siblings->schema == schema) {
1076 /* schema match is enough */
1077 break;
1078 }
1079 }
1080 }
1081
1082 if (!siblings) {
1083 if (match) {
1084 *match = NULL;
1085 }
1086 return LY_ENOTFOUND;
1087 }
1088
1089 if (match) {
1090 *match = (struct lyd_node *)siblings;
1091 }
1092 return LY_SUCCESS;
1093}
1094
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001095void
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001096lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
1097{
1098 if (*root && (lyd_owner_module(*root) != mod)) {
1099 /* there are no data of mod so this is simply the first top-level sibling */
1100 mod = NULL;
1101 }
1102
1103 if ((*root != to_del) || (*root)->parent) {
1104 return;
1105 }
1106
Michal Vasko598063b2021-07-19 11:39:05 +02001107 if (mod && (*root)->prev->next && (!(*root)->next || (lyd_owner_module(to_del) != lyd_owner_module((*root)->next)))) {
1108 /* there are no more nodes from mod, simply get the first top-level sibling */
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001109 *root = lyd_first_sibling(*root);
Michal Vasko598063b2021-07-19 11:39:05 +02001110 } else {
1111 *root = (*root)->next;
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001112 }
1113}
1114
Michal Vasko8cc3f662022-03-29 11:25:51 +02001115LY_ERR
1116ly_nested_ext_schema(const struct lyd_node *parent, const struct lysc_node *sparent, const char *prefix,
1117 size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
1118 const struct lysc_node **snode, struct lysc_ext_instance **ext)
1119{
1120 LY_ERR r;
1121 LY_ARRAY_COUNT_TYPE u;
1122 struct lysc_ext_instance *nested_exts = NULL;
1123 lyplg_ext_data_snode_clb ext_snode_cb;
1124
1125 /* check if there are any nested extension instances */
1126 if (parent && parent->schema) {
1127 nested_exts = parent->schema->exts;
1128 } else if (sparent) {
1129 nested_exts = sparent->exts;
1130 }
1131 LY_ARRAY_FOR(nested_exts, u) {
Michal Vasko305c6cb2022-04-27 10:33:04 +02001132 if (!nested_exts[u].def->plugin) {
1133 /* no plugin */
1134 continue;
1135 }
1136
Michal Vasko8cc3f662022-03-29 11:25:51 +02001137 ext_snode_cb = nested_exts[u].def->plugin->snode;
1138 if (!ext_snode_cb) {
1139 /* not an extension with nested data */
1140 continue;
1141 }
1142
1143 /* try to get the schema node */
1144 r = ext_snode_cb(&nested_exts[u], parent, sparent, prefix, prefix_len, format, prefix_data, name, name_len, snode);
1145 if (!r) {
1146 /* data successfully created, remember the ext instance */
1147 *ext = &nested_exts[u];
1148 return LY_SUCCESS;
1149 } else if (r != LY_ENOT) {
1150 /* fatal error */
1151 return r;
1152 }
1153 /* data was not from this module, continue */
1154 }
1155
1156 /* no extensions or none matched */
1157 return LY_ENOT;
1158}
1159
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001160void
Radek Krejci8df109d2021-04-23 12:19:08 +02001161ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001162{
1163 struct ly_set *ns_list;
1164 struct lysc_prefix *prefixes;
1165 uint32_t i;
1166 LY_ARRAY_COUNT_TYPE u;
1167
1168 if (!prefix_data) {
1169 return;
1170 }
1171
1172 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001173 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001174 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001175 ns_list = prefix_data;
1176 for (i = 0; i < ns_list->count; ++i) {
1177 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
1178 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
1179 }
1180 ly_set_free(ns_list, free);
1181 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001182 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001183 prefixes = prefix_data;
1184 LY_ARRAY_FOR(prefixes, u) {
1185 free(prefixes[u].prefix);
1186 }
1187 LY_ARRAY_FREE(prefixes);
1188 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001189 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001190 case LY_VALUE_SCHEMA:
1191 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001192 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001193 break;
1194 }
1195}
1196
1197LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +02001198ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001199 void **prefix_data_p)
1200{
1201 LY_ERR ret = LY_SUCCESS;
1202 struct lyxml_ns *ns;
1203 struct lysc_prefix *prefixes = NULL, *orig_pref;
1204 struct ly_set *ns_list, *orig_ns;
1205 uint32_t i;
1206 LY_ARRAY_COUNT_TYPE u;
1207
1208 assert(!*prefix_data_p);
1209
1210 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001211 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001212 *prefix_data_p = (void *)prefix_data;
1213 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001214 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001215 /* copy all the value prefixes */
1216 orig_pref = (struct lysc_prefix *)prefix_data;
1217 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
1218 *prefix_data_p = prefixes;
1219
1220 LY_ARRAY_FOR(orig_pref, u) {
1221 if (orig_pref[u].prefix) {
1222 prefixes[u].prefix = strdup(orig_pref[u].prefix);
1223 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1224 }
1225 prefixes[u].mod = orig_pref[u].mod;
1226 LY_ARRAY_INCREMENT(prefixes);
1227 }
1228 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001229 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001230 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001231 /* copy all the namespaces */
1232 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
1233 *prefix_data_p = ns_list;
1234
1235 orig_ns = (struct ly_set *)prefix_data;
1236 for (i = 0; i < orig_ns->count; ++i) {
1237 ns = calloc(1, sizeof *ns);
1238 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1239 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
1240
1241 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
1242 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
1243 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1244 }
1245 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
1246 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1247 }
1248 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001249 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001250 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001251 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001252 assert(!prefix_data);
1253 *prefix_data_p = NULL;
1254 break;
1255 }
1256
1257cleanup:
1258 if (ret) {
1259 ly_free_prefix_data(format, *prefix_data_p);
1260 *prefix_data_p = NULL;
1261 }
1262 return ret;
1263}
1264
1265LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +02001266ly_store_prefix_data(const struct ly_ctx *ctx, const void *value, size_t value_len, LY_VALUE_FORMAT format,
Radek Krejci8df109d2021-04-23 12:19:08 +02001267 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001268{
1269 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001270 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001271 const struct lyxml_ns *ns;
1272 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001273 struct ly_set *ns_list;
1274 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +02001275 const char *value_iter, *value_next, *value_end;
1276 uint32_t substr_len;
1277 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001278
1279 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001280 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001281 /* copy all referenced modules as prefix - module pairs */
1282 if (!*prefix_data_p) {
1283 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001284 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +02001285 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001286 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001287 } else {
1288 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +02001289 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001290 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001291 }
1292
Michal Vaskoc0f9c4c2022-05-06 12:12:17 +02001293 /* add current module for unprefixed values */
1294 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1295 *prefix_data_p = prefixes;
1296
1297 val_pref->prefix = NULL;
1298 val_pref->mod = ((const struct lysp_module *)prefix_data)->mod;
1299
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001300 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001301 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001302 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001303 LY_CHECK_GOTO(ret = ly_value_prefix_next(value_iter, value_end, &substr_len, &is_prefix, &value_next), cleanup);
aPiecek83436bc2021-03-30 12:20:45 +02001304 if (is_prefix) {
1305 /* we have a possible prefix. Do we already have the prefix? */
1306 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
1307 if (!mod) {
1308 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
1309 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001310 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +02001311 /* store a new prefix - module pair */
1312 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1313 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001314
aPiecek83436bc2021-03-30 12:20:45 +02001315 val_pref->prefix = strndup(value_iter, substr_len);
1316 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1317 val_pref->mod = mod;
1318 } /* else it is not even defined */
1319 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +01001320 }
1321 }
1322 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001323 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001324 case LY_VALUE_STR_NS:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001325 /* copy all referenced namespaces as prefix - namespace pairs */
1326 if (!*prefix_data_p) {
1327 /* new prefix data */
1328 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Michal Vaskoddd76592022-01-17 13:34:48 +01001329 *format_p = format;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001330 *prefix_data_p = ns_list;
1331 } else {
1332 /* reuse prefix data */
Michal Vaskoddd76592022-01-17 13:34:48 +01001333 assert(*format_p == format);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001334 ns_list = *prefix_data_p;
1335 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001336
Michal Vasko294e7f02022-02-28 13:59:00 +01001337 /* store default namespace */
1338 ns = lyxml_ns_get(prefix_data, NULL, 0);
1339 if (ns) {
1340 new_ns = calloc(1, sizeof *new_ns);
1341 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1342 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
1343
1344 new_ns->prefix = NULL;
1345 new_ns->uri = strdup(ns->uri);
1346 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1347 }
1348
Michal Vaskofc2cd072021-02-24 13:17:17 +01001349 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001350 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001351 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001352 LY_CHECK_GOTO(ret = ly_value_prefix_next(value_iter, value_end, &substr_len, &is_prefix, &value_next), cleanup);
aPiecek83436bc2021-03-30 12:20:45 +02001353 if (is_prefix) {
1354 /* we have a possible prefix. Do we already have the prefix? */
1355 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
1356 if (!ns) {
1357 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
1358 if (ns) {
1359 /* store a new prefix - namespace pair */
1360 new_ns = calloc(1, sizeof *new_ns);
1361 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1362 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001363
aPiecek83436bc2021-03-30 12:20:45 +02001364 new_ns->prefix = strndup(value_iter, substr_len);
1365 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1366 new_ns->uri = strdup(ns->uri);
1367 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1368 } /* else it is not even defined */
1369 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001370 }
1371 }
1372 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001373 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001374 case LY_VALUE_SCHEMA_RESOLVED:
1375 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001376 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001377 if (!*prefix_data_p) {
1378 /* new prefix data - simply copy all the prefix data */
1379 *format_p = format;
1380 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
1381 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001382 break;
1383 }
1384
1385cleanup:
1386 if (ret) {
1387 ly_free_prefix_data(*format_p, *prefix_data_p);
1388 *prefix_data_p = NULL;
1389 }
1390 return ret;
1391}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001392
1393const char *
Radek Krejci8df109d2021-04-23 12:19:08 +02001394ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001395{
1396 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +02001397 case LY_VALUE_CANON:
1398 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +02001399 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001400 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +02001401 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001402 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +02001403 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001404 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +02001405 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001406 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +02001407 case LY_VALUE_LYB:
1408 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001409 default:
1410 break;
1411 }
1412
1413 return NULL;
1414}
Michal Vasko43297a02021-05-19 11:12:37 +02001415
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001416LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001417ly_time_str2time(const char *value, time_t *time, char **fractions_s)
1418{
1419 struct tm tm = {0};
1420 uint32_t i, frac_len;
1421 const char *frac;
1422 int64_t shift, shift_m;
1423 time_t t;
1424
1425 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
1426
1427 tm.tm_year = atoi(&value[0]) - 1900;
1428 tm.tm_mon = atoi(&value[5]) - 1;
1429 tm.tm_mday = atoi(&value[8]);
1430 tm.tm_hour = atoi(&value[11]);
1431 tm.tm_min = atoi(&value[14]);
1432 tm.tm_sec = atoi(&value[17]);
1433
1434 t = timegm(&tm);
1435 i = 19;
1436
1437 /* fractions of a second */
1438 if (value[i] == '.') {
1439 ++i;
1440 frac = &value[i];
1441 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
1442
1443 i += frac_len;
Michal Vasko43297a02021-05-19 11:12:37 +02001444 } else {
1445 frac = NULL;
1446 }
1447
1448 /* apply offset */
1449 if ((value[i] == 'Z') || (value[i] == 'z')) {
1450 /* zero shift */
1451 shift = 0;
1452 } else {
1453 shift = strtol(&value[i], NULL, 10);
1454 shift = shift * 60 * 60; /* convert from hours to seconds */
1455 shift_m = strtol(&value[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
1456 /* correct sign */
1457 if (shift < 0) {
1458 shift_m *= -1;
1459 }
1460 /* connect hours and minutes of the shift */
1461 shift = shift + shift_m;
1462 }
1463
1464 /* we have to shift to the opposite way to correct the time */
1465 t -= shift;
1466
1467 *time = t;
1468 if (fractions_s) {
1469 if (frac) {
1470 *fractions_s = strndup(frac, frac_len);
1471 LY_CHECK_RET(!*fractions_s, LY_EMEM);
1472 } else {
1473 *fractions_s = NULL;
1474 }
1475 }
1476 return LY_SUCCESS;
1477}
1478
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001479LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001480ly_time_time2str(time_t time, const char *fractions_s, char **str)
1481{
1482 struct tm tm;
Michal Vasko143ffa82021-05-20 11:11:39 +02001483 char zoneshift[8];
Michal Vasko43297a02021-05-19 11:12:37 +02001484 int32_t zonediff_h, zonediff_m;
1485
1486 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
1487
1488 /* initialize the local timezone */
1489 tzset();
1490
Jan Kundrátb17efe92022-02-14 18:32:18 +01001491#ifdef HAVE_TM_GMTOFF
Michal Vasko43297a02021-05-19 11:12:37 +02001492 /* convert */
1493 if (!localtime_r(&time, &tm)) {
1494 return LY_ESYS;
1495 }
1496
1497 /* get timezone offset */
1498 if (tm.tm_gmtoff == 0) {
1499 /* time is Zulu (UTC) */
1500 zonediff_h = 0;
1501 zonediff_m = 0;
1502 } else {
1503 /* timezone offset */
1504 zonediff_h = tm.tm_gmtoff / 60 / 60;
1505 zonediff_m = tm.tm_gmtoff / 60 % 60;
1506 }
1507 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
Jan Kundráte182a272021-12-09 23:25:15 +01001508#else
Jan Kundrátb17efe92022-02-14 18:32:18 +01001509 /* convert */
1510 if (!gmtime_r(&time, &tm)) {
1511 return LY_ESYS;
1512 }
1513
Jan Kundráte182a272021-12-09 23:25:15 +01001514 (void)zonediff_h;
1515 (void)zonediff_m;
1516 sprintf(zoneshift, "-00:00");
1517#endif
Michal Vasko43297a02021-05-19 11:12:37 +02001518
1519 /* print */
1520 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
1521 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
1522 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
1523 return LY_EMEM;
1524 }
1525
1526 return LY_SUCCESS;
1527}
1528
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001529LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001530ly_time_str2ts(const char *value, struct timespec *ts)
1531{
1532 LY_ERR rc;
Michal Vasko72975062021-08-25 08:13:04 +02001533 char *fractions_s, frac_buf[10];
Michal Vasko43297a02021-05-19 11:12:37 +02001534 int frac_len;
1535
1536 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
1537
1538 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
1539 LY_CHECK_RET(rc);
1540
1541 /* convert fractions of a second to nanoseconds */
1542 if (fractions_s) {
Michal Vasko72975062021-08-25 08:13:04 +02001543 /* init frac_buf with zeroes */
1544 memset(frac_buf, '0', 9);
1545 frac_buf[9] = '\0';
1546
Michal Vasko43297a02021-05-19 11:12:37 +02001547 frac_len = strlen(fractions_s);
1548 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
1549 ts->tv_nsec = atol(frac_buf);
1550 free(fractions_s);
1551 } else {
1552 ts->tv_nsec = 0;
1553 }
1554
1555 return LY_SUCCESS;
1556}
1557
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001558LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001559ly_time_ts2str(const struct timespec *ts, char **str)
1560{
1561 char frac_buf[10];
1562
Jan Kundrátbd157002021-08-30 14:02:22 +02001563 LY_CHECK_ARG_RET(NULL, ts, str, ((ts->tv_nsec <= 999999999) && (ts->tv_nsec >= 0)), LY_EINVAL);
Michal Vasko43297a02021-05-19 11:12:37 +02001564
1565 /* convert nanoseconds to fractions of a second */
1566 if (ts->tv_nsec) {
1567 sprintf(frac_buf, "%09ld", ts->tv_nsec);
1568 }
1569
1570 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
1571}