blob: 7fd458209fe8cf4cd919a18150870f35390c7891 [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 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
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 Vaskoa820c312021-02-05 16:33:00 +010032#include "printer_data.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020033#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020034#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020035#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020036#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010037#include "tree_edit.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020038#include "tree_schema.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020039#include "tree_schema_internal.h"
Radek Krejci4f2e3e52021-03-30 14:20:28 +020040#include "validation.h"
Radek Krejci77114102021-03-10 15:21:57 +010041#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020042
Michal Vaskod7c048c2021-05-18 16:12:55 +020043/**
44 * @brief Find an entry in duplicate instance cache for an instance. Create it if it does not exist.
45 *
46 * @param[in] first_inst Instance of the cache entry.
47 * @param[in,out] dup_inst_cache Duplicate instance cache.
48 * @return Instance cache entry.
49 */
50static struct lyd_dup_inst *
51lyd_dup_inst_get(const struct lyd_node *first_inst, struct lyd_dup_inst **dup_inst_cache)
52{
53 struct lyd_dup_inst *item;
54 LY_ARRAY_COUNT_TYPE u;
55
56 LY_ARRAY_FOR(*dup_inst_cache, u) {
57 if ((*dup_inst_cache)[u].inst_set->dnodes[0] == first_inst) {
58 return &(*dup_inst_cache)[u];
59 }
60 }
61
62 /* it was not added yet, add it now */
63 LY_ARRAY_NEW_RET(LYD_CTX(first_inst), *dup_inst_cache, item, NULL);
64
65 return item;
66}
67
68LY_ERR
69lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struct lyd_dup_inst **dup_inst_cache)
70{
71 struct lyd_dup_inst *dup_inst;
72
73 if (!*inst || !lysc_is_dup_inst_list((*inst)->schema)) {
74 /* no match or not dup-inst list, inst is unchanged */
75 return LY_SUCCESS;
76 }
77
78 /* there can be more exact same instances and we must make sure we do not match a single node more times */
79 dup_inst = lyd_dup_inst_get(*inst, dup_inst_cache);
80 LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
81
82 if (!dup_inst->used) {
83 /* we did not cache these instances yet, do so */
84 lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->inst_set);
85 assert(dup_inst->inst_set->count && (dup_inst->inst_set->dnodes[0] == *inst));
86 }
87
88 if (dup_inst->used == dup_inst->inst_set->count) {
89 /* we have used all the instances */
90 *inst = NULL;
91 } else {
92 assert(dup_inst->used < dup_inst->inst_set->count);
93
94 /* use another instance */
95 *inst = dup_inst->inst_set->dnodes[dup_inst->used];
96 ++dup_inst->used;
97 }
98
99 return LY_SUCCESS;
100}
101
102void
103lyd_dup_inst_free(struct lyd_dup_inst *dup_inst)
104{
105 LY_ARRAY_COUNT_TYPE u;
106
107 LY_ARRAY_FOR(dup_inst, u) {
108 ly_set_free(dup_inst[u].inst_set, NULL);
109 }
110 LY_ARRAY_FREE(dup_inst);
111}
112
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200113struct lyd_node *
114lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +0200115 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200116{
117 const struct lysc_node *siter = NULL;
118 struct lyd_node *match = NULL;
119
120 assert(parent || module);
121 assert(!last || (slast && *slast));
122
123 if (slast) {
124 siter = *slast;
125 }
126
127 if (last && last->next && (last->next->schema == siter)) {
128 /* return next data instance */
129 return last->next;
130 }
131
132 /* find next schema node data instance */
133 while ((siter = lys_getnext(siter, parent, module, 0))) {
134 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
135 break;
136 }
137 }
138
139 if (slast) {
140 *slast = siter;
141 }
142 return match;
143}
144
Radek Krejcie7b95092019-05-15 11:03:07 +0200145struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +0100146lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200147{
148 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +0100149
150 if (!node->schema) {
151 return &((struct lyd_node_opaq *)node)->child;
152 } else {
153 switch (node->schema->nodetype) {
154 case LYS_CONTAINER:
155 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +0100156 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100157 case LYS_ACTION:
158 case LYS_NOTIF:
159 return &((struct lyd_node_inner *)node)->child;
160 default:
161 return NULL;
162 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200163 }
164}
165
Radek Krejcidae0ee82020-05-06 16:53:24 +0200166API struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +0200167lyd_child_no_keys(const struct lyd_node *node)
168{
169 struct lyd_node **children;
170
171 if (!node) {
172 return NULL;
173 }
174
175 if (!node->schema) {
176 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100177 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200178 }
179
Michal Vaskoe0665742021-02-11 11:08:44 +0100180 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200181 if (children) {
182 struct lyd_node *child = *children;
183 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
184 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200185 }
186 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200187 } else {
188 return NULL;
189 }
190}
Michal Vasko9b368d32020-02-14 13:53:31 +0100191
Michal Vaskoc193ce92020-03-06 11:04:48 +0100192API const struct lys_module *
193lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100194{
195 const struct lysc_node *schema;
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100196 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100197
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100198 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100199 return NULL;
200 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100201
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100202 if (!node->schema) {
203 opaq = (struct lyd_node_opaq *)node;
204 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200205 case LY_VALUE_XML:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100206 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
Radek Krejci8df109d2021-04-23 12:19:08 +0200207 case LY_VALUE_JSON:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100208 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
209 default:
210 return NULL;
211 }
212 }
213
Radek Krejci1e008d22020-08-17 11:37:37 +0200214 for (schema = node->schema; schema->parent; schema = schema->parent) {}
Michal Vasko9b368d32020-02-14 13:53:31 +0100215 return schema->module;
216}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100217
Michal Vasko598063b2021-07-19 11:39:05 +0200218void
219lyd_first_module_sibling(struct lyd_node **node, const struct lys_module *mod)
220{
221 int cmp;
222 struct lyd_node *first;
223
224 assert(node && mod);
225
226 if (!*node) {
227 return;
228 }
229
230 first = *node;
231 cmp = strcmp(lyd_owner_module(first)->name, mod->name);
232 if (cmp > 0) {
233 /* there may be some preceding data */
234 while (first->prev->next) {
235 first = first->prev;
236 if (lyd_owner_module(first) == mod) {
237 cmp = 0;
238 break;
239 }
240 }
241 }
242
243 if (cmp == 0) {
244 /* there may be some preceding data belonging to this module */
245 while (first->prev->next) {
246 if (lyd_owner_module(first->prev) != mod) {
247 break;
248 }
249 first = first->prev;
250 }
251 }
252
253 if (cmp < 0) {
254 /* there may be some following data */
255 LY_LIST_FOR(first, first) {
256 if (lyd_owner_module(first) == mod) {
257 cmp = 0;
258 break;
259 }
260 }
261 }
262
263 if (cmp == 0) {
264 /* we have found the first module data node */
265 *node = first;
266 }
267}
268
Michal Vaskob1b5c262020-03-05 14:29:47 +0100269const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200270lyd_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 +0200271 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100272{
273 struct lyd_node *iter;
274 const struct lys_module *mod;
275
276 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200277 if (module) {
278 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100279 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200280 } else {
281 mod = module;
282 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100283 }
284 } else {
285 do {
286 mod = ly_ctx_get_module_iter(ctx, i);
287 } while (mod && !mod->implemented);
288 }
289
290 /* find its data */
291 *first = NULL;
292 if (mod) {
293 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100294 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100295 *first = iter;
296 break;
297 }
298 }
299 }
300
301 return mod;
302}
303
304const struct lys_module *
305lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
306{
307 const struct lys_module *mod;
308
309 if (!*next) {
310 /* all data traversed */
311 *first = NULL;
312 return NULL;
313 }
314
315 *first = *next;
316
317 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100318 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100319 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100320 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100321 break;
322 }
323 }
324
325 return mod;
326}
Michal Vasko9f96a052020-03-10 09:41:45 +0100327
328LY_ERR
329lyd_parse_check_keys(struct lyd_node *node)
330{
331 const struct lysc_node *skey = NULL;
332 const struct lyd_node *key;
333
334 assert(node->schema->nodetype == LYS_LIST);
335
Radek Krejcia1c1e542020-09-29 16:06:52 +0200336 key = lyd_child(node);
Michal Vasko9f96a052020-03-10 09:41:45 +0100337 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
338 if (!key || (key->schema != skey)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100339 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, skey->name);
Michal Vasko9f96a052020-03-10 09:41:45 +0100340 return LY_EVALID;
341 }
342
343 key = key->next;
344 }
345
346 return LY_SUCCESS;
347}
Michal Vasko60ea6352020-06-29 13:39:39 +0200348
349void
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200350lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *when_check, struct ly_set *exts_check, struct lyd_meta **meta,
351 uint32_t options)
Michal Vasko60ea6352020-06-29 13:39:39 +0200352{
353 struct lyd_meta *meta2, *prev_meta = NULL;
354
Michal Vaskoa5705e52020-12-09 18:15:14 +0100355 if (lysc_has_when(node->schema)) {
Michal Vasko0f3377d2020-11-09 20:56:11 +0100356 if (!(options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200357 /* remember we need to evaluate this node's when */
Radek Krejci3d92e442020-10-12 12:48:13 +0200358 LY_CHECK_RET(ly_set_add(when_check, node, 1, NULL), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200359 }
360 }
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200361 LY_CHECK_RET(lysc_node_ext_tovalidate(exts_check, node), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200362
Michal Vasko60ea6352020-06-29 13:39:39 +0200363 LY_LIST_FOR(*meta, meta2) {
Michal Vasko69730152020-10-09 16:30:07 +0200364 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
365 meta2->value.boolean) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200366 /* node is default according to the metadata */
367 node->flags |= LYD_DEFAULT;
368
369 /* delete the metadata */
370 if (prev_meta) {
371 prev_meta->next = meta2->next;
372 } else {
373 *meta = (*meta)->next;
374 }
Michal Vasko3a41dff2020-07-15 14:30:28 +0200375 lyd_free_meta_single(meta2);
Michal Vasko60ea6352020-06-29 13:39:39 +0200376 break;
377 }
378
379 prev_meta = meta2;
380 }
381}
382
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200383API const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400384lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200385{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200386 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
387
Michal Vasko33876022021-04-27 16:42:24 +0200388 return value->_canonical ? value->_canonical :
389 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200390}
391
Michal Vaskoc0004272020-08-06 08:32:34 +0200392API LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100393lyd_any_value_str(const struct lyd_node *any, char **value_str)
394{
395 const struct lyd_node_any *a;
396 struct lyd_node *tree = NULL;
397 const char *str = NULL;
398 ly_bool dynamic = 0;
399 LY_ERR ret = LY_SUCCESS;
400
401 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200402 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100403
404 a = (struct lyd_node_any *)any;
405 *value_str = NULL;
406
407 if (!a->value.str) {
408 /* there is no value in the union */
409 return LY_SUCCESS;
410 }
411
412 switch (a->value_type) {
413 case LYD_ANYDATA_LYB:
414 /* parse into a data tree */
415 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
416 LY_CHECK_GOTO(ret, cleanup);
417 dynamic = 1;
418 break;
419 case LYD_ANYDATA_DATATREE:
420 tree = a->value.tree;
421 break;
422 case LYD_ANYDATA_STRING:
423 case LYD_ANYDATA_XML:
424 case LYD_ANYDATA_JSON:
425 /* simply use the string */
426 str = a->value.str;
427 break;
428 }
429
430 if (tree) {
431 /* print into a string */
432 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
433 LY_CHECK_GOTO(ret, cleanup);
434 } else {
435 assert(str);
436 *value_str = strdup(str);
437 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
438 }
439
440 /* success */
441
442cleanup:
443 if (dynamic) {
444 lyd_free_all(tree);
445 }
446 return ret;
447}
448
449API LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200450lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
451{
452 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200453
Michal Vaskoa820c312021-02-05 16:33:00 +0100454 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200455 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200456
457 t = (struct lyd_node_any *)trg;
458
459 /* free trg */
460 switch (t->value_type) {
461 case LYD_ANYDATA_DATATREE:
462 lyd_free_all(t->value.tree);
463 break;
464 case LYD_ANYDATA_STRING:
465 case LYD_ANYDATA_XML:
466 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100467 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200468 break;
469 case LYD_ANYDATA_LYB:
470 free(t->value.mem);
471 break;
472 }
473 t->value.str = NULL;
474
475 if (!value) {
476 /* only free value in this case */
477 return LY_SUCCESS;
478 }
479
480 /* copy src */
481 t->value_type = value_type;
482 switch (value_type) {
483 case LYD_ANYDATA_DATATREE:
484 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200485 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200486 }
487 break;
488 case LYD_ANYDATA_STRING:
489 case LYD_ANYDATA_XML:
490 case LYD_ANYDATA_JSON:
491 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200492 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200493 }
494 break;
495 case LYD_ANYDATA_LYB:
496 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200497 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200498 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200499 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200500 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200501 memcpy(t->value.mem, value->mem, len);
502 }
503 break;
504 }
505
506 return LY_SUCCESS;
507}
508
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100509void
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100510lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
511{
512 if (*root && (lyd_owner_module(*root) != mod)) {
513 /* there are no data of mod so this is simply the first top-level sibling */
514 mod = NULL;
515 }
516
517 if ((*root != to_del) || (*root)->parent) {
518 return;
519 }
520
Michal Vasko598063b2021-07-19 11:39:05 +0200521 if (mod && (*root)->prev->next && (!(*root)->next || (lyd_owner_module(to_del) != lyd_owner_module((*root)->next)))) {
522 /* there are no more nodes from mod, simply get the first top-level sibling */
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100523 *root = lyd_first_sibling(*root);
Michal Vasko598063b2021-07-19 11:39:05 +0200524 } else {
525 *root = (*root)->next;
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100526 }
527}
528
529void
Radek Krejci8df109d2021-04-23 12:19:08 +0200530ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100531{
532 struct ly_set *ns_list;
533 struct lysc_prefix *prefixes;
534 uint32_t i;
535 LY_ARRAY_COUNT_TYPE u;
536
537 if (!prefix_data) {
538 return;
539 }
540
541 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200542 case LY_VALUE_XML:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100543 ns_list = prefix_data;
544 for (i = 0; i < ns_list->count; ++i) {
545 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
546 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
547 }
548 ly_set_free(ns_list, free);
549 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200550 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100551 prefixes = prefix_data;
552 LY_ARRAY_FOR(prefixes, u) {
553 free(prefixes[u].prefix);
554 }
555 LY_ARRAY_FREE(prefixes);
556 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200557 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200558 case LY_VALUE_SCHEMA:
559 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200560 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100561 break;
562 }
563}
564
565LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +0200566ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100567 void **prefix_data_p)
568{
569 LY_ERR ret = LY_SUCCESS;
570 struct lyxml_ns *ns;
571 struct lysc_prefix *prefixes = NULL, *orig_pref;
572 struct ly_set *ns_list, *orig_ns;
573 uint32_t i;
574 LY_ARRAY_COUNT_TYPE u;
575
576 assert(!*prefix_data_p);
577
578 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200579 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100580 *prefix_data_p = (void *)prefix_data;
581 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200582 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100583 /* copy all the value prefixes */
584 orig_pref = (struct lysc_prefix *)prefix_data;
585 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
586 *prefix_data_p = prefixes;
587
588 LY_ARRAY_FOR(orig_pref, u) {
589 if (orig_pref[u].prefix) {
590 prefixes[u].prefix = strdup(orig_pref[u].prefix);
591 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
592 }
593 prefixes[u].mod = orig_pref[u].mod;
594 LY_ARRAY_INCREMENT(prefixes);
595 }
596 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200597 case LY_VALUE_XML:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100598 /* copy all the namespaces */
599 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
600 *prefix_data_p = ns_list;
601
602 orig_ns = (struct ly_set *)prefix_data;
603 for (i = 0; i < orig_ns->count; ++i) {
604 ns = calloc(1, sizeof *ns);
605 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
606 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
607
608 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
609 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
610 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
611 }
612 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
613 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
614 }
615 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200616 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200617 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200618 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100619 assert(!prefix_data);
620 *prefix_data_p = NULL;
621 break;
622 }
623
624cleanup:
625 if (ret) {
626 ly_free_prefix_data(format, *prefix_data_p);
627 *prefix_data_p = NULL;
628 }
629 return ret;
630}
631
632LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +0200633ly_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 +0200634 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100635{
636 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100637 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100638 const struct lyxml_ns *ns;
639 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100640 struct ly_set *ns_list;
641 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +0200642 const char *value_iter, *value_next, *value_end;
643 uint32_t substr_len;
644 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100645
646 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200647 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100648 /* copy all referenced modules as prefix - module pairs */
649 if (!*prefix_data_p) {
650 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100651 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +0200652 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100653 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100654 } else {
655 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +0200656 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100657 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100658 }
659
660 /* add all used prefixes */
aPiecek83436bc2021-03-30 12:20:45 +0200661 value_end = value + value_len;
662 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +0200663 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 +0200664 if (is_prefix) {
665 /* we have a possible prefix. Do we already have the prefix? */
666 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
667 if (!mod) {
668 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
669 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200670 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +0200671 /* store a new prefix - module pair */
672 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
673 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100674
aPiecek83436bc2021-03-30 12:20:45 +0200675 val_pref->prefix = strndup(value_iter, substr_len);
676 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
677 val_pref->mod = mod;
678 } /* else it is not even defined */
679 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100680 }
681 }
682 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200683 case LY_VALUE_XML:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100684 /* copy all referenced namespaces as prefix - namespace pairs */
685 if (!*prefix_data_p) {
686 /* new prefix data */
687 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +0200688 *format_p = LY_VALUE_XML;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100689 *prefix_data_p = ns_list;
690 } else {
691 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +0200692 assert(*format_p == LY_VALUE_XML);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100693 ns_list = *prefix_data_p;
694 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100695
Michal Vaskofc2cd072021-02-24 13:17:17 +0100696 /* add all used prefixes */
aPiecek83436bc2021-03-30 12:20:45 +0200697 value_end = value + value_len;
698 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +0200699 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 +0200700 if (is_prefix) {
701 /* we have a possible prefix. Do we already have the prefix? */
702 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
703 if (!ns) {
704 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
705 if (ns) {
706 /* store a new prefix - namespace pair */
707 new_ns = calloc(1, sizeof *new_ns);
708 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
709 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100710
aPiecek83436bc2021-03-30 12:20:45 +0200711 new_ns->prefix = strndup(value_iter, substr_len);
712 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
713 new_ns->uri = strdup(ns->uri);
714 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
715 } /* else it is not even defined */
716 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100717 }
718 }
719 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200720 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200721 case LY_VALUE_SCHEMA_RESOLVED:
722 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200723 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100724 if (!*prefix_data_p) {
725 /* new prefix data - simply copy all the prefix data */
726 *format_p = format;
727 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
728 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100729 break;
730 }
731
732cleanup:
733 if (ret) {
734 ly_free_prefix_data(*format_p, *prefix_data_p);
735 *prefix_data_p = NULL;
736 }
737 return ret;
738}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100739
740const char *
Radek Krejci8df109d2021-04-23 12:19:08 +0200741ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100742{
743 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +0200744 case LY_VALUE_CANON:
745 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +0200746 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100747 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +0200748 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100749 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +0200750 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100751 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +0200752 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100753 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +0200754 case LY_VALUE_LYB:
755 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100756 default:
757 break;
758 }
759
760 return NULL;
761}
Michal Vasko43297a02021-05-19 11:12:37 +0200762
763API LY_ERR
764ly_time_str2time(const char *value, time_t *time, char **fractions_s)
765{
766 struct tm tm = {0};
767 uint32_t i, frac_len;
768 const char *frac;
769 int64_t shift, shift_m;
770 time_t t;
771
772 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
773
774 tm.tm_year = atoi(&value[0]) - 1900;
775 tm.tm_mon = atoi(&value[5]) - 1;
776 tm.tm_mday = atoi(&value[8]);
777 tm.tm_hour = atoi(&value[11]);
778 tm.tm_min = atoi(&value[14]);
779 tm.tm_sec = atoi(&value[17]);
780
781 t = timegm(&tm);
782 i = 19;
783
784 /* fractions of a second */
785 if (value[i] == '.') {
786 ++i;
787 frac = &value[i];
788 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
789
790 i += frac_len;
791
792 /* skip trailing zeros */
793 for ( ; frac_len && (frac[frac_len - 1] == '0'); --frac_len) {}
794
795 if (!frac_len) {
796 /* only zeros, ignore */
797 frac = NULL;
798 }
799 } else {
800 frac = NULL;
801 }
802
803 /* apply offset */
804 if ((value[i] == 'Z') || (value[i] == 'z')) {
805 /* zero shift */
806 shift = 0;
807 } else {
808 shift = strtol(&value[i], NULL, 10);
809 shift = shift * 60 * 60; /* convert from hours to seconds */
810 shift_m = strtol(&value[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
811 /* correct sign */
812 if (shift < 0) {
813 shift_m *= -1;
814 }
815 /* connect hours and minutes of the shift */
816 shift = shift + shift_m;
817 }
818
819 /* we have to shift to the opposite way to correct the time */
820 t -= shift;
821
822 *time = t;
823 if (fractions_s) {
824 if (frac) {
825 *fractions_s = strndup(frac, frac_len);
826 LY_CHECK_RET(!*fractions_s, LY_EMEM);
827 } else {
828 *fractions_s = NULL;
829 }
830 }
831 return LY_SUCCESS;
832}
833
834API LY_ERR
835ly_time_time2str(time_t time, const char *fractions_s, char **str)
836{
837 struct tm tm;
Michal Vasko143ffa82021-05-20 11:11:39 +0200838 char zoneshift[8];
Michal Vasko43297a02021-05-19 11:12:37 +0200839 int32_t zonediff_h, zonediff_m;
840
841 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
842
843 /* initialize the local timezone */
844 tzset();
845
846 /* convert */
847 if (!localtime_r(&time, &tm)) {
848 return LY_ESYS;
849 }
850
851 /* get timezone offset */
852 if (tm.tm_gmtoff == 0) {
853 /* time is Zulu (UTC) */
854 zonediff_h = 0;
855 zonediff_m = 0;
856 } else {
857 /* timezone offset */
858 zonediff_h = tm.tm_gmtoff / 60 / 60;
859 zonediff_m = tm.tm_gmtoff / 60 % 60;
860 }
861 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
862
863 /* print */
864 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
865 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
866 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
867 return LY_EMEM;
868 }
869
870 return LY_SUCCESS;
871}
872
873API LY_ERR
874ly_time_str2ts(const char *value, struct timespec *ts)
875{
876 LY_ERR rc;
877 char *fractions_s, frac_buf[10] = {'0'};
878 int frac_len;
879
880 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
881
882 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
883 LY_CHECK_RET(rc);
884
885 /* convert fractions of a second to nanoseconds */
886 if (fractions_s) {
887 frac_len = strlen(fractions_s);
888 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
889 ts->tv_nsec = atol(frac_buf);
890 free(fractions_s);
891 } else {
892 ts->tv_nsec = 0;
893 }
894
895 return LY_SUCCESS;
896}
897
898API LY_ERR
899ly_time_ts2str(const struct timespec *ts, char **str)
900{
901 char frac_buf[10];
902
903 LY_CHECK_ARG_RET(NULL, ts, str, LY_EINVAL);
904
905 /* convert nanoseconds to fractions of a second */
906 if (ts->tv_nsec) {
907 sprintf(frac_buf, "%09ld", ts->tv_nsec);
908 }
909
910 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
911}