blob: 89afee31bf5d7e36cff81852acc12d1a4d5ce1c4 [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 */
Radek Krejcif8dc59a2020-11-25 13:47:44 +010014#define _POSIX_C_SOURCE 200809L /* strdup, strndup */
Radek Krejcie7b95092019-05-15 11:03:07 +020015
16#include <assert.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020017#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020018#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020019#include <string.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020020
Radek Krejci535ea9f2020-05-29 16:01:05 +020021#include "common.h"
Michal Vasko6b5cb2a2020-11-11 19:11:21 +010022#include "compat.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020023#include "context.h"
Radek Krejci47fab892020-11-05 17:02:41 +010024#include "dict.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020025#include "hash_table.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020026#include "log.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020027#include "lyb.h"
Radek Krejci7931b192020-06-25 17:05:03 +020028#include "parser_data.h"
Michal Vaskoa820c312021-02-05 16:33:00 +010029#include "printer_data.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020030#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020031#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020033#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010034#include "tree_edit.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020035#include "tree_schema.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020036#include "tree_schema_internal.h"
Radek Krejci4f2e3e52021-03-30 14:20:28 +020037#include "validation.h"
Radek Krejci77114102021-03-10 15:21:57 +010038#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020039
Michal Vaskoa6669ba2020-08-06 16:14:26 +020040struct lyd_node *
41lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +020042 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +020043{
44 const struct lysc_node *siter = NULL;
45 struct lyd_node *match = NULL;
46
47 assert(parent || module);
48 assert(!last || (slast && *slast));
49
50 if (slast) {
51 siter = *slast;
52 }
53
54 if (last && last->next && (last->next->schema == siter)) {
55 /* return next data instance */
56 return last->next;
57 }
58
59 /* find next schema node data instance */
60 while ((siter = lys_getnext(siter, parent, module, 0))) {
61 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
62 break;
63 }
64 }
65
66 if (slast) {
67 *slast = siter;
68 }
69 return match;
70}
71
Radek Krejcie7b95092019-05-15 11:03:07 +020072struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +010073lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +020074{
75 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +010076
77 if (!node->schema) {
78 return &((struct lyd_node_opaq *)node)->child;
79 } else {
80 switch (node->schema->nodetype) {
81 case LYS_CONTAINER:
82 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +010083 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +010084 case LYS_ACTION:
85 case LYS_NOTIF:
86 return &((struct lyd_node_inner *)node)->child;
87 default:
88 return NULL;
89 }
Radek Krejcie7b95092019-05-15 11:03:07 +020090 }
91}
92
Radek Krejcidae0ee82020-05-06 16:53:24 +020093API struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +020094lyd_child_no_keys(const struct lyd_node *node)
95{
96 struct lyd_node **children;
97
98 if (!node) {
99 return NULL;
100 }
101
102 if (!node->schema) {
103 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100104 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200105 }
106
Michal Vaskoe0665742021-02-11 11:08:44 +0100107 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200108 if (children) {
109 struct lyd_node *child = *children;
110 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
111 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200112 }
113 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200114 } else {
115 return NULL;
116 }
117}
Michal Vasko9b368d32020-02-14 13:53:31 +0100118
Michal Vaskoc193ce92020-03-06 11:04:48 +0100119API const struct lys_module *
120lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100121{
122 const struct lysc_node *schema;
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100123 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100124
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100125 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100126 return NULL;
127 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100128
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100129 if (!node->schema) {
130 opaq = (struct lyd_node_opaq *)node;
131 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200132 case LY_VALUE_XML:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100133 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
Radek Krejci8df109d2021-04-23 12:19:08 +0200134 case LY_VALUE_JSON:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100135 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
136 default:
137 return NULL;
138 }
139 }
140
Radek Krejci1e008d22020-08-17 11:37:37 +0200141 for (schema = node->schema; schema->parent; schema = schema->parent) {}
Michal Vasko9b368d32020-02-14 13:53:31 +0100142 return schema->module;
143}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100144
145const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200146lyd_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 +0200147 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100148{
149 struct lyd_node *iter;
150 const struct lys_module *mod;
151
152 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200153 if (module) {
154 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100155 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200156 } else {
157 mod = module;
158 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100159 }
160 } else {
161 do {
162 mod = ly_ctx_get_module_iter(ctx, i);
163 } while (mod && !mod->implemented);
164 }
165
166 /* find its data */
167 *first = NULL;
168 if (mod) {
169 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100170 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100171 *first = iter;
172 break;
173 }
174 }
175 }
176
177 return mod;
178}
179
180const struct lys_module *
181lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
182{
183 const struct lys_module *mod;
184
185 if (!*next) {
186 /* all data traversed */
187 *first = NULL;
188 return NULL;
189 }
190
191 *first = *next;
192
193 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100194 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100195 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100196 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100197 break;
198 }
199 }
200
201 return mod;
202}
Michal Vasko9f96a052020-03-10 09:41:45 +0100203
204LY_ERR
205lyd_parse_check_keys(struct lyd_node *node)
206{
207 const struct lysc_node *skey = NULL;
208 const struct lyd_node *key;
209
210 assert(node->schema->nodetype == LYS_LIST);
211
Radek Krejcia1c1e542020-09-29 16:06:52 +0200212 key = lyd_child(node);
Michal Vasko9f96a052020-03-10 09:41:45 +0100213 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
214 if (!key || (key->schema != skey)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100215 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, skey->name);
Michal Vasko9f96a052020-03-10 09:41:45 +0100216 return LY_EVALID;
217 }
218
219 key = key->next;
220 }
221
222 return LY_SUCCESS;
223}
Michal Vasko60ea6352020-06-29 13:39:39 +0200224
225void
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200226lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *when_check, struct ly_set *exts_check, struct lyd_meta **meta,
227 uint32_t options)
Michal Vasko60ea6352020-06-29 13:39:39 +0200228{
229 struct lyd_meta *meta2, *prev_meta = NULL;
230
Michal Vaskoa5705e52020-12-09 18:15:14 +0100231 if (lysc_has_when(node->schema)) {
Michal Vasko0f3377d2020-11-09 20:56:11 +0100232 if (!(options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200233 /* remember we need to evaluate this node's when */
Radek Krejci3d92e442020-10-12 12:48:13 +0200234 LY_CHECK_RET(ly_set_add(when_check, node, 1, NULL), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200235 }
236 }
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200237 LY_CHECK_RET(lysc_node_ext_tovalidate(exts_check, node), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200238
Michal Vasko60ea6352020-06-29 13:39:39 +0200239 LY_LIST_FOR(*meta, meta2) {
Michal Vasko69730152020-10-09 16:30:07 +0200240 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
241 meta2->value.boolean) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200242 /* node is default according to the metadata */
243 node->flags |= LYD_DEFAULT;
244
245 /* delete the metadata */
246 if (prev_meta) {
247 prev_meta->next = meta2->next;
248 } else {
249 *meta = (*meta)->next;
250 }
Michal Vasko3a41dff2020-07-15 14:30:28 +0200251 lyd_free_meta_single(meta2);
Michal Vasko60ea6352020-06-29 13:39:39 +0200252 break;
253 }
254
255 prev_meta = meta2;
256 }
257}
258
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200259API const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400260lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200261{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200262 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
263
Michal Vasko33876022021-04-27 16:42:24 +0200264 return value->_canonical ? value->_canonical :
265 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200266}
267
Michal Vaskoc0004272020-08-06 08:32:34 +0200268API LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100269lyd_any_value_str(const struct lyd_node *any, char **value_str)
270{
271 const struct lyd_node_any *a;
272 struct lyd_node *tree = NULL;
273 const char *str = NULL;
274 ly_bool dynamic = 0;
275 LY_ERR ret = LY_SUCCESS;
276
277 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200278 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100279
280 a = (struct lyd_node_any *)any;
281 *value_str = NULL;
282
283 if (!a->value.str) {
284 /* there is no value in the union */
285 return LY_SUCCESS;
286 }
287
288 switch (a->value_type) {
289 case LYD_ANYDATA_LYB:
290 /* parse into a data tree */
291 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
292 LY_CHECK_GOTO(ret, cleanup);
293 dynamic = 1;
294 break;
295 case LYD_ANYDATA_DATATREE:
296 tree = a->value.tree;
297 break;
298 case LYD_ANYDATA_STRING:
299 case LYD_ANYDATA_XML:
300 case LYD_ANYDATA_JSON:
301 /* simply use the string */
302 str = a->value.str;
303 break;
304 }
305
306 if (tree) {
307 /* print into a string */
308 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
309 LY_CHECK_GOTO(ret, cleanup);
310 } else {
311 assert(str);
312 *value_str = strdup(str);
313 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
314 }
315
316 /* success */
317
318cleanup:
319 if (dynamic) {
320 lyd_free_all(tree);
321 }
322 return ret;
323}
324
325API LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200326lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
327{
328 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200329
Michal Vaskoa820c312021-02-05 16:33:00 +0100330 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200331 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200332
333 t = (struct lyd_node_any *)trg;
334
335 /* free trg */
336 switch (t->value_type) {
337 case LYD_ANYDATA_DATATREE:
338 lyd_free_all(t->value.tree);
339 break;
340 case LYD_ANYDATA_STRING:
341 case LYD_ANYDATA_XML:
342 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100343 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200344 break;
345 case LYD_ANYDATA_LYB:
346 free(t->value.mem);
347 break;
348 }
349 t->value.str = NULL;
350
351 if (!value) {
352 /* only free value in this case */
353 return LY_SUCCESS;
354 }
355
356 /* copy src */
357 t->value_type = value_type;
358 switch (value_type) {
359 case LYD_ANYDATA_DATATREE:
360 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200361 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200362 }
363 break;
364 case LYD_ANYDATA_STRING:
365 case LYD_ANYDATA_XML:
366 case LYD_ANYDATA_JSON:
367 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200368 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200369 }
370 break;
371 case LYD_ANYDATA_LYB:
372 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200373 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200374 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200375 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200376 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200377 memcpy(t->value.mem, value->mem, len);
378 }
379 break;
380 }
381
382 return LY_SUCCESS;
383}
384
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100385void
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100386lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
387{
388 if (*root && (lyd_owner_module(*root) != mod)) {
389 /* there are no data of mod so this is simply the first top-level sibling */
390 mod = NULL;
391 }
392
393 if ((*root != to_del) || (*root)->parent) {
394 return;
395 }
396
397 *root = (*root)->next;
398 if (mod && *root && (lyd_owner_module(to_del) != lyd_owner_module(*root))) {
399 /* there are no more nodes from mod */
400 *root = lyd_first_sibling(*root);
401 }
402}
403
404void
Radek Krejci8df109d2021-04-23 12:19:08 +0200405ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100406{
407 struct ly_set *ns_list;
408 struct lysc_prefix *prefixes;
409 uint32_t i;
410 LY_ARRAY_COUNT_TYPE u;
411
412 if (!prefix_data) {
413 return;
414 }
415
416 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200417 case LY_VALUE_XML:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100418 ns_list = prefix_data;
419 for (i = 0; i < ns_list->count; ++i) {
420 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
421 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
422 }
423 ly_set_free(ns_list, free);
424 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200425 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100426 prefixes = prefix_data;
427 LY_ARRAY_FOR(prefixes, u) {
428 free(prefixes[u].prefix);
429 }
430 LY_ARRAY_FREE(prefixes);
431 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200432 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200433 case LY_VALUE_SCHEMA:
434 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200435 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100436 break;
437 }
438}
439
440LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +0200441ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100442 void **prefix_data_p)
443{
444 LY_ERR ret = LY_SUCCESS;
445 struct lyxml_ns *ns;
446 struct lysc_prefix *prefixes = NULL, *orig_pref;
447 struct ly_set *ns_list, *orig_ns;
448 uint32_t i;
449 LY_ARRAY_COUNT_TYPE u;
450
451 assert(!*prefix_data_p);
452
453 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200454 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100455 *prefix_data_p = (void *)prefix_data;
456 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200457 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100458 /* copy all the value prefixes */
459 orig_pref = (struct lysc_prefix *)prefix_data;
460 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
461 *prefix_data_p = prefixes;
462
463 LY_ARRAY_FOR(orig_pref, u) {
464 if (orig_pref[u].prefix) {
465 prefixes[u].prefix = strdup(orig_pref[u].prefix);
466 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
467 }
468 prefixes[u].mod = orig_pref[u].mod;
469 LY_ARRAY_INCREMENT(prefixes);
470 }
471 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200472 case LY_VALUE_XML:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100473 /* copy all the namespaces */
474 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
475 *prefix_data_p = ns_list;
476
477 orig_ns = (struct ly_set *)prefix_data;
478 for (i = 0; i < orig_ns->count; ++i) {
479 ns = calloc(1, sizeof *ns);
480 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
481 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
482
483 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
484 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
485 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
486 }
487 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
488 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
489 }
490 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200491 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200492 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200493 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100494 assert(!prefix_data);
495 *prefix_data_p = NULL;
496 break;
497 }
498
499cleanup:
500 if (ret) {
501 ly_free_prefix_data(format, *prefix_data_p);
502 *prefix_data_p = NULL;
503 }
504 return ret;
505}
506
507LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +0200508ly_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 +0200509 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100510{
511 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100512 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100513 const struct lyxml_ns *ns;
514 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100515 struct ly_set *ns_list;
516 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +0200517 const char *value_iter, *value_next, *value_end;
518 uint32_t substr_len;
519 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100520
521 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200522 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100523 /* copy all referenced modules as prefix - module pairs */
524 if (!*prefix_data_p) {
525 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100526 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +0200527 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100528 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100529 } else {
530 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +0200531 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100532 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100533 }
534
535 /* add all used prefixes */
aPiecek83436bc2021-03-30 12:20:45 +0200536 value_end = value + value_len;
537 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +0200538 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 +0200539 if (is_prefix) {
540 /* we have a possible prefix. Do we already have the prefix? */
541 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
542 if (!mod) {
543 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
544 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200545 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +0200546 /* store a new prefix - module pair */
547 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
548 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100549
aPiecek83436bc2021-03-30 12:20:45 +0200550 val_pref->prefix = strndup(value_iter, substr_len);
551 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
552 val_pref->mod = mod;
553 } /* else it is not even defined */
554 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100555 }
556 }
557 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200558 case LY_VALUE_XML:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100559 /* copy all referenced namespaces as prefix - namespace pairs */
560 if (!*prefix_data_p) {
561 /* new prefix data */
562 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +0200563 *format_p = LY_VALUE_XML;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100564 *prefix_data_p = ns_list;
565 } else {
566 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +0200567 assert(*format_p == LY_VALUE_XML);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100568 ns_list = *prefix_data_p;
569 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100570
Michal Vaskofc2cd072021-02-24 13:17:17 +0100571 /* add all used prefixes */
aPiecek83436bc2021-03-30 12:20:45 +0200572 value_end = value + value_len;
573 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +0200574 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 +0200575 if (is_prefix) {
576 /* we have a possible prefix. Do we already have the prefix? */
577 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
578 if (!ns) {
579 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
580 if (ns) {
581 /* store a new prefix - namespace pair */
582 new_ns = calloc(1, sizeof *new_ns);
583 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
584 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100585
aPiecek83436bc2021-03-30 12:20:45 +0200586 new_ns->prefix = strndup(value_iter, substr_len);
587 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
588 new_ns->uri = strdup(ns->uri);
589 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
590 } /* else it is not even defined */
591 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100592 }
593 }
594 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200595 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200596 case LY_VALUE_SCHEMA_RESOLVED:
597 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200598 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100599 if (!*prefix_data_p) {
600 /* new prefix data - simply copy all the prefix data */
601 *format_p = format;
602 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
603 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100604 break;
605 }
606
607cleanup:
608 if (ret) {
609 ly_free_prefix_data(*format_p, *prefix_data_p);
610 *prefix_data_p = NULL;
611 }
612 return ret;
613}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100614
615const char *
Radek Krejci8df109d2021-04-23 12:19:08 +0200616ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100617{
618 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +0200619 case LY_VALUE_CANON:
620 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +0200621 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100622 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +0200623 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100624 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +0200625 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100626 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +0200627 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100628 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +0200629 case LY_VALUE_LYB:
630 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100631 default:
632 break;
633 }
634
635 return NULL;
636}