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;
|
IXMLDOMNode *node;
|
||||||
} domdoc;
|
} 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 )
|
static inline domdoc *impl_from_IXMLDOMDocument( IXMLDOMDocument *iface )
|
||||||
{
|
{
|
||||||
return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtbl));
|
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 xmlChar *xmlChar_from_wchar( LPWSTR str );
|
||||||
extern BSTR bstr_from_xmlChar( const xmlChar *buf );
|
extern BSTR bstr_from_xmlChar( const xmlChar *buf );
|
||||||
|
|
||||||
|
extern LONG xmldoc_add_ref( xmlDocPtr doc );
|
||||||
|
extern LONG xmldoc_release( xmlDocPtr doc );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern IXMLDOMParseError *create_parseError( LONG code, BSTR url, BSTR reason, BSTR srcText,
|
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 );
|
ref = InterlockedDecrement( &This->ref );
|
||||||
if ( ref == 0 )
|
if ( ref == 0 )
|
||||||
{
|
{
|
||||||
if( This->node->type == XML_DOCUMENT_NODE )
|
|
||||||
{
|
|
||||||
xmlFreeDoc( (xmlDocPtr) This->node );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IXMLDOMNode *root;
|
|
||||||
assert( This->node->doc );
|
assert( This->node->doc );
|
||||||
root = This->node->doc->_private;
|
xmldoc_release( This->node->doc );
|
||||||
assert( root );
|
|
||||||
IXMLDOMNode_Release( root );
|
|
||||||
This->node->_private = NULL;
|
|
||||||
}
|
|
||||||
HeapFree( GetProcessHeap(), 0, This );
|
HeapFree( GetProcessHeap(), 0, This );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,40 +709,22 @@ IXMLDOMNode *create_node( xmlNodePtr node )
|
||||||
|
|
||||||
assert( node->doc );
|
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 );
|
This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
|
||||||
if ( !This )
|
if ( !This )
|
||||||
return NULL;
|
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->lpVtbl = &xmlnode_vtbl;
|
||||||
This->ref = 1;
|
This->ref = 1;
|
||||||
This->node = node;
|
This->node = node;
|
||||||
|
|
||||||
/* remember which interface we associated with this node */
|
|
||||||
node->_private = This;
|
|
||||||
|
|
||||||
return (IXMLDOMNode*) &This->lpVtbl;
|
return (IXMLDOMNode*) &This->lpVtbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -191,6 +191,7 @@ static ULONG WINAPI xmlnodelist_Release(
|
||||||
if ( ref == 0 )
|
if ( ref == 0 )
|
||||||
{
|
{
|
||||||
free_xslt_info( &This->xinfo );
|
free_xslt_info( &This->xinfo );
|
||||||
|
xmldoc_release( This->node->doc );
|
||||||
HeapFree( GetProcessHeap(), 0, This );
|
HeapFree( GetProcessHeap(), 0, This );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,6 +375,8 @@ static xmlnodelist *new_nodelist( xmlNodePtr node )
|
||||||
nodelist->current = node;
|
nodelist->current = node;
|
||||||
xlst_info_init( &nodelist->xinfo );
|
xlst_info_init( &nodelist->xinfo );
|
||||||
|
|
||||||
|
xmldoc_add_ref( node->doc );
|
||||||
|
|
||||||
return nodelist;
|
return nodelist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -331,6 +331,7 @@ IXMLDOMNamedNodeMap *create_nodemap( IXMLDOMNode *node )
|
||||||
nodemap->ref = 1;
|
nodemap->ref = 1;
|
||||||
|
|
||||||
IXMLDOMNode_AddRef( node );
|
IXMLDOMNode_AddRef( node );
|
||||||
|
/* Since we AddRef a node here, we don't need to call xmldoc_add_ref() */
|
||||||
|
|
||||||
return (IXMLDOMNamedNodeMap*) &nodemap->lpVtbl;
|
return (IXMLDOMNamedNodeMap*) &nodemap->lpVtbl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -505,6 +505,82 @@ void test_domnode( void )
|
||||||
IXMLDOMDocument_Release( doc );
|
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)
|
START_TEST(domdoc)
|
||||||
{
|
{
|
||||||
HRESULT r;
|
HRESULT r;
|
||||||
|
@ -514,6 +590,7 @@ START_TEST(domdoc)
|
||||||
|
|
||||||
test_domdoc();
|
test_domdoc();
|
||||||
test_domnode();
|
test_domnode();
|
||||||
|
test_refs();
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue