@@ -820,11 +820,62 @@ int dom_node_text_content_write(dom_object *obj, zval *newval)
820
820
821
821
/* }}} */
822
822
823
- static xmlNodePtr _php_dom_insert_fragment (xmlNodePtr nodep , xmlNodePtr prevsib , xmlNodePtr nextsib , xmlNodePtr fragment , dom_object * intern , dom_object * childobj ) /* {{{ */
823
+ /* Returns true if the node was changed, false otherwise. */
824
+ static bool dom_set_document_ref_obj_single (xmlNodePtr node , xmlDocPtr doc , php_libxml_ref_obj * document )
824
825
{
825
- xmlNodePtr newchild , node ;
826
+ dom_object * childobj = php_dom_object_get_data (node );
827
+ if (childobj && !childobj -> document ) {
828
+ childobj -> document = document ;
829
+ document -> refcount ++ ;
830
+ return true;
831
+ }
832
+ return false;
833
+ }
834
+
835
+ /* TODO: on 8.4 replace the loop with the tree walk helper function. */
836
+ static void dom_set_document_pointers (xmlNodePtr node , xmlDocPtr doc , php_libxml_ref_obj * document )
837
+ {
838
+ /* Applies the document to the entire subtree. */
839
+ xmlSetTreeDoc (node , doc );
840
+
841
+ if (!dom_set_document_ref_obj_single (node , doc , document )) {
842
+ return ;
843
+ }
844
+
845
+ xmlNodePtr base = node ;
846
+ node = node -> children ;
847
+ while (node != NULL ) {
848
+ ZEND_ASSERT (node != base );
849
+
850
+ if (!dom_set_document_ref_obj_single (node , doc , document )) {
851
+ break ;
852
+ }
853
+
854
+ if (node -> type == XML_ELEMENT_NODE ) {
855
+ if (node -> children ) {
856
+ node = node -> children ;
857
+ continue ;
858
+ }
859
+ }
860
+
861
+ if (node -> next ) {
862
+ node = node -> next ;
863
+ } else {
864
+ /* Go upwards, until we find a parent node with a next sibling, or until we hit the base. */
865
+ do {
866
+ node = node -> parent ;
867
+ if (node == base ) {
868
+ return ;
869
+ }
870
+ } while (node -> next == NULL );
871
+ node = node -> next ;
872
+ }
873
+ }
874
+ }
826
875
827
- newchild = fragment -> children ;
876
+ static xmlNodePtr _php_dom_insert_fragment (xmlNodePtr nodep , xmlNodePtr prevsib , xmlNodePtr nextsib , xmlNodePtr fragment , dom_object * intern , dom_object * childobj ) /* {{{ */
877
+ {
878
+ xmlNodePtr newchild = fragment -> children ;
828
879
829
880
if (newchild ) {
830
881
if (prevsib == NULL ) {
@@ -840,17 +891,10 @@ static xmlNodePtr _php_dom_insert_fragment(xmlNodePtr nodep, xmlNodePtr prevsib,
840
891
nextsib -> prev = fragment -> last ;
841
892
}
842
893
843
- node = newchild ;
894
+ /* Assign parent node pointer */
895
+ xmlNodePtr node = newchild ;
844
896
while (node != NULL ) {
845
897
node -> parent = nodep ;
846
- if (node -> doc != nodep -> doc ) {
847
- xmlSetTreeDoc (node , nodep -> doc );
848
- if (node -> _private != NULL ) {
849
- childobj = node -> _private ;
850
- childobj -> document = intern -> document ;
851
- php_libxml_increment_doc_ref ((php_libxml_node_object * )childobj , NULL );
852
- }
853
- }
854
898
if (node == fragment -> last ) {
855
899
break ;
856
900
}
@@ -930,8 +974,7 @@ PHP_METHOD(DOMNode, insertBefore)
930
974
}
931
975
932
976
if (child -> doc == NULL && parentp -> doc != NULL ) {
933
- childobj -> document = intern -> document ;
934
- php_libxml_increment_doc_ref ((php_libxml_node_object * )childobj , NULL );
977
+ dom_set_document_pointers (child , parentp -> doc , intern -> document );
935
978
}
936
979
937
980
php_libxml_invalidate_node_list_cache (intern -> document );
@@ -949,9 +992,6 @@ PHP_METHOD(DOMNode, insertBefore)
949
992
950
993
if (child -> type == XML_TEXT_NODE && (refp -> type == XML_TEXT_NODE ||
951
994
(refp -> prev != NULL && refp -> prev -> type == XML_TEXT_NODE ))) {
952
- if (child -> doc == NULL ) {
953
- xmlSetTreeDoc (child , parentp -> doc );
954
- }
955
995
new_child = child ;
956
996
new_child -> parent = refp -> parent ;
957
997
new_child -> next = refp ;
@@ -1003,9 +1043,6 @@ PHP_METHOD(DOMNode, insertBefore)
1003
1043
}
1004
1044
if (child -> type == XML_TEXT_NODE && parentp -> last != NULL && parentp -> last -> type == XML_TEXT_NODE ) {
1005
1045
child -> parent = parentp ;
1006
- if (child -> doc == NULL ) {
1007
- xmlSetTreeDoc (child , parentp -> doc );
1008
- }
1009
1046
new_child = child ;
1010
1047
if (parentp -> children == NULL ) {
1011
1048
parentp -> children = child ;
@@ -1111,6 +1148,10 @@ PHP_METHOD(DOMNode, replaceChild)
1111
1148
RETURN_FALSE ;
1112
1149
}
1113
1150
1151
+ if (newchild -> doc == NULL && nodep -> doc != NULL ) {
1152
+ dom_set_document_pointers (newchild , nodep -> doc , intern -> document );
1153
+ }
1154
+
1114
1155
if (newchild -> type == XML_DOCUMENT_FRAG_NODE ) {
1115
1156
xmlNodePtr prevsib , nextsib ;
1116
1157
prevsib = oldchild -> prev ;
@@ -1127,11 +1168,6 @@ PHP_METHOD(DOMNode, replaceChild)
1127
1168
xmlDtdPtr intSubset = xmlGetIntSubset (nodep -> doc );
1128
1169
replacedoctype = (intSubset == (xmlDtd * ) oldchild );
1129
1170
1130
- if (newchild -> doc == NULL && nodep -> doc != NULL ) {
1131
- xmlSetTreeDoc (newchild , nodep -> doc );
1132
- newchildobj -> document = intern -> document ;
1133
- php_libxml_increment_doc_ref ((php_libxml_node_object * )newchildobj , NULL );
1134
- }
1135
1171
xmlReplaceNode (oldchild , newchild );
1136
1172
dom_reconcile_ns (nodep -> doc , newchild );
1137
1173
@@ -1216,8 +1252,7 @@ PHP_METHOD(DOMNode, appendChild)
1216
1252
}
1217
1253
1218
1254
if (child -> doc == NULL && nodep -> doc != NULL ) {
1219
- childobj -> document = intern -> document ;
1220
- php_libxml_increment_doc_ref ((php_libxml_node_object * )childobj , NULL );
1255
+ dom_set_document_pointers (child , nodep -> doc , intern -> document );
1221
1256
}
1222
1257
1223
1258
if (child -> parent != NULL ){
@@ -1226,9 +1261,6 @@ PHP_METHOD(DOMNode, appendChild)
1226
1261
1227
1262
if (child -> type == XML_TEXT_NODE && nodep -> last != NULL && nodep -> last -> type == XML_TEXT_NODE ) {
1228
1263
child -> parent = nodep ;
1229
- if (child -> doc == NULL ) {
1230
- xmlSetTreeDoc (child , nodep -> doc );
1231
- }
1232
1264
new_child = child ;
1233
1265
if (nodep -> children == NULL ) {
1234
1266
nodep -> children = child ;
0 commit comments