blob: a364562986804f46e27c495dba5641c5c606cd64 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file tree_data_helpers.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Parsing and validation helper functions for data trees
5 *
Michal Vasko8cc3f662022-03-29 11:25:51 +02006 * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
Radek Krejcie7b95092019-05-15 11:03:07 +02007 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Michal Vasko43297a02021-05-19 11:12:37 +020014
15#define _GNU_SOURCE /* asprintf, strdup */
Radek Krejcie7b95092019-05-15 11:03:07 +020016
17#include <assert.h>
Michal Vasko43297a02021-05-19 11:12:37 +020018#include <ctype.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020019#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020020#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020021#include <string.h>
Michal Vasko43297a02021-05-19 11:12:37 +020022#include <time.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020023
Radek Krejci535ea9f2020-05-29 16:01:05 +020024#include "common.h"
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"
Radek Krejciad97c5f2020-06-30 09:19:28 +020030#include "lyb.h"
Radek Krejci7931b192020-06-25 17:05:03 +020031#include "parser_data.h"
Michal Vasko8cc3f662022-03-29 11:25:51 +020032#include "plugins_exts.h"
Michal Vaskoa820c312021-02-05 16:33:00 +010033#include "printer_data.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020034#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020035#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020036#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020037#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010038#include "tree_edit.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020039#include "tree_schema.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020040#include "tree_schema_internal.h"
Radek Krejci4f2e3e52021-03-30 14:20:28 +020041#include "validation.h"
Radek Krejci77114102021-03-10 15:21:57 +010042#include "xml.h"
aPiecekdf23eee2021-10-07 12:21:50 +020043#include "xpath.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020044
Michal Vaskod7c048c2021-05-18 16:12:55 +020045/**
46 * @brief Find an entry in duplicate instance cache for an instance. Create it if it does not exist.
47 *
48 * @param[in] first_inst Instance of the cache entry.
49 * @param[in,out] dup_inst_cache Duplicate instance cache.
50 * @return Instance cache entry.
51 */
52static struct lyd_dup_inst *
53lyd_dup_inst_get(const struct lyd_node *first_inst, struct lyd_dup_inst **dup_inst_cache)
54{
55 struct lyd_dup_inst *item;
56 LY_ARRAY_COUNT_TYPE u;
57
58 LY_ARRAY_FOR(*dup_inst_cache, u) {
59 if ((*dup_inst_cache)[u].inst_set->dnodes[0] == first_inst) {
60 return &(*dup_inst_cache)[u];
61 }
62 }
63
64 /* it was not added yet, add it now */
65 LY_ARRAY_NEW_RET(LYD_CTX(first_inst), *dup_inst_cache, item, NULL);
66
67 return item;
68}
69
70LY_ERR
71lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struct lyd_dup_inst **dup_inst_cache)
72{
73 struct lyd_dup_inst *dup_inst;
74
75 if (!*inst || !lysc_is_dup_inst_list((*inst)->schema)) {
76 /* no match or not dup-inst list, inst is unchanged */
77 return LY_SUCCESS;
78 }
79
80 /* there can be more exact same instances and we must make sure we do not match a single node more times */
81 dup_inst = lyd_dup_inst_get(*inst, dup_inst_cache);
82 LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
83
84 if (!dup_inst->used) {
85 /* we did not cache these instances yet, do so */
86 lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->inst_set);
87 assert(dup_inst->inst_set->count && (dup_inst->inst_set->dnodes[0] == *inst));
88 }
89
90 if (dup_inst->used == dup_inst->inst_set->count) {
91 /* we have used all the instances */
92 *inst = NULL;
93 } else {
94 assert(dup_inst->used < dup_inst->inst_set->count);
95
96 /* use another instance */
97 *inst = dup_inst->inst_set->dnodes[dup_inst->used];
98 ++dup_inst->used;
99 }
100
101 return LY_SUCCESS;
102}
103
104void
105lyd_dup_inst_free(struct lyd_dup_inst *dup_inst)
106{
107 LY_ARRAY_COUNT_TYPE u;
108
109 LY_ARRAY_FOR(dup_inst, u) {
110 ly_set_free(dup_inst[u].inst_set, NULL);
111 }
112 LY_ARRAY_FREE(dup_inst);
113}
114
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200115struct lyd_node *
116lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +0200117 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200118{
119 const struct lysc_node *siter = NULL;
120 struct lyd_node *match = NULL;
121
122 assert(parent || module);
123 assert(!last || (slast && *slast));
124
125 if (slast) {
126 siter = *slast;
127 }
128
129 if (last && last->next && (last->next->schema == siter)) {
130 /* return next data instance */
131 return last->next;
132 }
133
134 /* find next schema node data instance */
135 while ((siter = lys_getnext(siter, parent, module, 0))) {
136 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
137 break;
138 }
139 }
140
141 if (slast) {
142 *slast = siter;
143 }
144 return match;
145}
146
Radek Krejcie7b95092019-05-15 11:03:07 +0200147struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +0100148lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200149{
150 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +0100151
152 if (!node->schema) {
153 return &((struct lyd_node_opaq *)node)->child;
154 } else {
155 switch (node->schema->nodetype) {
156 case LYS_CONTAINER:
157 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +0100158 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100159 case LYS_ACTION:
160 case LYS_NOTIF:
161 return &((struct lyd_node_inner *)node)->child;
162 default:
163 return NULL;
164 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200165 }
166}
167
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100168LIBYANG_API_DEF LY_ERR
aPiecekdf23eee2021-10-07 12:21:50 +0200169lyxp_vars_set(struct lyxp_var **vars, const char *name, const char *value)
170{
171 LY_ERR ret = LY_SUCCESS;
172 char *var_name = NULL, *var_value = NULL;
173 struct lyxp_var *item;
174
175 if (!vars || !name || !value) {
176 return LY_EINVAL;
177 }
178
179 /* If variable is already defined then change its value. */
180 if (*vars && !lyxp_vars_find(*vars, name, 0, &item)) {
181 var_value = strdup(value);
182 LY_CHECK_RET(!var_value, LY_EMEM);
183
184 /* Set new value. */
185 free(item->value);
186 item->value = var_value;
187 } else {
188 var_name = strdup(name);
189 var_value = strdup(value);
190 LY_CHECK_ERR_GOTO(!var_name || !var_value, ret = LY_EMEM, error);
191
192 /* Add new variable. */
193 LY_ARRAY_NEW_GOTO(NULL, *vars, item, ret, error);
194 item->name = var_name;
195 item->value = var_value;
196 }
197
198 return LY_SUCCESS;
199
200error:
201 free(var_name);
202 free(var_value);
203 return ret;
204}
205
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100206LIBYANG_API_DEF void
aPiecekdf23eee2021-10-07 12:21:50 +0200207lyxp_vars_free(struct lyxp_var *vars)
208{
209 LY_ARRAY_COUNT_TYPE u;
210
211 if (!vars) {
212 return;
213 }
214
215 LY_ARRAY_FOR(vars, u) {
216 free(vars[u].name);
217 free(vars[u].value);
218 }
219
220 LY_ARRAY_FREE(vars);
221}
222
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100223LIBYANG_API_DEF struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +0200224lyd_child_no_keys(const struct lyd_node *node)
225{
226 struct lyd_node **children;
227
228 if (!node) {
229 return NULL;
230 }
231
232 if (!node->schema) {
233 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100234 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200235 }
236
Michal Vaskoe0665742021-02-11 11:08:44 +0100237 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200238 if (children) {
239 struct lyd_node *child = *children;
240 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
241 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200242 }
243 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200244 } else {
245 return NULL;
246 }
247}
Michal Vasko9b368d32020-02-14 13:53:31 +0100248
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100249LIBYANG_API_DEF const struct lys_module *
Michal Vaskoc193ce92020-03-06 11:04:48 +0100250lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100251{
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100252 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100253
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100254 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100255 return NULL;
256 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100257
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100258 if (!node->schema) {
259 opaq = (struct lyd_node_opaq *)node;
260 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200261 case LY_VALUE_XML:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100262 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
Radek Krejci8df109d2021-04-23 12:19:08 +0200263 case LY_VALUE_JSON:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100264 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
265 default:
266 return NULL;
267 }
268 }
269
Michal Vaskoef53c812021-10-13 10:21:03 +0200270 return lysc_owner_module(node->schema);
Michal Vasko9b368d32020-02-14 13:53:31 +0100271}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100272
Michal Vasko598063b2021-07-19 11:39:05 +0200273void
274lyd_first_module_sibling(struct lyd_node **node, const struct lys_module *mod)
275{
276 int cmp;
277 struct lyd_node *first;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200278 const struct lys_module *own_mod;
Michal Vasko598063b2021-07-19 11:39:05 +0200279
280 assert(node && mod);
281
282 if (!*node) {
283 return;
284 }
285
286 first = *node;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200287 own_mod = lyd_owner_module(first);
288 cmp = own_mod ? strcmp(own_mod->name, mod->name) : 1;
Michal Vasko598063b2021-07-19 11:39:05 +0200289 if (cmp > 0) {
290 /* there may be some preceding data */
291 while (first->prev->next) {
292 first = first->prev;
293 if (lyd_owner_module(first) == mod) {
294 cmp = 0;
295 break;
296 }
297 }
298 }
299
300 if (cmp == 0) {
301 /* there may be some preceding data belonging to this module */
302 while (first->prev->next) {
303 if (lyd_owner_module(first->prev) != mod) {
304 break;
305 }
306 first = first->prev;
307 }
308 }
309
310 if (cmp < 0) {
311 /* there may be some following data */
312 LY_LIST_FOR(first, first) {
313 if (lyd_owner_module(first) == mod) {
314 cmp = 0;
315 break;
316 }
317 }
318 }
319
320 if (cmp == 0) {
321 /* we have found the first module data node */
322 *node = first;
323 }
324}
325
Michal Vaskob1b5c262020-03-05 14:29:47 +0100326const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200327lyd_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 +0200328 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100329{
330 struct lyd_node *iter;
331 const struct lys_module *mod;
332
333 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200334 if (module) {
335 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100336 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200337 } else {
338 mod = module;
339 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100340 }
341 } else {
342 do {
343 mod = ly_ctx_get_module_iter(ctx, i);
344 } while (mod && !mod->implemented);
345 }
346
347 /* find its data */
348 *first = NULL;
349 if (mod) {
350 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100351 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100352 *first = iter;
353 break;
354 }
355 }
356 }
357
358 return mod;
359}
360
361const struct lys_module *
362lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
363{
364 const struct lys_module *mod;
365
366 if (!*next) {
367 /* all data traversed */
368 *first = NULL;
369 return NULL;
370 }
371
372 *first = *next;
373
374 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100375 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100376 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100377 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100378 break;
379 }
380 }
381
382 return mod;
383}
Michal Vasko9f96a052020-03-10 09:41:45 +0100384
385LY_ERR
386lyd_parse_check_keys(struct lyd_node *node)
387{
388 const struct lysc_node *skey = NULL;
389 const struct lyd_node *key;
390
391 assert(node->schema->nodetype == LYS_LIST);
392
Radek Krejcia1c1e542020-09-29 16:06:52 +0200393 key = lyd_child(node);
Michal Vasko9f96a052020-03-10 09:41:45 +0100394 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
395 if (!key || (key->schema != skey)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100396 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, skey->name);
Michal Vasko9f96a052020-03-10 09:41:45 +0100397 return LY_EVALID;
398 }
399
400 key = key->next;
401 }
402
403 return LY_SUCCESS;
404}
Michal Vasko60ea6352020-06-29 13:39:39 +0200405
Michal Vasko8cc3f662022-03-29 11:25:51 +0200406LY_ERR
407lyd_parse_set_data_flags(struct lyd_node *node, struct lyd_meta **meta, struct lyd_ctx *lydctx,
408 struct lysc_ext_instance *ext)
Michal Vasko60ea6352020-06-29 13:39:39 +0200409{
410 struct lyd_meta *meta2, *prev_meta = NULL;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200411 struct lyd_ctx_ext_val *ext_val;
Michal Vasko60ea6352020-06-29 13:39:39 +0200412
Michal Vaskoa5705e52020-12-09 18:15:14 +0100413 if (lysc_has_when(node->schema)) {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200414 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200415 /* remember we need to evaluate this node's when */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200416 LY_CHECK_RET(ly_set_add(&lydctx->node_when, node, 1, NULL));
Michal Vasko60ea6352020-06-29 13:39:39 +0200417 }
418 }
419
Michal Vasko60ea6352020-06-29 13:39:39 +0200420 LY_LIST_FOR(*meta, meta2) {
Michal Vasko69730152020-10-09 16:30:07 +0200421 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
422 meta2->value.boolean) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200423 /* node is default according to the metadata */
424 node->flags |= LYD_DEFAULT;
425
426 /* delete the metadata */
427 if (prev_meta) {
428 prev_meta->next = meta2->next;
429 } else {
430 *meta = (*meta)->next;
431 }
Michal Vasko3a41dff2020-07-15 14:30:28 +0200432 lyd_free_meta_single(meta2);
Michal Vasko60ea6352020-06-29 13:39:39 +0200433 break;
434 }
435
436 prev_meta = meta2;
437 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200438
439 if (ext) {
440 /* parsed for an extension */
441 node->flags |= LYD_EXT;
442
443 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
444 /* rememeber for validation */
445 ext_val = malloc(sizeof *ext_val);
446 LY_CHECK_ERR_RET(!ext_val, LOGMEM(LYD_CTX(node)), LY_EMEM);
447 ext_val->ext = ext;
448 ext_val->sibling = node;
449 LY_CHECK_RET(ly_set_add(&lydctx->ext_val, ext_val, 1, NULL));
450 }
451 }
452
453 return LY_SUCCESS;
Michal Vasko60ea6352020-06-29 13:39:39 +0200454}
455
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100456/**
457 * @brief Check list node parsed into an opaque node for the reason.
458 *
459 * @param[in] node Opaque node.
460 * @param[in] snode Schema node of @p opaq.
461 * @return LY_SUCCESS if the node is valid;
462 * @return LY_ERR on error.
463 */
464static LY_ERR
465lyd_parse_opaq_list_error(const struct lyd_node *node, const struct lysc_node *snode)
466{
467 LY_ERR ret = LY_SUCCESS;
468 struct ly_set key_set = {0};
469 const struct lysc_node *key = NULL;
470 const struct lyd_node *child;
471 const struct lyd_node_opaq *opaq_k;
472 uint32_t i;
473
474 assert(!node->schema);
475
476 /* get all keys into a set */
477 while ((key = lys_getnext(key, snode, NULL, 0)) && (snode->flags & LYS_KEY)) {
478 LY_CHECK_GOTO(ret = ly_set_add(&key_set, (void *)snode, 1, NULL), cleanup);
479 }
480
481 LY_LIST_FOR(lyd_child(node), child) {
482 if (child->schema) {
483 LOGERR(LYD_CTX(node), LY_EINVAL, "Unexpected node %s \"%s\".", lys_nodetype2str(child->schema->nodetype),
484 LYD_NAME(child));
485 ret = LY_EINVAL;
486 goto cleanup;
487 }
488
489 opaq_k = (struct lyd_node_opaq *)child;
490
491 /* find the key schema node */
492 for (i = 0; i < key_set.count; ++i) {
493 key = key_set.snodes[i];
494 if (!strcmp(key->name, opaq_k->name.name)) {
495 break;
496 }
497 }
498 if (i == key_set.count) {
499 /* some other node, skip */
500 continue;
501 }
502
503 /* key found */
504 ly_set_rm_index(&key_set, i, NULL);
505
506 /* check value */
507 ret = lys_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
508 opaq_k->val_prefix_data);
509 LY_CHECK_GOTO(ret, cleanup);
510 }
511
512 if (key_set.count) {
513 /* missing keys */
514 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, key_set.snodes[0]->name);
515 ret = LY_EVALID;
516 goto cleanup;
517 }
518
519cleanup:
520 ly_set_erase(&key_set, NULL);
521 return ret;
522}
523
524LIBYANG_API_DEF LY_ERR
525lyd_parse_opaq_error(const struct lyd_node *node)
526{
527 const struct ly_ctx *ctx;
528 const struct lyd_node_opaq *opaq;
529 const struct lyd_node *parent;
530 const struct lys_module *mod;
531 const struct lysc_node *snode;
532
533 LY_CHECK_ARG_RET(LYD_CTX(node), node, !node->schema, !lyd_parent(node) || lyd_parent(node)->schema, LY_EINVAL);
534
535 ctx = LYD_CTX(node);
536 opaq = (struct lyd_node_opaq *)node;
537 parent = lyd_parent(node);
538
Michal Vaskof4e63922022-05-10 10:32:13 +0200539 if (!opaq->name.module_ns) {
540 LOGVAL(ctx, LYVE_REFERENCE, "Unknown module of node \"%s\".", opaq->name.name);
541 return LY_EVALID;
542 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100543
544 /* module */
545 switch (opaq->format) {
546 case LY_VALUE_XML:
547 if (!parent || strcmp(opaq->name.module_ns, parent->schema->module->ns)) {
548 mod = ly_ctx_get_module_implemented_ns(ctx, opaq->name.module_ns);
549 if (!mod) {
550 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module with namespace \"%s\" in the context.",
551 opaq->name.module_ns);
552 return LY_EVALID;
553 }
554 } else {
555 /* inherit */
556 mod = parent->schema->module;
557 }
558 break;
559 case LY_VALUE_JSON:
560 case LY_VALUE_LYB:
561 if (!parent || strcmp(opaq->name.module_name, parent->schema->module->name)) {
562 mod = ly_ctx_get_module_implemented(ctx, opaq->name.module_name);
563 if (!mod) {
564 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module named \"%s\" in the context.", opaq->name.module_name);
565 return LY_EVALID;
566 }
567 } else {
568 /* inherit */
569 mod = parent->schema->module;
570 }
571 break;
572 default:
573 LOGERR(ctx, LY_EINVAL, "Unsupported value format.");
574 return LY_EINVAL;
575 }
576
577 /* schema */
578 snode = lys_find_child(parent ? parent->schema : NULL, mod, opaq->name.name, 0, 0, 0);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200579 if (!snode && parent && parent->schema && (parent->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
580 /* maybe output node */
Michal Vasko89afc6e2022-05-02 10:24:26 +0200581 snode = lys_find_child(parent->schema, mod, opaq->name.name, 0, 0, LYS_GETNEXT_OUTPUT);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200582 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100583 if (!snode) {
584 if (parent) {
585 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found as a child of \"%s\" node.", opaq->name.name,
586 LYD_NAME(parent));
587 } else {
588 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found in the \"%s\" module.", opaq->name.name, mod->name);
589 }
590 return LY_EVALID;
591 }
592
593 if (snode->nodetype & LYD_NODE_TERM) {
594 /* leaf / leaf-list */
595 LY_CHECK_RET(lys_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data));
596 } else if (snode->nodetype == LYS_LIST) {
597 /* list */
598 LY_CHECK_RET(lyd_parse_opaq_list_error(node, snode));
599 } else if (snode->nodetype & LYD_NODE_INNER) {
600 /* inner node */
601 if (opaq->value) {
602 LOGVAL(ctx, LYVE_DATA, "Invalid value \"%s\" for %s \"%s\".", opaq->value,
603 lys_nodetype2str(snode->nodetype), snode->name);
604 return LY_EVALID;
605 }
606 } else {
607 LOGERR(ctx, LY_EINVAL, "Unexpected opaque schema node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
608 return LY_EINVAL;
609 }
610
611 LOGERR(ctx, LY_EINVAL, "Unexpected valid opaque node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
612 return LY_EINVAL;
613}
614
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100615LIBYANG_API_DEF const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400616lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200617{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200618 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
619
Michal Vasko33876022021-04-27 16:42:24 +0200620 return value->_canonical ? value->_canonical :
621 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200622}
623
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100624LIBYANG_API_DEF LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100625lyd_any_value_str(const struct lyd_node *any, char **value_str)
626{
627 const struct lyd_node_any *a;
628 struct lyd_node *tree = NULL;
629 const char *str = NULL;
630 ly_bool dynamic = 0;
631 LY_ERR ret = LY_SUCCESS;
632
633 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200634 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100635
636 a = (struct lyd_node_any *)any;
637 *value_str = NULL;
638
639 if (!a->value.str) {
640 /* there is no value in the union */
641 return LY_SUCCESS;
642 }
643
644 switch (a->value_type) {
645 case LYD_ANYDATA_LYB:
646 /* parse into a data tree */
647 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
648 LY_CHECK_GOTO(ret, cleanup);
649 dynamic = 1;
650 break;
651 case LYD_ANYDATA_DATATREE:
652 tree = a->value.tree;
653 break;
654 case LYD_ANYDATA_STRING:
655 case LYD_ANYDATA_XML:
656 case LYD_ANYDATA_JSON:
657 /* simply use the string */
658 str = a->value.str;
659 break;
660 }
661
662 if (tree) {
663 /* print into a string */
664 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
665 LY_CHECK_GOTO(ret, cleanup);
666 } else {
667 assert(str);
668 *value_str = strdup(str);
669 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
670 }
671
672 /* success */
673
674cleanup:
675 if (dynamic) {
676 lyd_free_all(tree);
677 }
678 return ret;
679}
680
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100681LIBYANG_API_DEF LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200682lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
683{
684 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200685
Michal Vaskoa820c312021-02-05 16:33:00 +0100686 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200687 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200688
689 t = (struct lyd_node_any *)trg;
690
691 /* free trg */
692 switch (t->value_type) {
693 case LYD_ANYDATA_DATATREE:
694 lyd_free_all(t->value.tree);
695 break;
696 case LYD_ANYDATA_STRING:
697 case LYD_ANYDATA_XML:
698 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100699 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200700 break;
701 case LYD_ANYDATA_LYB:
702 free(t->value.mem);
703 break;
704 }
705 t->value.str = NULL;
706
707 if (!value) {
708 /* only free value in this case */
709 return LY_SUCCESS;
710 }
711
712 /* copy src */
713 t->value_type = value_type;
714 switch (value_type) {
715 case LYD_ANYDATA_DATATREE:
716 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200717 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200718 }
719 break;
720 case LYD_ANYDATA_STRING:
721 case LYD_ANYDATA_XML:
722 case LYD_ANYDATA_JSON:
723 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200724 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200725 }
726 break;
727 case LYD_ANYDATA_LYB:
728 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200729 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200730 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200731 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200732 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200733 memcpy(t->value.mem, value->mem, len);
734 }
735 break;
736 }
737
738 return LY_SUCCESS;
739}
740
Michal Vasko106f0862021-11-02 11:49:27 +0100741const struct lysc_node *
742lyd_node_schema(const struct lyd_node *node)
743{
744 const struct lysc_node *schema = NULL;
745 const struct lyd_node *prev_iter = NULL, *iter;
746 const struct lys_module *mod;
747
748 if (!node) {
749 return NULL;
750 } else if (node->schema) {
751 return node->schema;
752 }
753
754 /* get schema node of an opaque node */
755 do {
756 /* get next data node */
757 for (iter = node; lyd_parent(iter) != prev_iter; iter = lyd_parent(iter)) {}
758
759 /* get equivalent schema node */
760 if (iter->schema) {
761 schema = iter->schema;
762 } else {
763 /* get module */
764 mod = lyd_owner_module(iter);
Michal Vaskoa41826a2021-11-02 12:13:03 +0100765 if (!mod && !schema) {
766 /* top-level opaque node has unknown module */
767 break;
768 }
Michal Vasko106f0862021-11-02 11:49:27 +0100769
770 /* get schema node */
771 schema = lys_find_child(schema, mod ? mod : schema->module, LYD_NAME(iter), 0, 0, 0);
772 }
Michal Vaskod2f404f2021-11-04 15:37:11 +0100773
774 /* remember to move to the descendant */
775 prev_iter = iter;
Michal Vasko106f0862021-11-02 11:49:27 +0100776 } while (schema && (iter != node));
777
778 return schema;
779}
780
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100781void
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100782lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
783{
784 if (*root && (lyd_owner_module(*root) != mod)) {
785 /* there are no data of mod so this is simply the first top-level sibling */
786 mod = NULL;
787 }
788
789 if ((*root != to_del) || (*root)->parent) {
790 return;
791 }
792
Michal Vasko598063b2021-07-19 11:39:05 +0200793 if (mod && (*root)->prev->next && (!(*root)->next || (lyd_owner_module(to_del) != lyd_owner_module((*root)->next)))) {
794 /* there are no more nodes from mod, simply get the first top-level sibling */
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100795 *root = lyd_first_sibling(*root);
Michal Vasko598063b2021-07-19 11:39:05 +0200796 } else {
797 *root = (*root)->next;
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100798 }
799}
800
Michal Vasko8cc3f662022-03-29 11:25:51 +0200801LY_ERR
802ly_nested_ext_schema(const struct lyd_node *parent, const struct lysc_node *sparent, const char *prefix,
803 size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
804 const struct lysc_node **snode, struct lysc_ext_instance **ext)
805{
806 LY_ERR r;
807 LY_ARRAY_COUNT_TYPE u;
808 struct lysc_ext_instance *nested_exts = NULL;
809 lyplg_ext_data_snode_clb ext_snode_cb;
810
811 /* check if there are any nested extension instances */
812 if (parent && parent->schema) {
813 nested_exts = parent->schema->exts;
814 } else if (sparent) {
815 nested_exts = sparent->exts;
816 }
817 LY_ARRAY_FOR(nested_exts, u) {
Michal Vasko305c6cb2022-04-27 10:33:04 +0200818 if (!nested_exts[u].def->plugin) {
819 /* no plugin */
820 continue;
821 }
822
Michal Vasko8cc3f662022-03-29 11:25:51 +0200823 ext_snode_cb = nested_exts[u].def->plugin->snode;
824 if (!ext_snode_cb) {
825 /* not an extension with nested data */
826 continue;
827 }
828
829 /* try to get the schema node */
830 r = ext_snode_cb(&nested_exts[u], parent, sparent, prefix, prefix_len, format, prefix_data, name, name_len, snode);
831 if (!r) {
832 /* data successfully created, remember the ext instance */
833 *ext = &nested_exts[u];
834 return LY_SUCCESS;
835 } else if (r != LY_ENOT) {
836 /* fatal error */
837 return r;
838 }
839 /* data was not from this module, continue */
840 }
841
842 /* no extensions or none matched */
843 return LY_ENOT;
844}
845
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100846void
Radek Krejci8df109d2021-04-23 12:19:08 +0200847ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100848{
849 struct ly_set *ns_list;
850 struct lysc_prefix *prefixes;
851 uint32_t i;
852 LY_ARRAY_COUNT_TYPE u;
853
854 if (!prefix_data) {
855 return;
856 }
857
858 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200859 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +0100860 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100861 ns_list = prefix_data;
862 for (i = 0; i < ns_list->count; ++i) {
863 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
864 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
865 }
866 ly_set_free(ns_list, free);
867 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200868 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100869 prefixes = prefix_data;
870 LY_ARRAY_FOR(prefixes, u) {
871 free(prefixes[u].prefix);
872 }
873 LY_ARRAY_FREE(prefixes);
874 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200875 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200876 case LY_VALUE_SCHEMA:
877 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200878 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100879 break;
880 }
881}
882
883LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +0200884ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100885 void **prefix_data_p)
886{
887 LY_ERR ret = LY_SUCCESS;
888 struct lyxml_ns *ns;
889 struct lysc_prefix *prefixes = NULL, *orig_pref;
890 struct ly_set *ns_list, *orig_ns;
891 uint32_t i;
892 LY_ARRAY_COUNT_TYPE u;
893
894 assert(!*prefix_data_p);
895
896 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200897 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100898 *prefix_data_p = (void *)prefix_data;
899 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200900 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100901 /* copy all the value prefixes */
902 orig_pref = (struct lysc_prefix *)prefix_data;
903 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
904 *prefix_data_p = prefixes;
905
906 LY_ARRAY_FOR(orig_pref, u) {
907 if (orig_pref[u].prefix) {
908 prefixes[u].prefix = strdup(orig_pref[u].prefix);
909 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
910 }
911 prefixes[u].mod = orig_pref[u].mod;
912 LY_ARRAY_INCREMENT(prefixes);
913 }
914 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200915 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +0100916 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100917 /* copy all the namespaces */
918 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
919 *prefix_data_p = ns_list;
920
921 orig_ns = (struct ly_set *)prefix_data;
922 for (i = 0; i < orig_ns->count; ++i) {
923 ns = calloc(1, sizeof *ns);
924 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
925 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
926
927 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
928 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
929 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
930 }
931 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
932 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
933 }
934 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200935 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200936 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200937 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100938 assert(!prefix_data);
939 *prefix_data_p = NULL;
940 break;
941 }
942
943cleanup:
944 if (ret) {
945 ly_free_prefix_data(format, *prefix_data_p);
946 *prefix_data_p = NULL;
947 }
948 return ret;
949}
950
951LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +0200952ly_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 +0200953 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100954{
955 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100956 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100957 const struct lyxml_ns *ns;
958 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100959 struct ly_set *ns_list;
960 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +0200961 const char *value_iter, *value_next, *value_end;
962 uint32_t substr_len;
963 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100964
965 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200966 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100967 /* copy all referenced modules as prefix - module pairs */
968 if (!*prefix_data_p) {
969 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100970 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +0200971 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100972 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100973 } else {
974 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +0200975 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100976 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100977 }
978
Michal Vaskoc0f9c4c2022-05-06 12:12:17 +0200979 /* add current module for unprefixed values */
980 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
981 *prefix_data_p = prefixes;
982
983 val_pref->prefix = NULL;
984 val_pref->mod = ((const struct lysp_module *)prefix_data)->mod;
985
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100986 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +0200987 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +0200988 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +0200989 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 +0200990 if (is_prefix) {
991 /* we have a possible prefix. Do we already have the prefix? */
992 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
993 if (!mod) {
994 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
995 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200996 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +0200997 /* store a new prefix - module pair */
998 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
999 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001000
aPiecek83436bc2021-03-30 12:20:45 +02001001 val_pref->prefix = strndup(value_iter, substr_len);
1002 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1003 val_pref->mod = mod;
1004 } /* else it is not even defined */
1005 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +01001006 }
1007 }
1008 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001009 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001010 case LY_VALUE_STR_NS:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001011 /* copy all referenced namespaces as prefix - namespace pairs */
1012 if (!*prefix_data_p) {
1013 /* new prefix data */
1014 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Michal Vaskoddd76592022-01-17 13:34:48 +01001015 *format_p = format;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001016 *prefix_data_p = ns_list;
1017 } else {
1018 /* reuse prefix data */
Michal Vaskoddd76592022-01-17 13:34:48 +01001019 assert(*format_p == format);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001020 ns_list = *prefix_data_p;
1021 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001022
Michal Vasko294e7f02022-02-28 13:59:00 +01001023 /* store default namespace */
1024 ns = lyxml_ns_get(prefix_data, NULL, 0);
1025 if (ns) {
1026 new_ns = calloc(1, sizeof *new_ns);
1027 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1028 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
1029
1030 new_ns->prefix = NULL;
1031 new_ns->uri = strdup(ns->uri);
1032 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1033 }
1034
Michal Vaskofc2cd072021-02-24 13:17:17 +01001035 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001036 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001037 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001038 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 +02001039 if (is_prefix) {
1040 /* we have a possible prefix. Do we already have the prefix? */
1041 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
1042 if (!ns) {
1043 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
1044 if (ns) {
1045 /* store a new prefix - namespace pair */
1046 new_ns = calloc(1, sizeof *new_ns);
1047 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1048 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001049
aPiecek83436bc2021-03-30 12:20:45 +02001050 new_ns->prefix = strndup(value_iter, substr_len);
1051 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1052 new_ns->uri = strdup(ns->uri);
1053 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1054 } /* else it is not even defined */
1055 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001056 }
1057 }
1058 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001059 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001060 case LY_VALUE_SCHEMA_RESOLVED:
1061 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001062 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001063 if (!*prefix_data_p) {
1064 /* new prefix data - simply copy all the prefix data */
1065 *format_p = format;
1066 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
1067 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001068 break;
1069 }
1070
1071cleanup:
1072 if (ret) {
1073 ly_free_prefix_data(*format_p, *prefix_data_p);
1074 *prefix_data_p = NULL;
1075 }
1076 return ret;
1077}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001078
1079const char *
Radek Krejci8df109d2021-04-23 12:19:08 +02001080ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001081{
1082 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +02001083 case LY_VALUE_CANON:
1084 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +02001085 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001086 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +02001087 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001088 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +02001089 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001090 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +02001091 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001092 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +02001093 case LY_VALUE_LYB:
1094 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001095 default:
1096 break;
1097 }
1098
1099 return NULL;
1100}
Michal Vasko43297a02021-05-19 11:12:37 +02001101
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001102LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001103ly_time_str2time(const char *value, time_t *time, char **fractions_s)
1104{
1105 struct tm tm = {0};
1106 uint32_t i, frac_len;
1107 const char *frac;
1108 int64_t shift, shift_m;
1109 time_t t;
1110
1111 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
1112
1113 tm.tm_year = atoi(&value[0]) - 1900;
1114 tm.tm_mon = atoi(&value[5]) - 1;
1115 tm.tm_mday = atoi(&value[8]);
1116 tm.tm_hour = atoi(&value[11]);
1117 tm.tm_min = atoi(&value[14]);
1118 tm.tm_sec = atoi(&value[17]);
1119
1120 t = timegm(&tm);
1121 i = 19;
1122
1123 /* fractions of a second */
1124 if (value[i] == '.') {
1125 ++i;
1126 frac = &value[i];
1127 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
1128
1129 i += frac_len;
Michal Vasko43297a02021-05-19 11:12:37 +02001130 } else {
1131 frac = NULL;
1132 }
1133
1134 /* apply offset */
1135 if ((value[i] == 'Z') || (value[i] == 'z')) {
1136 /* zero shift */
1137 shift = 0;
1138 } else {
1139 shift = strtol(&value[i], NULL, 10);
1140 shift = shift * 60 * 60; /* convert from hours to seconds */
1141 shift_m = strtol(&value[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
1142 /* correct sign */
1143 if (shift < 0) {
1144 shift_m *= -1;
1145 }
1146 /* connect hours and minutes of the shift */
1147 shift = shift + shift_m;
1148 }
1149
1150 /* we have to shift to the opposite way to correct the time */
1151 t -= shift;
1152
1153 *time = t;
1154 if (fractions_s) {
1155 if (frac) {
1156 *fractions_s = strndup(frac, frac_len);
1157 LY_CHECK_RET(!*fractions_s, LY_EMEM);
1158 } else {
1159 *fractions_s = NULL;
1160 }
1161 }
1162 return LY_SUCCESS;
1163}
1164
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001165LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001166ly_time_time2str(time_t time, const char *fractions_s, char **str)
1167{
1168 struct tm tm;
Michal Vasko143ffa82021-05-20 11:11:39 +02001169 char zoneshift[8];
Michal Vasko43297a02021-05-19 11:12:37 +02001170 int32_t zonediff_h, zonediff_m;
1171
1172 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
1173
1174 /* initialize the local timezone */
1175 tzset();
1176
Jan Kundrátb17efe92022-02-14 18:32:18 +01001177#ifdef HAVE_TM_GMTOFF
Michal Vasko43297a02021-05-19 11:12:37 +02001178 /* convert */
1179 if (!localtime_r(&time, &tm)) {
1180 return LY_ESYS;
1181 }
1182
1183 /* get timezone offset */
1184 if (tm.tm_gmtoff == 0) {
1185 /* time is Zulu (UTC) */
1186 zonediff_h = 0;
1187 zonediff_m = 0;
1188 } else {
1189 /* timezone offset */
1190 zonediff_h = tm.tm_gmtoff / 60 / 60;
1191 zonediff_m = tm.tm_gmtoff / 60 % 60;
1192 }
1193 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
Jan Kundráte182a272021-12-09 23:25:15 +01001194#else
Jan Kundrátb17efe92022-02-14 18:32:18 +01001195 /* convert */
1196 if (!gmtime_r(&time, &tm)) {
1197 return LY_ESYS;
1198 }
1199
Jan Kundráte182a272021-12-09 23:25:15 +01001200 (void)zonediff_h;
1201 (void)zonediff_m;
1202 sprintf(zoneshift, "-00:00");
1203#endif
Michal Vasko43297a02021-05-19 11:12:37 +02001204
1205 /* print */
1206 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
1207 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
1208 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
1209 return LY_EMEM;
1210 }
1211
1212 return LY_SUCCESS;
1213}
1214
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001215LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001216ly_time_str2ts(const char *value, struct timespec *ts)
1217{
1218 LY_ERR rc;
Michal Vasko72975062021-08-25 08:13:04 +02001219 char *fractions_s, frac_buf[10];
Michal Vasko43297a02021-05-19 11:12:37 +02001220 int frac_len;
1221
1222 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
1223
1224 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
1225 LY_CHECK_RET(rc);
1226
1227 /* convert fractions of a second to nanoseconds */
1228 if (fractions_s) {
Michal Vasko72975062021-08-25 08:13:04 +02001229 /* init frac_buf with zeroes */
1230 memset(frac_buf, '0', 9);
1231 frac_buf[9] = '\0';
1232
Michal Vasko43297a02021-05-19 11:12:37 +02001233 frac_len = strlen(fractions_s);
1234 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
1235 ts->tv_nsec = atol(frac_buf);
1236 free(fractions_s);
1237 } else {
1238 ts->tv_nsec = 0;
1239 }
1240
1241 return LY_SUCCESS;
1242}
1243
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001244LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001245ly_time_ts2str(const struct timespec *ts, char **str)
1246{
1247 char frac_buf[10];
1248
Jan Kundrátbd157002021-08-30 14:02:22 +02001249 LY_CHECK_ARG_RET(NULL, ts, str, ((ts->tv_nsec <= 999999999) && (ts->tv_nsec >= 0)), LY_EINVAL);
Michal Vasko43297a02021-05-19 11:12:37 +02001250
1251 /* convert nanoseconds to fractions of a second */
1252 if (ts->tv_nsec) {
1253 sprintf(frac_buf, "%09ld", ts->tv_nsec);
1254 }
1255
1256 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
1257}