diff options
author | Rob Richards <rrichards@php.net> | 2003-09-29 11:35:39 +0000 |
---|---|---|
committer | Rob Richards <rrichards@php.net> | 2003-09-29 11:35:39 +0000 |
commit | 5fa23c593bab220f81a9930947b2b28a6e2c0611 (patch) | |
tree | e8c75f1fbbc1065fea3fc328f1ddeb63a2208f9c /ext/xml | |
parent | 103b3c6626844194abc8bb7ac8aff4f8a007febe (diff) | |
download | php-git-5fa23c593bab220f81a9930947b2b28a6e2c0611.tar.gz |
fix for bug #25666 (XML namespaces broken in PHP5)
Diffstat (limited to 'ext/xml')
-rw-r--r-- | ext/xml/compat.c | 157 | ||||
-rw-r--r-- | ext/xml/expat_compat.h | 3 |
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; |