/* * This file is part of libdom. * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org> */ #include <stdbool.h>#include <stdlib.h>#include <string.h>#include <assert.h> #include <libxml/parser.h>#include <libxml/SAX2.h>#include <libxml/xmlerror.h> #include <dom/dom.h> #include <libwapcaplet/libwapcaplet.h> #include "xmlerror.h"#include "xmlparser.h"#include "utils.h" #include "core/document.h" static void xml_parser_start_document(void *ctx);static void xml_parser_end_document(void *ctx);static void xml_parser_start_element_ns(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes);static void xml_parser_end_element_ns(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI); static dom_exception xml_parser_link_nodes(dom_xml_parser *parser, struct dom_node *dom, xmlNodePtr xml); static dom_exception xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child);static dom_exception xml_parser_add_element_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child);static dom_exception xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child);static dom_exception xml_parser_add_cdata_section(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child);static dom_exception xml_parser_add_entity_reference(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child);static dom_exception xml_parser_add_entity(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child);static dom_exception xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child);static dom_exception xml_parser_add_document_type(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static void xml_parser_internal_subset(void *ctx, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID);static int xml_parser_is_standalone(void *ctx);static int xml_parser_has_internal_subset(void *ctx);static int xml_parser_has_external_subset(void *ctx);static xmlParserInputPtr xml_parser_resolve_entity(void *ctx, const xmlChar *publicId, const xmlChar *systemId);static xmlEntityPtr xml_parser_get_entity(void *ctx, const xmlChar *name);static void xml_parser_entity_decl(void *ctx, const xmlChar *name, int type, const xmlChar *publicId, const xmlChar *systemId, xmlChar *content);static void xml_parser_notation_decl(void *ctx, const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId);static void xml_parser_attribute_decl(void *ctx, const xmlChar *elem, const xmlChar *fullname, int type, int def, const xmlChar *defaultValue, xmlEnumerationPtr tree);static void xml_parser_element_decl(void *ctx, const xmlChar *name, int type, xmlElementContentPtr content);static void xml_parser_unparsed_entity_decl(void *ctx, const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId, const xmlChar *notationName);static void xml_parser_set_document_locator(void *ctx, xmlSAXLocatorPtr loc);static void xml_parser_reference(void *ctx, const xmlChar *name);static void xml_parser_characters(void *ctx, const xmlChar *ch, int len);static void xml_parser_comment(void *ctx, const xmlChar *value);static xmlEntityPtr xml_parser_get_parameter_entity(void *ctx, const xmlChar *name);static void xml_parser_cdata_block(void *ctx, const xmlChar *value, int len);static void xml_parser_external_subset(void *ctx, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); /** * libdom XML parser object */struct dom_xml_parser { xmlParserCtxtPtr xml_ctx; /**< libxml parser context */ struct dom_document *doc; /**< DOM Document we're building */ dom_string *udkey; /**< Key for DOM node user data */ dom_msg msg; /**< Informational message function */ void *mctx; /**< Pointer to client data */ dom_exception err; /**< Last DOM error, if any */}; /** * SAX callback dispatch table */static xmlSAXHandler sax_handler = { .internalSubset = xml_parser_internal_subset, .isStandalone = xml_parser_is_standalone, .hasInternalSubset = xml_parser_has_internal_subset, .hasExternalSubset = xml_parser_has_external_subset, .resolveEntity = xml_parser_resolve_entity, .getEntity = xml_parser_get_entity, .entityDecl = xml_parser_entity_decl, .notationDecl = xml_parser_notation_decl, .attributeDecl = xml_parser_attribute_decl, .elementDecl = xml_parser_element_decl, .unparsedEntityDecl = xml_parser_unparsed_entity_decl, .setDocumentLocator = xml_parser_set_document_locator, .startDocument = xml_parser_start_document, .endDocument = xml_parser_end_document, .startElement = NULL, .endElement = NULL, .reference = xml_parser_reference, .characters = xml_parser_characters, .ignorableWhitespace = xml_parser_characters, .processingInstruction = NULL, .comment = xml_parser_comment, .warning = NULL, .error = NULL, .fatalError = NULL, .getParameterEntity = xml_parser_get_parameter_entity, .cdataBlock = xml_parser_cdata_block, .externalSubset = xml_parser_external_subset, .initialized = XML_SAX2_MAGIC, ._private = NULL, .startElementNs = xml_parser_start_element_ns, .endElementNs = xml_parser_end_element_ns, .serror = NULL,}; static void *dom_xml_alloc(void *ptr, size_t len, void *pw){ UNUSED(pw); if (ptr == NULL) return len > 0 ? malloc(len) : NULL; if (len == 0) { free(ptr); return NULL; } return realloc(ptr, len);} /** * Create an XML parser instance * * \param enc Source charset, or NULL * \param int_enc Desired charset of document buffer (UTF-8 or UTF-16) * \param msg Informational message function * \param mctx Pointer to client-specific private data * \return Pointer to instance, or NULL on memory exhaustion * * Neither \p enc nor \p int_enc are used here. * libxml only supports a UTF-8 document buffer and forcibly setting the * parser encoding is not yet implemented */dom_xml_parser *dom_xml_parser_create(const char *enc, const char *int_enc, dom_msg msg, void *mctx, dom_document **document){ dom_xml_parser *parser; dom_exception err; int ret; UNUSED(enc); UNUSED(int_enc); parser = dom_xml_alloc(NULL, sizeof(dom_xml_parser), NULL); if (parser == NULL) { msg(DOM_MSG_CRITICAL, mctx, "No memory for parser"); return NULL; } parser->xml_ctx = xmlCreatePushParserCtxt(&sax_handler, parser, "", 0, NULL); if (parser->xml_ctx == NULL) { dom_xml_alloc(parser, 0, NULL); msg(DOM_MSG_CRITICAL, mctx, "Failed to create XML parser"); return NULL; } /* Set options of parsing context */ ret = xmlCtxtUseOptions(parser->xml_ctx, XML_PARSE_DTDATTR | XML_PARSE_DTDLOAD); if (ret != 0) { xmlFreeParserCtxt(parser->xml_ctx); dom_xml_alloc(parser, 0, NULL); msg(DOM_MSG_CRITICAL, mctx, "Failed setting parser options"); return NULL; } /* Create key for user data registration */ err = dom_string_create((const uint8_t *) "__xmlnode", SLEN("__xmlnode"), &parser->udkey); if (err != DOM_NO_ERR) { xmlFreeParserCtxt(parser->xml_ctx); dom_xml_alloc(parser, 0, NULL); msg(DOM_MSG_CRITICAL, mctx, "No memory for userdata key"); return NULL; } err = dom_implementation_create_document( DOM_IMPLEMENTATION_XML, /* namespace */ NULL, /* qname */ NULL, /* doctype */ NULL, NULL, NULL, document); if (err != DOM_NO_ERR) { xmlFreeParserCtxt(parser->xml_ctx); dom_string_unref(parser->udkey); dom_xml_alloc(parser, 0, NULL); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed creating document"); return NULL; } parser->doc = (dom_document *) dom_node_ref(*document); parser->msg = msg; parser->mctx = mctx; parser->err = DOM_NO_ERR; return parser;} /** * Destroy an XML parser instance * * \param parser The parser instance to destroy */void dom_xml_parser_destroy(dom_xml_parser *parser){ dom_string_unref(parser->udkey); dom_node_unref(parser->doc); xmlFreeDoc(parser->xml_ctx->myDoc); xmlFreeParserCtxt(parser->xml_ctx); dom_xml_alloc(parser, 0, NULL);} /** * Parse a chunk of data * * \param parser The XML parser instance to use for parsing * \param data Pointer to data chunk * \param len Byte length of data chunk * \return DOM_XML_OK on success, DOM_XML_EXTERNAL_ERR | libxml error on failure */dom_xml_error dom_xml_parser_parse_chunk(dom_xml_parser *parser, uint8_t *data, size_t len){ xmlParserErrors err; err = xmlParseChunk(parser->xml_ctx, (char *) data, len, 0); if (err != XML_ERR_OK) { parser->msg(DOM_MSG_ERROR, parser->mctx, "xmlParseChunk failed: %d", err); return DOM_XML_EXTERNAL_ERR | err; } if (parser->err != DOM_NO_ERR) { return DOM_XML_DOM_ERR | parser->err; } return DOM_XML_OK;} /** * Notify parser that datastream is empty * * \param parser The XML parser instance to notify * \return DOM_XML_OK on success, DOM_XML_EXTERNAL_ERR | libxml error on failure * * This will force any remaining data through the parser */dom_xml_error dom_xml_parser_completed(dom_xml_parser *parser){ xmlParserErrors err; err = xmlParseChunk(parser->xml_ctx, "", 0, 1); if (err != XML_ERR_OK) { parser->msg(DOM_MSG_ERROR, parser->mctx, "xmlParseChunk failed: %d", err); return DOM_XML_EXTERNAL_ERR | err; } if (parser->err != DOM_NO_ERR) { return DOM_XML_DOM_ERR | parser->err; } return DOM_XML_OK;} /** * Handle a document start SAX event * * \param ctx The callback context */void xml_parser_start_document(void *ctx){ dom_xml_parser *parser = (dom_xml_parser *) ctx;#if LIBXML_VERSION >= 21200 const xmlError *xmlerr;#else xmlErrorPtr xmlerr;#endif if (parser->err != DOM_NO_ERR) return; /* Invoke libxml2's default behaviour */ xmlSAX2StartDocument(parser->xml_ctx); xmlerr = xmlCtxtGetLastError(parser->xml_ctx); if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { return; } /* Link nodes together */ parser->err = xml_parser_link_nodes(parser, (struct dom_node *) parser->doc, (xmlNodePtr) parser->xml_ctx->myDoc); if (parser->err != DOM_NO_ERR) { parser->msg(DOM_MSG_WARNING, parser->mctx, "Not able to link document nodes"); }} /** * Handle a document end SAX event * * \param ctx The callback context */void xml_parser_end_document(void *ctx){ dom_xml_parser *parser = (dom_xml_parser *) ctx; xmlNodePtr node; xmlNodePtr n;#if LIBXML_VERSION >= 21200 const xmlError *xmlerr;#else xmlErrorPtr xmlerr;#endif if (parser->err != DOM_NO_ERR) return; /* Invoke libxml2's default behaviour */ xmlSAX2EndDocument(parser->xml_ctx); xmlerr = xmlCtxtGetLastError(parser->xml_ctx); if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { return; } /* If there is no document, we can't do anything */ if (parser->doc == NULL) { parser->msg(DOM_MSG_WARNING, parser->mctx, "No document in end_document"); return; } /* We need to mirror any child nodes at the end of the list of * children which occur after the last Element node in the list */ /* Get XML node */ parser->err = dom_node_get_user_data((struct dom_node *) parser->doc, parser->udkey, (void **) (void *) &node); /* The return value from dom_node_get_user_data() is always * DOM_NO_ERR, but the returned "node" will be NULL if no user * data is found. */ if (parser->err != DOM_NO_ERR || node == NULL) { parser->msg(DOM_MSG_WARNING, parser->mctx, "Failed finding XML node"); return; } /* Find last Element node, if any */ for (n = node->last; n != NULL; n = n->prev) { if (n->type == XML_ELEMENT_NODE) break; } if (n == NULL) { /* No Element node found; entire list needs mirroring */ n = node->children; } else { /* Found last Element; skip over it */ n = n->next; } /* Now, mirror nodes in the DOM */ for (; n != NULL; n = n->next) { parser->err = xml_parser_add_node(parser, (struct dom_node *) node->_private, n); if (parser->err != DOM_NO_ERR) return; }} /** * Handle an element open SAX event * * \param ctx The callback context * \param localname The local name of the element * \param prefix The element namespace prefix * \param URI The element namespace URI * \param nb_namespaces The number of namespace definitions * \param namespaces Array of nb_namespaces prefix/URI pairs * \param nb_attributes The total number of attributes * \param nb_defaulted The number of defaulted attributes * \param attributes Array of nb_attributes attribute values * * The number of non-defaulted attributes is \p nb_attributes - \p nb_defaulted * The defaulted attributes are at the end of the array \p attributes. */void xml_parser_start_element_ns(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes){ dom_xml_parser *parser = (dom_xml_parser *) ctx; xmlNodePtr parent = parser->xml_ctx->node;#if LIBXML_VERSION >= 21200 const xmlError *xmlerr;#else xmlErrorPtr xmlerr;#endif if (parser->err != DOM_NO_ERR) return; /* Invoke libxml2's default behaviour */ xmlSAX2StartElementNs(parser->xml_ctx, localname, prefix, URI, nb_namespaces, namespaces, nb_attributes, nb_defaulted, attributes); xmlerr = xmlCtxtGetLastError(parser->xml_ctx); if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { return; } /* If there is no document, we can't do anything */ if (parser->doc == NULL) { parser->msg(DOM_MSG_WARNING, parser->mctx, "No document in start_element_ns"); return; } if (parent == NULL) { /* No parent; use document */ parent = (xmlNodePtr) parser->xml_ctx->myDoc; } if (parent->type == XML_DOCUMENT_NODE || parent->type == XML_ELEMENT_NODE) { /* Mirror in the DOM all children of the parent node * between the previous Element child (or the start, * whichever is encountered first) and the Element * just created */ xmlNodePtr n; /* Find previous element node, if any */ for (n = parser->xml_ctx->node->prev; n != NULL; n = n->prev) { if (n->type == XML_ELEMENT_NODE) break; } if (n == NULL) { /* No previous Element; use parent's children */ n = parent->children; } else { /* Previous Element; skip over it */ n = n->next; } /* Now, mirror nodes in the DOM */ for (; n != parser->xml_ctx->node; n = n->next) { parser->err = xml_parser_add_node(parser, (struct dom_node *) parent->_private, n); if (parser->err != DOM_NO_ERR)Lines 1–500 of 1436. Load more
/* * This file is part of libdom. * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org> */ #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <libxml/parser.h> #include <libxml/SAX2.h> #include <libxml/xmlerror.h> #include <dom/dom.h> #include <libwapcaplet/libwapcaplet.h> #include "xmlerror.h" #include "xmlparser.h" #include "utils.h" #include "core/document.h" static void xml_parser_start_document(void *ctx); static void xml_parser_end_document(void *ctx); static void xml_parser_start_element_ns(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes); static void xml_parser_end_element_ns(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI); static dom_exception xml_parser_link_nodes(dom_xml_parser *parser, struct dom_node *dom, xmlNodePtr xml); static dom_exception xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static dom_exception xml_parser_add_element_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static dom_exception xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static dom_exception xml_parser_add_cdata_section(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static dom_exception xml_parser_add_entity_reference(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static dom_exception xml_parser_add_entity(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static dom_exception xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static dom_exception xml_parser_add_document_type(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static void xml_parser_internal_subset(void *ctx, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); static int xml_parser_is_standalone(void *ctx); static int xml_parser_has_internal_subset(void *ctx); static int xml_parser_has_external_subset(void *ctx); static xmlParserInputPtr xml_parser_resolve_entity(void *ctx, const xmlChar *publicId, const xmlChar *systemId); static xmlEntityPtr xml_parser_get_entity(void *ctx, const xmlChar *name); static void xml_parser_entity_decl(void *ctx, const xmlChar *name, int type, const xmlChar *publicId, const xmlChar *systemId, xmlChar *content); static void xml_parser_notation_decl(void *ctx, const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId); static void xml_parser_attribute_decl(void *ctx, const xmlChar *elem, const xmlChar *fullname, int type, int def, const xmlChar *defaultValue, xmlEnumerationPtr tree); static void xml_parser_element_decl(void *ctx, const xmlChar *name, int type, xmlElementContentPtr content); static void xml_parser_unparsed_entity_decl(void *ctx, const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId, const xmlChar *notationName); static void xml_parser_set_document_locator(void *ctx, xmlSAXLocatorPtr loc); static void xml_parser_reference(void *ctx, const xmlChar *name); static void xml_parser_characters(void *ctx, const xmlChar *ch, int len); static void xml_parser_comment(void *ctx, const xmlChar *value); static xmlEntityPtr xml_parser_get_parameter_entity(void *ctx, const xmlChar *name); static void xml_parser_cdata_block(void *ctx, const xmlChar *value, int len); static void xml_parser_external_subset(void *ctx, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); /** * libdom XML parser object */ struct dom_xml_parser { xmlParserCtxtPtr xml_ctx; /**< libxml parser context */ struct dom_document *doc; /**< DOM Document we're building */ dom_string *udkey; /**< Key for DOM node user data */ dom_msg msg; /**< Informational message function */ void *mctx; /**< Pointer to client data */ dom_exception err; /**< Last DOM error, if any */ }; /** * SAX callback dispatch table */ static xmlSAXHandler sax_handler = { .internalSubset = xml_parser_internal_subset, .isStandalone = xml_parser_is_standalone, .hasInternalSubset = xml_parser_has_internal_subset, .hasExternalSubset = xml_parser_has_external_subset, .resolveEntity = xml_parser_resolve_entity, .getEntity = xml_parser_get_entity, .entityDecl = xml_parser_entity_decl, .notationDecl = xml_parser_notation_decl, .attributeDecl = xml_parser_attribute_decl, .elementDecl = xml_parser_element_decl, .unparsedEntityDecl = xml_parser_unparsed_entity_decl, .setDocumentLocator = xml_parser_set_document_locator, .startDocument = xml_parser_start_document, .endDocument = xml_parser_end_document, .startElement = NULL, .endElement = NULL, .reference = xml_parser_reference, .characters = xml_parser_characters, .ignorableWhitespace = xml_parser_characters, .processingInstruction = NULL, .comment = xml_parser_comment, .warning = NULL, .error = NULL, .fatalError = NULL, .getParameterEntity = xml_parser_get_parameter_entity, .cdataBlock = xml_parser_cdata_block, .externalSubset = xml_parser_external_subset, .initialized = XML_SAX2_MAGIC, ._private = NULL, .startElementNs = xml_parser_start_element_ns, .endElementNs = xml_parser_end_element_ns, .serror = NULL, }; static void *dom_xml_alloc(void *ptr, size_t len, void *pw) { UNUSED(pw); if (ptr == NULL) return len > 0 ? malloc(len) : NULL; if (len == 0) { free(ptr); return NULL; } return realloc(ptr, len); } /** * Create an XML parser instance * * \param enc Source charset, or NULL * \param int_enc Desired charset of document buffer (UTF-8 or UTF-16) * \param msg Informational message function * \param mctx Pointer to client-specific private data * \return Pointer to instance, or NULL on memory exhaustion * * Neither \p enc nor \p int_enc are used here. * libxml only supports a UTF-8 document buffer and forcibly setting the * parser encoding is not yet implemented */ dom_xml_parser *dom_xml_parser_create(const char *enc, const char *int_enc, dom_msg msg, void *mctx, dom_document **document) { dom_xml_parser *parser; dom_exception err; int ret; UNUSED(enc); UNUSED(int_enc); parser = dom_xml_alloc(NULL, sizeof(dom_xml_parser), NULL); if (parser == NULL) { msg(DOM_MSG_CRITICAL, mctx, "No memory for parser"); return NULL; } parser->xml_ctx = xmlCreatePushParserCtxt(&sax_handler, parser, "", 0, NULL); if (parser->xml_ctx == NULL) { dom_xml_alloc(parser, 0, NULL); msg(DOM_MSG_CRITICAL, mctx, "Failed to create XML parser"); return NULL; } /* Set options of parsing context */ ret = xmlCtxtUseOptions(parser->xml_ctx, XML_PARSE_DTDATTR | XML_PARSE_DTDLOAD); if (ret != 0) { xmlFreeParserCtxt(parser->xml_ctx); dom_xml_alloc(parser, 0, NULL); msg(DOM_MSG_CRITICAL, mctx, "Failed setting parser options"); return NULL; } /* Create key for user data registration */ err = dom_string_create((const uint8_t *) "__xmlnode", SLEN("__xmlnode"), &parser->udkey); if (err != DOM_NO_ERR) { xmlFreeParserCtxt(parser->xml_ctx); dom_xml_alloc(parser, 0, NULL); msg(DOM_MSG_CRITICAL, mctx, "No memory for userdata key"); return NULL; } err = dom_implementation_create_document( DOM_IMPLEMENTATION_XML, /* namespace */ NULL, /* qname */ NULL, /* doctype */ NULL, NULL, NULL, document); if (err != DOM_NO_ERR) { xmlFreeParserCtxt(parser->xml_ctx); dom_string_unref(parser->udkey); dom_xml_alloc(parser, 0, NULL); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed creating document"); return NULL; } parser->doc = (dom_document *) dom_node_ref(*document); parser->msg = msg; parser->mctx = mctx; parser->err = DOM_NO_ERR; return parser; } /** * Destroy an XML parser instance * * \param parser The parser instance to destroy */ void dom_xml_parser_destroy(dom_xml_parser *parser) { dom_string_unref(parser->udkey); dom_node_unref(parser->doc); xmlFreeDoc(parser->xml_ctx->myDoc); xmlFreeParserCtxt(parser->xml_ctx); dom_xml_alloc(parser, 0, NULL); } /** * Parse a chunk of data * * \param parser The XML parser instance to use for parsing * \param data Pointer to data chunk * \param len Byte length of data chunk * \return DOM_XML_OK on success, DOM_XML_EXTERNAL_ERR | libxml error on failure */ dom_xml_error dom_xml_parser_parse_chunk(dom_xml_parser *parser, uint8_t *data, size_t len) { xmlParserErrors err; err = xmlParseChunk(parser->xml_ctx, (char *) data, len, 0); if (err != XML_ERR_OK) { parser->msg(DOM_MSG_ERROR, parser->mctx, "xmlParseChunk failed: %d", err); return DOM_XML_EXTERNAL_ERR | err; } if (parser->err != DOM_NO_ERR) { return DOM_XML_DOM_ERR | parser->err; } return DOM_XML_OK; } /** * Notify parser that datastream is empty * * \param parser The XML parser instance to notify * \return DOM_XML_OK on success, DOM_XML_EXTERNAL_ERR | libxml error on failure * * This will force any remaining data through the parser */ dom_xml_error dom_xml_parser_completed(dom_xml_parser *parser) { xmlParserErrors err; err = xmlParseChunk(parser->xml_ctx, "", 0, 1); if (err != XML_ERR_OK) { parser->msg(DOM_MSG_ERROR, parser->mctx, "xmlParseChunk failed: %d", err); return DOM_XML_EXTERNAL_ERR | err; } if (parser->err != DOM_NO_ERR) { return DOM_XML_DOM_ERR | parser->err; } return DOM_XML_OK; } /** * Handle a document start SAX event * * \param ctx The callback context */ void xml_parser_start_document(void *ctx) { dom_xml_parser *parser = (dom_xml_parser *) ctx; #if LIBXML_VERSION >= 21200 const xmlError *xmlerr; #else xmlErrorPtr xmlerr; #endif if (parser->err != DOM_NO_ERR) return; /* Invoke libxml2's default behaviour */ xmlSAX2StartDocument(parser->xml_ctx); xmlerr = xmlCtxtGetLastError(parser->xml_ctx); if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { return; } /* Link nodes together */ parser->err = xml_parser_link_nodes(parser, (struct dom_node *) parser->doc, (xmlNodePtr) parser->xml_ctx->myDoc); if (parser->err != DOM_NO_ERR) { parser->msg(DOM_MSG_WARNING, parser->mctx, "Not able to link document nodes"); } } /** * Handle a document end SAX event * * \param ctx The callback context */ void xml_parser_end_document(void *ctx) { dom_xml_parser *parser = (dom_xml_parser *) ctx; xmlNodePtr node; xmlNodePtr n; #if LIBXML_VERSION >= 21200 const xmlError *xmlerr; #else xmlErrorPtr xmlerr; #endif if (parser->err != DOM_NO_ERR) return; /* Invoke libxml2's default behaviour */ xmlSAX2EndDocument(parser->xml_ctx); xmlerr = xmlCtxtGetLastError(parser->xml_ctx); if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { return; } /* If there is no document, we can't do anything */ if (parser->doc == NULL) { parser->msg(DOM_MSG_WARNING, parser->mctx, "No document in end_document"); return; } /* We need to mirror any child nodes at the end of the list of * children which occur after the last Element node in the list */ /* Get XML node */ parser->err = dom_node_get_user_data((struct dom_node *) parser->doc, parser->udkey, (void **) (void *) &node); /* The return value from dom_node_get_user_data() is always * DOM_NO_ERR, but the returned "node" will be NULL if no user * data is found. */ if (parser->err != DOM_NO_ERR || node == NULL) { parser->msg(DOM_MSG_WARNING, parser->mctx, "Failed finding XML node"); return; } /* Find last Element node, if any */ for (n = node->last; n != NULL; n = n->prev) { if (n->type == XML_ELEMENT_NODE) break; } if (n == NULL) { /* No Element node found; entire list needs mirroring */ n = node->children; } else { /* Found last Element; skip over it */ n = n->next; } /* Now, mirror nodes in the DOM */ for (; n != NULL; n = n->next) { parser->err = xml_parser_add_node(parser, (struct dom_node *) node->_private, n); if (parser->err != DOM_NO_ERR) return; } } /** * Handle an element open SAX event * * \param ctx The callback context * \param localname The local name of the element * \param prefix The element namespace prefix * \param URI The element namespace URI * \param nb_namespaces The number of namespace definitions * \param namespaces Array of nb_namespaces prefix/URI pairs * \param nb_attributes The total number of attributes * \param nb_defaulted The number of defaulted attributes * \param attributes Array of nb_attributes attribute values * * The number of non-defaulted attributes is \p nb_attributes - \p nb_defaulted * The defaulted attributes are at the end of the array \p attributes. */ void xml_parser_start_element_ns(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes) { dom_xml_parser *parser = (dom_xml_parser *) ctx; xmlNodePtr parent = parser->xml_ctx->node; #if LIBXML_VERSION >= 21200 const xmlError *xmlerr; #else xmlErrorPtr xmlerr; #endif if (parser->err != DOM_NO_ERR) return; /* Invoke libxml2's default behaviour */ xmlSAX2StartElementNs(parser->xml_ctx, localname, prefix, URI, nb_namespaces, namespaces, nb_attributes, nb_defaulted, attributes); xmlerr = xmlCtxtGetLastError(parser->xml_ctx); if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { return; } /* If there is no document, we can't do anything */ if (parser->doc == NULL) { parser->msg(DOM_MSG_WARNING, parser->mctx, "No document in start_element_ns"); return; } if (parent == NULL) { /* No parent; use document */ parent = (xmlNodePtr) parser->xml_ctx->myDoc; } if (parent->type == XML_DOCUMENT_NODE || parent->type == XML_ELEMENT_NODE) { /* Mirror in the DOM all children of the parent node * between the previous Element child (or the start, * whichever is encountered first) and the Element * just created */ xmlNodePtr n; /* Find previous element node, if any */ for (n = parser->xml_ctx->node->prev; n != NULL; n = n->prev) { if (n->type == XML_ELEMENT_NODE) break; } if (n == NULL) { /* No previous Element; use parent's children */ n = parent->children; } else { /* Previous Element; skip over it */ n = n->next; } /* Now, mirror nodes in the DOM */ for (; n != parser->xml_ctx->node; n = n->next) { parser->err = xml_parser_add_node(parser, (struct dom_node *) parent->_private, n); if (parser->err != DOM_NO_ERR)