blob: 1bc4fdfa5c5175fbc0ede411b3219cf660149ce4 [file] [log] [blame]
Radek Krejci54ea8de2015-04-09 18:02:56 +02001/**
2 * @file xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML parser implementation for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * 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
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejci54ea8de2015-04-09 18:02:56 +020013 */
14
Radek Krejci812b10a2015-05-28 16:48:25 +020015#include <assert.h>
Radek Krejci563427e2016-02-08 16:26:34 +010016#include <errno.h>
Radek Krejci709fee62015-04-15 13:56:19 +020017#include <ctype.h>
18#include <stdint.h>
Radek Krejcif0023a92015-04-20 20:51:39 +020019#include <stdio.h>
Radek Krejci02117302015-04-13 16:32:44 +020020#include <stdlib.h>
21#include <string.h>
Radek Krejci54ea8de2015-04-09 18:02:56 +020022#include <unistd.h>
Radek Krejci563427e2016-02-08 16:26:34 +010023#include <pthread.h>
Pavol Vicanb2570c12015-11-12 13:50:20 +010024#include <sys/stat.h>
25#include <sys/mman.h>
26#include <fcntl.h>
Radek Krejci54ea8de2015-04-09 18:02:56 +020027
Radek Krejci06a704e2015-04-22 14:50:49 +020028#include "common.h"
Michal Vasko6c810702018-03-14 16:23:21 +010029#include "hash_table.h"
Radek Krejci5248f132015-10-09 10:34:25 +020030#include "printer.h"
Radek Krejci5449d472015-10-26 14:35:56 +010031#include "parser.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020032#include "tree_schema.h"
Michal Vaskofc5744d2015-10-22 12:09:34 +020033#include "xml_internal.h"
Michal Vaskoc86327a2020-06-30 11:21:57 +020034#include "xpath.h"
Radek Krejci54ea8de2015-04-09 18:02:56 +020035
Radek Krejci3045cf32015-05-28 10:58:52 +020036#define ign_xmlws(p) \
Radek Krejci563427e2016-02-08 16:26:34 +010037 while (is_xmlws(*p)) { \
Radek Krejci563427e2016-02-08 16:26:34 +010038 p++; \
39 }
Radek Krejci02117302015-04-13 16:32:44 +020040
Michal Vasko88c29542015-11-27 14:57:53 +010041static struct lyxml_attr *lyxml_dup_attr(struct ly_ctx *ctx, struct lyxml_elem *parent, struct lyxml_attr *attr);
42
Michal Vasko1e62a092015-12-01 12:27:20 +010043API const struct lyxml_ns *
44lyxml_get_ns(const struct lyxml_elem *elem, const char *prefix)
Michal Vaskof8879c22015-08-21 09:07:36 +020045{
GalaxyGorillac7777422019-10-07 16:01:23 +020046 FUN_IN;
47
Michal Vaskof8879c22015-08-21 09:07:36 +020048 struct lyxml_attr *attr;
Michal Vaskof8879c22015-08-21 09:07:36 +020049
50 if (!elem) {
51 return NULL;
52 }
53
Michal Vaskof8879c22015-08-21 09:07:36 +020054 for (attr = elem->attr; attr; attr = attr->next) {
55 if (attr->type != LYXML_ATTR_NS) {
56 continue;
57 }
58 if (!attr->name) {
Radek Krejci13f3f152016-10-03 11:40:13 +020059 if (!prefix) {
Michal Vaskof8879c22015-08-21 09:07:36 +020060 /* default namespace found */
61 if (!attr->value) {
62 /* empty default namespace -> no default namespace */
63 return NULL;
64 }
65 return (struct lyxml_ns *)attr;
66 }
Radek Krejci7d39dae2016-10-03 17:33:01 +020067 } else if (prefix && !strcmp(attr->name, prefix)) {
Michal Vaskof8879c22015-08-21 09:07:36 +020068 /* prefix found */
69 return (struct lyxml_ns *)attr;
70 }
71 }
72
73 /* go recursively */
74 return lyxml_get_ns(elem->parent, prefix);
75}
76
Michal Vasko88c29542015-11-27 14:57:53 +010077static void
78lyxml_correct_attr_ns(struct ly_ctx *ctx, struct lyxml_attr *attr, struct lyxml_elem *attr_parent, int copy_ns)
79{
80 const struct lyxml_ns *tmp_ns;
Michal Vaskof6109112015-12-03 14:00:42 +010081 struct lyxml_elem *ns_root, *attr_root;
Michal Vasko88c29542015-11-27 14:57:53 +010082
83 if ((attr->type != LYXML_ATTR_NS) && attr->ns) {
Michal Vaskof6109112015-12-03 14:00:42 +010084 /* find the root of attr */
85 for (attr_root = attr_parent; attr_root->parent; attr_root = attr_root->parent);
Michal Vasko88c29542015-11-27 14:57:53 +010086
87 /* find the root of attr NS */
88 for (ns_root = attr->ns->parent; ns_root->parent; ns_root = ns_root->parent);
89
Michal Vaskof6109112015-12-03 14:00:42 +010090 /* attr NS is defined outside attr parent subtree */
91 if (ns_root != attr_root) {
Michal Vasko88c29542015-11-27 14:57:53 +010092 if (copy_ns) {
93 tmp_ns = attr->ns;
94 /* we may have already copied the NS over? */
Radek Krejci66aca402016-05-24 15:23:02 +020095 attr->ns = lyxml_get_ns(attr_parent, tmp_ns->prefix);
Michal Vasko88c29542015-11-27 14:57:53 +010096
97 /* we haven't copied it over, copy it now */
98 if (!attr->ns) {
Michal Vaskof6109112015-12-03 14:00:42 +010099 attr->ns = (struct lyxml_ns *)lyxml_dup_attr(ctx, attr_parent, (struct lyxml_attr *)tmp_ns);
Michal Vasko88c29542015-11-27 14:57:53 +0100100 }
101 } else {
102 attr->ns = NULL;
103 }
104 }
105 }
106}
107
108static struct lyxml_attr *
Michal Vaskof8879c22015-08-21 09:07:36 +0200109lyxml_dup_attr(struct ly_ctx *ctx, struct lyxml_elem *parent, struct lyxml_attr *attr)
110{
111 struct lyxml_attr *result, *a;
112
113 if (!attr || !parent) {
114 return NULL;
115 }
116
117 if (attr->type == LYXML_ATTR_NS) {
118 /* this is correct, despite that all attributes seems like a standard
119 * attributes (struct lyxml_attr), some of them can be namespace
120 * definitions (and in that case they are struct lyxml_ns).
121 */
122 result = (struct lyxml_attr *)calloc(1, sizeof (struct lyxml_ns));
123 } else {
124 result = calloc(1, sizeof (struct lyxml_attr));
125 }
Michal Vasko53b7da02018-02-13 15:28:42 +0100126 LY_CHECK_ERR_RETURN(!result, LOGMEM(ctx), NULL);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200127
Michal Vaskof8879c22015-08-21 09:07:36 +0200128 result->value = lydict_insert(ctx, attr->value, 0);
129 result->name = lydict_insert(ctx, attr->name, 0);
130 result->type = attr->type;
131
132 /* set namespace in case of standard attributes */
133 if (result->type == LYXML_ATTR_STD && attr->ns) {
Michal Vasko88c29542015-11-27 14:57:53 +0100134 result->ns = attr->ns;
135 lyxml_correct_attr_ns(ctx, result, parent, 1);
Michal Vaskof8879c22015-08-21 09:07:36 +0200136 }
137
138 /* set parent pointer in case of namespace attribute */
139 if (result->type == LYXML_ATTR_NS) {
140 ((struct lyxml_ns *)result)->parent = parent;
141 }
142
143 /* put attribute into the parent's attributes list */
144 if (parent->attr) {
145 /* go to the end of the list */
146 for (a = parent->attr; a->next; a = a->next);
147 /* and append new attribute */
148 a->next = result;
149 } else {
150 /* add the first attribute in the list */
151 parent->attr = result;
152 }
153
154 return result;
155}
156
Michal Vaskoc86327a2020-06-30 11:21:57 +0200157static void
158lyxml_correct_content_ns(struct ly_ctx *ctx, struct lyxml_elem *elem, struct lyxml_elem *orig)
159{
160 const char *end, *cur_expr;
161 char *prefix;
162 uint16_t i;
163 size_t pref_len;
164 const struct lyxml_ns *ns;
165 struct lyxp_expr *exp;
166 enum int_log_opts prev_ilo;
167
168 /* it may not be a valid XPath expression */
169 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
170 exp = lyxp_parse_expr(ctx, elem->content);
171 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
172 if (!exp) {
173 goto cleanup;
174 }
175
176 for (i = 0; i < exp->used; ++i) {
177 cur_expr = &exp->expr[exp->expr_pos[i]];
178
179 if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
180 /* get the prefix */
181 pref_len = end - cur_expr;
182 prefix = strndup(cur_expr, pref_len);
183 if (!prefix) {
184 LOGMEM(ctx);
185 goto cleanup;
186 }
187 ns = lyxml_get_ns(elem, prefix);
188
189 /* we already have the namespace */
190 if (ns) {
191 free(prefix);
192 continue;
193 }
194
195 /* find the namespace in the original XML */
196 ns = lyxml_get_ns(orig, prefix);
197 free(prefix);
198
199 /* copy the namespace over, if any */
200 if (ns && !lyxml_dup_attr(ctx, elem, (struct lyxml_attr *)ns)) {
201 LOGINT(ctx);
202 goto cleanup;
203 }
204 }
205 }
206
207cleanup:
208 lyxp_expr_free(exp);
209}
210
Michal Vaskof748dbc2016-04-05 11:27:47 +0200211void
Michal Vaskoc86327a2020-06-30 11:21:57 +0200212lyxml_correct_elem_ns(struct ly_ctx *ctx, struct lyxml_elem *elem, struct lyxml_elem *orig, int copy_ns,
213 int correct_attrs)
Michal Vasko88c29542015-11-27 14:57:53 +0100214{
215 const struct lyxml_ns *tmp_ns;
Radek Krejcid5be5682016-01-14 16:23:22 +0100216 struct lyxml_elem *elem_root, *ns_root, *tmp, *iter;
Michal Vasko88c29542015-11-27 14:57:53 +0100217 struct lyxml_attr *attr;
218
219 /* find the root of elem */
220 for (elem_root = elem; elem_root->parent; elem_root = elem_root->parent);
221
Radek Krejcid5be5682016-01-14 16:23:22 +0100222 LY_TREE_DFS_BEGIN(elem, tmp, iter) {
223 if (iter->ns) {
Michal Vasko88c29542015-11-27 14:57:53 +0100224 /* find the root of elem NS */
Radek Krejcic071c542016-01-27 14:57:51 +0100225 for (ns_root = iter->ns->parent; ns_root; ns_root = ns_root->parent);
Michal Vasko88c29542015-11-27 14:57:53 +0100226
227 /* elem NS is defined outside elem subtree */
228 if (ns_root != elem_root) {
229 if (copy_ns) {
Radek Krejcid5be5682016-01-14 16:23:22 +0100230 tmp_ns = iter->ns;
Michal Vasko88c29542015-11-27 14:57:53 +0100231 /* we may have already copied the NS over? */
Radek Krejcid5be5682016-01-14 16:23:22 +0100232 iter->ns = lyxml_get_ns(iter, tmp_ns->prefix);
Michal Vasko88c29542015-11-27 14:57:53 +0100233
234 /* we haven't copied it over, copy it now */
Radek Krejcid5be5682016-01-14 16:23:22 +0100235 if (!iter->ns) {
236 iter->ns = (struct lyxml_ns *)lyxml_dup_attr(ctx, iter, (struct lyxml_attr *)tmp_ns);
Michal Vasko88c29542015-11-27 14:57:53 +0100237 }
238 } else {
Radek Krejcid5be5682016-01-14 16:23:22 +0100239 iter->ns = NULL;
Michal Vasko88c29542015-11-27 14:57:53 +0100240 }
241 }
242 }
Michal Vasko1b4d4ea2020-11-18 11:32:57 +0100243 if (iter->content && iter->content[0] && copy_ns) {
Michal Vaskoc86327a2020-06-30 11:21:57 +0200244 lyxml_correct_content_ns(ctx, iter, orig);
245 }
Michal Vasko88c29542015-11-27 14:57:53 +0100246 if (correct_attrs) {
Radek Krejcid5be5682016-01-14 16:23:22 +0100247 LY_TREE_FOR(iter->attr, attr) {
Michal Vasko88c29542015-11-27 14:57:53 +0100248 lyxml_correct_attr_ns(ctx, attr, elem_root, copy_ns);
249 }
250 }
Radek Krejcid5be5682016-01-14 16:23:22 +0100251 LY_TREE_DFS_END(elem, tmp, iter);
Michal Vasko88c29542015-11-27 14:57:53 +0100252 }
253}
254
Michal Vaskof8879c22015-08-21 09:07:36 +0200255struct lyxml_elem *
Michal Vaskodbc40582019-03-12 10:54:24 +0100256lyxml_dup_elem(struct ly_ctx *ctx, struct lyxml_elem *elem, struct lyxml_elem *parent, int recursive, int with_siblings)
Michal Vaskof8879c22015-08-21 09:07:36 +0200257{
Michal Vaskodbc40582019-03-12 10:54:24 +0100258 struct lyxml_elem *dup, *result = NULL;
Michal Vaskof8879c22015-08-21 09:07:36 +0200259 struct lyxml_attr *attr;
260
261 if (!elem) {
262 return NULL;
263 }
264
Michal Vaskodbc40582019-03-12 10:54:24 +0100265 LY_TREE_FOR(elem, elem) {
266 dup = calloc(1, sizeof *dup);
267 LY_CHECK_ERR_RETURN(!dup, LOGMEM(ctx), NULL);
268 dup->content = lydict_insert(ctx, elem->content, 0);
269 dup->name = lydict_insert(ctx, elem->name, 0);
270 dup->flags = elem->flags;
271 dup->prev = dup;
Michal Vaskof8879c22015-08-21 09:07:36 +0200272
Michal Vaskodbc40582019-03-12 10:54:24 +0100273 if (parent) {
274 lyxml_add_child(ctx, parent, dup);
Amandeep Singh Sethi3f661302019-11-09 09:08:11 -0500275 } else if (result) {
276 dup->prev = result->prev;
277 dup->prev->next = dup;
278 result->prev = dup;
Michal Vaskodbc40582019-03-12 10:54:24 +0100279 }
Michal Vaskof8879c22015-08-21 09:07:36 +0200280
Michal Vaskodbc40582019-03-12 10:54:24 +0100281 /* keep old namespace for now */
282 dup->ns = elem->ns;
Michal Vasko88c29542015-11-27 14:57:53 +0100283
Michal Vaskodbc40582019-03-12 10:54:24 +0100284 /* duplicate attributes */
285 for (attr = elem->attr; attr; attr = attr->next) {
286 lyxml_dup_attr(ctx, dup, attr);
287 }
Michal Vaskof8879c22015-08-21 09:07:36 +0200288
Michal Vaskodbc40582019-03-12 10:54:24 +0100289 /* correct namespaces */
Michal Vaskoc86327a2020-06-30 11:21:57 +0200290 lyxml_correct_elem_ns(ctx, dup, elem, 1, 0);
Michal Vaskoa5c958f2018-12-11 08:31:42 +0100291
Michal Vaskodbc40582019-03-12 10:54:24 +0100292 if (recursive) {
293 /* duplicate children */
294 lyxml_dup_elem(ctx, elem->child, dup, 1, 1);
295 }
Michal Vaskof8879c22015-08-21 09:07:36 +0200296
Michal Vasko85f218c2019-03-13 11:29:50 +0100297 /* set result (first sibling) */
Michal Vaskodbc40582019-03-12 10:54:24 +0100298 if (!result) {
299 result = dup;
Michal Vaskodbc40582019-03-12 10:54:24 +0100300 }
301
302 if (!with_siblings) {
303 break;
304 }
Michal Vaskof8879c22015-08-21 09:07:36 +0200305 }
306
307 return result;
308}
309
Radek Krejci6879d952017-01-09 12:49:19 +0100310API struct lyxml_elem *
311lyxml_dup(struct ly_ctx *ctx, struct lyxml_elem *root)
312{
GalaxyGorillac7777422019-10-07 16:01:23 +0200313 FUN_IN;
314
Michal Vaskodbc40582019-03-12 10:54:24 +0100315 return lyxml_dup_elem(ctx, root, NULL, 1, 0);
Radek Krejci6879d952017-01-09 12:49:19 +0100316}
317
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200318void
Michal Vaskof8879c22015-08-21 09:07:36 +0200319lyxml_unlink_elem(struct ly_ctx *ctx, struct lyxml_elem *elem, int copy_ns)
Radek Krejci02117302015-04-13 16:32:44 +0200320{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200321 struct lyxml_elem *parent, *first;
Radek Krejci02117302015-04-13 16:32:44 +0200322
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200323 if (!elem) {
324 return;
325 }
Radek Krejci02117302015-04-13 16:32:44 +0200326
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200327 /* store pointers to important nodes */
328 parent = elem->parent;
Radek Krejcie1f13912015-05-26 15:17:38 +0200329
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200330 /* unlink from parent */
331 if (parent) {
332 if (parent->child == elem) {
333 /* we unlink the first child */
334 /* update the parent's link */
335 parent->child = elem->next;
336 }
337 /* forget about the parent */
338 elem->parent = NULL;
339 }
Radek Krejci02117302015-04-13 16:32:44 +0200340
Michal Vasko88c29542015-11-27 14:57:53 +0100341 if (copy_ns < 2) {
Michal Vaskoc86327a2020-06-30 11:21:57 +0200342 lyxml_correct_elem_ns(ctx, elem, parent, copy_ns, 1);
Michal Vasko88c29542015-11-27 14:57:53 +0100343 }
344
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200345 /* unlink from siblings */
346 if (elem->prev == elem) {
347 /* there are no more siblings */
348 return;
349 }
350 if (elem->next) {
351 elem->next->prev = elem->prev;
352 } else {
353 /* unlinking the last element */
354 if (parent) {
355 first = parent->child;
356 } else {
357 first = elem;
Radek Krejcie4fffcf2016-02-23 16:06:25 +0100358 while (first->prev->next) {
359 first = first->prev;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200360 }
361 }
362 first->prev = elem->prev;
363 }
364 if (elem->prev->next) {
365 elem->prev->next = elem->next;
366 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200367
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200368 /* clean up the unlinked element */
369 elem->next = NULL;
370 elem->prev = elem;
Radek Krejci02117302015-04-13 16:32:44 +0200371}
372
Michal Vasko345da0a2015-12-02 10:35:55 +0100373API void
374lyxml_unlink(struct ly_ctx *ctx, struct lyxml_elem *elem)
375{
GalaxyGorillac7777422019-10-07 16:01:23 +0200376 FUN_IN;
377
Michal Vasko345da0a2015-12-02 10:35:55 +0100378 if (!elem) {
379 return;
380 }
381
382 lyxml_unlink_elem(ctx, elem, 1);
383}
384
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200385void
Radek Krejci00249f22015-07-07 13:43:28 +0200386lyxml_free_attr(struct ly_ctx *ctx, struct lyxml_elem *parent, struct lyxml_attr *attr)
Radek Krejci02117302015-04-13 16:32:44 +0200387{
Radek Krejci00249f22015-07-07 13:43:28 +0200388 struct lyxml_attr *aiter, *aprev;
389
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200390 if (!attr) {
391 return;
392 }
Radek Krejci02117302015-04-13 16:32:44 +0200393
Radek Krejci00249f22015-07-07 13:43:28 +0200394 if (parent) {
395 /* unlink attribute from the parent's list of attributes */
396 aprev = NULL;
397 for (aiter = parent->attr; aiter; aiter = aiter->next) {
398 if (aiter == attr) {
399 break;
400 }
401 aprev = aiter;
402 }
403 if (!aiter) {
404 /* attribute to remove not found */
405 return;
406 }
407
408 if (!aprev) {
409 /* attribute is first in parent's list of attributes */
410 parent->attr = attr->next;
411 } else {
412 /* reconnect previous attribute to the next */
413 aprev->next = attr->next;
414 }
415 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200416 lydict_remove(ctx, attr->name);
417 lydict_remove(ctx, attr->value);
Michal Vasko36b72992020-02-25 12:12:47 +0100418 if (attr->type == LYXML_ATTR_STD_UNRES) {
419 free((char *)attr->ns);
420 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200421 free(attr);
Radek Krejci02117302015-04-13 16:32:44 +0200422}
423
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200424void
425lyxml_free_attrs(struct ly_ctx *ctx, struct lyxml_elem *elem)
Radek Krejci02117302015-04-13 16:32:44 +0200426{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200427 struct lyxml_attr *a, *next;
428 if (!elem || !elem->attr) {
429 return;
430 }
Radek Krejci02117302015-04-13 16:32:44 +0200431
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200432 a = elem->attr;
433 do {
434 next = a->next;
Radek Krejci02117302015-04-13 16:32:44 +0200435
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200436 lydict_remove(ctx, a->name);
437 lydict_remove(ctx, a->value);
Michal Vasko36b72992020-02-25 12:12:47 +0100438 if (a->type == LYXML_ATTR_STD_UNRES) {
439 free((char *)a->ns);
440 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200441 free(a);
Radek Krejci02117302015-04-13 16:32:44 +0200442
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200443 a = next;
444 } while (a);
Radek Krejci02117302015-04-13 16:32:44 +0200445}
446
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200447static void
Michal Vasko272e42f2015-12-02 12:20:37 +0100448lyxml_free_elem(struct ly_ctx *ctx, struct lyxml_elem *elem)
Radek Krejci02117302015-04-13 16:32:44 +0200449{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200450 struct lyxml_elem *e, *next;
Radek Krejci02117302015-04-13 16:32:44 +0200451
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200452 if (!elem) {
453 return;
454 }
Radek Krejci02117302015-04-13 16:32:44 +0200455
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200456 lyxml_free_attrs(ctx, elem);
457 LY_TREE_FOR_SAFE(elem->child, next, e) {
Michal Vasko272e42f2015-12-02 12:20:37 +0100458 lyxml_free_elem(ctx, e);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200459 }
460 lydict_remove(ctx, elem->name);
461 lydict_remove(ctx, elem->content);
462 free(elem);
Radek Krejci02117302015-04-13 16:32:44 +0200463}
464
Radek Krejcic6704c82015-10-06 11:12:45 +0200465API void
Michal Vasko345da0a2015-12-02 10:35:55 +0100466lyxml_free(struct ly_ctx *ctx, struct lyxml_elem *elem)
Radek Krejci02117302015-04-13 16:32:44 +0200467{
GalaxyGorillac7777422019-10-07 16:01:23 +0200468 FUN_IN;
469
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200470 if (!elem) {
471 return;
472 }
Radek Krejci02117302015-04-13 16:32:44 +0200473
Michal Vasko61f7ccb2015-10-23 10:15:08 +0200474 lyxml_unlink_elem(ctx, elem, 2);
Michal Vasko272e42f2015-12-02 12:20:37 +0100475 lyxml_free_elem(ctx, elem);
Radek Krejci02117302015-04-13 16:32:44 +0200476}
477
Radek Krejci8f8db232016-05-23 16:48:21 +0200478API void
479lyxml_free_withsiblings(struct ly_ctx *ctx, struct lyxml_elem *elem)
480{
GalaxyGorillac7777422019-10-07 16:01:23 +0200481 FUN_IN;
482
Radek Krejci8f8db232016-05-23 16:48:21 +0200483 struct lyxml_elem *iter, *aux;
484
485 if (!elem) {
486 return;
487 }
488
489 /* optimization - avoid freeing (unlinking) the last node of the siblings list */
490 /* so, first, free the node's predecessors to the beginning of the list ... */
491 for(iter = elem->prev; iter->next; iter = aux) {
492 aux = iter->prev;
493 lyxml_free(ctx, iter);
494 }
495 /* ... then, the node is the first in the siblings list, so free them all */
496 LY_TREE_FOR_SAFE(elem, aux, iter) {
497 lyxml_free(ctx, iter);
498 }
499}
500
Michal Vasko88c29542015-11-27 14:57:53 +0100501API const char *
Michal Vasko1e62a092015-12-01 12:27:20 +0100502lyxml_get_attr(const struct lyxml_elem *elem, const char *name, const char *ns)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200503{
GalaxyGorillac7777422019-10-07 16:01:23 +0200504 FUN_IN;
505
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200506 struct lyxml_attr *a;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200507
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200508 assert(elem);
509 assert(name);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200510
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200511 for (a = elem->attr; a; a = a->next) {
512 if (a->type != LYXML_ATTR_STD) {
513 continue;
514 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200515
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200516 if (!strcmp(name, a->name)) {
517 if ((!ns && !a->ns) || (ns && a->ns && !strcmp(ns, a->ns->value))) {
518 return a->value;
519 }
520 }
521 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200522
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200523 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200524}
525
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200526int
Michal Vaskof8879c22015-08-21 09:07:36 +0200527lyxml_add_child(struct ly_ctx *ctx, struct lyxml_elem *parent, struct lyxml_elem *elem)
Radek Krejci02117302015-04-13 16:32:44 +0200528{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200529 struct lyxml_elem *e;
Radek Krejci02117302015-04-13 16:32:44 +0200530
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200531 assert(parent);
532 assert(elem);
Radek Krejci02117302015-04-13 16:32:44 +0200533
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200534 /* (re)link element to parent */
535 if (elem->parent) {
Michal Vaskof8879c22015-08-21 09:07:36 +0200536 lyxml_unlink_elem(ctx, elem, 1);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200537 }
538 elem->parent = parent;
Radek Krejci02117302015-04-13 16:32:44 +0200539
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200540 /* link parent to element */
541 if (parent->child) {
542 e = parent->child;
543 elem->prev = e->prev;
544 elem->next = NULL;
545 elem->prev->next = elem;
546 e->prev = elem;
547 } else {
548 parent->child = elem;
549 elem->prev = elem;
550 elem->next = NULL;
551 }
Radek Krejci02117302015-04-13 16:32:44 +0200552
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200553 return EXIT_SUCCESS;
Radek Krejci02117302015-04-13 16:32:44 +0200554}
555
Michal Vasko3b855722015-08-28 16:01:18 +0200556int
Michal Vasko53b7da02018-02-13 15:28:42 +0100557lyxml_getutf8(struct ly_ctx *ctx, const char *buf, unsigned int *read)
Radek Krejci02117302015-04-13 16:32:44 +0200558{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200559 int c, aux;
560 int i;
Radek Krejci02117302015-04-13 16:32:44 +0200561
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200562 c = buf[0];
563 *read = 0;
Radek Krejci02117302015-04-13 16:32:44 +0200564
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200565 /* buf is NULL terminated string, so 0 means EOF */
566 if (!c) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100567 LOGVAL(ctx, LYE_EOF, LY_VLOG_NONE, NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200568 return 0;
569 }
570 *read = 1;
Radek Krejci02117302015-04-13 16:32:44 +0200571
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200572 /* process character byte(s) */
573 if ((c & 0xf8) == 0xf0) {
574 /* four bytes character */
575 *read = 4;
Radek Krejci02117302015-04-13 16:32:44 +0200576
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200577 c &= 0x07;
578 for (i = 1; i <= 3; i++) {
579 aux = buf[i];
580 if ((aux & 0xc0) != 0x80) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100581 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "input character");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200582 return 0;
583 }
Radek Krejci02117302015-04-13 16:32:44 +0200584
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200585 c = (c << 6) | (aux & 0x3f);
586 }
Radek Krejci02117302015-04-13 16:32:44 +0200587
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200588 if (c < 0x1000 || c > 0x10ffff) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100589 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "input character");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200590 return 0;
591 }
592 } else if ((c & 0xf0) == 0xe0) {
593 /* three bytes character */
594 *read = 3;
Radek Krejci02117302015-04-13 16:32:44 +0200595
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200596 c &= 0x0f;
597 for (i = 1; i <= 2; i++) {
598 aux = buf[i];
599 if ((aux & 0xc0) != 0x80) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100600 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "input character");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200601 return 0;
602 }
Radek Krejci02117302015-04-13 16:32:44 +0200603
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200604 c = (c << 6) | (aux & 0x3f);
605 }
Radek Krejci02117302015-04-13 16:32:44 +0200606
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200607 if (c < 0x800 || (c > 0xd7ff && c < 0xe000) || c > 0xfffd) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100608 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "input character");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200609 return 0;
610 }
611 } else if ((c & 0xe0) == 0xc0) {
612 /* two bytes character */
613 *read = 2;
Radek Krejci02117302015-04-13 16:32:44 +0200614
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200615 aux = buf[1];
616 if ((aux & 0xc0) != 0x80) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100617 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "input character");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200618 return 0;
619 }
620 c = ((c & 0x1f) << 6) | (aux & 0x3f);
Radek Krejci02117302015-04-13 16:32:44 +0200621
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200622 if (c < 0x80) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100623 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "input character");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200624 return 0;
625 }
626 } else if (!(c & 0x80)) {
627 /* one byte character */
628 if (c < 0x20 && c != 0x9 && c != 0xa && c != 0xd) {
629 /* invalid character */
Michal Vasko53b7da02018-02-13 15:28:42 +0100630 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "input character");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200631 return 0;
632 }
633 } else {
634 /* invalid character */
Michal Vasko53b7da02018-02-13 15:28:42 +0100635 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "input character");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200636 return 0;
637 }
Radek Krejci02117302015-04-13 16:32:44 +0200638
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200639 return c;
Radek Krejci02117302015-04-13 16:32:44 +0200640}
641
Michal Vasko0d343d12015-08-24 14:57:36 +0200642/* logs directly */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200643static int
Michal Vasko53b7da02018-02-13 15:28:42 +0100644parse_ignore(struct ly_ctx *ctx, const char *data, const char *endstr, unsigned int *len)
Radek Krejci02117302015-04-13 16:32:44 +0200645{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200646 unsigned int slen;
647 const char *c = data;
Radek Krejci02117302015-04-13 16:32:44 +0200648
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200649 slen = strlen(endstr);
Radek Krejci02117302015-04-13 16:32:44 +0200650
Radek Krejcifb783942016-10-06 09:49:33 +0200651 while (*c && strncmp(c, endstr, slen)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200652 c++;
653 }
654 if (!*c) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100655 LOGVAL(ctx, LYE_XML_MISS, LY_VLOG_NONE, NULL, "closing sequence", endstr);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200656 return EXIT_FAILURE;
657 }
658 c += slen;
Radek Krejci02117302015-04-13 16:32:44 +0200659
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200660 *len = c - data;
661 return EXIT_SUCCESS;
Radek Krejci02117302015-04-13 16:32:44 +0200662}
663
Michal Vasko53b7da02018-02-13 15:28:42 +0100664/* logs directly, fails when return == NULL and *len == 0 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200665static char *
Michal Vasko53b7da02018-02-13 15:28:42 +0100666parse_text(struct ly_ctx *ctx, const char *data, char delim, unsigned int *len)
Radek Krejci02117302015-04-13 16:32:44 +0200667{
Radek Krejci709fee62015-04-15 13:56:19 +0200668#define BUFSIZE 1024
Radek Krejci02117302015-04-13 16:32:44 +0200669
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200670 char buf[BUFSIZE];
Michal Vaskobddd3d72020-08-27 08:39:50 +0200671 char *result = NULL;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200672 unsigned int r;
673 int o, size = 0;
674 int cdsect = 0;
675 int32_t n;
Radek Krejci709fee62015-04-15 13:56:19 +0200676
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200677 for (*len = o = 0; cdsect || data[*len] != delim; o++) {
Radek Krejcifb783942016-10-06 09:49:33 +0200678 if (!data[*len] || (!cdsect && !strncmp(&data[*len], "]]>", 3))) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100679 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "element content, \"]]>\" found");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200680 goto error;
681 }
Radek Krejci709fee62015-04-15 13:56:19 +0200682
Radek Krejcia4a84062015-04-16 13:00:10 +0200683loop:
684
Radek Krejcia0802a82017-02-08 12:41:05 +0100685 if (o > BUFSIZE - 4) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200686 /* add buffer into the result */
687 if (result) {
688 size = size + o;
Radek Krejcia8d111f2017-05-31 13:57:37 +0200689 result = ly_realloc(result, size + 1);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200690 } else {
691 size = o;
692 result = malloc((size + 1) * sizeof *result);
693 }
Michal Vasko53b7da02018-02-13 15:28:42 +0100694 LY_CHECK_ERR_RETURN(!result, LOGMEM(ctx), NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200695 memcpy(&result[size - o], buf, o);
Radek Krejci709fee62015-04-15 13:56:19 +0200696
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200697 /* write again into the beginning of the buffer */
698 o = 0;
699 }
Radek Krejci709fee62015-04-15 13:56:19 +0200700
Radek Krejcifb783942016-10-06 09:49:33 +0200701 if (cdsect || !strncmp(&data[*len], "<![CDATA[", 9)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200702 /* CDSect */
703 if (!cdsect) {
704 cdsect = 1;
705 *len += 9;
706 }
Radek Krejcifb783942016-10-06 09:49:33 +0200707 if (data[*len] && !strncmp(&data[*len], "]]>", 3)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200708 *len += 3;
709 cdsect = 0;
710 o--; /* we don't write any data in this iteration */
711 } else {
712 buf[o] = data[*len];
713 (*len)++;
714 }
715 } else if (data[*len] == '&') {
716 (*len)++;
717 if (data[*len] != '#') {
718 /* entity reference - only predefined refs are supported */
Radek Krejcifb783942016-10-06 09:49:33 +0200719 if (!strncmp(&data[*len], "lt;", 3)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200720 buf[o] = '<';
721 *len += 3;
Radek Krejcifb783942016-10-06 09:49:33 +0200722 } else if (!strncmp(&data[*len], "gt;", 3)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200723 buf[o] = '>';
724 *len += 3;
Radek Krejcifb783942016-10-06 09:49:33 +0200725 } else if (!strncmp(&data[*len], "amp;", 4)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200726 buf[o] = '&';
727 *len += 4;
Radek Krejcifb783942016-10-06 09:49:33 +0200728 } else if (!strncmp(&data[*len], "apos;", 5)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200729 buf[o] = '\'';
730 *len += 5;
Radek Krejcifb783942016-10-06 09:49:33 +0200731 } else if (!strncmp(&data[*len], "quot;", 5)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200732 buf[o] = '\"';
733 *len += 5;
734 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +0100735 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "entity reference (only predefined references are supported)");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200736 goto error;
737 }
738 } else {
739 /* character reference */
740 (*len)++;
741 if (isdigit(data[*len])) {
742 for (n = 0; isdigit(data[*len]); (*len)++) {
743 n = (10 * n) + (data[*len] - '0');
744 }
745 if (data[*len] != ';') {
Michal Vasko53b7da02018-02-13 15:28:42 +0100746 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "character reference, missing semicolon");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200747 goto error;
748 }
749 } else if (data[(*len)++] == 'x' && isxdigit(data[*len])) {
750 for (n = 0; isxdigit(data[*len]); (*len)++) {
751 if (isdigit(data[*len])) {
752 r = (data[*len] - '0');
753 } else if (data[*len] > 'F') {
754 r = 10 + (data[*len] - 'a');
755 } else {
756 r = 10 + (data[*len] - 'A');
757 }
758 n = (16 * n) + r;
759 }
760 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +0100761 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "character reference");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200762 goto error;
Radek Krejci709fee62015-04-15 13:56:19 +0200763
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200764 }
Michal Vasko53b7da02018-02-13 15:28:42 +0100765 r = pututf8(ctx, &buf[o], n);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200766 if (!r) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100767 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "character reference value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200768 goto error;
769 }
770 o += r - 1; /* o is ++ in for loop */
771 (*len)++;
772 }
773 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +0100774 r = copyutf8(ctx, &buf[o], &data[*len]);
Radek Krejcideee60e2016-09-23 15:21:14 +0200775 if (!r) {
776 goto error;
777 }
778
779 o += r - 1; /* o is ++ in for loop */
780 (*len) = (*len) + r;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200781 }
782 }
Radek Krejci02117302015-04-13 16:32:44 +0200783
Radek Krejcifb783942016-10-06 09:49:33 +0200784 if (delim == '<' && !strncmp(&data[*len], "<![CDATA[", 9)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200785 /* ignore loop's end condition on beginning of CDSect */
786 goto loop;
787 }
Radek Krejci709fee62015-04-15 13:56:19 +0200788#undef BUFSIZE
789
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200790 if (o) {
791 if (result) {
792 size = size + o;
Michal Vaskobddd3d72020-08-27 08:39:50 +0200793 result = ly_realloc(result, size + 1);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200794 } else {
795 size = o;
796 result = malloc((size + 1) * sizeof *result);
797 }
Michal Vasko53b7da02018-02-13 15:28:42 +0100798 LY_CHECK_ERR_RETURN(!result, LOGMEM(ctx), NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200799 memcpy(&result[size - o], buf, o);
800 }
801 if (result) {
802 result[size] = '\0';
Radek Krejcia5269642015-07-20 19:04:11 +0200803 } else {
804 size = 0;
805 result = strdup("");
Michal Vasko53b7da02018-02-13 15:28:42 +0100806 LY_CHECK_ERR_RETURN(!result, LOGMEM(ctx), NULL)
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200807 }
Radek Krejci02117302015-04-13 16:32:44 +0200808
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200809 return result;
Radek Krejci709fee62015-04-15 13:56:19 +0200810
811error:
Michal Vasko53b7da02018-02-13 15:28:42 +0100812 *len = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200813 free(result);
814 return NULL;
Radek Krejci02117302015-04-13 16:32:44 +0200815}
816
Michal Vasko0d343d12015-08-24 14:57:36 +0200817/* logs directly */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200818static struct lyxml_attr *
Radek Krejci00249f22015-07-07 13:43:28 +0200819parse_attr(struct ly_ctx *ctx, const char *data, unsigned int *len, struct lyxml_elem *parent)
Radek Krejci674e1f82015-04-21 14:12:19 +0200820{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200821 const char *c = data, *start, *delim;
aweast069a6c02018-05-30 16:44:18 -0500822 char *prefix = NULL, xml_flag, *str;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200823 int uc;
Radek Krejci00249f22015-07-07 13:43:28 +0200824 struct lyxml_attr *attr = NULL, *a;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200825 unsigned int size;
Radek Krejci02117302015-04-13 16:32:44 +0200826
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200827 /* check if it is attribute or namespace */
Radek Krejcifb783942016-10-06 09:49:33 +0200828 if (!strncmp(c, "xmlns", 5)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200829 /* namespace */
830 attr = calloc(1, sizeof (struct lyxml_ns));
Michal Vasko53b7da02018-02-13 15:28:42 +0100831 LY_CHECK_ERR_RETURN(!attr, LOGMEM(ctx), NULL);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200832
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200833 attr->type = LYXML_ATTR_NS;
Radek Krejci00249f22015-07-07 13:43:28 +0200834 ((struct lyxml_ns *)attr)->parent = parent;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200835 c += 5;
836 if (*c != ':') {
837 /* default namespace, prefix will be empty */
838 goto equal;
839 }
840 c++; /* go after ':' to the prefix value */
841 } else {
842 /* attribute */
843 attr = calloc(1, sizeof *attr);
Michal Vasko53b7da02018-02-13 15:28:42 +0100844 LY_CHECK_ERR_RETURN(!attr, LOGMEM(ctx), NULL);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200845
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200846 attr->type = LYXML_ATTR_STD;
847 }
Radek Krejci4ea08382015-04-21 09:41:40 +0200848
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200849 /* process name part of the attribute */
850 start = c;
Michal Vasko53b7da02018-02-13 15:28:42 +0100851 uc = lyxml_getutf8(ctx, c, &size);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200852 if (!is_xmlnamestartchar(uc)) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100853 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "NameStartChar of the attribute");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200854 free(attr);
855 return NULL;
856 }
Michal Vasko62d5a6b2018-01-03 14:31:39 +0100857 xml_flag = 4;
858 if (*c == 'x') {
859 xml_flag = 1;
860 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200861 c += size;
Michal Vasko53b7da02018-02-13 15:28:42 +0100862 uc = lyxml_getutf8(ctx, c, &size);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200863 while (is_xmlnamechar(uc)) {
Michal Vasko62d5a6b2018-01-03 14:31:39 +0100864 if (attr->type == LYXML_ATTR_STD) {
865 if ((*c == ':') && (xml_flag != 3)) {
866 /* attribute in a namespace (but disregard the special "xml" namespace) */
867 start = c + 1;
Radek Krejci4ea08382015-04-21 09:41:40 +0200868
Michal Vasko62d5a6b2018-01-03 14:31:39 +0100869 /* look for the prefix in namespaces */
Michal Vaskoa690d912020-08-31 15:09:43 +0200870 if (prefix) {
871 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "prefix start, \":\" already parsed");
872 goto error;
873 }
aweast069a6c02018-05-30 16:44:18 -0500874 prefix = malloc((c - data + 1) * sizeof *prefix);
875 LY_CHECK_ERR_GOTO(!prefix, LOGMEM(ctx), error);
Michal Vasko62d5a6b2018-01-03 14:31:39 +0100876 memcpy(prefix, data, c - data);
877 prefix[c - data] = '\0';
878 attr->ns = lyxml_get_ns(parent, prefix);
Michal Vasko36b72992020-02-25 12:12:47 +0100879 if (!attr->ns) {
880 /* remember the prefix for later resolution */
881 attr->type = LYXML_ATTR_STD_UNRES;
882 attr->ns = (struct lyxml_ns *)prefix;
883 prefix = NULL;
884 }
Michal Vasko62d5a6b2018-01-03 14:31:39 +0100885 } else if (((*c == 'm') && (xml_flag == 1)) ||
886 ((*c == 'l') && (xml_flag == 2))) {
887 ++xml_flag;
888 } else {
889 xml_flag = 4;
890 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200891 }
892 c += size;
Michal Vasko53b7da02018-02-13 15:28:42 +0100893 uc = lyxml_getutf8(ctx, c, &size);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200894 }
Radek Krejci674e1f82015-04-21 14:12:19 +0200895
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200896 /* store the name */
897 size = c - start;
898 attr->name = lydict_insert(ctx, start, size);
Radek Krejci674e1f82015-04-21 14:12:19 +0200899
900equal:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200901 /* check Eq mark that can be surrounded by whitespaces */
902 ign_xmlws(c);
903 if (*c != '=') {
Michal Vasko53b7da02018-02-13 15:28:42 +0100904 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "attribute definition, \"=\" expected");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200905 goto error;
906 }
907 c++;
908 ign_xmlws(c);
Radek Krejci02117302015-04-13 16:32:44 +0200909
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200910 /* process value part of the attribute */
911 if (!*c || (*c != '"' && *c != '\'')) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100912 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "attribute value, \" or \' expected");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200913 goto error;
914 }
915 delim = c;
Michal Vasko53b7da02018-02-13 15:28:42 +0100916 str = parse_text(ctx, ++c, *delim, &size);
917 if (!str && !size) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200918 goto error;
919 }
Michal Vasko53b7da02018-02-13 15:28:42 +0100920 attr->value = lydict_insert_zc(ctx, str);
Radek Krejci02117302015-04-13 16:32:44 +0200921
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200922 *len = c + size + 1 - data; /* +1 is delimiter size */
Radek Krejci00249f22015-07-07 13:43:28 +0200923
924 /* put attribute into the parent's attributes list */
925 if (parent->attr) {
926 /* go to the end of the list */
927 for (a = parent->attr; a->next; a = a->next);
928 /* and append new attribute */
929 a->next = attr;
930 } else {
931 /* add the first attribute in the list */
932 parent->attr = attr;
933 }
934
aweast069a6c02018-05-30 16:44:18 -0500935 free(prefix);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200936 return attr;
Radek Krejci02117302015-04-13 16:32:44 +0200937
938error:
Radek Krejci00249f22015-07-07 13:43:28 +0200939 lyxml_free_attr(ctx, NULL, attr);
aweast069a6c02018-05-30 16:44:18 -0500940 free(prefix);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200941 return NULL;
Radek Krejci54ea8de2015-04-09 18:02:56 +0200942}
943
Michal Vasko0d343d12015-08-24 14:57:36 +0200944/* logs directly */
Radek Krejci9a5daea2016-03-02 16:49:40 +0100945struct lyxml_elem *
Radek Krejcie1bacd72017-03-01 13:18:46 +0100946lyxml_parse_elem(struct ly_ctx *ctx, const char *data, unsigned int *len, struct lyxml_elem *parent, int options)
Radek Krejci54ea8de2015-04-09 18:02:56 +0200947{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200948 const char *c = data, *start, *e;
949 const char *lws; /* leading white space for handling mixed content */
950 int uc;
951 char *str;
aweast069a6c02018-05-30 16:44:18 -0500952 char *prefix = NULL;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200953 unsigned int prefix_len = 0;
954 struct lyxml_elem *elem = NULL, *child;
955 struct lyxml_attr *attr;
956 unsigned int size;
957 int nons_flag = 0, closed_flag = 0;
Radek Krejci02117302015-04-13 16:32:44 +0200958
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200959 *len = 0;
Radek Krejci02117302015-04-13 16:32:44 +0200960
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200961 if (*c != '<') {
962 return NULL;
963 }
Radek Krejci02117302015-04-13 16:32:44 +0200964
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200965 /* locate element name */
966 c++;
967 e = c;
Radek Krejci02117302015-04-13 16:32:44 +0200968
Michal Vasko53b7da02018-02-13 15:28:42 +0100969 uc = lyxml_getutf8(ctx, e, &size);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200970 if (!is_xmlnamestartchar(uc)) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100971 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "NameStartChar of the element");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200972 return NULL;
973 }
974 e += size;
Michal Vasko53b7da02018-02-13 15:28:42 +0100975 uc = lyxml_getutf8(ctx, e, &size);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200976 while (is_xmlnamechar(uc)) {
977 if (*e == ':') {
978 if (prefix_len) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100979 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "element name, multiple colons found");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200980 goto error;
981 }
982 /* element in a namespace */
983 start = e + 1;
Radek Krejci674e1f82015-04-21 14:12:19 +0200984
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200985 /* look for the prefix in namespaces */
aweast069a6c02018-05-30 16:44:18 -0500986 prefix_len = e - c;
Michal Vasko5f5096b2018-08-17 10:56:48 +0200987 LY_CHECK_ERR_GOTO(prefix, LOGVAL(ctx, LYE_XML_INCHAR, LY_VLOG_NONE, NULL, e), error);
aweast069a6c02018-05-30 16:44:18 -0500988 prefix = malloc((prefix_len + 1) * sizeof *prefix);
989 LY_CHECK_ERR_GOTO(!prefix, LOGMEM(ctx), error);
990 memcpy(prefix, c, prefix_len);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200991 prefix[prefix_len] = '\0';
992 c = start;
993 }
994 e += size;
Michal Vasko53b7da02018-02-13 15:28:42 +0100995 uc = lyxml_getutf8(ctx, e, &size);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200996 }
997 if (!*e) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100998 LOGVAL(ctx, LYE_EOF, LY_VLOG_NONE, NULL);
aweast069a6c02018-05-30 16:44:18 -0500999 free(prefix);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001000 return NULL;
1001 }
Radek Krejci02117302015-04-13 16:32:44 +02001002
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001003 /* allocate element structure */
1004 elem = calloc(1, sizeof *elem);
Michal Vasko64e6cf82018-08-17 10:32:23 +02001005 LY_CHECK_ERR_RETURN(!elem, free(prefix); LOGMEM(ctx), NULL);
Radek Krejcia8d111f2017-05-31 13:57:37 +02001006
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001007 elem->next = NULL;
1008 elem->prev = elem;
1009 if (parent) {
Michal Vaskof8879c22015-08-21 09:07:36 +02001010 lyxml_add_child(ctx, parent, elem);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001011 }
Radek Krejci02117302015-04-13 16:32:44 +02001012
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001013 /* store the name into the element structure */
1014 elem->name = lydict_insert(ctx, c, e - c);
1015 c = e;
Radek Krejci02117302015-04-13 16:32:44 +02001016
1017process:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001018 ign_xmlws(c);
Radek Krejcifb783942016-10-06 09:49:33 +02001019 if (!strncmp("/>", c, 2)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001020 /* we are done, it was EmptyElemTag */
1021 c += 2;
Michal Vasko44913842016-04-13 14:20:41 +02001022 elem->content = lydict_insert(ctx, "", 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001023 closed_flag = 1;
1024 } else if (*c == '>') {
1025 /* process element content */
1026 c++;
1027 lws = NULL;
Radek Krejci02117302015-04-13 16:32:44 +02001028
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001029 while (*c) {
Radek Krejcifb783942016-10-06 09:49:33 +02001030 if (!strncmp(c, "</", 2)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001031 if (lws && !elem->child) {
1032 /* leading white spaces were actually content */
1033 goto store_content;
1034 }
Radek Krejci02117302015-04-13 16:32:44 +02001035
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001036 /* Etag */
1037 c += 2;
1038 /* get name and check it */
1039 e = c;
Michal Vasko53b7da02018-02-13 15:28:42 +01001040 uc = lyxml_getutf8(ctx, e, &size);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001041 if (!is_xmlnamestartchar(uc)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001042 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, elem, "NameStartChar of the element");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001043 goto error;
1044 }
1045 e += size;
Michal Vasko53b7da02018-02-13 15:28:42 +01001046 uc = lyxml_getutf8(ctx, e, &size);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001047 while (is_xmlnamechar(uc)) {
1048 if (*e == ':') {
1049 /* element in a namespace */
1050 start = e + 1;
Radek Krejci674e1f82015-04-21 14:12:19 +02001051
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001052 /* look for the prefix in namespaces */
aweast069a6c02018-05-30 16:44:18 -05001053 if (!prefix || memcmp(prefix, c, e - c)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001054 LOGVAL(ctx, LYE_SPEC, LY_VLOG_XML, elem,
Michal Vaskoff9336a2016-05-10 10:48:48 +02001055 "Invalid (different namespaces) opening (%s) and closing element tags.", elem->name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001056 goto error;
1057 }
1058 c = start;
1059 }
1060 e += size;
Michal Vasko53b7da02018-02-13 15:28:42 +01001061 uc = lyxml_getutf8(ctx, e, &size);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001062 }
1063 if (!*e) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001064 LOGVAL(ctx, LYE_EOF, LY_VLOG_NONE, NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001065 goto error;
1066 }
Radek Krejci02117302015-04-13 16:32:44 +02001067
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001068 /* check that it corresponds to opening tag */
1069 size = e - c;
1070 str = malloc((size + 1) * sizeof *str);
Michal Vasko53b7da02018-02-13 15:28:42 +01001071 LY_CHECK_ERR_GOTO(!str, LOGMEM(ctx), error);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001072 memcpy(str, c, e - c);
1073 str[e - c] = '\0';
1074 if (size != strlen(elem->name) || memcmp(str, elem->name, size)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001075 LOGVAL(ctx, LYE_SPEC, LY_VLOG_XML, elem,
Michal Vaskoff9336a2016-05-10 10:48:48 +02001076 "Invalid (mixed names) opening (%s) and closing (%s) element tags.", elem->name, str);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001077 free(str);
1078 goto error;
1079 }
1080 free(str);
1081 c = e;
Radek Krejci02117302015-04-13 16:32:44 +02001082
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001083 ign_xmlws(c);
1084 if (*c != '>') {
Michal Vasko53b7da02018-02-13 15:28:42 +01001085 LOGVAL(ctx, LYE_SPEC, LY_VLOG_XML, elem, "Data after closing element tag \"%s\".", elem->name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001086 goto error;
1087 }
1088 c++;
Michal Vaskoe00b7892016-04-14 10:12:18 +02001089 if (!(elem->flags & LYXML_ELEM_MIXED) && !elem->content) {
1090 /* there was no content, but we don't want NULL (only if mixed content) */
1091 elem->content = lydict_insert(ctx, "", 0);
1092 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001093 closed_flag = 1;
1094 break;
Radek Krejci02117302015-04-13 16:32:44 +02001095
Radek Krejcifb783942016-10-06 09:49:33 +02001096 } else if (!strncmp(c, "<?", 2)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001097 if (lws) {
1098 /* leading white spaces were only formatting */
1099 lws = NULL;
1100 }
1101 /* PI - ignore it */
1102 c += 2;
Michal Vasko53b7da02018-02-13 15:28:42 +01001103 if (parse_ignore(ctx, c, "?>", &size)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001104 goto error;
1105 }
1106 c += size;
Radek Krejcifb783942016-10-06 09:49:33 +02001107 } else if (!strncmp(c, "<!--", 4)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001108 if (lws) {
1109 /* leading white spaces were only formatting */
1110 lws = NULL;
1111 }
1112 /* Comment - ignore it */
1113 c += 4;
Michal Vasko53b7da02018-02-13 15:28:42 +01001114 if (parse_ignore(ctx, c, "-->", &size)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001115 goto error;
1116 }
1117 c += size;
Radek Krejcifb783942016-10-06 09:49:33 +02001118 } else if (!strncmp(c, "<![CDATA[", 9)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001119 /* CDSect */
1120 goto store_content;
1121 } else if (*c == '<') {
1122 if (lws) {
1123 if (elem->flags & LYXML_ELEM_MIXED) {
1124 /* we have a mixed content */
1125 goto store_content;
1126 } else {
1127 /* leading white spaces were only formatting */
1128 lws = NULL;
1129 }
1130 }
1131 if (elem->content) {
1132 /* we have a mixed content */
Radek Krejcie1bacd72017-03-01 13:18:46 +01001133 if (options & LYXML_PARSE_NOMIXEDCONTENT) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001134 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, elem, "XML element with mixed content");
Radek Krejcie1bacd72017-03-01 13:18:46 +01001135 goto error;
1136 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001137 child = calloc(1, sizeof *child);
Michal Vasko53b7da02018-02-13 15:28:42 +01001138 LY_CHECK_ERR_GOTO(!child, LOGMEM(ctx), error);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001139 child->content = elem->content;
1140 elem->content = NULL;
Michal Vaskof8879c22015-08-21 09:07:36 +02001141 lyxml_add_child(ctx, elem, child);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001142 elem->flags |= LYXML_ELEM_MIXED;
1143 }
Radek Krejcie1bacd72017-03-01 13:18:46 +01001144 child = lyxml_parse_elem(ctx, c, &size, elem, options);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001145 if (!child) {
1146 goto error;
1147 }
1148 c += size; /* move after processed child element */
1149 } else if (is_xmlws(*c)) {
1150 lws = c;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001151 ign_xmlws(c);
1152 } else {
Radek Krejci02117302015-04-13 16:32:44 +02001153store_content:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001154 /* store text content */
1155 if (lws) {
1156 /* process content including the leading white spaces */
1157 c = lws;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001158 lws = NULL;
1159 }
Michal Vasko53b7da02018-02-13 15:28:42 +01001160 str = parse_text(ctx, c, '<', &size);
1161 if (!str && !size) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001162 goto error;
1163 }
Michal Vasko53b7da02018-02-13 15:28:42 +01001164 elem->content = lydict_insert_zc(ctx, str);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001165 c += size; /* move after processed text content */
Radek Krejci02117302015-04-13 16:32:44 +02001166
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001167 if (elem->child) {
1168 /* we have a mixed content */
Radek Krejcie1bacd72017-03-01 13:18:46 +01001169 if (options & LYXML_PARSE_NOMIXEDCONTENT) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001170 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, elem, "XML element with mixed content");
Radek Krejcie1bacd72017-03-01 13:18:46 +01001171 goto error;
1172 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001173 child = calloc(1, sizeof *child);
Michal Vasko53b7da02018-02-13 15:28:42 +01001174 LY_CHECK_ERR_GOTO(!child, LOGMEM(ctx), error);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001175 child->content = elem->content;
1176 elem->content = NULL;
Michal Vaskof8879c22015-08-21 09:07:36 +02001177 lyxml_add_child(ctx, elem, child);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001178 elem->flags |= LYXML_ELEM_MIXED;
1179 }
1180 }
1181 }
1182 } else {
1183 /* process attribute */
1184 attr = parse_attr(ctx, c, &size, elem);
1185 if (!attr) {
1186 goto error;
1187 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001188 c += size; /* move after processed attribute */
Radek Krejci02117302015-04-13 16:32:44 +02001189
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001190 /* check namespace */
1191 if (attr->type == LYXML_ATTR_NS) {
aweast069a6c02018-05-30 16:44:18 -05001192 if ((!prefix || !prefix[0]) && !attr->name) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001193 if (attr->value) {
1194 /* default prefix */
1195 elem->ns = (struct lyxml_ns *)attr;
1196 } else {
1197 /* xmlns="" -> no namespace */
1198 nons_flag = 1;
1199 }
aweast069a6c02018-05-30 16:44:18 -05001200 } else if (prefix && prefix[0] && attr->name && !strncmp(attr->name, prefix, prefix_len + 1)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001201 /* matching namespace with prefix */
1202 elem->ns = (struct lyxml_ns *)attr;
1203 }
1204 }
Radek Krejci674e1f82015-04-21 14:12:19 +02001205
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001206 /* go back to finish element processing */
1207 goto process;
1208 }
Radek Krejci02117302015-04-13 16:32:44 +02001209
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001210 *len = c - data;
Radek Krejci02117302015-04-13 16:32:44 +02001211
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001212 if (!closed_flag) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001213 LOGVAL(ctx, LYE_XML_MISS, LY_VLOG_XML, elem, "closing element tag", elem->name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001214 goto error;
1215 }
Radek Krejci674e1f82015-04-21 14:12:19 +02001216
Michal Vasko36b72992020-02-25 12:12:47 +01001217 /* resolve all attribute prefixes */
1218 LY_TREE_FOR(elem->attr, attr) {
1219 if (attr->type == LYXML_ATTR_STD_UNRES) {
1220 str = (char *)attr->ns;
1221 attr->ns = lyxml_get_ns(elem, str);
1222 free(str);
1223 attr->type = LYXML_ATTR_STD;
1224 }
1225 }
1226
Radek Krejci78a230a2015-07-07 17:04:40 +02001227 if (!elem->ns && !nons_flag && parent) {
Radek Krejci4476d412015-07-10 15:35:01 +02001228 elem->ns = lyxml_get_ns(parent, prefix_len ? prefix : NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001229 }
aweast069a6c02018-05-30 16:44:18 -05001230 free(prefix);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001231 return elem;
Radek Krejci02117302015-04-13 16:32:44 +02001232
1233error:
Michal Vasko345da0a2015-12-02 10:35:55 +01001234 lyxml_free(ctx, elem);
aweast069a6c02018-05-30 16:44:18 -05001235 free(prefix);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001236 return NULL;
Radek Krejci54ea8de2015-04-09 18:02:56 +02001237}
1238
Michal Vasko0d343d12015-08-24 14:57:36 +02001239/* logs directly */
Radek Krejcic6704c82015-10-06 11:12:45 +02001240API struct lyxml_elem *
Radek Krejci722b0072016-02-01 17:09:45 +01001241lyxml_parse_mem(struct ly_ctx *ctx, const char *data, int options)
Radek Krejci54ea8de2015-04-09 18:02:56 +02001242{
GalaxyGorillac7777422019-10-07 16:01:23 +02001243 FUN_IN;
1244
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001245 const char *c = data;
1246 unsigned int len;
Radek Krejci851ea662016-01-08 09:30:53 +01001247 struct lyxml_elem *root, *first = NULL, *next;
Radek Krejci2342cf62016-01-29 16:48:23 +01001248
Radek Krejci19b9b252017-03-17 16:14:09 +01001249 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001250 LOGARG;
Radek Krejci19b9b252017-03-17 16:14:09 +01001251 return NULL;
1252 }
1253
Michal Vasko78c7cbf2021-01-25 17:15:59 +01001254 if (!data) {
1255 /* nothing to parse */
1256 return NULL;
1257 }
1258
Radek Krejci120f6242015-12-17 12:32:56 +01001259repeat:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001260 /* process document */
Radek Krejcif8ae23e2016-07-26 17:11:17 +02001261 while (1) {
1262 if (!*c) {
1263 /* eof */
Michal Vasko53b7da02018-02-13 15:28:42 +01001264 return first;
Radek Krejcif8ae23e2016-07-26 17:11:17 +02001265 } else if (is_xmlws(*c)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001266 /* skip whitespaces */
1267 ign_xmlws(c);
Radek Krejcifb783942016-10-06 09:49:33 +02001268 } else if (!strncmp(c, "<?", 2)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001269 /* XMLDecl or PI - ignore it */
1270 c += 2;
Michal Vasko53b7da02018-02-13 15:28:42 +01001271 if (parse_ignore(ctx, c, "?>", &len)) {
Radek Krejcicf748252017-09-04 11:11:14 +02001272 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001273 }
1274 c += len;
Radek Krejcifb783942016-10-06 09:49:33 +02001275 } else if (!strncmp(c, "<!--", 4)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001276 /* Comment - ignore it */
1277 c += 2;
Michal Vasko53b7da02018-02-13 15:28:42 +01001278 if (parse_ignore(ctx, c, "-->", &len)) {
Radek Krejcicf748252017-09-04 11:11:14 +02001279 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001280 }
1281 c += len;
Radek Krejcifb783942016-10-06 09:49:33 +02001282 } else if (!strncmp(c, "<!", 2)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001283 /* DOCTYPE */
1284 /* TODO - standalone ignore counting < and > */
Michal Vasko53b7da02018-02-13 15:28:42 +01001285 LOGERR(ctx, LY_EINVAL, "DOCTYPE not supported in XML documents.");
Radek Krejcicf748252017-09-04 11:11:14 +02001286 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001287 } else if (*c == '<') {
1288 /* element - process it in next loop to strictly follow XML
1289 * format
1290 */
1291 break;
Michal Vaskoc2e80562015-07-27 11:31:41 +02001292 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01001293 LOGVAL(ctx, LYE_XML_INCHAR, LY_VLOG_NONE, NULL, c);
Radek Krejcicf748252017-09-04 11:11:14 +02001294 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001295 }
1296 }
Radek Krejci02117302015-04-13 16:32:44 +02001297
Radek Krejcie1bacd72017-03-01 13:18:46 +01001298 root = lyxml_parse_elem(ctx, c, &len, NULL, options);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001299 if (!root) {
Radek Krejcicf748252017-09-04 11:11:14 +02001300 goto error;
Radek Krejci120f6242015-12-17 12:32:56 +01001301 } else if (!first) {
1302 first = root;
1303 } else {
1304 first->prev->next = root;
1305 root->prev = first->prev;
1306 first->prev = root;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001307 }
1308 c += len;
Radek Krejci02117302015-04-13 16:32:44 +02001309
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001310 /* ignore the rest of document where can be comments, PIs and whitespaces,
1311 * note that we are not detecting syntax errors in these parts
1312 */
1313 ign_xmlws(c);
1314 if (*c) {
Radek Krejci722b0072016-02-01 17:09:45 +01001315 if (options & LYXML_PARSE_MULTIROOT) {
Radek Krejci120f6242015-12-17 12:32:56 +01001316 goto repeat;
1317 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01001318 LOGWRN(ctx, "There are some not parsed data:\n%s", c);
Radek Krejci120f6242015-12-17 12:32:56 +01001319 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001320 }
Radek Krejci02117302015-04-13 16:32:44 +02001321
Radek Krejci120f6242015-12-17 12:32:56 +01001322 return first;
Radek Krejcicf748252017-09-04 11:11:14 +02001323
1324error:
1325 LY_TREE_FOR_SAFE(first, next, root) {
1326 lyxml_free(ctx, root);
1327 }
Radek Krejcicf748252017-09-04 11:11:14 +02001328 return NULL;
Radek Krejci02117302015-04-13 16:32:44 +02001329}
1330
Radek Krejcic6704c82015-10-06 11:12:45 +02001331API struct lyxml_elem *
Radek Krejci722b0072016-02-01 17:09:45 +01001332lyxml_parse_path(struct ly_ctx *ctx, const char *filename, int options)
Radek Krejci54ea8de2015-04-09 18:02:56 +02001333{
GalaxyGorillac7777422019-10-07 16:01:23 +02001334 FUN_IN;
1335
Radek Krejci6b3d9262015-12-03 13:45:27 +01001336 struct lyxml_elem *elem = NULL;
Radek Krejci0fb11502017-01-31 16:45:42 +01001337 size_t length;
Pavol Vicanb2570c12015-11-12 13:50:20 +01001338 int fd;
1339 char *addr;
1340
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001341 if (!filename || !ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001342 LOGARG;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001343 return NULL;
1344 }
Radek Krejci54ea8de2015-04-09 18:02:56 +02001345
Pavol Vicanb2570c12015-11-12 13:50:20 +01001346 fd = open(filename, O_RDONLY);
1347 if (fd == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001348 LOGERR(ctx, LY_EINVAL,"Opening file \"%s\" failed.", filename);
Pavol Vicanb2570c12015-11-12 13:50:20 +01001349 return NULL;
1350 }
Michal Vasko53b7da02018-02-13 15:28:42 +01001351 if (lyp_mmap(ctx, fd, 0, &length, (void **)&addr)) {
1352 LOGERR(ctx, LY_ESYS, "Mapping file descriptor into memory failed (%s()).", __func__);
Pavol Vicanb2570c12015-11-12 13:50:20 +01001353 goto error;
Radek Krejci10c216a2017-02-01 10:36:00 +01001354 } else if (!addr) {
1355 /* empty XML file */
1356 goto error;
Pavol Vicanb2570c12015-11-12 13:50:20 +01001357 }
Radek Krejci6b3d9262015-12-03 13:45:27 +01001358
Radek Krejci722b0072016-02-01 17:09:45 +01001359 elem = lyxml_parse_mem(ctx, addr, options);
Radek Krejci0fb11502017-01-31 16:45:42 +01001360 lyp_munmap(addr, length);
Radek Krejci30793ab2015-12-03 13:45:45 +01001361 close(fd);
Radek Krejci6b3d9262015-12-03 13:45:27 +01001362
Pavol Vicanb2570c12015-11-12 13:50:20 +01001363 return elem;
1364
1365error:
Radek Krejci6b3d9262015-12-03 13:45:27 +01001366 if (fd != -1) {
1367 close(fd);
1368 }
1369
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001370 return NULL;
Radek Krejci54ea8de2015-04-09 18:02:56 +02001371}
Radek Krejci02117302015-04-13 16:32:44 +02001372
Michal Vasko5db027d2015-10-09 14:38:50 +02001373int
Radek Krejcieb827b72018-02-23 10:05:02 +01001374lyxml_dump_text(struct lyout *out, const char *text, LYXML_DATA_TYPE type)
Radek Krejcif0023a92015-04-20 20:51:39 +02001375{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001376 unsigned int i, n;
Radek Krejcif0023a92015-04-20 20:51:39 +02001377
Michal Vasko5db027d2015-10-09 14:38:50 +02001378 if (!text) {
1379 return 0;
1380 }
1381
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001382 for (i = n = 0; text[i]; i++) {
1383 switch (text[i]) {
1384 case '&':
Radek Krejci5248f132015-10-09 10:34:25 +02001385 n += ly_print(out, "&amp;");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001386 break;
1387 case '<':
Radek Krejci5248f132015-10-09 10:34:25 +02001388 n += ly_print(out, "&lt;");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001389 break;
1390 case '>':
1391 /* not needed, just for readability */
Radek Krejci5248f132015-10-09 10:34:25 +02001392 n += ly_print(out, "&gt;");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001393 break;
Radek Krejci952a7252016-07-16 20:52:43 +02001394 case '"':
Radek Krejcieb827b72018-02-23 10:05:02 +01001395 if (type == LYXML_DATA_ATTR) {
1396 n += ly_print(out, "&quot;");
1397 break;
1398 }
1399 /* falls through */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001400 default:
Radek Krejci5248f132015-10-09 10:34:25 +02001401 ly_write(out, &text[i], 1);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001402 n++;
1403 }
1404 }
Radek Krejcif0023a92015-04-20 20:51:39 +02001405
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001406 return n;
Radek Krejcif0023a92015-04-20 20:51:39 +02001407}
1408
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001409static int
Michal Vaskob2f1db72016-11-16 13:57:35 +01001410dump_elem(struct lyout *out, const struct lyxml_elem *e, int level, int options, int last_elem)
Radek Krejcif0023a92015-04-20 20:51:39 +02001411{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001412 int size = 0;
1413 struct lyxml_attr *a;
1414 struct lyxml_elem *child;
1415 const char *delim, *delim_outer;
1416 int indent;
Radek Krejcif0023a92015-04-20 20:51:39 +02001417
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001418 if (!e->name) {
1419 /* mixed content */
1420 if (e->content) {
Radek Krejcieb827b72018-02-23 10:05:02 +01001421 return lyxml_dump_text(out, e->content, LYXML_DATA_ELEM);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001422 } else {
1423 return 0;
1424 }
1425 }
Radek Krejcif0023a92015-04-20 20:51:39 +02001426
Radek Krejci722b0072016-02-01 17:09:45 +01001427 delim = delim_outer = (options & LYXML_PRINT_FORMAT) ? "\n" : "";
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001428 indent = 2 * level;
1429 if ((e->flags & LYXML_ELEM_MIXED) || (e->parent && (e->parent->flags & LYXML_ELEM_MIXED))) {
1430 delim = "";
1431 }
1432 if (e->parent && (e->parent->flags & LYXML_ELEM_MIXED)) {
1433 delim_outer = "";
1434 indent = 0;
1435 }
Michal Vaskob2f1db72016-11-16 13:57:35 +01001436 if (last_elem && (options & LYXML_PRINT_NO_LAST_NEWLINE)) {
1437 delim_outer = "";
1438 }
Radek Krejcif0023a92015-04-20 20:51:39 +02001439
Radek Krejci722b0072016-02-01 17:09:45 +01001440 if (!(options & (LYXML_PRINT_OPEN | LYXML_PRINT_CLOSE | LYXML_PRINT_ATTRS)) || (options & LYXML_PRINT_OPEN)) {
Radek Krejcic6704c82015-10-06 11:12:45 +02001441 /* opening tag */
1442 if (e->ns && e->ns->prefix) {
Radek Krejci5248f132015-10-09 10:34:25 +02001443 size += ly_print(out, "%*s<%s:%s", indent, "", e->ns->prefix, e->name);
Radek Krejcic6704c82015-10-06 11:12:45 +02001444 } else {
Radek Krejci5248f132015-10-09 10:34:25 +02001445 size += ly_print(out, "%*s<%s", indent, "", e->name);
Radek Krejcic6704c82015-10-06 11:12:45 +02001446 }
Radek Krejci722b0072016-02-01 17:09:45 +01001447 } else if (options & LYXML_PRINT_CLOSE) {
Radek Krejcic6704c82015-10-06 11:12:45 +02001448 indent = 0;
1449 goto close;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001450 }
Radek Krejci674e1f82015-04-21 14:12:19 +02001451
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001452 /* attributes */
1453 for (a = e->attr; a; a = a->next) {
1454 if (a->type == LYXML_ATTR_NS) {
1455 if (a->name) {
oldermae80b74e2020-09-22 19:46:55 +08001456 size += ly_print(out, " xmlns:%s=\"", a->name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001457 } else {
oldermae80b74e2020-09-22 19:46:55 +08001458 size += ly_print(out, " xmlns=\"");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001459 }
1460 } else if (a->ns && a->ns->prefix) {
oldermae80b74e2020-09-22 19:46:55 +08001461 size += ly_print(out, " %s:%s=\"", a->ns->prefix, a->name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001462 } else {
oldermae80b74e2020-09-22 19:46:55 +08001463 size += ly_print(out, " %s=\"", a->name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001464 }
oldermae80b74e2020-09-22 19:46:55 +08001465
1466 if (a->value) {
1467 size += lyxml_dump_text(out, a->value, LYXML_DATA_ATTR);
1468 } else {
1469 size += ly_print(out, "&quot;&quot;");
1470 }
1471 size += ly_print(out, "\"");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001472 }
Radek Krejci674e1f82015-04-21 14:12:19 +02001473
Radek Krejcic6704c82015-10-06 11:12:45 +02001474 /* apply options */
Radek Krejci722b0072016-02-01 17:09:45 +01001475 if ((options & LYXML_PRINT_CLOSE) && (options & LYXML_PRINT_OPEN)) {
Radek Krejci5248f132015-10-09 10:34:25 +02001476 size += ly_print(out, "/>%s", delim);
Radek Krejcic6704c82015-10-06 11:12:45 +02001477 return size;
Radek Krejci722b0072016-02-01 17:09:45 +01001478 } else if (options & LYXML_PRINT_OPEN) {
Radek Krejci5248f132015-10-09 10:34:25 +02001479 ly_print(out, ">");
Radek Krejcic6704c82015-10-06 11:12:45 +02001480 return ++size;
Radek Krejci722b0072016-02-01 17:09:45 +01001481 } else if (options & LYXML_PRINT_ATTRS) {
Radek Krejcic6704c82015-10-06 11:12:45 +02001482 return size;
1483 }
1484
Michal Vasko3a611612016-04-14 10:12:56 +02001485 if (!e->child && (!e->content || !e->content[0])) {
Radek Krejci5248f132015-10-09 10:34:25 +02001486 size += ly_print(out, "/>%s", delim);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001487 return size;
Michal Vasko3a611612016-04-14 10:12:56 +02001488 } else if (e->content && e->content[0]) {
Radek Krejci5248f132015-10-09 10:34:25 +02001489 ly_print(out, ">");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001490 size++;
Radek Krejcif0023a92015-04-20 20:51:39 +02001491
Radek Krejcieb827b72018-02-23 10:05:02 +01001492 size += lyxml_dump_text(out, e->content, LYXML_DATA_ELEM);
Radek Krejcif0023a92015-04-20 20:51:39 +02001493
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001494 if (e->ns && e->ns->prefix) {
Radek Krejci5248f132015-10-09 10:34:25 +02001495 size += ly_print(out, "</%s:%s>%s", e->ns->prefix, e->name, delim);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001496 } else {
Radek Krejci5248f132015-10-09 10:34:25 +02001497 size += ly_print(out, "</%s>%s", e->name, delim);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001498 }
1499 return size;
1500 } else {
Radek Krejci5248f132015-10-09 10:34:25 +02001501 size += ly_print(out, ">%s", delim);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001502 }
Radek Krejci674e1f82015-04-21 14:12:19 +02001503
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001504 /* go recursively */
1505 LY_TREE_FOR(e->child, child) {
Radek Krejci722b0072016-02-01 17:09:45 +01001506 if (options & LYXML_PRINT_FORMAT) {
Michal Vaskob2f1db72016-11-16 13:57:35 +01001507 size += dump_elem(out, child, level + 1, LYXML_PRINT_FORMAT, 0);
Pavol Vicanbe7eef52015-10-22 14:07:48 +02001508 } else {
Michal Vaskob2f1db72016-11-16 13:57:35 +01001509 size += dump_elem(out, child, level, 0, 0);
Pavol Vicanbe7eef52015-10-22 14:07:48 +02001510 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001511 }
Radek Krejcif0023a92015-04-20 20:51:39 +02001512
Radek Krejcic6704c82015-10-06 11:12:45 +02001513close:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001514 /* closing tag */
1515 if (e->ns && e->ns->prefix) {
Radek Krejci5248f132015-10-09 10:34:25 +02001516 size += ly_print(out, "%*s</%s:%s>%s", indent, "", e->ns->prefix, e->name, delim_outer);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001517 } else {
Radek Krejci5248f132015-10-09 10:34:25 +02001518 size += ly_print(out, "%*s</%s>%s", indent, "", e->name, delim_outer);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001519 }
Radek Krejcif0023a92015-04-20 20:51:39 +02001520
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001521 return size;
Radek Krejcif0023a92015-04-20 20:51:39 +02001522}
1523
Radek Krejci8c56a5a2015-12-16 15:10:28 +01001524static int
1525dump_siblings(struct lyout *out, const struct lyxml_elem *e, int options)
1526{
Michal Vaskob2f1db72016-11-16 13:57:35 +01001527 const struct lyxml_elem *start, *iter, *next;
Radek Krejci8c56a5a2015-12-16 15:10:28 +01001528 int ret = 0;
1529
1530 if (e->parent) {
1531 start = e->parent->child;
1532 } else {
1533 start = e;
1534 while(start->prev && start->prev->next) {
1535 start = start->prev;
1536 }
1537 }
1538
Michal Vaskob2f1db72016-11-16 13:57:35 +01001539 LY_TREE_FOR_SAFE(start, next, iter) {
1540 ret += dump_elem(out, iter, 0, options, (next ? 0 : 1));
Radek Krejci8c56a5a2015-12-16 15:10:28 +01001541 }
1542
1543 return ret;
1544}
1545
Radek Krejcic6704c82015-10-06 11:12:45 +02001546API int
Radek Krejci722b0072016-02-01 17:09:45 +01001547lyxml_print_file(FILE *stream, const struct lyxml_elem *elem, int options)
Radek Krejcif0023a92015-04-20 20:51:39 +02001548{
GalaxyGorillac7777422019-10-07 16:01:23 +02001549 FUN_IN;
1550
Radek Krejci5248f132015-10-09 10:34:25 +02001551 struct lyout out;
1552
1553 if (!stream || !elem) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001554 return 0;
1555 }
Radek Krejcif0023a92015-04-20 20:51:39 +02001556
Michal Vasko002db142018-07-03 13:52:59 +02001557 memset(&out, 0, sizeof out);
1558
Radek Krejci5248f132015-10-09 10:34:25 +02001559 out.type = LYOUT_STREAM;
1560 out.method.f = stream;
1561
Radek Krejci722b0072016-02-01 17:09:45 +01001562 if (options & LYXML_PRINT_SIBLINGS) {
Radek Krejci8c56a5a2015-12-16 15:10:28 +01001563 return dump_siblings(&out, elem, options);
1564 } else {
Michal Vaskob2f1db72016-11-16 13:57:35 +01001565 return dump_elem(&out, elem, 0, options, 1);
Radek Krejci8c56a5a2015-12-16 15:10:28 +01001566 }
Radek Krejci5248f132015-10-09 10:34:25 +02001567}
1568
1569API int
Radek Krejci722b0072016-02-01 17:09:45 +01001570lyxml_print_fd(int fd, const struct lyxml_elem *elem, int options)
Radek Krejci5248f132015-10-09 10:34:25 +02001571{
GalaxyGorillac7777422019-10-07 16:01:23 +02001572 FUN_IN;
1573
Radek Krejci5248f132015-10-09 10:34:25 +02001574 struct lyout out;
1575
1576 if (fd < 0 || !elem) {
1577 return 0;
1578 }
1579
Michal Vasko002db142018-07-03 13:52:59 +02001580 memset(&out, 0, sizeof out);
1581
Radek Krejci5248f132015-10-09 10:34:25 +02001582 out.type = LYOUT_FD;
1583 out.method.fd = fd;
1584
Radek Krejci722b0072016-02-01 17:09:45 +01001585 if (options & LYXML_PRINT_SIBLINGS) {
Radek Krejci8c56a5a2015-12-16 15:10:28 +01001586 return dump_siblings(&out, elem, options);
1587 } else {
Michal Vaskob2f1db72016-11-16 13:57:35 +01001588 return dump_elem(&out, elem, 0, options, 1);
Radek Krejci8c56a5a2015-12-16 15:10:28 +01001589 }
Radek Krejcif0023a92015-04-20 20:51:39 +02001590}
Radek Krejci6140e4e2015-10-09 15:50:55 +02001591
1592API int
Radek Krejci722b0072016-02-01 17:09:45 +01001593lyxml_print_mem(char **strp, const struct lyxml_elem *elem, int options)
Radek Krejci2fa0fc12015-10-14 18:14:29 +02001594{
GalaxyGorillac7777422019-10-07 16:01:23 +02001595 FUN_IN;
1596
Radek Krejci2fa0fc12015-10-14 18:14:29 +02001597 struct lyout out;
1598 int r;
1599
1600 if (!strp || !elem) {
1601 return 0;
1602 }
1603
Michal Vasko002db142018-07-03 13:52:59 +02001604 memset(&out, 0, sizeof out);
1605
Radek Krejci2fa0fc12015-10-14 18:14:29 +02001606 out.type = LYOUT_MEMORY;
Radek Krejci2fa0fc12015-10-14 18:14:29 +02001607
Radek Krejci722b0072016-02-01 17:09:45 +01001608 if (options & LYXML_PRINT_SIBLINGS) {
Radek Krejci8c56a5a2015-12-16 15:10:28 +01001609 r = dump_siblings(&out, elem, options);
1610 } else {
Michal Vaskob2f1db72016-11-16 13:57:35 +01001611 r = dump_elem(&out, elem, 0, options, 1);
Radek Krejci8c56a5a2015-12-16 15:10:28 +01001612 }
Radek Krejci2fa0fc12015-10-14 18:14:29 +02001613
1614 *strp = out.method.mem.buf;
1615 return r;
1616}
1617
1618API int
Radek Krejci722b0072016-02-01 17:09:45 +01001619lyxml_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lyxml_elem *elem, int options)
Radek Krejci6140e4e2015-10-09 15:50:55 +02001620{
GalaxyGorillac7777422019-10-07 16:01:23 +02001621 FUN_IN;
1622
Radek Krejci6140e4e2015-10-09 15:50:55 +02001623 struct lyout out;
1624
1625 if (!writeclb || !elem) {
1626 return 0;
1627 }
1628
Michal Vasko002db142018-07-03 13:52:59 +02001629 memset(&out, 0, sizeof out);
1630
Radek Krejci6140e4e2015-10-09 15:50:55 +02001631 out.type = LYOUT_CALLBACK;
Radek Krejci50929eb2015-10-09 18:14:15 +02001632 out.method.clb.f = writeclb;
1633 out.method.clb.arg = arg;
Radek Krejci6140e4e2015-10-09 15:50:55 +02001634
Radek Krejci722b0072016-02-01 17:09:45 +01001635 if (options & LYXML_PRINT_SIBLINGS) {
Radek Krejci8c56a5a2015-12-16 15:10:28 +01001636 return dump_siblings(&out, elem, options);
1637 } else {
Michal Vaskob2f1db72016-11-16 13:57:35 +01001638 return dump_elem(&out, elem, 0, options, 1);
Radek Krejci8c56a5a2015-12-16 15:10:28 +01001639 }
Radek Krejci6140e4e2015-10-09 15:50:55 +02001640}