msxml3: Properly update xmldoc refcounts on insertBefore().

insertBefore() is able to work on nodes from different documents, so on 
adding child or sibling it's possible that libxml2 switches doc pointer 
for a node, we need to update refcounts to cover that case.
This commit is contained in:
Nikolay Sivov 2011-03-06 22:28:29 +03:00 committed by Alexandre Julliard
parent d05435167a
commit 0f3c247e46
2 changed files with 69 additions and 4 deletions

View File

@ -295,6 +295,7 @@ HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT
xmlNodePtr new_child_node; xmlNodePtr new_child_node;
IXMLDOMNode *before = NULL; IXMLDOMNode *before = NULL;
xmlnode *node_obj; xmlnode *node_obj;
xmlDocPtr doc;
HRESULT hr; HRESULT hr;
if(!new_child) if(!new_child)
@ -336,7 +337,10 @@ HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT
/* unlink from current parent first */ /* unlink from current parent first */
if(node_obj->parent) if(node_obj->parent)
IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL); IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
doc = new_child_node->doc;
xmldoc_add_ref(before_node_obj->node->doc);
xmlAddPrevSibling(before_node_obj->node, new_child_node); xmlAddPrevSibling(before_node_obj->node, new_child_node);
xmldoc_release(doc);
node_obj->parent = This->parent; node_obj->parent = This->parent;
} }
else else
@ -344,7 +348,10 @@ HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT
/* unlink from current parent first */ /* unlink from current parent first */
if(node_obj->parent) if(node_obj->parent)
IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL); IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
doc = new_child_node->doc;
xmldoc_add_ref(This->node->doc);
xmlAddChild(This->node, new_child_node); xmlAddChild(This->node, new_child_node);
xmldoc_release(doc);
node_obj->parent = This->iface; node_obj->parent = This->iface;
} }

View File

