blob: 8f087b211b4f6e4e91954ef5d937e0f800b2ac8e [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
Michal Vasko59892dd2022-05-13 11:02:30 +02002 * @file tree_data_common.c
Radek Krejcie7b95092019-05-15 11:03:07 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vasko59892dd2022-05-13 11:02:30 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
5 * @brief Parsing and validation common functions for data trees
Radek Krejcie7b95092019-05-15 11:03:07 +02006 *
Michal Vasko8cc3f662022-03-29 11:25:51 +02007 * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
Radek Krejcie7b95092019-05-15 11:03:07 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
Michal Vasko43297a02021-05-19 11:12:37 +020015
16#define _GNU_SOURCE /* asprintf, strdup */
Radek Krejcie7b95092019-05-15 11:03:07 +020017
18#include <assert.h>
Michal Vasko43297a02021-05-19 11:12:37 +020019#include <ctype.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020022#include <string.h>
Michal Vasko43297a02021-05-19 11:12:37 +020023#include <time.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020024
Radek Krejci535ea9f2020-05-29 16:01:05 +020025#include "common.h"
Michal Vasko6b5cb2a2020-11-11 19:11:21 +010026#include "compat.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020027#include "context.h"
Radek Krejci47fab892020-11-05 17:02:41 +010028#include "dict.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020029#include "hash_table.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020030#include "log.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020031#include "lyb.h"
Radek Krejci7931b192020-06-25 17:05:03 +020032#include "parser_data.h"
Michal Vasko8cc3f662022-03-29 11:25:51 +020033#include "plugins_exts.h"
Michal Vaskoa820c312021-02-05 16:33:00 +010034#include "printer_data.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020035#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020036#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020037#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020038#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010039#include "tree_edit.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020040#include "tree_schema.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020041#include "tree_schema_internal.h"
Radek Krejci4f2e3e52021-03-30 14:20:28 +020042#include "validation.h"
Radek Krejci77114102021-03-10 15:21:57 +010043#include "xml.h"
aPiecekdf23eee2021-10-07 12:21:50 +020044#include "xpath.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020045
Michal Vaskod7c048c2021-05-18 16:12:55 +020046/**
47 * @brief Find an entry in duplicate instance cache for an instance. Create it if it does not exist.
48 *
49 * @param[in] first_inst Instance of the cache entry.
50 * @param[in,out] dup_inst_cache Duplicate instance cache.
51 * @return Instance cache entry.
52 */
53static struct lyd_dup_inst *
54lyd_dup_inst_get(const struct lyd_node *first_inst, struct lyd_dup_inst **dup_inst_cache)
55{
56 struct lyd_dup_inst *item;
57 LY_ARRAY_COUNT_TYPE u;
58
59 LY_ARRAY_FOR(*dup_inst_cache, u) {
60 if ((*dup_inst_cache)[u].inst_set->dnodes[0] == first_inst) {
61 return &(*dup_inst_cache)[u];
62 }
63 }
64
65 /* it was not added yet, add it now */
66 LY_ARRAY_NEW_RET(LYD_CTX(first_inst), *dup_inst_cache, item, NULL);
67
68 return item;
69}
70
71LY_ERR
72lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struct lyd_dup_inst **dup_inst_cache)
73{
74 struct lyd_dup_inst *dup_inst;
75
76 if (!*inst || !lysc_is_dup_inst_list((*inst)->schema)) {
77 /* no match or not dup-inst list, inst is unchanged */
78 return LY_SUCCESS;
79 }
80
81 /* there can be more exact same instances and we must make sure we do not match a single node more times */
82 dup_inst = lyd_dup_inst_get(*inst, dup_inst_cache);
83 LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
84
85 if (!dup_inst->used) {
86 /* we did not cache these instances yet, do so */
87 lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->inst_set);
88 assert(dup_inst->inst_set->count && (dup_inst->inst_set->dnodes[0] == *inst));
89 }
90
91 if (dup_inst->used == dup_inst->inst_set->count) {
92 /* we have used all the instances */
93 *inst = NULL;
94 } else {
95 assert(dup_inst->used < dup_inst->inst_set->count);
96
97 /* use another instance */
98 *inst = dup_inst->inst_set->dnodes[dup_inst->used];
99 ++dup_inst->used;
100 }
101
102 return LY_SUCCESS;
103}
104
105void
106lyd_dup_inst_free(struct lyd_dup_inst *dup_inst)
107{
108 LY_ARRAY_COUNT_TYPE u;
109
110 LY_ARRAY_FOR(dup_inst, u) {
111 ly_set_free(dup_inst[u].inst_set, NULL);
112 }
113 LY_ARRAY_FREE(dup_inst);
114}
115
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200116struct lyd_node *
117lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +0200118 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200119{
120 const struct lysc_node *siter = NULL;
121 struct lyd_node *match = NULL;
122
123 assert(parent || module);
124 assert(!last || (slast && *slast));
125
126 if (slast) {
127 siter = *slast;
128 }
129
130 if (last && last->next && (last->next->schema == siter)) {
131 /* return next data instance */
132 return last->next;
133 }
134
135 /* find next schema node data instance */
136 while ((siter = lys_getnext(siter, parent, module, 0))) {
137 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
138 break;
139 }
140 }
141
142 if (slast) {
143 *slast = siter;
144 }
145 return match;
146}
147
Radek Krejcie7b95092019-05-15 11:03:07 +0200148struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +0100149lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200150{
151 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +0100152
153 if (!node->schema) {
154 return &((struct lyd_node_opaq *)node)->child;
155 } else {
156 switch (node->schema->nodetype) {
157 case LYS_CONTAINER:
158 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +0100159 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100160 case LYS_ACTION:
161 case LYS_NOTIF:
162 return &((struct lyd_node_inner *)node)->child;
163 default:
164 return NULL;
165 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200166 }
167}
168
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100169LIBYANG_API_DEF LY_ERR
aPiecekdf23eee2021-10-07 12:21:50 +0200170lyxp_vars_set(struct lyxp_var **vars, const char *name, const char *value)
171{
172 LY_ERR ret = LY_SUCCESS;
173 char *var_name = NULL, *var_value = NULL;
174 struct lyxp_var *item;
175
176 if (!vars || !name || !value) {
177 return LY_EINVAL;
178 }
179
180 /* If variable is already defined then change its value. */
181 if (*vars && !lyxp_vars_find(*vars, name, 0, &item)) {
182 var_value = strdup(value);
183 LY_CHECK_RET(!var_value, LY_EMEM);
184
185 /* Set new value. */
186 free(item->value);
187 item->value = var_value;
188 } else {
189 var_name = strdup(name);
190 var_value = strdup(value);
191 LY_CHECK_ERR_GOTO(!var_name || !var_value, ret = LY_EMEM, error);
192
193 /* Add new variable. */
194 LY_ARRAY_NEW_GOTO(NULL, *vars, item, ret, error);
195 item->name = var_name;
196 item->value = var_value;
197 }
198
199 return LY_SUCCESS;
200
201error:
202 free(var_name);
203 free(var_value);
204 return ret;
205}
206
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100207LIBYANG_API_DEF void
aPiecekdf23eee2021-10-07 12:21:50 +0200208lyxp_vars_free(struct lyxp_var *vars)
209{
210 LY_ARRAY_COUNT_TYPE u;
211
212 if (!vars) {
213 return;
214 }
215
216 LY_ARRAY_FOR(vars, u) {
217 free(vars[u].name);
218 free(vars[u].value);
219 }
220
221 LY_ARRAY_FREE(vars);
222}
223
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100224LIBYANG_API_DEF struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +0200225lyd_child_no_keys(const struct lyd_node *node)
226{
227 struct lyd_node **children;
228
229 if (!node) {
230 return NULL;
231 }
232
233 if (!node->schema) {
234 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100235 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200236 }
237
Michal Vaskoe0665742021-02-11 11:08:44 +0100238 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200239 if (children) {
240 struct lyd_node *child = *children;
241 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
242 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200243 }
244 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200245 } else {
246 return NULL;
247 }
248}
Michal Vasko9b368d32020-02-14 13:53:31 +0100249
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100250LIBYANG_API_DEF const struct lys_module *
Michal Vaskoc193ce92020-03-06 11:04:48 +0100251lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100252{
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100253 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100254
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100255 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100256 return NULL;
257 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100258
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100259 if (!node->schema) {
260 opaq = (struct lyd_node_opaq *)node;
261 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200262 case LY_VALUE_XML:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100263 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
Radek Krejci8df109d2021-04-23 12:19:08 +0200264 case LY_VALUE_JSON:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100265 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
266 default:
267 return NULL;
268 }
269 }
270
Michal Vaskoef53c812021-10-13 10:21:03 +0200271 return lysc_owner_module(node->schema);
Michal Vasko9b368d32020-02-14 13:53:31 +0100272}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100273
Michal Vasko598063b2021-07-19 11:39:05 +0200274void
275lyd_first_module_sibling(struct lyd_node **node, const struct lys_module *mod)
276{
277 int cmp;
278 struct lyd_node *first;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200279 const struct lys_module *own_mod;
Michal Vasko598063b2021-07-19 11:39:05 +0200280
281 assert(node && mod);
282
283 if (!*node) {
284 return;
285 }
286
287 first = *node;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200288 own_mod = lyd_owner_module(first);
289 cmp = own_mod ? strcmp(own_mod->name, mod->name) : 1;
Michal Vasko598063b2021-07-19 11:39:05 +0200290 if (cmp > 0) {
291 /* there may be some preceding data */
292 while (first->prev->next) {
293 first = first->prev;
294 if (lyd_owner_module(first) == mod) {
295 cmp = 0;
296 break;
297 }
298 }
299 }
300
301 if (cmp == 0) {
302 /* there may be some preceding data belonging to this module */
303 while (first->prev->next) {
304 if (lyd_owner_module(first->prev) != mod) {
305 break;
306 }
307 first = first->prev;
308 }
309 }
310
311 if (cmp < 0) {
312 /* there may be some following data */
313 LY_LIST_FOR(first, first) {
314 if (lyd_owner_module(first) == mod) {
315 cmp = 0;
316 break;
317 }
318 }
319 }
320
321 if (cmp == 0) {
322 /* we have found the first module data node */
323 *node = first;
324 }
325}
326
Michal Vaskob1b5c262020-03-05 14:29:47 +0100327const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200328lyd_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 +0200329 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100330{
331 struct lyd_node *iter;
332 const struct lys_module *mod;
333
334 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200335 if (module) {
336 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100337 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200338 } else {
339 mod = module;
340 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100341 }
342 } else {
343 do {
344 mod = ly_ctx_get_module_iter(ctx, i);
345 } while (mod && !mod->implemented);
346 }
347
348 /* find its data */
349 *first = NULL;
350 if (mod) {
351 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100352 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100353 *first = iter;
354 break;
355 }
356 }
357 }
358
359 return mod;
360}
361
362const struct lys_module *
363lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
364{
365 const struct lys_module *mod;
366
367 if (!*next) {
368 /* all data traversed */
369 *first = NULL;
370 return NULL;
371 }
372
373 *first = *next;
374
375 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100376 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100377 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100378 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100379 break;
380 }
381 }
382
383 return mod;
384}
Michal Vasko9f96a052020-03-10 09:41:45 +0100385
386LY_ERR
Michal Vasko59892dd2022-05-13 11:02:30 +0200387lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct lysc_type *type, const void *value,
388 size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
389 const struct lysc_node *ctx_node, ly_bool *incomplete)
390{
391 LY_ERR ret;
392 struct ly_err_item *err = NULL;
393 uint32_t options = (dynamic && *dynamic ? LYPLG_TYPE_STORE_DYNAMIC : 0);
394
395 if (!value) {
396 value = "";
397 }
398 if (incomplete) {
399 *incomplete = 0;
400 }
401
402 ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data, hints, ctx_node, val, NULL, &err);
403 if (dynamic) {
404 *dynamic = 0;
405 }
406
407 if (ret == LY_EINCOMPLETE) {
408 if (incomplete) {
409 *incomplete = 1;
410 }
411 } else if (ret) {
412 if (err) {
413 LOGVAL_ERRITEM(ctx, err);
414 ly_err_free(err);
415 } else {
416 LOGVAL(ctx, LYVE_OTHER, "Storing value failed.");
417 }
418 return ret;
419 }
420
421 return LY_SUCCESS;
422}
423
424LY_ERR
425lyd_value_validate_incomplete(const struct ly_ctx *ctx, const struct lysc_type *type, struct lyd_value *val,
426 const struct lyd_node *ctx_node, const struct lyd_node *tree)
427{
428 LY_ERR ret;
429 struct ly_err_item *err = NULL;
430
431 assert(type->plugin->validate);
432
433 ret = type->plugin->validate(ctx, type, ctx_node, tree, val, &err);
434 if (ret) {
435 if (err) {
436 LOGVAL_ERRITEM(ctx, err);
437 ly_err_free(err);
438 } else {
439 LOGVAL(ctx, LYVE_OTHER, "Resolving value \"%s\" failed.", type->plugin->print(ctx, val, LY_VALUE_CANON,
440 NULL, NULL, NULL));
441 }
442 return ret;
443 }
444
445 return LY_SUCCESS;
446}
447
448LY_ERR
449lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
450 LY_VALUE_FORMAT format, void *prefix_data)
451{
452 LY_ERR rc = LY_SUCCESS;
453 struct ly_err_item *err = NULL;
454 struct lyd_value storage;
455 struct lysc_type *type;
456
457 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
458
459 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
460 LOGARG(ctx, node);
461 return LY_EINVAL;
462 }
463
464 type = ((struct lysc_node_leaf *)node)->type;
465 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, 0, format, prefix_data,
466 LYD_HINT_SCHEMA, node, &storage, NULL, &err);
467 if (rc == LY_EINCOMPLETE) {
468 /* actually success since we do not provide the context tree and call validation with
469 * LY_TYPE_OPTS_INCOMPLETE_DATA */
470 rc = LY_SUCCESS;
471 } else if (rc && err) {
472 if (ctx) {
473 /* log only in case the ctx was provided as input parameter */
474 LOG_LOCSET(NULL, NULL, err->path, NULL);
475 LOGVAL_ERRITEM(ctx, err);
476 LOG_LOCBACK(0, 0, 1, 0);
477 }
478 ly_err_free(err);
479 }
480
481 if (!rc) {
482 type->plugin->free(ctx ? ctx : node->module->ctx, &storage);
483 }
484 return rc;
485}
486
487LIBYANG_API_DEF LY_ERR
488lyd_value_validate(const struct ly_ctx *ctx, const struct lysc_node *schema, const char *value, size_t value_len,
489 const struct lyd_node *ctx_node, const struct lysc_type **realtype, const char **canonical)
490{
491 LY_ERR rc;
492 struct ly_err_item *err = NULL;
493 struct lysc_type *type;
494 struct lyd_value val = {0};
495 ly_bool stored = 0, log = 1;
496
497 LY_CHECK_ARG_RET(ctx, schema, value, LY_EINVAL);
498
499 if (!ctx) {
500 ctx = schema->module->ctx;
501 log = 0;
502 }
503 type = ((struct lysc_node_leaf *)schema)->type;
504
505 /* store */
506 rc = type->plugin->store(ctx, type, value, value_len, 0, LY_VALUE_JSON, NULL,
507 LYD_HINT_DATA, schema, &val, NULL, &err);
508 if (!rc || (rc == LY_EINCOMPLETE)) {
509 stored = 1;
510 }
511
512 if (ctx_node && (rc == LY_EINCOMPLETE)) {
513 /* resolve */
514 rc = type->plugin->validate(ctx, type, ctx_node, ctx_node, &val, &err);
515 }
516
517 if (rc && (rc != LY_EINCOMPLETE) && err) {
518 if (log) {
519 /* log error */
520 if (err->path) {
521 LOG_LOCSET(NULL, NULL, err->path, NULL);
522 } else if (ctx_node) {
523 LOG_LOCSET(NULL, ctx_node, NULL, NULL);
524 } else {
525 LOG_LOCSET(schema, NULL, NULL, NULL);
526 }
527 LOGVAL_ERRITEM(ctx, err);
528 if (err->path) {
529 LOG_LOCBACK(0, 0, 1, 0);
530 } else if (ctx_node) {
531 LOG_LOCBACK(0, 1, 0, 0);
532 } else {
533 LOG_LOCBACK(1, 0, 0, 0);
534 }
535 }
536 ly_err_free(err);
537 }
538
539 if (!rc || (rc == LY_EINCOMPLETE)) {
540 if (realtype) {
541 /* return realtype */
542 if (val.realtype->basetype == LY_TYPE_UNION) {
543 *realtype = val.subvalue->value.realtype;
544 } else {
545 *realtype = val.realtype;
546 }
547 }
548
549 if (canonical) {
550 /* return canonical value */
551 lydict_insert(ctx, val.realtype->plugin->print(ctx, &val, LY_VALUE_CANON, NULL, NULL, NULL), 0, canonical);
552 }
553 }
554
555 if (stored) {
556 /* free value */
557 type->plugin->free(ctx ? ctx : schema->module->ctx, &val);
558 }
559 return rc;
560}
561
562LIBYANG_API_DEF LY_ERR
563lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len)
564{
565 LY_ERR ret = LY_SUCCESS;
566 struct ly_ctx *ctx;
567 struct lysc_type *type;
568 struct lyd_value val = {0};
569
570 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
571
572 ctx = node->schema->module->ctx;
573 type = ((struct lysc_node_leaf *)node->schema)->type;
574
575 /* store the value */
576 LOG_LOCSET(node->schema, &node->node, NULL, NULL);
577 ret = lyd_value_store(ctx, &val, type, value, value_len, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL);
578 LOG_LOCBACK(1, 1, 0, 0);
579 LY_CHECK_RET(ret);
580
581 /* compare values */
582 ret = type->plugin->compare(&node->value, &val);
583
584 type->plugin->free(ctx, &val);
585 return ret;
586}
587
588LIBYANG_API_DEF ly_bool
589lyd_is_default(const struct lyd_node *node)
590{
591 const struct lysc_node_leaf *leaf;
592 const struct lysc_node_leaflist *llist;
593 const struct lyd_node_term *term;
594 LY_ARRAY_COUNT_TYPE u;
595
596 if (!(node->schema->nodetype & LYD_NODE_TERM)) {
597 return 0;
598 }
599
600 term = (const struct lyd_node_term *)node;
601
602 if (node->schema->nodetype == LYS_LEAF) {
603 leaf = (const struct lysc_node_leaf *)node->schema;
604 if (!leaf->dflt) {
605 return 0;
606 }
607
608 /* compare with the default value */
609 if (!leaf->type->plugin->compare(&term->value, leaf->dflt)) {
610 return 1;
611 }
612 } else {
613 llist = (const struct lysc_node_leaflist *)node->schema;
614 if (!llist->dflts) {
615 return 0;
616 }
617
618 LY_ARRAY_FOR(llist->dflts, u) {
619 /* compare with each possible default value */
620 if (!llist->type->plugin->compare(&term->value, llist->dflts[u])) {
621 return 1;
622 }
623 }
624 }
625
626 return 0;
627}
628
629LIBYANG_API_DEF uint32_t
630lyd_list_pos(const struct lyd_node *instance)
631{
632 const struct lyd_node *iter = NULL;
633 uint32_t pos = 0;
634
635 if (!instance || !(instance->schema->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
636 return 0;
637 }
638
639 /* data instances are ordered, so we can stop when we found instance of other schema node */
640 for (iter = instance; iter->schema == instance->schema; iter = iter->prev) {
641 if (pos && (iter->next == NULL)) {
642 /* overrun to the end of the siblings list */
643 break;
644 }
645 ++pos;
646 }
647
648 return pos;
649}
650
651LIBYANG_API_DEF struct lyd_node *
652lyd_first_sibling(const struct lyd_node *node)
653{
654 struct lyd_node *start;
655
656 if (!node) {
657 return NULL;
658 }
659
660 /* get the first sibling */
661 if (node->parent) {
662 start = node->parent->child;
663 } else {
664 for (start = (struct lyd_node *)node; start->prev->next; start = start->prev) {}
665 }
666
667 return start;
668}
669
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100670/**
671 * @brief Check list node parsed into an opaque node for the reason.
672 *
673 * @param[in] node Opaque node.
674 * @param[in] snode Schema node of @p opaq.
675 * @return LY_SUCCESS if the node is valid;
676 * @return LY_ERR on error.
677 */
678static LY_ERR
679lyd_parse_opaq_list_error(const struct lyd_node *node, const struct lysc_node *snode)
680{
681 LY_ERR ret = LY_SUCCESS;
682 struct ly_set key_set = {0};
683 const struct lysc_node *key = NULL;
684 const struct lyd_node *child;
685 const struct lyd_node_opaq *opaq_k;
686 uint32_t i;
687
688 assert(!node->schema);
689
690 /* get all keys into a set */
691 while ((key = lys_getnext(key, snode, NULL, 0)) && (snode->flags & LYS_KEY)) {
692 LY_CHECK_GOTO(ret = ly_set_add(&key_set, (void *)snode, 1, NULL), cleanup);
693 }
694
695 LY_LIST_FOR(lyd_child(node), child) {
696 if (child->schema) {
697 LOGERR(LYD_CTX(node), LY_EINVAL, "Unexpected node %s \"%s\".", lys_nodetype2str(child->schema->nodetype),
698 LYD_NAME(child));
699 ret = LY_EINVAL;
700 goto cleanup;
701 }
702
703 opaq_k = (struct lyd_node_opaq *)child;
704
705 /* find the key schema node */
706 for (i = 0; i < key_set.count; ++i) {
707 key = key_set.snodes[i];
708 if (!strcmp(key->name, opaq_k->name.name)) {
709 break;
710 }
711 }
712 if (i == key_set.count) {
713 /* some other node, skip */
714 continue;
715 }
716
717 /* key found */
718 ly_set_rm_index(&key_set, i, NULL);
719
720 /* check value */
721 ret = lys_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
722 opaq_k->val_prefix_data);
723 LY_CHECK_GOTO(ret, cleanup);
724 }
725
726 if (key_set.count) {
727 /* missing keys */
728 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, key_set.snodes[0]->name);
729 ret = LY_EVALID;
730 goto cleanup;
731 }
732
733cleanup:
734 ly_set_erase(&key_set, NULL);
735 return ret;
736}
737
738LIBYANG_API_DEF LY_ERR
739lyd_parse_opaq_error(const struct lyd_node *node)
740{
741 const struct ly_ctx *ctx;
742 const struct lyd_node_opaq *opaq;
743 const struct lyd_node *parent;
744 const struct lys_module *mod;
745 const struct lysc_node *snode;
746
747 LY_CHECK_ARG_RET(LYD_CTX(node), node, !node->schema, !lyd_parent(node) || lyd_parent(node)->schema, LY_EINVAL);
748
749 ctx = LYD_CTX(node);
750 opaq = (struct lyd_node_opaq *)node;
751 parent = lyd_parent(node);
752
Michal Vaskof4e63922022-05-10 10:32:13 +0200753 if (!opaq->name.module_ns) {
754 LOGVAL(ctx, LYVE_REFERENCE, "Unknown module of node \"%s\".", opaq->name.name);
755 return LY_EVALID;
756 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100757
758 /* module */
759 switch (opaq->format) {
760 case LY_VALUE_XML:
761 if (!parent || strcmp(opaq->name.module_ns, parent->schema->module->ns)) {
762 mod = ly_ctx_get_module_implemented_ns(ctx, opaq->name.module_ns);
763 if (!mod) {
764 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module with namespace \"%s\" in the context.",
765 opaq->name.module_ns);
766 return LY_EVALID;
767 }
768 } else {
769 /* inherit */
770 mod = parent->schema->module;
771 }
772 break;
773 case LY_VALUE_JSON:
774 case LY_VALUE_LYB:
775 if (!parent || strcmp(opaq->name.module_name, parent->schema->module->name)) {
776 mod = ly_ctx_get_module_implemented(ctx, opaq->name.module_name);
777 if (!mod) {
778 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module named \"%s\" in the context.", opaq->name.module_name);
779 return LY_EVALID;
780 }
781 } else {
782 /* inherit */
783 mod = parent->schema->module;
784 }
785 break;
786 default:
787 LOGERR(ctx, LY_EINVAL, "Unsupported value format.");
788 return LY_EINVAL;
789 }
790
791 /* schema */
792 snode = lys_find_child(parent ? parent->schema : NULL, mod, opaq->name.name, 0, 0, 0);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200793 if (!snode && parent && parent->schema && (parent->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
794 /* maybe output node */
Michal Vasko89afc6e2022-05-02 10:24:26 +0200795 snode = lys_find_child(parent->schema, mod, opaq->name.name, 0, 0, LYS_GETNEXT_OUTPUT);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200796 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100797 if (!snode) {
798 if (parent) {
799 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found as a child of \"%s\" node.", opaq->name.name,
800 LYD_NAME(parent));
801 } else {
802 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found in the \"%s\" module.", opaq->name.name, mod->name);
803 }
804 return LY_EVALID;
805 }
806
807 if (snode->nodetype & LYD_NODE_TERM) {
808 /* leaf / leaf-list */
809 LY_CHECK_RET(lys_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data));
810 } else if (snode->nodetype == LYS_LIST) {
811 /* list */
812 LY_CHECK_RET(lyd_parse_opaq_list_error(node, snode));
813 } else if (snode->nodetype & LYD_NODE_INNER) {
814 /* inner node */
815 if (opaq->value) {
816 LOGVAL(ctx, LYVE_DATA, "Invalid value \"%s\" for %s \"%s\".", opaq->value,
817 lys_nodetype2str(snode->nodetype), snode->name);
818 return LY_EVALID;
819 }
820 } else {
821 LOGERR(ctx, LY_EINVAL, "Unexpected opaque schema node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
822 return LY_EINVAL;
823 }
824
825 LOGERR(ctx, LY_EINVAL, "Unexpected valid opaque node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
826 return LY_EINVAL;
827}
828
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100829LIBYANG_API_DEF const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400830lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200831{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200832 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
833
Michal Vasko33876022021-04-27 16:42:24 +0200834 return value->_canonical ? value->_canonical :
835 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200836}
837
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100838LIBYANG_API_DEF LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100839lyd_any_value_str(const struct lyd_node *any, char **value_str)
840{
841 const struct lyd_node_any *a;
842 struct lyd_node *tree = NULL;
843 const char *str = NULL;
844 ly_bool dynamic = 0;
845 LY_ERR ret = LY_SUCCESS;
846
847 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200848 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100849
850 a = (struct lyd_node_any *)any;
851 *value_str = NULL;
852
853 if (!a->value.str) {
854 /* there is no value in the union */
855 return LY_SUCCESS;
856 }
857
858 switch (a->value_type) {
859 case LYD_ANYDATA_LYB:
860 /* parse into a data tree */
861 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
862 LY_CHECK_GOTO(ret, cleanup);
863 dynamic = 1;
864 break;
865 case LYD_ANYDATA_DATATREE:
866 tree = a->value.tree;
867 break;
868 case LYD_ANYDATA_STRING:
869 case LYD_ANYDATA_XML:
870 case LYD_ANYDATA_JSON:
871 /* simply use the string */
872 str = a->value.str;
873 break;
874 }
875
876 if (tree) {
877 /* print into a string */
878 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
879 LY_CHECK_GOTO(ret, cleanup);
880 } else {
881 assert(str);
882 *value_str = strdup(str);
883 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
884 }
885
886 /* success */
887
888cleanup:
889 if (dynamic) {
890 lyd_free_all(tree);
891 }
892 return ret;
893}
894
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100895LIBYANG_API_DEF LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200896lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
897{
898 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200899
Michal Vaskoa820c312021-02-05 16:33:00 +0100900 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200901 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200902
903 t = (struct lyd_node_any *)trg;
904
905 /* free trg */
906 switch (t->value_type) {
907 case LYD_ANYDATA_DATATREE:
908 lyd_free_all(t->value.tree);
909 break;
910 case LYD_ANYDATA_STRING:
911 case LYD_ANYDATA_XML:
912 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100913 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200914 break;
915 case LYD_ANYDATA_LYB:
916 free(t->value.mem);
917 break;
918 }
919 t->value.str = NULL;
920
921 if (!value) {
922 /* only free value in this case */
923 return LY_SUCCESS;
924 }
925
926 /* copy src */
927 t->value_type = value_type;
928 switch (value_type) {
929 case LYD_ANYDATA_DATATREE:
930 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200931 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200932 }
933 break;
934 case LYD_ANYDATA_STRING:
935 case LYD_ANYDATA_XML:
936 case LYD_ANYDATA_JSON:
937 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200938 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200939 }
940 break;
941 case LYD_ANYDATA_LYB:
942 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200943 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200944 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200945 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200946 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200947 memcpy(t->value.mem, value->mem, len);
948 }
949 break;
950 }
951
952 return LY_SUCCESS;
953}
954
Michal Vasko106f0862021-11-02 11:49:27 +0100955const struct lysc_node *
956lyd_node_schema(const struct lyd_node *node)
957{
958 const struct lysc_node *schema = NULL;
959 const struct lyd_node *prev_iter = NULL, *iter;
960 const struct lys_module *mod;
961
962 if (!node) {
963 return NULL;
964 } else if (node->schema) {
965 return node->schema;
966 }
967
968 /* get schema node of an opaque node */
969 do {
970 /* get next data node */
971 for (iter = node; lyd_parent(iter) != prev_iter; iter = lyd_parent(iter)) {}
972
973 /* get equivalent schema node */
974 if (iter->schema) {
975 schema = iter->schema;
976 } else {
977 /* get module */
978 mod = lyd_owner_module(iter);
Michal Vaskoa41826a2021-11-02 12:13:03 +0100979 if (!mod && !schema) {
980 /* top-level opaque node has unknown module */
981 break;
982 }
Michal Vasko106f0862021-11-02 11:49:27 +0100983
984 /* get schema node */
985 schema = lys_find_child(schema, mod ? mod : schema->module, LYD_NAME(iter), 0, 0, 0);
986 }
Michal Vaskod2f404f2021-11-04 15:37:11 +0100987
988 /* remember to move to the descendant */
989 prev_iter = iter;
Michal Vasko106f0862021-11-02 11:49:27 +0100990 } while (schema && (iter != node));
991
992 return schema;
993}
994
Michal Vasko59892dd2022-05-13 11:02:30 +0200995/**
996 * @brief Comparison callback to match schema node with a schema of a data node.
997 *
998 * @param[in] val1_p Pointer to the schema node
999 * @param[in] val2_p Pointer to the data node
1000 * Implementation of ::lyht_value_equal_cb.
1001 */
1002static ly_bool
1003lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
1004{
1005 struct lysc_node *val1;
1006 struct lyd_node *val2;
1007
1008 val1 = *((struct lysc_node **)val1_p);
1009 val2 = *((struct lyd_node **)val2_p);
1010
1011 if (val1 == val2->schema) {
1012 /* schema match is enough */
1013 return 1;
1014 } else {
1015 return 0;
1016 }
1017}
1018
1019LY_ERR
1020lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
1021{
1022 struct lyd_node **match_p;
1023 struct lyd_node_inner *parent;
1024 uint32_t hash;
1025 lyht_value_equal_cb ht_cb;
1026
1027 assert(siblings && schema);
1028
1029 parent = siblings->parent;
1030 if (parent && parent->schema && parent->children_ht) {
1031 /* calculate our hash */
1032 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
1033 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
1034 hash = dict_hash_multi(hash, NULL, 0);
1035
1036 /* use special hash table function */
1037 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
1038
1039 /* find by hash */
1040 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
1041 siblings = *match_p;
1042 } else {
1043 /* not found */
1044 siblings = NULL;
1045 }
1046
1047 /* set the original hash table compare function back */
1048 lyht_set_cb(parent->children_ht, ht_cb);
1049 } else {
1050 /* find first sibling */
1051 if (siblings->parent) {
1052 siblings = siblings->parent->child;
1053 } else {
1054 while (siblings->prev->next) {
1055 siblings = siblings->prev;
1056 }
1057 }
1058
1059 /* search manually without hashes */
1060 for ( ; siblings; siblings = siblings->next) {
1061 if (siblings->schema == schema) {
1062 /* schema match is enough */
1063 break;
1064 }
1065 }
1066 }
1067
1068 if (!siblings) {
1069 if (match) {
1070 *match = NULL;
1071 }
1072 return LY_ENOTFOUND;
1073 }
1074
1075 if (match) {
1076 *match = (struct lyd_node *)siblings;
1077 }
1078 return LY_SUCCESS;
1079}
1080
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001081void
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001082lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
1083{
1084 if (*root && (lyd_owner_module(*root) != mod)) {
1085 /* there are no data of mod so this is simply the first top-level sibling */
1086 mod = NULL;
1087 }
1088
1089 if ((*root != to_del) || (*root)->parent) {
1090 return;
1091 }
1092
Michal Vasko598063b2021-07-19 11:39:05 +02001093 if (mod && (*root)->prev->next && (!(*root)->next || (lyd_owner_module(to_del) != lyd_owner_module((*root)->next)))) {
1094 /* there are no more nodes from mod, simply get the first top-level sibling */
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001095 *root = lyd_first_sibling(*root);
Michal Vasko598063b2021-07-19 11:39:05 +02001096 } else {
1097 *root = (*root)->next;
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001098 }
1099}
1100
Michal Vasko8cc3f662022-03-29 11:25:51 +02001101LY_ERR
1102ly_nested_ext_schema(const struct lyd_node *parent, const struct lysc_node *sparent, const char *prefix,
1103 size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
1104 const struct lysc_node **snode, struct lysc_ext_instance **ext)
1105{
1106 LY_ERR r;
1107 LY_ARRAY_COUNT_TYPE u;
1108 struct lysc_ext_instance *nested_exts = NULL;
1109 lyplg_ext_data_snode_clb ext_snode_cb;
1110
1111 /* check if there are any nested extension instances */
1112 if (parent && parent->schema) {
1113 nested_exts = parent->schema->exts;
1114 } else if (sparent) {
1115 nested_exts = sparent->exts;
1116 }
1117 LY_ARRAY_FOR(nested_exts, u) {
Michal Vasko305c6cb2022-04-27 10:33:04 +02001118 if (!nested_exts[u].def->plugin) {
1119 /* no plugin */
1120 continue;
1121 }
1122
Michal Vasko8cc3f662022-03-29 11:25:51 +02001123 ext_snode_cb = nested_exts[u].def->plugin->snode;
1124 if (!ext_snode_cb) {
1125 /* not an extension with nested data */
1126 continue;
1127 }
1128
1129 /* try to get the schema node */
1130 r = ext_snode_cb(&nested_exts[u], parent, sparent, prefix, prefix_len, format, prefix_data, name, name_len, snode);
1131 if (!r) {
1132 /* data successfully created, remember the ext instance */
1133 *ext = &nested_exts[u];
1134 return LY_SUCCESS;
1135 } else if (r != LY_ENOT) {
1136 /* fatal error */
1137 return r;
1138 }
1139 /* data was not from this module, continue */
1140 }
1141
1142 /* no extensions or none matched */
1143 return LY_ENOT;
1144}
1145
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001146void
Radek Krejci8df109d2021-04-23 12:19:08 +02001147ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001148{
1149 struct ly_set *ns_list;
1150 struct lysc_prefix *prefixes;
1151 uint32_t i;
1152 LY_ARRAY_COUNT_TYPE u;
1153
1154 if (!prefix_data) {
1155 return;
1156 }
1157
1158 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001159 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001160 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001161 ns_list = prefix_data;
1162 for (i = 0; i < ns_list->count; ++i) {
1163 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
1164 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
1165 }
1166 ly_set_free(ns_list, free);
1167 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001168 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001169 prefixes = prefix_data;
1170 LY_ARRAY_FOR(prefixes, u) {
1171 free(prefixes[u].prefix);
1172 }
1173 LY_ARRAY_FREE(prefixes);
1174 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001175 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001176 case LY_VALUE_SCHEMA:
1177 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001178 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001179 break;
1180 }
1181}
1182
1183LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +02001184ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001185 void **prefix_data_p)
1186{
1187 LY_ERR ret = LY_SUCCESS;
1188 struct lyxml_ns *ns;
1189 struct lysc_prefix *prefixes = NULL, *orig_pref;
1190 struct ly_set *ns_list, *orig_ns;
1191 uint32_t i;
1192 LY_ARRAY_COUNT_TYPE u;
1193
1194 assert(!*prefix_data_p);
1195
1196 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001197 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001198 *prefix_data_p = (void *)prefix_data;
1199 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001200 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001201 /* copy all the value prefixes */
1202 orig_pref = (struct lysc_prefix *)prefix_data;
1203 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
1204 *prefix_data_p = prefixes;
1205
1206 LY_ARRAY_FOR(orig_pref, u) {
1207 if (orig_pref[u].prefix) {
1208 prefixes[u].prefix = strdup(orig_pref[u].prefix);
1209 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1210 }
1211 prefixes[u].mod = orig_pref[u].mod;
1212 LY_ARRAY_INCREMENT(prefixes);
1213 }
1214 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001215 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001216 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001217 /* copy all the namespaces */
1218 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
1219 *prefix_data_p = ns_list;
1220
1221 orig_ns = (struct ly_set *)prefix_data;
1222 for (i = 0; i < orig_ns->count; ++i) {
1223 ns = calloc(1, sizeof *ns);
1224 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1225 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
1226
1227 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
1228 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
1229 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1230 }
1231 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
1232 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1233 }
1234 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001235 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001236 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001237 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001238 assert(!prefix_data);
1239 *prefix_data_p = NULL;
1240 break;
1241 }
1242
1243cleanup:
1244 if (ret) {
1245 ly_free_prefix_data(format, *prefix_data_p);
1246 *prefix_data_p = NULL;
1247 }
1248 return ret;
1249}
1250
1251LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +02001252ly_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 +02001253 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001254{
1255 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001256 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001257 const struct lyxml_ns *ns;
1258 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001259 struct ly_set *ns_list;
1260 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +02001261 const char *value_iter, *value_next, *value_end;
1262 uint32_t substr_len;
1263 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001264
1265 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001266 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001267 /* copy all referenced modules as prefix - module pairs */
1268 if (!*prefix_data_p) {
1269 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001270 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +02001271 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001272 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001273 } else {
1274 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +02001275 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001276 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001277 }
1278
Michal Vaskoc0f9c4c2022-05-06 12:12:17 +02001279 /* add current module for unprefixed values */
1280 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1281 *prefix_data_p = prefixes;
1282
1283 val_pref->prefix = NULL;
1284 val_pref->mod = ((const struct lysp_module *)prefix_data)->mod;
1285
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001286 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001287 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001288 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001289 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 +02001290 if (is_prefix) {
1291 /* we have a possible prefix. Do we already have the prefix? */
1292 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
1293 if (!mod) {
1294 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
1295 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001296 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +02001297 /* store a new prefix - module pair */
1298 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1299 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001300
aPiecek83436bc2021-03-30 12:20:45 +02001301 val_pref->prefix = strndup(value_iter, substr_len);
1302 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1303 val_pref->mod = mod;
1304 } /* else it is not even defined */
1305 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +01001306 }
1307 }
1308 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001309 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001310 case LY_VALUE_STR_NS:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001311 /* copy all referenced namespaces as prefix - namespace pairs */
1312 if (!*prefix_data_p) {
1313 /* new prefix data */
1314 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Michal Vaskoddd76592022-01-17 13:34:48 +01001315 *format_p = format;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001316 *prefix_data_p = ns_list;
1317 } else {
1318 /* reuse prefix data */
Michal Vaskoddd76592022-01-17 13:34:48 +01001319 assert(*format_p == format);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001320 ns_list = *prefix_data_p;
1321 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001322
Michal Vasko294e7f02022-02-28 13:59:00 +01001323 /* store default namespace */
1324 ns = lyxml_ns_get(prefix_data, NULL, 0);
1325 if (ns) {
1326 new_ns = calloc(1, sizeof *new_ns);
1327 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1328 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
1329
1330 new_ns->prefix = NULL;
1331 new_ns->uri = strdup(ns->uri);
1332 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1333 }
1334
Michal Vaskofc2cd072021-02-24 13:17:17 +01001335 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001336 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001337 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001338 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 +02001339 if (is_prefix) {
1340 /* we have a possible prefix. Do we already have the prefix? */
1341 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
1342 if (!ns) {
1343 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
1344 if (ns) {
1345 /* store a new prefix - namespace pair */
1346 new_ns = calloc(1, sizeof *new_ns);
1347 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1348 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001349
aPiecek83436bc2021-03-30 12:20:45 +02001350 new_ns->prefix = strndup(value_iter, substr_len);
1351 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1352 new_ns->uri = strdup(ns->uri);
1353 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1354 } /* else it is not even defined */
1355 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001356 }
1357 }
1358 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001359 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001360 case LY_VALUE_SCHEMA_RESOLVED:
1361 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001362 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001363 if (!*prefix_data_p) {
1364 /* new prefix data - simply copy all the prefix data */
1365 *format_p = format;
1366 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
1367 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001368 break;
1369 }
1370
1371cleanup:
1372 if (ret) {
1373 ly_free_prefix_data(*format_p, *prefix_data_p);
1374 *prefix_data_p = NULL;
1375 }
1376 return ret;
1377}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001378
1379const char *
Radek Krejci8df109d2021-04-23 12:19:08 +02001380ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001381{
1382 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +02001383 case LY_VALUE_CANON:
1384 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +02001385 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001386 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +02001387 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001388 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +02001389 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001390 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +02001391 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001392 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +02001393 case LY_VALUE_LYB:
1394 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001395 default:
1396 break;
1397 }
1398
1399 return NULL;
1400}
Michal Vasko43297a02021-05-19 11:12:37 +02001401
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001402LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001403ly_time_str2time(const char *value, time_t *time, char **fractions_s)
1404{
1405 struct tm tm = {0};
1406 uint32_t i, frac_len;
1407 const char *frac;
1408 int64_t shift, shift_m;
1409 time_t t;
1410
1411 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
1412
1413 tm.tm_year = atoi(&value[0]) - 1900;
1414 tm.tm_mon = atoi(&value[5]) - 1;
1415 tm.tm_mday = atoi(&value[8]);
1416 tm.tm_hour = atoi(&value[11]);
1417 tm.tm_min = atoi(&value[14]);
1418 tm.tm_sec = atoi(&value[17]);
1419
1420 t = timegm(&tm);
1421 i = 19;
1422
1423 /* fractions of a second */
1424 if (value[i] == '.') {
1425 ++i;
1426 frac = &value[i];
1427 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
1428
1429 i += frac_len;
Michal Vasko43297a02021-05-19 11:12:37 +02001430 } else {
1431 frac = NULL;
1432 }
1433
1434 /* apply offset */
1435 if ((value[i] == 'Z') || (value[i] == 'z')) {
1436 /* zero shift */
1437 shift = 0;
1438 } else {
1439 shift = strtol(&value[i], NULL, 10);
1440 shift = shift * 60 * 60; /* convert from hours to seconds */
1441 shift_m = strtol(&value[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
1442 /* correct sign */
1443 if (shift < 0) {
1444 shift_m *= -1;
1445 }
1446 /* connect hours and minutes of the shift */
1447 shift = shift + shift_m;
1448 }
1449
1450 /* we have to shift to the opposite way to correct the time */
1451 t -= shift;
1452
1453 *time = t;
1454 if (fractions_s) {
1455 if (frac) {
1456 *fractions_s = strndup(frac, frac_len);
1457 LY_CHECK_RET(!*fractions_s, LY_EMEM);
1458 } else {
1459 *fractions_s = NULL;
1460 }
1461 }
1462 return LY_SUCCESS;
1463}
1464
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001465LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001466ly_time_time2str(time_t time, const char *fractions_s, char **str)
1467{
1468 struct tm tm;
Michal Vasko143ffa82021-05-20 11:11:39 +02001469 char zoneshift[8];
Michal Vasko43297a02021-05-19 11:12:37 +02001470 int32_t zonediff_h, zonediff_m;
1471
1472 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
1473
1474 /* initialize the local timezone */
1475 tzset();
1476
Jan Kundrátb17efe92022-02-14 18:32:18 +01001477#ifdef HAVE_TM_GMTOFF
Michal Vasko43297a02021-05-19 11:12:37 +02001478 /* convert */
1479 if (!localtime_r(&time, &tm)) {
1480 return LY_ESYS;
1481 }
1482
1483 /* get timezone offset */
1484 if (tm.tm_gmtoff == 0) {
1485 /* time is Zulu (UTC) */
1486 zonediff_h = 0;
1487 zonediff_m = 0;
1488 } else {
1489 /* timezone offset */
1490 zonediff_h = tm.tm_gmtoff / 60 / 60;
1491 zonediff_m = tm.tm_gmtoff / 60 % 60;
1492 }
1493 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
Jan Kundráte182a272021-12-09 23:25:15 +01001494#else
Jan Kundrátb17efe92022-02-14 18:32:18 +01001495 /* convert */
1496 if (!gmtime_r(&time, &tm)) {
1497 return LY_ESYS;
1498 }
1499
Jan Kundráte182a272021-12-09 23:25:15 +01001500 (void)zonediff_h;
1501 (void)zonediff_m;
1502 sprintf(zoneshift, "-00:00");
1503#endif
Michal Vasko43297a02021-05-19 11:12:37 +02001504
1505 /* print */
1506 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
1507 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
1508 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
1509 return LY_EMEM;
1510 }
1511
1512 return LY_SUCCESS;
1513}
1514
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001515LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001516ly_time_str2ts(const char *value, struct timespec *ts)
1517{
1518 LY_ERR rc;
Michal Vasko72975062021-08-25 08:13:04 +02001519 char *fractions_s, frac_buf[10];
Michal Vasko43297a02021-05-19 11:12:37 +02001520 int frac_len;
1521
1522 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
1523
1524 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
1525 LY_CHECK_RET(rc);
1526
1527 /* convert fractions of a second to nanoseconds */
1528 if (fractions_s) {
Michal Vasko72975062021-08-25 08:13:04 +02001529 /* init frac_buf with zeroes */
1530 memset(frac_buf, '0', 9);
1531 frac_buf[9] = '\0';
1532
Michal Vasko43297a02021-05-19 11:12:37 +02001533 frac_len = strlen(fractions_s);
1534 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
1535 ts->tv_nsec = atol(frac_buf);
1536 free(fractions_s);
1537 } else {
1538 ts->tv_nsec = 0;
1539 }
1540
1541 return LY_SUCCESS;
1542}
1543
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001544LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001545ly_time_ts2str(const struct timespec *ts, char **str)
1546{
1547 char frac_buf[10];
1548
Jan Kundrátbd157002021-08-30 14:02:22 +02001549 LY_CHECK_ARG_RET(NULL, ts, str, ((ts->tv_nsec <= 999999999) && (ts->tv_nsec >= 0)), LY_EINVAL);
Michal Vasko43297a02021-05-19 11:12:37 +02001550
1551 /* convert nanoseconds to fractions of a second */
1552 if (ts->tv_nsec) {
1553 sprintf(frac_buf, "%09ld", ts->tv_nsec);
1554 }
1555
1556 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
1557}