Skip to content

Commit ab75195

Browse files
committed
address feedback
1 parent 8e57401 commit ab75195

3 files changed

Lines changed: 142 additions & 143 deletions

File tree

ext/dom/namespace_compat.c

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,4 +501,142 @@ PHP_DOM_EXPORT void php_dom_in_scope_ns_destroy(php_dom_in_scope_ns *in_scope_ns
501501
}
502502
}
503503

504+
static xmlNsPtr dom_alloc_ns_decl(HashTable *links, xmlNodePtr node)
505+
{
506+
xmlNsPtr ns = xmlMalloc(sizeof(*ns));
507+
if (!ns) {
508+
return NULL;
509+
}
510+
511+
zval *zv = zend_hash_index_lookup(links, (zend_ulong) node);
512+
if (Z_ISNULL_P(zv)) {
513+
ZVAL_LONG(zv, 1);
514+
} else {
515+
Z_LVAL_P(zv)++;
516+
}
517+
518+
memset(ns, 0, sizeof(*ns));
519+
ns->type = XML_LOCAL_NAMESPACE;
520+
ns->next = node->nsDef;
521+
node->nsDef = ns;
522+
523+
return ns;
524+
}
525+
526+
/* Mint a temporary nsDef entry so C14N finds namespaces that live on node->ns
527+
* but have no matching xmlns attribute (typical for createElementNS). */
528+
static void dom_add_synthetic_ns_decl(HashTable *links, xmlNodePtr node, xmlNsPtr src_ns)
529+
{
530+
xmlNsPtr ns = dom_alloc_ns_decl(links, node);
531+
if (!ns) {
532+
return;
533+
}
534+
535+
ns->href = xmlStrdup(src_ns->href);
536+
ns->prefix = src_ns->prefix ? xmlStrdup(src_ns->prefix) : NULL;
537+
}
538+
539+
/* Same, but for attribute namespaces, which may collide by prefix with the
540+
* element's own ns or with a sibling attribute's ns. */
541+
static void dom_add_synthetic_ns_decl_for_attr(HashTable *links, xmlNodePtr node, xmlNsPtr src_ns)
542+
{
543+
for (xmlNsPtr existing = node->nsDef; existing; existing = existing->next) {
544+
if (xmlStrEqual(existing->prefix, src_ns->prefix)) {
545+
return;
546+
}
547+
}
548+
549+
dom_add_synthetic_ns_decl(links, node, src_ns);
550+
}
551+
552+
static void dom_relink_ns_decls_element(HashTable *links, xmlNodePtr node)
553+
{
554+
if (node->type == XML_ELEMENT_NODE) {
555+
for (xmlAttrPtr attr = node->properties; attr; attr = attr->next) {
556+
if (php_dom_ns_is_fast((const xmlNode *) attr, php_dom_ns_is_xmlns_magic_token)) {
557+
xmlNsPtr ns = dom_alloc_ns_decl(links, node);
558+
if (!ns) {
559+
return;
560+
}
561+
562+
bool should_free;
563+
xmlChar *attr_value = php_libxml_attr_value(attr, &should_free);
564+
565+
ns->href = should_free ? attr_value : xmlStrdup(attr_value);
566+
ns->prefix = attr->ns->prefix ? xmlStrdup(attr->name) : NULL;
567+
ns->_private = attr;
568+
if (attr->prev) {
569+
attr->prev->next = attr->next;
570+
} else {
571+
node->properties = attr->next;
572+
}
573+
if (attr->next) {
574+
attr->next->prev = attr->prev;
575+
}
576+
}
577+
}
578+
579+
/* The default namespace is handled separately from the other namespaces in C14N.
580+
* The default namespace is explicitly looked up while the other namespaces are
581+
* deduplicated and compared to a list of visible namespaces. */
582+
if (node->ns && !node->ns->prefix) {
583+
/* Workaround for the behaviour where the xmlSearchNs() call inside c14n.c
584+
* can return the current namespace. */
585+
zend_hash_index_add_new_ptr(links, (zend_ulong) node | 1, node->ns);
586+
node->ns = xmlSearchNs(node->doc, node, NULL);
587+
} else if (node->ns) {
588+
dom_add_synthetic_ns_decl(links, node, node->ns);
589+
}
590+
591+
for (xmlAttrPtr attr = node->properties; attr; attr = attr->next) {
592+
if (attr->ns && !php_dom_ns_is_fast((const xmlNode *) attr, php_dom_ns_is_xmlns_magic_token)) {
593+
dom_add_synthetic_ns_decl_for_attr(links, node, attr->ns);
594+
}
595+
}
596+
}
597+
}
598+
599+
void dom_relink_ns_decls(HashTable *links, xmlNodePtr root)
600+
{
601+
dom_relink_ns_decls_element(links, root);
602+
603+
xmlNodePtr base = root;
604+
xmlNodePtr node = base->children;
605+
while (node != NULL) {
606+
dom_relink_ns_decls_element(links, node);
607+
node = php_dom_next_in_tree_order(node, base);
608+
}
609+
}
610+
611+
void dom_unlink_ns_decls(HashTable *links)
612+
{
613+
ZEND_HASH_MAP_FOREACH_NUM_KEY_VAL(links, zend_ulong h, zval *data) {
614+
if (h & 1) {
615+
xmlNodePtr node = (xmlNodePtr) (h ^ 1);
616+
node->ns = Z_PTR_P(data);
617+
} else {
618+
xmlNodePtr node = (xmlNodePtr) h;
619+
while (Z_LVAL_P(data)-- > 0) {
620+
xmlNsPtr ns = node->nsDef;
621+
node->nsDef = ns->next;
622+
623+
xmlAttrPtr attr = ns->_private;
624+
if (attr) {
625+
if (attr->prev) {
626+
attr->prev->next = attr;
627+
} else {
628+
node->properties = attr;
629+
}
630+
if (attr->next) {
631+
attr->next->prev = attr;
632+
}
633+
}
634+
635+
xmlFreeNs(ns);
636+
}
637+
}
638+
} ZEND_HASH_FOREACH_END();
639+
}
640+
641+
504642
#endif /* HAVE_LIBXML && HAVE_DOM */

