Ref count the xmlDocPtr.
If two nodes refer to the same xmlNodePtr don't return same object.
This commit is contained in:
parent
29c2c75e04
commit
c868b45113
|
@ -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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue