blob: 705b625063e2d58873e637c34f7b5a1f82ce6b52 [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 Krejcie7b95092019-05-15 11:03:07 +020034#include "tree_schema.h"
35
Michal Vaskoa6669ba2020-08-06 16:14:26 +020036struct lyd_node *
37lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +020038 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +020039{
40 const struct lysc_node *siter = NULL;
41 struct lyd_node *match = NULL;
42
43 assert(parent || module);
44 assert(!last || (slast && *slast));
45
46 if (slast) {
47 siter = *slast;
48 }
49
50 if (last && last->next && (last->next->schema == siter)) {
51 /* return next data instance */
52 return last->next;
53 }
54
55 /* find next schema node data instance */
56 while ((siter = lys_getnext(siter, parent, module, 0))) {
57 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
58 break;
59 }
60 }
61
62 if (slast) {
63 *slast = siter;
64 }
65 return match;
66}
67
Radek Krejcie7b95092019-05-15 11:03:07 +020068struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +010069lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +020070{
71 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +010072
73 if (!node->schema) {
74 return &((struct lyd_node_opaq *)node)->child;
75 } else {
76 switch (node->schema->nodetype) {
77 case LYS_CONTAINER:
78 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +010079 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +010080 case LYS_ACTION:
81 case LYS_NOTIF:
82 return &((struct lyd_node_inner *)node)->child;
83 default:
84 return NULL;
85 }
Radek Krejcie7b95092019-05-15 11:03:07 +020086 }
87}
88
Radek Krejcidae0ee82020-05-06 16:53:24 +020089API struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +020090lyd_child_no_keys(const struct lyd_node *node)
91{
92 struct lyd_node **children;
93
94 if (!node) {
95 return NULL;
96 }
97
98 if (!node->schema) {
99 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100100 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200101 }
102
Michal Vaskoe0665742021-02-11 11:08:44 +0100103 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200104 if (children) {
105 struct lyd_node *child = *children;
106 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
107 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200108 }
109 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200110 } else {
111 return NULL;
112 }
113}
Michal Vasko9b368d32020-02-14 13:53:31 +0100114
Michal Vaskoc193ce92020-03-06 11:04:48 +0100115API const struct lys_module *
116lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100117{
118 const struct lysc_node *schema;
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100119 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100120
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100121 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100122 return NULL;
123 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100124
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100125 if (!node->schema) {
126 opaq = (struct lyd_node_opaq *)node;
127 switch (opaq->format) {
128 case LY_PREF_XML:
129 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
130 case LY_PREF_JSON:
131 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
132 default:
133 return NULL;
134 }
135 }
136
Radek Krejci1e008d22020-08-17 11:37:37 +0200137 for (schema = node->schema; schema->parent; schema = schema->parent) {}
Michal Vasko9b368d32020-02-14 13:53:31 +0100138 return schema->module;
139}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100140
141const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200142lyd_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 +0200143 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100144{
145 struct lyd_node *iter;
146 const struct lys_module *mod;
147
148 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200149 if (module) {
150 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100151 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200152 } else {
153 mod = module;
154 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100155 }
156 } else {
157 do {
158 mod = ly_ctx_get_module_iter(ctx, i);
159 } while (mod && !mod->implemented);
160 }
161
162 /* find its data */
163 *first = NULL;
164 if (mod) {
165 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100166 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100167 *first = iter;
168 break;
169 }
170 }
171 }
172
173 return mod;
174}
175
176const struct lys_module *
177lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
178{
179 const struct lys_module *mod;
180
181 if (!*next) {
182 /* all data traversed */
183 *first = NULL;
184 return NULL;
185 }
186
187 *first = *next;
188
189 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100190 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100191 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100192 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100193 break;
194 }
195 }
196
197 return mod;
198}
Michal Vasko9f96a052020-03-10 09:41:45 +0100199
200LY_ERR
201lyd_parse_check_keys(struct lyd_node *node)
202{
203 const struct lysc_node *skey = NULL;
204 const struct lyd_node *key;
205
206 assert(node->schema->nodetype == LYS_LIST);
207
Radek Krejcia1c1e542020-09-29 16:06:52 +0200208 key = lyd_child(node);
Michal Vasko9f96a052020-03-10 09:41:45 +0100209 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
210 if (!key || (key->schema != skey)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100211 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, skey->name);
Michal Vasko9f96a052020-03-10 09:41:45 +0100212 return LY_EVALID;
213 }
214
215 key = key->next;
216 }
217
218 return LY_SUCCESS;
219}
Michal Vasko60ea6352020-06-29 13:39:39 +0200220
221void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200222lyd_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 +0200223{
224 struct lyd_meta *meta2, *prev_meta = NULL;
225
Michal Vaskoa5705e52020-12-09 18:15:14 +0100226 if (lysc_has_when(node->schema)) {
Michal Vasko0f3377d2020-11-09 20:56:11 +0100227 if (!(options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200228 /* remember we need to evaluate this node's when */
Radek Krejci3d92e442020-10-12 12:48:13 +0200229 LY_CHECK_RET(ly_set_add(when_check, node, 1, NULL), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200230 }
231 }
232
Michal Vasko60ea6352020-06-29 13:39:39 +0200233 LY_LIST_FOR(*meta, meta2) {
Michal Vasko69730152020-10-09 16:30:07 +0200234 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
235 meta2->value.boolean) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200236 /* node is default according to the metadata */
237 node->flags |= LYD_DEFAULT;
238
239 /* delete the metadata */
240 if (prev_meta) {
241 prev_meta->next = meta2->next;
242 } else {
243 *meta = (*meta)->next;
244 }
Michal Vasko3a41dff2020-07-15 14:30:28 +0200245 lyd_free_meta_single(meta2);
Michal Vasko60ea6352020-06-29 13:39:39 +0200246 break;
247 }
248
249 prev_meta = meta2;
250 }
251}
252
Michal Vaskoc0004272020-08-06 08:32:34 +0200253API LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100254lyd_any_value_str(const struct lyd_node *any, char **value_str)
255{
256 const struct lyd_node_any *a;
257 struct lyd_node *tree = NULL;
258 const char *str = NULL;
259 ly_bool dynamic = 0;
260 LY_ERR ret = LY_SUCCESS;
261
262 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
263
264 a = (struct lyd_node_any *)any;
265 *value_str = NULL;
266
267 if (!a->value.str) {
268 /* there is no value in the union */
269 return LY_SUCCESS;
270 }
271
272 switch (a->value_type) {
273 case LYD_ANYDATA_LYB:
274 /* parse into a data tree */
275 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
276 LY_CHECK_GOTO(ret, cleanup);
277 dynamic = 1;
278 break;
279 case LYD_ANYDATA_DATATREE:
280 tree = a->value.tree;
281 break;
282 case LYD_ANYDATA_STRING:
283 case LYD_ANYDATA_XML:
284 case LYD_ANYDATA_JSON:
285 /* simply use the string */
286 str = a->value.str;
287 break;
288 }
289
290 if (tree) {
291 /* print into a string */
292 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
293 LY_CHECK_GOTO(ret, cleanup);
294 } else {
295 assert(str);
296 *value_str = strdup(str);
297 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
298 }
299
300 /* success */
301
302cleanup:
303 if (dynamic) {
304 lyd_free_all(tree);
305 }
306 return ret;
307}
308
309API LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200310lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
311{
312 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200313
Michal Vaskoa820c312021-02-05 16:33:00 +0100314 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200315
316 t = (struct lyd_node_any *)trg;
317
318 /* free trg */
319 switch (t->value_type) {
320 case LYD_ANYDATA_DATATREE:
321 lyd_free_all(t->value.tree);
322 break;
323 case LYD_ANYDATA_STRING:
324 case LYD_ANYDATA_XML:
325 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100326 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200327 break;
328 case LYD_ANYDATA_LYB:
329 free(t->value.mem);
330 break;
331 }
332 t->value.str = NULL;
333
334 if (!value) {
335 /* only free value in this case */
336 return LY_SUCCESS;
337 }
338
339 /* copy src */
340 t->value_type = value_type;
341 switch (value_type) {
342 case LYD_ANYDATA_DATATREE:
343 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200344 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200345 }
346 break;
347 case LYD_ANYDATA_STRING:
348 case LYD_ANYDATA_XML:
349 case LYD_ANYDATA_JSON:
350 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200351 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200352 }
353 break;
354 case LYD_ANYDATA_LYB:
355 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200356 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200357 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200358 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200359 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200360 memcpy(t->value.mem, value->mem, len);
361 }
362 break;
363 }
364
365 return LY_SUCCESS;
366}
367
Michal Vasko60ea6352020-06-29 13:39:39 +0200368LYB_HASH
369lyb_hash(struct lysc_node *sibling, uint8_t collision_id)
370{
371 const struct lys_module *mod;
Michal Vasko60ea6352020-06-29 13:39:39 +0200372 uint32_t full_hash;
373 LYB_HASH hash;
374
375 if ((collision_id < LYS_NODE_HASH_COUNT) && sibling->hash[collision_id]) {
376 return sibling->hash[collision_id];
377 }
378
379 mod = sibling->module;
380
381 full_hash = dict_hash_multi(0, mod->name, strlen(mod->name));
382 full_hash = dict_hash_multi(full_hash, sibling->name, strlen(sibling->name));
383 if (collision_id) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200384 size_t ext_len;
385
Michal Vasko60ea6352020-06-29 13:39:39 +0200386 if (collision_id > strlen(mod->name)) {
387 /* fine, we will not hash more bytes, just use more bits from the hash than previously */
388 ext_len = strlen(mod->name);
389 } else {
390 /* use one more byte from the module name than before */
391 ext_len = collision_id;
392 }
393 full_hash = dict_hash_multi(full_hash, mod->name, ext_len);
394 }
395 full_hash = dict_hash_multi(full_hash, NULL, 0);
396
397 /* use the shortened hash */
398 hash = full_hash & (LYB_HASH_MASK >> collision_id);
399 /* add colision identificator */
400 hash |= LYB_HASH_COLLISION_ID >> collision_id;
401
402 /* save this hash */
403 if (collision_id < LYS_NODE_HASH_COUNT) {
404 sibling->hash[collision_id] = hash;
405 }
406
407 return hash;
408}
409
Radek Krejci857189e2020-09-01 13:26:36 +0200410ly_bool
Michal Vasko60ea6352020-06-29 13:39:39 +0200411lyb_has_schema_model(const struct lysc_node *sibling, const struct lys_module **models)
412{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200413 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +0200414
415 LY_ARRAY_FOR(models, u) {
416 if (sibling->module == models[u]) {
417 return 1;
418 }
419 }
420
421 return 0;
422}
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100423
424void
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100425lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
426{
427 if (*root && (lyd_owner_module(*root) != mod)) {
428 /* there are no data of mod so this is simply the first top-level sibling */
429 mod = NULL;
430 }
431
432 if ((*root != to_del) || (*root)->parent) {
433 return;
434 }
435
436 *root = (*root)->next;
437 if (mod && *root && (lyd_owner_module(to_del) != lyd_owner_module(*root))) {
438 /* there are no more nodes from mod */
439 *root = lyd_first_sibling(*root);
440 }
441}
442
443void
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100444ly_free_prefix_data(LY_PREFIX_FORMAT format, void *prefix_data)
445{
446 struct ly_set *ns_list;
447 struct lysc_prefix *prefixes;
448 uint32_t i;
449 LY_ARRAY_COUNT_TYPE u;
450
451 if (!prefix_data) {
452 return;
453 }
454
455 switch (format) {
456 case LY_PREF_XML:
457 ns_list = prefix_data;
458 for (i = 0; i < ns_list->count; ++i) {
459 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
460 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
461 }
462 ly_set_free(ns_list, free);
463 break;
464 case LY_PREF_SCHEMA_RESOLVED:
465 prefixes = prefix_data;
466 LY_ARRAY_FOR(prefixes, u) {
467 free(prefixes[u].prefix);
468 }
469 LY_ARRAY_FREE(prefixes);
470 break;
471 case LY_PREF_SCHEMA:
472 case LY_PREF_JSON:
473 break;
474 }
475}
476
477LY_ERR
478ly_dup_prefix_data(const struct ly_ctx *ctx, LY_PREFIX_FORMAT format, const void *prefix_data,
479 void **prefix_data_p)
480{
481 LY_ERR ret = LY_SUCCESS;
482 struct lyxml_ns *ns;
483 struct lysc_prefix *prefixes = NULL, *orig_pref;
484 struct ly_set *ns_list, *orig_ns;
485 uint32_t i;
486 LY_ARRAY_COUNT_TYPE u;
487
488 assert(!*prefix_data_p);
489
490 switch (format) {
491 case LY_PREF_SCHEMA:
492 *prefix_data_p = (void *)prefix_data;
493 break;
494 case LY_PREF_SCHEMA_RESOLVED:
495 /* copy all the value prefixes */
496 orig_pref = (struct lysc_prefix *)prefix_data;
497 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
498 *prefix_data_p = prefixes;
499
500 LY_ARRAY_FOR(orig_pref, u) {
501 if (orig_pref[u].prefix) {
502 prefixes[u].prefix = strdup(orig_pref[u].prefix);
503 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
504 }
505 prefixes[u].mod = orig_pref[u].mod;
506 LY_ARRAY_INCREMENT(prefixes);
507 }
508 break;
509 case LY_PREF_XML:
510 /* copy all the namespaces */
511 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
512 *prefix_data_p = ns_list;
513
514 orig_ns = (struct ly_set *)prefix_data;
515 for (i = 0; i < orig_ns->count; ++i) {
516 ns = calloc(1, sizeof *ns);
517 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
518 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
519
520 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
521 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
522 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
523 }
524 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
525 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
526 }
527 break;
528 case LY_PREF_JSON:
529 assert(!prefix_data);
530 *prefix_data_p = NULL;
531 break;
532 }
533
534cleanup:
535 if (ret) {
536 ly_free_prefix_data(format, *prefix_data_p);
537 *prefix_data_p = NULL;
538 }
539 return ret;
540}
541
542LY_ERR
543ly_store_prefix_data(const struct ly_ctx *ctx, const char *value, size_t value_len, LY_PREFIX_FORMAT format,
544 void *prefix_data, LY_PREFIX_FORMAT *format_p, void **prefix_data_p)
545{
546 LY_ERR ret = LY_SUCCESS;
547 const char *start, *stop;
548 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100549 const struct lyxml_ns *ns;
550 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100551 struct ly_set *ns_list;
552 struct lysc_prefix *prefixes = NULL, *val_pref;
553
554 switch (format) {
555 case LY_PREF_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100556 /* copy all referenced modules as prefix - module pairs */
557 if (!*prefix_data_p) {
558 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100559 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
560 *format_p = LY_PREF_SCHEMA_RESOLVED;
561 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100562 } else {
563 /* reuse prefix data */
564 assert(*format_p == LY_PREF_SCHEMA_RESOLVED);
565 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100566 }
567
568 /* add all used prefixes */
569 for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
570 size_t bytes;
571 uint32_t c;
572
573 ly_getutf8(&stop, &c, &bytes);
574 if (is_xmlqnamestartchar(c)) {
575 for (ly_getutf8(&stop, &c, &bytes);
576 is_xmlqnamechar(c) && (size_t)(stop - value) < value_len;
577 ly_getutf8(&stop, &c, &bytes)) {}
578 stop = stop - bytes;
579 if (*stop == ':') {
580 /* we have a possible prefix */
581 size_t len = stop - start;
582
583 /* do we already have the prefix? */
584 mod = ly_type_store_resolve_prefix(ctx, start, len, *format_p, *prefix_data_p);
585 if (!mod) {
586 mod = ly_type_store_resolve_prefix(ctx, start, len, format, prefix_data);
587 if (mod) {
Michal Vaskofc2cd072021-02-24 13:17:17 +0100588 assert(*format_p == LY_PREF_SCHEMA_RESOLVED);
589 /* store a new prefix - module pair */
590 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
591 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100592
Michal Vaskofc2cd072021-02-24 13:17:17 +0100593 val_pref->prefix = strndup(start, len);
594 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
595 val_pref->mod = mod;
596 } /* else it is not even defined */
597 } /* else the prefix is already present */
598 }
599 stop = stop + bytes;
600 }
601 }
602 break;
603 case LY_PREF_XML:
604 /* copy all referenced namespaces as prefix - namespace pairs */
605 if (!*prefix_data_p) {
606 /* new prefix data */
607 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
608 *format_p = LY_PREF_XML;
609 *prefix_data_p = ns_list;
610 } else {
611 /* reuse prefix data */
612 assert(*format_p == LY_PREF_XML);
613 ns_list = *prefix_data_p;
614 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100615
Michal Vaskofc2cd072021-02-24 13:17:17 +0100616 /* add all used prefixes */
617 for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
618 size_t bytes;
619 uint32_t c;
620
621 ly_getutf8(&stop, &c, &bytes);
622 if (is_xmlqnamestartchar(c)) {
623 for (ly_getutf8(&stop, &c, &bytes);
624 is_xmlqnamechar(c) && (size_t)(stop - value) < value_len;
625 ly_getutf8(&stop, &c, &bytes)) {}
626 stop = stop - bytes;
627 if (*stop == ':') {
628 /* we have a possible prefix */
629 size_t len = stop - start;
630
631 /* do we already have the prefix? */
632 ns = lyxml_ns_get(ns_list, start, len);
633 if (!ns) {
634 ns = lyxml_ns_get(prefix_data, start, len);
635 if (ns) {
636 /* store a new prefix - namespace pair */
637 new_ns = calloc(1, sizeof *new_ns);
638 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
639 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
640
641 new_ns->prefix = strndup(start, len);
642 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
643 new_ns->uri = strdup(ns->uri);
644 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100645 } /* else it is not even defined */
646 } /* else the prefix is already present */
647 }
648 stop = stop + bytes;
649 }
650 }
651 break;
652 case LY_PREF_SCHEMA_RESOLVED:
653 case LY_PREF_JSON:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100654 if (!*prefix_data_p) {
655 /* new prefix data - simply copy all the prefix data */
656 *format_p = format;
657 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
658 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100659 break;
660 }
661
662cleanup:
663 if (ret) {
664 ly_free_prefix_data(*format_p, *prefix_data_p);
665 *prefix_data_p = NULL;
666 }
667 return ret;
668}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100669
670const char *
671ly_format2str(LY_PREFIX_FORMAT format)
672{
673 switch (format) {
674 case LY_PREF_SCHEMA:
675 return "schema imports";
676 case LY_PREF_SCHEMA_RESOLVED:
677 return "schema stored mapping";
678 case LY_PREF_XML:
679 return "XML prefixes";
680 case LY_PREF_JSON:
681 return "JSON module names";
682 default:
683 break;
684 }
685
686 return NULL;
687}