blob: 9746faaa1cf481c8e59db0bc454e878e5bd09d02 [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"
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/**
Michal Vasko271d2e32023-01-31 15:43:19 +010047 * @brief Callback for checking first instance hash table values equivalence.
48 *
49 * @param[in] val1_p If not @p mod, pointer to the first instance.
50 * @param[in] val2_p If not @p mod, pointer to the found dup inst item.
51 */
52static ly_bool
53lyht_dup_inst_ht_equal_cb(void *val1_p, void *val2_p, ly_bool mod, void *UNUSED(cb_data))
54{
55 if (mod) {
56 struct lyd_dup_inst **item1 = val1_p, **item2 = val2_p;
57
58 /* equal on 2 dup inst items */
59 return *item1 == *item2 ? 1 : 0;
60 } else {
61 struct lyd_node **first_inst = val1_p;
62 struct lyd_dup_inst **item = val2_p;
63
64 /* equal on dup inst item and a first instance */
65 return (*item)->set->dnodes[0] == *first_inst ? 1 : 0;
66 }
67}
68
69/**
Michal Vaskod7c048c2021-05-18 16:12:55 +020070 * @brief Find an entry in duplicate instance cache for an instance. Create it if it does not exist.
71 *
Michal Vasko271d2e32023-01-31 15:43:19 +010072 * @param[in] first_inst First instance of the cache entry.
73 * @param[in] dup_inst_ht Duplicate instance cache hash table.
Michal Vaskod7c048c2021-05-18 16:12:55 +020074 * @return Instance cache entry.
75 */
76static struct lyd_dup_inst *
Michal Vasko8efac242023-03-30 08:24:56 +020077lyd_dup_inst_get(const struct lyd_node *first_inst, struct ly_ht **dup_inst_ht)
Michal Vaskod7c048c2021-05-18 16:12:55 +020078{
Michal Vasko271d2e32023-01-31 15:43:19 +010079 struct lyd_dup_inst **item_p, *item;
Michal Vaskod7c048c2021-05-18 16:12:55 +020080
Michal Vasko271d2e32023-01-31 15:43:19 +010081 if (*dup_inst_ht) {
82 /* find the item of the first instance */
83 if (!lyht_find(*dup_inst_ht, &first_inst, first_inst->hash, (void **)&item_p)) {
84 return *item_p;
Michal Vaskod7c048c2021-05-18 16:12:55 +020085 }
Michal Vasko271d2e32023-01-31 15:43:19 +010086 } else {
87 /* create the hash table */
88 *dup_inst_ht = lyht_new(2, sizeof item, lyht_dup_inst_ht_equal_cb, NULL, 1);
89 LY_CHECK_RET(!*dup_inst_ht, NULL);
Michal Vaskod7c048c2021-05-18 16:12:55 +020090 }
91
Michal Vasko271d2e32023-01-31 15:43:19 +010092 /* first instance has no dup inst item, create it */
93 item = calloc(1, sizeof *item);
94 LY_CHECK_RET(!item, NULL);
95
96 /* add into the hash table */
97 if (lyht_insert(*dup_inst_ht, &item, first_inst->hash, NULL)) {
98 return NULL;
99 }
Michal Vaskod7c048c2021-05-18 16:12:55 +0200100
101 return item;
102}
103
104LY_ERR
Michal Vasko8efac242023-03-30 08:24:56 +0200105lyd_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 +0200106{
107 struct lyd_dup_inst *dup_inst;
108
Michal Vasko83ae7772022-06-08 10:01:55 +0200109 if (!*inst) {
110 /* no match, inst is unchanged */
Michal Vaskod7c048c2021-05-18 16:12:55 +0200111 return LY_SUCCESS;
112 }
113
Michal Vasko83ae7772022-06-08 10:01:55 +0200114 /* there can be more exact same instances (even if not allowed in invalid data) and we must make sure we do not
115 * match a single node more times */
Michal Vasko271d2e32023-01-31 15:43:19 +0100116 dup_inst = lyd_dup_inst_get(*inst, dup_inst_ht);
Michal Vaskod7c048c2021-05-18 16:12:55 +0200117 LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
118
119 if (!dup_inst->used) {
120 /* we did not cache these instances yet, do so */
Michal Vasko271d2e32023-01-31 15:43:19 +0100121 lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->set);
122 assert(dup_inst->set->count && (dup_inst->set->dnodes[0] == *inst));
Michal Vaskod7c048c2021-05-18 16:12:55 +0200123 }
124
Michal Vasko271d2e32023-01-31 15:43:19 +0100125 if (dup_inst->used == dup_inst->set->count) {
Michal Vasko4525e1f2022-07-13 16:20:59 +0200126 if (lysc_is_dup_inst_list((*inst)->schema)) {
127 /* we have used all the instances */
128 *inst = NULL;
129 } /* else just keep using the last (ideally only) instance */
Michal Vaskod7c048c2021-05-18 16:12:55 +0200130 } else {
Michal Vasko271d2e32023-01-31 15:43:19 +0100131 assert(dup_inst->used < dup_inst->set->count);
Michal Vaskod7c048c2021-05-18 16:12:55 +0200132
133 /* use another instance */
Michal Vasko271d2e32023-01-31 15:43:19 +0100134 *inst = dup_inst->set->dnodes[dup_inst->used];
Michal Vaskod7c048c2021-05-18 16:12:55 +0200135 ++dup_inst->used;
136 }
137
138 return LY_SUCCESS;
139}
140
Michal Vasko271d2e32023-01-31 15:43:19 +0100141/**
142 * @brief Callback for freeing first instance hash table values.
143 */
144static void
145lyht_dup_inst_ht_free_cb(void *val_p)
Michal Vaskod7c048c2021-05-18 16:12:55 +0200146{
Michal Vasko271d2e32023-01-31 15:43:19 +0100147 struct lyd_dup_inst **item = val_p;
Michal Vaskod7c048c2021-05-18 16:12:55 +0200148
Michal Vasko271d2e32023-01-31 15:43:19 +0100149 ly_set_free((*item)->set, NULL);
150 free(*item);
151}
152
153void
Michal Vasko8efac242023-03-30 08:24:56 +0200154lyd_dup_inst_free(struct ly_ht *dup_inst_ht)
Michal Vasko271d2e32023-01-31 15:43:19 +0100155{
156 lyht_free(dup_inst_ht, lyht_dup_inst_ht_free_cb);
Michal Vaskod7c048c2021-05-18 16:12:55 +0200157}
158
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200159struct lyd_node *
160lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +0200161 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200162{
163 const struct lysc_node *siter = NULL;
164 struct lyd_node *match = NULL;
165
166 assert(parent || module);
167 assert(!last || (slast && *slast));
168
169 if (slast) {
170 siter = *slast;
171 }
172
173 if (last && last->next && (last->next->schema == siter)) {
174 /* return next data instance */
175 return last->next;
176 }
177
178 /* find next schema node data instance */
179 while ((siter = lys_getnext(siter, parent, module, 0))) {
180 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
181 break;
182 }
183 }
184
185 if (slast) {
186 *slast = siter;
187 }
188 return match;
189}
190
Radek Krejcie7b95092019-05-15 11:03:07 +0200191struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +0100192lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200193{
194 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +0100195
196 if (!node->schema) {
197 return &((struct lyd_node_opaq *)node)->child;
198 } else {
199 switch (node->schema->nodetype) {
200 case LYS_CONTAINER:
201 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +0100202 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100203 case LYS_ACTION:
204 case LYS_NOTIF:
205 return &((struct lyd_node_inner *)node)->child;
206 default:
207 return NULL;
208 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200209 }
210}
211
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100212LIBYANG_API_DEF LY_ERR
aPiecekdf23eee2021-10-07 12:21:50 +0200213lyxp_vars_set(struct lyxp_var **vars, const char *name, const char *value)
214{
215 LY_ERR ret = LY_SUCCESS;
216 char *var_name = NULL, *var_value = NULL;
217 struct lyxp_var *item;
218
219 if (!vars || !name || !value) {
220 return LY_EINVAL;
221 }
222
Michal Vasko90189962023-02-28 12:10:34 +0100223 /* if variable is already defined then change its value */
224 if (*vars && !lyxp_vars_find(NULL, *vars, name, 0, &item)) {
aPiecekdf23eee2021-10-07 12:21:50 +0200225 var_value = strdup(value);
226 LY_CHECK_RET(!var_value, LY_EMEM);
227
Michal Vasko90189962023-02-28 12:10:34 +0100228 /* update value */
aPiecekdf23eee2021-10-07 12:21:50 +0200229 free(item->value);
230 item->value = var_value;
231 } else {
232 var_name = strdup(name);
233 var_value = strdup(value);
234 LY_CHECK_ERR_GOTO(!var_name || !var_value, ret = LY_EMEM, error);
235
Michal Vasko90189962023-02-28 12:10:34 +0100236 /* add new variable */
aPiecekdf23eee2021-10-07 12:21:50 +0200237 LY_ARRAY_NEW_GOTO(NULL, *vars, item, ret, error);
238 item->name = var_name;
239 item->value = var_value;
240 }
241
242 return LY_SUCCESS;
243
244error:
245 free(var_name);
246 free(var_value);
247 return ret;
248}
249
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100250LIBYANG_API_DEF void
aPiecekdf23eee2021-10-07 12:21:50 +0200251lyxp_vars_free(struct lyxp_var *vars)
252{
253 LY_ARRAY_COUNT_TYPE u;
254
255 if (!vars) {
256 return;
257 }
258
259 LY_ARRAY_FOR(vars, u) {
260 free(vars[u].name);
261 free(vars[u].value);
262 }
263
264 LY_ARRAY_FREE(vars);
265}
266
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100267LIBYANG_API_DEF struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +0200268lyd_child_no_keys(const struct lyd_node *node)
269{
270 struct lyd_node **children;
271
272 if (!node) {
273 return NULL;
274 }
275
276 if (!node->schema) {
277 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100278 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200279 }
280
Michal Vaskoe0665742021-02-11 11:08:44 +0100281 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200282 if (children) {
283 struct lyd_node *child = *children;
Michal Vasko26bbb272022-08-02 14:54:33 +0200284
Radek Krejcia1c1e542020-09-29 16:06:52 +0200285 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
286 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200287 }
288 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200289 } else {
290 return NULL;
291 }
292}
Michal Vasko9b368d32020-02-14 13:53:31 +0100293
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100294LIBYANG_API_DEF const struct lys_module *
Michal Vaskoc193ce92020-03-06 11:04:48 +0100295lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100296{
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100297 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100298
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100299 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100300 return NULL;
301 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100302
Michal Vasko420cc252023-08-24 08:14:24 +0200303 while (!node->schema && node->parent) {
304 node = lyd_parent(node);
305 }
306
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100307 if (!node->schema) {
Michal Vasko420cc252023-08-24 08:14:24 +0200308 /* top-level opaque node */
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100309 opaq = (struct lyd_node_opaq *)node;
310 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200311 case LY_VALUE_XML:
Michal Vasko09fbb812023-04-13 14:11:06 +0200312 if (opaq->name.module_ns) {
313 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
314 }
315 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200316 case LY_VALUE_JSON:
Michal Vasko09fbb812023-04-13 14:11:06 +0200317 if (opaq->name.module_name) {
318 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
319 }
320 break;
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100321 default:
322 return NULL;
323 }
Michal Vasko09fbb812023-04-13 14:11:06 +0200324
Michal Vasko420cc252023-08-24 08:14:24 +0200325 return NULL;
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100326 }
327
Michal Vaskoef53c812021-10-13 10:21:03 +0200328 return lysc_owner_module(node->schema);
Michal Vasko9b368d32020-02-14 13:53:31 +0100329}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100330
Michal Vasko420cc252023-08-24 08:14:24 +0200331LIBYANG_API_DEF const struct lys_module *
332lyd_node_module(const struct lyd_node *node)
333{
334 const struct lyd_node_opaq *opaq;
335
336 while (node) {
337 /* data node */
338 if (node->schema) {
339 return node->schema->module;
340 }
341
342 /* opaque node */
343 opaq = (struct lyd_node_opaq *)node;
344 switch (opaq->format) {
345 case LY_VALUE_XML:
346 if (opaq->name.module_ns) {
347 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
348 }
349 break;
350 case LY_VALUE_JSON:
351 if (opaq->name.module_name) {
352 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
353 }
354 break;
355 default:
356 break;
357 }
358
359 node = lyd_parent(node);
360 }
361
362 return NULL;
363}
364
Michal Vasko598063b2021-07-19 11:39:05 +0200365void
366lyd_first_module_sibling(struct lyd_node **node, const struct lys_module *mod)
367{
368 int cmp;
369 struct lyd_node *first;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200370 const struct lys_module *own_mod;
Michal Vasko598063b2021-07-19 11:39:05 +0200371
372 assert(node && mod);
373
374 if (!*node) {
375 return;
376 }
377
378 first = *node;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200379 own_mod = lyd_owner_module(first);
380 cmp = own_mod ? strcmp(own_mod->name, mod->name) : 1;
Michal Vasko598063b2021-07-19 11:39:05 +0200381 if (cmp > 0) {
382 /* there may be some preceding data */
383 while (first->prev->next) {
384 first = first->prev;
385 if (lyd_owner_module(first) == mod) {
386 cmp = 0;
387 break;
388 }
389 }
390 }
391
392 if (cmp == 0) {
393 /* there may be some preceding data belonging to this module */
394 while (first->prev->next) {
395 if (lyd_owner_module(first->prev) != mod) {
396 break;
397 }
398 first = first->prev;
399 }
400 }
401
402 if (cmp < 0) {
403 /* there may be some following data */
404 LY_LIST_FOR(first, first) {
405 if (lyd_owner_module(first) == mod) {
406 cmp = 0;
407 break;
408 }
409 }
410 }
411
412 if (cmp == 0) {
413 /* we have found the first module data node */
414 *node = first;
415 }
416}
417
Michal Vaskob1b5c262020-03-05 14:29:47 +0100418const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200419lyd_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 +0200420 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100421{
422 struct lyd_node *iter;
423 const struct lys_module *mod;
424
425 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200426 if (module) {
427 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100428 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200429 } else {
430 mod = module;
431 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100432 }
433 } else {
434 do {
435 mod = ly_ctx_get_module_iter(ctx, i);
436 } while (mod && !mod->implemented);
437 }
438
439 /* find its data */
440 *first = NULL;
441 if (mod) {
442 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100443 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100444 *first = iter;
445 break;
446 }
447 }
448 }
449
450 return mod;
451}
452
453const struct lys_module *
454lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
455{
456 const struct lys_module *mod;
457
458 if (!*next) {
459 /* all data traversed */
460 *first = NULL;
461 return NULL;
462 }
463
464 *first = *next;
465
466 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100467 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100468 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100469 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100470 break;
471 }
472 }
473
474 return mod;
475}
Michal Vasko9f96a052020-03-10 09:41:45 +0100476
Michal Vasko7a266772024-01-23 11:02:38 +0100477/**
478 * @brief Log generated error item and use log location information if not in the error item.
479 *
480 * @param[in] ctx Context to use.
481 * @param[in] node Optional data node to log.
482 * @param[in] scnode Optional schema node to log.
483 * @param[in] eitem Error item to log.
484 */
485static void
486ly_err_print_build_path(const struct ly_ctx *ctx, const struct lyd_node *node, const struct lysc_node *scnode,
487 struct ly_err_item *eitem)
488{
489 if (eitem->data_path || eitem->schema_path || eitem->line) {
490 ly_err_print(ctx, eitem);
491 } else {
492 if (node) {
493 LOG_LOCSET(NULL, node);
494 } else if (scnode) {
495 LOG_LOCSET(scnode, NULL);
496 }
497 ly_vlog(ctx, eitem->apptag, eitem->err == LY_EVALID ? eitem->vecode : LYVE_DATA, "%s", eitem->msg);
498 if (node) {
499 LOG_LOCBACK(0, 1);
500 } else if (scnode) {
501 LOG_LOCBACK(1, 0);
502 }
503 }
504}
505
Michal Vasko9f96a052020-03-10 09:41:45 +0100506LY_ERR
Michal Vasko59892dd2022-05-13 11:02:30 +0200507lyd_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 +0100508 size_t value_len, ly_bool is_utf8, ly_bool store_only, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data,
509 uint32_t hints, const struct lysc_node *ctx_node, ly_bool *incomplete)
Michal Vasko59892dd2022-05-13 11:02:30 +0200510{
511 LY_ERR ret;
512 struct ly_err_item *err = NULL;
Michal Vasko989cdb42023-10-06 15:32:37 +0200513 uint32_t options = 0;
Michal Vasko59892dd2022-05-13 11:02:30 +0200514
515 if (!value) {
516 value = "";
517 }
518 if (incomplete) {
519 *incomplete = 0;
520 }
521
Michal Vasko989cdb42023-10-06 15:32:37 +0200522 if (dynamic && *dynamic) {
523 options |= LYPLG_TYPE_STORE_DYNAMIC;
524 }
525 if (is_utf8) {
526 options |= LYPLG_TYPE_STORE_IS_UTF8;
527 }
stewegd4cde642024-02-21 08:34:16 +0100528 if (store_only) {
529 options |= LYPLG_TYPE_STORE_ONLY;
530 }
Michal Vasko989cdb42023-10-06 15:32:37 +0200531
Michal Vasko59892dd2022-05-13 11:02:30 +0200532 ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data, hints, ctx_node, val, NULL, &err);
533 if (dynamic) {
534 *dynamic = 0;
535 }
536
537 if (ret == LY_EINCOMPLETE) {
538 if (incomplete) {
539 *incomplete = 1;
540 }
541 } else if (ret) {
542 if (err) {
Michal Vasko7a266772024-01-23 11:02:38 +0100543 ly_err_print_build_path(ctx, NULL, ctx_node, err);
Michal Vasko59892dd2022-05-13 11:02:30 +0200544 ly_err_free(err);
545 } else {
546 LOGVAL(ctx, LYVE_OTHER, "Storing value failed.");
547 }
548 return ret;
549 }
550
551 return LY_SUCCESS;
552}
553
554LY_ERR
555lyd_value_validate_incomplete(const struct ly_ctx *ctx, const struct lysc_type *type, struct lyd_value *val,
556 const struct lyd_node *ctx_node, const struct lyd_node *tree)
557{
558 LY_ERR ret;
559 struct ly_err_item *err = NULL;
560
561 assert(type->plugin->validate);
562
563 ret = type->plugin->validate(ctx, type, ctx_node, tree, val, &err);
564 if (ret) {
565 if (err) {
Michal Vasko7a266772024-01-23 11:02:38 +0100566 ly_err_print_build_path(ctx, ctx_node, NULL, err);
Michal Vasko59892dd2022-05-13 11:02:30 +0200567 ly_err_free(err);
568 } else {
Michal Vasko7b3a00e2023-08-09 11:58:03 +0200569 LOGVAL(ctx, LYVE_OTHER, "Resolving value \"%s\" failed.",
570 (char *)type->plugin->print(ctx, val, LY_VALUE_CANON, NULL, NULL, NULL));
Michal Vasko59892dd2022-05-13 11:02:30 +0200571 }
572 return ret;
573 }
574
575 return LY_SUCCESS;
576}
577
578LY_ERR
Michal Vasko583b4642023-05-25 10:39:34 +0200579ly_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
580 LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints)
Michal Vasko59892dd2022-05-13 11:02:30 +0200581{
582 LY_ERR rc = LY_SUCCESS;
583 struct ly_err_item *err = NULL;
584 struct lyd_value storage;
585 struct lysc_type *type;
586
Michal Vasko0c361552023-04-04 10:04:03 +0200587 LY_CHECK_ARG_RET(ctx, node, LY_EINVAL);
Michal Vasko59892dd2022-05-13 11:02:30 +0200588
589 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
590 LOGARG(ctx, node);
591 return LY_EINVAL;
592 }
593
594 type = ((struct lysc_node_leaf *)node)->type;
Michal Vasko583b4642023-05-25 10:39:34 +0200595 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, 0, format, prefix_data, hints, node,
596 &storage, NULL, &err);
Michal Vasko59892dd2022-05-13 11:02:30 +0200597 if (rc == LY_EINCOMPLETE) {
598 /* actually success since we do not provide the context tree and call validation with
599 * LY_TYPE_OPTS_INCOMPLETE_DATA */
600 rc = LY_SUCCESS;
601 } else if (rc && err) {
602 if (ctx) {
603 /* log only in case the ctx was provided as input parameter */
Michal Vasko7a266772024-01-23 11:02:38 +0100604 ly_err_print_build_path(ctx, NULL, node, err);
Michal Vasko59892dd2022-05-13 11:02:30 +0200605 }
606 ly_err_free(err);
607 }
608
609 if (!rc) {
610 type->plugin->free(ctx ? ctx : node->module->ctx, &storage);
611 }
612 return rc;
613}
614
615LIBYANG_API_DEF LY_ERR
616lyd_value_validate(const struct ly_ctx *ctx, const struct lysc_node *schema, const char *value, size_t value_len,
617 const struct lyd_node *ctx_node, const struct lysc_type **realtype, const char **canonical)
618{
619 LY_ERR rc;
620 struct ly_err_item *err = NULL;
621 struct lysc_type *type;
622 struct lyd_value val = {0};
623 ly_bool stored = 0, log = 1;
624
Michal Vasko3dd16da2022-06-15 07:58:41 +0200625 LY_CHECK_ARG_RET(ctx, schema, !value_len || value, LY_EINVAL);
Michal Vasko59892dd2022-05-13 11:02:30 +0200626
627 if (!ctx) {
628 ctx = schema->module->ctx;
629 log = 0;
630 }
Michal Vasko3dd16da2022-06-15 07:58:41 +0200631 if (!value_len) {
632 value = "";
633 }
Michal Vasko59892dd2022-05-13 11:02:30 +0200634 type = ((struct lysc_node_leaf *)schema)->type;
635
636 /* store */
637 rc = type->plugin->store(ctx, type, value, value_len, 0, LY_VALUE_JSON, NULL,
638 LYD_HINT_DATA, schema, &val, NULL, &err);
639 if (!rc || (rc == LY_EINCOMPLETE)) {
640 stored = 1;
641 }
642
643 if (ctx_node && (rc == LY_EINCOMPLETE)) {
644 /* resolve */
645 rc = type->plugin->validate(ctx, type, ctx_node, ctx_node, &val, &err);
646 }
647
648 if (rc && (rc != LY_EINCOMPLETE) && err) {
649 if (log) {
650 /* log error */
Michal Vasko7a266772024-01-23 11:02:38 +0100651 ly_err_print_build_path(ctx, ctx_node, schema, err);
Michal Vasko59892dd2022-05-13 11:02:30 +0200652 }
653 ly_err_free(err);
654 }
655
656 if (!rc || (rc == LY_EINCOMPLETE)) {
657 if (realtype) {
658 /* return realtype */
659 if (val.realtype->basetype == LY_TYPE_UNION) {
660 *realtype = val.subvalue->value.realtype;
661 } else {
662 *realtype = val.realtype;
663 }
664 }
665
666 if (canonical) {
667 /* return canonical value */
668 lydict_insert(ctx, val.realtype->plugin->print(ctx, &val, LY_VALUE_CANON, NULL, NULL, NULL), 0, canonical);
669 }
670 }
671
672 if (stored) {
673 /* free value */
674 type->plugin->free(ctx ? ctx : schema->module->ctx, &val);
675 }
676 return rc;
677}
678
679LIBYANG_API_DEF LY_ERR
680lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len)
681{
682 LY_ERR ret = LY_SUCCESS;
683 struct ly_ctx *ctx;
684 struct lysc_type *type;
685 struct lyd_value val = {0};
686
687 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
688
689 ctx = node->schema->module->ctx;
690 type = ((struct lysc_node_leaf *)node->schema)->type;
691
692 /* store the value */
Michal Vasko7a266772024-01-23 11:02:38 +0100693 LOG_LOCSET(NULL, &node->node);
stewegd4cde642024-02-21 08:34:16 +0100694 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 +0100695 LOG_LOCBACK(0, 1);
Michal Vasko59892dd2022-05-13 11:02:30 +0200696 LY_CHECK_RET(ret);
697
698 /* compare values */
aPiecek0a6705b2023-11-14 14:20:58 +0100699 ret = type->plugin->compare(ctx, &node->value, &val);
Michal Vasko59892dd2022-05-13 11:02:30 +0200700
701 type->plugin->free(ctx, &val);
702 return ret;
703}
704
705LIBYANG_API_DEF ly_bool
706lyd_is_default(const struct lyd_node *node)
707{
708 const struct lysc_node_leaf *leaf;
709 const struct lysc_node_leaflist *llist;
710 const struct lyd_node_term *term;
711 LY_ARRAY_COUNT_TYPE u;
712
713 if (!(node->schema->nodetype & LYD_NODE_TERM)) {
714 return 0;
715 }
716
717 term = (const struct lyd_node_term *)node;
718
719 if (node->schema->nodetype == LYS_LEAF) {
720 leaf = (const struct lysc_node_leaf *)node->schema;
721 if (!leaf->dflt) {
722 return 0;
723 }
724
725 /* compare with the default value */
aPiecek0a6705b2023-11-14 14:20:58 +0100726 if (!leaf->type->plugin->compare(LYD_CTX(node), &term->value, leaf->dflt)) {
Michal Vasko59892dd2022-05-13 11:02:30 +0200727 return 1;
728 }
729 } else {
730 llist = (const struct lysc_node_leaflist *)node->schema;
731 if (!llist->dflts) {
732 return 0;
733 }
734
735 LY_ARRAY_FOR(llist->dflts, u) {
736 /* compare with each possible default value */
aPiecek0a6705b2023-11-14 14:20:58 +0100737 if (!llist->type->plugin->compare(LYD_CTX(node), &term->value, llist->dflts[u])) {
Michal Vasko59892dd2022-05-13 11:02:30 +0200738 return 1;
739 }
740 }
741 }
742
743 return 0;
744}
745
746LIBYANG_API_DEF uint32_t
747lyd_list_pos(const struct lyd_node *instance)
748{
749 const struct lyd_node *iter = NULL;
750 uint32_t pos = 0;
751
752 if (!instance || !(instance->schema->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
753 return 0;
754 }
755
756 /* data instances are ordered, so we can stop when we found instance of other schema node */
757 for (iter = instance; iter->schema == instance->schema; iter = iter->prev) {
758 if (pos && (iter->next == NULL)) {
759 /* overrun to the end of the siblings list */
760 break;
761 }
762 ++pos;
763 }
764
765 return pos;
766}
767
768LIBYANG_API_DEF struct lyd_node *
769lyd_first_sibling(const struct lyd_node *node)
770{
771 struct lyd_node *start;
772
773 if (!node) {
774 return NULL;
775 }
776
777 /* get the first sibling */
778 if (node->parent) {
aPiecek743184b2024-02-01 13:25:56 +0100779 return node->parent->child;
780 } else if (!node->prev->next) {
781 return (struct lyd_node *)node;
782 }
783
784 for (start = (struct lyd_node *)node->prev; start->prev->next; start = start->prev) {
785 assert(start != node);
Michal Vasko59892dd2022-05-13 11:02:30 +0200786 }
787
788 return start;
789}
790
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100791/**
792 * @brief Check list node parsed into an opaque node for the reason.
793 *
794 * @param[in] node Opaque node.
795 * @param[in] snode Schema node of @p opaq.
796 * @return LY_SUCCESS if the node is valid;
797 * @return LY_ERR on error.
798 */
799static LY_ERR
800lyd_parse_opaq_list_error(const struct lyd_node *node, const struct lysc_node *snode)
801{
802 LY_ERR ret = LY_SUCCESS;
803 struct ly_set key_set = {0};
804 const struct lysc_node *key = NULL;
805 const struct lyd_node *child;
806 const struct lyd_node_opaq *opaq_k;
807 uint32_t i;
808
809 assert(!node->schema);
810
811 /* get all keys into a set */
Michal Vaskof30bcf12023-07-14 12:12:03 +0200812 while ((key = lys_getnext(key, snode, NULL, 0)) && (key->flags & LYS_KEY)) {
813 LY_CHECK_GOTO(ret = ly_set_add(&key_set, (void *)key, 1, NULL), cleanup);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100814 }
815
816 LY_LIST_FOR(lyd_child(node), child) {
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100817 /* find the key schema node */
818 for (i = 0; i < key_set.count; ++i) {
819 key = key_set.snodes[i];
Michal Vaskoa878a892023-08-18 12:22:07 +0200820 if (!strcmp(key->name, LYD_NAME(child))) {
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100821 break;
822 }
823 }
824 if (i == key_set.count) {
825 /* some other node, skip */
826 continue;
827 }
828
829 /* key found */
830 ly_set_rm_index(&key_set, i, NULL);
831
Michal Vaskoa878a892023-08-18 12:22:07 +0200832 if (child->schema) {
833 /* valid key */
834 continue;
835 }
836
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100837 /* check value */
Michal Vaskoa878a892023-08-18 12:22:07 +0200838 opaq_k = (struct lyd_node_opaq *)child;
Michal Vasko583b4642023-05-25 10:39:34 +0200839 ret = ly_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
840 opaq_k->val_prefix_data, opaq_k->hints);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100841 LY_CHECK_GOTO(ret, cleanup);
842 }
843
844 if (key_set.count) {
845 /* missing keys */
846 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, key_set.snodes[0]->name);
847 ret = LY_EVALID;
848 goto cleanup;
849 }
850
851cleanup:
852 ly_set_erase(&key_set, NULL);
853 return ret;
854}
855
856LIBYANG_API_DEF LY_ERR
857lyd_parse_opaq_error(const struct lyd_node *node)
858{
Michal Vasko6727c682023-02-17 10:40:26 +0100859 LY_ERR rc = LY_SUCCESS;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100860 const struct ly_ctx *ctx;
861 const struct lyd_node_opaq *opaq;
862 const struct lyd_node *parent;
863 const struct lys_module *mod;
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200864 const struct lysc_node *sparent, *snode;
Michal Vasko7a266772024-01-23 11:02:38 +0100865 uint32_t loc_scnode = 0, loc_dnode = 0;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100866
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200867 LY_CHECK_ARG_RET(LYD_CTX(node), node, !node->schema, LY_EINVAL);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100868
869 ctx = LYD_CTX(node);
870 opaq = (struct lyd_node_opaq *)node;
871 parent = lyd_parent(node);
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200872 sparent = lyd_node_schema(parent);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100873
Michal Vasko7a266772024-01-23 11:02:38 +0100874 /* if parent is NULL, it is still added as root */
875 LOG_LOCSET(NULL, parent);
876 loc_dnode = 1;
Michal Vasko6727c682023-02-17 10:40:26 +0100877
Michal Vaskof4e63922022-05-10 10:32:13 +0200878 if (!opaq->name.module_ns) {
879 LOGVAL(ctx, LYVE_REFERENCE, "Unknown module of node \"%s\".", opaq->name.name);
Michal Vasko6727c682023-02-17 10:40:26 +0100880 rc = LY_EVALID;
881 goto cleanup;
Michal Vaskof4e63922022-05-10 10:32:13 +0200882 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100883
884 /* module */
885 switch (opaq->format) {
886 case LY_VALUE_XML:
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200887 if (!sparent || strcmp(opaq->name.module_ns, sparent->module->ns)) {
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100888 mod = ly_ctx_get_module_implemented_ns(ctx, opaq->name.module_ns);
889 if (!mod) {
Michal Vasko959f8d82022-06-16 07:51:50 +0200890 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module with namespace \"%s\" of node \"%s\" in the context.",
891 opaq->name.module_ns, opaq->name.name);
Michal Vasko6727c682023-02-17 10:40:26 +0100892 rc = LY_EVALID;
893 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100894 }
895 } else {
896 /* inherit */
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200897 mod = sparent->module;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100898 }
899 break;
900 case LY_VALUE_JSON:
901 case LY_VALUE_LYB:
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200902 if (!sparent || strcmp(opaq->name.module_name, sparent->module->name)) {
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100903 mod = ly_ctx_get_module_implemented(ctx, opaq->name.module_name);
904 if (!mod) {
Michal Vasko959f8d82022-06-16 07:51:50 +0200905 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module named \"%s\" of node \"%s\" in the context.",
906 opaq->name.module_name, opaq->name.name);
Michal Vasko6727c682023-02-17 10:40:26 +0100907 rc = LY_EVALID;
908 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100909 }
910 } else {
911 /* inherit */
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200912 mod = sparent->module;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100913 }
914 break;
915 default:
916 LOGERR(ctx, LY_EINVAL, "Unsupported value format.");
Michal Vasko6727c682023-02-17 10:40:26 +0100917 rc = LY_EINVAL;
918 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100919 }
920
921 /* schema */
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200922 snode = lys_find_child(sparent, mod, opaq->name.name, 0, 0, 0);
923 if (!snode && sparent && (sparent->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200924 /* maybe output node */
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200925 snode = lys_find_child(sparent, mod, opaq->name.name, 0, 0, LYS_GETNEXT_OUTPUT);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200926 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100927 if (!snode) {
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200928 if (sparent) {
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100929 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found as a child of \"%s\" node.", opaq->name.name,
Michal Vasko9d9b88d2023-08-21 11:55:43 +0200930 sparent->name);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100931 } else {
932 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found in the \"%s\" module.", opaq->name.name, mod->name);
933 }
Michal Vasko6727c682023-02-17 10:40:26 +0100934 rc = LY_EVALID;
935 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100936 }
937
Michal Vasko6727c682023-02-17 10:40:26 +0100938 /* schema node exists */
Michal Vasko7a266772024-01-23 11:02:38 +0100939 LOG_LOCBACK(0, 1);
940 loc_dnode = 0;
941 LOG_LOCSET(snode, NULL);
942 loc_scnode = 1;
Michal Vasko6727c682023-02-17 10:40:26 +0100943
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100944 if (snode->nodetype & LYD_NODE_TERM) {
945 /* leaf / leaf-list */
Michal Vasko583b4642023-05-25 10:39:34 +0200946 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 +0100947 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100948 } else if (snode->nodetype == LYS_LIST) {
949 /* list */
Michal Vasko6727c682023-02-17 10:40:26 +0100950 rc = lyd_parse_opaq_list_error(node, snode);
951 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100952 } else if (snode->nodetype & LYD_NODE_INNER) {
953 /* inner node */
954 if (opaq->value) {
955 LOGVAL(ctx, LYVE_DATA, "Invalid value \"%s\" for %s \"%s\".", opaq->value,
956 lys_nodetype2str(snode->nodetype), snode->name);
Michal Vasko6727c682023-02-17 10:40:26 +0100957 rc = LY_EVALID;
958 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100959 }
960 } else {
961 LOGERR(ctx, LY_EINVAL, "Unexpected opaque schema node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
Michal Vasko6727c682023-02-17 10:40:26 +0100962 rc = LY_EINVAL;
963 goto cleanup;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100964 }
965
966 LOGERR(ctx, LY_EINVAL, "Unexpected valid opaque node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
Michal Vasko6727c682023-02-17 10:40:26 +0100967 rc = LY_EINVAL;
968
969cleanup:
Michal Vasko7a266772024-01-23 11:02:38 +0100970 LOG_LOCBACK(loc_scnode, loc_dnode);
Michal Vasko6727c682023-02-17 10:40:26 +0100971 return rc;
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100972}
973
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100974LIBYANG_API_DEF const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400975lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200976{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200977 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
978
Michal Vasko33876022021-04-27 16:42:24 +0200979 return value->_canonical ? value->_canonical :
980 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200981}
982
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100983LIBYANG_API_DEF LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100984lyd_any_value_str(const struct lyd_node *any, char **value_str)
985{
986 const struct lyd_node_any *a;
987 struct lyd_node *tree = NULL;
988 const char *str = NULL;
989 ly_bool dynamic = 0;
990 LY_ERR ret = LY_SUCCESS;
991
992 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200993 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100994
995 a = (struct lyd_node_any *)any;
996 *value_str = NULL;
997
998 if (!a->value.str) {
999 /* there is no value in the union */
1000 return LY_SUCCESS;
1001 }
1002
1003 switch (a->value_type) {
1004 case LYD_ANYDATA_LYB:
1005 /* parse into a data tree */
1006 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
1007 LY_CHECK_GOTO(ret, cleanup);
1008 dynamic = 1;
1009 break;
1010 case LYD_ANYDATA_DATATREE:
1011 tree = a->value.tree;
1012 break;
1013 case LYD_ANYDATA_STRING:
1014 case LYD_ANYDATA_XML:
1015 case LYD_ANYDATA_JSON:
1016 /* simply use the string */
1017 str = a->value.str;
1018 break;
1019 }
1020
1021 if (tree) {
1022 /* print into a string */
1023 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
1024 LY_CHECK_GOTO(ret, cleanup);
1025 } else {
1026 assert(str);
1027 *value_str = strdup(str);
1028 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
1029 }
1030
1031 /* success */
1032
1033cleanup:
1034 if (dynamic) {
1035 lyd_free_all(tree);
1036 }
1037 return ret;
1038}
1039
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001040LIBYANG_API_DEF LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +02001041lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
1042{
1043 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +02001044
Michal Vaskoa820c312021-02-05 16:33:00 +01001045 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +02001046 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +02001047
1048 t = (struct lyd_node_any *)trg;
1049
1050 /* free trg */
1051 switch (t->value_type) {
1052 case LYD_ANYDATA_DATATREE:
1053 lyd_free_all(t->value.tree);
1054 break;
1055 case LYD_ANYDATA_STRING:
1056 case LYD_ANYDATA_XML:
1057 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +01001058 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +02001059 break;
1060 case LYD_ANYDATA_LYB:
1061 free(t->value.mem);
1062 break;
1063 }
1064 t->value.str = NULL;
1065
1066 if (!value) {
1067 /* only free value in this case */
1068 return LY_SUCCESS;
1069 }
1070
1071 /* copy src */
1072 t->value_type = value_type;
1073 switch (value_type) {
1074 case LYD_ANYDATA_DATATREE:
1075 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +02001076 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +02001077 }
1078 break;
1079 case LYD_ANYDATA_STRING:
1080 case LYD_ANYDATA_XML:
1081 case LYD_ANYDATA_JSON:
1082 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02001083 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +02001084 }
1085 break;
1086 case LYD_ANYDATA_LYB:
1087 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +02001088 int len = lyd_lyb_data_length(value->mem);
Michal Vasko26bbb272022-08-02 14:54:33 +02001089
Radek Krejci82fa8d42020-07-11 22:00:59 +02001090 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +02001091 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +02001092 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +02001093 memcpy(t->value.mem, value->mem, len);
1094 }
1095 break;
1096 }
1097
1098 return LY_SUCCESS;
1099}
1100
Michal Vasko21c11c22023-10-09 16:06:58 +02001101LIBYANG_API_DEF const struct lysc_node *
Michal Vasko106f0862021-11-02 11:49:27 +01001102lyd_node_schema(const struct lyd_node *node)
1103{
1104 const struct lysc_node *schema = NULL;
1105 const struct lyd_node *prev_iter = NULL, *iter;
1106 const struct lys_module *mod;
1107
1108 if (!node) {
1109 return NULL;
1110 } else if (node->schema) {
1111 return node->schema;
1112 }
1113
Michal Vaskoa878a892023-08-18 12:22:07 +02001114 /* find the first schema node in the parents */
1115 for (iter = lyd_parent(node); iter && !iter->schema; iter = lyd_parent(iter)) {}
1116 if (iter) {
1117 prev_iter = iter;
1118 schema = prev_iter->schema;
1119 }
1120
Michal Vasko106f0862021-11-02 11:49:27 +01001121 /* get schema node of an opaque node */
1122 do {
1123 /* get next data node */
1124 for (iter = node; lyd_parent(iter) != prev_iter; iter = lyd_parent(iter)) {}
1125
Michal Vaskoa878a892023-08-18 12:22:07 +02001126 /* get module */
Michal Vasko420cc252023-08-24 08:14:24 +02001127 mod = lyd_node_module(iter);
Michal Vaskoa878a892023-08-18 12:22:07 +02001128 if (!mod) {
1129 /* unknown module, no schema node */
1130 schema = NULL;
1131 break;
Michal Vasko106f0862021-11-02 11:49:27 +01001132 }
Michal Vaskod2f404f2021-11-04 15:37:11 +01001133
Michal Vaskoa878a892023-08-18 12:22:07 +02001134 /* get schema node */
1135 schema = lys_find_child(schema, mod, LYD_NAME(iter), 0, 0, 0);
1136
1137 /* move to the descendant */
Michal Vaskod2f404f2021-11-04 15:37:11 +01001138 prev_iter = iter;
Michal Vasko106f0862021-11-02 11:49:27 +01001139 } while (schema && (iter != node));
1140
1141 return schema;
1142}
1143
Michal Vasko4754d4a2022-12-01 10:11:21 +01001144void
1145lyd_cont_set_dflt(struct lyd_node *node)
1146{
1147 const struct lyd_node *child;
1148
1149 while (node) {
1150 if (!node->schema || (node->flags & LYD_DEFAULT) || !lysc_is_np_cont(node->schema)) {
1151 /* not a non-dflt NP container */
1152 break;
1153 }
1154
1155 LY_LIST_FOR(lyd_child(node), child) {
1156 if (!(child->flags & LYD_DEFAULT)) {
1157 break;
1158 }
1159 }
1160 if (child) {
1161 /* explicit child, no dflt change */
1162 break;
1163 }
1164
1165 /* set the dflt flag */
1166 node->flags |= LYD_DEFAULT;
1167
1168 /* check all parent containers */
1169 node = lyd_parent(node);
1170 }
1171}
1172
Michal Vasko59892dd2022-05-13 11:02:30 +02001173/**
1174 * @brief Comparison callback to match schema node with a schema of a data node.
1175 *
1176 * @param[in] val1_p Pointer to the schema node
1177 * @param[in] val2_p Pointer to the data node
1178 * Implementation of ::lyht_value_equal_cb.
1179 */
1180static ly_bool
1181lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
1182{
1183 struct lysc_node *val1;
1184 struct lyd_node *val2;
1185
1186 val1 = *((struct lysc_node **)val1_p);
1187 val2 = *((struct lyd_node **)val2_p);
1188
1189 if (val1 == val2->schema) {
1190 /* schema match is enough */
1191 return 1;
1192 } else {
1193 return 0;
1194 }
1195}
1196
1197LY_ERR
1198lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
1199{
1200 struct lyd_node **match_p;
1201 struct lyd_node_inner *parent;
1202 uint32_t hash;
Michal Vasko59892dd2022-05-13 11:02:30 +02001203
Michal Vasko21beaeb2022-08-02 10:42:48 +02001204 assert(schema);
1205 if (!siblings) {
1206 /* no data */
1207 if (match) {
1208 *match = NULL;
1209 }
1210 return LY_ENOTFOUND;
1211 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001212
1213 parent = siblings->parent;
1214 if (parent && parent->schema && parent->children_ht) {
1215 /* calculate our hash */
Michal Vaskoae130f52023-04-20 14:25:16 +02001216 hash = lyht_hash_multi(0, schema->module->name, strlen(schema->module->name));
1217 hash = lyht_hash_multi(hash, schema->name, strlen(schema->name));
1218 hash = lyht_hash_multi(hash, NULL, 0);
Michal Vasko59892dd2022-05-13 11:02:30 +02001219
Michal Vasko87d6bf62023-10-23 10:05:43 +02001220 /* find by hash but use special hash table function (and stay thread-safe) */
1221 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 +02001222 siblings = *match_p;
1223 } else {
1224 /* not found */
1225 siblings = NULL;
1226 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001227 } else {
1228 /* find first sibling */
1229 if (siblings->parent) {
1230 siblings = siblings->parent->child;
1231 } else {
1232 while (siblings->prev->next) {
1233 siblings = siblings->prev;
1234 }
1235 }
1236
Michal Vaskod8a52012023-08-15 11:38:10 +02001237 /* search manually without hashes and ignore opaque nodes (cannot be found by hashes) */
1238 for ( ; siblings && siblings->schema; siblings = siblings->next) {
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001239 /* schema match is enough */
Michal Vaskod8a52012023-08-15 11:38:10 +02001240 if (LYD_CTX(siblings) == schema->module->ctx) {
1241 if (siblings->schema == schema) {
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001242 break;
1243 }
1244 } else {
Michal Vaskod8a52012023-08-15 11:38:10 +02001245 if (!strcmp(LYD_NAME(siblings), schema->name) && !strcmp(siblings->schema->module->name, schema->module->name)) {
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001246 break;
1247 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001248 }
1249 }
Michal Vaskod8a52012023-08-15 11:38:10 +02001250 if (siblings && !siblings->schema) {
1251 siblings = NULL;
1252 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001253 }
1254
1255 if (!siblings) {
1256 if (match) {
1257 *match = NULL;
1258 }
1259 return LY_ENOTFOUND;
1260 }
1261
1262 if (match) {
1263 *match = (struct lyd_node *)siblings;
1264 }
1265 return LY_SUCCESS;
1266}
1267
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001268void
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001269lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
1270{
1271 if (*root && (lyd_owner_module(*root) != mod)) {
1272 /* there are no data of mod so this is simply the first top-level sibling */
1273 mod = NULL;
1274 }
1275
1276 if ((*root != to_del) || (*root)->parent) {
1277 return;
1278 }
1279
Michal Vasko598063b2021-07-19 11:39:05 +02001280 if (mod && (*root)->prev->next && (!(*root)->next || (lyd_owner_module(to_del) != lyd_owner_module((*root)->next)))) {
1281 /* there are no more nodes from mod, simply get the first top-level sibling */
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001282 *root = lyd_first_sibling(*root);
Michal Vasko598063b2021-07-19 11:39:05 +02001283 } else {
1284 *root = (*root)->next;
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001285 }
1286}
1287
Michal Vasko8cc3f662022-03-29 11:25:51 +02001288LY_ERR
1289ly_nested_ext_schema(const struct lyd_node *parent, const struct lysc_node *sparent, const char *prefix,
1290 size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
1291 const struct lysc_node **snode, struct lysc_ext_instance **ext)
1292{
1293 LY_ERR r;
1294 LY_ARRAY_COUNT_TYPE u;
1295 struct lysc_ext_instance *nested_exts = NULL;
1296 lyplg_ext_data_snode_clb ext_snode_cb;
1297
1298 /* check if there are any nested extension instances */
1299 if (parent && parent->schema) {
1300 nested_exts = parent->schema->exts;
1301 } else if (sparent) {
1302 nested_exts = sparent->exts;
1303 }
1304 LY_ARRAY_FOR(nested_exts, u) {
Michal Vasko305c6cb2022-04-27 10:33:04 +02001305 if (!nested_exts[u].def->plugin) {
1306 /* no plugin */
1307 continue;
1308 }
1309
Michal Vasko8cc3f662022-03-29 11:25:51 +02001310 ext_snode_cb = nested_exts[u].def->plugin->snode;
1311 if (!ext_snode_cb) {
1312 /* not an extension with nested data */
1313 continue;
1314 }
1315
1316 /* try to get the schema node */
1317 r = ext_snode_cb(&nested_exts[u], parent, sparent, prefix, prefix_len, format, prefix_data, name, name_len, snode);
1318 if (!r) {
Michal Vasko66330fc2022-11-21 15:52:24 +01001319 if (ext) {
1320 /* data successfully created, remember the ext instance */
1321 *ext = &nested_exts[u];
1322 }
Michal Vasko8cc3f662022-03-29 11:25:51 +02001323 return LY_SUCCESS;
1324 } else if (r != LY_ENOT) {
1325 /* fatal error */
1326 return r;
1327 }
1328 /* data was not from this module, continue */
1329 }
1330
1331 /* no extensions or none matched */
1332 return LY_ENOT;
1333}
1334
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001335void
Radek Krejci8df109d2021-04-23 12:19:08 +02001336ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001337{
1338 struct ly_set *ns_list;
1339 struct lysc_prefix *prefixes;
1340 uint32_t i;
1341 LY_ARRAY_COUNT_TYPE u;
1342
1343 if (!prefix_data) {
1344 return;
1345 }
1346
1347 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001348 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001349 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001350 ns_list = prefix_data;
1351 for (i = 0; i < ns_list->count; ++i) {
1352 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
1353 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
1354 }
1355 ly_set_free(ns_list, free);
1356 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001357 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001358 prefixes = prefix_data;
1359 LY_ARRAY_FOR(prefixes, u) {
1360 free(prefixes[u].prefix);
1361 }
1362 LY_ARRAY_FREE(prefixes);
1363 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001364 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001365 case LY_VALUE_SCHEMA:
1366 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001367 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001368 break;
1369 }
1370}
1371
1372LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +02001373ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001374 void **prefix_data_p)
1375{
1376 LY_ERR ret = LY_SUCCESS;
1377 struct lyxml_ns *ns;
1378 struct lysc_prefix *prefixes = NULL, *orig_pref;
1379 struct ly_set *ns_list, *orig_ns;
1380 uint32_t i;
1381 LY_ARRAY_COUNT_TYPE u;
1382
1383 assert(!*prefix_data_p);
1384
1385 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001386 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001387 *prefix_data_p = (void *)prefix_data;
1388 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001389 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001390 /* copy all the value prefixes */
1391 orig_pref = (struct lysc_prefix *)prefix_data;
1392 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
1393 *prefix_data_p = prefixes;
1394
1395 LY_ARRAY_FOR(orig_pref, u) {
1396 if (orig_pref[u].prefix) {
1397 prefixes[u].prefix = strdup(orig_pref[u].prefix);
1398 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1399 }
1400 prefixes[u].mod = orig_pref[u].mod;
1401 LY_ARRAY_INCREMENT(prefixes);
1402 }
1403 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001404 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001405 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001406 /* copy all the namespaces */
1407 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
1408 *prefix_data_p = ns_list;
1409
1410 orig_ns = (struct ly_set *)prefix_data;
1411 for (i = 0; i < orig_ns->count; ++i) {
1412 ns = calloc(1, sizeof *ns);
1413 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1414 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
1415
1416 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
1417 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
1418 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1419 }
1420 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
1421 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1422 }
1423 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001424 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001425 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001426 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001427 assert(!prefix_data);
1428 *prefix_data_p = NULL;
1429 break;
1430 }
1431
1432cleanup:
1433 if (ret) {
1434 ly_free_prefix_data(format, *prefix_data_p);
1435 *prefix_data_p = NULL;
1436 }
1437 return ret;
1438}
1439
1440LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +02001441ly_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 +02001442 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001443{
1444 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001445 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001446 const struct lyxml_ns *ns;
1447 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001448 struct ly_set *ns_list;
1449 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +02001450 const char *value_iter, *value_next, *value_end;
1451 uint32_t substr_len;
1452 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001453
1454 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001455 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001456 /* copy all referenced modules as prefix - module pairs */
1457 if (!*prefix_data_p) {
1458 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001459 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +02001460 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001461 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001462 } else {
1463 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +02001464 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001465 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001466 }
1467
Michal Vaskoc0f9c4c2022-05-06 12:12:17 +02001468 /* add current module for unprefixed values */
1469 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1470 *prefix_data_p = prefixes;
1471
1472 val_pref->prefix = NULL;
1473 val_pref->mod = ((const struct lysp_module *)prefix_data)->mod;
1474
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001475 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001476 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001477 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001478 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 +02001479 if (is_prefix) {
1480 /* we have a possible prefix. Do we already have the prefix? */
1481 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
1482 if (!mod) {
1483 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
1484 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001485 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +02001486 /* store a new prefix - module pair */
1487 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1488 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001489
aPiecek83436bc2021-03-30 12:20:45 +02001490 val_pref->prefix = strndup(value_iter, substr_len);
1491 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1492 val_pref->mod = mod;
1493 } /* else it is not even defined */
1494 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +01001495 }
1496 }
1497 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001498 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001499 case LY_VALUE_STR_NS:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001500 /* copy all referenced namespaces as prefix - namespace pairs */
1501 if (!*prefix_data_p) {
1502 /* new prefix data */
1503 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Michal Vaskoddd76592022-01-17 13:34:48 +01001504 *format_p = format;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001505 *prefix_data_p = ns_list;
1506 } else {
1507 /* reuse prefix data */
Michal Vaskoddd76592022-01-17 13:34:48 +01001508 assert(*format_p == format);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001509 ns_list = *prefix_data_p;
1510 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001511
Michal Vasko294e7f02022-02-28 13:59:00 +01001512 /* store default namespace */
1513 ns = lyxml_ns_get(prefix_data, NULL, 0);
1514 if (ns) {
1515 new_ns = calloc(1, sizeof *new_ns);
1516 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1517 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
1518
1519 new_ns->prefix = NULL;
1520 new_ns->uri = strdup(ns->uri);
1521 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1522 }
1523
Michal Vaskofc2cd072021-02-24 13:17:17 +01001524 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001525 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001526 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001527 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 +02001528 if (is_prefix) {
1529 /* we have a possible prefix. Do we already have the prefix? */
1530 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
1531 if (!ns) {
1532 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
1533 if (ns) {
1534 /* store a new prefix - namespace pair */
1535 new_ns = calloc(1, sizeof *new_ns);
1536 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1537 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001538
aPiecek83436bc2021-03-30 12:20:45 +02001539 new_ns->prefix = strndup(value_iter, substr_len);
1540 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1541 new_ns->uri = strdup(ns->uri);
1542 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1543 } /* else it is not even defined */
1544 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001545 }
1546 }
1547 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001548 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001549 case LY_VALUE_SCHEMA_RESOLVED:
1550 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001551 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001552 if (!*prefix_data_p) {
1553 /* new prefix data - simply copy all the prefix data */
1554 *format_p = format;
1555 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
1556 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001557 break;
1558 }
1559
1560cleanup:
1561 if (ret) {
1562 ly_free_prefix_data(*format_p, *prefix_data_p);
1563 *prefix_data_p = NULL;
1564 }
1565 return ret;
1566}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001567
1568const char *
Radek Krejci8df109d2021-04-23 12:19:08 +02001569ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001570{
1571 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +02001572 case LY_VALUE_CANON:
1573 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +02001574 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001575 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +02001576 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001577 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +02001578 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001579 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +02001580 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001581 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +02001582 case LY_VALUE_LYB:
1583 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001584 default:
1585 break;
1586 }
1587
1588 return NULL;
1589}
Michal Vasko43297a02021-05-19 11:12:37 +02001590
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001591LIBYANG_API_DEF int
1592ly_time_tz_offset(void)
1593{
Michal Vasko9b560332023-04-24 15:43:56 +02001594 return ly_time_tz_offset_at(time(NULL));
1595}
1596
1597LIBYANG_API_DEF int
1598ly_time_tz_offset_at(time_t time)
1599{
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001600 struct tm tm_local, tm_utc;
1601 int result = 0;
1602
1603 /* init timezone */
1604 tzset();
1605
1606 /* get local and UTC time */
Michal Vasko9b560332023-04-24 15:43:56 +02001607 localtime_r(&time, &tm_local);
1608 gmtime_r(&time, &tm_utc);
Michal Vaskoe50b98d2023-03-28 11:39:01 +02001609
Michal Vasko9b560332023-04-24 15:43:56 +02001610 /* account for year/month/day change by adding/subtracting from the hours, the change cannot be more than 1 day */
1611 if (tm_local.tm_year < tm_utc.tm_year) {
1612 tm_utc.tm_hour += 24;
1613 } else if (tm_local.tm_year > tm_utc.tm_year) {
1614 tm_local.tm_hour += 24;
1615 } else if (tm_local.tm_mon < tm_utc.tm_mon) {
1616 tm_utc.tm_hour += 24;
1617 } else if (tm_local.tm_mon > tm_utc.tm_mon) {
1618 tm_local.tm_hour += 24;
1619 } else if (tm_local.tm_mday < tm_utc.tm_mday) {
1620 tm_utc.tm_hour += 24;
1621 } else if (tm_local.tm_mday > tm_utc.tm_mday) {
1622 tm_local.tm_hour += 24;
Michal Vaskoe50b98d2023-03-28 11:39:01 +02001623 }
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001624
1625 /* hours shift in seconds */
1626 result += (tm_local.tm_hour - tm_utc.tm_hour) * 3600;
1627
1628 /* minutes shift in seconds */
1629 result += (tm_local.tm_min - tm_utc.tm_min) * 60;
1630
1631 /* seconds shift */
1632 result += tm_local.tm_sec - tm_utc.tm_sec;
1633
1634 return result;
1635}
1636
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001637LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001638ly_time_str2time(const char *value, time_t *time, char **fractions_s)
1639{
1640 struct tm tm = {0};
1641 uint32_t i, frac_len;
1642 const char *frac;
1643 int64_t shift, shift_m;
1644 time_t t;
1645
1646 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
1647
1648 tm.tm_year = atoi(&value[0]) - 1900;
1649 tm.tm_mon = atoi(&value[5]) - 1;
1650 tm.tm_mday = atoi(&value[8]);
1651 tm.tm_hour = atoi(&value[11]);
1652 tm.tm_min = atoi(&value[14]);
1653 tm.tm_sec = atoi(&value[17]);
1654
Michal Vasko2b7e1612023-08-08 13:37:34 +02001655 /* explicit checks for some gross errors */
1656 if (tm.tm_mon > 11) {
1657 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time month \"%d\".", tm.tm_mon);
1658 return LY_EINVAL;
1659 }
1660 if ((tm.tm_mday < 1) || (tm.tm_mday > 31)) {
1661 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time day of month \"%d\".", tm.tm_mday);
1662 return LY_EINVAL;
1663 }
1664 if (tm.tm_hour > 23) {
1665 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time hours \"%d\".", tm.tm_hour);
1666 return LY_EINVAL;
1667 }
1668 if (tm.tm_min > 59) {
1669 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time minutes \"%d\".", tm.tm_min);
1670 return LY_EINVAL;
1671 }
1672 if (tm.tm_sec > 60) {
1673 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time seconds \"%d\".", tm.tm_sec);
1674 return LY_EINVAL;
1675 }
1676
Michal Vasko43297a02021-05-19 11:12:37 +02001677 t = timegm(&tm);
1678 i = 19;
1679
1680 /* fractions of a second */
1681 if (value[i] == '.') {
1682 ++i;
1683 frac = &value[i];
1684 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
1685
1686 i += frac_len;
Michal Vasko43297a02021-05-19 11:12:37 +02001687 } else {
1688 frac = NULL;
1689 }
1690
1691 /* apply offset */
1692 if ((value[i] == 'Z') || (value[i] == 'z')) {
1693 /* zero shift */
1694 shift = 0;
1695 } else {
1696 shift = strtol(&value[i], NULL, 10);
Michal Vasko2b7e1612023-08-08 13:37:34 +02001697 if (shift > 23) {
1698 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time timezone hour \"%" PRIi64 "\".", shift);
1699 return LY_EINVAL;
1700 }
Michal Vasko43297a02021-05-19 11:12:37 +02001701 shift = shift * 60 * 60; /* convert from hours to seconds */
Michal Vasko2b7e1612023-08-08 13:37:34 +02001702
1703 shift_m = strtol(&value[i + 4], NULL, 10);
1704 if (shift_m > 59) {
1705 LOGERR(NULL, LY_EINVAL, "Invalid date-and-time timezone minutes \"%" PRIi64 "\".", shift_m);
1706 return LY_EINVAL;
1707 }
1708 shift_m *= 60; /* convert from minutes to seconds */
1709
Michal Vasko43297a02021-05-19 11:12:37 +02001710 /* correct sign */
1711 if (shift < 0) {
1712 shift_m *= -1;
1713 }
Michal Vasko2b7e1612023-08-08 13:37:34 +02001714
Michal Vasko43297a02021-05-19 11:12:37 +02001715 /* connect hours and minutes of the shift */
1716 shift = shift + shift_m;
1717 }
1718
1719 /* we have to shift to the opposite way to correct the time */
1720 t -= shift;
1721
1722 *time = t;
1723 if (fractions_s) {
1724 if (frac) {
1725 *fractions_s = strndup(frac, frac_len);
1726 LY_CHECK_RET(!*fractions_s, LY_EMEM);
1727 } else {
1728 *fractions_s = NULL;
1729 }
1730 }
1731 return LY_SUCCESS;
1732}
1733
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001734LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001735ly_time_time2str(time_t time, const char *fractions_s, char **str)
1736{
1737 struct tm tm;
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001738 char zoneshift[12];
1739 int zonediff_s, zonediff_h, zonediff_m;
Michal Vasko43297a02021-05-19 11:12:37 +02001740
1741 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
1742
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001743 /* init timezone */
Michal Vasko43297a02021-05-19 11:12:37 +02001744 tzset();
1745
1746 /* convert */
1747 if (!localtime_r(&time, &tm)) {
1748 return LY_ESYS;
1749 }
1750
Michal Vaskoe50b98d2023-03-28 11:39:01 +02001751 /* get timezone offset (do not use tm_gmtoff to avoid portability problems) */
Michal Vasko9b560332023-04-24 15:43:56 +02001752 zonediff_s = ly_time_tz_offset_at(time);
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001753 zonediff_h = zonediff_s / 60 / 60;
1754 zonediff_m = zonediff_s / 60 % 60;
Michal Vasko43297a02021-05-19 11:12:37 +02001755 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
1756
1757 /* print */
1758 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
1759 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
1760 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
1761 return LY_EMEM;
1762 }
1763
1764 return LY_SUCCESS;
1765}
1766
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001767LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001768ly_time_str2ts(const char *value, struct timespec *ts)
1769{
1770 LY_ERR rc;
Michal Vasko72975062021-08-25 08:13:04 +02001771 char *fractions_s, frac_buf[10];
Michal Vasko43297a02021-05-19 11:12:37 +02001772 int frac_len;
1773
1774 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
1775
1776 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
1777 LY_CHECK_RET(rc);
1778
1779 /* convert fractions of a second to nanoseconds */
1780 if (fractions_s) {
Michal Vasko72975062021-08-25 08:13:04 +02001781 /* init frac_buf with zeroes */
1782 memset(frac_buf, '0', 9);
1783 frac_buf[9] = '\0';
1784
Michal Vasko43297a02021-05-19 11:12:37 +02001785 frac_len = strlen(fractions_s);
1786 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
1787 ts->tv_nsec = atol(frac_buf);
1788 free(fractions_s);
1789 } else {
1790 ts->tv_nsec = 0;
1791 }
1792
1793 return LY_SUCCESS;
1794}
1795
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001796LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001797ly_time_ts2str(const struct timespec *ts, char **str)
1798{
1799 char frac_buf[10];
1800
Jan Kundrátbd157002021-08-30 14:02:22 +02001801 LY_CHECK_ARG_RET(NULL, ts, str, ((ts->tv_nsec <= 999999999) && (ts->tv_nsec >= 0)), LY_EINVAL);
Michal Vasko43297a02021-05-19 11:12:37 +02001802
1803 /* convert nanoseconds to fractions of a second */
1804 if (ts->tv_nsec) {
1805 sprintf(frac_buf, "%09ld", ts->tv_nsec);
1806 }
1807
1808 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
1809}