@@ -2103,33 +2103,72 @@ PHP_METHOD(DOMNode, lookupNamespaceURI)
21032103}
21042104/* }}} end dom_node_lookup_namespace_uri */
21052105
2106+ /* Allocate, track and prepend a temporary nsDef entry for C14N.
2107+ * Returns the new xmlNsPtr for the caller to fill in href/prefix/_private,
2108+ * or NULL on allocation failure. */
2109+ static xmlNsPtr dom_alloc_ns_decl (HashTable * links , xmlNodePtr node )
2110+ {
2111+ xmlNsPtr ns = xmlMalloc (sizeof (* ns ));
2112+ if (!ns ) {
2113+ return NULL ;
2114+ }
2115+
2116+ zval * zv = zend_hash_index_lookup (links , (zend_ulong ) node );
2117+ if (Z_ISNULL_P (zv )) {
2118+ ZVAL_LONG (zv , 1 );
2119+ } else {
2120+ Z_LVAL_P (zv )++ ;
2121+ }
2122+
2123+ memset (ns , 0 , sizeof (* ns ));
2124+ ns -> type = XML_LOCAL_NAMESPACE ;
2125+ ns -> next = node -> nsDef ;
2126+ node -> nsDef = ns ;
2127+
2128+ return ns ;
2129+ }
2130+
2131+ /* Mint a temporary nsDef entry so C14N finds namespaces that live on node->ns
2132+ * but have no matching xmlns attribute (typical for createElementNS). */
2133+ static void dom_add_synthetic_ns_decl (HashTable * links , xmlNodePtr node , xmlNsPtr src_ns )
2134+ {
2135+ xmlNsPtr ns = dom_alloc_ns_decl (links , node );
2136+ if (!ns ) {
2137+ return ;
2138+ }
2139+
2140+ ns -> href = xmlStrdup (src_ns -> href );
2141+ ns -> prefix = src_ns -> prefix ? xmlStrdup (src_ns -> prefix ) : NULL ;
2142+ }
2143+
2144+ /* Same, but for attribute namespaces, which may collide by prefix with the
2145+ * element's own ns or with a sibling attribute's ns. */
2146+ static void dom_add_synthetic_ns_decl_for_attr (HashTable * links , xmlNodePtr node , xmlNsPtr src_ns )
2147+ {
2148+ for (xmlNsPtr existing = node -> nsDef ; existing ; existing = existing -> next ) {
2149+ if (xmlStrEqual (existing -> prefix , src_ns -> prefix )) {
2150+ return ;
2151+ }
2152+ }
2153+
2154+ dom_add_synthetic_ns_decl (links , node , src_ns );
2155+ }
2156+
21062157static void dom_relink_ns_decls_element (HashTable * links , xmlNodePtr node )
21072158{
21082159 if (node -> type == XML_ELEMENT_NODE ) {
21092160 for (xmlAttrPtr attr = node -> properties ; attr ; attr = attr -> next ) {
21102161 if (php_dom_ns_is_fast ((const xmlNode * ) attr , php_dom_ns_is_xmlns_magic_token )) {
2111- xmlNsPtr ns = xmlMalloc ( sizeof ( * ns ) );
2162+ xmlNsPtr ns = dom_alloc_ns_decl ( links , node );
21122163 if (!ns ) {
21132164 return ;
21142165 }
21152166
2116- zval * zv = zend_hash_index_lookup (links , (zend_ulong ) node );
2117- if (Z_ISNULL_P (zv )) {
2118- ZVAL_LONG (zv , 1 );
2119- } else {
2120- Z_LVAL_P (zv )++ ;
2121- }
2122-
21232167 bool should_free ;
21242168 xmlChar * attr_value = php_libxml_attr_value (attr , & should_free );
21252169
2126- memset (ns , 0 , sizeof (* ns ));
2127- ns -> type = XML_LOCAL_NAMESPACE ;
21282170 ns -> href = should_free ? attr_value : xmlStrdup (attr_value );
21292171 ns -> prefix = attr -> ns -> prefix ? xmlStrdup (attr -> name ) : NULL ;
2130- ns -> next = node -> nsDef ;
2131- node -> nsDef = ns ;
2132-
21332172 ns -> _private = attr ;
21342173 if (attr -> prev ) {
21352174 attr -> prev -> next = attr -> next ;
@@ -2150,6 +2189,14 @@ static void dom_relink_ns_decls_element(HashTable *links, xmlNodePtr node)
21502189 * can return the current namespace. */
21512190 zend_hash_index_add_new_ptr (links , (zend_ulong ) node | 1 , node -> ns );
21522191 node -> ns = xmlSearchNs (node -> doc , node , NULL );
2192+ } else if (node -> ns ) {
2193+ dom_add_synthetic_ns_decl (links , node , node -> ns );
2194+ }
2195+
2196+ for (xmlAttrPtr attr = node -> properties ; attr ; attr = attr -> next ) {
2197+ if (attr -> ns && !php_dom_ns_is_fast ((const xmlNode * ) attr , php_dom_ns_is_xmlns_magic_token )) {
2198+ dom_add_synthetic_ns_decl_for_attr (links , node , attr -> ns );
2199+ }
21532200 }
21542201 }
21552202}
@@ -2179,13 +2226,15 @@ static void dom_unlink_ns_decls(HashTable *links)
21792226 node -> nsDef = ns -> next ;
21802227
21812228 xmlAttrPtr attr = ns -> _private ;
2182- if (attr -> prev ) {
2183- attr -> prev -> next = attr ;
2184- } else {
2185- node -> properties = attr ;
2186- }
2187- if (attr -> next ) {
2188- attr -> next -> prev = attr ;
2229+ if (attr ) {
2230+ if (attr -> prev ) {
2231+ attr -> prev -> next = attr ;
2232+ } else {
2233+ node -> properties = attr ;
2234+ }
2235+ if (attr -> next ) {
2236+ attr -> next -> prev = attr ;
2237+ }
21892238 }
21902239
21912240 xmlFreeNs (ns );
0 commit comments