Ref count the xmlDocPtr.

If two nodes refer to the same xmlNodePtr don't return same object.
This commit is contained in:
Huw Davies 2005-11-18 15:05:26 +00:00 committed by Alexandre Julliard
parent 29c2c75e04
commit c868b45113
6 changed files with 113 additions and 39 deletions

View File

@ -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));

View File

@ -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,

View File

@ -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;
}
/*
* Try adding a reference to the IXMLDOMNode implementation
* containing the document's root element.
*/
if ( node->type != XML_DOCUMENT_NODE )
{
IXMLDOMNode *root = NULL;
root = node->doc->_private;
assert( root );
IXMLDOMNode_AddRef( root );
}
else
assert( node->doc == (xmlDocPtr) node );
This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
if ( !This )
return NULL;
if ( node->type == XML_DOCUMENT_NODE )
{
assert( node->doc == (xmlDocPtr) node );
node->doc->_private = 0;
}
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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}