blob: 05cab2a67893526f94639662ba478697afb9610c [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
Michal Vasko6b5cb2a2020-11-11 19:11:21 +010025#include "compat.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020026#include "context.h"
Radek Krejci47fab892020-11-05 17:02:41 +010027#include "dict.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020028#include "hash_table.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020029#include "log.h"
Michal Vasko8f702ee2024-02-20 15:44:24 +010030#include "ly_common.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020031#include "lyb.h"
Michal Vaskof77ca9c2024-05-29 13:44:16 +020032#include "metadata.h"
Radek Krejci7931b192020-06-25 17:05:03 +020033#include "parser_data.h"
Michal Vasko8cc3f662022-03-29 11:25:51 +020034#include "plugins_exts.h"
Michal Vaskoa820c312021-02-05 16:33:00 +010035#include "printer_data.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020036#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020037#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020038#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020039#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010040#include "tree_edit.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020041#include "tree_schema.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020042#include "tree_schema_internal.h"
Radek Krejci4f2e3e52021-03-30 14:20:28 +020043#include "validation.h"
Radek Krejci77114102021-03-10 15:21:57 +010044#include "xml.h"
aPiecekdf23eee2021-10-07 12:21:50 +020045#include "xpath.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020046
Michal Vaskod7c048c2021-05-18 16:12:55 +020047/**
Michal Vasko271d2e32023-01-31 15:43:19 +010048 * @brief Callback for checking first instance hash table values equivalence.
49 *
50 * @param[in] val1_p If not @p mod, pointer to the first instance.
51 * @param[in] val2_p If not @p mod, pointer to the found dup inst item.
52 */
53static ly_bool
54lyht_dup_inst_ht_equal_cb(void *val1_p, void *val2_p, ly_bool mod, void *UNUSED(cb_data))
55{
56 if (mod) {
57 struct lyd_dup_inst **item1 = val1_p, **item2 = val2_p;
58
59 /* equal on 2 dup inst items */
60 return *item1 == *item2 ? 1 : 0;
61 } else {
62 struct lyd_node **first_inst = val1_p;
63 struct lyd_dup_inst **item = val2_p;
64
65 /* equal on dup inst item and a first instance */
66 return (*item)->set->dnodes[0] == *first_inst ? 1 : 0;
67 }
68}
69
70/**
Michal Vaskod7c048c2021-05-18 16:12:55 +020071 * @brief Find an entry in duplicate instance cache for an instance. Create it if it does not exist.
72 *
Michal Vasko271d2e32023-01-31 15:43:19 +010073 * @param[in] first_inst First instance of the cache entry.
74 * @param[in] dup_inst_ht Duplicate instance cache hash table.
Michal Vaskod7c048c2021-05-18 16:12:55 +020075 * @return Instance cache entry.
76 */
77static struct lyd_dup_inst *
Michal Vasko8efac242023-03-30 08:24:56 +020078lyd_dup_inst_get(const struct lyd_node *first_inst, struct ly_ht **dup_inst_ht)
Michal Vaskod7c048c2021-05-18 16:12:55 +020079{
Michal Vasko271d2e32023-01-31 15:43:19 +010080 struct lyd_dup_inst **item_p, *item;
Michal Vaskod7c048c2021-05-18 16:12:55 +020081
Michal Vasko271d2e32023-01-31 15:43:19 +010082 if (*dup_inst_ht) {
83 /* find the item of the first instance */
84 if (!lyht_find(*dup_inst_ht, &first_inst, first_inst->hash, (void **)&item_p)) {
85 return *item_p;
Michal Vaskod7c048c2021-05-18 16:12:55 +020086 }
Michal Vasko271d2e32023-01-31 15:43:19 +010087 } else {
88 /* create the hash table */
89 *dup_inst_ht = lyht_new(2, sizeof item, lyht_dup_inst_ht_equal_cb, NULL, 1);
90 LY_CHECK_RET(!*dup_inst_ht, NULL);
Michal Vaskod7c048c2021-05-18 16:12:55 +020091 }
92
Michal Vasko271d2e32023-01-31 15:43:19 +010093 /* first instance has no dup inst item, create it */
94 item = calloc(1, sizeof *item);
95 LY_CHECK_RET(!item, NULL);
96
97 /* add into the hash table */
98 if (lyht_insert(*dup_inst_ht, &item, first_inst->hash, NULL)) {
99 return NULL;
100 }
Michal Vaskod7c048c2021-05-18 16:12:55 +0200101
102 return item;
103}
104
105LY_ERR
Michal Vasko8efac242023-03-30 08:24:56 +0200106lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struct ly_ht **dup_inst_ht)
Michal Vaskod7c048c2021-05-18 16:12:55 +0200107{
108 struct lyd_dup_inst *dup_inst;
109
Michal Vasko83ae7772022-06-08 10:01:55 +0200110 if (!*inst) {
111 /* no match, inst is unchanged */
Michal Vaskod7c048c2021-05-18 16:12:55 +0200112 return LY_SUCCESS;
113 }
114
Michal Vasko83ae7772022-06-08 10:01:55 +0200115 /* there can be more exact same instances (even if not allowed in invalid data) and we must make sure we do not
116 * match a single node more times */
Michal Vasko271d2e32023-01-31 15:43:19 +0100117 dup_inst = lyd_dup_inst_get(*inst, dup_inst_ht);
Michal Vaskod7c048c2021-05-18 16:12:55 +0200118 LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
119
120 if (!dup_inst->used) {
121 /* we did not cache these instances yet, do so */
Michal Vasko271d2e32023-01-31 15:43:19 +0100122 lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->set);
123 assert(dup_inst->set->count && (dup_inst->set->dnodes[0] == *inst));
Michal Vaskod7c048c2021-05-18 16:12:55 +0200124 }
125
Michal Vasko271d2e32023-01-31 15:43:19 +0100126 if (dup_inst->used == dup_inst->set->count) {
Michal Vasko4525e1f2022-07-13 16:20:59 +0200127 if (lysc_is_dup_inst_list((*inst)->schema)) {
128 /* we have used all the instances */
129 *inst = NULL;
130 } /* else just keep using the last (ideally only) instance */
Michal Vaskod7c048c2021-05-18 16:12:55 +0200131 } else {
Michal Vasko271d2e32023-01-31 15:43:19 +0100132 assert(dup_inst->used < dup_inst->set->count);
Michal Vaskod7c048c2021-05-18 16:12:55 +0200133
134 /* use another instance */
Michal Vasko271d2e32023-01-31 15:43:19 +0100135 *inst = dup_inst->set->dnodes[dup_inst->used];
Michal Vaskod7c048c2021-05-18 16:12:55 +0200136 ++dup_inst->used;
137 }
138
139 return LY_SUCCESS;
140}
141
Michal Vasko271d2e32023-01-31 15:43:19 +0100142/**
143 * @brief Callback for freeing first instance hash table values.
144 */
145static void
146lyht_dup_inst_ht_free_cb(void *val_p)
Michal Vaskod7c048c2021-05-18 16:12:55 +0200147{
Michal Vasko271d2e32023-01-31 15:43:19 +0100148 struct lyd_dup_inst **item = val_p;
Michal Vaskod7c048c2021-05-18 16:12:55 +0200149
Michal Vasko271d2e32023-01-31 15:43:19 +0100150 ly_set_free((*item)->set, NULL);
151 free(*item);
152}
153
154void
Michal Vasko8efac242023-03-30 08:24:56 +0200155lyd_dup_inst_free(struct ly_ht *dup_inst_ht)
Michal Vasko271d2e32023-01-31 15:43:19 +0100156{
157 lyht_free(dup_inst_ht, lyht_dup_inst_ht_free_cb);
Michal Vaskod7c048c2021-05-18 16:12:55 +0200158}
159
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200160struct lyd_node *
161lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +0200162 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200163{
164 const struct lysc_node *siter = NULL;
165 struct lyd_node *match = NULL;
166
167 assert(parent || module);
168 assert(!last || (slast && *slast));
169
170 if (slast) {
171 siter = *slast;
172 }
173
174 if (last && last->next && (last->next->schema == siter)) {
175 /* return next data instance */
176 return last->next;
177 }
178
179 /* find next schema node data instance */
180 while ((siter = lys_getnext(siter, parent, module, 0))) {
181 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
182 break;
183 }
184 }
185
186 if (slast) {
187 *slast = siter;
188 }
189 return match;
190}
191
Radek Krejcie7b95092019-05-15 11:03:07 +0200192struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +0100193lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200194{
195 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +0100196
197 if (!node->schema) {
198 return &((struct lyd_node_opaq *)node)->child;
199 } else {
200 switch (node->schema->nodetype) {
201 case LYS_CONTAINER:
202 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +0100203 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100204 case LYS_ACTION:
205 case LYS_NOTIF:
206 return &((struct lyd_node_inner *)node)->child;
207 default:
208 return NULL;
209 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200210 }
211}
212
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100213LIBYANG_API_DEF LY_ERR
aPiecekdf23eee2021-10-07 12:21:50 +0200214lyxp_vars_set(struct lyxp_var **vars, const char *name, const char *value)
215{
216 LY_ERR ret = LY_SUCCESS;
217 char *var_name = NULL, *var_value = NULL;
218 struct lyxp_var *item;
219
220 if (!vars || !name || !value) {
221 return LY_EINVAL;
222 }
223
Michal Vasko90189962023-02-28 12:10:34 +0100224 /* if variable is already defined then change its value */
225 if (*vars && !lyxp_vars_find(NULL, *vars, name, 0, &item)) {
aPiecekdf23eee2021-10-07 12:21:50 +0200226 var_value = strdup(value);
227 LY_CHECK_RET(!var_value, LY_EMEM);
228
Michal Vasko90189962023-02-28 12:10:34 +0100229 /* update value */
aPiecekdf23eee2021-10-07 12:21:50 +0200230 free(item->value);
231 item->value = var_value;
232 } else {
233 var_name = strdup(name);
234 var_value = strdup(value);
235 LY_CHECK_ERR_GOTO(!var_name || !var_value, ret = LY_EMEM, error);
236
Michal Vasko90189962023-02-28 12:10:34 +0100237 /* add new variable */
aPiecekdf23eee2021-10-07 12:21:50 +0200238 LY_ARRAY_NEW_GOTO(NULL, *vars, item, ret, error);
239 item->name = var_name;
240 item->value = var_value;
241 }
242
243 return LY_SUCCESS;
244
245error:
246 free(var_name);
247 free(var_value);
248 return ret;
249}
250
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100251LIBYANG_API_DEF void
aPiecekdf23eee2021-10-07 12:21:50 +0200252lyxp_vars_free(struct lyxp_var *vars)
253{
254 LY_ARRAY_COUNT_TYPE u;
255
256 if (!vars) {
257 return;
258 }
259
260 LY_ARRAY_FOR(vars, u) {
261 free(vars[u].name);
262 free(vars[u].value);
263 }
264
265 LY_ARRAY_FREE(vars);
266}
267
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100268LIBYANG_API_DEF struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +0200269lyd_child_no_keys(const struct lyd_node *node)
270{
271 struct lyd_node **children;
272
273 if (!node) {
274 return NULL;
275 }
276
277 if (!node->schema) {
278 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100279 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200280 }
281
Michal Vaskoe0665742021-02-11 11:08:44 +0100282 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200283 if (children) {
284 struct lyd_node *child = *children;
Michal Vasko26bbb272022-08-02 14:54:33 +0200285
Radek Krejcia1c1e542020-09-29 16:06:52 +0200286 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
287 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200288 }
289 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200290 } else {
291 return NULL;
292 }
293}
Michal Vasko9b368d32020-02-14 13:53:31 +0100294
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100295LIBYANG_API_DEF const struct lys_module *
Michal Vaskoc193ce92020-03-06 11:04:48 +0100296lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100297{
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100298 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100299
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100300 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100301 return NULL;
302 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100303
Michal Vasko420cc252023-08-24 08:14:24 +0200304 while (!node->schema && node->parent) {
305 node = lyd_parent(node);
306 }
307
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100308 if (!node->schema) {
Michal Vasko420cc252023-08-24 08:14:24 +0200309 /* top-level opaque node */
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100310 opaq = (struct lyd_node_opaq *)node;
311 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200312 case LY_VALUE_XML:
Michal Vasko09fbb812023-04-13 14:11:06 +0200313 if (opaq->name.module_ns) {
314 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
315 }
316 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200317 case LY_VALUE_JSON:
Michal Vasko09fbb812023-04-13 14:11:06 +0200318 if (opaq->name.module_name) {
319 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
320 }
321 break;
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100322 default:
323 return NULL;
324 }
Michal Vasko09fbb812023-04-13 14:11:06 +0200325
Michal Vasko420cc252023-08-24 08:14:24 +0200326 return NULL;
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100327 }
328
Michal Vaskoef53c812021-10-13 10:21:03 +0200329 return lysc_owner_module(node->schema);
Michal Vasko9b368d32020-02-14 13:53:31 +0100330}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100331
Michal Vasko420cc252023-08-24 08:14:24 +0200332LIBYANG_API_DEF const struct lys_module *
333lyd_node_module(const struct lyd_node *node)
334{
335 const struct lyd_node_opaq *opaq;
336
337 while (node) {
338 /* data node */
339 if (node->schema) {
340 return node->schema->module;
341 }
342
343 /* opaque node */
344 opaq = (struct lyd_node_opaq *)node;
345 switch (opaq->format) {
346 case LY_VALUE_XML:
347 if (opaq->name.module_ns) {
348 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
349 }
350 break;
351 case LY_VALUE_JSON:
352 if (opaq->name.module_name) {
353 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
354 }
355 break;
356 default:
357 break;
358 }
359
360 node = lyd_parent(node);
361 }
362
363 return NULL;
364}
365
Michal Vasko598063b2021-07-19 11:39:05 +0200366void
367lyd_first_module_sibling(struct lyd_node **node, const struct lys_module *mod)
368{
369 int cmp;
370 struct lyd_node *first;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200371 const struct lys_module *own_mod;
Michal Vasko598063b2021-07-19 11:39:05 +0200372
373 assert(node && mod);
374
375 if (!*node) {
376 return;
377 }
378
379 first = *node;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200380 own_mod = lyd_owner_module(first);
381 cmp = own_mod ? strcmp(own_mod->name, mod->name) : 1;
Michal Vasko598063b2021-07-19 11:39:05 +0200382 if (cmp > 0) {
383 /* there may be some preceding data */
384 while (first->prev->next) {
385 first = first->prev;
386 if (lyd_owner_module(first) == mod) {
387 cmp = 0;
388 break;
389 }
390 }
391 }
392
393 if (cmp == 0) {
394 /* there may be some preceding data belonging to this module */
395 while (first->prev->next) {
396 if (lyd_owner_module(first->prev) != mod) {
397 break;
398 }
399 first = first->prev;
400 }
401 }
402
403 if (cmp < 0) {
404 /* there may be some following data */
405 LY_LIST_FOR(first, first) {
406 if (lyd_owner_module(first) == mod) {
407 cmp = 0;
408 break;
409 }
410 }
411 }
412
413 if (cmp == 0) {
414 /* we have found the first module data node */
415 *node = first;
416 }
417}
418
Michal Vaskob1b5c262020-03-05 14:29:47 +0100419const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200420lyd_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 +0200421 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100422{
423 struct lyd_node *iter;
424 const struct lys_module *mod;
425
426 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200427 if (module) {
428 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100429 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200430 } else {
431 mod = module;
432 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100433 }
434 } else {
435 do {
436 mod = ly_ctx_get_module_iter(ctx, i);
437 } while (mod && !mod->implemented);
438 }
439
440 /* find its data */
441 *first = NULL;
442 if (mod) {
443 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100444 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100445 *first = iter;
446 break;
447 }
448 }
449 }
450
451 return mod;
452}
453
454const struct lys_module *
455lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
456{
457 const struct lys_module *mod;
458
459 if (!*next) {
460 /* all data traversed */
461 *first = NULL;
462 return NULL;
463 }
464
465 *first = *next;
466
467 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100468 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100469 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100470 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100471 break;
472 }
473 }
474
475 return mod;
476}
Michal Vasko9f96a052020-03-10 09:41:45 +0100477
Michal Vasko7a266772024-01-23 11:02:38 +0100478/**
479 * @brief Log generated error item and use log location information if not in the error item.
480 *
481 * @param[in] ctx Context to use.
482 * @param[in] node Optional data node to log.
483 * @param[in] scnode Optional schema node to log.
484 * @param[in] eitem Error item to log.
485 */
486static void
487ly_err_print_build_path(const struct ly_ctx *ctx, const struct lyd_node *node, const struct lysc_node *scnode,
488 struct ly_err_item *eitem)
489{
490 if (eitem->data_path || eitem->schema_path || eitem->line) {
491 ly_err_print(ctx, eitem);
492 } else {
493 if (node) {
494 LOG_LOCSET(NULL, node);
495 } else if (scnode) {
496 LOG_LOCSET(scnode, NULL);
497 }
498 ly_vlog(ctx, eitem->apptag, eitem->err == LY_EVALID ? eitem->vecode : LYVE_DATA, "%s", eitem->msg);
499 if (node) {
500 LOG_LOCBACK(0, 1);
501 } else if (scnode) {
502 LOG_LOCBACK(1, 0);
503 }
504 }
505}
506
Michal Vasko9f96a052020-03-10 09:41:45 +0100507LY_ERR
Michal Vasko59892dd2022-05-13 11:02:30 +0200508lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct lysc_type *type, const void *value,
stewegd4cde642024-02-21 08:34:16 +0100509 size_t value_len, ly_bool is_utf8, ly_bool store_only, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data,
510 uint32_t hints, const struct lysc_node *ctx_node, ly_bool *incomplete)
Michal Vasko59892dd2022-05-13 11:02:30 +0200511{
512 LY_ERR ret;
513 struct ly_err_item *err = NULL;
Michal Vasko989cdb42023-10-06 15:32:37 +0200514 uint32_t options = 0;
Michal Vasko59892dd2022-05-13 11:02:30 +0200515
516 if (!value) {
517 value = "";
518 }
519 if (incomplete) {
520 *incomplete = 0;
521 }
522
Michal Vasko989cdb42023-10-06 15:32:37 +0200523 if (dynamic && *dynamic) {
524 options |= LYPLG_TYPE_STORE_DYNAMIC;
525 }
526 if (is_utf8) {
527 options |= LYPLG_TYPE_STORE_IS_UTF8;
528 }
stewegd4cde642024-02-21 08:34:16 +0100529 if (store_only) {
530 options |= LYPLG_TYPE_STORE_ONLY;
531 }
Michal Vasko989cdb42023-10-06 15:32:37 +0200532
Michal Vasko59892dd2022-05-13 11:02:30 +0200533 ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data, hints, ctx_node, val, NULL, &err);
534 if (dynamic) {
535 *dynamic = 0;
536 }
537
538 if (ret == LY_EINCOMPLETE) {
539 if (incomplete) {
540 *incomplete = 1;
541 }
542 } else if (ret) {
543 if (err) {
Michal Vasko7a266772024-01-23 11:02:38 +0100544 ly_err_print_build_path(ctx, NULL, ctx_node, err);
Michal Vasko59892dd2022-05-13 11:02:30 +0200545 ly_err_free(err);
546 } else {
547 LOGVAL(ctx, LYVE_OTHER, "Storing value failed.");
548 }
549 return ret;
550 }
551
552 return LY_SUCCESS;
553}
554
555LY_ERR
556lyd_value_validate_incomplete(const struct ly_ctx *ctx, const struct lysc_type *type, struct lyd_value *val,
557 const struct lyd_node *ctx_node, const struct lyd_node *tree)
558{
559 LY_ERR ret;
560 struct ly_err_item *err = NULL;
561
562 assert(type->plugin->validate);
563
564 ret = type->plugin->validate(ctx, type, ctx_node, tree, val, &err);
565 if (ret) {
566 if (err) {
Michal Vasko7a266772024-01-23 11:02:38 +0100567 ly_err_print_build_path(ctx, ctx_node, NULL, err);
Michal Vasko59892dd2022-05-13 11:02:30 +0200568 ly_err_free(err);
569 } else {
Michal Vasko7b3a00e2023-08-09 11:58:03 +0200570 LOGVAL(ctx, LYVE_OTHER, "Resolving value \"%s\" failed.",
571 (char *)type->plugin->print(ctx, val, LY_VALUE_CANON, NULL, NULL, NULL));
Michal Vasko59892dd2022-05-13 11:02:30 +0200572 }
573 return ret;
574 }
575
576 return LY_SUCCESS;
577}
578
579LY_ERR
Michal Vasko583b4642023-05-25 10:39:34 +0200580ly_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
581 LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints)
Michal Vasko59892dd2022-05-13 11:02:30 +0200582{
583 LY_ERR rc = LY_SUCCESS;
584 struct ly_err_item *err = NULL;
585 struct lyd_value storage;
586 struct lysc_type *type;
587
Michal Vasko0c361552023-04-04 10:04:03 +0200588 LY_CHECK_ARG_RET(ctx, node, LY_EINVAL);
Michal Vasko59892dd2022-05-13 11:02:30 +0200589
590 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
591 LOGARG(ctx, node);
592 return LY_EINVAL;
593 }
594
595 type = ((struct lysc_node_leaf *)node)->type;
Michal Vasko583b4642023-05-25 10:39:34 +0200596 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, 0, format, prefix_data, hints, node,
597 &storage, NULL, &err);
Michal Vasko59892dd2022-05-13 11:02:30 +0200598 if (rc == LY_EINCOMPLETE) {
599 /* actually success since we do not provide the context tree and call validation with
600 * LY_TYPE_OPTS_INCOMPLETE_DATA */
601 rc = LY_SUCCESS;
602 } else if (rc && err) {
603 if (ctx) {
604 /* log only in case the ctx was provided as input parameter */
Michal Vasko7a266772024-01-23 11:02:38 +0100605 ly_err_print_build_path(ctx, NULL, node, err);
Michal Vasko59892dd2022-05-13 11:02:30 +0200606 }
607 ly_err_free(err);
608 }
609
610 if (!rc) {
611 type->plugin->free(ctx ? ctx : node->module->ctx, &storage);
612 }
613 return rc;
614}
615
616LIBYANG_API_DEF LY_ERR
617lyd_value_validate(const struct ly_ctx *ctx, const struct lysc_node *schema, const char *value, size_t value_len,
618 const struct lyd_node *ctx_node, const struct lysc_type **realtype, const char **canonical)
619{
620 LY_ERR rc;
621 struct ly_err_item *err = NULL;
622 struct lysc_type *type;
623 struct lyd_value val = {0};
624 ly_bool stored = 0, log = 1;
625
Michal Vasko3dd16da2022-06-15 07:58:41 +0200626 LY_CHECK_ARG_RET(ctx, schema, !value_len || value, LY_EINVAL);
Michal Vasko59892dd2022-05-13 11:02:30 +0200627
628 if (!ctx) {
629 ctx = schema->module->ctx;
630 log = 0;
631 }
Michal Vasko3dd16da2022-06-15 07:58:41 +0200632 if (!value_len) {
633 value = "";
634 }
Michal Vasko59892dd2022-05-13 11:02:30 +0200635 type = ((struct lysc_node_leaf *)schema)->type;
636
637 /* store */
638 rc = type->plugin->store(ctx, type, value, value_len, 0, LY_VALUE_JSON, NULL,
639 LYD_HINT_DATA, schema, &val, NULL, &err);
640 if (!rc || (rc == LY_EINCOMPLETE)) {
641 stored = 1;
642 }
643
644 if (ctx_node && (rc == LY_EINCOMPLETE)) {
645 /* resolve */
646 rc = type->plugin->validate(ctx, type, ctx_node, ctx_node, &val, &err);
647 }
648
649 if (rc && (rc != LY_EINCOMPLETE) && err) {
650 if (log) {
651 /* log error */
Michal Vasko7a266772024-01-23 11:02:38 +0100652 ly_err_print_build_path(ctx, ctx_node, schema, err);
Michal Vasko59892dd2022-05-13 11:02:30 +0200653 }
654 ly_err_free(err);
655 }
656
657 if (!rc || (rc == LY_EINCOMPLETE)) {
658 if (realtype) {
659 /* return realtype */
660 if (val.realtype->basetype == LY_TYPE_UNION) {
661 *realtype = val.subvalue->value.realtype;
662 } else {
663 *realtype = val.realtype;
664 }
665 }
666
667 if (canonical) {
668 /* return canonical value */
669 lydict_insert(ctx, val.realtype->plugin->print(ctx, &val, LY_VALUE_CANON, NULL, NULL, NULL), 0, canonical);
670 }
671 }
672
673 if (stored) {
674 /* free value */
675 type->plugin->free(ctx ? ctx : schema->module->ctx, &val);
676 }
677 return rc;
678}
679
680LIBYANG_API_DEF LY_ERR
681lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len)
682{
683 LY_ERR ret = LY_SUCCESS;
684 struct ly_ctx *ctx;
685 struct lysc_type *type;
686 struct lyd_value val = {0};
687
688 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
689
690 ctx = node->schema->module->ctx;
691 type = ((struct lysc_node_leaf *)node->schema)->type;
692
693 /* store the value */
Michal Vasko7a266772024-01-23 11:02:38 +0100694 LOG_LOCSET(NULL, &node->node);
stewegd4cde642024-02-21 08:34:16 +0100695 ret = lyd_value_store(ctx, &val, type, value, value_len, 0, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL);
Michal Vasko7a266772024-01-23 11:02:38 +0100696 LOG_LOCBACK(0, 1);
Michal Vasko59892dd2022-05-13 11:02:30 +0200697 LY_CHECK_RET(ret);
698
699 /* compare values */
aPiecek0a6705b2023-11-14 14:20:58 +0100700 ret = type->plugin->compare(ctx, &node->value, &val);
Michal Vasko59892dd2022-05-13 11:02:30 +0200701
702 type->plugin->free(ctx, &val);
703 return ret;
704}
705
706LIBYANG_API_DEF ly_bool
707lyd_is_default(const struct lyd_node *node)
708{
709 const struct lysc_node_leaf *leaf;
710 const struct lysc_node_leaflist *llist;
711 const struct lyd_node_term *term;
712 LY_ARRAY_COUNT_TYPE u;
713
714 if (!(node->schema->nodetype & LYD_NODE_TERM)) {
715 return 0;
716 }
717
718 term = (const struct lyd_node_term *)node;
719
720 if (node->schema->nodetype == LYS_LEAF) {
721 leaf = (const struct lysc_node_leaf *)node->schema;
722 if (!leaf->dflt) {
723 return 0;
724 }
725
726 /* compare with the default value */
aPiecek0a6705b2023-11-14 14:20:58 +0100727 if (!leaf->type->plugin->compare(LYD_CTX(node), &term->value, leaf->dflt)) {
Michal Vasko59892dd2022-05-13 11:02:30 +0200728 return 1;
729 }
730 } else {
731 llist = (const struct lysc_node_leaflist *)node->schema;
732 if (!llist->dflts) {
733 return 0;
734 }
735
736 LY_ARRAY_FOR(llist->dflts, u) {
737 /* compare with each possible default value */
aPiecek0a6705b2023-11-14 14:20:58 +0100738 if (!llist->type->plugin->compare(LYD_CTX(node), &term->value, llist->dflts[u])) {
Michal Vasko59892dd2022-05-13 11:02:30 +0200739 return 1;
740 }
741 }
742 }
743
744 return 0;
745}
746
747LIBYANG_API_DEF uint32_t
748lyd_list_pos(const struct lyd_node *instance)
749{
750 const struct lyd_node *iter = NULL;
751 uint32_t pos = 0;
752
753 if (!instance || !(instance->schema->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
754 return 0;
755 }
756
757 /* data instances are ordered, so we can stop when we found instance of other schema node */
758 for (iter = instance; iter->schema == instance->schema; iter = iter->prev) {
759 if (pos && (iter->next == NULL)) {
760 /* overrun to the end of the siblings list */
761 break;
762 }
763 ++pos;
764 }
765
766 return pos;
767}
768
769LIBYANG_API_DEF struct lyd_node *
770lyd_first_sibling(const struct lyd_node *node)
771{
772 struct lyd_node *start;
773
774 if (!node) {
775 return NULL;
776 }
777
778 /* get the first sibling */
779 if (node->parent) {
aPiecek743184b2024-02-01 13:25:56 +0100780 return node->parent->child;
781 } else if (!node->prev->next) {
782 return (struct lyd_node *)node;
783 }
784
785 for (start = (struct lyd_node *)node->prev; start->prev->next; start = start->prev) {
786 assert(start != node);
Michal Vasko59892dd2022-05-13 11:02:30 +0200787 }
788
789 return start;
790}
791
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100792/**
793 * @brief Check list node parsed into an opaque node for the reason.
794 *
795 * @param[in] node Opaque node.
796 * @param[in] snode Schema node of @p opaq.
797 * @return LY_SUCCESS if the node is valid;
798 * @return LY_ERR on error.
799 */
800static LY_ERR
801lyd_parse_opaq_list_error(const struct lyd_node *node, const struct lysc_node *snode)
802{
803 LY_ERR ret = LY_SUCCESS;
804 struct ly_set key_set = {0};
805 const struct lysc_node *key = NULL;
806 const struct lyd_node *child;
807 const struct lyd_node_opaq *opaq_k;
808 uint32_t i;
809
810 assert(!node->schema);
811
812 /* get all keys into a set */
Michal Vaskof30bcf12023-07-14 12:12:03 +0200813 while ((key = lys_getnext(key, snode, NULL, 0)) && (key->flags & LYS_KEY)) {
814 LY_CHECK_GOTO(ret = ly_set_add(&key_set, (void *)key, 1, NULL), cleanup);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100815 }
816
817 LY_LIST_FOR(lyd_child(node), child) {
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100818 /* find the key schema node */
819 for (i = 0; i < key_set.count; ++i) {
820 key = key_set.snodes[i];
Michal Vaskoa878a892023-08-18 12:22:07 +0200821 if (!strcmp(key->name, LYD_NAME(child))) {
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100822 break;
823 }
824 }
825 if (i == key_set.count) {
826 /* some other node, skip */
827 continue;
828 }
829
830 /* key found */
831 ly_set_rm_index(&key_set, i, NULL);
832
Michal Vaskoa878a892023-08-18 12:22:07 +0200833 if (child->schema) {
834 /* valid key */
835 continue;
836 }
837
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100838 /* check value */
Michal Vaskoa878a892023-08-18 12:22:07 +0200839 opaq_k = (struct lyd_node_opaq *)child;
Michal Vasko583b4642023-05-25 10:39:34 +0200840 ret = ly_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
841 opaq_k->val_prefix_data, opaq_k->hints);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100842 LY_CHECK_GOTO(ret, cleanup);
843 }
844
845 if (key_set.count) {
846 /* missing keys */
847 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, key_set.snodes[0]->name);
848 ret = LY_EVALID;
849 goto cleanup;
850 }
851
852cleanup:
853 ly_set_erase(&key_set, NULL);
854 return ret;
855}
856
857LIBYANG_API_DEF LY_ERR
858lyd_parse_opaq_error(const struct lyd_node *node)
859{
Michal Vasko6727c682023-02-17 10:40:26 +0100860 LY_ERR rc = LY_SUCCESS;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100861 const struct ly_ctx *ctx;
862 const struct lyd_node_opaq *opaq;
863 const struct lyd_node *parent;
864 const struct lys_module *mod;
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200865 const struct lysc_node *sparent, *snode;
Michal Vasko7a266772024-01-23 11:02:38 +0100866 uint32_t loc_scnode = 0, loc_dnode = 0;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100867
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200868 LY_CHECK_ARG_RET(LYD_CTX(node), node, !node->schema, LY_EINVAL);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100869
870 ctx = LYD_CTX(node);
871 opaq = (struct lyd_node_opaq *)node;
872 parent = lyd_parent(node);
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200873 sparent = lyd_node_schema(parent);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100874
Michal Vasko7a266772024-01-23 11:02:38 +0100875 /* if parent is NULL, it is still added as root */
876 LOG_LOCSET(NULL, parent);
877 loc_dnode = 1;
Michal Vasko6727c682023-02-17 10:40:26 +0100878
Michal Vaskof4e63922022-05-10 10:32:13 +0200879 if (!opaq->name.module_ns) {
880 LOGVAL(ctx, LYVE_REFERENCE, "Unknown module of node \"%s\".", opaq->name.name);
Michal Vasko6727c682023-02-17 10:40:26 +0100881 rc = LY_EVALID;
882 goto cleanup;
Michal Vaskof4e63922022-05-10 10:32:13 +0200883 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100884
885 /* module */
886 switch (opaq->format) {
887 case LY_VALUE_XML:
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200888 if (!sparent || strcmp(opaq->name.module_ns, sparent->module->ns)) {
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100889 mod = ly_ctx_get_module_implemented_ns(ctx, opaq->name.module_ns);
890 if (!mod) {
Michal Vasko959f8d82022-06-16 07:51:50 +0200891 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module with namespace \"%s\" of node \"%s\" in the context.",
892 opaq->name.module_ns, opaq->name.name);
Michal Vasko6727c682023-02-17 10:40:26 +0100893 rc = LY_EVALID;
894 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100895 }
896 } else {
897 /* inherit */
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200898 mod = sparent->module;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100899 }
900 break;
901 case LY_VALUE_JSON:
902 case LY_VALUE_LYB:
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200903 if (!sparent || strcmp(opaq->name.module_name, sparent->module->name)) {
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100904 mod = ly_ctx_get_module_implemented(ctx, opaq->name.module_name);
905 if (!mod) {
Michal Vasko959f8d82022-06-16 07:51:50 +0200906 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module named \"%s\" of node \"%s\" in the context.",
907 opaq->name.module_name, opaq->name.name);
Michal Vasko6727c682023-02-17 10:40:26 +0100908 rc = LY_EVALID;
909 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100910 }
911 } else {
912 /* inherit */
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200913 mod = sparent->module;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100914 }
915 break;
916 default:
917 LOGERR(ctx, LY_EINVAL, "Unsupported value format.");
Michal Vasko6727c682023-02-17 10:40:26 +0100918 rc = LY_EINVAL;
919 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100920 }
921
922 /* schema */
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200923 snode = lys_find_child(sparent, mod, opaq->name.name, 0, 0, 0);
924 if (!snode && sparent && (sparent->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200925 /* maybe output node */
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200926 snode = lys_find_child(sparent, mod, opaq->name.name, 0, 0, LYS_GETNEXT_OUTPUT);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200927 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100928 if (!snode) {
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200929 if (sparent) {
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100930 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found as a child of \"%s\" node.", opaq->name.name,
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200931 sparent->name);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100932 } else {
933 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found in the \"%s\" module.", opaq->name.name, mod->name);
934 }
Michal Vasko6727c682023-02-17 10:40:26 +0100935 rc = LY_EVALID;
936 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100937 }
938
Michal Vasko6727c682023-02-17 10:40:26 +0100939 /* schema node exists */
Michal Vasko7a266772024-01-23 11:02:38 +0100940 LOG_LOCBACK(0, 1);
941 loc_dnode = 0;
942 LOG_LOCSET(snode, NULL);
943 loc_scnode = 1;
Michal Vasko6727c682023-02-17 10:40:26 +0100944
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100945 if (snode->nodetype & LYD_NODE_TERM) {
946 /* leaf / leaf-list */
Michal Vasko583b4642023-05-25 10:39:34 +0200947 rc = ly_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data, opaq->hints);
Michal Vasko6727c682023-02-17 10:40:26 +0100948 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100949 } else if (snode->nodetype == LYS_LIST) {
950 /* list */
Michal Vasko6727c682023-02-17 10:40:26 +0100951 rc = lyd_parse_opaq_list_error(node, snode);
952 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100953 } else if (snode->nodetype & LYD_NODE_INNER) {
954 /* inner node */
955 if (opaq->value) {
956 LOGVAL(ctx, LYVE_DATA, "Invalid value \"%s\" for %s \"%s\".", opaq->value,
957 lys_nodetype2str(snode->nodetype), snode->name);
Michal Vasko6727c682023-02-17 10:40:26 +0100958 rc = LY_EVALID;
959 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100960 }
961 } else {
962 LOGERR(ctx, LY_EINVAL, "Unexpected opaque schema node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
Michal Vasko6727c682023-02-17 10:40:26 +0100963 rc = LY_EINVAL;
964 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100965 }
966
967 LOGERR(ctx, LY_EINVAL, "Unexpected valid opaque node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
Michal Vasko6727c682023-02-17 10:40:26 +0100968 rc = LY_EINVAL;
969
970cleanup:
Michal Vasko7a266772024-01-23 11:02:38 +0100971 LOG_LOCBACK(loc_scnode, loc_dnode);
Michal Vasko6727c682023-02-17 10:40:26 +0100972 return rc;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100973}
974
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100975LIBYANG_API_DEF const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400976lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200977{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200978 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
979
Michal Vasko33876022021-04-27 16:42:24 +0200980 return value->_canonical ? value->_canonical :
981 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200982}
983
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100984LIBYANG_API_DEF LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100985lyd_any_value_str(const struct lyd_node *any, char **value_str)
986{
987 const struct lyd_node_any *a;
988 struct lyd_node *tree = NULL;
989 const char *str = NULL;
990 ly_bool dynamic = 0;
991 LY_ERR ret = LY_SUCCESS;
992
993 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200994 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100995
996 a = (struct lyd_node_any *)any;
997 *value_str = NULL;
998
999 if (!a->value.str) {
1000 /* there is no value in the union */
1001 return LY_SUCCESS;
1002 }
1003
1004 switch (a->value_type) {
1005 case LYD_ANYDATA_LYB:
1006 /* parse into a data tree */
1007 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
1008 LY_CHECK_GOTO(ret, cleanup);
1009 dynamic = 1;
1010 break;
1011 case LYD_ANYDATA_DATATREE:
1012 tree = a->value.tree;
1013 break;
1014 case LYD_ANYDATA_STRING:
1015 case LYD_ANYDATA_XML:
1016 case LYD_ANYDATA_JSON:
1017 /* simply use the string */
1018 str = a->value.str;
1019 break;
1020 }
1021
1022 if (tree) {
1023 /* print into a string */
1024 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
1025 LY_CHECK_GOTO(ret, cleanup);
1026 } else {
1027 assert(str);
1028 *value_str = strdup(str);
1029 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
1030 }
1031
1032 /* success */
1033
1034cleanup:
1035 if (dynamic) {
1036 lyd_free_all(tree);
1037 }
1038 return ret;
1039}
1040
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001041LIBYANG_API_DEF LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +02001042lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
1043{
1044 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +02001045
Michal Vaskoa820c312021-02-05 16:33:00 +01001046 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +02001047 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +02001048
1049 t = (struct lyd_node_any *)trg;
1050
1051 /* free trg */
1052 switch (t->value_type) {
1053 case LYD_ANYDATA_DATATREE:
1054 lyd_free_all(t->value.tree);
1055 break;
1056 case LYD_ANYDATA_STRING:
1057 case LYD_ANYDATA_XML:
1058 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +01001059 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +02001060 break;
1061 case LYD_ANYDATA_LYB:
1062 free(t->value.mem);
1063 break;
1064 }
1065 t->value.str = NULL;
1066
1067 if (!value) {
1068 /* only free value in this case */
1069 return LY_SUCCESS;
1070 }
1071
1072 /* copy src */
1073 t->value_type = value_type;
1074 switch (value_type) {
1075 case LYD_ANYDATA_DATATREE:
1076 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +02001077 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +02001078 }
1079 break;
1080 case LYD_ANYDATA_STRING:
1081 case LYD_ANYDATA_XML:
1082 case LYD_ANYDATA_JSON:
1083 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02001084 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +02001085 }
1086 break;
1087 case LYD_ANYDATA_LYB:
1088 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +02001089 int len = lyd_lyb_data_length(value->mem);
Michal Vasko26bbb272022-08-02 14:54:33 +02001090
Radek Krejci82fa8d42020-07-11 22:00:59 +02001091 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +02001092 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +02001093 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +02001094 memcpy(t->value.mem, value->mem, len);
1095 }
1096 break;
1097 }
1098
1099 return LY_SUCCESS;
1100}
1101
Michal Vasko21c11c22023-10-09 16:06:58 +02001102LIBYANG_API_DEF const struct lysc_node *
Michal Vasko106f0862021-11-02 11:49:27 +01001103lyd_node_schema(const struct lyd_node *node)
1104{
1105 const struct lysc_node *schema = NULL;
1106 const struct lyd_node *prev_iter = NULL, *iter;
1107 const struct lys_module *mod;
1108
1109 if (!node) {
1110 return NULL;
1111 } else if (node->schema) {
1112 return node->schema;
1113 }
1114
Michal Vaskoa878a892023-08-18 12:22:07 +02001115 /* find the first schema node in the parents */
1116 for (iter = lyd_parent(node); iter && !iter->schema; iter = lyd_parent(iter)) {}
1117 if (iter) {
1118 prev_iter = iter;
1119 schema = prev_iter->schema;
1120 }
1121
Michal Vasko106f0862021-11-02 11:49:27 +01001122 /* get schema node of an opaque node */
1123 do {
1124 /* get next data node */
1125 for (iter = node; lyd_parent(iter) != prev_iter; iter = lyd_parent(iter)) {}
1126
Michal Vaskoa878a892023-08-18 12:22:07 +02001127 /* get module */
Michal Vasko420cc252023-08-24 08:14:24 +02001128 mod = lyd_node_module(iter);
Michal Vaskoa878a892023-08-18 12:22:07 +02001129 if (!mod) {
1130 /* unknown module, no schema node */
1131 schema = NULL;
1132 break;
Michal Vasko106f0862021-11-02 11:49:27 +01001133 }
Michal Vaskod2f404f2021-11-04 15:37:11 +01001134
Michal Vaskoa878a892023-08-18 12:22:07 +02001135 /* get schema node */
1136 schema = lys_find_child(schema, mod, LYD_NAME(iter), 0, 0, 0);
1137
1138 /* move to the descendant */
Michal Vaskod2f404f2021-11-04 15:37:11 +01001139 prev_iter = iter;
Michal Vasko106f0862021-11-02 11:49:27 +01001140 } while (schema && (iter != node));
1141
1142 return schema;
1143}
1144
Michal Vaskof77ca9c2024-05-29 13:44:16 +02001145LIBYANG_API_DEF ly_bool
1146lyd_meta_is_internal(const struct lyd_meta *meta)
1147{
1148 const char *arg;
1149
1150 assert(meta->annotation);
1151
1152 arg = meta->annotation->argument;
1153 if (!strcmp(meta->annotation->module->name, "yang") && !strcmp(arg, "lyds_tree")) {
1154 return 1;
1155 }
1156
1157 return 0;
1158}
1159
Michal Vasko4754d4a2022-12-01 10:11:21 +01001160void
1161lyd_cont_set_dflt(struct lyd_node *node)
1162{
1163 const struct lyd_node *child;
1164
1165 while (node) {
1166 if (!node->schema || (node->flags & LYD_DEFAULT) || !lysc_is_np_cont(node->schema)) {
1167 /* not a non-dflt NP container */
1168 break;
1169 }
1170
1171 LY_LIST_FOR(lyd_child(node), child) {
1172 if (!(child->flags & LYD_DEFAULT)) {
1173 break;
1174 }
1175 }
1176 if (child) {
1177 /* explicit child, no dflt change */
1178 break;
1179 }
1180
1181 /* set the dflt flag */
1182 node->flags |= LYD_DEFAULT;
1183
1184 /* check all parent containers */
1185 node = lyd_parent(node);
1186 }
1187}
1188
Michal Vasko59892dd2022-05-13 11:02:30 +02001189/**
1190 * @brief Comparison callback to match schema node with a schema of a data node.
1191 *
1192 * @param[in] val1_p Pointer to the schema node
1193 * @param[in] val2_p Pointer to the data node
1194 * Implementation of ::lyht_value_equal_cb.
1195 */
1196static ly_bool
1197lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
1198{
1199 struct lysc_node *val1;
1200 struct lyd_node *val2;
1201
1202 val1 = *((struct lysc_node **)val1_p);
1203 val2 = *((struct lyd_node **)val2_p);
1204
1205 if (val1 == val2->schema) {
1206 /* schema match is enough */
1207 return 1;
1208 } else {
1209 return 0;
1210 }
1211}
1212
1213LY_ERR
1214lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
1215{
1216 struct lyd_node **match_p;
1217 struct lyd_node_inner *parent;
1218 uint32_t hash;
Michal Vasko59892dd2022-05-13 11:02:30 +02001219
Michal Vasko21beaeb2022-08-02 10:42:48 +02001220 assert(schema);
1221 if (!siblings) {
1222 /* no data */
1223 if (match) {
1224 *match = NULL;
1225 }
1226 return LY_ENOTFOUND;
1227 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001228
1229 parent = siblings->parent;
1230 if (parent && parent->schema && parent->children_ht) {
1231 /* calculate our hash */
Michal Vaskoae130f52023-04-20 14:25:16 +02001232 hash = lyht_hash_multi(0, schema->module->name, strlen(schema->module->name));
1233 hash = lyht_hash_multi(hash, schema->name, strlen(schema->name));
1234 hash = lyht_hash_multi(hash, NULL, 0);
Michal Vasko59892dd2022-05-13 11:02:30 +02001235
Michal Vasko87d6bf62023-10-23 10:05:43 +02001236 /* find by hash but use special hash table function (and stay thread-safe) */
1237 if (!lyht_find_with_val_cb(parent->children_ht, &schema, hash, lyd_hash_table_schema_val_equal, (void **)&match_p)) {
Michal Vasko59892dd2022-05-13 11:02:30 +02001238 siblings = *match_p;
1239 } else {
1240 /* not found */
1241 siblings = NULL;
1242 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001243 } else {
1244 /* find first sibling */
1245 if (siblings->parent) {
1246 siblings = siblings->parent->child;
1247 } else {
1248 while (siblings->prev->next) {
1249 siblings = siblings->prev;
1250 }
1251 }
1252
Michal Vaskod8a52012023-08-15 11:38:10 +02001253 /* search manually without hashes and ignore opaque nodes (cannot be found by hashes) */
1254 for ( ; siblings && siblings->schema; siblings = siblings->next) {
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001255 /* schema match is enough */
Michal Vaskod8a52012023-08-15 11:38:10 +02001256 if (LYD_CTX(siblings) == schema->module->ctx) {
1257 if (siblings->schema == schema) {
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001258 break;
1259 }
1260 } else {
Michal Vaskod8a52012023-08-15 11:38:10 +02001261 if (!strcmp(LYD_NAME(siblings), schema->name) && !strcmp(siblings->schema->module->name, schema->module->name)) {
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001262 break;
1263 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001264 }
1265 }
Michal Vaskod8a52012023-08-15 11:38:10 +02001266 if (siblings && !siblings->schema) {
1267 siblings = NULL;
1268 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001269 }
1270
1271 if (!siblings) {
1272 if (match) {
1273 *match = NULL;
1274 }
1275 return LY_ENOTFOUND;
1276 }
1277
1278 if (match) {
1279 *match = (struct lyd_node *)siblings;
1280 }
1281 return LY_SUCCESS;
1282}
1283
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001284void
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001285lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
1286{
1287 if (*root && (lyd_owner_module(*root) != mod)) {
1288 /* there are no data of mod so this is simply the first top-level sibling */
1289 mod = NULL;
1290 }
1291
1292 if ((*root != to_del) || (*root)->parent) {
1293 return;
1294 }
1295
Michal Vasko598063b2021-07-19 11:39:05 +02001296 if (mod && (*root)->prev->next && (!(*root)->next || (lyd_owner_module(to_del) != lyd_owner_module((*root)->next)))) {
1297 /* there are no more nodes from mod, simply get the first top-level sibling */
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001298 *root = lyd_first_sibling(*root);
Michal Vasko598063b2021-07-19 11:39:05 +02001299 } else {
1300 *root = (*root)->next;
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001301 }
1302}
1303
Michal Vasko8cc3f662022-03-29 11:25:51 +02001304LY_ERR
1305ly_nested_ext_schema(const struct lyd_node *parent, const struct lysc_node *sparent, const char *prefix,
1306 size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
1307 const struct lysc_node **snode, struct lysc_ext_instance **ext)
1308{
1309 LY_ERR r;
1310 LY_ARRAY_COUNT_TYPE u;
1311 struct lysc_ext_instance *nested_exts = NULL;
1312 lyplg_ext_data_snode_clb ext_snode_cb;
1313
1314 /* check if there are any nested extension instances */
1315 if (parent && parent->schema) {
1316 nested_exts = parent->schema->exts;
1317 } else if (sparent) {
1318 nested_exts = sparent->exts;
1319 }
1320 LY_ARRAY_FOR(nested_exts, u) {
Michal Vasko305c6cb2022-04-27 10:33:04 +02001321 if (!nested_exts[u].def->plugin) {
1322 /* no plugin */
1323 continue;
1324 }
1325
Michal Vasko8cc3f662022-03-29 11:25:51 +02001326 ext_snode_cb = nested_exts[u].def->plugin->snode;
1327 if (!ext_snode_cb) {
1328 /* not an extension with nested data */
1329 continue;
1330 }
1331
1332 /* try to get the schema node */
1333 r = ext_snode_cb(&nested_exts[u], parent, sparent, prefix, prefix_len, format, prefix_data, name, name_len, snode);
1334 if (!r) {
Michal Vasko66330fc2022-11-21 15:52:24 +01001335 if (ext) {
1336 /* data successfully created, remember the ext instance */
1337 *ext = &nested_exts[u];
1338 }
Michal Vasko8cc3f662022-03-29 11:25:51 +02001339 return LY_SUCCESS;
1340 } else if (r != LY_ENOT) {
1341 /* fatal error */
1342 return r;
1343 }
1344 /* data was not from this module, continue */
1345 }
1346
1347 /* no extensions or none matched */
1348 return LY_ENOT;
1349}
1350
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001351void
Radek Krejci8df109d2021-04-23 12:19:08 +02001352ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001353{
1354 struct ly_set *ns_list;
1355 struct lysc_prefix *prefixes;
1356 uint32_t i;
1357 LY_ARRAY_COUNT_TYPE u;
1358
1359 if (!prefix_data) {
1360 return;
1361 }
1362
1363 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001364 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001365 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001366 ns_list = prefix_data;
1367 for (i = 0; i < ns_list->count; ++i) {
1368 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
1369 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
1370 }
1371 ly_set_free(ns_list, free);
1372 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001373 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001374 prefixes = prefix_data;
1375 LY_ARRAY_FOR(prefixes, u) {
1376 free(prefixes[u].prefix);
1377 }
1378 LY_ARRAY_FREE(prefixes);
1379 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001380 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001381 case LY_VALUE_SCHEMA:
1382 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001383 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001384 break;
1385 }
1386}
1387
1388LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +02001389ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001390 void **prefix_data_p)
1391{
1392 LY_ERR ret = LY_SUCCESS;
1393 struct lyxml_ns *ns;
1394 struct lysc_prefix *prefixes = NULL, *orig_pref;
1395 struct ly_set *ns_list, *orig_ns;
1396 uint32_t i;
1397 LY_ARRAY_COUNT_TYPE u;
1398
1399 assert(!*prefix_data_p);
1400
1401 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001402 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001403 *prefix_data_p = (void *)prefix_data;
1404 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001405 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001406 /* copy all the value prefixes */
1407 orig_pref = (struct lysc_prefix *)prefix_data;
1408 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
1409 *prefix_data_p = prefixes;
1410
1411 LY_ARRAY_FOR(orig_pref, u) {
1412 if (orig_pref[u].prefix) {
1413 prefixes[u].prefix = strdup(orig_pref[u].prefix);
1414 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1415 }
1416 prefixes[u].mod = orig_pref[u].mod;
1417 LY_ARRAY_INCREMENT(prefixes);
1418 }
1419 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001420 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001421 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001422 /* copy all the namespaces */
1423 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
1424 *prefix_data_p = ns_list;
1425
1426 orig_ns = (struct ly_set *)prefix_data;
1427 for (i = 0; i < orig_ns->count; ++i) {
1428 ns = calloc(1, sizeof *ns);
1429 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1430 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
1431
1432 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
1433 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
1434 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1435 }
1436 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
1437 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1438 }
1439 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001440 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001441 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001442 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001443 assert(!prefix_data);
1444 *prefix_data_p = NULL;
1445 break;
1446 }
1447
1448cleanup:
1449 if (ret) {
1450 ly_free_prefix_data(format, *prefix_data_p);
1451 *prefix_data_p = NULL;
1452 }
1453 return ret;
1454}
1455
1456LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +02001457ly_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 +02001458 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001459{
1460 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001461 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001462 const struct lyxml_ns *ns;
1463 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001464 struct ly_set *ns_list;
1465 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +02001466 const char *value_iter, *value_next, *value_end;
1467 uint32_t substr_len;
1468 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001469
1470 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001471 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001472 /* copy all referenced modules as prefix - module pairs */
1473 if (!*prefix_data_p) {
1474 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001475 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +02001476 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001477 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001478 } else {
1479 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +02001480 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001481 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001482 }
1483
Michal Vaskoc0f9c4c2022-05-06 12:12:17 +02001484 /* add current module for unprefixed values */
1485 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1486 *prefix_data_p = prefixes;
1487
1488 val_pref->prefix = NULL;
1489 val_pref->mod = ((const struct lysp_module *)prefix_data)->mod;
1490
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001491 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001492 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001493 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001494 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 +02001495 if (is_prefix) {
1496 /* we have a possible prefix. Do we already have the prefix? */
1497 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
1498 if (!mod) {
1499 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
1500 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001501 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +02001502 /* store a new prefix - module pair */
1503 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1504 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001505
aPiecek83436bc2021-03-30 12:20:45 +02001506 val_pref->prefix = strndup(value_iter, substr_len);
1507 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1508 val_pref->mod = mod;
1509 } /* else it is not even defined */
1510 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +01001511 }
1512 }
1513 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001514 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001515 case LY_VALUE_STR_NS:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001516 /* copy all referenced namespaces as prefix - namespace pairs */
1517 if (!*prefix_data_p) {
1518 /* new prefix data */
1519 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Michal Vaskoddd76592022-01-17 13:34:48 +01001520 *format_p = format;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001521 *prefix_data_p = ns_list;
1522 } else {
1523 /* reuse prefix data */
Michal Vaskoddd76592022-01-17 13:34:48 +01001524 assert(*format_p == format);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001525 ns_list = *prefix_data_p;
1526 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001527
Michal Vasko294e7f02022-02-28 13:59:00 +01001528 /* store default namespace */
1529 ns = lyxml_ns_get(prefix_data, NULL, 0);
1530 if (ns) {
1531 new_ns = calloc(1, sizeof *new_ns);
1532 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1533 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
1534
1535 new_ns->prefix = NULL;
1536 new_ns->uri = strdup(ns->uri);
1537 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1538 }
1539
Michal Vaskofc2cd072021-02-24 13:17:17 +01001540 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001541 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001542 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001543 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 +02001544 if (is_prefix) {
1545 /* we have a possible prefix. Do we already have the prefix? */
1546 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
1547 if (!ns) {
1548 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
1549 if (ns) {
1550 /* store a new prefix - namespace pair */
1551 new_ns = calloc(1, sizeof *new_ns);
1552 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1553 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001554
aPiecek83436bc2021-03-30 12:20:45 +02001555 new_ns->prefix = strndup(value_iter, substr_len);
1556 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1557 new_ns->uri = strdup(ns->uri);
1558 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1559 } /* else it is not even defined */
1560 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001561 }
1562 }
1563 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001564 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001565 case LY_VALUE_SCHEMA_RESOLVED:
1566 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001567 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001568 if (!*prefix_data_p) {
1569 /* new prefix data - simply copy all the prefix data */
1570 *format_p = format;
1571 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
1572 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001573 break;
1574 }
1575
1576cleanup:
1577 if (ret) {
1578 ly_free_prefix_data(*format_p, *prefix_data_p);
1579 *prefix_data_p = NULL;
1580 }
1581 return ret;
1582}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001583
1584const char *
Radek Krejci8df109d2021-04-23 12:19:08 +02001585ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001586{
1587 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +02001588 case LY_VALUE_CANON:
1589 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +02001590 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001591 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +02001592 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001593 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +02001594 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001595 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +02001596 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001597 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +02001598 case LY_VALUE_LYB:
1599 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001600 default:
1601 break;
1602 }
1603
1604 return NULL;
1605}
Michal Vasko43297a02021-05-19 11:12:37 +02001606
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001607LIBYANG_API_DEF int
1608ly_time_tz_offset(void)
1609{
Michal Vasko9b560332023-04-24 15:43:56 +02001610 return ly_time_tz_offset_at(time(NULL));
1611}
1612
1613LIBYANG_API_DEF int
1614ly_time_tz_offset_at(time_t time)
1615{
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001616 struct tm tm_local, tm_utc;
1617 int result = 0;
1618
1619 /* init timezone */
1620 tzset();
1621
1622 /* get local and UTC time */
Michal Vasko9b560332023-04-24 15:43:56 +02001623 localtime_r(&time, &tm_local);
1624 gmtime_r(&time, &tm_utc);
Michal Vaskoe50b98d2023-03-28 11:39:01 +02001625
Michal Vasko9b560332023-04-24 15:43:56 +02001626 /* account for year/month/day change by adding/subtracting from the hours, the change cannot be more than 1 day */
1627 if (tm_local.tm_year < tm_utc.tm_year) {
1628 tm_utc.tm_hour += 24;
1629 } else if (tm_local.tm_year > tm_utc.tm_year) {
1630 tm_local.tm_hour += 24;
1631 } else if (tm_local.tm_mon < tm_utc.tm_mon) {
1632 tm_utc.tm_hour += 24;
1633 } else if (tm_local.tm_mon > tm_utc.tm_mon) {
1634 tm_local.tm_hour += 24;
1635 } else if (tm_local.tm_mday < tm_utc.tm_mday) {
1636 tm_utc.tm_hour += 24;
1637 } else if (tm_local.tm_mday > tm_utc.tm_mday) {
1638 tm_local.tm_hour += 24;
Michal Vaskoe50b98d2023-03-28 11:39:01 +02001639 }
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001640
1641 /* hours shift in seconds */
1642 result += (tm_local.tm_hour - tm_utc.tm_hour) * 3600;
1643
1644 /* minutes shift in seconds */
1645 result += (tm_local.tm_min - tm_utc.tm_min) * 60;
1646
1647 /* seconds shift */
1648 result += tm_local.tm_sec - tm_utc.tm_sec;
1649
1650 return result;
1651}
1652
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001653LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001654ly_time_str2time(const char *value, time_t *time, char **fractions_s)
1655{
1656 struct tm tm = {0};
1657 uint32_t i, frac_len;
1658 const char *frac;
1659 int64_t shift, shift_m;
1660 time_t t;
1661
1662 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
1663
1664 tm.tm_year = atoi(&value[0]) - 1900;
1665 tm.tm_mon = atoi(&value[5]) - 1;
1666 tm.tm_mday = atoi(&value[8]);
1667 tm.tm_hour = atoi(&value[11]);
1668 tm.tm_min = atoi(&value[14]);
1669 tm.tm_sec = atoi(&value[17]);
1670
Michal Vasko2b7e1612023-08-08 13:37:34 +02001671 /* explicit checks for some gross errors */
1672 if (tm.tm_mon > 11) {
1673 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time month \"%d\".", tm.tm_mon);
1674 return LY_EINVAL;
1675 }
1676 if ((tm.tm_mday < 1) || (tm.tm_mday > 31)) {
1677 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time day of month \"%d\".", tm.tm_mday);
1678 return LY_EINVAL;
1679 }
1680 if (tm.tm_hour > 23) {
1681 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time hours \"%d\".", tm.tm_hour);
1682 return LY_EINVAL;
1683 }
1684 if (tm.tm_min > 59) {
1685 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time minutes \"%d\".", tm.tm_min);
1686 return LY_EINVAL;
1687 }
1688 if (tm.tm_sec > 60) {
1689 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time seconds \"%d\".", tm.tm_sec);
1690 return LY_EINVAL;
1691 }
1692
Michal Vasko43297a02021-05-19 11:12:37 +02001693 t = timegm(&tm);
1694 i = 19;
1695
1696 /* fractions of a second */
1697 if (value[i] == '.') {
1698 ++i;
1699 frac = &value[i];
1700 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
1701
1702 i += frac_len;
Michal Vasko43297a02021-05-19 11:12:37 +02001703 } else {
1704 frac = NULL;
1705 }
1706
1707 /* apply offset */
1708 if ((value[i] == 'Z') || (value[i] == 'z')) {
1709 /* zero shift */
1710 shift = 0;
1711 } else {
1712 shift = strtol(&value[i], NULL, 10);
Michal Vasko2b7e1612023-08-08 13:37:34 +02001713 if (shift > 23) {
1714 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time timezone hour \"%" PRIi64 "\".", shift);
1715 return LY_EINVAL;
1716 }
Michal Vasko43297a02021-05-19 11:12:37 +02001717 shift = shift * 60 * 60; /* convert from hours to seconds */
Michal Vasko2b7e1612023-08-08 13:37:34 +02001718
1719 shift_m = strtol(&value[i + 4], NULL, 10);
1720 if (shift_m > 59) {
1721 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time timezone minutes \"%" PRIi64 "\".", shift_m);
1722 return LY_EINVAL;
1723 }
1724 shift_m *= 60; /* convert from minutes to seconds */
1725
Michal Vasko43297a02021-05-19 11:12:37 +02001726 /* correct sign */
1727 if (shift < 0) {
1728 shift_m *= -1;
1729 }
Michal Vasko2b7e1612023-08-08 13:37:34 +02001730
Michal Vasko43297a02021-05-19 11:12:37 +02001731 /* connect hours and minutes of the shift */
1732 shift = shift + shift_m;
1733 }
1734
1735 /* we have to shift to the opposite way to correct the time */
1736 t -= shift;
1737
1738 *time = t;
1739 if (fractions_s) {
1740 if (frac) {
1741 *fractions_s = strndup(frac, frac_len);
1742 LY_CHECK_RET(!*fractions_s, LY_EMEM);
1743 } else {
1744 *fractions_s = NULL;
1745 }
1746 }
1747 return LY_SUCCESS;
1748}
1749
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001750LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001751ly_time_time2str(time_t time, const char *fractions_s, char **str)
1752{
1753 struct tm tm;
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001754 char zoneshift[12];
1755 int zonediff_s, zonediff_h, zonediff_m;
Michal Vasko43297a02021-05-19 11:12:37 +02001756
1757 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
1758
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001759 /* init timezone */
Michal Vasko43297a02021-05-19 11:12:37 +02001760 tzset();
1761
1762 /* convert */
1763 if (!localtime_r(&time, &tm)) {
1764 return LY_ESYS;
1765 }
1766
Michal Vasko3057c052024-06-21 07:59:27 +02001767 /* get timezone offset (do not use tm_gmtoff to avoid portability problems),
1768 * zonediff_h may be negative, zonediff_m MUST NOT */
Michal Vasko9b560332023-04-24 15:43:56 +02001769 zonediff_s = ly_time_tz_offset_at(time);
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001770 zonediff_h = zonediff_s / 60 / 60;
1771 zonediff_m = zonediff_s / 60 % 60;
Michal Vasko3057c052024-06-21 07:59:27 +02001772 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m < 0 ? -zonediff_m : zonediff_m);
Michal Vasko43297a02021-05-19 11:12:37 +02001773
1774 /* print */
1775 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
1776 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
1777 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
1778 return LY_EMEM;
1779 }
1780
1781 return LY_SUCCESS;
1782}
1783
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001784LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001785ly_time_str2ts(const char *value, struct timespec *ts)
1786{
1787 LY_ERR rc;
Michal Vasko72975062021-08-25 08:13:04 +02001788 char *fractions_s, frac_buf[10];
Michal Vasko43297a02021-05-19 11:12:37 +02001789 int frac_len;
1790
1791 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
1792
1793 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
1794 LY_CHECK_RET(rc);
1795
1796 /* convert fractions of a second to nanoseconds */
1797 if (fractions_s) {
Michal Vasko72975062021-08-25 08:13:04 +02001798 /* init frac_buf with zeroes */
1799 memset(frac_buf, '0', 9);
1800 frac_buf[9] = '\0';
1801
Michal Vasko43297a02021-05-19 11:12:37 +02001802 frac_len = strlen(fractions_s);
1803 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
1804 ts->tv_nsec = atol(frac_buf);
1805 free(fractions_s);
1806 } else {
1807 ts->tv_nsec = 0;
1808 }
1809
1810 return LY_SUCCESS;
1811}
1812
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001813LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001814ly_time_ts2str(const struct timespec *ts, char **str)
1815{
1816 char frac_buf[10];
1817
Jan Kundrátbd157002021-08-30 14:02:22 +02001818 LY_CHECK_ARG_RET(NULL, ts, str, ((ts->tv_nsec <= 999999999) && (ts->tv_nsec >= 0)), LY_EINVAL);
Michal Vasko43297a02021-05-19 11:12:37 +02001819
1820 /* convert nanoseconds to fractions of a second */
1821 if (ts->tv_nsec) {
1822 sprintf(frac_buf, "%09ld", ts->tv_nsec);
1823 }
1824
1825 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
1826}