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