GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/xml.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 338 705 47.9%
Functions: 23 40 57.5%
Branches: 113 363 31.1%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/encode/xml.h"
30 #include "gate/results.h"
31 #include "gate/debugging.h"
32 #include "gate/utilities.h"
33
34
35
36 #define GATE_XML_CHAR_OPEN '<'
37 #define GATE_XML_CHAR_CLOSE '>'
38 #define GATE_XML_CHAR_END '/'
39 #define GATE_XML_CHAR_QUOTE '\"'
40 #define GATE_XML_CHAR_APOS '\''
41 #define GATE_XML_CHAR_EQUAL '='
42 #define GATE_XML_CHAR_AMPERSAND '&'
43 #define GATE_XML_CHAR_QUEST '?'
44 #define GATE_XML_CHAR_COLON ':'
45 #define GATE_XML_CHAR_EXCLAMATION '!'
46 #define GATE_XML_CHAR_SEMICOLON ';'
47
48 static char const GATE_XML_WHITESPACES[] = { ' ', '\r', '\n', '\t' };
49 #define GATE_XML_WHITESPACES_COUNT sizeof(GATE_XML_WHITESPACES)
50
51 #define GATE_XML_ENTITY_OPEN "&lt;"
52 #define GATE_XML_ENTITY_OPEN_LEN 4
53 #define GATE_XML_ENTITY_CLOSE "&gt;"
54 #define GATE_XML_ENTITY_CLOSE_LEN 4
55 #define GATE_XML_ENTITY_QUOTE "&quot;"
56 #define GATE_XML_ENTITY_QUOTE_LEN 6
57 #define GATE_XML_ENTITY_APOS "&apos;"
58 #define GATE_XML_ENTITY_APOS_LEN 6
59 #define GATE_XML_ENTITY_AMP "&amp;"
60 #define GATE_XML_ENTITY_AMP_LEN 5
61 #define GATE_XML_ENTITY_UNICODE_HEX "&#x"
62 #define GATE_XML_ENTITY_UNICODE_HEX_LEN 3
63 #define GATE_XML_ENTITY_UNICODE_DEC "&#"
64 #define GATE_XML_ENTITY_UNICODE_DEC_LEN 2
65
66 #define GATE_XML_CDATABEGIN "<![CDATA["
67 #define GATE_XML_CDATABEGIN_LENGTH 9
68 #define GATE_XML_CDATAEND "]]>"
69 #define GATE_XML_CDATAEND_LENGTH 3
70
71 #define GATE_XML_COMMENTBEGIN "<!--"
72 #define GATE_XML_COMMENTBEGIN_LENGTH 4
73 #define GATE_XML_COMMENTEND "-->"
74 #define GATE_XML_COMMENTEND_LENGTH 3
75
76 #define GATE_XML_DECLBEGIN "<?"
77 #define GATE_XML_DECLBEGIN_LENGTH 2
78 #define GATE_XML_DECLEND "?>"
79 #define GATE_XML_DECLEND_LENGTH 2
80
81
82 static char const xml_escape_chars[] =
83 {
84 GATE_XML_CHAR_OPEN, GATE_XML_CHAR_CLOSE, GATE_XML_CHAR_QUOTE, GATE_XML_CHAR_APOS, GATE_XML_CHAR_AMPERSAND
85 };
86 static gate_size_t xml_escape_chars_count = sizeof(xml_escape_chars);
87
88
89 gate_result_t gate_xml_encode(gate_string_t const* plaintext, gate_string_t* xmltext)
90 {
91 gate_result_t ret = GATE_RESULT_OK;
92 gate_size_t pos;
93 gate_strbuilder_t builder = GATE_INIT_EMPTY;
94 char const* ptr;
95 gate_size_t len;
96 do
97 {
98 ptr = gate_string_ptr(plaintext, 0);
99 len = gate_string_length(plaintext);
100
101 pos = gate_str_find_first_of(ptr, len, xml_escape_chars, xml_escape_chars_count, 0);
102 if (GATE_STR_NPOS == pos)
103 {
104 /* nothing to encode, we can copy the string */
105 if (NULL == gate_string_duplicate(xmltext, plaintext))
106 {
107 ret = GATE_RESULT_OUTOFMEMORY;
108 break;
109 }
110 }
111 else
112 {
113 gate_strbuilder_create(&builder, plaintext->length + 16 + plaintext->length / 10);
114 while (len-- != 0)
115 {
116 switch (*ptr)
117 {
118 case GATE_XML_CHAR_OPEN:
119 {
120 if (0 == gate_strbuilder_append_text(&builder, GATE_XML_ENTITY_OPEN, GATE_XML_ENTITY_OPEN_LEN))
121 {
122 ret = GATE_RESULT_OUTOFMEMORY;
123 }
124 break;
125 }
126 case GATE_XML_CHAR_CLOSE:
127 {
128 if (0 == gate_strbuilder_append_text(&builder, GATE_XML_ENTITY_CLOSE, GATE_XML_ENTITY_CLOSE_LEN))
129 {
130 ret = GATE_RESULT_OUTOFMEMORY;
131 }
132 break;
133 }
134 case GATE_XML_CHAR_QUOTE:
135 {
136 if (0 == gate_strbuilder_append_text(&builder, GATE_XML_ENTITY_QUOTE, GATE_XML_ENTITY_QUOTE_LEN))
137 {
138 ret = GATE_RESULT_OUTOFMEMORY;
139 }
140 break;
141 }
142 case GATE_XML_CHAR_APOS:
143 {
144 if (0 == gate_strbuilder_append_text(&builder, GATE_XML_ENTITY_APOS, GATE_XML_ENTITY_APOS_LEN))
145 {
146 ret = GATE_RESULT_OUTOFMEMORY;
147 }
148 break;
149 }
150 case GATE_XML_CHAR_AMPERSAND:
151 {
152 if (0 == gate_strbuilder_append_text(&builder, GATE_XML_ENTITY_AMP, GATE_XML_ENTITY_AMP_LEN))
153 {
154 ret = GATE_RESULT_OUTOFMEMORY;
155 }
156 break;
157 }
158 default:
159 {
160 if (0 == gate_strbuilder_append_text(&builder, ptr, 1))
161 {
162 ret = GATE_RESULT_OUTOFMEMORY;
163 }
164 break;
165 }
166 }
167 ++ptr;
168 }
169 if (GATE_SUCCEEDED(ret))
170 {
171 if (NULL == gate_strbuilder_to_string(&builder, xmltext))
172 {
173 ret = GATE_RESULT_OUTOFMEMORY;
174 }
175 }
176 }
177
178 } while (0);
179
180 gate_strbuilder_release(&builder);
181
182 return ret;
183 }
184 43 gate_result_t gate_xml_decode(gate_string_t const* xmltext, gate_string_t* plaintext)
185 {
186 43 gate_result_t ret = GATE_RESULT_OK;
187 43 gate_strbuilder_t builder = GATE_INIT_EMPTY;
188 char const* ptr;
189 gate_size_t len;
190 gate_size_t pos;
191 char chars_to_add[8];
192 43 gate_size_t chars_to_add_len = 1;
193 gate_size_t chars_decoded;
194 gate_uint64_t u64;
195 gate_char32_t chr32;
196
197 do
198 {
199 43 ptr = gate_string_ptr(xmltext, 0);
200 43 len = gate_string_length(xmltext);
201
202 43 pos = gate_str_char_pos(ptr, len, GATE_XML_CHAR_AMPERSAND, 0);
203
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 20 times.
43 if (GATE_STR_NPOS == pos)
204 {
205 /* nothing to decode -> return copy of string */
206
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
23 if (NULL == gate_string_duplicate(plaintext, xmltext))
207 {
208 ret = GATE_RESULT_OUTOFMEMORY;
209 }
210 23 break;
211 }
212
213 20 gate_strbuilder_create(&builder, len);
214
215
2/2
✓ Branch 0 taken 18061 times.
✓ Branch 1 taken 20 times.
18081 while (len != 0)
216 {
217 18061 chars_to_add_len = 1;
218
2/2
✓ Branch 0 taken 1021 times.
✓ Branch 1 taken 17040 times.
18061 if (*ptr == GATE_XML_CHAR_AMPERSAND)
219 {
220
2/2
✓ Branch 1 taken 500 times.
✓ Branch 2 taken 521 times.
1021 if (gate_str_starts_with(ptr, len, GATE_XML_ENTITY_OPEN, GATE_XML_ENTITY_OPEN_LEN))
221 {
222 500 chars_to_add[0] = GATE_XML_CHAR_OPEN;
223 500 chars_decoded = GATE_XML_ENTITY_OPEN_LEN;
224 }
225
2/2
✓ Branch 1 taken 500 times.
✓ Branch 2 taken 21 times.
521 else if (gate_str_starts_with(ptr, len, GATE_XML_ENTITY_CLOSE, GATE_XML_ENTITY_CLOSE_LEN))
226 {
227 500 chars_to_add[0] = GATE_XML_CHAR_CLOSE;
228 500 chars_decoded = GATE_XML_ENTITY_CLOSE_LEN;
229 }
230
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
21 else if (gate_str_starts_with(ptr, len, GATE_XML_ENTITY_QUOTE, GATE_XML_ENTITY_QUOTE_LEN))
231 {
232 chars_to_add[0] = GATE_XML_CHAR_QUOTE;
233 chars_decoded = GATE_XML_ENTITY_QUOTE_LEN;
234 }
235
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
21 else if (gate_str_starts_with(ptr, len, GATE_XML_ENTITY_APOS, GATE_XML_ENTITY_APOS_LEN))
236 {
237 chars_to_add[0] = GATE_XML_CHAR_APOS;
238 chars_decoded = GATE_XML_ENTITY_APOS_LEN;
239 }
240
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 else if (gate_str_starts_with(ptr, len, GATE_XML_ENTITY_AMP, GATE_XML_ENTITY_AMP_LEN))
241 {
242 21 chars_to_add[0] = GATE_XML_CHAR_AMPERSAND;
243 21 chars_decoded = GATE_XML_ENTITY_AMP_LEN;
244 }
245 else if (gate_str_starts_with(ptr, len, GATE_XML_ENTITY_UNICODE_HEX, GATE_XML_ENTITY_UNICODE_HEX_LEN))
246 {
247 pos = gate_str_char_pos(ptr, len, GATE_XML_CHAR_SEMICOLON, GATE_XML_ENTITY_UNICODE_HEX_LEN);
248 if (GATE_STR_NPOS == pos)
249 {
250 ret = GATE_RESULT_INVALIDDATA;
251 break;
252 }
253 if (0 == gate_str_parse_hex_int(ptr + GATE_XML_ENTITY_UNICODE_HEX_LEN, pos - GATE_XML_ENTITY_UNICODE_HEX_LEN, &u64))
254 {
255 ret = GATE_RESULT_INVALIDDATA;
256 break;
257 }
258 chr32 = (gate_char32_t)u64;
259 chars_to_add_len = gate_char_write_utf8(chr32, chars_to_add, sizeof(chars_to_add));
260 chars_decoded = pos + 1;
261 }
262 else if (gate_str_starts_with(ptr, len, GATE_XML_ENTITY_UNICODE_DEC, GATE_XML_ENTITY_UNICODE_DEC_LEN))
263 {
264 pos = gate_str_char_pos(ptr, len, GATE_XML_CHAR_SEMICOLON, GATE_XML_ENTITY_UNICODE_HEX_LEN);
265 if (GATE_STR_NPOS == pos)
266 {
267 ret = GATE_RESULT_INVALIDDATA;
268 break;
269 }
270 if (0 == gate_str_parse_uint64(ptr + GATE_XML_ENTITY_UNICODE_DEC_LEN, pos - GATE_XML_ENTITY_UNICODE_DEC_LEN, &u64))
271 {
272 ret = GATE_RESULT_INVALIDDATA;
273 break;
274 }
275 chr32 = (gate_char32_t)u64;
276 chars_to_add_len = gate_char_write_utf8(chr32, chars_to_add, sizeof(chars_to_add));
277 chars_decoded = pos + 1;
278 }
279 else
280 {
281 chars_to_add[0] = *ptr;
282 chars_decoded = 1;
283 }
284 }
285 else
286 {
287 17040 chars_to_add[0] = *ptr;
288 17040 chars_decoded = 1;
289 }
290
291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18061 times.
18061 if (chars_to_add_len == 0)
292 {
293 ret = GATE_RESULT_INVALIDOUTPUT;
294 break;
295 }
296
297
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18061 times.
18061 if (0 == gate_strbuilder_append_text(&builder, chars_to_add, chars_to_add_len))
298 {
299 ret = GATE_RESULT_OUTOFMEMORY;
300 break;
301 }
302
303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18061 times.
18061 if (chars_decoded > len)
304 {
305 ret = GATE_RESULT_CRITICALERROR;
306 break;
307 }
308
309 18061 len -= chars_decoded;
310 18061 ptr += chars_decoded;
311 }
312
313
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (GATE_SUCCEEDED(ret))
314 {
315
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 if (NULL == gate_strbuilder_to_string(&builder, plaintext))
316 {
317 ret = GATE_RESULT_OUTOFMEMORY;
318 break;
319 }
320 }
321 } while (0);
322
323 43 gate_strbuilder_release(&builder);
324
325 43 return ret;
326 }
327
328
329 68 static gate_result_t gate_xml_pair_cctor(void* dest, void const* src)
330 {
331 68 gate_xml_pair_t* dest_pair = (gate_xml_pair_t*)dest;
332 68 gate_xml_pair_t const* src_pair = (gate_xml_pair_t const*)src;
333
334
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 68 times.
68 if (NULL == gate_string_duplicate(&dest_pair->key, &src_pair->key))
335 {
336 return GATE_RESULT_OUTOFMEMORY;
337 }
338
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 68 times.
68 if (NULL == gate_string_duplicate(&dest_pair->value, &src_pair->value))
339 {
340 gate_string_release(&dest_pair->key);
341 return GATE_RESULT_OUTOFMEMORY;
342 }
343 68 return GATE_RESULT_OK;
344 }
345 180 static void gate_xml_pair_dtor(void* dest)
346 {
347 180 gate_xml_pair_t* dest_pair = (gate_xml_pair_t*)dest;
348 180 gate_string_release(&dest_pair->key);
349 180 gate_string_release(&dest_pair->value);
350 180 }
351
352
353 428 gate_result_t gate_xml_node_create(gate_xml_node_t* node, gate_enumint_t node_type,
354 gate_string_t const* tag, gate_array_t const* attributes,
355 gate_array_t const* child_nodes, gate_string_t const* content)
356 {
357 428 gate_result_t ret = GATE_RESULT_FAILED;
358 do
359 {
360 428 gate_mem_clear(node, sizeof(gate_xml_node_t));
361 428 node->node_type = node_type;
362
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 428 times.
428 if (NULL == gate_string_duplicate(&node->tag, tag))
363 {
364 ret = GATE_RESULT_OUTOFMEMORY;
365 break;
366 }
367
368
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 428 times.
428 if (NULL == gate_array_duplicate(&node->attributes, attributes))
369 {
370 ret = GATE_RESULT_OUTOFMEMORY;
371 break;
372 }
373
374
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 428 times.
428 if (NULL == gate_array_duplicate(&node->child_nodes, child_nodes))
375 {
376 ret = GATE_RESULT_OUTOFMEMORY;
377 break;
378 }
379
380
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 428 times.
428 if (NULL == gate_string_duplicate(&node->content, content))
381 {
382 ret = GATE_RESULT_OUTOFMEMORY;
383 break;
384 }
385 428 ret = GATE_RESULT_OK;
386 } while (0);
387
388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 428 times.
428 if (GATE_FAILED(ret))
389 {
390 gate_xml_node_destroy(node);
391
392 }
393 428 return ret;
394 }
395
396 446 gate_xml_node_t* gate_xml_node_duplicate(gate_xml_node_t* dest, gate_xml_node_t const* src)
397 {
398 446 gate_mem_clear(dest, sizeof(gate_xml_node_t));
399
400 446 gate_string_duplicate(&dest->tag, &src->tag);
401 446 gate_array_duplicate(&dest->attributes, &src->attributes);
402 446 gate_array_duplicate(&dest->child_nodes, &src->child_nodes);
403 446 gate_string_duplicate(&dest->content, &src->content);
404 446 dest->node_type = src->node_type;
405 446 return dest;
406 }
407
408
409 1300 gate_result_t gate_xml_node_destroy(gate_xml_node_t* node)
410 {
411 1300 gate_result_t ret = GATE_RESULT_OK;
412
413 1300 gate_string_release(&node->tag);
414 1300 gate_array_release(&node->attributes);
415 1300 gate_array_release(&node->child_nodes);
416 1300 gate_string_release(&node->content);
417
418 1300 gate_mem_clear(node, sizeof(gate_xml_node_t));
419
420 1300 return ret;
421 }
422
423 446 gate_result_t gate_xml_node_copy_constructor(void* destMem, void const* srcMem)
424 {
425
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 446 times.
446 if (NULL == gate_xml_node_duplicate((gate_xml_node_t*)destMem, (gate_xml_node_t const*)srcMem))
426 {
427 return GATE_RESULT_OUTOFMEMORY;
428 }
429 else
430 {
431 446 return GATE_RESULT_OK;
432 }
433 }
434 446 void gate_xml_node_destructor(void* destMem)
435 {
436 446 gate_xml_node_destroy((gate_xml_node_t*)destMem);
437 446 }
438
439
440 gate_result_t gate_xml_node_attribute_by_name(gate_xml_node_t const* node, gate_string_t const* attr_name, gate_string_t* attr_value)
441 {
442 gate_size_t length = gate_array_length(&node->attributes);
443 gate_size_t index;
444 gate_xml_pair_t const* ptr_pair;
445
446 for (index = 0; index != length; ++index)
447 {
448 ptr_pair = (gate_xml_pair_t const*)gate_array_get(&node->attributes, index);
449
450 if (0 == gate_string_comp(attr_name, &ptr_pair->key))
451 {
452 if (NULL == gate_string_duplicate(attr_value, &ptr_pair->value))
453 {
454 return GATE_RESULT_OUTOFMEMORY;
455 }
456 else
457 {
458 return GATE_RESULT_OK;
459 }
460 }
461 }
462 return GATE_RESULT_NOMATCH;
463 }
464
465 gate_string_t const* gate_xml_node_attribute_ptr_by_name(gate_xml_node_t const* node, gate_string_t const* attr_name)
466 {
467 gate_size_t length = gate_array_length(&node->attributes);
468 gate_size_t index;
469 gate_xml_pair_t const* ptr_pair;
470
471 for (index = 0; index != length; ++index)
472 {
473 ptr_pair = (gate_xml_pair_t const*)gate_array_get(&node->attributes, index);
474
475 if (0 == gate_string_comp(attr_name, &ptr_pair->key))
476 {
477 return &ptr_pair->value;
478 }
479 }
480 return NULL;
481 }
482
483
484 gate_size_t gate_xml_node_attribute_count(gate_xml_node_t const* node)
485 {
486 return gate_array_length(&node->attributes);
487 }
488
489 gate_result_t gate_xml_node_attribute_by_index(gate_xml_node_t const* node, gate_size_t index,
490 gate_string_t* attr_name, gate_string_t* attr_value)
491 {
492 gate_xml_pair_t const* ptr_pair = (gate_xml_pair_t const*)gate_array_get(&node->attributes, index);
493 if (NULL == ptr_pair)
494 {
495 return GATE_RESULT_OUTOFBOUNDS;
496 }
497 else
498 {
499 if (attr_name)
500 {
501 gate_string_duplicate(attr_name, &ptr_pair->key);
502 }
503 if (attr_value)
504 {
505 gate_string_duplicate(attr_value, &ptr_pair->value);
506 }
507 return GATE_RESULT_OK;
508 }
509 }
510
511 89 gate_size_t gate_xml_node_children_count(gate_xml_node_t const* node)
512 {
513 89 return gate_array_length(&node->child_nodes);
514 }
515
516 gate_result_t gate_xml_node_child(gate_xml_node_t const* node, gate_size_t index, gate_xml_node_t* child)
517 {
518 gate_xml_node_t const* ptr = (gate_xml_node_t const*)gate_array_get(&node->child_nodes, index);
519 if (ptr)
520 {
521 return gate_xml_node_create(child, ptr->node_type, &ptr->tag, &ptr->attributes, &ptr->child_nodes, &ptr->content);
522 }
523 else
524 {
525 return GATE_RESULT_OUTOFBOUNDS;
526 }
527 }
528
529 462 gate_xml_node_t const* gate_xml_node_child_ptr(gate_xml_node_t const* node, gate_size_t index)
530 {
531 462 gate_xml_node_t const* ptr = (gate_xml_node_t const*)gate_array_get(&node->child_nodes, index);
532 462 return ptr;
533 }
534
535
536
537 gate_size_t gate_xml_parse_next_whitespace(gate_string_t const* xmltoken)
538 {
539 return gate_str_find_first_of(xmltoken->str, xmltoken->length, GATE_XML_WHITESPACES, sizeof(GATE_XML_WHITESPACES), 0);
540 }
541 gate_size_t gate_xml_parse_trim_whitespaces(gate_string_t* xmltoken)
542 {
543 gate_size_t pos = gate_str_find_first_not_of(xmltoken->str, xmltoken->length, GATE_XML_WHITESPACES, sizeof(GATE_XML_WHITESPACES), 0);
544 if (pos == GATE_STR_NPOS)
545 {
546 pos = xmltoken->length;
547 gate_string_release(xmltoken);
548 }
549 else
550 {
551 xmltoken->str += pos;
552 xmltoken->length -= pos;
553 }
554 return pos;
555 }
556
557 425 gate_size_t gate_xml_parse_tag_content(gate_string_t const* text, gate_string_t* tag_content, gate_enumint_t* ptr_node_type)
558 {
559 425 gate_size_t chars_parsed = 0;
560 425 gate_size_t text_len = gate_string_length(text);
561 char const* ptr_text;
562 gate_size_t pos;
563 425 gate_enumint_t node_type = GATE_XML_NODE_TYPE_NONE;
564 425 gate_string_t dummy = GATE_STRING_INIT_EMPTY;
565
566 do
567 {
568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 425 times.
425 if (NULL == tag_content)
569 {
570 tag_content = &dummy;
571 }
572
573
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 425 times.
425 if (text_len < 3)
574 { /* smallest tag has at least 3 characters: e.g. "<a>" */
575 break;
576 }
577 425 ptr_text = text->str;
578
579
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 425 times.
425 if (*ptr_text != GATE_XML_CHAR_OPEN)
580 { /* tag must begin with open-character */
581 break;
582 }
583
584 /* check for comment */
585
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 425 times.
425 if (gate_str_starts_with(ptr_text, text_len, GATE_XML_COMMENTBEGIN, GATE_XML_COMMENTBEGIN_LENGTH))
586 {
587 /* comment node detected */
588 node_type = GATE_XML_NODE_TYPE_COMMENT;
589 pos = gate_str_pos(ptr_text, text_len, GATE_XML_COMMENTEND, GATE_XML_COMMENTEND_LENGTH, GATE_XML_COMMENTBEGIN_LENGTH);
590 if (GATE_STR_NPOS == pos)
591 {
592 /* comment-ending not found */
593 break;
594 }
595 if (NULL == gate_string_substr(tag_content, text, GATE_XML_COMMENTBEGIN_LENGTH, pos - GATE_XML_COMMENTBEGIN_LENGTH))
596 {
597 /* substring allocation failed */
598 break;
599 }
600
601 chars_parsed = pos + GATE_XML_COMMENTEND_LENGTH;
602 break;
603 }
604
605 /* check for CDATA */
606
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 425 times.
425 if (gate_str_starts_with(ptr_text, text_len, GATE_XML_CDATABEGIN, GATE_XML_CDATABEGIN_LENGTH))
607 {
608 /* CDATA node detected */
609 node_type = GATE_XML_NODE_TYPE_CDATA;
610 pos = gate_str_pos(ptr_text, text_len, GATE_XML_CDATAEND, GATE_XML_CDATAEND_LENGTH, GATE_XML_CDATABEGIN_LENGTH);
611 if (GATE_STR_NPOS == pos)
612 {
613 /* CDATA-ending not found */
614 break;
615 }
616 if (NULL == gate_string_substr(tag_content, text, GATE_XML_CDATABEGIN_LENGTH, pos - GATE_XML_CDATABEGIN_LENGTH))
617 {
618 /* substring allocation failed */
619 break;
620 }
621
622 chars_parsed = pos + GATE_XML_CDATAEND_LENGTH;
623 break;
624 }
625
626 /* check for DECLARATION */
627
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 424 times.
425 if (gate_str_starts_with(ptr_text, text_len, GATE_XML_DECLBEGIN, GATE_XML_DECLBEGIN_LENGTH))
628 {
629 /* DECLARATION node detected */
630 1 node_type = GATE_XML_NODE_TYPE_DECLARATION;
631 1 pos = gate_str_pos(ptr_text, text_len, GATE_XML_DECLEND, GATE_XML_DECLEND_LENGTH, GATE_XML_DECLBEGIN_LENGTH);
632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_STR_NPOS == pos)
633 {
634 /* DECLARATION-ending not found */
635 break;
636 }
637
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_string_substr(tag_content, text, GATE_XML_DECLBEGIN_LENGTH, pos - GATE_XML_DECLBEGIN_LENGTH))
638 {
639 /* substring allocation failed */
640 break;
641 }
642 1 gate_string_trim(tag_content, tag_content);
643
644 1 chars_parsed = pos + GATE_XML_DECLEND_LENGTH;
645 1 break;
646 }
647
648 /* generic DTD*/
649
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 424 times.
424 if (ptr_text[1] == GATE_XML_CHAR_EXCLAMATION)
650 {
651 /* DTD node detected */
652 node_type = GATE_XML_NODE_TYPE_DTD;
653 pos = gate_str_char_pos(ptr_text, text_len, GATE_XML_CHAR_CLOSE, 2);
654 if (GATE_STR_NPOS == pos)
655 {
656 /* TAG-ending not found */
657 break;
658 }
659 if (NULL == gate_string_substr(tag_content, text, 2, pos - 2))
660 {
661 /* substring allocation failed */
662 break;
663 }
664
665 chars_parsed = pos + 1;
666 break;
667 }
668
669 /* otherwise: assume a regular ELEMENT tag */
670 424 node_type = GATE_XML_NODE_TYPE_ELEMENT;
671 424 pos = gate_str_char_pos(ptr_text, text_len, GATE_XML_CHAR_CLOSE, 1);
672
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 424 times.
424 if (GATE_STR_NPOS == pos)
673 {
674 /* TAG-ending not found */
675 break;
676 }
677
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 424 times.
424 if (NULL == gate_string_substr(tag_content, text, 1, pos - 1))
678 {
679 /* substring allocation failed */
680 break;
681 }
682 424 gate_string_trim(tag_content, tag_content);
683
684 424 chars_parsed = pos + 1;
685 424 break;
686
687
688 } while (0);
689
690
1/2
✓ Branch 0 taken 425 times.
✗ Branch 1 not taken.
425 if (NULL != ptr_node_type)
691 {
692 425 *ptr_node_type = node_type;
693 }
694
695 425 gate_string_release(&dummy);
696
697 425 return chars_parsed;
698 }
699
700
701 1 gate_result_t gate_xml_parse_decompose_name(gate_string_t const* attribname, gate_string_t* prefix, gate_string_t* localname)
702 {
703 1 gate_result_t ret = GATE_RESULT_OK;
704 1 gate_size_t pos = gate_string_char_pos(attribname, GATE_XML_CHAR_COLON, 0);
705 gate_size_t len;
706
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_STR_NPOS == pos)
707 {
708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (prefix)
709 {
710 gate_string_create_empty(prefix);
711 }
712
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (attribname)
713 {
714 1 gate_string_duplicate(localname, attribname);
715 }
716 }
717 else
718 {
719 len = gate_string_length(attribname);
720 if ((pos == 0) && (pos + 1 == len))
721 {
722 ret = GATE_RESULT_INVALIDCONTENT;
723 }
724 else
725 {
726 if (prefix)
727 {
728 gate_string_substr(prefix, attribname, 0, pos);
729 }
730 if (attribname)
731 {
732 gate_string_substr(localname, attribname, pos + 1, len - pos - 1);
733 }
734 }
735 }
736 1 return ret;
737 }
738 /*
739 gate_result_t gate_xml_parser_decode_name(gate_string_t const* xmltoken, gate_string_t* name)
740 {
741 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
742 return ret;
743 }
744 gate_result_t gate_xml_parser_decode_attribute(gate_string_t const* xmltoken, gate_string_t* attribname, gate_string_t* attribvalue, gate_size_t* charsprocessed)
745 {
746 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
747 return ret;
748 }
749 gate_result_t gate_xml_parser_decode_nested_elements(gate_string_t const* xmltoken, gate_char8_t charopen, gate_char8_t charclose, gate_string_t* content, gate_size_t* charsprocessed)
750 {
751 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
752 return ret;
753 }
754 */
755
756 44 static gate_result_t gate_xml_node_parse_attributes(gate_string_t* tag_attribs, gate_arraylist_t list)
757 {
758 44 gate_result_t ret = GATE_RESULT_OK;
759 gate_size_t pos;
760 44 gate_xml_pair_t attr_pair = GATE_INIT_EMPTY;
761 char quot_char;
762
763 44 gate_mem_clear(&attr_pair, sizeof(attr_pair));
764 ;
765
2/2
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 44 times.
112 while (!gate_string_is_empty(gate_string_ltrim(tag_attribs, tag_attribs)))
766 {
767 68 pos = gate_string_char_pos(tag_attribs, GATE_XML_CHAR_EQUAL, 0);
768
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if (GATE_STR_NPOS == pos)
769 {
770 ret = GATE_RESULT_INVALIDCONTENT;
771 break;
772 }
773
774 68 gate_string_substr(&attr_pair.key, tag_attribs, 0, pos);
775
776 68 gate_string_substr(tag_attribs, tag_attribs, pos + 1, GATE_STR_NPOS);
777 68 gate_string_ltrim(tag_attribs, tag_attribs);
778
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 68 times.
68 if (gate_string_is_empty(tag_attribs))
779 {
780 ret = GATE_RESULT_INVALIDCONTENT;
781 break;
782 }
783 68 quot_char = tag_attribs->str[0];
784 68 pos = gate_str_char_pos(tag_attribs->str, tag_attribs->length, quot_char, 1);
785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if (GATE_STR_NPOS == pos)
786 {
787 ret = GATE_RESULT_INVALIDCONTENT;
788 break;
789 }
790 68 gate_string_substr(&attr_pair.value, tag_attribs, 1, pos - 1);
791
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 68 times.
68 if (NULL == gate_arraylist_add(list, &attr_pair))
792 {
793 ret = GATE_RESULT_OUTOFMEMORY;
794 break;
795 }
796 68 gate_xml_pair_dtor(&attr_pair);
797
798 68 gate_string_substr(tag_attribs, tag_attribs, pos + 1, GATE_STR_NPOS);
799
800 }
801 44 gate_xml_pair_dtor(&attr_pair);
802
803 44 return ret;
804 }
805
806 425 static gate_result_t gate_xml_node_parse_tag_content(gate_string_t const* tag_content, gate_string_t* tag_name, gate_array_t* attribs)
807 {
808 425 gate_result_t ret = GATE_RESULT_OK;
809 gate_size_t pos;
810 425 gate_string_t attrib_content = GATE_STRING_INIT_EMPTY;
811 425 gate_arraylist_t attrib_list = NULL;
812
813 do
814 {
815 425 pos = gate_str_find_first_of(tag_content->str, tag_content->length, GATE_XML_WHITESPACES, GATE_XML_WHITESPACES_COUNT, 0);
816
2/2
✓ Branch 0 taken 381 times.
✓ Branch 1 taken 44 times.
425 if (GATE_STR_NPOS == pos)
817 {
818 381 gate_string_duplicate(tag_name, tag_content);
819
1/2
✓ Branch 0 taken 381 times.
✗ Branch 1 not taken.
381 if (attribs != NULL)
820 {
821 381 gate_array_create_empty(attribs);
822 }
823 /* done, no attributes, tag completed */
824 381 break;
825 }
826
827 44 gate_string_substr(tag_name, tag_content, 0, pos);
828 44 gate_string_substr(&attrib_content, tag_content, pos + 1, GATE_STR_NPOS);
829 44 attrib_list = gate_arraylist_create(sizeof(gate_xml_pair_t), NULL, 8, &gate_xml_pair_cctor, &gate_xml_pair_dtor);
830
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 if (NULL == attrib_list)
831 {
832 ret = GATE_RESULT_OUTOFMEMORY;
833 break;
834 }
835 44 ret = gate_xml_node_parse_attributes(&attrib_content, attrib_list);
836
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 GATE_BREAK_IF_FAILED(ret);
837
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 if (attribs != NULL)
838 {
839 44 gate_array_create(attribs, attrib_list);
840 }
841 44 ret = GATE_RESULT_OK;
842 } while (0);
843
844 425 gate_arraylist_release(attrib_list);
845 425 gate_string_release(&attrib_content);
846 425 return ret;
847 }
848
849 425 gate_result_t gate_xml_node_parse(gate_string_t const* source, gate_xml_node_t* node, gate_size_t* bytes_parsed)
850 {
851 425 gate_result_t ret = GATE_RESULT_FAILED;
852 425 gate_string_t tag = GATE_STRING_INIT_EMPTY;
853 425 gate_string_t tag_content = GATE_STRING_INIT_EMPTY;
854 425 gate_string_t tag_name = GATE_STRING_INIT_EMPTY;
855 425 gate_array_t tag_attribs = GATE_INIT_EMPTY;
856 425 gate_arraylist_t sub_node_list = NULL;
857 425 gate_xml_node_t sub_node = GATE_INIT_EMPTY;
858 425 gate_array_t sub_nodes = GATE_INIT_EMPTY;
859 425 gate_string_t post_tag_data = GATE_STRING_INIT_EMPTY;
860 425 gate_string_t tag_text = GATE_STRING_INIT_EMPTY;
861 425 gate_enumint_t node_type = 0;
862 425 gate_size_t bytes_processed = 0;
863 425 gate_size_t subnode_bytes = 0;
864 gate_size_t count;
865 gate_bool_t single_tag;
866 gate_size_t pos;
867 gate_bool_t continue_sub_node_parsing;
868
869 do
870 {
871 425 gate_string_ltrim(&tag, source);
872
873 425 bytes_processed += gate_string_length(source) - gate_string_length(&tag);
874
875 425 count = gate_xml_parse_tag_content(&tag, &tag_content, &node_type);
876
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 425 times.
425 if (count == 0)
877 {
878 ret = GATE_RESULT_INVALIDCONTENT;
879 break;
880 }
881 425 gate_string_substr(&post_tag_data, &tag, count, GATE_STR_NPOS);
882 425 bytes_processed += count;
883
884 425 gate_string_trim(&tag_content, &tag_content);
885
886
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 424 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
425 switch (node_type)
887 {
888 case GATE_XML_NODE_TYPE_DTD:
889 {
890 ret = GATE_RESULT_NOTSUPPORTED;
891 break;
892 }
893 1 case GATE_XML_NODE_TYPE_DECLARATION:
894 {
895 1 ret = gate_xml_node_parse_tag_content(&tag_content, &tag_name, &tag_attribs);
896
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
897 1 ret = gate_xml_node_create(node, GATE_XML_NODE_TYPE_DECLARATION, &tag_name, &tag_attribs, NULL, NULL);
898 1 break;
899 }
900 case GATE_XML_NODE_TYPE_COMMENT:
901 {
902 ret = gate_xml_node_create(node, GATE_XML_NODE_TYPE_COMMENT, NULL, NULL, NULL, &tag_content);
903 break;
904 }
905 424 case GATE_XML_NODE_TYPE_ELEMENT:
906 {
907 424 single_tag = false;
908
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 424 times.
424 if (gate_string_ends_with_char(&tag_content, GATE_XML_CHAR_END))
909 {
910 single_tag = true;
911 gate_string_substr(&tag_content, &tag_content, 0, gate_string_length(&tag_content) - 1);
912 gate_string_rtrim(&tag_content, &tag_content);
913 }
914
2/2
✓ Branch 1 taken 212 times.
✓ Branch 2 taken 212 times.
424 else if (gate_string_starts_with_char(&tag_content, GATE_XML_CHAR_END))
915 {
916 212 single_tag = true;
917 212 gate_string_trim(&tag_content, &tag_content);
918 }
919
920 424 ret = gate_xml_node_parse_tag_content(&tag_content, &tag_name, &tag_attribs);
921
922
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 424 times.
424 if (GATE_FAILED(ret))
923 {
924 break;
925 }
926
927
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 212 times.
424 if (!single_tag)
928 {
929 212 continue_sub_node_parsing = true;
930 212 sub_node_list = gate_arraylist_create(sizeof(gate_xml_node_t), NULL, 0, &gate_xml_node_copy_constructor, &gate_xml_node_destructor);
931
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 if (NULL == sub_node_list)
932 {
933 ret = GATE_RESULT_OUTOFMEMORY;
934 }
935 else
936 {
937
2/2
✓ Branch 0 taken 422 times.
✓ Branch 1 taken 212 times.
634 while (continue_sub_node_parsing)
938 {
939 422 pos = gate_string_char_pos(&post_tag_data, GATE_XML_CHAR_OPEN, 0);
940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 422 times.
422 if (pos == GATE_STR_NPOS)
941 {
942 /* error: missing xml end tag */
943 ret = GATE_RESULT_INVALIDDATA;
944 break;
945 }
946 422 gate_string_substr(&tag_text, &post_tag_data, 0, pos);
947 422 gate_string_substr(&post_tag_data, &post_tag_data, pos, GATE_STR_NPOS);
948 422 bytes_processed += pos;
949 422 ret = gate_xml_node_parse(&post_tag_data, &sub_node, &subnode_bytes);
950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 422 times.
422 GATE_BREAK_IF_FAILED(ret);
951
952 422 bytes_processed += subnode_bytes;
953 422 gate_string_substr(&post_tag_data, &post_tag_data, subnode_bytes, GATE_STR_NPOS);
954
955
2/2
✓ Branch 1 taken 212 times.
✓ Branch 2 taken 210 times.
422 if (gate_string_starts_with_char(&sub_node.tag, GATE_XML_CHAR_END)
956
1/2
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
212 && (0 == gate_str_compare(tag_name.str, tag_name.length, sub_node.tag.str + 1, sub_node.tag.length - 1))
957 )
958 {
959 /* end tag found */
960 212 continue_sub_node_parsing = false;
961 }
962 else
963 {
964 210 gate_string_release(&tag_text);
965
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 210 times.
210 if (NULL == gate_arraylist_add(sub_node_list, &sub_node))
966 {
967 ret = GATE_RESULT_OUTOFMEMORY;
968 continue_sub_node_parsing = false;
969 }
970 }
971 422 gate_xml_node_destroy(&sub_node);
972 }
973
1/2
✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
212 if (GATE_SUCCEEDED(ret))
974 {
975 212 gate_array_create(&sub_nodes, sub_node_list);
976 }
977 }
978 }
979
980
1/2
✓ Branch 0 taken 424 times.
✗ Branch 1 not taken.
424 if (GATE_SUCCEEDED(ret))
981 {
982
4/4
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 214 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 392 times.
848 ret = gate_xml_node_create(node, GATE_XML_NODE_TYPE_ELEMENT, &tag_name, &tag_attribs,
983 424 (gate_array_length(&sub_nodes) > 0) ? &sub_nodes : NULL,
984 424 gate_string_is_empty(&tag_text) ? NULL : &tag_text);
985
986 }
987
988 424 gate_xml_node_destroy(&sub_node);
989 424 gate_arraylist_release(sub_node_list);
990 424 sub_node_list = NULL;
991 424 gate_array_release(&sub_nodes);
992 424 gate_string_release(&tag_text);
993
994 424 break;
995 }
996 case GATE_XML_NODE_TYPE_CDATA:
997 {
998 ret = gate_xml_node_create(node, GATE_XML_NODE_TYPE_CDATA, NULL, NULL, NULL, &tag_content);
999 break;
1000 }
1001
1002 case GATE_XML_NODE_TYPE_NONE:
1003 default:
1004 {
1005 ret = GATE_RESULT_NOTSUPPORTED;
1006 break;
1007 }
1008 }
1009
1010 } while (0);
1011
1012 425 gate_array_release(&sub_nodes);
1013 425 gate_arraylist_release(sub_node_list);
1014 425 gate_string_release(&tag_text);
1015 425 gate_string_release(&tag_name);
1016 425 gate_string_release(&post_tag_data);
1017 425 gate_string_release(&tag_content);
1018 425 gate_string_release(&tag);
1019 425 gate_array_release(&tag_attribs);
1020
1021
1/2
✓ Branch 0 taken 425 times.
✗ Branch 1 not taken.
425 if (NULL != bytes_parsed)
1022 {
1023 425 *bytes_parsed = bytes_processed;
1024 }
1025
1026 425 return ret;
1027 }
1028
1029
1030 1 static gate_result_t gate_xml_indent(gate_stream_t* stream, gate_size_t spaces)
1031 {
1032 1 gate_result_t ret = GATE_RESULT_OK;
1033 gate_size_t written;
1034 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
1035
1036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (spaces > sizeof(buffer))
1037 {
1038 spaces = sizeof(buffer);
1039 }
1040
1041 1 gate_mem_fill(buffer, ' ', spaces);
1042 1 ret = gate_stream_write_block(stream, buffer, spaces, &written);
1043 1 return ret;
1044 }
1045
1046 1 static gate_result_t gate_xml_print(gate_xml_node_t const* node, gate_stream_t* stream, gate_size_t level, gate_size_t indent_spaces)
1047 {
1048 1 gate_result_t ret = GATE_RESULT_OK;
1049 gate_size_t index;
1050 1 gate_size_t attr_length = gate_array_length(&node->attributes);
1051 1 gate_size_t child_count = gate_array_length(&node->child_nodes);
1052 1 gate_size_t content_length = gate_string_length(&node->content);
1053 gate_xml_pair_t const* pair;
1054 gate_xml_node_t const* child;
1055 1 gate_size_t spaces = level * indent_spaces;
1056
1057 do
1058 {
1059
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 switch (node->node_type)
1060 {
1061 case GATE_XML_NODE_TYPE_DTD:
1062 case GATE_XML_NODE_TYPE_DECLARATION:
1063 case GATE_XML_NODE_TYPE_COMMENT:
1064 case GATE_XML_NODE_TYPE_CDATA:
1065 {
1066 ret = GATE_RESULT_NOTSUPPORTED;
1067 break;
1068 }
1069 1 case GATE_XML_NODE_TYPE_ELEMENT:
1070 {
1071 1 ret = gate_xml_indent(stream, spaces);
1072
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1073
1074 1 ret = gate_stream_print(stream,
1075 GATE_PRINT_CHAR, GATE_XML_CHAR_OPEN,
1076 GATE_PRINT_STRING, &node->tag,
1077 GATE_PRINT_END);
1078
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1079
1080
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 for (index = 0; index != attr_length; ++index)
1081 {
1082 pair = (gate_xml_pair_t const*)gate_array_get(&node->attributes, index);
1083 if (pair)
1084 {
1085 ret = gate_stream_print(stream,
1086 GATE_PRINT_CHAR, ' ',
1087 GATE_PRINT_STRING, &pair->key,
1088 GATE_PRINT_CHAR, GATE_XML_CHAR_EQUAL,
1089 GATE_PRINT_CHAR, GATE_XML_CHAR_QUOTE,
1090 GATE_PRINT_STRING, &pair->value,
1091 GATE_PRINT_CHAR, GATE_XML_CHAR_QUOTE,
1092 GATE_PRINT_END);
1093 GATE_BREAK_IF_FAILED(ret);
1094 }
1095 }
1096
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1097
1098
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if ((child_count == 0) && (content_length == 0))
1099 {
1100
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 ret = gate_stream_print(stream,
1101 GATE_PRINT_CHAR, GATE_XML_CHAR_END,
1102 GATE_PRINT_CHAR, GATE_XML_CHAR_CLOSE,
1103 ((indent_spaces == 0) ? GATE_PRINT_END : GATE_PRINT_NEWLINE),
1104 GATE_PRINT_END);
1105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1106 }
1107 else if (child_count != 0)
1108 {
1109 ret = gate_stream_print(stream,
1110 GATE_PRINT_CHAR, GATE_XML_CHAR_CLOSE,
1111 ((indent_spaces == 0) ? GATE_PRINT_END : GATE_PRINT_NEWLINE),
1112 GATE_PRINT_END);
1113 GATE_BREAK_IF_FAILED(ret);
1114
1115 for (index = 0; index != child_count; ++index)
1116 {
1117 child = (gate_xml_node_t const*)gate_array_get(&node->child_nodes, index);
1118 if (child)
1119 {
1120 ret = gate_xml_print(child, stream, level + 1, indent_spaces);
1121 GATE_BREAK_IF_FAILED(ret);
1122 }
1123 }
1124 GATE_BREAK_IF_FAILED(ret);
1125
1126 ret = gate_xml_indent(stream, spaces);
1127 GATE_BREAK_IF_FAILED(ret);
1128
1129 ret = gate_stream_print(stream,
1130 GATE_PRINT_CHAR, GATE_XML_CHAR_OPEN,
1131 GATE_PRINT_CHAR, GATE_XML_CHAR_END,
1132 GATE_PRINT_STRING, &node->tag,
1133 GATE_PRINT_CHAR, GATE_XML_CHAR_CLOSE,
1134 ((indent_spaces == 0) ? GATE_PRINT_END : GATE_PRINT_NEWLINE),
1135 GATE_PRINT_END);
1136 GATE_BREAK_IF_FAILED(ret);
1137 }
1138 else
1139 {
1140 ret = gate_stream_print(stream,
1141 GATE_PRINT_CHAR, GATE_XML_CHAR_CLOSE,
1142 GATE_PRINT_STRING, &node->content,
1143 GATE_PRINT_CHAR, GATE_XML_CHAR_OPEN,
1144 GATE_PRINT_CHAR, GATE_XML_CHAR_END,
1145 GATE_PRINT_STRING, &node->tag,
1146 GATE_PRINT_CHAR, GATE_XML_CHAR_CLOSE,
1147 ((indent_spaces == 0) ? GATE_PRINT_END : GATE_PRINT_NEWLINE),
1148 GATE_PRINT_END);
1149 GATE_BREAK_IF_FAILED(ret);
1150 }
1151 1 break;
1152 }
1153 break;
1154 }
1155
1156 1 } while (0);
1157
1158 1 return ret;
1159 }
1160
1161
1162 1 gate_result_t gate_xml_node_print(gate_xml_node_t const* node, gate_stream_t* stream, gate_size_t indent_spaces)
1163 {
1164 1 gate_result_t ret = GATE_RESULT_FAILED;
1165 do
1166 {
1167 1 ret = gate_xml_print(node, stream, 0, indent_spaces);
1168 } while (0);
1169 1 return ret;
1170 }
1171
1172
1173
1174
1175 3 gate_result_t gate_xml_doc_create(gate_xml_doc_t* doc, gate_xml_node_t const* document_element)
1176 {
1177 3 gate_result_t ret = GATE_RESULT_FAILED;
1178
1179 do
1180 {
1181 3 gate_mem_clear(doc, sizeof(gate_xml_doc_t));
1182
1183
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (NULL == gate_util_stringset_create(&doc->token_map))
1184 {
1185 ret = GATE_RESULT_OUTOFMEMORY;
1186 break;
1187 }
1188
1189 3 doc->elemements = gate_arraylist_create(sizeof(gate_xml_node_t), NULL, 2, &gate_xml_node_copy_constructor, &gate_xml_node_destructor);
1190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (doc->elemements == NULL)
1191 {
1192 ret = GATE_RESULT_OUTOFBOUNDS;
1193 break;
1194 }
1195
1196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (document_element != NULL)
1197 {
1198 ret = gate_xml_doc_add_node(doc, NULL, document_element);
1199 }
1200 else
1201 {
1202 3 ret = GATE_RESULT_OK;
1203 }
1204
1205 } while (0);
1206
1207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(ret))
1208 {
1209 gate_xml_doc_destroy(doc);
1210 }
1211
1212 3 return ret;
1213 }
1214 3 gate_result_t gate_xml_doc_destroy(gate_xml_doc_t* doc)
1215 {
1216 3 gate_set_destroy(&doc->token_map);
1217 3 gate_arraylist_release(doc->elemements);
1218 3 gate_mem_clear(doc, sizeof(gate_xml_doc_t));
1219 3 return GATE_RESULT_OK;
1220 }
1221 1 gate_result_t gate_xml_doc_load(gate_xml_doc_t* doc, gate_stream_t* stream)
1222 {
1223 1 gate_result_t ret = GATE_RESULT_FAILED;
1224 1 gate_stringstream_t* ss = NULL;
1225 1 gate_string_t str = GATE_STRING_INIT_EMPTY;
1226
1227 do
1228 {
1229 1 ss = gate_stringstream_create(4096);
1230
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ss == NULL)
1231 {
1232 ret = GATE_RESULT_OUTOFMEMORY;
1233 break;
1234 }
1235
1236 1 ret = gate_stream_transfer(stream, (gate_stream_t*)ss);
1237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1238
1239 1 ret = gate_stringstream_to_string(ss, &str);
1240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1241
1242 1 ret = gate_xml_doc_load_text(doc, &str);
1243 } while (0);
1244
1245
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ss)
1246 {
1247 1 gate_object_release(ss);
1248 }
1249 1 gate_string_release(&str);
1250
1251 1 return ret;
1252
1253
1254 }
1255 gate_result_t gate_xml_doc_store(gate_xml_doc_t* doc, gate_stream_t* stream, gate_size_t indent_spaces)
1256 {
1257 gate_result_t ret = GATE_RESULT_FAILED;
1258 gate_size_t index;
1259 gate_size_t count;
1260 gate_xml_node_t const* ptr_node;
1261 do
1262 {
1263 if (!doc->elemements)
1264 {
1265 /* seems to be an empty document -> no serialization -> nothing to do */
1266 ret = GATE_RESULT_OK;
1267 break;
1268 }
1269
1270 count = gate_arraylist_length(doc->elemements);
1271
1272 ret = GATE_RESULT_OK;
1273 for (index = 0; index != count; ++index)
1274 {
1275 ptr_node = (gate_xml_node_t const*)gate_arraylist_get(doc->elemements, index);
1276 if (ptr_node)
1277 {
1278 ret = gate_xml_node_print(ptr_node, stream, indent_spaces);
1279 GATE_BREAK_IF_FAILED(ret);
1280 }
1281 }
1282 } while (0);
1283
1284 return ret;
1285 }
1286
1287 2 gate_result_t gate_xml_doc_load_text(gate_xml_doc_t* doc, gate_string_t const* text)
1288 {
1289 2 gate_result_t ret = GATE_RESULT_FAILED;
1290 2 gate_string_t xml = GATE_STRING_INIT_EMPTY;
1291 2 gate_xml_node_t node = GATE_INIT_EMPTY;
1292 2 gate_size_t bytes_parsed = 0;
1293 gate_enumint_t node_type;
1294 do
1295 {
1296 2 gate_string_clone(&xml, text);
1297
1298 2 ret = gate_xml_doc_create(doc, NULL);
1299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
1300
1301 2 node_type = GATE_XML_NODE_TYPE_NONE;
1302
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 while ((node_type != GATE_XML_NODE_TYPE_ELEMENT)
1303
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 && (GATE_RESULT_OK == (ret = gate_xml_node_parse(&xml, &node, &bytes_parsed))))
1304 {
1305
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (bytes_parsed == 0)
1306 {
1307 ret = GATE_RESULT_INVALIDDATA;
1308 break;
1309 }
1310
1311 3 gate_string_substr(&xml, &xml, bytes_parsed, GATE_STR_NPOS);
1312
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (NULL == gate_arraylist_add(doc->elemements, &node))
1313 {
1314 ret = GATE_RESULT_OUTOFMEMORY;
1315 break;
1316 }
1317 3 node_type = node.node_type;
1318 3 gate_xml_node_destroy(&node);
1319 }
1320
1321
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (GATE_SUCCEEDED(ret) && (node_type != GATE_XML_NODE_TYPE_ELEMENT))
1322 {
1323 /* there was no XML root element decoded */
1324 ret = GATE_RESULT_INVALIDCONTENT;
1325 }
1326 } while (0);
1327
1328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (GATE_FAILED(ret))
1329 {
1330 gate_xml_doc_destroy(doc);
1331 }
1332 2 gate_xml_node_destroy(&node);
1333 2 gate_string_release(&xml);
1334
1335 2 return ret;
1336 }
1337 gate_result_t gate_xml_doc_store_text(gate_xml_doc_t* doc, gate_string_t* text, gate_size_t indent_spaces)
1338 {
1339 gate_result_t ret = GATE_RESULT_FAILED;
1340 gate_stringstream_t* ss = NULL;
1341 do
1342 {
1343 ss = gate_stringstream_create(1024);
1344 if (NULL == ss)
1345 {
1346 ret = GATE_RESULT_OUTOFMEMORY;
1347 break;
1348 }
1349 ret = gate_xml_doc_store(doc, (gate_stream_t*)ss, indent_spaces);
1350 if (GATE_SUCCEEDED(ret))
1351 {
1352 ret = gate_stringstream_to_string(ss, text);
1353 }
1354
1355 } while (0);
1356
1357 if (NULL != ss)
1358 {
1359 gate_object_release(ss);
1360 }
1361
1362 return ret;
1363 }
1364
1365 1 gate_result_t gate_xml_doc_root_element(gate_xml_doc_t* doc, gate_xml_node_t const** ptr_document_element)
1366 {
1367 1 gate_result_t ret = GATE_RESULT_NOMATCH;
1368 gate_size_t count;
1369 gate_size_t index;
1370 1 gate_xml_node_t const* ptr_node = NULL;
1371 do
1372 {
1373 1 count = gate_arraylist_length(doc->elemements);
1374
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 for (index = 0; index != count; ++index)
1375 {
1376 2 ptr_node = (gate_xml_node_t const*)gate_arraylist_get(doc->elemements, index);
1377
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (ptr_node)
1378 {
1379
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (ptr_node->node_type == GATE_XML_NODE_TYPE_ELEMENT)
1380 {
1381
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_document_element)
1382 {
1383 1 *ptr_document_element = ptr_node;
1384 1 ret = GATE_RESULT_OK;
1385 1 break;
1386 }
1387 }
1388 }
1389 }
1390 } while (0);
1391 1 return ret;
1392 }
1393
1394 static gate_string_t const* resolve_string(gate_set_t* s, gate_string_t const* str)
1395 {
1396 gate_set_iterator_t iter = gate_set_get(s, str);
1397 if (iter == NULL)
1398 {
1399 iter = gate_set_add(s, str);
1400 if (iter == NULL)
1401 {
1402 return str;
1403 }
1404 }
1405 return (gate_string_t const*)gate_map_iterator_key(iter);
1406 }
1407
1408
1409 static gate_result_t gate_xml_doc_add(gate_xml_doc_t* doc, gate_arraylist_t parent_list, gate_xml_node_t const* child_node)
1410 {
1411 gate_result_t ret = GATE_RESULT_FAILED;
1412 gate_string_t tag_name = GATE_STRING_INIT_EMPTY;
1413 gate_string_t tag_content = GATE_STRING_INIT_EMPTY;
1414 gate_xml_pair_t new_pair = GATE_INIT_EMPTY;
1415 gate_xml_node_t new_node = GATE_INIT_EMPTY;
1416 gate_arraylist_t attribs = NULL;
1417 gate_arraylist_t children = NULL;
1418 gate_size_t count;
1419 gate_size_t index;
1420 gate_xml_node_t const* ptr_node = NULL;
1421 gate_xml_pair_t const* ptr_pair = NULL;
1422
1423 do
1424 {
1425 ret = GATE_RESULT_OK;
1426 count = gate_array_length(&child_node->child_nodes);
1427 if (count > 0)
1428 {
1429 children = gate_arraylist_create(sizeof(gate_xml_node_t), NULL, count, &gate_xml_node_copy_constructor, &gate_xml_node_destructor);
1430 if (children == NULL)
1431 {
1432 ret = GATE_RESULT_OUTOFMEMORY;
1433 break;
1434 }
1435 for (index = 0; index != count; ++index)
1436 {
1437 ptr_node = (gate_xml_node_t const*)gate_array_get(&child_node->child_nodes, index);
1438 if (ptr_node)
1439 {
1440 ret = gate_xml_doc_add(doc, children, ptr_node);
1441 GATE_BREAK_IF_FAILED(ret);
1442 }
1443 }
1444 GATE_BREAK_IF_FAILED(ret);
1445 }
1446
1447 count = gate_array_length(&child_node->attributes);
1448 if (count > 0)
1449 {
1450 attribs = gate_arraylist_create(sizeof(gate_xml_node_t), NULL, count, &gate_xml_pair_cctor, &gate_xml_pair_dtor);
1451 if (attribs == NULL)
1452 {
1453 ret = GATE_RESULT_OUTOFMEMORY;
1454 break;
1455 }
1456 for (index = 0; index != count; ++index)
1457 {
1458 ptr_pair = (gate_xml_pair_t const*)gate_array_get(&child_node->attributes, index);
1459 if (ptr_pair)
1460 {
1461 gate_string_duplicate(&new_pair.key, resolve_string(&doc->token_map, &ptr_pair->key));
1462 gate_string_duplicate(&new_pair.value, resolve_string(&doc->token_map, &ptr_pair->value));
1463 if (NULL == gate_arraylist_add(attribs, &new_pair))
1464 {
1465 ret = GATE_RESULT_OUTOFMEMORY;
1466 break;
1467 }
1468 gate_xml_pair_dtor(&new_pair);
1469 }
1470 }
1471 GATE_BREAK_IF_FAILED(ret);
1472 }
1473
1474 if (NULL == gate_array_create(&new_node.child_nodes, children))
1475 {
1476 ret = GATE_RESULT_OUTOFMEMORY;
1477 break;
1478 }
1479 if (NULL == gate_array_create(&new_node.attributes, attribs))
1480 {
1481 ret = GATE_RESULT_OUTOFMEMORY;
1482 break;
1483 }
1484
1485 gate_string_duplicate(&new_node.tag, resolve_string(&doc->token_map, &child_node->tag));
1486 gate_string_duplicate(&new_node.content, resolve_string(&doc->token_map, &child_node->content));
1487
1488 if (NULL == gate_arraylist_add(parent_list, &new_node))
1489 {
1490 ret = GATE_RESULT_OUTOFMEMORY;
1491 break;
1492 }
1493
1494 ret = GATE_RESULT_OK;
1495 } while (0);
1496
1497 gate_xml_node_destroy(&new_node);
1498
1499 gate_xml_pair_dtor(&new_pair);
1500 gate_arraylist_release(attribs);
1501 gate_arraylist_release(children);
1502 gate_string_release(&tag_name);
1503 gate_string_release(&tag_content);
1504
1505 return ret;
1506 }
1507
1508 gate_result_t gate_xml_doc_add_node(gate_xml_doc_t* doc, gate_xml_node_t* parent_node, gate_xml_node_t const* child_node)
1509 {
1510 gate_result_t ret;
1511 gate_arraylist_t list = NULL;
1512 gate_array_t new_children = GATE_INIT_EMPTY;
1513
1514 do
1515 {
1516 if (parent_node != NULL)
1517 {
1518 list = gate_arraylist_create(sizeof(gate_xml_node_t),
1519 gate_array_get(&parent_node->child_nodes, 0), gate_array_length(&parent_node->child_nodes),
1520 &gate_xml_node_copy_constructor, &gate_xml_node_destructor);
1521 if (list == NULL)
1522 {
1523 ret = GATE_RESULT_OUTOFMEMORY;
1524 break;
1525 }
1526 ret = gate_xml_doc_add(doc, list, child_node);
1527 GATE_BREAK_IF_FAILED(ret);
1528
1529 if (NULL == gate_array_create(&new_children, list))
1530 {
1531 ret = GATE_RESULT_OUTOFMEMORY;
1532 break;
1533 }
1534 gate_array_release(&parent_node->child_nodes);
1535 gate_array_duplicate(&parent_node->child_nodes, &new_children);
1536 }
1537 else
1538 {
1539 ret = gate_xml_doc_root_element(doc, NULL);
1540 if (GATE_SUCCEEDED(ret))
1541 {
1542 /* element is already present -> we cannot add another one! */
1543 ret = GATE_RESULT_INVALIDSTATE;
1544 break;
1545 }
1546
1547 /* add element as new root element */
1548 ret = gate_xml_doc_add(doc, doc->elemements, child_node);
1549 }
1550 } while (0);
1551
1552 gate_arraylist_release(list);
1553 gate_array_release(&new_children);
1554 return ret;
1555 }
1556
1557 gate_result_t gate_xml_doc_add_attribute(gate_xml_doc_t* doc, gate_xml_node_t* target_node,
1558 gate_string_t const* name, gate_string_t const* value)
1559 {
1560 return GATE_RESULT_NOTIMPLEMENTED;
1561 }
1562
1563 gate_result_t gate_xml_doc_remove_attribute(gate_xml_doc_t* doc, gate_xml_node_t* target_node, gate_string_t const* name)
1564 {
1565 return GATE_RESULT_NOTIMPLEMENTED;
1566 }
1567
1568 gate_result_t gate_xml_doc_remove_node(gate_xml_doc_t* doc, gate_xml_node_t* target_node, gate_size_t index)
1569 {
1570 return GATE_RESULT_NOTIMPLEMENTED;
1571 }
1572
1573 gate_result_t gate_xml_doc_set_node_content(gate_xml_doc_t* doc, gate_xml_node_t* target_node, gate_string_t const* content)
1574 {
1575 return GATE_RESULT_NOTIMPLEMENTED;
1576 }
1577