@ -2064,6 +2064,7 @@ static void test_refs(void)
doc = create_document(&IID_IXMLDOMDocument); doc = create_document(&IID_IXMLDOMDocument);
if (!doc) return; if (!doc) return;
EXPECT_REF(doc, 1);
ref = IXMLDOMDocument_Release(doc); ref = IXMLDOMDocument_Release(doc);
ok( ref == 0, "ref %d\n", ref); ok( ref == 0, "ref %d\n", ref);
@ -2076,6 +2077,7 @@ static void test_refs(void)
ok( b == VARIANT_TRUE, "failed to load XML string\n"); ok( b == VARIANT_TRUE, "failed to load XML string\n");
SysFreeString( str ); SysFreeString( str );
EXPECT_REF(doc, 1);
IXMLDOMDocument_AddRef( doc ); IXMLDOMDocument_AddRef( doc );
EXPECT_REF(doc, 2); EXPECT_REF(doc, 2);
IXMLDOMDocument_AddRef( doc ); IXMLDOMDocument_AddRef( doc );
@ -2089,19 +2091,27 @@ static void test_refs(void)
ok( element != NULL, "should be an element\n"); ok( element != NULL, "should be an element\n");
EXPECT_REF(doc, 1); EXPECT_REF(doc, 1);
todo_wine EXPECT_REF(element, 2);
IXMLDOMElement_AddRef(element);
todo_wine EXPECT_REF(element, 3);
IXMLDOMElement_Release(element);
r = IXMLDOMElement_get_childNodes( element, &node_list ); r = IXMLDOMElement_get_childNodes( element, &node_list );
ok( r == S_OK, "rets %08x\n", r); ok( r == S_OK, "rets %08x\n", r);
todo_wine EXPECT_REF(element, 2);
EXPECT_REF(node_list, 1); EXPECT_REF(node_list, 1);
IXMLDOMNodeList_get_item( node_list, 0, &node ); IXMLDOMNodeList_get_item( node_list, 0, &node );
ok( r == S_OK, "rets %08x\n", r); ok( r == S_OK, "rets %08x\n", r);
EXPECT_REF(node_list, 1);
EXPECT_REF(node, 1);
IXMLDOMNodeList_get_item( node_list, 0, &node2 ); IXMLDOMNodeList_get_item( node_list, 0, &node2 );
ok( r == S_OK, "rets %08x\n", r); ok( r == S_OK, "rets %08x\n", r);
EXPECT_REF(node_list, 1);
EXPECT_REF(node, 1); EXPECT_REF(node2, 1);
ref = IXMLDOMNode_Release( node ); ref = IXMLDOMNode_Release( node );
ok( ref == 0, "ref %d\n", ref ); ok( ref == 0, "ref %d\n", ref );
@ -2121,18 +2131,22 @@ static void test_refs(void)
/* IUnknown must be unique however we obtain it */ /* IUnknown must be unique however we obtain it */
r = IXMLDOMElement_QueryInterface( element, &IID_IUnknown, (void**)&unk ); r = IXMLDOMElement_QueryInterface( element, &IID_IUnknown, (void**)&unk );
ok( r == S_OK, "rets %08x\n", r ); ok( r == S_OK, "rets %08x\n", r );
EXPECT_REF(element, 2);
r = IXMLDOMElement_QueryInterface( element, &IID_IXMLDOMNode, (void**)&node ); r = IXMLDOMElement_QueryInterface( element, &IID_IXMLDOMNode, (void**)&node );
ok( r == S_OK, "rets %08x\n", r ); ok( r == S_OK, "rets %08x\n", r );
todo_wine EXPECT_REF(element, 2);
r = IXMLDOMNode_QueryInterface( node, &IID_IUnknown, (void**)&unk2 ); r = IXMLDOMNode_QueryInterface( node, &IID_IUnknown, (void**)&unk2 );
ok( r == S_OK, "rets %08x\n", r ); ok( r == S_OK, "rets %08x\n", r );
todo_wine EXPECT_REF(element, 2);
ok( unk == unk2, "unk %p unk2 %p\n", unk, unk2 ); ok( unk == unk2, "unk %p unk2 %p\n", unk, unk2 );
todo_wine ok( element != (void*)node, "node %p element %p\n", node, element );
IUnknown_Release( unk2 ); IUnknown_Release( unk2 );
IUnknown_Release( unk ); IUnknown_Release( unk );
IXMLDOMNode_Release( node ); IXMLDOMNode_Release( node );
todo_wine EXPECT_REF(element, 2);
IXMLDOMElement_Release( element ); IXMLDOMElement_Release( element );
} }
static void test_create(void) static void test_create(void)
@ -2156,6 +2170,8 @@ static void test_create(void)
doc = create_document(&IID_IXMLDOMDocument); doc = create_document(&IID_IXMLDOMDocument);
if (!doc) return; if (!doc) return;
EXPECT_REF(doc, 1);
/* types not supported for creation */ /* types not supported for creation */
V_VT(&var) = VT_I1; V_VT(&var) = VT_I1;
V_I1(&var) = NODE_DOCUMENT; V_I1(&var) = NODE_DOCUMENT;
@ -2452,9 +2468,12 @@ static void test_create(void)
V_I4(&var) = NODE_ELEMENT; V_I4(&var) = NODE_ELEMENT;
r = IXMLDOMDocument_createNode( doc, var, str, NULL, &node ); r = IXMLDOMDocument_createNode( doc, var, str, NULL, &node );
ok( r == S_OK, "returns %08x\n", r ); ok( r == S_OK, "returns %08x\n", r );
EXPECT_REF(doc, 1);
r = IXMLDOMDocument_appendChild( doc, node, &root ); r = IXMLDOMDocument_appendChild( doc, node, &root );
ok( r == S_OK, "returns %08x\n", r ); ok( r == S_OK, "returns %08x\n", r );
ok( node == root, "%p %p\n", node, root ); ok( node == root, "%p %p\n", node, root );
EXPECT_REF(doc, 1);
EXPECT_REF(node, 2); EXPECT_REF(node, 2);
@ -8250,7 +8269,45 @@ static void test_insertBefore(void)
SysFreeString(p); SysFreeString(p);
IXMLDOMDocument_Release(doc); IXMLDOMDocument_Release(doc);
free_bstrs(); }
static void test_appendChild(void)
{
IXMLDOMDocument *doc, *doc2;
IXMLDOMElement *elem, *elem2;
HRESULT hr;
doc = create_document(&IID_IXMLDOMDocument);
doc2 = create_document(&IID_IXMLDOMDocument);
hr = IXMLDOMDocument_createElement(doc, _bstr_("elem"), &elem);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IXMLDOMDocument_createElement(doc2, _bstr_("elem2"), &elem2);
ok(hr == S_OK, "got 0x%08x\n", hr);
EXPECT_REF(doc, 1);
todo_wine EXPECT_REF(elem, 2);
EXPECT_REF(doc2, 1);
todo_wine EXPECT_REF(elem2, 2);
EXPECT_NO_CHILDREN(doc);
EXPECT_NO_CHILDREN(doc2);
/* append from another document */
hr = IXMLDOMDocument_appendChild(doc2, (IXMLDOMNode*)elem, NULL);
ok(hr == S_OK, "got 0x%08x\n", hr);
EXPECT_REF(doc, 1);
todo_wine EXPECT_REF(elem, 2);
EXPECT_REF(doc2, 1);
todo_wine EXPECT_REF(elem2, 2);
EXPECT_NO_CHILDREN(doc);
EXPECT_CHILDREN(doc2);
IXMLDOMElement_Release(elem);
IXMLDOMElement_Release(elem2);
IXMLDOMDocument_Release(doc);
IXMLDOMDocument_Release(doc2);
} }
START_TEST(domdoc) START_TEST(domdoc)
@ -8318,6 +8375,7 @@ START_TEST(domdoc)
test_put_nodeTypedValue(); test_put_nodeTypedValue();
test_get_xml(); test_get_xml();
test_insertBefore(); test_insertBefore();
test_appendChild();
test_xsltemplate(); test_xsltemplate();
CoUninitialize(); CoUninitialize();