summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2012-07-15 18:28:06 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2012-07-15 18:28:06 +0100
commit57bee28b15d3f8b878e3ebfe8aaa7aeb0fd7addf (patch)
tree56d43f0cfe4f7911293a77e453989d543ad25e79
parentcb0225a6d309cd951b595eb5c1b488f21a0f17be (diff)
parent2f4be485272446109e4451a19dc29ba6728f0039 (diff)
downloadlibdom-57bee28b15d3f8b878e3ebfe8aaa7aeb0fd7addf.tar.gz
libdom-57bee28b15d3f8b878e3ebfe8aaa7aeb0fd7addf.tar.bz2
Merge expat support. Test suite now passes with expat.
-rw-r--r--bindings/xml/Makefile2
-rw-r--r--bindings/xml/expat_xmlparser.c312
2 files changed, 259 insertions, 55 deletions
diff --git a/bindings/xml/Makefile b/bindings/xml/Makefile
index e75e362..ea7653c 100644
--- a/bindings/xml/Makefile
+++ b/bindings/xml/Makefile
@@ -26,7 +26,7 @@ ifeq ($(WITH_EXPAT_BINDING),yes)
endif
ifeq ($(DO_XML_INSTALL),yes)
- DIR_INSTALL_ITEMS := /include/dom/bindings/libxml:xmlerror.h;xmlparser.h
+ DIR_INSTALL_ITEMS := /include/dom/bindings/xml:xmlerror.h;xmlparser.h
endif
include $(NSBUILD)/Makefile.subdir
diff --git a/bindings/xml/expat_xmlparser.c b/bindings/xml/expat_xmlparser.c
index ce649d7..1077bc9 100644
--- a/bindings/xml/expat_xmlparser.c
+++ b/bindings/xml/expat_xmlparser.c
@@ -29,6 +29,7 @@ struct dom_xml_parser {
bool complete; /**< Indicate stream completion */
struct dom_document *doc; /**< DOM Document we're building */
struct dom_node *current; /**< DOM node we're currently building */
+ bool is_cdata; /**< If the character data is cdata or text */
};
/* Binding functions */
@@ -42,9 +43,7 @@ expat_xmlparser_start_element_handler(void *_parser,
dom_exception err;
dom_element *elem, *ins_elem;
dom_string *tag_name;
-
- fprintf(stderr, "<%s>\n", name);
-
+
err = dom_string_create((const uint8_t *)name,
strlen(name),
&tag_name);
@@ -53,7 +52,7 @@ expat_xmlparser_start_element_handler(void *_parser,
"No memory for tag name");
return;
}
-
+
err = dom_document_create_element(parser->doc, tag_name, &elem);
if (err != DOM_NO_ERR) {
dom_string_unref(tag_name);
@@ -61,15 +60,15 @@ expat_xmlparser_start_element_handler(void *_parser,
"Failed to create element '%s'", name);
return;
}
-
+
dom_string_unref(tag_name);
-
+
/* Add attributes to the element */
-
+
while (*atts) {
dom_string *key, *value;
- err = dom_string_create((const uint8_t *)(*atts),
+ err = dom_string_create((const uint8_t *)(*atts),
strlen(*atts), &key);
if (err != DOM_NO_ERR) {
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
@@ -88,7 +87,7 @@ expat_xmlparser_start_element_handler(void *_parser,
return;
}
atts++;
-
+
err = dom_element_set_attribute(elem, key, value);
dom_string_unref(key);
dom_string_unref(value);
@@ -99,7 +98,7 @@ expat_xmlparser_start_element_handler(void *_parser,
return;
}
}
-
+
err = dom_node_append_child(parser->current, elem, &ins_elem);
if (err != DOM_NO_ERR) {
dom_node_unref(elem);
@@ -107,9 +106,9 @@ expat_xmlparser_start_element_handler(void *_parser,
"No memory for appending child node");
return;
}
-
+
dom_node_unref(ins_elem);
-
+
dom_node_unref(parser->current);
parser->current = (struct dom_node *)elem; /* Steal initial ref */
}
@@ -121,24 +120,38 @@ expat_xmlparser_end_element_handler(void *_parser,
dom_xml_parser *parser = _parser;
dom_exception err;
dom_node *parent;
-
+
UNUSED(name);
-
- fprintf(stderr, "</%s>\n", name);
-
+
err = dom_node_get_parent_node(parser->current, &parent);
-
+
if (err != DOM_NO_ERR) {
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
"Unable to find a parent while closing element.");
return;
}
-
+
dom_node_unref(parser->current);
parser->current = parent; /* Takes the ref given by get_parent_node */
}
static void
+expat_xmlparser_start_cdata_handler(void *_parser)
+{
+ dom_xml_parser *parser = _parser;
+
+ parser->is_cdata = true;
+}
+
+static void
+expat_xmlparser_end_cdata_handler(void *_parser)
+{
+ dom_xml_parser *parser = _parser;
+
+ parser->is_cdata = false;
+}
+
+static void
expat_xmlparser_cdata_handler(void *_parser,
const XML_Char *s,
int len)
@@ -146,29 +159,66 @@ expat_xmlparser_cdata_handler(void *_parser,
dom_xml_parser *parser = _parser;
dom_string *data;
dom_exception err;
- struct dom_cdata_section *cdata, *ins_cdata;
-
+ struct dom_node *cdata, *ins_cdata, *lastchild = NULL;
+ dom_node_type ntype = 0;
+
err = dom_string_create((const uint8_t *)s, len, &data);
if (err != DOM_NO_ERR) {
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
"No memory for cdata section contents");
return;
}
-
- err = dom_document_create_cdata_section(parser->doc, data, &cdata);
+
+ err = dom_node_get_last_child(parser->current, &lastchild);
+
+ if (err == DOM_NO_ERR && lastchild != NULL) {
+ err = dom_node_get_node_type(lastchild, &ntype);
+ }
+
if (err != DOM_NO_ERR) {
dom_string_unref(data);
+ if (lastchild != NULL)
+ dom_node_unref(lastchild);
parser->msg(DOM_MSG_CRITICAL, parser->mctx,
"No memory for cdata section");
return;
}
-
+
+ if (ntype == DOM_TEXT_NODE && parser->is_cdata == false) {
+ /* We can append this text instead */
+ err = dom_characterdata_append_data(
+ (dom_characterdata *)lastchild, data);
+ dom_string_unref(data);
+ if (lastchild != NULL)
+ dom_node_unref(lastchild);
+ if (err != DOM_NO_ERR) {
+ parser->msg(DOM_MSG_CRITICAL, parser->mctx,
+ "No memory for cdata section");
+ }
+ return;
+ }
+
+ if (lastchild != NULL)
+ dom_node_unref(lastchild);
+
+ /* We can't append directly, so make a new node */
+ err = parser->is_cdata ?
+ dom_document_create_cdata_section(parser->doc, data,
+ (dom_cdata_section **)&cdata) :
+ dom_document_create_text_node(parser->doc, data,
+ (dom_text **)&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(parser->current, (struct dom_node *) cdata,
- (struct dom_node **) (void *) &ins_cdata);
+ err = dom_node_append_child(parser->current, cdata, &ins_cdata);
if (err != DOM_NO_ERR) {
dom_node_unref((struct dom_node *) cdata);
parser->msg(DOM_MSG_ERROR, parser->mctx,
@@ -178,10 +228,149 @@ expat_xmlparser_cdata_handler(void *_parser,
/* We're not interested in the inserted cdata section */
if (ins_cdata != NULL)
- dom_node_unref((struct dom_node *) ins_cdata);
+ dom_node_unref(ins_cdata);
/* No longer interested in cdata section */
- dom_node_unref((struct dom_node *) cdata);
+ dom_node_unref(cdata);
+}
+
+static int
+expat_xmlparser_external_entity_ref_handler(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *system_id,
+ const XML_Char *public_id)
+{
+ FILE *fh;
+ XML_Parser subparser;
+ unsigned char data[1024];
+ size_t len;
+ enum XML_Status status;
+
+ UNUSED(base);
+ UNUSED(public_id);
+
+ if (system_id == NULL)
+ return XML_STATUS_OK;
+
+ fh = fopen(system_id, "r");
+
+ if (fh == NULL)
+ return XML_STATUS_OK;
+
+ subparser = XML_ExternalEntityParserCreate(parser,
+ context,
+ NULL);
+
+ if (subparser == NULL) {
+ fclose(fh);
+ return XML_STATUS_OK;
+ }
+
+ /* Parse the file bit by bit */
+ while ((len = fread(data, 1, 1024, fh)) > 0) {
+ status = XML_Parse(subparser, (const char *)data, len, 0);
+ if (status != XML_STATUS_OK) {
+ XML_ParserFree(subparser);
+ fclose(fh);
+ return XML_STATUS_OK;
+ }
+ }
+ XML_Parse(subparser, "", 0, 1);
+ XML_ParserFree(subparser);
+ fclose(fh);
+ return XML_STATUS_OK;
+}
+
+static void
+expat_xmlparser_comment_handler(void *_parser,
+ const XML_Char *_comment)
+{
+ dom_xml_parser *parser = _parser;
+ struct dom_comment *comment, *ins_comment = NULL;
+ dom_string *data;
+ dom_exception err;
+
+ /* Create DOM string data for comment */
+ err = dom_string_create((const uint8_t *)_comment,
+ strlen((const char *) _comment), &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(parser->current, (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);
+
+ /* No longer interested in comment */
+ dom_node_unref((struct dom_node *) comment);
+
+}
+
+static void
+expat_xmlparser_start_doctype_decl_handler(void *_parser,
+ const XML_Char *doctype_name,
+ const XML_Char *system_id,
+ const XML_Char *public_id,
+ int has_internal_subset)
+{
+ dom_xml_parser *parser = _parser;
+ struct dom_document_type *doctype, *ins_doctype = NULL;
+ dom_exception err;
+
+ UNUSED(has_internal_subset);
+
+ err = dom_implementation_create_document_type(
+ doctype_name, system_id ? system_id : "",
+ public_id ? public_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(parser->doc, (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);
+
+ /* No longer interested in doctype */
+ dom_node_unref((struct dom_node *) doctype);
}
static void
@@ -190,8 +379,8 @@ expat_xmlparser_unknown_data_handler(void *_parser,
int len)
{
UNUSED(_parser);
-
- fprintf(stderr, "!!! %.*s !!!\n", len, s);
+ UNUSED(s);
+ UNUSED(len);
}
/**
* Create an XML parser instance
@@ -210,29 +399,29 @@ dom_xml_parser_create(const char *enc, const char *int_enc,
{
dom_xml_parser *parser;
dom_exception err;
-
+
UNUSED(int_enc);
-
+
parser = calloc(sizeof(*parser), 1);
if (parser == NULL) {
msg(DOM_MSG_CRITICAL, mctx, "No memory for parser");
return NULL;
}
-
+
parser->msg = msg;
parser->mctx = mctx;
-
+
parser->parser = XML_ParserCreateNS(enc, ':');
-
+
if (parser->parser == NULL) {
free(parser);
msg(DOM_MSG_CRITICAL, mctx, "No memory for parser");
return NULL;
}
-
+
parser->complete = false;
parser->doc = NULL;
-
+
err = dom_implementation_create_document(
DOM_IMPLEMENTATION_XML,
/* namespace */ NULL,
@@ -240,32 +429,47 @@ dom_xml_parser_create(const char *enc, const char *int_enc,
/* doctype */ NULL,
NULL,
&parser->doc);
-
+
if (err != DOM_NO_ERR) {
- parser->msg(DOM_MSG_CRITICAL, parser->mctx,
+ parser->msg(DOM_MSG_CRITICAL, parser->mctx,
"Failed creating document");
XML_ParserFree(parser->parser);
free(parser);
return NULL;
}
-
+
XML_SetUserData(parser->parser, parser);
-
+
XML_SetElementHandler(parser->parser,
expat_xmlparser_start_element_handler,
expat_xmlparser_end_element_handler);
-
+
+ XML_SetCdataSectionHandler(parser->parser,
+ expat_xmlparser_start_cdata_handler,
+ expat_xmlparser_end_cdata_handler);
+
XML_SetCharacterDataHandler(parser->parser,
expat_xmlparser_cdata_handler);
-
- XML_SetParamEntityParsing(parser->parser,
+
+ XML_SetParamEntityParsing(parser->parser,
XML_PARAM_ENTITY_PARSING_ALWAYS);
-
- XML_SetDefaultHandler(parser->parser,
+
+ XML_SetExternalEntityRefHandler(parser->parser,
+ expat_xmlparser_external_entity_ref_handler);
+
+ XML_SetCommentHandler(parser->parser,
+ expat_xmlparser_comment_handler);
+
+ XML_SetStartDoctypeDeclHandler(parser->parser,
+ expat_xmlparser_start_doctype_decl_handler);
+
+ XML_SetDefaultHandlerExpand(parser->parser,
expat_xmlparser_unknown_data_handler);
-
+
parser->current = dom_node_ref(parser->doc);
-
+
+ parser->is_cdata = false;
+
return parser;
}
@@ -278,7 +482,7 @@ void
dom_xml_parser_destroy(dom_xml_parser *parser)
{
XML_ParserFree(parser->parser);
-
+
free(parser);
}
@@ -294,14 +498,14 @@ dom_xml_error
dom_xml_parser_parse_chunk(dom_xml_parser *parser, uint8_t *data, size_t len)
{
enum XML_Status status;
-
+
status = XML_Parse(parser->parser, (const char *)data, len, 0);
if (status != XML_STATUS_OK) {
parser->msg(DOM_MSG_ERROR, parser->mctx,
"XML_Parse failed: %d", status);
return DOM_XML_EXTERNAL_ERR | status;
}
-
+
return DOM_XML_OK;
}
@@ -313,20 +517,20 @@ dom_xml_parser_parse_chunk(dom_xml_parser *parser, uint8_t *data, size_t len)
*
* This will force any remaining data through the parser
*/
-dom_xml_error
+dom_xml_error
dom_xml_parser_completed(dom_xml_parser *parser)
{
enum XML_Status status;
-
+
status = XML_Parse(parser->parser, "", 0, 1);
if (status != XML_STATUS_OK) {
parser->msg(DOM_MSG_ERROR, parser->mctx,
"XML_Parse failed: %d", status);
return DOM_XML_EXTERNAL_ERR | status;
}
-
+
parser->complete = true;
-
+
return DOM_XML_OK;
}