blob: 4632d5043d053412f14317c4d0d0f20da6b0510a [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"
Radek Krejci77114102021-03-10 15:21:57 +010029#include "plugins_types.h"
Michal Vaskoa820c312021-02-05 16:33:00 +010030#include "printer_data.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020031#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020032#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020033#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020034#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010035#include "tree_edit.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020036#include "tree_schema.h"
Radek Krejci77114102021-03-10 15:21:57 +010037#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020038
Michal Vaskoa6669ba2020-08-06 16:14:26 +020039struct lyd_node *
40lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +020041 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +020042{
43 const struct lysc_node *siter = NULL;
44 struct lyd_node *match = NULL;
45
46 assert(parent || module);
47 assert(!last || (slast && *slast));
48
49 if (slast) {
50 siter = *slast;
51 }
52
53 if (last && last->next && (last->next->schema == siter)) {
54 /* return next data instance */
55 return last->next;
56 }
57
58 /* find next schema node data instance */
59 while ((siter = lys_getnext(siter, parent, module, 0))) {
60 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
61 break;
62 }
63 }
64
65 if (slast) {
66 *slast = siter;
67 }
68 return match;
69}
70
Radek Krejcie7b95092019-05-15 11:03:07 +020071struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +010072lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +020073{
74 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +010075
76 if (!node->schema) {
77 return &((struct lyd_node_opaq *)node)->child;
78 } else {
79 switch (node->schema->nodetype) {
80 case LYS_CONTAINER:
81 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +010082 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +010083 case LYS_ACTION:
84 case LYS_NOTIF:
85 return &((struct lyd_node_inner *)node)->child;
86 default:
87 return NULL;
88 }
Radek Krejcie7b95092019-05-15 11:03:07 +020089 }
90}
91
Radek Krejcidae0ee82020-05-06 16:53:24 +020092API struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +020093lyd_child_no_keys(const struct lyd_node *node)
94{
95 struct lyd_node **children;
96
97 if (!node) {
98 return NULL;
99 }
100
101 if (!node->schema) {
102 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100103 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200104 }
105
Michal Vaskoe0665742021-02-11 11:08:44 +0100106 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200107 if (children) {
108 struct lyd_node *child = *children;
109 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
110 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200111 }
112 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200113 } else {
114 return NULL;
115 }
116}
Michal Vasko9b368d32020-02-14 13:53:31 +0100117
Michal Vaskoc193ce92020-03-06 11:04:48 +0100118API const struct lys_module *
119lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100120{
121 const struct lysc_node *schema;
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100122 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100123
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100124 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100125 return NULL;
126 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100127
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100128 if (!node->schema) {
129 opaq = (struct lyd_node_opaq *)node;
130 switch (opaq->format) {
131 case LY_PREF_XML:
132 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
133 case LY_PREF_JSON:
134 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
135 default:
136 return NULL;
137 }
138 }
139
Radek Krejci1e008d22020-08-17 11:37:37 +0200140 for (schema = node->schema; schema->parent; schema = schema->parent) {}
Michal Vasko9b368d32020-02-14 13:53:31 +0100141 return schema->module;
142}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100143
144const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200145lyd_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 +0200146 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100147{
148 struct lyd_node *iter;
149 const struct lys_module *mod;
150
151 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200152 if (module) {
153 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100154 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200155 } else {
156 mod = module;
157 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100158 }
159 } else {
160 do {
161 mod = ly_ctx_get_module_iter(ctx, i);
162 } while (mod && !mod->implemented);
163 }
164
165 /* find its data */
166 *first = NULL;
167 if (mod) {
168 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100169 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100170 *first = iter;
171 break;
172 }
173 }
174 }
175
176 return mod;
177}
178
179const struct lys_module *
180lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
181{
182 const struct lys_module *mod;
183
184 if (!*next) {
185 /* all data traversed */
186 *first = NULL;
187 return NULL;
188 }
189
190 *first = *next;
191
192 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100193 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100194 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100195 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100196 break;
197 }
198 }
199
200 return mod;
201}
Michal Vasko9f96a052020-03-10 09:41:45 +0100202
203LY_ERR
204lyd_parse_check_keys(struct lyd_node *node)
205{
206 const struct lysc_node *skey = NULL;
207 const struct lyd_node *key;
208
209 assert(node->schema->nodetype == LYS_LIST);
210
Radek Krejcia1c1e542020-09-29 16:06:52 +0200211 key = lyd_child(node);
Michal Vasko9f96a052020-03-10 09:41:45 +0100212 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
213 if (!key || (key->schema != skey)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100214 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, skey->name);
Michal Vasko9f96a052020-03-10 09:41:45 +0100215 return LY_EVALID;
216 }
217
218 key = key->next;
219 }
220
221 return LY_SUCCESS;
222}
Michal Vasko60ea6352020-06-29 13:39:39 +0200223
224void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200225lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *when_check, struct lyd_meta **meta, uint32_t options)
Michal Vasko60ea6352020-06-29 13:39:39 +0200226{
227 struct lyd_meta *meta2, *prev_meta = NULL;
228
Michal Vaskoa5705e52020-12-09 18:15:14 +0100229 if (lysc_has_when(node->schema)) {
Michal Vasko0f3377d2020-11-09 20:56:11 +0100230 if (!(options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200231 /* remember we need to evaluate this node's when */
Radek Krejci3d92e442020-10-12 12:48:13 +0200232 LY_CHECK_RET(ly_set_add(when_check, node, 1, NULL), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200233 }
234 }
235
Michal Vasko60ea6352020-06-29 13:39:39 +0200236 LY_LIST_FOR(*meta, meta2) {
Michal Vasko69730152020-10-09 16:30:07 +0200237 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
238 meta2->value.boolean) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200239 /* node is default according to the metadata */
240 node->flags |= LYD_DEFAULT;
241
242 /* delete the metadata */
243 if (prev_meta) {
244 prev_meta->next = meta2->next;
245 } else {
246 *meta = (*meta)->next;
247 }
Michal Vasko3a41dff2020-07-15 14:30:28 +0200248 lyd_free_meta_single(meta2);
Michal Vasko60ea6352020-06-29 13:39:39 +0200249 break;
250 }
251
252 prev_meta = meta2;
253 }
254}
255
Michal Vaskoc0004272020-08-06 08:32:34 +0200256API LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100257lyd_any_value_str(const struct lyd_node *any, char **value_str)
258{
259 const struct lyd_node_any *a;
260 struct lyd_node *tree = NULL;
261 const char *str = NULL;
262 ly_bool dynamic = 0;
263 LY_ERR ret = LY_SUCCESS;
264
265 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
266
267 a = (struct lyd_node_any *)any;
268 *value_str = NULL;
269
270 if (!a->value.str) {
271 /* there is no value in the union */
272 return LY_SUCCESS;
273 }
274
275 switch (a->value_type) {
276 case LYD_ANYDATA_LYB:
277 /* parse into a data tree */
278 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
279 LY_CHECK_GOTO(ret, cleanup);
280 dynamic = 1;
281 break;
282 case LYD_ANYDATA_DATATREE:
283 tree = a->value.tree;
284 break;
285 case LYD_ANYDATA_STRING:
286 case LYD_ANYDATA_XML:
287 case LYD_ANYDATA_JSON:
288 /* simply use the string */
289 str = a->value.str;
290 break;
291 }
292
293 if (tree) {
294 /* print into a string */
295 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
296 LY_CHECK_GOTO(ret, cleanup);
297 } else {
298 assert(str);
299 *value_str = strdup(str);
300 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
301 }
302
303 /* success */
304
305cleanup:
306 if (dynamic) {
307 lyd_free_all(tree);
308 }
309 return ret;
310}
311
312API LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200313lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
314{
315 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200316
Michal Vaskoa820c312021-02-05 16:33:00 +0100317 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200318
319 t = (struct lyd_node_any *)trg;
320
321 /* free trg */
322 switch (t->value_type) {
323 case LYD_ANYDATA_DATATREE:
324 lyd_free_all(t->value.tree);
325 break;
326 case LYD_ANYDATA_STRING:
327 case LYD_ANYDATA_XML:
328 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100329 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200330 break;
331 case LYD_ANYDATA_LYB:
332 free(t->value.mem);
333 break;
334 }
335 t->value.str = NULL;
336
337 if (!value) {
338 /* only free value in this case */
339 return LY_SUCCESS;
340 }
341
342 /* copy src */
343 t->value_type = value_type;
344 switch (value_type) {
345 case LYD_ANYDATA_DATATREE:
346 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200347 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200348 }
349 break;
350 case LYD_ANYDATA_STRING:
351 case LYD_ANYDATA_XML:
352 case LYD_ANYDATA_JSON:
353 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200354 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200355 }
356 break;
357 case LYD_ANYDATA_LYB:
358 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200359 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200360 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200361 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200362 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200363 memcpy(t->value.mem, value->mem, len);
364 }
365 break;
366 }
367
368 return LY_SUCCESS;
369}
370
Michal Vasko60ea6352020-06-29 13:39:39 +0200371LYB_HASH
372lyb_hash(struct lysc_node *sibling, uint8_t collision_id)
373{
374 const struct lys_module *mod;
Michal Vasko60ea6352020-06-29 13:39:39 +0200375 uint32_t full_hash;
376 LYB_HASH hash;
377
378 if ((collision_id < LYS_NODE_HASH_COUNT) && sibling->hash[collision_id]) {
379 return sibling->hash[collision_id];
380 }
381
382 mod = sibling->module;
383
384 full_hash = dict_hash_multi(0, mod->name, strlen(mod->name));
385 full_hash = dict_hash_multi(full_hash, sibling->name, strlen(sibling->name));
386 if (collision_id) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200387 size_t ext_len;
388
Michal Vasko60ea6352020-06-29 13:39:39 +0200389 if (collision_id > strlen(mod->name)) {
390 /* fine, we will not hash more bytes, just use more bits from the hash than previously */
391 ext_len = strlen(mod->name);
392 } else {
393 /* use one more byte from the module name than before */
394 ext_len = collision_id;
395 }
396 full_hash = dict_hash_multi(full_hash, mod->name, ext_len);
397 }
398 full_hash = dict_hash_multi(full_hash, NULL, 0);
399
400 /* use the shortened hash */
401 hash = full_hash & (LYB_HASH_MASK >> collision_id);
402 /* add colision identificator */
403 hash |= LYB_HASH_COLLISION_ID >> collision_id;
404
405 /* save this hash */
406 if (collision_id < LYS_NODE_HASH_COUNT) {
407 sibling->hash[collision_id] = hash;
408 }
409
410 return hash;
411}
412
Radek Krejci857189e2020-09-01 13:26:36 +0200413ly_bool
Michal Vasko60ea6352020-06-29 13:39:39 +0200414lyb_has_schema_model(const struct lysc_node *sibling, const struct lys_module **models)
415{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200416 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +0200417
418 LY_ARRAY_FOR(models, u) {
419 if (sibling->module == models[u]) {
420 return 1;
421 }
422 }
423
424 return 0;
425}
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100426
427void
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100428lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
429{
430 if (*root && (lyd_owner_module(*root) != mod)) {
431 /* there are no data of mod so this is simply the first top-level sibling */
432 mod = NULL;
433 }
434
435 if ((*root != to_del) || (*root)->parent) {
436 return;
437 }
438
439 *root = (*root)->next;
440 if (mod && *root && (lyd_owner_module(to_del) != lyd_owner_module(*root))) {
441 /* there are no more nodes from mod */
442 *root = lyd_first_sibling(*root);
443 }
444}
445
446void
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100447ly_free_prefix_data(LY_PREFIX_FORMAT format, void *prefix_data)
448{
449 struct ly_set *ns_list;
450 struct lysc_prefix *prefixes;
451 uint32_t i;
452 LY_ARRAY_COUNT_TYPE u;
453
454 if (!prefix_data) {
455 return;
456 }
457
458 switch (format) {
459 case LY_PREF_XML:
460 ns_list = prefix_data;
461 for (i = 0; i < ns_list->count; ++i) {
462 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
463 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
464 }
465 ly_set_free(ns_list, free);
466 break;
467 case LY_PREF_SCHEMA_RESOLVED:
468 prefixes = prefix_data;
469 LY_ARRAY_FOR(prefixes, u) {
470 free(prefixes[u].prefix);
471 }
472 LY_ARRAY_FREE(prefixes);
473 break;
474 case LY_PREF_SCHEMA:
475 case LY_PREF_JSON:
476 break;
477 }
478}
479
480LY_ERR
481ly_dup_prefix_data(const struct ly_ctx *ctx, LY_PREFIX_FORMAT format, const void *prefix_data,
482 void **prefix_data_p)
483{
484 LY_ERR ret = LY_SUCCESS;
485 struct lyxml_ns *ns;
486 struct lysc_prefix *prefixes = NULL, *orig_pref;
487 struct ly_set *ns_list, *orig_ns;
488 uint32_t i;
489 LY_ARRAY_COUNT_TYPE u;
490
491 assert(!*prefix_data_p);
492
493 switch (format) {
494 case LY_PREF_SCHEMA:
495 *prefix_data_p = (void *)prefix_data;
496 break;
497 case LY_PREF_SCHEMA_RESOLVED:
498 /* copy all the value prefixes */
499 orig_pref = (struct lysc_prefix *)prefix_data;
500 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
501 *prefix_data_p = prefixes;
502
503 LY_ARRAY_FOR(orig_pref, u) {
504 if (orig_pref[u].prefix) {
505 prefixes[u].prefix = strdup(orig_pref[u].prefix);
506 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
507 }
508 prefixes[u].mod = orig_pref[u].mod;
509 LY_ARRAY_INCREMENT(prefixes);
510 }
511 break;
512 case LY_PREF_XML:
513 /* copy all the namespaces */
514 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
515 *prefix_data_p = ns_list;
516
517 orig_ns = (struct ly_set *)prefix_data;
518 for (i = 0; i < orig_ns->count; ++i) {
519 ns = calloc(1, sizeof *ns);
520 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
521 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
522
523 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
524 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
525 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
526 }
527 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
528 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
529 }
530 break;
531 case LY_PREF_JSON:
532 assert(!prefix_data);
533 *prefix_data_p = NULL;
534 break;
535 }
536
537cleanup:
538 if (ret) {
539 ly_free_prefix_data(format, *prefix_data_p);
540 *prefix_data_p = NULL;
541 }
542 return ret;
543}
544
545LY_ERR
546ly_store_prefix_data(const struct ly_ctx *ctx, const char *value, size_t value_len, LY_PREFIX_FORMAT format,
547 void *prefix_data, LY_PREFIX_FORMAT *format_p, void **prefix_data_p)
548{
549 LY_ERR ret = LY_SUCCESS;
550 const char *start, *stop;
551 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100552 const struct lyxml_ns *ns;
553 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100554 struct ly_set *ns_list;
555 struct lysc_prefix *prefixes = NULL, *val_pref;
556
557 switch (format) {
558 case LY_PREF_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100559 /* copy all referenced modules as prefix - module pairs */
560 if (!*prefix_data_p) {
561 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100562 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
563 *format_p = LY_PREF_SCHEMA_RESOLVED;
564 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100565 } else {
566 /* reuse prefix data */
567 assert(*format_p == LY_PREF_SCHEMA_RESOLVED);
568 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100569 }
570
571 /* add all used prefixes */
572 for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
573 size_t bytes;
574 uint32_t c;
575
576 ly_getutf8(&stop, &c, &bytes);
577 if (is_xmlqnamestartchar(c)) {
578 for (ly_getutf8(&stop, &c, &bytes);
579 is_xmlqnamechar(c) && (size_t)(stop - value) < value_len;
580 ly_getutf8(&stop, &c, &bytes)) {}
581 stop = stop - bytes;
582 if (*stop == ':') {
583 /* we have a possible prefix */
584 size_t len = stop - start;
585
586 /* do we already have the prefix? */
Radek Krejci99052522021-03-15 20:04:06 +0100587 mod = ly_resolve_prefix(ctx, start, len, *format_p, *prefix_data_p);
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100588 if (!mod) {
Radek Krejci99052522021-03-15 20:04:06 +0100589 mod = ly_resolve_prefix(ctx, start, len, format, prefix_data);
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100590 if (mod) {
Michal Vaskofc2cd072021-02-24 13:17:17 +0100591 assert(*format_p == LY_PREF_SCHEMA_RESOLVED);
592 /* store a new prefix - module pair */
593 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
594 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100595
Michal Vaskofc2cd072021-02-24 13:17:17 +0100596 val_pref->prefix = strndup(start, len);
597 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
598 val_pref->mod = mod;
599 } /* else it is not even defined */
600 } /* else the prefix is already present */
601 }
602 stop = stop + bytes;
603 }
604 }
605 break;
606 case LY_PREF_XML:
607 /* copy all referenced namespaces as prefix - namespace pairs */
608 if (!*prefix_data_p) {
609 /* new prefix data */
610 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
611 *format_p = LY_PREF_XML;
612 *prefix_data_p = ns_list;
613 } else {
614 /* reuse prefix data */
615 assert(*format_p == LY_PREF_XML);
616 ns_list = *prefix_data_p;
617 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100618
Michal Vaskofc2cd072021-02-24 13:17:17 +0100619 /* add all used prefixes */
620 for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
621 size_t bytes;
622 uint32_t c;
623
624 ly_getutf8(&stop, &c, &bytes);
625 if (is_xmlqnamestartchar(c)) {
626 for (ly_getutf8(&stop, &c, &bytes);
627 is_xmlqnamechar(c) && (size_t)(stop - value) < value_len;
628 ly_getutf8(&stop, &c, &bytes)) {}
629 stop = stop - bytes;
630 if (*stop == ':') {
631 /* we have a possible prefix */
632 size_t len = stop - start;
633
634 /* do we already have the prefix? */
635 ns = lyxml_ns_get(ns_list, start, len);
636 if (!ns) {
637 ns = lyxml_ns_get(prefix_data, start, len);
638 if (ns) {
639 /* store a new prefix - namespace pair */
640 new_ns = calloc(1, sizeof *new_ns);
641 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
642 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
643
644 new_ns->prefix = strndup(start, len);
645 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
646 new_ns->uri = strdup(ns->uri);
647 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100648 } /* else it is not even defined */
649 } /* else the prefix is already present */
650 }
651 stop = stop + bytes;
652 }
653 }
654 break;
655 case LY_PREF_SCHEMA_RESOLVED:
656 case LY_PREF_JSON:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100657 if (!*prefix_data_p) {
658 /* new prefix data - simply copy all the prefix data */
659 *format_p = format;
660 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
661 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100662 break;
663 }
664
665cleanup:
666 if (ret) {
667 ly_free_prefix_data(*format_p, *prefix_data_p);
668 *prefix_data_p = NULL;
669 }
670 return ret;
671}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100672
673const char *
674ly_format2str(LY_PREFIX_FORMAT format)
675{
676 switch (format) {
677 case LY_PREF_SCHEMA:
678 return "schema imports";
679 case LY_PREF_SCHEMA_RESOLVED:
680 return "schema stored mapping";
681 case LY_PREF_XML:
682 return "XML prefixes";
683 case LY_PREF_JSON:
684 return "JSON module names";
685 default:
686 break;
687 }
688
689 return NULL;
690}