Bug Summary

File:bindings/xml/expat_xmlparser.c
Warning:line 350, column 16
File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name expat_xmlparser.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-libdom -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-libdom -resource-dir /usr/lib/llvm-19/lib/clang/19 -D _BSD_SOURCE -D _DEFAULT_SOURCE -I /var/lib/jenkins/workspace/scan-build-libdom/include/ -I /var/lib/jenkins/workspace/scan-build-libdom/src -I /var/lib/jenkins/workspace/scan-build-libdom/binding -D _ALIGNED=__attribute__((aligned)) -D STMTEXPR=1 -D DEBUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Og -Wwrite-strings -Wno-error -std=c99 -fconst-strings -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-libdom/clangScanBuildReports/2025-11-29-164526-2895463-1 -x c bindings/xml/expat_xmlparser.c
1/*
2 * This file is part of libdom.
3 * Licensed under the MIT License,
4 * http://www.opensource.org/licenses/mit-license.php
5 * Copyright 2012 Daniel Silverstone <dsilvers@netsurf-browser.org>
6 */
7
8#include <stdbool.h>
9#include <string.h>
10#include <assert.h>
11
12#include <stdlib.h>
13#include <stdio.h>
14
15#include <dom/dom.h>
16
17#include "xmlparser.h"
18#include "utils.h"
19
20#include <expat.h>
21
22/**
23 * expat XML parser object
24 */
25struct dom_xml_parser {
26 dom_msg msg; /**< Informational message function */
27 void *mctx; /**< Pointer to client data */
28 XML_Parser parser; /**< expat parser context */
29 struct dom_document *doc; /**< DOM Document we're building */
30 struct dom_node *current; /**< DOM node we're currently building */
31 bool_Bool is_cdata; /**< If the character data is cdata or text */
32};
33
34/* Binding functions */
35
36static void
37expat_xmlparser_start_element_handler(void *_parser,
38 const XML_Char *name,
39 const XML_Char **atts)
40{
41 dom_xml_parser *parser = _parser;
42 dom_exception err;
43 dom_element *elem, *ins_elem;
44 dom_string *tag_name;
45 dom_string *namespace = NULL((void*)0);
46 const XML_Char *ns_sep = strchr(name, '\n');
47
48 assert(parser->current)((parser->current) ? (void) (0) : __assert_fail ("parser->current"
, "bindings/xml/expat_xmlparser.c", 48, __extension__ __PRETTY_FUNCTION__
))
;
49
50 if (ns_sep != NULL((void*)0)) {
51 err = dom_string_create_interned((const uint8_t *)name,
52 ns_sep - name,
53 &namespace);
54 if (err != DOM_NO_ERR) {
55 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
56 "No memory for namespace name");
57 return;
58 }
59 name = ns_sep + 1;
60 }
61
62 err = dom_string_create_interned((const uint8_t *)name,
63 strlen(name),
64 &tag_name);
65 if (err != DOM_NO_ERR) {
66 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
67 "No memory for tag name");
68 if (namespace != NULL((void*)0))
69 dom_string_unref(namespace);
70 return;
71 }
72
73 if (namespace == NULL((void*)0))
74 err = dom_document_create_element(parser->doc,dom_document_create_element( (dom_document *) (parser->doc
), (tag_name), (struct dom_element **) (&elem))
75 tag_name, &elem)dom_document_create_element( (dom_document *) (parser->doc
), (tag_name), (struct dom_element **) (&elem))
;
76 else
77 err = dom_document_create_element_ns(parser->doc, namespace,dom_document_create_element_ns((dom_document *) (parser->doc
), (namespace), (tag_name), (struct dom_element **) (&elem
))
78 tag_name, &elem)dom_document_create_element_ns((dom_document *) (parser->doc
), (namespace), (tag_name), (struct dom_element **) (&elem
))
;
79 if (err != DOM_NO_ERR) {
80 if (namespace != NULL((void*)0))
81 dom_string_unref(namespace);
82 dom_string_unref(tag_name);
83 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
84 "Failed to create element '%s'", name);
85 return;
86 }
87
88 dom_string_unref(tag_name);
89 if (namespace != NULL((void*)0))
90 dom_string_unref(namespace);
91
92 /* Add attributes to the element */
93 while (*atts) {
94 dom_string *key, *value;
95 ns_sep = strchr(*atts, '\n');
96 if (ns_sep != NULL((void*)0)) {
97 err = dom_string_create_interned((const uint8_t *)(*atts),
98 ns_sep - (*atts),
99 &namespace);
100 if (err != DOM_NO_ERR) {
101 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
102 "No memory for attr namespace");
103 dom_node_unref(elem)dom_node_unref((dom_node *) (elem));
104 return;
105 }
106 } else
107 namespace = NULL((void*)0);
108 if (ns_sep == NULL((void*)0))
109 err = dom_string_create_interned((const uint8_t *)(*atts),
110 strlen(*atts), &key);
111 else
112 err = dom_string_create_interned((const uint8_t *)(ns_sep + 1),
113 strlen(ns_sep + 1),
114 &key);
115 if (err != DOM_NO_ERR) {
116 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
117 "No memory for attribute name");
118 if (namespace != NULL((void*)0))
119 dom_string_unref(namespace);
120 dom_node_unref(elem)dom_node_unref((dom_node *) (elem));
121 return;
122 }
123 atts++;
124 err = dom_string_create((const uint8_t *)(*atts),
125 strlen(*atts), &value);
126 if (err != DOM_NO_ERR) {
127 dom_node_unref(elem)dom_node_unref((dom_node *) (elem));
128 if (namespace != NULL((void*)0))
129 dom_string_unref(namespace);
130 dom_string_unref(key);
131 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
132 "No memory for attribute value");
133 return;
134 }
135 atts++;
136
137 if (namespace == NULL((void*)0))
138 err = dom_element_set_attribute(elem, key, value)dom_element_set_attribute( (dom_element *) (elem), (key), (value
))
;
139 else
140 err = dom_element_set_attribute_ns(elem, namespace,dom_element_set_attribute_ns((dom_element *) (elem), (namespace
), (key), (value))
141 key, value)dom_element_set_attribute_ns((dom_element *) (elem), (namespace
), (key), (value))
;
142 if (namespace != NULL((void*)0))
143 dom_string_unref(namespace);
144 dom_string_unref(key);
145 dom_string_unref(value);
146 if (err != DOM_NO_ERR) {
147 dom_node_unref(elem)dom_node_unref((dom_node *) (elem));
148 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
149 "No memory for setting attribute");
150 return;
151 }
152 }
153
154 err = dom_node_append_child(parser->current, (struct dom_node *) elem,dom_node_append_child( (dom_node *) (parser->current), (dom_node
*) ((struct dom_node *) elem), (dom_node **) ((struct dom_node
**) (void *) &ins_elem))
155 (struct dom_node **) (void *) &ins_elem)dom_node_append_child( (dom_node *) (parser->current), (dom_node
*) ((struct dom_node *) elem), (dom_node **) ((struct dom_node
**) (void *) &ins_elem))
;
156 if (err != DOM_NO_ERR) {
157 dom_node_unref(elem)dom_node_unref((dom_node *) (elem));
158 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
159 "No memory for appending child node");
160 return;
161 }
162
163 dom_node_unref(ins_elem)dom_node_unref((dom_node *) (ins_elem));
164
165 dom_node_unref(parser->current)dom_node_unref((dom_node *) (parser->current));
166 parser->current = (struct dom_node *)elem; /* Steal initial ref */
167}
168
169static void
170expat_xmlparser_end_element_handler(void *_parser,
171 const XML_Char *name)
172{
173 dom_xml_parser *parser = _parser;
174 dom_exception err;
175 dom_node *parent;
176
177 UNUSED(name)((void)(name));
178
179 assert(parser->current)((parser->current) ? (void) (0) : __assert_fail ("parser->current"
, "bindings/xml/expat_xmlparser.c", 179, __extension__ __PRETTY_FUNCTION__
))
;
180
181 err = dom_node_get_parent_node(parser->current, &parent)dom_node_get_parent_node( (dom_node *) (parser->current), (
dom_node **) (&parent))
;
182
183 if (parent == NULL((void*)0) || parent == (dom_node *)parser->doc) {
184 /* The XML has tried to close more than it should */
185 if (parent != NULL((void*)0))
186 dom_node_unref(parent)dom_node_unref((dom_node *) (parent));
187 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
188 "Attempted to close more than was opened.");
189 return;
190 }
191
192 if (err != DOM_NO_ERR) {
193 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
194 "Unable to find a parent while closing element.");
195 return;
196 }
197
198 dom_node_unref(parser->current)dom_node_unref((dom_node *) (parser->current));
199 parser->current = parent; /* Takes the ref given by get_parent_node */
200}
201
202static void
203expat_xmlparser_start_cdata_handler(void *_parser)
204{
205 dom_xml_parser *parser = _parser;
206
207 parser->is_cdata = true1;
208}
209
210static void
211expat_xmlparser_end_cdata_handler(void *_parser)
212{
213 dom_xml_parser *parser = _parser;
214
215 parser->is_cdata = false0;
216}
217
218static void
219expat_xmlparser_cdata_handler(void *_parser,
220 const XML_Char *s,
221 int len)
222{
223 dom_xml_parser *parser = _parser;
224 dom_string *data;
225 dom_exception err;
226 struct dom_node *cdata, *ins_cdata, *lastchild = NULL((void*)0);
227 dom_node_type ntype = 0;
228
229 assert(parser->current)((parser->current) ? (void) (0) : __assert_fail ("parser->current"
, "bindings/xml/expat_xmlparser.c", 229, __extension__ __PRETTY_FUNCTION__
))
;
230
231 err = dom_string_create((const uint8_t *)s, len, &data);
232 if (err != DOM_NO_ERR) {
233 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
234 "No memory for cdata section contents");
235 return;
236 }
237
238 err = dom_node_get_last_child(parser->current, &lastchild)dom_node_get_last_child( (dom_node *) (parser->current), (
dom_node **) (&lastchild))
;
239
240 if (err == DOM_NO_ERR && lastchild != NULL((void*)0)) {
241 err = dom_node_get_node_type(lastchild, &ntype)dom_node_get_node_type( (dom_node *) (lastchild), (dom_node_type
*) (&ntype))
;
242 }
243
244 if (err != DOM_NO_ERR) {
245 dom_string_unref(data);
246 if (lastchild != NULL((void*)0))
247 dom_node_unref(lastchild)dom_node_unref((dom_node *) (lastchild));
248 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
249 "No memory for cdata section");
250 return;
251 }
252
253 if (ntype == DOM_TEXT_NODE && parser->is_cdata == false0) {
254 /* We can append this text instead */
255 err = dom_characterdata_append_data(dom_characterdata_append_data( (struct dom_characterdata *) (
(dom_characterdata *)lastchild), (data))
256 (dom_characterdata *)lastchild, data)dom_characterdata_append_data( (struct dom_characterdata *) (
(dom_characterdata *)lastchild), (data))
;
257 dom_string_unref(data);
258 if (lastchild != NULL((void*)0))
259 dom_node_unref(lastchild)dom_node_unref((dom_node *) (lastchild));
260 if (err != DOM_NO_ERR) {
261 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
262 "No memory for cdata section");
263 }
264 return;
265 }
266
267 if (lastchild != NULL((void*)0))
268 dom_node_unref(lastchild)dom_node_unref((dom_node *) (lastchild));
269
270 /* We can't append directly, so make a new node */
271 err = parser->is_cdata ?
272 dom_document_create_cdata_section(parser->doc, data,dom_document_create_cdata_section((dom_document *) (parser->
doc), (data), (struct dom_cdata_section **) ((dom_cdata_section
**) (void *) &cdata))
273 (dom_cdata_section **) (void *) &cdata)dom_document_create_cdata_section((dom_document *) (parser->
doc), (data), (struct dom_cdata_section **) ((dom_cdata_section
**) (void *) &cdata))
:
274 dom_document_create_text_node(parser->doc, data,dom_document_create_text_node((dom_document *) (parser->doc
), (data), (struct dom_text **) ((dom_text **) (void *) &
cdata))
275 (dom_text **) (void *) &cdata)dom_document_create_text_node((dom_document *) (parser->doc
), (data), (struct dom_text **) ((dom_text **) (void *) &
cdata))
;
276 if (err != DOM_NO_ERR) {
277 dom_string_unref(data);
278 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
279 "No memory for cdata section");
280 return;
281 }
282
283 /* No longer need data */
284 dom_string_unref(data);
285
286 /* Append cdata section to parent */
287 err = dom_node_append_child(parser->current, cdata, &ins_cdata)dom_node_append_child( (dom_node *) (parser->current), (dom_node
*) (cdata), (dom_node **) (&ins_cdata))
;
288 if (err != DOM_NO_ERR) {
289 dom_node_unref((struct dom_node *) cdata)dom_node_unref((dom_node *) ((struct dom_node *) cdata));
290 parser->msg(DOM_MSG_ERROR, parser->mctx,
291 "Failed attaching cdata section");
292 return;
293 }
294
295 /* We're not interested in the inserted cdata section */
296 if (ins_cdata != NULL((void*)0))
297 dom_node_unref(ins_cdata)dom_node_unref((dom_node *) (ins_cdata));
298
299 /* No longer interested in cdata section */
300 dom_node_unref(cdata)dom_node_unref((dom_node *) (cdata));
301}
302
303static int
304expat_xmlparser_external_entity_ref_handler(XML_Parser parser,
1
[debug] analyzing from expat_xmlparser_external_entity_ref_handler
305 const XML_Char *context,
306 const XML_Char *base,
307 const XML_Char *system_id,
308 const XML_Char *public_id)
309{
310 FILE *fh;
311 XML_Parser subparser;
312 unsigned char data[1024];
313 size_t len;
314 enum XML_Status status;
315
316 UNUSED(base)((void)(base));
317 UNUSED(public_id)((void)(public_id));
318
319 if (system_id == NULL((void*)0))
2
Assuming 'system_id' is not equal to NULL
320 return XML_STATUS_OKXML_STATUS_OK;
321
322 /* If the ID is a network URI, return (see bug 2313 and below) */
323 if ((strncmp(system_id, "http://", 7) == 0) ||
3
Assuming the condition is false
5
Taking false branch
324 (strncmp(system_id, "https://", 8) == 0)) {
4
Assuming the condition is false
325 return XML_STATUS_OKXML_STATUS_OK;
326 }
327
328 /*\todo This needs fixing. Our system_id, if not
329 * absolute, needs to be made absolute relative to
330 * base before being opened. It should also be
331 * passed back to the client to be opened, as network
332 * addresses need special handling and local files
333 * should also have the file:// scheme, so fopen is
334 * not necessarily going to work. */
335 fh = fopen(system_id, "r");
336
337 if (fh
5.1
'fh' is not equal to NULL
== NULL((void*)0))
6
Taking false branch
338 return XML_STATUS_OKXML_STATUS_OK;
339
340 subparser = XML_ExternalEntityParserCreate(parser,
341 context,
342 NULL((void*)0));
343
344 if (subparser == NULL((void*)0)) {
7
Assuming 'subparser' is not equal to NULL
8
Taking false branch
345 fclose(fh);
346 return XML_STATUS_OKXML_STATUS_OK;
347 }
348
349 /* Parse the file bit by bit */
350 while ((len = fread(data, 1, 1024, fh)) > 0) {
9
Assuming this stream operation fails
10
Assuming the condition is true
11
Loop condition is true. Entering loop body
14
File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior
351 status = XML_Parse(subparser, (const char *)data, len, 0);
352 if (status != XML_STATUS_OKXML_STATUS_OK) {
12
Assuming 'status' is equal to XML_STATUS_OK
13
Taking false branch
353 XML_ParserFree(subparser);
354 fclose(fh);
355 return XML_STATUS_OKXML_STATUS_OK;
356 }
357 }
358 XML_Parse(subparser, "", 0, 1);
359 XML_ParserFree(subparser);
360 fclose(fh);
361 return XML_STATUS_OKXML_STATUS_OK;
362}
363
364static void
365expat_xmlparser_comment_handler(void *_parser,
366 const XML_Char *_comment)
367{
368 dom_xml_parser *parser = _parser;
369 struct dom_comment *comment, *ins_comment = NULL((void*)0);
370 dom_string *data;
371 dom_exception err;
372
373 assert(parser->current)((parser->current) ? (void) (0) : __assert_fail ("parser->current"
, "bindings/xml/expat_xmlparser.c", 373, __extension__ __PRETTY_FUNCTION__
))
;
374
375 /* Create DOM string data for comment */
376 err = dom_string_create((const uint8_t *)_comment,
377 strlen((const char *) _comment), &data);
378 if (err != DOM_NO_ERR) {
379 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
380 "No memory for comment data");
381 return;
382 }
383
384 /* Create comment */
385 err = dom_document_create_comment(parser->doc, data, &comment)dom_document_create_comment( (dom_document *) (parser->doc
), (data), (struct dom_comment **) (&comment))
;
386 if (err != DOM_NO_ERR) {
387 dom_string_unref(data);
388 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
389 "No memory for comment node");
390 return;
391 }
392
393 /* No longer need data */
394 dom_string_unref(data);
395
396 /* Append comment to parent */
397 err = dom_node_append_child(parser->current, (struct dom_node *) comment,dom_node_append_child( (dom_node *) (parser->current), (dom_node
*) ((struct dom_node *) comment), (dom_node **) ((struct dom_node
**) (void *) &ins_comment))
398 (struct dom_node **) (void *) &ins_comment)dom_node_append_child( (dom_node *) (parser->current), (dom_node
*) ((struct dom_node *) comment), (dom_node **) ((struct dom_node
**) (void *) &ins_comment))
;
399 if (err != DOM_NO_ERR) {
400 dom_node_unref((struct dom_node *) comment)dom_node_unref((dom_node *) ((struct dom_node *) comment));
401 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
402 "Failed attaching comment node");
403 return;
404 }
405
406 /* We're not interested in the inserted comment */
407 if (ins_comment != NULL((void*)0))
408 dom_node_unref((struct dom_node *) ins_comment)dom_node_unref((dom_node *) ((struct dom_node *) ins_comment)
)
;
409
410 /* No longer interested in comment */
411 dom_node_unref((struct dom_node *) comment)dom_node_unref((dom_node *) ((struct dom_node *) comment));
412
413}
414
415static void
416expat_xmlparser_start_doctype_decl_handler(void *_parser,
417 const XML_Char *doctype_name,
418 const XML_Char *system_id,
419 const XML_Char *public_id,
420 int has_internal_subset)
421{
422 dom_xml_parser *parser = _parser;
423 struct dom_document_type *doctype, *ins_doctype = NULL((void*)0);
424 dom_exception err;
425
426 UNUSED(has_internal_subset)((void)(has_internal_subset));
427
428 err = dom_implementation_create_document_type(
429 doctype_name, system_id ? system_id : "",
430 public_id ? public_id : "",
431 &doctype);
432
433 if (err != DOM_NO_ERR) {
434 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
435 "Failed to create document type");
436 return;
437 }
438
439 /* Add doctype to document */
440 err = dom_node_append_child(parser->doc, (struct dom_node *) doctype,dom_node_append_child( (dom_node *) (parser->doc), (dom_node
*) ((struct dom_node *) doctype), (dom_node **) ((struct dom_node
**) (void *) &ins_doctype))
441 (struct dom_node **) (void *) &ins_doctype)dom_node_append_child( (dom_node *) (parser->doc), (dom_node
*) ((struct dom_node *) doctype), (dom_node **) ((struct dom_node
**) (void *) &ins_doctype))
;
442 if (err != DOM_NO_ERR) {
443 dom_node_unref((struct dom_node *) doctype)dom_node_unref((dom_node *) ((struct dom_node *) doctype));
444 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
445 "Failed attaching doctype");
446 return;
447 }
448
449 /* Not interested in inserted node */
450 if (ins_doctype != NULL((void*)0))
451 dom_node_unref((struct dom_node *) ins_doctype)dom_node_unref((dom_node *) ((struct dom_node *) ins_doctype)
)
;
452
453 /* No longer interested in doctype */
454 dom_node_unref((struct dom_node *) doctype)dom_node_unref((dom_node *) ((struct dom_node *) doctype));
455}
456
457static void
458expat_xmlparser_unknown_data_handler(void *_parser,
459 const XML_Char *s,
460 int len)
461{
462 UNUSED(_parser)((void)(_parser));
463 UNUSED(s)((void)(s));
464 UNUSED(len)((void)(len));
465}
466/**
467 * Create an XML parser instance
468 *
469 * \param enc Source charset, or NULL
470 * \param int_enc Desired charset of document buffer (UTF-8 or UTF-16)
471 * \param msg Informational message function
472 * \param mctx Pointer to client-specific private data
473 * \param document DOM Document
474 * \return Pointer to instance, or NULL on memory exhaustion
475 *
476 * int_enc is ignored due to it being made of bees.
477 */
478dom_xml_parser *
479dom_xml_parser_create(const char *enc, const char *int_enc,
480 dom_msg msg, void *mctx, dom_document **document)
481{
482 dom_xml_parser *parser;
483 dom_exception err;
484
485 UNUSED(int_enc)((void)(int_enc));
486
487 parser = calloc(1, sizeof(*parser));
488 if (parser == NULL((void*)0)) {
489 msg(DOM_MSG_CRITICAL, mctx, "No memory for parser");
490 return NULL((void*)0);
491 }
492
493 parser->msg = msg;
494 parser->mctx = mctx;
495
496 parser->parser = XML_ParserCreateNS(enc, '\n');
497
498 if (parser->parser == NULL((void*)0)) {
499 free(parser);
500 msg(DOM_MSG_CRITICAL, mctx, "No memory for parser");
501 return NULL((void*)0);
502 }
503
504 parser->doc = NULL((void*)0);
505
506 err = dom_implementation_create_document(
507 DOM_IMPLEMENTATION_XML,
508 /* namespace */ NULL((void*)0),
509 /* qname */ NULL((void*)0),
510 /* doctype */ NULL((void*)0),
511 NULL((void*)0),
512 NULL((void*)0),
513 document);
514
515 if (err != DOM_NO_ERR) {
516 parser->msg(DOM_MSG_CRITICAL, parser->mctx,
517 "Failed creating document");
518 XML_ParserFree(parser->parser);
519 free(parser);
520 return NULL((void*)0);
521 }
522
523 parser->doc = (dom_document *) dom_node_ref(*document)dom_node_ref((dom_node *) (*document));
524
525 XML_SetUserData(parser->parser, parser);
526
527 XML_SetElementHandler(parser->parser,
528 expat_xmlparser_start_element_handler,
529 expat_xmlparser_end_element_handler);
530
531 XML_SetCdataSectionHandler(parser->parser,
532 expat_xmlparser_start_cdata_handler,
533 expat_xmlparser_end_cdata_handler);
534
535 XML_SetCharacterDataHandler(parser->parser,
536 expat_xmlparser_cdata_handler);
537
538 XML_SetParamEntityParsing(parser->parser,
539 XML_PARAM_ENTITY_PARSING_ALWAYS);
540
541 XML_SetExternalEntityRefHandler(parser->parser,
542 expat_xmlparser_external_entity_ref_handler);
543
544 XML_SetCommentHandler(parser->parser,
545 expat_xmlparser_comment_handler);
546
547 XML_SetStartDoctypeDeclHandler(parser->parser,
548 expat_xmlparser_start_doctype_decl_handler);
549
550 XML_SetDefaultHandlerExpand(parser->parser,
551 expat_xmlparser_unknown_data_handler);
552
553 parser->current = dom_node_ref(parser->doc)dom_node_ref((dom_node *) (parser->doc));
554
555 parser->is_cdata = false0;
556
557 return parser;
558}
559
560/**
561 * Destroy an XML parser instance
562 *
563 * \param parser The parser instance to destroy
564 */
565void
566dom_xml_parser_destroy(dom_xml_parser *parser)
567{
568 XML_ParserFree(parser->parser);
569 assert(parser->current)((parser->current) ? (void) (0) : __assert_fail ("parser->current"
, "bindings/xml/expat_xmlparser.c", 569, __extension__ __PRETTY_FUNCTION__
))
;
570 dom_node_unref(parser->current)dom_node_unref((dom_node *) (parser->current));
571 dom_node_unref(parser->doc)dom_node_unref((dom_node *) (parser->doc));
572 free(parser);
573}
574
575/**
576 * Parse a chunk of data
577 *
578 * \param parser The XML parser instance to use for parsing
579 * \param data Pointer to data chunk
580 * \param len Byte length of data chunk
581 * \return DOM_XML_OK on success, DOM_XML_EXTERNAL_ERR | expat error on failure
582 */
583dom_xml_error
584dom_xml_parser_parse_chunk(dom_xml_parser *parser, uint8_t *data, size_t len)
585{
586 enum XML_Status status;
587
588 status = XML_Parse(parser->parser, (const char *)data, len, 0);
589 if (status != XML_STATUS_OKXML_STATUS_OK) {
590 parser->msg(DOM_MSG_ERROR, parser->mctx,
591 "XML_Parse failed: %d", status);
592 return DOM_XML_EXTERNAL_ERR | status;
593 }
594
595 return DOM_XML_OK;
596}
597
598/**
599 * Notify parser that datastream is empty
600 *
601 * \param parser The XML parser instance to notify
602 * \return DOM_XML_OK on success, DOM_XML_EXTERNAL_ERR | expat error on failure
603 *
604 * This will force any remaining data through the parser
605 */
606dom_xml_error
607dom_xml_parser_completed(dom_xml_parser *parser)
608{
609 enum XML_Status status;
610
611 status = XML_Parse(parser->parser, "", 0, 1);
612 if (status != XML_STATUS_OKXML_STATUS_OK) {
613 parser->msg(DOM_MSG_ERROR, parser->mctx,
614 "XML_Parse failed: %d", status);
615 return DOM_XML_EXTERNAL_ERR | status;
616 }
617
618 return DOM_XML_OK;
619
620}