@@ -1076,10 +1076,56 @@ static void php_dom_transfer_document_ref(xmlNodePtr node, php_libxml_ref_obj *n
10761076 }
10771077}
10781078
1079+ /* Workaround for bug that was fixed in https://github.com/GNOME/libxml2/commit/4bc3ebf3eaba352fbbce2ef70ad00a3c7752478a */
1080+ #if LIBXML_VERSION < 21000
1081+ static xmlChar * libxml_copy_dicted_string (xmlDictPtr src_dict , xmlDictPtr dst_dict , xmlChar * str )
1082+ {
1083+ if (str == NULL ) {
1084+ return NULL ;
1085+ }
1086+ if (xmlDictOwns (src_dict , str ) == 1 ) {
1087+ if (dst_dict == NULL ) {
1088+ return xmlStrdup (str );
1089+ }
1090+ return BAD_CAST xmlDictLookup (dst_dict , str , -1 );
1091+ }
1092+ return str ;
1093+ }
1094+
1095+ static void libxml_fixup_name_and_content (xmlDocPtr src_doc , xmlDocPtr dst_doc , xmlNodePtr node )
1096+ {
1097+ if (node -> type == XML_ENTITY_REF_NODE ) {
1098+ node -> children = NULL ; /* Break link with original document. */
1099+ }
1100+ if (src_doc != NULL && src_doc -> dict != NULL ) {
1101+ ZEND_ASSERT (dst_doc != src_doc );
1102+ node -> name = libxml_copy_dicted_string (src_doc -> dict , dst_doc -> dict , BAD_CAST node -> name );
1103+ node -> content = libxml_copy_dicted_string (src_doc -> dict , NULL , node -> content );
1104+ }
1105+ }
1106+
1107+ static void libxml_fixup_name_and_content_element (xmlDocPtr src_doc , xmlDocPtr dst_doc , xmlNodePtr node )
1108+ {
1109+ libxml_fixup_name_and_content (src_doc , dst_doc , node );
1110+ for (xmlAttrPtr attr = node -> properties ; attr != NULL ; attr = attr -> next ) {
1111+ libxml_fixup_name_and_content (src_doc , dst_doc , (xmlNodePtr ) attr );
1112+ for (xmlNodePtr attr_child = attr -> children ; attr_child != NULL ; attr_child = attr_child -> next ) {
1113+ libxml_fixup_name_and_content (src_doc , dst_doc , attr_child );
1114+ }
1115+ }
1116+
1117+ for (xmlNodePtr child = node -> children ; child != NULL ; child = child -> next ) {
1118+ libxml_fixup_name_and_content_element (src_doc , dst_doc , child );
1119+ }
1120+ }
1121+ #endif
1122+
10791123bool php_dom_adopt_node (xmlNodePtr nodep , dom_object * dom_object_new_document , xmlDocPtr new_document )
10801124{
1081- php_libxml_invalidate_node_list_cache_from_doc (nodep -> doc );
1082- if (nodep -> doc != new_document ) {
1125+ xmlDocPtr old_doc = nodep -> doc ;
1126+
1127+ php_libxml_invalidate_node_list_cache_from_doc (old_doc );
1128+ if (old_doc != new_document ) {
10831129 php_libxml_invalidate_node_list_cache (dom_object_new_document -> document );
10841130
10851131 /* Note for ATTRIBUTE_NODE: specified is always true in ext/dom,
@@ -1089,6 +1135,11 @@ bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, x
10891135 return false;
10901136 }
10911137
1138+ #if LIBXML_VERSION < 21000
1139+ /* Must be first before transferring the ref to ensure the old document dictionary stays alive. */
1140+ libxml_fixup_name_and_content_element (old_doc , new_document , nodep );
1141+ #endif
1142+
10921143 php_dom_transfer_document_ref (nodep , dom_object_new_document -> document );
10931144 } else {
10941145 xmlUnlinkNode (nodep );
0 commit comments