forked from KolibriOS/kolibrios
1336 lines
36 KiB
C
1336 lines
36 KiB
C
|
/*
|
||
|
* 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 <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 void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent,
|
||
|
xmlNodePtr child);
|
||
|
static void xml_parser_add_element_node(dom_xml_parser *parser,
|
||
|
struct dom_node *parent, xmlNodePtr child);
|
||
|
static void xml_parser_add_text_node(dom_xml_parser *parser,
|
||
|
struct dom_node *parent, xmlNodePtr child);
|
||
|
static void xml_parser_add_cdata_section(dom_xml_parser *parser,
|
||
|
struct dom_node *parent, xmlNodePtr child);
|
||
|
static void xml_parser_add_entity_reference(dom_xml_parser *parser,
|
||
|
struct dom_node *parent, xmlNodePtr child);
|
||
|
static void xml_parser_add_entity(dom_xml_parser *parser,
|
||
|
struct dom_node *parent, xmlNodePtr child);
|
||
|
static void xml_parser_add_comment(dom_xml_parser *parser,
|
||
|
struct dom_node *parent, xmlNodePtr child);
|
||
|
static void 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 */
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* 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 ::enc nor ::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;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
dom_exception err;
|
||
|
|
||
|
/* Invoke libxml2's default behaviour */
|
||
|
xmlSAX2StartDocument(parser->xml_ctx);
|
||
|
|
||
|
/* Link nodes together */
|
||
|
err = xml_parser_link_nodes(parser, (struct dom_node *) parser->doc,
|
||
|
(xmlNodePtr) parser->xml_ctx->myDoc);
|
||
|
if (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;
|
||
|
dom_exception err;
|
||
|
|
||
|
/* Invoke libxml2's default behaviour */
|
||
|
xmlSAX2EndDocument(parser->xml_ctx);
|
||
|
|
||
|
/* 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 */
|
||
|
err = dom_node_get_user_data((struct dom_node *) parser->doc,
|
||
|
parser->udkey, (void **) (void *) &node);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
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) {
|
||
|
xml_parser_add_node(parser,
|
||
|
(struct dom_node *) node->_private, n);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 ::nb_attributes - ::nb_defaulted
|
||
|
* The defaulted attributes are at the end of the array ::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;
|
||
|
|
||
|
/* Invoke libxml2's default behaviour */
|
||
|
xmlSAX2StartElementNs(parser->xml_ctx, localname, prefix, URI,
|
||
|
nb_namespaces, namespaces, nb_attributes,
|
||
|
nb_defaulted, attributes);
|
||
|
|
||
|
/* 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) {
|
||
|
xml_parser_add_node(parser,
|
||
|
(struct dom_node *) parent->_private,
|
||
|
n);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Mirror the created node and its attributes in the DOM */
|
||
|
xml_parser_add_node(parser, (struct dom_node *) parent->_private,
|
||
|
parser->xml_ctx->node);
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle an element close 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
|
||
|
*/
|
||
|
void xml_parser_end_element_ns(void *ctx, const xmlChar *localname,
|
||
|
const xmlChar *prefix, const xmlChar *URI)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
xmlNodePtr node = parser->xml_ctx->node;
|
||
|
xmlNodePtr n;
|
||
|
|
||
|
/* Invoke libxml2's default behaviour */
|
||
|
xmlSAX2EndElementNs(parser->xml_ctx, localname, prefix, URI);
|
||
|
|
||
|
/* 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_element_ns");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* If node wasn't linked, we can't do anything */
|
||
|
if (node->_private == NULL) {
|
||
|
parser->msg(DOM_MSG_WARNING, parser->mctx,
|
||
|
"Node '%s' not linked", node->name);
|
||
|
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 */
|
||
|
|
||
|
/* 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) {
|
||
|
xml_parser_add_node(parser,
|
||
|
(struct dom_node *) node->_private, n);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Link a DOM and XML node together
|
||
|
*
|
||
|
* \param parser The parser context
|
||
|
* \param dom The DOM node
|
||
|
* \param xml The XML node
|
||
|
* \return DOM_NO_ERR on success, appropriate error otherwise
|
||
|
*/
|
||
|
dom_exception xml_parser_link_nodes(dom_xml_parser *parser,
|
||
|
struct dom_node *dom, xmlNodePtr xml)
|
||
|
{
|
||
|
void *prev_data;
|
||
|
dom_exception err;
|
||
|
|
||
|
/* Register XML node as user data for DOM node */
|
||
|
err = dom_node_set_user_data(dom, parser->udkey, xml, NULL,
|
||
|
&prev_data);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
parser->msg(DOM_MSG_ERROR, parser->mctx,
|
||
|
"Failed setting user data: %d", err);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
/* Register DOM node with the XML node */
|
||
|
xml->_private = dom;
|
||
|
|
||
|
return DOM_NO_ERR;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a node to the DOM
|
||
|
*
|
||
|
* \param parser The parser context
|
||
|
* \param parent The parent DOM node
|
||
|
* \param child The xmlNode to mirror in the DOM as a child of parent
|
||
|
*/
|
||
|
void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent,
|
||
|
xmlNodePtr child)
|
||
|
{
|
||
|
static const char *node_types[] = {
|
||
|
"THIS_IS_NOT_A_NODE",
|
||
|
"XML_ELEMENT_NODE",
|
||
|
"XML_ATTRIBUTE_NODE",
|
||
|
"XML_TEXT_NODE",
|
||
|
"XML_CDATA_SECTION_NODE",
|
||
|
"XML_ENTITY_REF_NODE",
|
||
|
"XML_ENTITY_NODE",
|
||
|
"XML_PI_NODE",
|
||
|
"XML_COMMENT_NODE",
|
||
|
"XML_DOCUMENT_NODE",
|
||
|
"XML_DOCUMENT_TYPE_NODE",
|
||
|
"XML_DOCUMENT_FRAG_NODE",
|
||
|
"XML_NOTATION_NODE",
|
||
|
"XML_HTML_DOCUMENT_NODE",
|
||
|
"XML_DTD_NODE",
|
||
|
"XML_ELEMENT_DECL",
|
||
|
"XML_ATTRIBUTE_DECL",
|
||
|
"XML_ENTITY_DECL",
|
||
|
"XML_NAMESPACE_DECL",
|
||
|
"XML_XINCLUDE_START",
|
||
|
"XML_XINCLUDE_END",
|
||
|
"XML_DOCB_DOCUMENT_NODE"
|
||
|
};
|
||
|
|
||
|
switch (child->type) {
|
||
|
case XML_ELEMENT_NODE:
|
||
|
xml_parser_add_element_node(parser, parent, child);
|
||
|
break;
|
||
|
case XML_TEXT_NODE:
|
||
|
xml_parser_add_text_node(parser, parent, child);
|
||
|
break;
|
||
|
case XML_CDATA_SECTION_NODE:
|
||
|
xml_parser_add_cdata_section(parser, parent, child);
|
||
|
break;
|
||
|
case XML_ENTITY_REF_NODE:
|
||
|
xml_parser_add_entity_reference(parser, parent, child);
|
||
|
break;
|
||
|
case XML_COMMENT_NODE:
|
||
|
xml_parser_add_comment(parser, parent, child);
|
||
|
break;
|
||
|
case XML_DTD_NODE:
|
||
|
xml_parser_add_document_type(parser, parent, child);
|
||
|
break;
|
||
|
case XML_ENTITY_DECL:
|
||
|
xml_parser_add_entity(parser, parent, child);
|
||
|
break;
|
||
|
default:
|
||
|
parser->msg(DOM_MSG_NOTICE, parser->mctx,
|
||
|
"Unsupported node type: %s",
|
||
|
node_types[child->type]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add an element node to the DOM
|
||
|
*
|
||
|
* \param parser The parser context
|
||
|
* \param parent The parent DOM node
|
||
|
* \param child The xmlNode to mirror in the DOM as a child of parent
|
||
|
*/
|
||
|
void xml_parser_add_element_node(dom_xml_parser *parser,
|
||
|
struct dom_node *parent, xmlNodePtr child)
|
||
|
{
|
||
|
struct dom_element *el, *ins_el = NULL;
|
||
|
xmlAttrPtr a;
|
||
|
dom_exception err;
|
||
|
|
||
|
/* Create the element node */
|
||
|
if (child->ns == NULL) {
|
||
|
/* No namespace */
|
||
|
dom_string *tag_name;
|
||
|
|
||
|
/* Create tag name DOM string */
|
||
|
err = dom_string_create(child->name,
|
||
|
strlen((const char *) child->name), &tag_name);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for tag name");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Create element node */
|
||
|
err = dom_document_create_element(parser->doc,
|
||
|
tag_name, &el);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_string_unref(tag_name);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"Failed creating element '%s'",
|
||
|
child->name);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer need tag name */
|
||
|
dom_string_unref(tag_name);
|
||
|
} else {
|
||
|
/* Namespace */
|
||
|
dom_string *namespace;
|
||
|
dom_string *qname;
|
||
|
size_t qnamelen = (child->ns->prefix != NULL ?
|
||
|
strlen((const char *) child->ns->prefix) : 0) +
|
||
|
(child->ns->prefix != NULL ? 1 : 0) /* ':' */ +
|
||
|
strlen((const char *) child->name);
|
||
|
uint8_t qnamebuf[qnamelen + 1 /* '\0' */];
|
||
|
|
||
|
/* Create namespace DOM string */
|
||
|
err = dom_string_create(
|
||
|
child->ns->href,
|
||
|
strlen((const char *) child->ns->href),
|
||
|
&namespace);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for namespace");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* QName is "prefix:localname",
|
||
|
* or "localname" if there is no prefix */
|
||
|
sprintf((char *) qnamebuf, "%s%s%s",
|
||
|
child->ns->prefix != NULL ?
|
||
|
(const char *) child->ns->prefix : "",
|
||
|
child->ns->prefix != NULL ? ":" : "",
|
||
|
(const char *) child->name);
|
||
|
|
||
|
/* Create qname DOM string */
|
||
|
err = dom_string_create(
|
||
|
qnamebuf,
|
||
|
qnamelen,
|
||
|
&qname);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_string_unref(namespace);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for qname");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Create element node */
|
||
|
err = dom_document_create_element_ns(parser->doc,
|
||
|
namespace, qname, &el);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_string_unref(namespace);
|
||
|
dom_string_unref(qname);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"Failed creating element '%s'",
|
||
|
qnamebuf);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer need namespace / qname */
|
||
|
dom_string_unref(namespace);
|
||
|
dom_string_unref(qname);
|
||
|
}
|
||
|
|
||
|
/* Add attributes to created element */
|
||
|
for (a = child->properties; a != NULL; a = a->next) {
|
||
|
struct dom_attr *attr, *prev_attr;
|
||
|
xmlNodePtr c;
|
||
|
|
||
|
/* Create attribute node */
|
||
|
if (a->ns == NULL) {
|
||
|
/* Attribute has no namespace */
|
||
|
dom_string *name;
|
||
|
|
||
|
/* Create attribute name DOM string */
|
||
|
err = dom_string_create(
|
||
|
a->name,
|
||
|
strlen((const char *) a->name),
|
||
|
&name);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for attribute name");
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
/* Create attribute */
|
||
|
err = dom_document_create_attribute(parser->doc,
|
||
|
name, &attr);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_string_unref(name);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"Failed creating attribute \
|
||
|
'%s'", a->name);
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
/* No longer need attribute name */
|
||
|
dom_string_unref(name);
|
||
|
} else {
|
||
|
/* Attribute has namespace */
|
||
|
dom_string *namespace;
|
||
|
dom_string *qname;
|
||
|
size_t qnamelen = (a->ns->prefix != NULL ?
|
||
|
strlen((const char *) a->ns->prefix) : 0) +
|
||
|
(a->ns->prefix != NULL ? 1 : 0) /* ':' */ +
|
||
|
strlen((const char *) a->name);
|
||
|
uint8_t qnamebuf[qnamelen + 1 /* '\0' */];
|
||
|
|
||
|
/* Create namespace DOM string */
|
||
|
err = dom_string_create(
|
||
|
a->ns->href,
|
||
|
strlen((const char *) a->ns->href),
|
||
|
&namespace);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for namespace");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* QName is "prefix:localname",
|
||
|
* or "localname" if there is no prefix */
|
||
|
sprintf((char *) qnamebuf, "%s%s%s",
|
||
|
a->ns->prefix != NULL ?
|
||
|
(const char *) a->ns->prefix : "",
|
||
|
a->ns->prefix != NULL ? ":" : "",
|
||
|
(const char *) a->name);
|
||
|
|
||
|
/* Create qname DOM string */
|
||
|
err = dom_string_create(
|
||
|
qnamebuf,
|
||
|
qnamelen,
|
||
|
&qname);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_string_unref(namespace);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for qname");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Create attribute */
|
||
|
err = dom_document_create_attribute_ns(parser->doc,
|
||
|
namespace, qname, &attr);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_string_unref(namespace);
|
||
|
dom_string_unref(qname);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"Failed creating attribute \
|
||
|
'%s'", qnamebuf);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer need namespace / qname */
|
||
|
dom_string_unref(namespace);
|
||
|
dom_string_unref(qname);
|
||
|
}
|
||
|
|
||
|
/* Clone subtree (attribute value) */
|
||
|
for (c = a->children; c != NULL; c = c->next) {
|
||
|
xml_parser_add_node(parser,
|
||
|
(struct dom_node *) attr, c);
|
||
|
}
|
||
|
|
||
|
/* Link nodes together */
|
||
|
err = xml_parser_link_nodes(parser,
|
||
|
(struct dom_node *) attr, (xmlNodePtr) a);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) attr);
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
if (a->ns == NULL) {
|
||
|
/* And add attribute to the element */
|
||
|
err = dom_element_set_attribute_node(el, attr,
|
||
|
&prev_attr);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) attr);
|
||
|
parser->msg(DOM_MSG_ERROR, parser->mctx,
|
||
|
"Failed attaching attribute \
|
||
|
'%s'", a->name);
|
||
|
goto cleanup;
|
||
|
}
|
||
|
} else {
|
||
|
err = dom_element_set_attribute_node_ns(el, attr,
|
||
|
&prev_attr);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) attr);
|
||
|
parser->msg(DOM_MSG_ERROR, parser->mctx,
|
||
|
"Failed attaching attribute \
|
||
|
'%s'", a->name);
|
||
|
goto cleanup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* We're not interested in the previous attribute (if any) */
|
||
|
if (prev_attr != NULL && prev_attr != attr)
|
||
|
dom_node_unref((struct dom_node *) prev_attr);
|
||
|
|
||
|
/* We're no longer interested in the attribute node */
|
||
|
dom_node_unref((struct dom_node *) attr);
|
||
|
}
|
||
|
|
||
|
/* Append element to parent */
|
||
|
err = dom_node_append_child(parent, (struct dom_node *) el,
|
||
|
(struct dom_node **) (void *) &ins_el);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
parser->msg(DOM_MSG_ERROR, parser->mctx,
|
||
|
"Failed attaching element '%s'",
|
||
|
child->name);
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
/* We're not interested in the inserted element */
|
||
|
if (ins_el != NULL)
|
||
|
dom_node_unref((struct dom_node *) ins_el);
|
||
|
|
||
|
/* Link nodes together */
|
||
|
err = xml_parser_link_nodes(parser, (struct dom_node *) el,
|
||
|
child);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
/* No longer interested in element node */
|
||
|
dom_node_unref((struct dom_node *) el);
|
||
|
|
||
|
return;
|
||
|
|
||
|
cleanup:
|
||
|
/* No longer want node (any attributes attached to it
|
||
|
* will be cleaned up with it) */
|
||
|
dom_node_unref((struct dom_node *) el);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a text node to the DOM
|
||
|
*
|
||
|
* \param parser The parser context
|
||
|
* \param parent The parent DOM node
|
||
|
* \param child The xmlNode to mirror in the DOM as a child of parent
|
||
|
*/
|
||
|
void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent,
|
||
|
xmlNodePtr child)
|
||
|
{
|
||
|
struct dom_text *text, *ins_text = NULL;
|
||
|
dom_string *data;
|
||
|
dom_exception err;
|
||
|
|
||
|
/* Create DOM string data for text node */
|
||
|
err = dom_string_create(child->content,
|
||
|
strlen((const char *) child->content), &data);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for text node contents ");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Create text node */
|
||
|
err = dom_document_create_text_node(parser->doc, data, &text);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_string_unref(data);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for text node");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer need data */
|
||
|
dom_string_unref(data);
|
||
|
|
||
|
/* Append text node to parent */
|
||
|
err = dom_node_append_child(parent, (struct dom_node *) text,
|
||
|
(struct dom_node **) (void *) &ins_text);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) text);
|
||
|
parser->msg(DOM_MSG_ERROR, parser->mctx,
|
||
|
"Failed attaching text node");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* We're not interested in the inserted text node */
|
||
|
if (ins_text != NULL)
|
||
|
dom_node_unref((struct dom_node *) ins_text);
|
||
|
|
||
|
/* Link nodes together */
|
||
|
err = xml_parser_link_nodes(parser, (struct dom_node *) text,
|
||
|
child);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) text);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer interested in text node */
|
||
|
dom_node_unref((struct dom_node *) text);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a cdata section to the DOM
|
||
|
*
|
||
|
* \param parser The parser context
|
||
|
* \param parent The parent DOM node
|
||
|
* \param child The xmlNode to mirror in the DOM as a child of parent
|
||
|
*/
|
||
|
void xml_parser_add_cdata_section(dom_xml_parser *parser,
|
||
|
struct dom_node *parent, xmlNodePtr child)
|
||
|
{
|
||
|
struct dom_cdata_section *cdata, *ins_cdata = NULL;
|
||
|
dom_string *data;
|
||
|
dom_exception err;
|
||
|
|
||
|
/* Create DOM string data for cdata section */
|
||
|
err = dom_string_create(child->content,
|
||
|
strlen((const char *) child->content), &data);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for cdata section contents");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Create cdata section */
|
||
|
err = dom_document_create_cdata_section(parser->doc, data, &cdata);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_string_unref(data);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for cdata section");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer need data */
|
||
|
dom_string_unref(data);
|
||
|
|
||
|
/* Append cdata section to parent */
|
||
|
err = dom_node_append_child(parent, (struct dom_node *) cdata,
|
||
|
(struct dom_node **) (void *) &ins_cdata);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) cdata);
|
||
|
parser->msg(DOM_MSG_ERROR, parser->mctx,
|
||
|
"Failed attaching cdata section");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* We're not interested in the inserted cdata section */
|
||
|
if (ins_cdata != NULL)
|
||
|
dom_node_unref((struct dom_node *) ins_cdata);
|
||
|
|
||
|
/* Link nodes together */
|
||
|
err = xml_parser_link_nodes(parser, (struct dom_node *) cdata,
|
||
|
child);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) cdata);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer interested in cdata section */
|
||
|
dom_node_unref((struct dom_node *) cdata);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add an entity reference to the DOM
|
||
|
*
|
||
|
* \param parser The parser context
|
||
|
* \param parent The parent DOM node
|
||
|
* \param child The xmlNode to mirror in the DOM as a child of parent
|
||
|
*/
|
||
|
void xml_parser_add_entity_reference(dom_xml_parser *parser,
|
||
|
struct dom_node *parent, xmlNodePtr child)
|
||
|
{
|
||
|
struct dom_entity_reference *entity, *ins_entity = NULL;
|
||
|
dom_string *name;
|
||
|
xmlNodePtr c;
|
||
|
dom_exception err;
|
||
|
|
||
|
/* Create name of entity reference */
|
||
|
err = dom_string_create(child->name,
|
||
|
strlen((const char *) child->name), &name);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for entity reference name");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Create text node */
|
||
|
err = dom_document_create_entity_reference(parser->doc, name,
|
||
|
&entity);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_string_unref(name);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for entity reference");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer need name */
|
||
|
dom_string_unref(name);
|
||
|
|
||
|
/* Mirror subtree (reference value) */
|
||
|
for (c = child->children; c != NULL; c = c->next) {
|
||
|
xml_parser_add_node(parser, (struct dom_node *) entity, c);
|
||
|
}
|
||
|
|
||
|
/* Append entity reference to parent */
|
||
|
err = dom_node_append_child(parent, (struct dom_node *) entity,
|
||
|
(struct dom_node **) (void *) &ins_entity);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) entity);
|
||
|
parser->msg(DOM_MSG_ERROR, parser->mctx,
|
||
|
"Failed attaching entity reference");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* We're not interested in the inserted entity reference */
|
||
|
if (ins_entity != NULL)
|
||
|
dom_node_unref((struct dom_node *) ins_entity);
|
||
|
|
||
|
/* Link nodes together */
|
||
|
err = xml_parser_link_nodes(parser, (struct dom_node *) entity,
|
||
|
child);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) entity);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer interested in entity reference */
|
||
|
dom_node_unref((struct dom_node *) entity);
|
||
|
}
|
||
|
|
||
|
static void xml_parser_add_entity(dom_xml_parser *parser,
|
||
|
struct dom_node *parent, xmlNodePtr child)
|
||
|
{
|
||
|
UNUSED(parser);
|
||
|
UNUSED(parent);
|
||
|
UNUSED(child);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a comment to the DOM
|
||
|
*
|
||
|
* \param parser The parser context
|
||
|
* \param parent The parent DOM node
|
||
|
* \param child The xmlNode to mirror in the DOM as a child of parent
|
||
|
*/
|
||
|
void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent,
|
||
|
xmlNodePtr child)
|
||
|
{
|
||
|
struct dom_comment *comment, *ins_comment = NULL;
|
||
|
dom_string *data;
|
||
|
dom_exception err;
|
||
|
|
||
|
/* Create DOM string data for comment */
|
||
|
err = dom_string_create(child->content,
|
||
|
strlen((const char *) child->content), &data);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for comment data");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Create comment */
|
||
|
err = dom_document_create_comment(parser->doc, data, &comment);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_string_unref(data);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"No memory for comment node");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer need data */
|
||
|
dom_string_unref(data);
|
||
|
|
||
|
/* Append comment to parent */
|
||
|
err = dom_node_append_child(parent, (struct dom_node *) comment,
|
||
|
(struct dom_node **) (void *) &ins_comment);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) comment);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"Failed attaching comment node");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* We're not interested in the inserted comment */
|
||
|
if (ins_comment != NULL)
|
||
|
dom_node_unref((struct dom_node *) ins_comment);
|
||
|
|
||
|
/* Link nodes together */
|
||
|
err = xml_parser_link_nodes(parser, (struct dom_node *) comment,
|
||
|
child);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) comment);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer interested in comment */
|
||
|
dom_node_unref((struct dom_node *) comment);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a document type to the DOM
|
||
|
*
|
||
|
* \param parser The parser context
|
||
|
* \param parent The parent DOM node
|
||
|
* \param child The xmlNode to mirror in the DOM as a child of parent
|
||
|
*/
|
||
|
void xml_parser_add_document_type(dom_xml_parser *parser,
|
||
|
struct dom_node *parent, xmlNodePtr child)
|
||
|
{
|
||
|
xmlDtdPtr dtd = (xmlDtdPtr) child;
|
||
|
struct dom_document_type *doctype, *ins_doctype = NULL;
|
||
|
const char *qname, *public_id, *system_id;
|
||
|
dom_exception err;
|
||
|
|
||
|
/* Create qname for doctype */
|
||
|
qname = (const char *) dtd->name;
|
||
|
|
||
|
/* Create public ID for doctype */
|
||
|
public_id = dtd->ExternalID != NULL ?
|
||
|
(const char *) dtd->ExternalID : "";
|
||
|
|
||
|
/* Create system ID for doctype */
|
||
|
system_id = dtd->SystemID != NULL ?
|
||
|
(const char *) dtd->SystemID : "";
|
||
|
|
||
|
/* Create doctype */
|
||
|
err = dom_implementation_create_document_type(
|
||
|
qname, public_id, system_id,
|
||
|
&doctype);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"Failed to create document type");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Add doctype to document */
|
||
|
err = dom_node_append_child(parent, (struct dom_node *) doctype,
|
||
|
(struct dom_node **) (void *) &ins_doctype);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) doctype);
|
||
|
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
|
||
|
"Failed attaching doctype");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Not interested in inserted node */
|
||
|
if (ins_doctype != NULL)
|
||
|
dom_node_unref((struct dom_node *) ins_doctype);
|
||
|
|
||
|
/* Link nodes together */
|
||
|
err = xml_parser_link_nodes(parser, (struct dom_node *) doctype,
|
||
|
child);
|
||
|
if (err != DOM_NO_ERR) {
|
||
|
dom_node_unref((struct dom_node *) doctype);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* No longer interested in doctype */
|
||
|
dom_node_unref((struct dom_node *) doctype);
|
||
|
}
|
||
|
|
||
|
/* ------------------------------------------------------------------------*/
|
||
|
|
||
|
void xml_parser_internal_subset(void *ctx, const xmlChar *name,
|
||
|
const xmlChar *ExternalID, const xmlChar *SystemID)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2InternalSubset(parser->xml_ctx, name, ExternalID, SystemID);
|
||
|
}
|
||
|
|
||
|
int xml_parser_is_standalone(void *ctx)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
return xmlSAX2IsStandalone(parser->xml_ctx);
|
||
|
}
|
||
|
|
||
|
int xml_parser_has_internal_subset(void *ctx)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
return xmlSAX2HasInternalSubset(parser->xml_ctx);
|
||
|
}
|
||
|
|
||
|
int xml_parser_has_external_subset(void *ctx)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
return xmlSAX2HasExternalSubset(parser->xml_ctx);
|
||
|
}
|
||
|
|
||
|
xmlParserInputPtr xml_parser_resolve_entity(void *ctx,
|
||
|
const xmlChar *publicId, const xmlChar *systemId)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
return xmlSAX2ResolveEntity(parser->xml_ctx, publicId, systemId);
|
||
|
}
|
||
|
|
||
|
xmlEntityPtr xml_parser_get_entity(void *ctx, const xmlChar *name)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
return xmlSAX2GetEntity(parser->xml_ctx, name);
|
||
|
}
|
||
|
|
||
|
void xml_parser_entity_decl(void *ctx, const xmlChar *name,
|
||
|
int type, const xmlChar *publicId, const xmlChar *systemId,
|
||
|
xmlChar *content)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2EntityDecl(parser->xml_ctx, name, type, publicId, systemId,
|
||
|
content);
|
||
|
}
|
||
|
|
||
|
void xml_parser_notation_decl(void *ctx, const xmlChar *name,
|
||
|
const xmlChar *publicId, const xmlChar *systemId)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2NotationDecl(parser->xml_ctx, name, publicId, systemId);
|
||
|
}
|
||
|
|
||
|
void xml_parser_attribute_decl(void *ctx, const xmlChar *elem,
|
||
|
const xmlChar *fullname, int type, int def,
|
||
|
const xmlChar *defaultValue, xmlEnumerationPtr tree)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2AttributeDecl(parser->xml_ctx, elem, fullname, type, def,
|
||
|
defaultValue, tree);
|
||
|
}
|
||
|
|
||
|
void xml_parser_element_decl(void *ctx, const xmlChar *name,
|
||
|
int type, xmlElementContentPtr content)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2ElementDecl(parser->xml_ctx, name, type, content);
|
||
|
}
|
||
|
|
||
|
void xml_parser_unparsed_entity_decl(void *ctx, const xmlChar *name,
|
||
|
const xmlChar *publicId, const xmlChar *systemId,
|
||
|
const xmlChar *notationName)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2UnparsedEntityDecl(parser->xml_ctx, name, publicId,
|
||
|
systemId, notationName);
|
||
|
}
|
||
|
|
||
|
void xml_parser_set_document_locator(void *ctx, xmlSAXLocatorPtr loc)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2SetDocumentLocator(parser->xml_ctx, loc);
|
||
|
}
|
||
|
|
||
|
void xml_parser_reference(void *ctx, const xmlChar *name)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2Reference(parser->xml_ctx, name);
|
||
|
}
|
||
|
|
||
|
void xml_parser_characters(void *ctx, const xmlChar *ch, int len)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2Characters(parser->xml_ctx, ch, len);
|
||
|
}
|
||
|
|
||
|
void xml_parser_comment(void *ctx, const xmlChar *value)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2Comment(parser->xml_ctx, value);
|
||
|
}
|
||
|
|
||
|
xmlEntityPtr xml_parser_get_parameter_entity(void *ctx, const xmlChar *name)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
return xmlSAX2GetParameterEntity(parser->xml_ctx, name);
|
||
|
}
|
||
|
|
||
|
void xml_parser_cdata_block(void *ctx, const xmlChar *value, int len)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2CDataBlock(parser->xml_ctx, value, len);
|
||
|
}
|
||
|
|
||
|
void xml_parser_external_subset(void *ctx, const xmlChar *name,
|
||
|
const xmlChar *ExternalID, const xmlChar *SystemID)
|
||
|
{
|
||
|
dom_xml_parser *parser = (dom_xml_parser *) ctx;
|
||
|
|
||
|
xmlSAX2ExternalSubset(parser->xml_ctx, name, ExternalID, SystemID);
|
||
|
}
|