blob: 2d9ba624761199d96021168d2c99ccddb61a9457 [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
218const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200219lyd_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 +0200220 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100221{
222 struct lyd_node *iter;
223 const struct lys_module *mod;
224
225 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200226 if (module) {
227 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100228 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200229 } else {
230 mod = module;
231 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100232 }
233 } else {
234 do {
235 mod = ly_ctx_get_module_iter(ctx, i);
236 } while (mod && !mod->implemented);
237 }
238
239 /* find its data */
240 *first = NULL;
241 if (mod) {
242 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100243 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100244 *first = iter;
245 break;
246 }
247 }
248 }
249
250 return mod;
251}
252
253const struct lys_module *
254lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
255{
256 const struct lys_module *mod;
257
258 if (!*next) {
259 /* all data traversed */
260 *first = NULL;
261 return NULL;
262 }
263
264 *first = *next;
265
266 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100267 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100268 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100269 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100270 break;
271 }
272 }
273
274 return mod;
275}
Michal Vasko9f96a052020-03-10 09:41:45 +0100276
277LY_ERR
278lyd_parse_check_keys(struct lyd_node *node)
279{
280 const struct lysc_node *skey = NULL;
281 const struct lyd_node *key;
282
283 assert(node->schema->nodetype == LYS_LIST);
284
Radek Krejcia1c1e542020-09-29 16:06:52 +0200285 key = lyd_child(node);
Michal Vasko9f96a052020-03-10 09:41:45 +0100286 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
287 if (!key || (key->schema != skey)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100288 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, skey->name);
Michal Vasko9f96a052020-03-10 09:41:45 +0100289 return LY_EVALID;
290 }
291
292 key = key->next;
293 }
294
295 return LY_SUCCESS;
296}
Michal Vasko60ea6352020-06-29 13:39:39 +0200297
298void
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200299lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *when_check, struct ly_set *exts_check, struct lyd_meta **meta,
300 uint32_t options)
Michal Vasko60ea6352020-06-29 13:39:39 +0200301{
302 struct lyd_meta *meta2, *prev_meta = NULL;
303
Michal Vaskoa5705e52020-12-09 18:15:14 +0100304 if (lysc_has_when(node->schema)) {
Michal Vasko0f3377d2020-11-09 20:56:11 +0100305 if (!(options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200306 /* remember we need to evaluate this node's when */
Radek Krejci3d92e442020-10-12 12:48:13 +0200307 LY_CHECK_RET(ly_set_add(when_check, node, 1, NULL), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200308 }
309 }
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200310 LY_CHECK_RET(lysc_node_ext_tovalidate(exts_check, node), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200311
Michal Vasko60ea6352020-06-29 13:39:39 +0200312 LY_LIST_FOR(*meta, meta2) {
Michal Vasko69730152020-10-09 16:30:07 +0200313 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
314 meta2->value.boolean) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200315 /* node is default according to the metadata */
316 node->flags |= LYD_DEFAULT;
317
318 /* delete the metadata */
319 if (prev_meta) {
320 prev_meta->next = meta2->next;
321 } else {
322 *meta = (*meta)->next;
323 }
Michal Vasko3a41dff2020-07-15 14:30:28 +0200324 lyd_free_meta_single(meta2);
Michal Vasko60ea6352020-06-29 13:39:39 +0200325 break;
326 }
327
328 prev_meta = meta2;
329 }
330}
331
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200332API const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400333lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200334{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200335 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
336
Michal Vasko33876022021-04-27 16:42:24 +0200337 return value->_canonical ? value->_canonical :
338 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200339}
340
Michal Vaskoc0004272020-08-06 08:32:34 +0200341API LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100342lyd_any_value_str(const struct lyd_node *any, char **value_str)
343{
344 const struct lyd_node_any *a;
345 struct lyd_node *tree = NULL;
346 const char *str = NULL;
347 ly_bool dynamic = 0;
348 LY_ERR ret = LY_SUCCESS;
349
350 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200351 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100352
353 a = (struct lyd_node_any *)any;
354 *value_str = NULL;
355
356 if (!a->value.str) {
357 /* there is no value in the union */
358 return LY_SUCCESS;
359 }
360
361 switch (a->value_type) {
362 case LYD_ANYDATA_LYB:
363 /* parse into a data tree */
364 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
365 LY_CHECK_GOTO(ret, cleanup);
366 dynamic = 1;
367 break;
368 case LYD_ANYDATA_DATATREE:
369 tree = a->value.tree;
370 break;
371 case LYD_ANYDATA_STRING:
372 case LYD_ANYDATA_XML:
373 case LYD_ANYDATA_JSON:
374 /* simply use the string */
375 str = a->value.str;
376 break;
377 }
378
379 if (tree) {
380 /* print into a string */
381 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
382 LY_CHECK_GOTO(ret, cleanup);
383 } else {
384 assert(str);
385 *value_str = strdup(str);
386 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
387 }
388
389 /* success */
390
391cleanup:
392 if (dynamic) {
393 lyd_free_all(tree);
394 }
395 return ret;
396}
397
398API LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200399lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
400{
401 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200402
Michal Vaskoa820c312021-02-05 16:33:00 +0100403 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200404 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200405
406 t = (struct lyd_node_any *)trg;
407
408 /* free trg */
409 switch (t->value_type) {
410 case LYD_ANYDATA_DATATREE:
411 lyd_free_all(t->value.tree);
412 break;
413 case LYD_ANYDATA_STRING:
414 case LYD_ANYDATA_XML:
415 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100416 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200417 break;
418 case LYD_ANYDATA_LYB:
419 free(t->value.mem);
420 break;
421 }
422 t->value.str = NULL;
423
424 if (!value) {
425 /* only free value in this case */
426 return LY_SUCCESS;
427 }
428
429 /* copy src */
430 t->value_type = value_type;
431 switch (value_type) {
432 case LYD_ANYDATA_DATATREE:
433 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200434 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200435 }
436 break;
437 case LYD_ANYDATA_STRING:
438 case LYD_ANYDATA_XML:
439 case LYD_ANYDATA_JSON:
440 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200441 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200442 }
443 break;
444 case LYD_ANYDATA_LYB:
445 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200446 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200447 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200448 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200449 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200450 memcpy(t->value.mem, value->mem, len);
451 }
452 break;
453 }
454
455 return LY_SUCCESS;
456}
457
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100458void
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100459lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
460{
461 if (*root && (lyd_owner_module(*root) != mod)) {
462 /* there are no data of mod so this is simply the first top-level sibling */
463 mod = NULL;
464 }
465
466 if ((*root != to_del) || (*root)->parent) {
467 return;
468 }
469
470 *root = (*root)->next;
471 if (mod && *root && (lyd_owner_module(to_del) != lyd_owner_module(*root))) {
472 /* there are no more nodes from mod */
473 *root = lyd_first_sibling(*root);
474 }
475}
476
477void
Radek Krejci8df109d2021-04-23 12:19:08 +0200478ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100479{
480 struct ly_set *ns_list;
481 struct lysc_prefix *prefixes;
482 uint32_t i;
483 LY_ARRAY_COUNT_TYPE u;
484
485 if (!prefix_data) {
486 return;
487 }
488
489 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200490 case LY_VALUE_XML:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100491 ns_list = prefix_data;
492 for (i = 0; i < ns_list->count; ++i) {
493 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
494 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
495 }
496 ly_set_free(ns_list, free);
497 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200498 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100499 prefixes = prefix_data;
500 LY_ARRAY_FOR(prefixes, u) {
501 free(prefixes[u].prefix);
502 }
503 LY_ARRAY_FREE(prefixes);
504 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200505 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200506 case LY_VALUE_SCHEMA:
507 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200508 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100509 break;
510 }
511}
512
513LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +0200514ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100515 void **prefix_data_p)
516{
517 LY_ERR ret = LY_SUCCESS;
518 struct lyxml_ns *ns;
519 struct lysc_prefix *prefixes = NULL, *orig_pref;
520 struct ly_set *ns_list, *orig_ns;
521 uint32_t i;
522 LY_ARRAY_COUNT_TYPE u;
523
524 assert(!*prefix_data_p);
525
526 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200527 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100528 *prefix_data_p = (void *)prefix_data;
529 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200530 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100531 /* copy all the value prefixes */
532 orig_pref = (struct lysc_prefix *)prefix_data;
533 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
534 *prefix_data_p = prefixes;
535
536 LY_ARRAY_FOR(orig_pref, u) {
537 if (orig_pref[u].prefix) {
538 prefixes[u].prefix = strdup(orig_pref[u].prefix);
539 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
540 }
541 prefixes[u].mod = orig_pref[u].mod;
542 LY_ARRAY_INCREMENT(prefixes);
543 }
544 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200545 case LY_VALUE_XML:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100546 /* copy all the namespaces */
547 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
548 *prefix_data_p = ns_list;
549
550 orig_ns = (struct ly_set *)prefix_data;
551 for (i = 0; i < orig_ns->count; ++i) {
552 ns = calloc(1, sizeof *ns);
553 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
554 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
555
556 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
557 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
558 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
559 }
560 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
561 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
562 }
563 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200564 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200565 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200566 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100567 assert(!prefix_data);
568 *prefix_data_p = NULL;
569 break;
570 }
571
572cleanup:
573 if (ret) {
574 ly_free_prefix_data(format, *prefix_data_p);
575 *prefix_data_p = NULL;
576 }
577 return ret;
578}
579
580LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +0200581ly_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 +0200582 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100583{
584 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100585 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100586 const struct lyxml_ns *ns;
587 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100588 struct ly_set *ns_list;
589 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +0200590 const char *value_iter, *value_next, *value_end;
591 uint32_t substr_len;
592 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100593
594 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200595 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100596 /* copy all referenced modules as prefix - module pairs */
597 if (!*prefix_data_p) {
598 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100599 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +0200600 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100601 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100602 } else {
603 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +0200604 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100605 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100606 }
607
608 /* add all used prefixes */
aPiecek83436bc2021-03-30 12:20:45 +0200609 value_end = value + value_len;
610 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +0200611 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 +0200612 if (is_prefix) {
613 /* we have a possible prefix. Do we already have the prefix? */
614 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
615 if (!mod) {
616 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
617 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200618 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +0200619 /* store a new prefix - module pair */
620 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
621 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100622
aPiecek83436bc2021-03-30 12:20:45 +0200623 val_pref->prefix = strndup(value_iter, substr_len);
624 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
625 val_pref->mod = mod;
626 } /* else it is not even defined */
627 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100628 }
629 }
630 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200631 case LY_VALUE_XML:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100632 /* copy all referenced namespaces as prefix - namespace pairs */
633 if (!*prefix_data_p) {
634 /* new prefix data */
635 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +0200636 *format_p = LY_VALUE_XML;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100637 *prefix_data_p = ns_list;
638 } else {
639 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +0200640 assert(*format_p == LY_VALUE_XML);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100641 ns_list = *prefix_data_p;
642 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100643
Michal Vaskofc2cd072021-02-24 13:17:17 +0100644 /* add all used prefixes */
aPiecek83436bc2021-03-30 12:20:45 +0200645 value_end = value + value_len;
646 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +0200647 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 +0200648 if (is_prefix) {
649 /* we have a possible prefix. Do we already have the prefix? */
650 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
651 if (!ns) {
652 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
653 if (ns) {
654 /* store a new prefix - namespace pair */
655 new_ns = calloc(1, sizeof *new_ns);
656 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
657 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100658
aPiecek83436bc2021-03-30 12:20:45 +0200659 new_ns->prefix = strndup(value_iter, substr_len);
660 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
661 new_ns->uri = strdup(ns->uri);
662 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
663 } /* else it is not even defined */
664 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100665 }
666 }
667 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200668 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200669 case LY_VALUE_SCHEMA_RESOLVED:
670 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200671 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100672 if (!*prefix_data_p) {
673 /* new prefix data - simply copy all the prefix data */
674 *format_p = format;
675 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
676 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100677 break;
678 }
679
680cleanup:
681 if (ret) {
682 ly_free_prefix_data(*format_p, *prefix_data_p);
683 *prefix_data_p = NULL;
684 }
685 return ret;
686}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100687
688const char *
Radek Krejci8df109d2021-04-23 12:19:08 +0200689ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100690{
691 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +0200692 case LY_VALUE_CANON:
693 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +0200694 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100695 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +0200696 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100697 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +0200698 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100699 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +0200700 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100701 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +0200702 case LY_VALUE_LYB:
703 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100704 default:
705 break;
706 }
707
708 return NULL;
709}
Michal Vasko43297a02021-05-19 11:12:37 +0200710
711API LY_ERR
712ly_time_str2time(const char *value, time_t *time, char **fractions_s)
713{
714 struct tm tm = {0};
715 uint32_t i, frac_len;
716 const char *frac;
717 int64_t shift, shift_m;
718 time_t t;
719
720 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
721
722 tm.tm_year = atoi(&value[0]) - 1900;
723 tm.tm_mon = atoi(&value[5]) - 1;
724 tm.tm_mday = atoi(&value[8]);
725 tm.tm_hour = atoi(&value[11]);
726 tm.tm_min = atoi(&value[14]);
727 tm.tm_sec = atoi(&value[17]);
728
729 t = timegm(&tm);
730 i = 19;
731
732 /* fractions of a second */
733 if (value[i] == '.') {
734 ++i;
735 frac = &value[i];
736 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
737
738 i += frac_len;
739
740 /* skip trailing zeros */
741 for ( ; frac_len && (frac[frac_len - 1] == '0'); --frac_len) {}
742
743 if (!frac_len) {
744 /* only zeros, ignore */
745 frac = NULL;
746 }
747 } else {
748 frac = NULL;
749 }
750
751 /* apply offset */
752 if ((value[i] == 'Z') || (value[i] == 'z')) {
753 /* zero shift */
754 shift = 0;
755 } else {
756 shift = strtol(&value[i], NULL, 10);
757 shift = shift * 60 * 60; /* convert from hours to seconds */
758 shift_m = strtol(&value[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
759 /* correct sign */
760 if (shift < 0) {
761 shift_m *= -1;
762 }
763 /* connect hours and minutes of the shift */
764 shift = shift + shift_m;
765 }
766
767 /* we have to shift to the opposite way to correct the time */
768 t -= shift;
769
770 *time = t;
771 if (fractions_s) {
772 if (frac) {
773 *fractions_s = strndup(frac, frac_len);
774 LY_CHECK_RET(!*fractions_s, LY_EMEM);
775 } else {
776 *fractions_s = NULL;
777 }
778 }
779 return LY_SUCCESS;
780}
781
782API LY_ERR
783ly_time_time2str(time_t time, const char *fractions_s, char **str)
784{
785 struct tm tm;
Michal Vasko143ffa82021-05-20 11:11:39 +0200786 char zoneshift[8];
Michal Vasko43297a02021-05-19 11:12:37 +0200787 int32_t zonediff_h, zonediff_m;
788
789 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
790
791 /* initialize the local timezone */
792 tzset();
793
794 /* convert */
795 if (!localtime_r(&time, &tm)) {
796 return LY_ESYS;
797 }
798
799 /* get timezone offset */
800 if (tm.tm_gmtoff == 0) {
801 /* time is Zulu (UTC) */
802 zonediff_h = 0;
803 zonediff_m = 0;
804 } else {
805 /* timezone offset */
806 zonediff_h = tm.tm_gmtoff / 60 / 60;
807 zonediff_m = tm.tm_gmtoff / 60 % 60;
808 }
809 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
810
811 /* print */
812 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
813 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
814 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
815 return LY_EMEM;
816 }
817
818 return LY_SUCCESS;
819}
820
821API LY_ERR
822ly_time_str2ts(const char *value, struct timespec *ts)
823{
824 LY_ERR rc;
825 char *fractions_s, frac_buf[10] = {'0'};
826 int frac_len;
827
828 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
829
830 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
831 LY_CHECK_RET(rc);
832
833 /* convert fractions of a second to nanoseconds */
834 if (fractions_s) {
835 frac_len = strlen(fractions_s);
836 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
837 ts->tv_nsec = atol(frac_buf);
838 free(fractions_s);
839 } else {
840 ts->tv_nsec = 0;
841 }
842
843 return LY_SUCCESS;
844}
845
846API LY_ERR
847ly_time_ts2str(const struct timespec *ts, char **str)
848{
849 char frac_buf[10];
850
851 LY_CHECK_ARG_RET(NULL, ts, str, LY_EINVAL);
852
853 /* convert nanoseconds to fractions of a second */
854 if (ts->tv_nsec) {
855 sprintf(frac_buf, "%09ld", ts->tv_nsec);
856 }
857
858 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
859}