blob: 168869acf669a9ade95dfae248cce71da0aaa5f7 [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"
36
Michal Vaskoa6669ba2020-08-06 16:14:26 +020037struct lyd_node *
38lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +020039 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +020040{
41 const struct lysc_node *siter = NULL;
42 struct lyd_node *match = NULL;
43
44 assert(parent || module);
45 assert(!last || (slast && *slast));
46
47 if (slast) {
48 siter = *slast;
49 }
50
51 if (last && last->next && (last->next->schema == siter)) {
52 /* return next data instance */
53 return last->next;
54 }
55
56 /* find next schema node data instance */
57 while ((siter = lys_getnext(siter, parent, module, 0))) {
58 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
59 break;
60 }
61 }
62
63 if (slast) {
64 *slast = siter;
65 }
66 return match;
67}
68
Radek Krejcie7b95092019-05-15 11:03:07 +020069struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +010070lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +020071{
72 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +010073
74 if (!node->schema) {
75 return &((struct lyd_node_opaq *)node)->child;
76 } else {
77 switch (node->schema->nodetype) {
78 case LYS_CONTAINER:
79 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +010080 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +010081 case LYS_ACTION:
82 case LYS_NOTIF:
83 return &((struct lyd_node_inner *)node)->child;
84 default:
85 return NULL;
86 }
Radek Krejcie7b95092019-05-15 11:03:07 +020087 }
88}
89
Radek Krejcidae0ee82020-05-06 16:53:24 +020090API struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +020091lyd_child_no_keys(const struct lyd_node *node)
92{
93 struct lyd_node **children;
94
95 if (!node) {
96 return NULL;
97 }
98
99 if (!node->schema) {
100 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100101 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200102 }
103
Michal Vaskoe0665742021-02-11 11:08:44 +0100104 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200105 if (children) {
106 struct lyd_node *child = *children;
107 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
108 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200109 }
110 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200111 } else {
112 return NULL;
113 }
114}
Michal Vasko9b368d32020-02-14 13:53:31 +0100115
Michal Vaskoc193ce92020-03-06 11:04:48 +0100116API const struct lys_module *
117lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100118{
119 const struct lysc_node *schema;
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100120 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100121
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100122 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100123 return NULL;
124 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100125
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100126 if (!node->schema) {
127 opaq = (struct lyd_node_opaq *)node;
128 switch (opaq->format) {
129 case LY_PREF_XML:
130 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
131 case LY_PREF_JSON:
132 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
133 default:
134 return NULL;
135 }
136 }
137
Radek Krejci1e008d22020-08-17 11:37:37 +0200138 for (schema = node->schema; schema->parent; schema = schema->parent) {}
Michal Vasko9b368d32020-02-14 13:53:31 +0100139 return schema->module;
140}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100141
142const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200143lyd_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 +0200144 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100145{
146 struct lyd_node *iter;
147 const struct lys_module *mod;
148
149 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200150 if (module) {
151 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100152 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200153 } else {
154 mod = module;
155 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100156 }
157 } else {
158 do {
159 mod = ly_ctx_get_module_iter(ctx, i);
160 } while (mod && !mod->implemented);
161 }
162
163 /* find its data */
164 *first = NULL;
165 if (mod) {
166 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100167 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100168 *first = iter;
169 break;
170 }
171 }
172 }
173
174 return mod;
175}
176
177const struct lys_module *
178lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
179{
180 const struct lys_module *mod;
181
182 if (!*next) {
183 /* all data traversed */
184 *first = NULL;
185 return NULL;
186 }
187
188 *first = *next;
189
190 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100191 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100192 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100193 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100194 break;
195 }
196 }
197
198 return mod;
199}
Michal Vasko9f96a052020-03-10 09:41:45 +0100200
201LY_ERR
202lyd_parse_check_keys(struct lyd_node *node)
203{
204 const struct lysc_node *skey = NULL;
205 const struct lyd_node *key;
206
207 assert(node->schema->nodetype == LYS_LIST);
208
Radek Krejcia1c1e542020-09-29 16:06:52 +0200209 key = lyd_child(node);
Michal Vasko9f96a052020-03-10 09:41:45 +0100210 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
211 if (!key || (key->schema != skey)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100212 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, skey->name);
Michal Vasko9f96a052020-03-10 09:41:45 +0100213 return LY_EVALID;
214 }
215
216 key = key->next;
217 }
218
219 return LY_SUCCESS;
220}
Michal Vasko60ea6352020-06-29 13:39:39 +0200221
222void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200223lyd_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 +0200224{
225 struct lyd_meta *meta2, *prev_meta = NULL;
226
Michal Vaskoa5705e52020-12-09 18:15:14 +0100227 if (lysc_has_when(node->schema)) {
Michal Vasko0f3377d2020-11-09 20:56:11 +0100228 if (!(options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200229 /* remember we need to evaluate this node's when */
Radek Krejci3d92e442020-10-12 12:48:13 +0200230 LY_CHECK_RET(ly_set_add(when_check, node, 1, NULL), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200231 }
232 }
233
Michal Vasko60ea6352020-06-29 13:39:39 +0200234 LY_LIST_FOR(*meta, meta2) {
Michal Vasko69730152020-10-09 16:30:07 +0200235 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
236 meta2->value.boolean) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200237 /* node is default according to the metadata */
238 node->flags |= LYD_DEFAULT;
239
240 /* delete the metadata */
241 if (prev_meta) {
242 prev_meta->next = meta2->next;
243 } else {
244 *meta = (*meta)->next;
245 }
Michal Vasko3a41dff2020-07-15 14:30:28 +0200246 lyd_free_meta_single(meta2);
Michal Vasko60ea6352020-06-29 13:39:39 +0200247 break;
248 }
249
250 prev_meta = meta2;
251 }
252}
253
Michal Vaskoc0004272020-08-06 08:32:34 +0200254API LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100255lyd_any_value_str(const struct lyd_node *any, char **value_str)
256{
257 const struct lyd_node_any *a;
258 struct lyd_node *tree = NULL;
259 const char *str = NULL;
260 ly_bool dynamic = 0;
261 LY_ERR ret = LY_SUCCESS;
262
263 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
264
265 a = (struct lyd_node_any *)any;
266 *value_str = NULL;
267
268 if (!a->value.str) {
269 /* there is no value in the union */
270 return LY_SUCCESS;
271 }
272
273 switch (a->value_type) {
274 case LYD_ANYDATA_LYB:
275 /* parse into a data tree */
276 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
277 LY_CHECK_GOTO(ret, cleanup);
278 dynamic = 1;
279 break;
280 case LYD_ANYDATA_DATATREE:
281 tree = a->value.tree;
282 break;
283 case LYD_ANYDATA_STRING:
284 case LYD_ANYDATA_XML:
285 case LYD_ANYDATA_JSON:
286 /* simply use the string */
287 str = a->value.str;
288 break;
289 }
290
291 if (tree) {
292 /* print into a string */
293 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
294 LY_CHECK_GOTO(ret, cleanup);
295 } else {
296 assert(str);
297 *value_str = strdup(str);
298 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
299 }
300
301 /* success */
302
303cleanup:
304 if (dynamic) {
305 lyd_free_all(tree);
306 }
307 return ret;
308}
309
310API LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200311lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
312{
313 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200314
Michal Vaskoa820c312021-02-05 16:33:00 +0100315 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200316
317 t = (struct lyd_node_any *)trg;
318
319 /* free trg */
320 switch (t->value_type) {
321 case LYD_ANYDATA_DATATREE:
322 lyd_free_all(t->value.tree);
323 break;
324 case LYD_ANYDATA_STRING:
325 case LYD_ANYDATA_XML:
326 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100327 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200328 break;
329 case LYD_ANYDATA_LYB:
330 free(t->value.mem);
331 break;
332 }
333 t->value.str = NULL;
334
335 if (!value) {
336 /* only free value in this case */
337 return LY_SUCCESS;
338 }
339
340 /* copy src */
341 t->value_type = value_type;
342 switch (value_type) {
343 case LYD_ANYDATA_DATATREE:
344 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200345 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200346 }
347 break;
348 case LYD_ANYDATA_STRING:
349 case LYD_ANYDATA_XML:
350 case LYD_ANYDATA_JSON:
351 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200352 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200353 }
354 break;
355 case LYD_ANYDATA_LYB:
356 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200357 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200358 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200359 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200360 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200361 memcpy(t->value.mem, value->mem, len);
362 }
363 break;
364 }
365
366 return LY_SUCCESS;
367}
368
Michal Vasko60ea6352020-06-29 13:39:39 +0200369LYB_HASH
370lyb_hash(struct lysc_node *sibling, uint8_t collision_id)
371{
372 const struct lys_module *mod;
Michal Vasko60ea6352020-06-29 13:39:39 +0200373 uint32_t full_hash;
374 LYB_HASH hash;
375
376 if ((collision_id < LYS_NODE_HASH_COUNT) && sibling->hash[collision_id]) {
377 return sibling->hash[collision_id];
378 }
379
380 mod = sibling->module;
381
382 full_hash = dict_hash_multi(0, mod->name, strlen(mod->name));
383 full_hash = dict_hash_multi(full_hash, sibling->name, strlen(sibling->name));
384 if (collision_id) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200385 size_t ext_len;
386
Michal Vasko60ea6352020-06-29 13:39:39 +0200387 if (collision_id > strlen(mod->name)) {
388 /* fine, we will not hash more bytes, just use more bits from the hash than previously */
389 ext_len = strlen(mod->name);
390 } else {
391 /* use one more byte from the module name than before */
392 ext_len = collision_id;
393 }
394 full_hash = dict_hash_multi(full_hash, mod->name, ext_len);
395 }
396 full_hash = dict_hash_multi(full_hash, NULL, 0);
397
398 /* use the shortened hash */
399 hash = full_hash & (LYB_HASH_MASK >> collision_id);
400 /* add colision identificator */
401 hash |= LYB_HASH_COLLISION_ID >> collision_id;
402
403 /* save this hash */
404 if (collision_id < LYS_NODE_HASH_COUNT) {
405 sibling->hash[collision_id] = hash;
406 }
407
408 return hash;
409}
410
Radek Krejci857189e2020-09-01 13:26:36 +0200411ly_bool
Michal Vasko60ea6352020-06-29 13:39:39 +0200412lyb_has_schema_model(const struct lysc_node *sibling, const struct lys_module **models)
413{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200414 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +0200415
416 LY_ARRAY_FOR(models, u) {
417 if (sibling->module == models[u]) {
418 return 1;
419 }
420 }
421
422 return 0;
423}
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100424
425void
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100426lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
427{
428 if (*root && (lyd_owner_module(*root) != mod)) {
429 /* there are no data of mod so this is simply the first top-level sibling */
430 mod = NULL;
431 }
432
433 if ((*root != to_del) || (*root)->parent) {
434 return;
435 }
436
437 *root = (*root)->next;
438 if (mod && *root && (lyd_owner_module(to_del) != lyd_owner_module(*root))) {
439 /* there are no more nodes from mod */
440 *root = lyd_first_sibling(*root);
441 }
442}
443
444void
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100445ly_free_prefix_data(LY_PREFIX_FORMAT format, void *prefix_data)
446{
447 struct ly_set *ns_list;
448 struct lysc_prefix *prefixes;
449 uint32_t i;
450 LY_ARRAY_COUNT_TYPE u;
451
452 if (!prefix_data) {
453 return;
454 }
455
456 switch (format) {
457 case LY_PREF_XML:
458 ns_list = prefix_data;
459 for (i = 0; i < ns_list->count; ++i) {
460 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
461 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
462 }
463 ly_set_free(ns_list, free);
464 break;
465 case LY_PREF_SCHEMA_RESOLVED:
466 prefixes = prefix_data;
467 LY_ARRAY_FOR(prefixes, u) {
468 free(prefixes[u].prefix);
469 }
470 LY_ARRAY_FREE(prefixes);
471 break;
472 case LY_PREF_SCHEMA:
473 case LY_PREF_JSON:
474 break;
475 }
476}
477
478LY_ERR
479ly_dup_prefix_data(const struct ly_ctx *ctx, LY_PREFIX_FORMAT format, const void *prefix_data,
480 void **prefix_data_p)
481{
482 LY_ERR ret = LY_SUCCESS;
483 struct lyxml_ns *ns;
484 struct lysc_prefix *prefixes = NULL, *orig_pref;
485 struct ly_set *ns_list, *orig_ns;
486 uint32_t i;
487 LY_ARRAY_COUNT_TYPE u;
488
489 assert(!*prefix_data_p);
490
491 switch (format) {
492 case LY_PREF_SCHEMA:
493 *prefix_data_p = (void *)prefix_data;
494 break;
495 case LY_PREF_SCHEMA_RESOLVED:
496 /* copy all the value prefixes */
497 orig_pref = (struct lysc_prefix *)prefix_data;
498 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
499 *prefix_data_p = prefixes;
500
501 LY_ARRAY_FOR(orig_pref, u) {
502 if (orig_pref[u].prefix) {
503 prefixes[u].prefix = strdup(orig_pref[u].prefix);
504 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
505 }
506 prefixes[u].mod = orig_pref[u].mod;
507 LY_ARRAY_INCREMENT(prefixes);
508 }
509 break;
510 case LY_PREF_XML:
511 /* copy all the namespaces */
512 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
513 *prefix_data_p = ns_list;
514
515 orig_ns = (struct ly_set *)prefix_data;
516 for (i = 0; i < orig_ns->count; ++i) {
517 ns = calloc(1, sizeof *ns);
518 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
519 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
520
521 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
522 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
523 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
524 }
525 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
526 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
527 }
528 break;
529 case LY_PREF_JSON:
530 assert(!prefix_data);
531 *prefix_data_p = NULL;
532 break;
533 }
534
535cleanup:
536 if (ret) {
537 ly_free_prefix_data(format, *prefix_data_p);
538 *prefix_data_p = NULL;
539 }
540 return ret;
541}
542
543LY_ERR
544ly_store_prefix_data(const struct ly_ctx *ctx, const char *value, size_t value_len, LY_PREFIX_FORMAT format,
545 void *prefix_data, LY_PREFIX_FORMAT *format_p, void **prefix_data_p)
546{
547 LY_ERR ret = LY_SUCCESS;
548 const char *start, *stop;
549 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100550 const struct lyxml_ns *ns;
551 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100552 struct ly_set *ns_list;
553 struct lysc_prefix *prefixes = NULL, *val_pref;
554
555 switch (format) {
556 case LY_PREF_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100557 /* copy all referenced modules as prefix - module pairs */
558 if (!*prefix_data_p) {
559 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100560 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
561 *format_p = LY_PREF_SCHEMA_RESOLVED;
562 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100563 } else {
564 /* reuse prefix data */
565 assert(*format_p == LY_PREF_SCHEMA_RESOLVED);
566 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100567 }
568
569 /* add all used prefixes */
570 for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
571 size_t bytes;
572 uint32_t c;
573
574 ly_getutf8(&stop, &c, &bytes);
575 if (is_xmlqnamestartchar(c)) {
576 for (ly_getutf8(&stop, &c, &bytes);
577 is_xmlqnamechar(c) && (size_t)(stop - value) < value_len;
578 ly_getutf8(&stop, &c, &bytes)) {}
579 stop = stop - bytes;
580 if (*stop == ':') {
581 /* we have a possible prefix */
582 size_t len = stop - start;
583
584 /* do we already have the prefix? */
585 mod = ly_type_store_resolve_prefix(ctx, start, len, *format_p, *prefix_data_p);
586 if (!mod) {
587 mod = ly_type_store_resolve_prefix(ctx, start, len, format, prefix_data);
588 if (mod) {
Michal Vaskofc2cd072021-02-24 13:17:17 +0100589 assert(*format_p == LY_PREF_SCHEMA_RESOLVED);
590 /* store a new prefix - module pair */
591 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
592 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100593
Michal Vaskofc2cd072021-02-24 13:17:17 +0100594 val_pref->prefix = strndup(start, len);
595 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
596 val_pref->mod = mod;
597 } /* else it is not even defined */
598 } /* else the prefix is already present */
599 }
600 stop = stop + bytes;
601 }
602 }
603 break;
604 case LY_PREF_XML:
605 /* copy all referenced namespaces as prefix - namespace pairs */
606 if (!*prefix_data_p) {
607 /* new prefix data */
608 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
609 *format_p = LY_PREF_XML;
610 *prefix_data_p = ns_list;
611 } else {
612 /* reuse prefix data */
613 assert(*format_p == LY_PREF_XML);
614 ns_list = *prefix_data_p;
615 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100616
Michal Vaskofc2cd072021-02-24 13:17:17 +0100617 /* add all used prefixes */
618 for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
619 size_t bytes;
620 uint32_t c;
621
622 ly_getutf8(&stop, &c, &bytes);
623 if (is_xmlqnamestartchar(c)) {
624 for (ly_getutf8(&stop, &c, &bytes);
625 is_xmlqnamechar(c) && (size_t)(stop - value) < value_len;
626 ly_getutf8(&stop, &c, &bytes)) {}
627 stop = stop - bytes;
628 if (*stop == ':') {
629 /* we have a possible prefix */
630 size_t len = stop - start;
631
632 /* do we already have the prefix? */
633 ns = lyxml_ns_get(ns_list, start, len);
634 if (!ns) {
635 ns = lyxml_ns_get(prefix_data, start, len);
636 if (ns) {
637 /* store a new prefix - namespace pair */
638 new_ns = calloc(1, sizeof *new_ns);
639 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
640 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
641
642 new_ns->prefix = strndup(start, len);
643 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
644 new_ns->uri = strdup(ns->uri);
645 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100646 } /* else it is not even defined */
647 } /* else the prefix is already present */
648 }
649 stop = stop + bytes;
650 }
651 }
652 break;
653 case LY_PREF_SCHEMA_RESOLVED:
654 case LY_PREF_JSON:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100655 if (!*prefix_data_p) {
656 /* new prefix data - simply copy all the prefix data */
657 *format_p = format;
658 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
659 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100660 break;
661 }
662
663cleanup:
664 if (ret) {
665 ly_free_prefix_data(*format_p, *prefix_data_p);
666 *prefix_data_p = NULL;
667 }
668 return ret;
669}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100670
671const char *
672ly_format2str(LY_PREFIX_FORMAT format)
673{
674 switch (format) {
675 case LY_PREF_SCHEMA:
676 return "schema imports";
677 case LY_PREF_SCHEMA_RESOLVED:
678 return "schema stored mapping";
679 case LY_PREF_XML:
680 return "XML prefixes";
681 case LY_PREF_JSON:
682 return "JSON module names";
683 default:
684 break;
685 }
686
687 return NULL;
688}