summaryrefslogtreecommitdiff
path: root/ext/xml
diff options
context:
space:
mode:
authorRob Richards <rrichards@php.net>2003-09-29 11:35:39 +0000
committerRob Richards <rrichards@php.net>2003-09-29 11:35:39 +0000
commit5fa23c593bab220f81a9930947b2b28a6e2c0611 (patch)
treee8c75f1fbbc1065fea3fc328f1ddeb63a2208f9c /ext/xml
parent103b3c6626844194abc8bb7ac8aff4f8a007febe (diff)
downloadphp-git-5fa23c593bab220f81a9930947b2b28a6e2c0611.tar.gz
fix for bug #25666 (XML namespaces broken in PHP5)
Diffstat (limited to 'ext/xml')
-rw-r--r--ext/xml/compat.c157
-rw-r--r--ext/xml/expat_compat.h3
2 files changed, 140 insertions, 20 deletions
diff --git a/ext/xml/compat.c b/ext/xml/compat.c
index 45c47d14d7..da7642982c 100644
--- a/ext/xml/compat.c
+++ b/ext/xml/compat.c
@@ -20,6 +20,13 @@
#if HAVE_LIBXML && HAVE_XML
#include "expat_compat.h"
+typedef struct _php_xml_ns {
+ xmlNsPtr nsptr;
+ int ref_count;
+ void *next;
+ void *prev;
+} php_xml_ns;
+
#ifdef LIBXML_EXPAT_COMPAT
#define IS_NS_DECL(__ns) \
@@ -34,24 +41,84 @@ _find_namespace_decl(XML_Parser parser, const xmlChar *tagname, const xmlChar **
xmlChar *value;
xmlChar *partial;
xmlChar *namespace;
+ php_xml_ns *cur_ns_scope = NULL;
+ php_xml_ns *exist_ns_scope;
+ xmlNsPtr nsptr, curnsptr;
+
+ exist_ns_scope = xmlHashLookup(parser->_reverse_ns_map, tagname);
+
+ if (exist_ns_scope) {
+ while (exist_ns_scope->next != NULL)
+ exist_ns_scope = exist_ns_scope->next;
+ }
while (attr_p && *attr_p) {
name = attr_p[0];
value = xmlStrdup(attr_p[1]);
partial = xmlSplitQName(parser->parser, name, &namespace);
+
if (IS_NS_DECL(namespace)) {
+
if (parser->h_start_ns) {
parser->h_start_ns(parser->user, partial, (const XML_Char *) value);
}
- xmlHashAddEntry(parser->_ns_map, partial, value);
- xmlHashAddEntry(parser->_reverse_ns_map, tagname, xmlStrdup(partial));
- break;
+ if (xmlHashLookup(parser->_ns_map, partial) == NULL) {
+ xmlHashAddEntry(parser->_ns_map, partial, value);
+ } else {
+ xmlFree(value);
+ }
+
+ nsptr = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
+
+ if (nsptr) {
+ memset(nsptr, 0, sizeof(xmlNs));
+ nsptr->type = XML_LOCAL_NAMESPACE;
+
+ if (value != NULL)
+ nsptr->href = xmlStrdup(value);
+ if (partial != NULL)
+ nsptr->prefix = xmlStrdup(partial);
+
+ if (cur_ns_scope == NULL) {
+ cur_ns_scope = emalloc(sizeof(php_xml_ns));
+ cur_ns_scope->next = NULL;
+ cur_ns_scope->prev = NULL;
+ cur_ns_scope->nsptr = nsptr;
+ cur_ns_scope->ref_count = 0;
+
+ if (exist_ns_scope) {
+ exist_ns_scope->next = cur_ns_scope;
+ cur_ns_scope->prev = exist_ns_scope;
+ } else {
+ xmlHashAddEntry(parser->_reverse_ns_map, tagname, cur_ns_scope);
+ }
+
+ exist_ns_scope = cur_ns_scope;
+ } else {
+ curnsptr = cur_ns_scope->nsptr;
+ while (curnsptr->next != NULL) {
+ curnsptr = curnsptr->next;
+ }
+ curnsptr->next = nsptr;
+ }
+ }
+
+ } else {
+ xmlFree(value);
+ }
+
+ xmlFree(partial);
+ if (namespace != NULL) {
+ xmlFree(namespace);
}
- xmlFree(value);
attr_p += 2;
}
+
+ if (exist_ns_scope) {
+ exist_ns_scope->ref_count++;
+ }
}
static void
@@ -59,7 +126,6 @@ _qualify_namespace(XML_Parser parser, const xmlChar *name, xmlChar **qualified)
{
xmlChar *partial;
xmlChar *namespace;
- int len;
partial = xmlSplitQName(parser->parser, name, &namespace);
if (namespace) {
@@ -67,18 +133,19 @@ _qualify_namespace(XML_Parser parser, const xmlChar *name, xmlChar **qualified)
nsvalue = xmlHashLookup(parser->_ns_map, namespace);
if (nsvalue) {
- len = strlen(nsvalue) + strlen(partial) + 1; /* colon */
- *qualified = malloc(len+1);
- memcpy(*qualified, nsvalue, strlen(nsvalue));
- memcpy(*qualified + strlen(nsvalue), ":", 1);
- memcpy(*qualified + strlen(nsvalue) + 1, partial, strlen(partial));
- (*qualified)[len] = '\0';
+ /* Use libxml functions otherwise its memory deallocation is screwed up */
+ *qualified = xmlStrdup(nsvalue);
+ *qualified = xmlStrncat(*qualified, parser->_ns_seperator, 1);
+ *qualified = xmlStrncat(*qualified, partial, strlen(partial));
} else {
*qualified = xmlStrdup(name);
}
+ xmlFree(namespace);
} else {
*qualified = xmlStrdup(name);
}
+
+ xmlFree(partial);
}
static void
@@ -104,6 +171,15 @@ _start_element_handler(void *user, const xmlChar *name, const xmlChar **attribut
}
static void
+_namespace_handler(XML_Parser parser, xmlNsPtr nsptr)
+{
+ if (nsptr != NULL) {
+ _namespace_handler(parser, nsptr->next);
+ parser->h_end_ns(parser->user, nsptr->prefix);
+ }
+}
+
+static void
_end_element_handler(void *user, const xmlChar *name)
{
xmlChar *qualified_name;
@@ -114,13 +190,6 @@ _end_element_handler(void *user, const xmlChar *name)
}
if (parser->use_namespace) {
- xmlChar *nsname;
-
- nsname = xmlHashLookup(parser->_reverse_ns_map, name);
- if (nsname && parser->h_end_ns) {
- parser->h_end_ns(parser->user, nsname);
- }
-
_qualify_namespace(parser, name, &qualified_name);
} else {
qualified_name = xmlStrdup(name);
@@ -128,6 +197,33 @@ _end_element_handler(void *user, const xmlChar *name)
parser->h_end_element(parser->user, (const XML_Char *) qualified_name);
+ if (parser->use_namespace) {
+ int tag_counter;
+ php_xml_ns *cur_ns_scope, *prev_ns_scope;
+ xmlNsPtr nsptr;
+
+ cur_ns_scope = xmlHashLookup(parser->_reverse_ns_map, name);
+ if (cur_ns_scope) {
+ while (cur_ns_scope->next != NULL) {
+ cur_ns_scope = cur_ns_scope->next;
+ }
+ tag_counter = --cur_ns_scope->ref_count;
+ if (tag_counter == 0) {
+ nsptr = cur_ns_scope->nsptr;
+ if (nsptr && parser->h_end_ns) {
+ _namespace_handler(parser, nsptr);
+ }
+ xmlFreeNsList(nsptr);
+ cur_ns_scope->nsptr = NULL;
+ prev_ns_scope = cur_ns_scope->prev;
+ if (prev_ns_scope != NULL) {
+ efree(cur_ns_scope);
+ prev_ns_scope->next = NULL;
+ }
+ }
+ }
+ }
+
xmlFree(qualified_name);
}
@@ -304,6 +400,8 @@ XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *m
parser = (XML_Parser) emalloc(sizeof(struct _XML_Parser));
memset(parser, 0, sizeof(struct _XML_Parser));
parser->use_namespace = 0;
+ parser->_ns_seperator = NULL;
+
parser->parser = xmlCreatePushParserCtxt((xmlSAXHandlerPtr) &php_xml_compat_handlers, (void *) parser, NULL, 0, NULL);
if (parser->parser == NULL) {
efree(parser);
@@ -318,6 +416,7 @@ XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *m
parser->use_namespace = 1;
parser->_ns_map = xmlHashCreate(10);
parser->_reverse_ns_map = xmlHashCreate(10);
+ parser->_ns_seperator = xmlStrdup(sep);
}
return parser;
}
@@ -544,12 +643,32 @@ _free_ns_name(void *ptr, xmlChar *name)
xmlFree(ptr);
}
+static void
+_free_ns_pointer(void *ptr, xmlChar *name)
+{
+ php_xml_ns *cur_ns_scope;
+
+ /* Child scopes should already be removed, but in the event
+ of malformed xml, they may still be resident and need to be cleaned */
+ cur_ns_scope = ((php_xml_ns *) ptr)->next;
+ if (cur_ns_scope != NULL) {
+ _free_ns_pointer(cur_ns_scope, NULL);
+ }
+
+ xmlFreeNsList(((php_xml_ns *) ptr)->nsptr);
+
+ efree(ptr);
+}
+
void
XML_ParserFree(XML_Parser parser)
{
if (parser->use_namespace) {
xmlHashFree(parser->_ns_map, _free_ns_name);
- xmlHashFree(parser->_reverse_ns_map, _free_ns_name);
+ xmlHashFree(parser->_reverse_ns_map, _free_ns_pointer);
+ if (parser->_ns_seperator) {
+ xmlFree(parser->_ns_seperator);
+ }
}
xmlFreeParserCtxt(parser->parser);
efree(parser);
diff --git a/ext/xml/expat_compat.h b/ext/xml/expat_compat.h
index 16407ff71c..13012bc2c3 100644
--- a/ext/xml/expat_compat.h
+++ b/ext/xml/expat_compat.h
@@ -56,7 +56,8 @@ typedef struct _XML_Parser {
xmlHashTablePtr _ns_map;
xmlHashTablePtr _reverse_ns_map;
-
+ xmlChar *_ns_seperator;
+
void *user;
xmlParserCtxtPtr parser;