Commit c868b451 authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

Ref count the xmlDocPtr.

If two nodes refer to the same xmlNodePtr don't return same object.
parent 29c2c75e
......@@ -46,6 +46,26 @@ typedef struct _domdoc
IXMLDOMNode *node;
} domdoc;
LONG xmldoc_add_ref(xmlDocPtr doc)
{
LONG ref = InterlockedIncrement((LONG*)&doc->_private);
TRACE("%ld\n", ref);
return ref;
}
LONG xmldoc_release(xmlDocPtr doc)
{
LONG ref = InterlockedDecrement((LONG*)&doc->_private);
TRACE("%ld\n", ref);
if(ref == 0)
{
TRACE("freeing docptr %p\n", doc);
xmlFreeDoc(doc);
}
return ref;
}
static inline domdoc *impl_from_IXMLDOMDocument( IXMLDOMDocument *iface )
{
return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtbl));
......
......@@ -43,6 +43,8 @@ xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type );
extern xmlChar *xmlChar_from_wchar( LPWSTR str );
extern BSTR bstr_from_xmlChar( const xmlChar *buf );
extern LONG xmldoc_add_ref( xmlDocPtr doc );
extern LONG xmldoc_release( xmlDocPtr doc );
#endif
extern IXMLDOMParseError *create_parseError( LONG code, BSTR url, BSTR reason, BSTR srcText,
......
......@@ -102,19 +102,8 @@ static ULONG WINAPI xmlnode_Release(
ref = InterlockedDecrement( &This->ref );
if ( ref == 0 )
{
if( This->node->type == XML_DOCUMENT_NODE )
{
xmlFreeDoc( (xmlDocPtr) This->node );
}
else
{
IXMLDOMNode *root;
assert( This->node->doc );
root = This->node->doc->_private;
assert( root );
IXMLDOMNode_Release( root );
This->node->_private = NULL;
}
assert( This->node->doc );
xmldoc_release( This->node->doc );
HeapFree( GetProcessHeap(), 0, This );
}
......@@ -720,40 +709,22 @@ IXMLDOMNode *create_node( xmlNodePtr node )
assert( node->doc );
/* if an interface already exists for this node, return it */
if ( node->_private )
{
IXMLDOMNode *n = node->_private;
IXMLDOMNode_AddRef( n );
return n;
}
This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
if ( !This )
return NULL;
/*
* Try adding a reference to the IXMLDOMNode implementation
* containing the document's root element.
*/
if ( node->type != XML_DOCUMENT_NODE )
if ( node->type == XML_DOCUMENT_NODE )
{
IXMLDOMNode *root = NULL;
root = node->doc->_private;
assert( root );
IXMLDOMNode_AddRef( root );
}
else
assert( node->doc == (xmlDocPtr) node );
node->doc->_private = 0;
}
This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
if ( !This )
return NULL;
xmldoc_add_ref( node->doc );
This->lpVtbl = &xmlnode_vtbl;
This->ref = 1;
This->node = node;
/* remember which interface we associated with this node */
node->_private = This;
return (IXMLDOMNode*) &This->lpVtbl;
}
......
......@@ -191,6 +191,7 @@ static ULONG WINAPI xmlnodelist_Release(
if ( ref == 0 )
{
free_xslt_info( &This->xinfo );
xmldoc_release( This->node->doc );
HeapFree( GetProcessHeap(), 0, This );
}
......@@ -374,6 +375,8 @@ static xmlnodelist *new_nodelist( xmlNodePtr node )
nodelist->current = node;
xlst_info_init( &nodelist->xinfo );
xmldoc_add_ref( node->doc );
return nodelist;
}
......
......@@ -331,6 +331,7 @@ IXMLDOMNamedNodeMap *create_nodemap( IXMLDOMNode *node )
nodemap->ref = 1;
IXMLDOMNode_AddRef( node );
/* Since we AddRef a node here, we don't need to call xmldoc_add_ref() */
return (IXMLDOMNamedNodeMap*) &nodemap->lpVtbl;
}
......
......@@ -505,6 +505,82 @@ void test_domnode( void )
IXMLDOMDocument_Release( doc );
}
static void test_refs(void)
{
HRESULT r;
BSTR str;
VARIANT_BOOL b;
IXMLDOMDocument *doc = NULL;
IXMLDOMElement *element = NULL;
IXMLDOMNode *node = NULL, *node2;
IXMLDOMNodeList *node_list = NULL;
LONG ref;
r = CoCreateInstance( &CLSID_DOMDocument, NULL,
CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc );
if( r != S_OK )
return;
str = SysAllocString( szComplete4 );
r = IXMLDOMDocument_loadXML( doc, str, &b );
ok( r == S_OK, "loadXML failed\n");
ok( b == VARIANT_TRUE, "failed to load XML string\n");
SysFreeString( str );
ref = IXMLDOMDocument_AddRef( doc );
ok( ref == 2, "ref %ld\n", ref );
ref = IXMLDOMDocument_AddRef( doc );
ok( ref == 3, "ref %ld\n", ref );
IXMLDOMDocument_Release( doc );
IXMLDOMDocument_Release( doc );
r = IXMLDOMDocument_get_documentElement( doc, &element );
ok( r == S_OK, "should be a document element\n");
ok( element != NULL, "should be an element\n");
ref = IXMLDOMDocument_AddRef( doc );
ok( ref == 2, "ref %ld\n", ref );
IXMLDOMDocument_Release( doc );
r = IXMLDOMElement_get_childNodes( element, &node_list );
ok( r == S_OK, "rets %08lx\n", r);
ref = IXMLDOMNodeList_AddRef( node_list );
ok( ref == 2, "ref %ld\n", ref );
IXMLDOMNodeList_Release( node_list );
IXMLDOMNodeList_get_item( node_list, 0, &node );
ok( r == S_OK, "rets %08lx\n", r);
IXMLDOMNodeList_get_item( node_list, 0, &node2 );
ok( r == S_OK, "rets %08lx\n", r);
ref = IXMLDOMNode_AddRef( node );
ok( ref == 2, "ref %ld\n", ref );
IXMLDOMNode_Release( node );
ref = IXMLDOMNode_Release( node );
ok( ref == 0, "ref %ld\n", ref );
ref = IXMLDOMNode_Release( node2 );
ok( ref == 0, "ref %ld\n", ref );
ref = IXMLDOMNodeList_Release( node_list );
ok( ref == 0, "ref %ld\n", ref );
ok( node != node2, "node %p node2 %p\n", node, node2 );
ref = IXMLDOMDocument_Release( doc );
ok( ref == 0, "ref %ld\n", ref );
ref = IXMLDOMElement_AddRef( element );
todo_wine {
ok( ref == 3, "ref %ld\n", ref );
}
IXMLDOMElement_Release( element );
IXMLDOMElement_Release( element );
}
START_TEST(domdoc)
{
HRESULT r;
......@@ -514,6 +590,7 @@ START_TEST(domdoc)
test_domdoc();
test_domnode();
test_refs();
CoUninitialize();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment