GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/xml.c
Date: 2026-06-21 00:38:37
Exec Total Coverage
Lines: 570 708 80.5%
Functions: 34 38 89.5%
Branches: 236 371 63.6%

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