1 /**
2  * @file common.c
3  * @author Radek Krejci <rkrejci@cesnet.cz>
4  * @brief common libyang routines implementations
5  *
6  * Copyright (c) 2015 - 2017 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  */
14 
15 #define _GNU_SOURCE /*strndup */
16 
17 #include <assert.h>
18 #include <ctype.h>
19 #include <errno.h>
20 #include <limits.h>
21 #include <pthread.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 
29 #include "common.h"
30 #include "parser.h"
31 #include "xpath.h"
32 #include "context.h"
33 
34 THREAD_LOCAL enum int_log_opts log_opt;
35 THREAD_LOCAL LY_ERR ly_errno_glob;
36 
37 API LY_ERR *
ly_errno_glob_address(void)38 ly_errno_glob_address(void)
39 {
40     FUN_IN;
41 
42     return &ly_errno_glob;
43 }
44 
45 API LY_VECODE
ly_vecode(const struct ly_ctx * ctx)46 ly_vecode(const struct ly_ctx *ctx)
47 {
48     FUN_IN;
49 
50     struct ly_err_item *i;
51 
52     i = ly_err_first(ctx);
53     if (i) {
54         return i->prev->vecode;
55     }
56 
57     return 0;
58 }
59 
60 API const char *
ly_errmsg(const struct ly_ctx * ctx)61 ly_errmsg(const struct ly_ctx *ctx)
62 {
63     FUN_IN;
64 
65     struct ly_err_item *i;
66 
67     i = ly_err_first(ctx);
68     if (i) {
69         return i->prev->msg;
70     }
71 
72     return NULL;
73 }
74 
75 API const char *
ly_errpath(const struct ly_ctx * ctx)76 ly_errpath(const struct ly_ctx *ctx)
77 {
78     FUN_IN;
79 
80     struct ly_err_item *i;
81 
82     i = ly_err_first(ctx);
83     if (i) {
84         return i->prev->path;
85     }
86 
87     return NULL;
88 }
89 
90 API const char *
ly_errapptag(const struct ly_ctx * ctx)91 ly_errapptag(const struct ly_ctx *ctx)
92 {
93     FUN_IN;
94 
95     struct ly_err_item *i;
96 
97     i = ly_err_first(ctx);
98     if (i) {
99         return i->prev->apptag;
100     }
101 
102     return NULL;
103 }
104 
105 API struct ly_err_item *
ly_err_first(const struct ly_ctx * ctx)106 ly_err_first(const struct ly_ctx *ctx)
107 {
108     FUN_IN;
109 
110     if (!ctx) {
111         return NULL;
112     }
113 
114     return pthread_getspecific(ctx->errlist_key);
115 }
116 
117 void
ly_err_free(void * ptr)118 ly_err_free(void *ptr)
119 {
120     struct ly_err_item *i, *next;
121 
122     /* clean the error list */
123     for (i = (struct ly_err_item *)ptr; i; i = next) {
124         next = i->next;
125         free(i->msg);
126         free(i->path);
127         free(i->apptag);
128         free(i);
129     }
130 }
131 
132 API void
ly_err_clean(struct ly_ctx * ctx,struct ly_err_item * eitem)133 ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem)
134 {
135     FUN_IN;
136 
137     struct ly_err_item *i, *first;
138 
139     first = ly_err_first(ctx);
140     if (first == eitem) {
141         eitem = NULL;
142     }
143     if (eitem) {
144         /* disconnect the error */
145         for (i = first; i && (i->next != eitem); i = i->next);
146         assert(i);
147         i->next = NULL;
148         first->prev = i;
149         /* free this err and newer */
150         ly_err_free(eitem);
151         /* update errno */
152         ly_errno = i->no;
153     } else {
154         /* free all err */
155         ly_err_free(first);
156         pthread_setspecific(ctx->errlist_key, NULL);
157         /* also clean errno */
158         ly_errno = LY_SUCCESS;
159     }
160 }
161 
162 const char *
strpbrk_backwards(const char * s,const char * accept,unsigned int s_len)163 strpbrk_backwards(const char *s, const char *accept, unsigned int s_len)
164 {
165     const char *sc;
166 
167     for (; *s != '\0' && s_len; --s, --s_len) {
168         for (sc = accept; *sc != '\0'; ++sc) {
169             if (*s == *sc) {
170                 return s;
171             }
172         }
173     }
174     return s;
175 }
176 
177 char *
strnchr(const char * s,int c,unsigned int len)178 strnchr(const char *s, int c, unsigned int len)
179 {
180     for (; *s != (char)c; ++s, --len) {
181         if ((*s == '\0') || (!len)) {
182             return NULL;
183         }
184     }
185     return (char *)s;
186 }
187 
188 const char *
strnodetype(LYS_NODE type)189 strnodetype(LYS_NODE type)
190 {
191     switch (type) {
192     case LYS_UNKNOWN:
193         return NULL;
194     case LYS_AUGMENT:
195         return "augment";
196     case LYS_CONTAINER:
197         return "container";
198     case LYS_CHOICE:
199         return "choice";
200     case LYS_LEAF:
201         return "leaf";
202     case LYS_LEAFLIST:
203         return "leaf-list";
204     case LYS_LIST:
205         return "list";
206     case LYS_ANYXML:
207         return "anyxml";
208     case LYS_GROUPING:
209         return "grouping";
210     case LYS_CASE:
211         return "case";
212     case LYS_INPUT:
213         return "input";
214     case LYS_OUTPUT:
215         return "output";
216     case LYS_NOTIF:
217         return "notification";
218     case LYS_RPC:
219         return "rpc";
220     case LYS_USES:
221         return "uses";
222     case LYS_ACTION:
223         return "action";
224     case LYS_ANYDATA:
225         return "anydata";
226     case LYS_EXT:
227         return "extension instance";
228     }
229 
230     return NULL;
231 }
232 
233 const char *
transform_module_name2import_prefix(const struct lys_module * module,const char * module_name)234 transform_module_name2import_prefix(const struct lys_module *module, const char *module_name)
235 {
236     uint16_t i;
237 
238     if (!module_name) {
239         return NULL;
240     }
241 
242     if (!strcmp(lys_main_module(module)->name, module_name)) {
243         /* the same for module and submodule */
244         return module->prefix;
245     }
246 
247     for (i = 0; i < module->imp_size; ++i) {
248         if (!strcmp(module->imp[i].module->name, module_name)) {
249             return module->imp[i].prefix;
250         }
251     }
252 
253     return NULL;
254 }
255 
256 static int
_transform_json2xml_subexp(const struct lys_module * module,const char * expr,char ** out,size_t * out_used,size_t * out_size,int schema,int inst_id,const char *** prefixes,const char *** namespaces,uint32_t * ns_count)257 _transform_json2xml_subexp(const struct lys_module *module, const char *expr, char **out, size_t *out_used, size_t *out_size,
258                            int schema, int inst_id, const char ***prefixes, const char ***namespaces, uint32_t *ns_count)
259 {
260     const char *cur_expr, *end, *prefix, *literal;
261     char *name;
262     size_t name_len;
263     const struct lys_module *mod = NULL, *prev_mod = NULL;
264     uint32_t i, j;
265     struct lyxp_expr *exp;
266     struct ly_ctx *ctx = module->ctx;
267     enum int_log_opts prev_ilo;
268 
269     assert(module && expr && ((!prefixes && !namespaces && !ns_count) || (prefixes && namespaces && ns_count)));
270 
271     exp = lyxp_parse_expr(ctx, expr);
272     LY_CHECK_RETURN(!exp, 1);
273 
274     for (i = 0; i < exp->used; ++i) {
275         cur_expr = &exp->expr[exp->expr_pos[i]];
276 
277         /* copy WS */
278         if (i && ((end = exp->expr + exp->expr_pos[i - 1] + exp->tok_len[i - 1]) != cur_expr)) {
279             strncpy(&(*out)[*out_used], end, cur_expr - end);
280             (*out_used) += cur_expr - end;
281         }
282 
283         if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && ((end = strnchr(cur_expr, ':', exp->tok_len[i])) || inst_id)) {
284             /* get the module */
285             if (!schema) {
286                 if (end) {
287                     name_len = end - cur_expr;
288                     name = strndup(cur_expr, name_len);
289                     mod = ly_ctx_get_module(module->ctx, name, NULL, 0);
290                     if (module->ctx->data_clb) {
291                         if (!mod) {
292                             mod = module->ctx->data_clb(module->ctx, name, NULL, 0, module->ctx->data_clb_data);
293                         } else if (!mod->implemented) {
294                             mod = module->ctx->data_clb(module->ctx, name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, module->ctx->data_clb_data);
295                         }
296                     }
297                     free(name);
298                     if (!mod) {
299                         LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len, cur_expr);
300                         goto error;
301                     }
302                     prev_mod = mod;
303                 } else {
304                     mod = prev_mod;
305                     if (!mod) {
306                         LOGINT(ctx);
307                         goto error;
308                     }
309                     name_len = 0;
310                     end = cur_expr;
311                 }
312                 prefix = mod->prefix;
313             } else {
314                 if (end) {
315                     name_len = end - cur_expr;
316                 } else {
317                     name_len = strlen(cur_expr);
318                     end = cur_expr;
319                 }
320                 name = strndup(cur_expr, name_len);
321                 prefix = transform_module_name2import_prefix(module, name);
322                 free(name);
323                 if (!prefix) {
324                     LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len, cur_expr);
325                     goto error;
326                 }
327             }
328 
329             /* remember the namespace definition (only if it's new) */
330             if (!schema && ns_count) {
331                 for (j = 0; j < *ns_count; ++j) {
332                     if (ly_strequal((*namespaces)[j], mod->ns, 1)) {
333                         break;
334                     }
335                 }
336                 if (j == *ns_count) {
337                     ++(*ns_count);
338                     *prefixes = ly_realloc(*prefixes, *ns_count * sizeof **prefixes);
339                     LY_CHECK_ERR_GOTO(!(*prefixes), LOGMEM(ctx), error);
340                     *namespaces = ly_realloc(*namespaces, *ns_count * sizeof **namespaces);
341                     LY_CHECK_ERR_GOTO(!(*namespaces), LOGMEM(ctx), error);
342                     (*prefixes)[*ns_count - 1] = mod->prefix;
343                     (*namespaces)[*ns_count - 1] = mod->ns;
344                 }
345             }
346 
347             /* adjust out size (it can even decrease in some strange cases) */
348             *out_size += strlen(prefix) + 1 - name_len;
349             *out = ly_realloc(*out, *out_size);
350             LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
351 
352             /* copy the model name */
353             strcpy(&(*out)[*out_used], prefix);
354             *out_used += strlen(prefix);
355 
356             if (!name_len) {
357                 /* we are adding the prefix, so also ':' */
358                 (*out)[*out_used] = ':';
359                 ++(*out_used);
360             }
361 
362             /* copy the rest */
363             strncpy(&(*out)[*out_used], end, exp->tok_len[i] - name_len);
364             *out_used += exp->tok_len[i] - name_len;
365         } else if ((exp->tokens[i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
366             /* copy begin quote */
367             (*out)[*out_used] = cur_expr[0];
368             ++(*out_used);
369 
370             /* skip quotes */
371             literal = lydict_insert(module->ctx, cur_expr + 1, exp->tok_len[i] - 2);
372 
373             /* parse literals as subexpressions if possible, otherwise treat as a literal */
374             ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
375             if (_transform_json2xml_subexp(module, literal, out, out_used, out_size, schema, inst_id, prefixes, namespaces, ns_count)) {
376                 strncpy(&(*out)[*out_used], literal, exp->tok_len[i] - 2);
377                 *out_used += exp->tok_len[i] - 2;
378             }
379             ly_ilo_restore(NULL, prev_ilo, NULL, 0);
380 
381             lydict_remove(module->ctx, literal);
382 
383             /* copy end quote */
384             (*out)[*out_used] = cur_expr[exp->tok_len[i] - 1];
385             ++(*out_used);
386         } else {
387             strncpy(&(*out)[*out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
388             *out_used += exp->tok_len[i];
389         }
390     }
391 
392     lyxp_expr_free(exp);
393     return 0;
394 
395 error:
396     lyxp_expr_free(exp);
397     return 1;
398 }
399 
400 static const char *
_transform_json2xml(const struct lys_module * module,const char * expr,int schema,int inst_id,const char *** prefixes,const char *** namespaces,uint32_t * ns_count)401 _transform_json2xml(const struct lys_module *module, const char *expr, int schema, int inst_id, const char ***prefixes,
402                     const char ***namespaces, uint32_t *ns_count)
403 {
404     char *out;
405     size_t out_size, out_used;
406     int ret;
407 
408     assert(module && expr && ((!prefixes && !namespaces && !ns_count) || (prefixes && namespaces && ns_count)));
409 
410     if (ns_count) {
411         *ns_count = 0;
412         *prefixes = NULL;
413         *namespaces = NULL;
414     }
415 
416     if (!expr[0]) {
417         /* empty value */
418         return lydict_insert(module->ctx, expr, 0);
419     }
420 
421     out_size = strlen(expr) + 1;
422     out = malloc(out_size);
423     LY_CHECK_ERR_RETURN(!out, LOGMEM(module->ctx), NULL);
424     out_used = 0;
425 
426     ret = _transform_json2xml_subexp(module, expr, &out, &out_used, &out_size, schema, inst_id, prefixes, namespaces, ns_count);
427     if (!ret) {
428         out[out_used] = '\0';
429         return lydict_insert_zc(module->ctx, out);
430     }
431 
432     /* fail */
433     if (ns_count) {
434         *ns_count = 0;
435         free(*prefixes);
436         *prefixes = NULL;
437         free(*namespaces);
438         *namespaces = NULL;
439     }
440     free(out);
441     return NULL;
442 }
443 
444 const char *
transform_json2xml(const struct lys_module * module,const char * expr,int inst_id,const char *** prefixes,const char *** namespaces,uint32_t * ns_count)445 transform_json2xml(const struct lys_module *module, const char *expr, int inst_id, const char ***prefixes,
446                    const char ***namespaces, uint32_t *ns_count)
447 {
448     return _transform_json2xml(module, expr, 0, inst_id, prefixes, namespaces, ns_count);
449 }
450 
451 const char *
transform_json2schema(const struct lys_module * module,const char * expr)452 transform_json2schema(const struct lys_module *module, const char *expr)
453 {
454     return _transform_json2xml(module, expr, 1, 0, NULL, NULL, NULL);
455 }
456 
457 static int
transform_xml2json_subexp(struct ly_ctx * ctx,const char * expr,char ** out,size_t * out_used,size_t * out_size,struct lyxml_elem * xml,int inst_id,int use_ctx_data_clb)458 transform_xml2json_subexp(struct ly_ctx *ctx, const char *expr, char **out, size_t *out_used, size_t *out_size,
459                           struct lyxml_elem *xml, int inst_id, int use_ctx_data_clb)
460 {
461     const char *end, *cur_expr, *literal;
462     char *prefix;
463     uint16_t i;
464     enum int_log_opts prev_ilo;
465     size_t pref_len;
466     const struct lys_module *mod, *prev_mod = NULL;
467     const struct lyxml_ns *ns;
468     struct lyxp_expr *exp;
469 
470     exp = lyxp_parse_expr(ctx, expr);
471     if (!exp) {
472         return 1;
473     }
474 
475     for (i = 0; i < exp->used; ++i) {
476         cur_expr = &exp->expr[exp->expr_pos[i]];
477 
478         /* copy WS */
479         if (i && ((end = exp->expr + exp->expr_pos[i - 1] + exp->tok_len[i - 1]) != cur_expr)) {
480             strncpy(&(*out)[*out_used], end, cur_expr - end);
481             (*out_used) += cur_expr - end;
482         }
483 
484         if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
485             /* get the module */
486             pref_len = end - cur_expr;
487             prefix = strndup(cur_expr, pref_len);
488             if (!prefix) {
489                 LOGMEM(ctx);
490                 goto error;
491             }
492             ns = lyxml_get_ns(xml, prefix);
493             free(prefix);
494             if (!ns) {
495                 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, xml, "namespace prefix");
496                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "XML namespace with prefix \"%.*s\" not defined.", pref_len, cur_expr);
497                 goto error;
498             }
499             mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL, 0);
500             if (use_ctx_data_clb && ctx->data_clb) {
501                 if (!mod) {
502                     mod = ctx->data_clb(ctx, NULL, ns->value, 0, ctx->data_clb_data);
503                 } else if (!mod->implemented) {
504                     mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
505                 }
506             }
507             if (!mod) {
508                 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, xml, "module namespace");
509                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Module with the namespace \"%s\" could not be found.", ns->value);
510                 goto error;
511             }
512 
513             if (!inst_id || (mod != prev_mod)) {
514                 /* adjust out size (it can even decrease in some strange cases) */
515                 *out_size += strlen(mod->name) - pref_len;
516                 *out = ly_realloc(*out, *out_size);
517                 if (!(*out)) {
518                     LOGMEM(ctx);
519                     goto error;
520                 }
521 
522                 /* copy the model name */
523                 strcpy(&(*out)[*out_used], mod->name);
524                 *out_used += strlen(mod->name);
525             } else {
526                 /* skip ':' */
527                 ++end;
528                 ++pref_len;
529             }
530 
531             /* remember previous model name */
532             prev_mod = mod;
533 
534             /* copy the rest */
535             strncpy(&(*out)[*out_used], end, exp->tok_len[i] - pref_len);
536             *out_used += exp->tok_len[i] - pref_len;
537         } else if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && inst_id) {
538             LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, xml, "namespace prefix");
539             LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Node name is missing module prefix.");
540             goto error;
541         } else if ((exp->tokens[i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
542             /* copy begin quote */
543             (*out)[*out_used] = cur_expr[0];
544             ++(*out_used);
545 
546             /* skip quotes */
547             literal = lydict_insert(ctx, cur_expr + 1, exp->tok_len[i] - 2);
548 
549             /* parse literals as subexpressions if possible, otherwise treat as a literal, do not log */
550             prev_ilo = log_opt;
551             log_opt = ILO_IGNORE;
552             if (transform_xml2json_subexp(ctx, literal, out, out_used, out_size, xml, inst_id, use_ctx_data_clb)) {
553                 strncpy(&(*out)[*out_used], literal, exp->tok_len[i] - 2);
554                 *out_used += exp->tok_len[i] - 2;
555             }
556             log_opt = prev_ilo;
557 
558             lydict_remove(ctx, literal);
559 
560             /* copy end quote */
561             (*out)[*out_used] = cur_expr[exp->tok_len[i] - 1];
562             ++(*out_used);
563         } else {
564             strncpy(&(*out)[*out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
565             *out_used += exp->tok_len[i];
566         }
567     }
568 
569     lyxp_expr_free(exp);
570     return 0;
571 
572 error:
573     lyxp_expr_free(exp);
574     return 1;
575 }
576 
577 const char *
transform_xml2json(struct ly_ctx * ctx,const char * expr,struct lyxml_elem * xml,int inst_id,int use_ctx_data_clb)578 transform_xml2json(struct ly_ctx *ctx, const char *expr, struct lyxml_elem *xml, int inst_id, int use_ctx_data_clb)
579 {
580     char *out;
581     size_t out_size, out_used;
582     int ret;
583 
584     out_size = strlen(expr) + 1;
585     out = malloc(out_size);
586     if (!out) {
587         LOGMEM(ctx);
588         return NULL;
589     }
590     out_used = 0;
591 
592     ret = transform_xml2json_subexp(ctx, expr, &out, &out_used, &out_size, xml, inst_id, use_ctx_data_clb);
593     if (!ret) {
594         out[out_used] = '\0';
595         return lydict_insert_zc(ctx, out);
596     }
597 
598     free(out);
599     return NULL;
600 }
601 
602 API char *
ly_path_xml2json(struct ly_ctx * ctx,const char * xml_path,struct lyxml_elem * xml)603 ly_path_xml2json(struct ly_ctx *ctx, const char *xml_path, struct lyxml_elem *xml)
604 {
605     FUN_IN;
606 
607     const char *json_path;
608     char *ret = NULL;
609 
610     if (!ctx || !xml_path || !xml) {
611         LOGARG;
612         return NULL;
613     }
614 
615     json_path = transform_xml2json(ctx, xml_path, xml, 0, 1);
616     if (json_path) {
617         ret = strdup(json_path);
618         lydict_remove(ctx, json_path);
619     }
620 
621     return ret;
622 }
623 
624 const char *
transform_schema2json(const struct lys_module * module,const char * expr)625 transform_schema2json(const struct lys_module *module, const char *expr)
626 {
627     const char *end, *cur_expr, *ptr;
628     char *out;
629     uint16_t i;
630     size_t out_size, out_used, pref_len;
631     const struct lys_module *mod;
632     struct ly_ctx *ctx = module->ctx;
633     struct lyxp_expr *exp = NULL;
634 
635     out_size = strlen(expr) + 1;
636     out = malloc(out_size);
637     LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
638     out_used = 0;
639 
640     exp = lyxp_parse_expr(ctx, expr);
641     LY_CHECK_ERR_GOTO(!exp, , error);
642 
643     for (i = 0; i < exp->used; ++i) {
644         cur_expr = &exp->expr[exp->expr_pos[i]];
645 
646         /* copy WS */
647         if (i && ((end = exp->expr + exp->expr_pos[i - 1] + exp->tok_len[i - 1]) != cur_expr)) {
648             strncpy(&out[out_used], end, cur_expr - end);
649             out_used += cur_expr - end;
650         }
651 
652         if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
653             /* get the module */
654             pref_len = end - cur_expr;
655             mod = lyp_get_module(module, cur_expr, pref_len, NULL, 0, 0);
656             if (!mod) {
657                 LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, pref_len, cur_expr);
658                 goto error;
659             }
660 
661             /* adjust out size (it can even decrease in some strange cases) */
662             out_size += strlen(mod->name) - pref_len;
663             out = ly_realloc(out, out_size);
664             LY_CHECK_ERR_GOTO(!out, LOGMEM(ctx), error);
665 
666             /* copy the model name */
667             strcpy(&out[out_used], mod->name);
668             out_used += strlen(mod->name);
669 
670             /* copy the rest */
671             strncpy(&out[out_used], end, exp->tok_len[i] - pref_len);
672             out_used += exp->tok_len[i] - pref_len;
673         } else if ((exp->tokens[i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
674             ptr = end;
675             while (isalnum(ptr[-1]) || (ptr[-1] == '_') || (ptr[-1] == '-') || (ptr[-1] == '.')) {
676                 --ptr;
677             }
678 
679             /* get the module */
680             pref_len = end - ptr;
681             mod = lyp_get_module(module, ptr, pref_len, NULL, 0, 0);
682             if (mod) {
683                 /* adjust out size (it can even decrease in some strange cases) */
684                 out_size += strlen(mod->name) - pref_len;
685                 out = ly_realloc(out, out_size);
686                 LY_CHECK_ERR_GOTO(!out, LOGMEM(ctx), error);
687 
688                 /* copy any beginning */
689                 strncpy(&out[out_used], cur_expr, ptr - cur_expr);
690                 out_used += ptr - cur_expr;
691 
692                 /* copy the model name */
693                 strcpy(&out[out_used], mod->name);
694                 out_used += strlen(mod->name);
695 
696                 /* copy the rest */
697                 strncpy(&out[out_used], end, (exp->tok_len[i] - pref_len) - (ptr - cur_expr));
698                 out_used += (exp->tok_len[i] - pref_len) - (ptr - cur_expr);
699             } else {
700                 strncpy(&out[out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
701                 out_used += exp->tok_len[i];
702             }
703         } else {
704             strncpy(&out[out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
705             out_used += exp->tok_len[i];
706         }
707     }
708     out[out_used] = '\0';
709 
710     lyxp_expr_free(exp);
711     return lydict_insert_zc(module->ctx, out);
712 
713 error:
714     free(out);
715     lyxp_expr_free(exp);
716     return NULL;
717 }
718 
719 const char *
transform_iffeat_schema2json(const struct lys_module * module,const char * expr)720 transform_iffeat_schema2json(const struct lys_module *module, const char *expr)
721 {
722     const char *in, *id;
723     char *out, *col;
724     size_t out_size, out_used, id_len, rc;
725     const struct lys_module *mod;
726     struct ly_ctx *ctx = module->ctx;
727 
728     in = expr;
729     out_size = strlen(in) + 1;
730     out = malloc(out_size);
731     LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
732     out_used = 0;
733 
734     while (1) {
735         col = strchr(in, ':');
736         /* we're finished, copy the remaining part */
737         if (!col) {
738             strcpy(&out[out_used], in);
739             out_used += strlen(in) + 1;
740             assert(out_size == out_used);
741             return lydict_insert_zc(ctx, out);
742         }
743         id = strpbrk_backwards(col - 1, " \f\n\r\t\v(", (col - in) - 1);
744         if ((id[0] == ' ') || (id[0] == '\f') || (id[0] == '\n') || (id[0] == '\r') ||
745             (id[0] == '\t') || (id[0] == '\v') || (id[0] == '(')) {
746             ++id;
747         }
748         id_len = col - id;
749         rc = parse_identifier(id);
750         if (rc < id_len) {
751             LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, id[rc], &id[rc]);
752             free(out);
753             return NULL;
754         }
755 
756         /* get the module */
757         mod = lyp_get_module(module, id, id_len, NULL, 0, 0);
758         if (!mod) {
759             LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Module prefix \"%.*s\" is unknown.", id_len, id);
760             free(out);
761             return NULL;
762         }
763 
764         /* adjust out size (it can even decrease in some strange cases) */
765         out_size += strlen(mod->name) - id_len;
766         out = ly_realloc(out, out_size);
767         LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
768 
769         /* copy the data before prefix */
770         strncpy(&out[out_used], in, id - in);
771         out_used += id - in;
772 
773         /* copy the model name */
774         strcpy(&out[out_used], mod->name);
775         out_used += strlen(mod->name);
776 
777         /* copy ':' */
778         out[out_used] = ':';
779         ++out_used;
780 
781         /* finally adjust in pointer for next round */
782         in = col + 1;
783     }
784 
785     /* unreachable */
786     LOGINT(ctx);
787     return NULL;
788 }
789 
790 static int
transform_json2xpath_subexpr(const struct lys_module * cur_module,const struct lys_module * prev_mod,struct lyxp_expr * exp,uint32_t * i,enum lyxp_token end_token,char ** out,size_t * out_used,size_t * out_size)791 transform_json2xpath_subexpr(const struct lys_module *cur_module, const struct lys_module *prev_mod, struct lyxp_expr *exp,
792                              uint32_t *i, enum lyxp_token end_token, char **out, size_t *out_used, size_t *out_size)
793 {
794     const char *cur_expr, *end, *ptr;
795     size_t name_len;
796     char *name;
797     const struct lys_module *mod;
798     struct ly_ctx *ctx = cur_module->ctx;
799 
800     while (*i < exp->used) {
801         if (exp->tokens[*i] == end_token) {
802             return 0;
803         }
804 
805         cur_expr = &exp->expr[exp->expr_pos[*i]];
806 
807         /* copy WS */
808         if (*i && ((end = exp->expr + exp->expr_pos[*i - 1] + exp->tok_len[*i - 1]) != cur_expr)) {
809             strncpy(*out + *out_used, end, cur_expr - end);
810             *out_used += cur_expr - end;
811         }
812 
813         if (exp->tokens[*i] == LYXP_TOKEN_BRACK1) {
814             /* copy "[" */
815             strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
816             *out_used += exp->tok_len[*i];
817             ++(*i);
818 
819             /* call recursively because we need to remember current prev_mod for after the predicate */
820             if (transform_json2xpath_subexpr(cur_module, prev_mod, exp, i, LYXP_TOKEN_BRACK2, out, out_used, out_size)) {
821                 return -1;
822             }
823 
824             if (*i >= exp->used) {
825                 LOGVAL(ctx, LYE_XPATH_EOF, LY_VLOG_NONE, NULL);
826                 return -1;
827             }
828 
829             /* copy "]" */
830             strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
831             *out_used += exp->tok_len[*i];
832         } else if (exp->tokens[*i] == LYXP_TOKEN_NAMETEST) {
833             if ((end = strnchr(cur_expr, ':', exp->tok_len[*i]))) {
834                 /* there is a prefix, get the module */
835                 name_len = end - cur_expr;
836                 name = strndup(cur_expr, name_len);
837                 prev_mod = ly_ctx_get_module(ctx, name, NULL, 1);
838                 free(name);
839                 if (!prev_mod) {
840                     LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len ? name_len : exp->tok_len[*i], cur_expr);
841                     return -1;
842                 }
843                 /* skip ":" */
844                 ++end;
845                 ++name_len;
846             } else {
847                 end = cur_expr;
848                 name_len = 0;
849             }
850 
851             /* do we print the module name? (always for "*" if there was any, it's an exception) */
852             if (((prev_mod != cur_module) && (end[0] != '*')) || (name_len && (end[0] == '*'))) {
853                 /* adjust out size (it can even decrease in some strange cases) */
854                 *out_size += (strlen(prev_mod->name) - name_len) + 1;
855                 *out = ly_realloc(*out, *out_size);
856                 LY_CHECK_ERR_RETURN(!*out, LOGMEM(ctx), -1);
857 
858                 /* copy the model name */
859                 strcpy(*out + *out_used, prev_mod->name);
860                 *out_used += strlen(prev_mod->name);
861 
862                 /* print ":" */
863                 (*out)[*out_used] = ':';
864                 ++(*out_used);
865             }
866 
867             /* copy the rest */
868             strncpy(*out + *out_used, end, exp->tok_len[*i] - name_len);
869             *out_used += exp->tok_len[*i] - name_len;
870         } else if ((exp->tokens[*i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[*i]))) {
871             ptr = end;
872             while (isalnum(ptr[-1]) || (ptr[-1] == '_') || (ptr[-1] == '-') || (ptr[-1] == '.')) {
873                 --ptr;
874             }
875 
876             /* get the module, but it may actually not be a module name */
877             name_len = end - ptr;
878             name = strndup(ptr, name_len);
879             mod = ly_ctx_get_module(ctx, name, NULL, 1);
880             free(name);
881 
882             if (mod && (mod != cur_module)) {
883                 /* adjust out size (it can even decrease in some strange cases) */
884                 *out_size += strlen(mod->name) - name_len;
885                 *out = ly_realloc(*out, *out_size);
886                 LY_CHECK_ERR_RETURN(!*out, LOGMEM(ctx), -1);
887 
888                 /* copy any beginning */
889                 strncpy(*out + *out_used, cur_expr, ptr - cur_expr);
890                 *out_used += ptr - cur_expr;
891 
892                 /* copy the model name */
893                 strcpy(*out + *out_used, mod->name);
894                 *out_used += strlen(mod->name);
895 
896                 /* copy the rest */
897                 strncpy(*out + *out_used, end, (exp->tok_len[*i] - name_len) - (ptr - cur_expr));
898                 *out_used += (exp->tok_len[*i] - name_len) - (ptr - cur_expr);
899             } else {
900                 strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
901                 *out_used += exp->tok_len[*i];
902             }
903         } else {
904             strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
905             *out_used += exp->tok_len[*i];
906         }
907 
908         ++(*i);
909     }
910 
911     return 0;
912 }
913 
914 char *
transform_json2xpath(const struct lys_module * cur_module,const char * expr)915 transform_json2xpath(const struct lys_module *cur_module, const char *expr)
916 {
917     char *out;
918     size_t out_size, out_used;
919     uint32_t i;
920     struct lyxp_expr *exp;
921 
922     assert(cur_module && expr);
923 
924     out_size = strlen(expr) + 1;
925     out = malloc(out_size);
926     LY_CHECK_ERR_RETURN(!out, LOGMEM(cur_module->ctx), NULL);
927     out_used = 0;
928 
929     exp = lyxp_parse_expr(cur_module->ctx, expr);
930     LY_CHECK_ERR_RETURN(!exp, free(out), NULL);
931 
932     i = 0;
933     if (transform_json2xpath_subexpr(cur_module, cur_module, exp, &i, LYXP_TOKEN_NONE, &out, &out_used, &out_size)) {
934         goto error;
935     }
936     out[out_used] = '\0';
937 
938     lyxp_expr_free(exp);
939     return out;
940 
941 error:
942     free(out);
943     lyxp_expr_free(exp);
944     return NULL;
945 }
946 
947 static int
ly_path_data2schema_copy_token(const struct ly_ctx * ctx,struct lyxp_expr * exp,uint16_t cur_exp,char ** out,uint16_t * out_used)948 ly_path_data2schema_copy_token(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t cur_exp, char **out, uint16_t *out_used)
949 {
950     uint16_t len;
951 
952     for (len = exp->tok_len[cur_exp]; isspace(exp->expr[exp->expr_pos[cur_exp] + len]); ++len);
953     *out = ly_realloc(*out, *out_used + len);
954     LY_CHECK_ERR_RETURN(!(*out), LOGMEM(ctx), -1);
955     sprintf(*out + *out_used - 1, "%.*s", len, exp->expr + exp->expr_pos[cur_exp]);
956     *out_used += len;
957 
958     return 0;
959 }
960 
961 static int
ly_path_data2schema_subexp(const struct ly_ctx * ctx,const struct lys_node * orig_parent,const struct lys_module * cur_mod,struct lyxp_expr * exp,uint16_t * cur_exp,char ** out,uint16_t * out_used)962 ly_path_data2schema_subexp(const struct ly_ctx *ctx, const struct lys_node *orig_parent, const struct lys_module *cur_mod,
963                            struct lyxp_expr *exp, uint16_t *cur_exp, char **out, uint16_t *out_used)
964 {
965     uint16_t j, k, len, slash;
966     char *str = NULL, *col;
967     const struct lys_node *node, *node2, *parent;
968     enum lyxp_token end_token = 0;
969     int first, path_lost;
970 
971     switch (exp->tokens[*cur_exp]) {
972     case LYXP_TOKEN_BRACK1:
973         end_token = LYXP_TOKEN_BRACK2;
974 
975         if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
976             goto error;
977         }
978         ++(*cur_exp);
979         first = 0;
980         break;
981     case LYXP_TOKEN_PAR1:
982         end_token = LYXP_TOKEN_PAR2;
983 
984         if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
985             goto error;
986         }
987         ++(*cur_exp);
988         first = 0;
989         break;
990     case LYXP_TOKEN_OPERATOR_PATH:
991         first = (orig_parent) ? 0 : 1;
992         break;
993     default:
994         first = 1;
995         break;
996     }
997 
998     path_lost = 0;
999     parent = orig_parent;
1000     while (*cur_exp < exp->used) {
1001         switch (exp->tokens[*cur_exp]) {
1002         case LYXP_TOKEN_DOT:
1003         case LYXP_TOKEN_DDOT:
1004         case LYXP_TOKEN_NAMETEST:
1005             if (path_lost) {
1006                 /* we do not know anything anymore, just copy it */
1007                 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
1008                     goto error;
1009                 }
1010                 break;
1011             }
1012 
1013             str = strndup(exp->expr + exp->expr_pos[*cur_exp], exp->tok_len[*cur_exp]);
1014             LY_CHECK_ERR_GOTO(!str, LOGMEM(ctx), error);
1015 
1016             col = strchr(str, ':');
1017             if (col) {
1018                 *col = '\0';
1019                 ++col;
1020             }
1021 
1022             /* special node test */
1023             if (((col ? col[0] : str[0]) == '.') || ((col ? col[0] : str[0]) == '*')) {
1024                 free(str);
1025                 str = NULL;
1026 
1027                 if (end_token) {
1028                     LOGERR(ctx, LY_EINVAL, "Invalid path used (%s in a subexpression).", str);
1029                     goto error;
1030                 }
1031 
1032                 /* we can no longer evaluate the path, so just copy the rest */
1033                 path_lost = 1;
1034                 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
1035                     goto error;
1036                 }
1037                 first = 0;
1038                 break;
1039             }
1040 
1041             /* first node */
1042             if (first) {
1043                 if (!col) {
1044                     LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_NONE, NULL);
1045                     goto error;
1046                 }
1047 
1048                 cur_mod = ly_ctx_get_module(ctx, str, NULL, 0);
1049                 if (!cur_mod) {
1050                     LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
1051                     goto error;
1052                 }
1053 
1054                 first = 0;
1055             }
1056 
1057             /* create schema path for this data node */
1058             node = NULL;
1059             while ((node = lys_getnext(node, parent, cur_mod, LYS_GETNEXT_NOSTATECHECK))) {
1060                 if (strcmp(node->name, col ? col : str)) {
1061                     continue;
1062                 }
1063 
1064                 if (col && strcmp(lys_node_module(node)->name, str)) {
1065                     continue;
1066                 }
1067                 if (!col && (lys_node_module(node) != lys_node_module(parent))) {
1068                     continue;
1069                 }
1070 
1071                 /* determine how deep the node actually is, we must generate the path from the highest parent */
1072                 j = 0;
1073                 node2 = node;
1074                 while (node2 != parent) {
1075                     node2 = lys_parent(node2);
1076                     if (!node2 || (node2->nodetype != LYS_USES)) {
1077                         ++j;
1078                     }
1079                 }
1080 
1081                 /* first node, do not print '/' */
1082                 slash = 0;
1083                 while (j) {
1084                     k = j - 1;
1085                     node2 = node;
1086                     while (k) {
1087                         node2 = lys_parent(node2);
1088                         assert(node2);
1089                         if (node2->nodetype != LYS_USES) {
1090                             --k;
1091                         }
1092                     }
1093 
1094                     if ((lys_node_module(node2) != cur_mod) || !parent) {
1095                         /* module name and node name */
1096                         len = slash + strlen(lys_node_module(node2)->name) + 1 + strlen(node2->name);
1097                         *out = ly_realloc(*out, *out_used + len);
1098                         LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
1099                         sprintf(*out + *out_used - 1, "%s%s:%s", slash ? "/" : "", lys_node_module(node2)->name, node2->name);
1100                         *out_used += len;
1101                     } else {
1102                         /* only node name */
1103                         len = slash + strlen(node2->name);
1104                         *out = ly_realloc(*out, *out_used + len);
1105                         LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
1106                         sprintf(*out + *out_used - 1, "%s%s", slash ? "/" : "", node2->name);
1107                         *out_used += len;
1108                     }
1109 
1110                     slash = 1;
1111                     --j;
1112                 }
1113 
1114                 break;
1115             }
1116             if (!node) {
1117                 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, col ? col : str);
1118                 goto error;
1119             }
1120 
1121             /* copy any whitespaces */
1122             for (len = 0; isspace(exp->expr[exp->expr_pos[*cur_exp] + exp->tok_len[*cur_exp] + len]); ++len);
1123             if (len) {
1124                 *out = ly_realloc(*out, *out_used + len);
1125                 LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
1126                 sprintf(*out + *out_used - 1, "%*s", len, " ");
1127                 *out_used += len;
1128             }
1129 
1130             /* next iteration */
1131             free(str);
1132             str = NULL;
1133             parent = node;
1134             break;
1135         case LYXP_TOKEN_COMMA:
1136         case LYXP_TOKEN_OPERATOR_LOG:
1137         case LYXP_TOKEN_OPERATOR_COMP:
1138         case LYXP_TOKEN_OPERATOR_MATH:
1139         case LYXP_TOKEN_OPERATOR_UNI:
1140             /* reset the processing */
1141             first = 1;
1142             path_lost = 0;
1143             parent = orig_parent;
1144 
1145             /* fallthrough */
1146         case LYXP_TOKEN_OPERATOR_PATH:
1147             if ((exp->tokens[*cur_exp] == LYXP_TOKEN_OPERATOR_PATH) && (exp->tok_len[*cur_exp] == 2)) {
1148                 /* we can no longer evaluate the path further */
1149                 path_lost = 1;
1150             }
1151             /* fallthrough */
1152         case LYXP_TOKEN_NODETYPE:
1153         case LYXP_TOKEN_FUNCNAME:
1154         case LYXP_TOKEN_LITERAL:
1155         case LYXP_TOKEN_NUMBER:
1156             /* just copy it */
1157             if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
1158                 goto error;
1159             }
1160             break;
1161         case LYXP_TOKEN_BRACK1:
1162         case LYXP_TOKEN_PAR1:
1163             if (ly_path_data2schema_subexp(ctx, parent, cur_mod, exp, cur_exp, out, out_used)) {
1164                 goto error;
1165             }
1166             break;
1167         default:
1168             if (end_token && (exp->tokens[*cur_exp] == end_token)) {
1169                 /* we are done (with this subexpression) */
1170                 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
1171                     goto error;
1172                 }
1173 
1174                 return 0;
1175             }
1176             LOGERR(ctx, LY_EINVAL, "Invalid token used (%.*s).", exp->tok_len[*cur_exp], exp->expr + exp->expr_pos[*cur_exp]);
1177             goto error;
1178         }
1179 
1180         ++(*cur_exp);
1181     }
1182 
1183     if (end_token) {
1184         LOGVAL(ctx, LYE_XPATH_EOF, LY_VLOG_NONE, NULL);
1185         return -1;
1186     }
1187 
1188     return 0;
1189 
1190 error:
1191     free(str);
1192     return -1;
1193 }
1194 
1195 API char *
ly_path_data2schema(struct ly_ctx * ctx,const char * data_path)1196 ly_path_data2schema(struct ly_ctx *ctx, const char *data_path)
1197 {
1198     FUN_IN;
1199 
1200     struct lyxp_expr *exp;
1201     uint16_t out_used, cur_exp = 0;
1202     char *out;
1203     int r, mod_name_len, nam_len, is_relative = -1;
1204     const char *mod_name, *name;
1205     const struct lys_module *mod = NULL;
1206     const struct lys_node *parent = NULL;
1207     char *str;
1208 
1209     if (!ctx || !data_path) {
1210         LOGARG;
1211         return NULL;
1212     }
1213 
1214     if ((r = parse_schema_nodeid(data_path, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) {
1215         LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, data_path[-r], &data_path[-r]);
1216         return NULL;
1217     }
1218 
1219     if (name[0] == '#') {
1220         if (is_relative) {
1221             LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
1222             return NULL;
1223         }
1224 
1225         ++name;
1226         --nam_len;
1227 
1228         if (!mod_name) {
1229             str = strndup(data_path, (name + nam_len) - data_path);
1230             LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, str);
1231             free(str);
1232             return NULL;
1233         }
1234 
1235         str = strndup(mod_name, mod_name_len);
1236         if (!str) {
1237             LOGMEM(ctx);
1238             return NULL;
1239         }
1240         mod = ly_ctx_get_module(ctx, str, NULL, 1);
1241         free(str);
1242         if (!mod) {
1243             str = strndup(data_path, (mod_name + mod_name_len) - data_path);
1244             LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
1245             free(str);
1246             return NULL;
1247         }
1248 
1249         parent = lyp_get_yang_data_template(mod, name, nam_len);
1250         if (!parent) {
1251             str = strndup(data_path, (name + nam_len) - data_path);
1252             LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
1253             free(str);
1254             return NULL;
1255         }
1256 
1257         out_used = (name + nam_len) - data_path + 1;
1258         out = malloc(out_used);
1259         LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
1260         memcpy(out, data_path, out_used -1);
1261         data_path += r;
1262     } else {
1263         out_used = 1;
1264         out = malloc(1);
1265         LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
1266     }
1267 
1268     exp = lyxp_parse_expr(ctx, data_path);
1269     if (!exp) {
1270         free(out);
1271         return NULL;
1272     }
1273 
1274     if (parent) {
1275         if (ly_path_data2schema_subexp(ctx, parent, mod, exp, &cur_exp, &out, &out_used)) {
1276             free(out);
1277             out = NULL;
1278         }
1279     } else {
1280         if (ly_path_data2schema_subexp(ctx, NULL, NULL, exp, &cur_exp, &out, &out_used)) {
1281             free(out);
1282             out = NULL;
1283         }
1284     }
1285 
1286     lyxp_expr_free(exp);
1287     return out;
1288 }
1289 
1290 int
ly_new_node_validity(const struct lys_node * schema)1291 ly_new_node_validity(const struct lys_node *schema)
1292 {
1293     int validity;
1294 
1295     validity = LYD_VAL_OK;
1296 
1297     if (schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) {
1298         /* duplicit instance check */
1299         validity |= LYD_VAL_DUP;
1300     }
1301     if ((schema->nodetype == LYS_LIST) && ((struct lys_node_list *)schema)->unique_size) {
1302         /* unique check */
1303         validity |= LYD_VAL_UNIQUE;
1304     }
1305     if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CONTAINER | LYS_NOTIF | LYS_RPC | LYS_ACTION | LYS_ANYDATA)) {
1306         /* mandatory children check */
1307         validity |= LYD_VAL_MAND;
1308     }
1309 
1310     return validity;
1311 }
1312 
1313 void *
ly_realloc(void * ptr,size_t size)1314 ly_realloc(void *ptr, size_t size)
1315 {
1316     void *new_mem;
1317 
1318     new_mem = realloc(ptr, size);
1319     if (!new_mem) {
1320         free(ptr);
1321     }
1322 
1323     return new_mem;
1324 }
1325 
1326 int
ly_strequal_(const char * s1,const char * s2)1327 ly_strequal_(const char *s1, const char *s2)
1328 {
1329     if (s1 == s2) {
1330         return 1;
1331     } else if (!s1 || !s2) {
1332         return 0;
1333     } else {
1334         for ( ; *s1 == *s2; s1++, s2++) {
1335             if (*s1 == '\0') {
1336                 return 1;
1337             }
1338         }
1339         return 0;
1340     }
1341 }
1342 
1343 int64_t
dec_pow(uint8_t exp)1344 dec_pow(uint8_t exp)
1345 {
1346     int64_t ret = 1;
1347     uint8_t i;
1348 
1349     for (i = 0; i < exp; ++i) {
1350         ret *= 10;
1351     }
1352 
1353     return ret;
1354 }
1355 
1356 int
dec64cmp(int64_t num1,uint8_t dig1,int64_t num2,uint8_t dig2)1357 dec64cmp(int64_t num1, uint8_t dig1, int64_t num2, uint8_t dig2)
1358 {
1359     if (dig1 < dig2) {
1360         num2 /= dec_pow(dig2 - dig1);
1361     } else if (dig1 > dig2) {
1362         num1 /= dec_pow(dig1 - dig2);
1363     }
1364 
1365     if (num1 == num2) {
1366         return 0;
1367     }
1368     return (num1 > num2 ? 1 : -1);
1369 }
1370 
1371 #ifdef LY_ENABLED_CACHE
1372 #  if defined(__has_feature)
1373 #    if __has_feature(thread_sanitizer)
1374 #      define LY_HASH_NO_TSAN __attribute__((no_sanitize("thread")))
1375 #    endif
1376 #  endif
1377 #  ifndef LY_HASH_NO_TSAN
1378 #    define LY_HASH_NO_TSAN
1379 #  endif
1380 
lyb_hash_cache_check(const struct lys_node * sibling,const uint8_t collision_id)1381 LY_HASH_NO_TSAN static inline LYB_HASH lyb_hash_cache_check(const struct lys_node *sibling, const uint8_t collision_id)
1382 {
1383     if ((collision_id < LYS_NODE_HASH_COUNT) && sibling->hash[collision_id]) {
1384         return sibling->hash[collision_id];
1385     }
1386     return 0;
1387 }
1388 
lyb_hash_cache_update(struct lys_node * sibling,const uint8_t collision_id,const LYB_HASH hash)1389 LY_HASH_NO_TSAN static inline void lyb_hash_cache_update(struct lys_node *sibling, const uint8_t collision_id, const LYB_HASH hash)
1390 {
1391     if (collision_id < LYS_NODE_HASH_COUNT) {
1392         sibling->hash[collision_id] = hash;
1393     }
1394 }
1395 #endif
1396 
1397 LYB_HASH
lyb_hash(struct lys_node * sibling,uint8_t collision_id)1398 lyb_hash(struct lys_node *sibling, uint8_t collision_id)
1399 {
1400     struct lys_module *mod;
1401     int ext_len;
1402     uint32_t full_hash;
1403     LYB_HASH hash;
1404 
1405 #ifdef LY_ENABLED_CACHE
1406     if ((hash = lyb_hash_cache_check(sibling, collision_id))) {
1407         return hash;
1408     }
1409 #endif
1410 
1411     mod = lys_node_module(sibling);
1412 
1413     full_hash = dict_hash_multi(0, mod->name, strlen(mod->name));
1414     full_hash = dict_hash_multi(full_hash, sibling->name, strlen(sibling->name));
1415     if (collision_id) {
1416         if (collision_id > strlen(mod->name)) {
1417             /* fine, we will not hash more bytes, just use more bits from the hash than previously */
1418             ext_len = strlen(mod->name);
1419         } else {
1420             /* use one more byte from the module name than before */
1421             ext_len = collision_id;
1422         }
1423         full_hash = dict_hash_multi(full_hash, mod->name, ext_len);
1424     }
1425     full_hash = dict_hash_multi(full_hash, NULL, 0);
1426 
1427     /* use the shortened hash */
1428     hash = full_hash & (LYB_HASH_MASK >> collision_id);
1429     /* add colision identificator */
1430     hash |= LYB_HASH_COLLISION_ID >> collision_id;
1431 
1432     /* save this hash */
1433 #ifdef LY_ENABLED_CACHE
1434     lyb_hash_cache_update(sibling, collision_id, hash);
1435 #endif
1436 
1437     return hash;
1438 }
1439 
1440 int
lyb_has_schema_model(struct lys_node * sibling,const struct lys_module ** models,int mod_count)1441 lyb_has_schema_model(struct lys_node *sibling, const struct lys_module **models, int mod_count)
1442 {
1443     int i;
1444     const struct lys_module *mod = lys_node_module(sibling);
1445 
1446     for (i = 0; i < mod_count; ++i) {
1447         if (mod == models[i]) {
1448             return 1;
1449         }
1450     }
1451 
1452     return 0;
1453 }
1454 
1455 /**
1456  * @brief Static table of the UTF8 characters lengths according to their first byte.
1457  */
1458 static const unsigned char
1459 utf8_char_length_table[] = {
1460     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1461     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1462     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1463     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1464     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1465     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1466     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1467     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1468     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1469     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1470     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1471     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1472     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1473     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1474     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1475     4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
1476 };
1477 
1478 /**
1479  * @brief Use of utf8_char_length_table.
1480  */
1481 #define UTF8LEN(x) utf8_char_length_table[((unsigned char)(x))]
1482 
1483 size_t
ly_strlen_utf8(const char * str)1484 ly_strlen_utf8(const char *str)
1485 {
1486     size_t clen, len;
1487     const char *ptr;
1488 
1489     for (len = 0, clen = strlen(str), ptr = str; *ptr && len < clen; ++len, ptr += UTF8LEN(*ptr));
1490     return len;
1491 }
1492