GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/xml.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 469 704 66.6%
Functions: 32 40 80.0%
Branches: 177 363 48.8%

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