blob: f26749baf0e6ec2f66a3dc5d55946e5192a0ef19 [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 */
16#include <sys/cdefs.h>
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 Vaskoa820c312021-02-05 16:33:00 +010033#include "printer_data.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020034#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020035#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020036#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020037#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010038#include "tree_edit.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020039#include "tree_schema.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020040#include "tree_schema_internal.h"
Radek Krejci4f2e3e52021-03-30 14:20:28 +020041#include "validation.h"
Radek Krejci77114102021-03-10 15:21:57 +010042#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020043
Michal Vaskod7c048c2021-05-18 16:12:55 +020044/**
45 * @brief Find an entry in duplicate instance cache for an instance. Create it if it does not exist.
46 *
47 * @param[in] first_inst Instance of the cache entry.
48 * @param[in,out] dup_inst_cache Duplicate instance cache.
49 * @return Instance cache entry.
50 */
51static struct lyd_dup_inst *
52lyd_dup_inst_get(const struct lyd_node *first_inst, struct lyd_dup_inst **dup_inst_cache)
53{
54 struct lyd_dup_inst *item;
55 LY_ARRAY_COUNT_TYPE u;
56
57 LY_ARRAY_FOR(*dup_inst_cache, u) {
58 if ((*dup_inst_cache)[u].inst_set->dnodes[0] == first_inst) {
59 return &(*dup_inst_cache)[u];
60 }
61 }
62
63 /* it was not added yet, add it now */
64 LY_ARRAY_NEW_RET(LYD_CTX(first_inst), *dup_inst_cache, item, NULL);
65
66 return item;
67}
68
69LY_ERR
70lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struct lyd_dup_inst **dup_inst_cache)
71{
72 struct lyd_dup_inst *dup_inst;
73
74 if (!*inst || !lysc_is_dup_inst_list((*inst)->schema)) {
75 /* no match or not dup-inst list, inst is unchanged */
76 return LY_SUCCESS;
77 }
78
79 /* there can be more exact same instances and we must make sure we do not match a single node more times */
80 dup_inst = lyd_dup_inst_get(*inst, dup_inst_cache);
81 LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
82
83 if (!dup_inst->used) {
84 /* we did not cache these instances yet, do so */
85 lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->inst_set);
86 assert(dup_inst->inst_set->count && (dup_inst->inst_set->dnodes[0] == *inst));
87 }
88
89 if (dup_inst->used == dup_inst->inst_set->count) {
90 /* we have used all the instances */
91 *inst = NULL;
92 } else {
93 assert(dup_inst->used < dup_inst->inst_set->count);
94
95 /* use another instance */
96 *inst = dup_inst->inst_set->dnodes[dup_inst->used];
97 ++dup_inst->used;
98 }
99
100 return LY_SUCCESS;
101}
102
103void
104lyd_dup_inst_free(struct lyd_dup_inst *dup_inst)
105{
106 LY_ARRAY_COUNT_TYPE u;
107
108 LY_ARRAY_FOR(dup_inst, u) {
109 ly_set_free(dup_inst[u].inst_set, NULL);
110 }
111 LY_ARRAY_FREE(dup_inst);
112}
113
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200114struct lyd_node *
115lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +0200116 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200117{
118 const struct lysc_node *siter = NULL;
119 struct lyd_node *match = NULL;
120
121 assert(parent || module);
122 assert(!last || (slast && *slast));
123
124 if (slast) {
125 siter = *slast;
126 }
127
128 if (last && last->next && (last->next->schema == siter)) {
129 /* return next data instance */
130 return last->next;
131 }
132
133 /* find next schema node data instance */
134 while ((siter = lys_getnext(siter, parent, module, 0))) {
135 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
136 break;
137 }
138 }
139
140 if (slast) {
141 *slast = siter;
142 }
143 return match;
144}
145
Radek Krejcie7b95092019-05-15 11:03:07 +0200146struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +0100147lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200148{
149 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +0100150
151 if (!node->schema) {
152 return &((struct lyd_node_opaq *)node)->child;
153 } else {
154 switch (node->schema->nodetype) {
155 case LYS_CONTAINER:
156 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +0100157 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100158 case LYS_ACTION:
159 case LYS_NOTIF:
160 return &((struct lyd_node_inner *)node)->child;
161 default:
162 return NULL;
163 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200164 }
165}
166
Radek Krejcidae0ee82020-05-06 16:53:24 +0200167API struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +0200168lyd_child_no_keys(const struct lyd_node *node)
169{
170 struct lyd_node **children;
171
172 if (!node) {
173 return NULL;
174 }
175
176 if (!node->schema) {
177 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100178 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200179 }
180
Michal Vaskoe0665742021-02-11 11:08:44 +0100181 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200182 if (children) {
183 struct lyd_node *child = *children;
184 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
185 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200186 }
187 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200188 } else {
189 return NULL;
190 }
191}
Michal Vasko9b368d32020-02-14 13:53:31 +0100192
Michal Vaskoc193ce92020-03-06 11:04:48 +0100193API const struct lys_module *
194lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100195{
196 const struct lysc_node *schema;
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100197 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100198
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100199 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100200 return NULL;
201 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100202
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100203 if (!node->schema) {
204 opaq = (struct lyd_node_opaq *)node;
205 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200206 case LY_VALUE_XML:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100207 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
Radek Krejci8df109d2021-04-23 12:19:08 +0200208 case LY_VALUE_JSON:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100209 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
210 default:
211 return NULL;
212 }
213 }
214
Radek Krejci1e008d22020-08-17 11:37:37 +0200215 for (schema = node->schema; schema->parent; schema = schema->parent) {}
Michal Vasko9b368d32020-02-14 13:53:31 +0100216 return schema->module;
217}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100218
219const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200220lyd_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 +0200221 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100222{
223 struct lyd_node *iter;
224 const struct lys_module *mod;
225
226 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200227 if (module) {
228 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100229 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200230 } else {
231 mod = module;
232 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100233 }
234 } else {
235 do {
236 mod = ly_ctx_get_module_iter(ctx, i);
237 } while (mod && !mod->implemented);
238 }
239
240 /* find its data */
241 *first = NULL;
242 if (mod) {
243 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100244 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100245 *first = iter;
246 break;
247 }
248 }
249 }
250
251 return mod;
252}
253
254const struct lys_module *
255lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
256{
257 const struct lys_module *mod;
258
259 if (!*next) {
260 /* all data traversed */
261 *first = NULL;
262 return NULL;
263 }
264
265 *first = *next;
266
267 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100268 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100269 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100270 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100271 break;
272 }
273 }
274
275 return mod;
276}
Michal Vasko9f96a052020-03-10 09:41:45 +0100277
278LY_ERR
279lyd_parse_check_keys(struct lyd_node *node)
280{
281 const struct lysc_node *skey = NULL;
282 const struct lyd_node *key;
283
284 assert(node->schema->nodetype == LYS_LIST);
285
Radek Krejcia1c1e542020-09-29 16:06:52 +0200286 key = lyd_child(node);
Michal Vasko9f96a052020-03-10 09:41:45 +0100287 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
288 if (!key || (key->schema != skey)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100289 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, skey->name);
Michal Vasko9f96a052020-03-10 09:41:45 +0100290 return LY_EVALID;
291 }
292
293 key = key->next;
294 }
295
296 return LY_SUCCESS;
297}
Michal Vasko60ea6352020-06-29 13:39:39 +0200298
299void
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200300lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *when_check, struct ly_set *exts_check, struct lyd_meta **meta,
301 uint32_t options)
Michal Vasko60ea6352020-06-29 13:39:39 +0200302{
303 struct lyd_meta *meta2, *prev_meta = NULL;
304
Michal Vaskoa5705e52020-12-09 18:15:14 +0100305 if (lysc_has_when(node->schema)) {
Michal Vasko0f3377d2020-11-09 20:56:11 +0100306 if (!(options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200307 /* remember we need to evaluate this node's when */
Radek Krejci3d92e442020-10-12 12:48:13 +0200308 LY_CHECK_RET(ly_set_add(when_check, node, 1, NULL), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200309 }
310 }
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200311 LY_CHECK_RET(lysc_node_ext_tovalidate(exts_check, node), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200312
Michal Vasko60ea6352020-06-29 13:39:39 +0200313 LY_LIST_FOR(*meta, meta2) {
Michal Vasko69730152020-10-09 16:30:07 +0200314 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
315 meta2->value.boolean) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200316 /* node is default according to the metadata */
317 node->flags |= LYD_DEFAULT;
318
319 /* delete the metadata */
320 if (prev_meta) {
321 prev_meta->next = meta2->next;
322 } else {
323 *meta = (*meta)->next;
324 }
Michal Vasko3a41dff2020-07-15 14:30:28 +0200325 lyd_free_meta_single(meta2);
Michal Vasko60ea6352020-06-29 13:39:39 +0200326 break;
327 }
328
329 prev_meta = meta2;
330 }
331}
332
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200333API const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400334lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200335{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200336 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
337
Michal Vasko33876022021-04-27 16:42:24 +0200338 return value->_canonical ? value->_canonical :
339 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200340}
341
Michal Vaskoc0004272020-08-06 08:32:34 +0200342API LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100343lyd_any_value_str(const struct lyd_node *any, char **value_str)
344{
345 const struct lyd_node_any *a;
346 struct lyd_node *tree = NULL;
347 const char *str = NULL;
348 ly_bool dynamic = 0;
349 LY_ERR ret = LY_SUCCESS;
350
351 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200352 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100353
354 a = (struct lyd_node_any *)any;
355 *value_str = NULL;
356
357 if (!a->value.str) {
358 /* there is no value in the union */
359 return LY_SUCCESS;
360 }
361
362 switch (a->value_type) {
363 case LYD_ANYDATA_LYB:
364 /* parse into a data tree */
365 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
366 LY_CHECK_GOTO(ret, cleanup);
367 dynamic = 1;
368 break;
369 case LYD_ANYDATA_DATATREE:
370 tree = a->value.tree;
371 break;
372 case LYD_ANYDATA_STRING:
373 case LYD_ANYDATA_XML:
374 case LYD_ANYDATA_JSON:
375 /* simply use the string */
376 str = a->value.str;
377 break;
378 }
379
380 if (tree) {
381 /* print into a string */
382 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
383 LY_CHECK_GOTO(ret, cleanup);
384 } else {
385 assert(str);
386 *value_str = strdup(str);
387 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
388 }
389
390 /* success */
391
392cleanup:
393 if (dynamic) {
394 lyd_free_all(tree);
395 }
396 return ret;
397}
398
399API LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200400lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
401{
402 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200403
Michal Vaskoa820c312021-02-05 16:33:00 +0100404 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200405 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200406
407 t = (struct lyd_node_any *)trg;
408
409 /* free trg */
410 switch (t->value_type) {
411 case LYD_ANYDATA_DATATREE:
412 lyd_free_all(t->value.tree);
413 break;
414 case LYD_ANYDATA_STRING:
415 case LYD_ANYDATA_XML:
416 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100417 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200418 break;
419 case LYD_ANYDATA_LYB:
420 free(t->value.mem);
421 break;
422 }
423 t->value.str = NULL;
424
425 if (!value) {
426 /* only free value in this case */
427 return LY_SUCCESS;
428 }
429
430 /* copy src */
431 t->value_type = value_type;
432 switch (value_type) {
433 case LYD_ANYDATA_DATATREE:
434 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200435 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200436 }
437 break;
438 case LYD_ANYDATA_STRING:
439 case LYD_ANYDATA_XML:
440 case LYD_ANYDATA_JSON:
441 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200442 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200443 }
444 break;
445 case LYD_ANYDATA_LYB:
446 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200447 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200448 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200449 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200450 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200451 memcpy(t->value.mem, value->mem, len);
452 }
453 break;
454 }
455
456 return LY_SUCCESS;
457}
458
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100459void
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100460lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
461{
462 if (*root && (lyd_owner_module(*root) != mod)) {
463 /* there are no data of mod so this is simply the first top-level sibling */
464 mod = NULL;
465 }
466
467 if ((*root != to_del) || (*root)->parent) {
468 return;
469 }
470
471 *root = (*root)->next;
472 if (mod && *root && (lyd_owner_module(to_del) != lyd_owner_module(*root))) {
473 /* there are no more nodes from mod */
474 *root = lyd_first_sibling(*root);
475 }
476}
477
478void
Radek Krejci8df109d2021-04-23 12:19:08 +0200479ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100480{
481 struct ly_set *ns_list;
482 struct lysc_prefix *prefixes;
483 uint32_t i;
484 LY_ARRAY_COUNT_TYPE u;
485
486 if (!prefix_data) {
487 return;
488 }
489
490 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200491 case LY_VALUE_XML:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100492 ns_list = prefix_data;
493 for (i = 0; i < ns_list->count; ++i) {
494 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
495 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
496 }
497 ly_set_free(ns_list, free);
498 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200499 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100500 prefixes = prefix_data;
501 LY_ARRAY_FOR(prefixes, u) {
502 free(prefixes[u].prefix);
503 }
504 LY_ARRAY_FREE(prefixes);
505 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200506 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200507 case LY_VALUE_SCHEMA:
508 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200509 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100510 break;
511 }
512}
513
514LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +0200515ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100516 void **prefix_data_p)
517{
518 LY_ERR ret = LY_SUCCESS;
519 struct lyxml_ns *ns;
520 struct lysc_prefix *prefixes = NULL, *orig_pref;
521 struct ly_set *ns_list, *orig_ns;
522 uint32_t i;
523 LY_ARRAY_COUNT_TYPE u;
524
525 assert(!*prefix_data_p);
526
527 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200528 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100529 *prefix_data_p = (void *)prefix_data;
530 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200531 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100532 /* copy all the value prefixes */
533 orig_pref = (struct lysc_prefix *)prefix_data;
534 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
535 *prefix_data_p = prefixes;
536
537 LY_ARRAY_FOR(orig_pref, u) {
538 if (orig_pref[u].prefix) {
539 prefixes[u].prefix = strdup(orig_pref[u].prefix);
540 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
541 }
542 prefixes[u].mod = orig_pref[u].mod;
543 LY_ARRAY_INCREMENT(prefixes);
544 }
545 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200546 case LY_VALUE_XML:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100547 /* copy all the namespaces */
548 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
549 *prefix_data_p = ns_list;
550
551 orig_ns = (struct ly_set *)prefix_data;
552 for (i = 0; i < orig_ns->count; ++i) {
553 ns = calloc(1, sizeof *ns);
554 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
555 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
556
557 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
558 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
559 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
560 }
561 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
562 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
563 }
564 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200565 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200566 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200567 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100568 assert(!prefix_data);
569 *prefix_data_p = NULL;
570 break;
571 }
572
573cleanup:
574 if (ret) {
575 ly_free_prefix_data(format, *prefix_data_p);
576 *prefix_data_p = NULL;
577 }
578 return ret;
579}
580
581LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +0200582ly_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 +0200583 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100584{
585 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100586 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100587 const struct lyxml_ns *ns;
588 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100589 struct ly_set *ns_list;
590 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +0200591 const char *value_iter, *value_next, *value_end;
592 uint32_t substr_len;
593 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100594
595 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200596 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100597 /* copy all referenced modules as prefix - module pairs */
598 if (!*prefix_data_p) {
599 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100600 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +0200601 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100602 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100603 } else {
604 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +0200605 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100606 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100607 }
608
609 /* add all used prefixes */
aPiecek83436bc2021-03-30 12:20:45 +0200610 value_end = value + value_len;
611 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +0200612 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 +0200613 if (is_prefix) {
614 /* we have a possible prefix. Do we already have the prefix? */
615 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
616 if (!mod) {
617 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
618 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200619 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +0200620 /* store a new prefix - module pair */
621 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
622 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100623
aPiecek83436bc2021-03-30 12:20:45 +0200624 val_pref->prefix = strndup(value_iter, substr_len);
625 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
626 val_pref->mod = mod;
627 } /* else it is not even defined */
628 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100629 }
630 }
631 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200632 case LY_VALUE_XML:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100633 /* copy all referenced namespaces as prefix - namespace pairs */
634 if (!*prefix_data_p) {
635 /* new prefix data */
636 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +0200637 *format_p = LY_VALUE_XML;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100638 *prefix_data_p = ns_list;
639 } else {
640 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +0200641 assert(*format_p == LY_VALUE_XML);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100642 ns_list = *prefix_data_p;
643 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100644
Michal Vaskofc2cd072021-02-24 13:17:17 +0100645 /* add all used prefixes */
aPiecek83436bc2021-03-30 12:20:45 +0200646 value_end = value + value_len;
647 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +0200648 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 +0200649 if (is_prefix) {
650 /* we have a possible prefix. Do we already have the prefix? */
651 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
652 if (!ns) {
653 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
654 if (ns) {
655 /* store a new prefix - namespace pair */
656 new_ns = calloc(1, sizeof *new_ns);
657 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
658 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100659
aPiecek83436bc2021-03-30 12:20:45 +0200660 new_ns->prefix = strndup(value_iter, substr_len);
661 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
662 new_ns->uri = strdup(ns->uri);
663 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
664 } /* else it is not even defined */
665 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100666 }
667 }
668 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200669 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200670 case LY_VALUE_SCHEMA_RESOLVED:
671 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200672 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100673 if (!*prefix_data_p) {
674 /* new prefix data - simply copy all the prefix data */
675 *format_p = format;
676 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
677 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100678 break;
679 }
680
681cleanup:
682 if (ret) {
683 ly_free_prefix_data(*format_p, *prefix_data_p);
684 *prefix_data_p = NULL;
685 }
686 return ret;
687}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100688
689const char *
Radek Krejci8df109d2021-04-23 12:19:08 +0200690ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100691{
692 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +0200693 case LY_VALUE_CANON:
694 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +0200695 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100696 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +0200697 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100698 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +0200699 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100700 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +0200701 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100702 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +0200703 case LY_VALUE_LYB:
704 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100705 default:
706 break;
707 }
708
709 return NULL;
710}
Michal Vasko43297a02021-05-19 11:12:37 +0200711
712API LY_ERR
713ly_time_str2time(const char *value, time_t *time, char **fractions_s)
714{
715 struct tm tm = {0};
716 uint32_t i, frac_len;
717 const char *frac;
718 int64_t shift, shift_m;
719 time_t t;
720
721 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
722
723 tm.tm_year = atoi(&value[0]) - 1900;
724 tm.tm_mon = atoi(&value[5]) - 1;
725 tm.tm_mday = atoi(&value[8]);
726 tm.tm_hour = atoi(&value[11]);
727 tm.tm_min = atoi(&value[14]);
728 tm.tm_sec = atoi(&value[17]);
729
730 t = timegm(&tm);
731 i = 19;
732
733 /* fractions of a second */
734 if (value[i] == '.') {
735 ++i;
736 frac = &value[i];
737 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
738
739 i += frac_len;
740
741 /* skip trailing zeros */
742 for ( ; frac_len && (frac[frac_len - 1] == '0'); --frac_len) {}
743
744 if (!frac_len) {
745 /* only zeros, ignore */
746 frac = NULL;
747 }
748 } else {
749 frac = NULL;
750 }
751
752 /* apply offset */
753 if ((value[i] == 'Z') || (value[i] == 'z')) {
754 /* zero shift */
755 shift = 0;
756 } else {
757 shift = strtol(&value[i], NULL, 10);
758 shift = shift * 60 * 60; /* convert from hours to seconds */
759 shift_m = strtol(&value[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
760 /* correct sign */
761 if (shift < 0) {
762 shift_m *= -1;
763 }
764 /* connect hours and minutes of the shift */
765 shift = shift + shift_m;
766 }
767
768 /* we have to shift to the opposite way to correct the time */
769 t -= shift;
770
771 *time = t;
772 if (fractions_s) {
773 if (frac) {
774 *fractions_s = strndup(frac, frac_len);
775 LY_CHECK_RET(!*fractions_s, LY_EMEM);
776 } else {
777 *fractions_s = NULL;
778 }
779 }
780 return LY_SUCCESS;
781}
782
783API LY_ERR
784ly_time_time2str(time_t time, const char *fractions_s, char **str)
785{
786 struct tm tm;
787 char zoneshift[7];
788 int32_t zonediff_h, zonediff_m;
789
790 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
791
792 /* initialize the local timezone */
793 tzset();
794
795 /* convert */
796 if (!localtime_r(&time, &tm)) {
797 return LY_ESYS;
798 }
799
800 /* get timezone offset */
801 if (tm.tm_gmtoff == 0) {
802 /* time is Zulu (UTC) */
803 zonediff_h = 0;
804 zonediff_m = 0;
805 } else {
806 /* timezone offset */
807 zonediff_h = tm.tm_gmtoff / 60 / 60;
808 zonediff_m = tm.tm_gmtoff / 60 % 60;
809 }
810 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
811
812 /* print */
813 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
814 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
815 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
816 return LY_EMEM;
817 }
818
819 return LY_SUCCESS;
820}
821
822API LY_ERR
823ly_time_str2ts(const char *value, struct timespec *ts)
824{
825 LY_ERR rc;
826 char *fractions_s, frac_buf[10] = {'0'};
827 int frac_len;
828
829 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
830
831 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
832 LY_CHECK_RET(rc);
833
834 /* convert fractions of a second to nanoseconds */
835 if (fractions_s) {
836 frac_len = strlen(fractions_s);
837 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
838 ts->tv_nsec = atol(frac_buf);
839 free(fractions_s);
840 } else {
841 ts->tv_nsec = 0;
842 }
843
844 return LY_SUCCESS;
845}
846
847API LY_ERR
848ly_time_ts2str(const struct timespec *ts, char **str)
849{
850 char frac_buf[10];
851
852 LY_CHECK_ARG_RET(NULL, ts, str, LY_EINVAL);
853
854 /* convert nanoseconds to fractions of a second */
855 if (ts->tv_nsec) {
856 sprintf(frac_buf, "%09ld", ts->tv_nsec);
857 }
858
859 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
860}