ext/dom/namespace_compat.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ PHP_DOM_EXPORT void php_dom_in_scope_ns_destroy(php_dom_in_scope_ns *in_scope_ns
7272
/* Temporarily materialize namespace declarations as nsDef entries on the tree so
7373
* that libxml's native validators/canonicalizers can resolve prefixed QNames that
7474
* appear in element/attribute *content*. Modern DOM keeps declarations off the
75-
* tree (node->nsDef == NULL), which xmlSearchNs() cannot follow. */
76-
PHP_DOM_EXPORT void dom_relink_ns_decls(HashTable *links, xmlNodePtr root);
77-
PHP_DOM_EXPORT void dom_unlink_ns_decls(HashTable *links);
75+
* tree (node->nsDef == NULL), which xmlSearchNs() cannot follow. Internal only —
76+
* not part of the exported DOM ABI. */
77+
void dom_relink_ns_decls(HashTable *links, xmlNodePtr root);
78+
void dom_unlink_ns_decls(HashTable *links);
7879

7980
#endif

ext/dom/node.c

Lines changed: 0 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,146 +2103,6 @@ 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-
2157-
static void dom_relink_ns_decls_element(HashTable *links, xmlNodePtr node)
2158-
{
2159-
if (node->type == XML_ELEMENT_NODE) {
2160-
for (xmlAttrPtr attr = node->properties; attr; attr = attr->next) {
2161-
if (php_dom_ns_is_fast((const xmlNode *) attr, php_dom_ns_is_xmlns_magic_token)) {
2162-
xmlNsPtr ns = dom_alloc_ns_decl(links, node);
2163-
if (!ns) {
2164-
return;
2165-
}
2166-
2167-
bool should_free;
2168-
xmlChar *attr_value = php_libxml_attr_value(attr, &should_free);
2169-
2170-
ns->href = should_free ? attr_value : xmlStrdup(attr_value);
2171-
ns->prefix = attr->ns->prefix ? xmlStrdup(attr->name) : NULL;
2172-
ns->_private = attr;
2173-
if (attr->prev) {
2174-
attr->prev->next = attr->next;
2175-
} else {
2176-
node->properties = attr->next;
2177-
}
2178-
if (attr->next) {
2179-
attr->next->prev = attr->prev;
2180-
}
2181-
}
2182-
}
2183-
2184-
/* The default namespace is handled separately from the other namespaces in C14N.
2185-
* The default namespace is explicitly looked up while the other namespaces are
2186-
* deduplicated and compared to a list of visible namespaces. */
2187-
if (node->ns && !node->ns->prefix) {
2188-
/* Workaround for the behaviour where the xmlSearchNs() call inside c14n.c
2189-
* can return the current namespace. */
2190-
zend_hash_index_add_new_ptr(links, (zend_ulong) node | 1, node->ns);
2191-
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-
}
2200-
}
2201-
}
2202-
}
2203-
2204-
void dom_relink_ns_decls(HashTable *links, xmlNodePtr root)
2205-
{
2206-
dom_relink_ns_decls_element(links, root);
2207-
2208-
xmlNodePtr base = root;
2209-
xmlNodePtr node = base->children;
2210-
while (node != NULL) {
2211-
dom_relink_ns_decls_element(links, node);
2212-
node = php_dom_next_in_tree_order(node, base);
2213-
}
2214-
}
2215-
2216-
void dom_unlink_ns_decls(HashTable *links)
2217-
{
2218-
ZEND_HASH_MAP_FOREACH_NUM_KEY_VAL(links, zend_ulong h, zval *data) {
2219-
if (h & 1) {
2220-
xmlNodePtr node = (xmlNodePtr) (h ^ 1);
2221-
node->ns = Z_PTR_P(data);
2222-
} else {
2223-
xmlNodePtr node = (xmlNodePtr) h;
2224-
while (Z_LVAL_P(data)-- > 0) {
2225-
xmlNsPtr ns = node->nsDef;
2226-
node->nsDef = ns->next;
2227-
2228-
xmlAttrPtr attr = ns->_private;
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-
}
2238-
}
2239-
2240-
xmlFreeNs(ns);
2241-
}
2242-
}
2243-
} ZEND_HASH_FOREACH_END();
2244-
}
2245-
22462106
static int dom_canonicalize_node_parent_lookup_cb(void *user_data, xmlNodePtr node, xmlNodePtr parent)
22472107
{
22482108
xmlNodePtr root = user_data;

0 commit comments

Comments
 (0)