msxml3: Add an orphan node list to xmlDoc.
This commit is contained in:
parent
0f8950d646
commit
e497ed823e
@ -39,6 +39,7 @@
|
|||||||
#include "dispex.h"
|
#include "dispex.h"
|
||||||
|
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
#include "wine/list.h"
|
||||||
|
|
||||||
#include "msxml_private.h"
|
#include "msxml_private.h"
|
||||||
|
|
||||||
@ -81,10 +82,38 @@ typedef struct _domdoc
|
|||||||
DispatchEx dispex;
|
DispatchEx dispex;
|
||||||
} domdoc;
|
} domdoc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
In native windows, the whole lifetime management of XMLDOMNodes is
|
||||||
|
managed automatically using reference counts. Wine emulates that by
|
||||||
|
maintaining a reference count to the document that is increased for
|
||||||
|
each IXMLDOMNode pointer passed out for this document. If all these
|
||||||
|
pointers are gone, the document is unreachable and gets freed, that
|
||||||
|
is, all nodes in the tree of the document get freed.
|
||||||
|
|
||||||
|
You are able to create nodes that are associated to a document (in
|
||||||
|
fact, in msxml's XMLDOM model, all nodes are associated to a document),
|
||||||
|
but not in the tree of that document, for example using the createFoo
|
||||||
|
functions from IXMLDOMDocument. These nodes do not get cleaned up
|
||||||
|
by libxml, so we have to do it ourselves.
|
||||||
|
|
||||||
|
To catch these nodes, a list of "orphan nodes" is introduced.
|
||||||
|
It contains pointers to all roots of node trees that are
|
||||||
|
associated with the document without being part of the document
|
||||||
|
tree. All nodes with parent==NULL (except for the document root nodes)
|
||||||
|
should be in the orphan node list of their document. All orphan nodes
|
||||||
|
get freed together with the document itself.
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct _xmldoc_priv {
|
typedef struct _xmldoc_priv {
|
||||||
LONG refs;
|
LONG refs;
|
||||||
|
struct list orphans;
|
||||||
} xmldoc_priv;
|
} xmldoc_priv;
|
||||||
|
|
||||||
|
typedef struct _orphan_entry {
|
||||||
|
struct list entry;
|
||||||
|
xmlNode * node;
|
||||||
|
} orphan_entry;
|
||||||
|
|
||||||
static inline xmldoc_priv * priv_from_xmlDocPtr(xmlDocPtr doc)
|
static inline xmldoc_priv * priv_from_xmlDocPtr(xmlDocPtr doc)
|
||||||
{
|
{
|
||||||
return doc->_private;
|
return doc->_private;
|
||||||
@ -96,7 +125,10 @@ static xmldoc_priv * create_priv(void)
|
|||||||
priv = HeapAlloc( GetProcessHeap(), 0, sizeof (*priv) );
|
priv = HeapAlloc( GetProcessHeap(), 0, sizeof (*priv) );
|
||||||
|
|
||||||
if(priv)
|
if(priv)
|
||||||
|
{
|
||||||
priv->refs = 0;
|
priv->refs = 0;
|
||||||
|
list_init( &priv->orphans );
|
||||||
|
}
|
||||||
|
|
||||||
return priv;
|
return priv;
|
||||||
}
|
}
|
||||||
@ -129,7 +161,14 @@ LONG xmldoc_release(xmlDocPtr doc)
|
|||||||
TRACE("%d\n", ref);
|
TRACE("%d\n", ref);
|
||||||
if(ref == 0)
|
if(ref == 0)
|
||||||
{
|
{
|
||||||
|
orphan_entry *orphan, *orphan2;
|
||||||
TRACE("freeing docptr %p\n", doc);
|
TRACE("freeing docptr %p\n", doc);
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
|
||||||
|
{
|
||||||
|
xmlFreeNode( orphan->node );
|
||||||
|
HeapFree( GetProcessHeap(), 0, orphan );
|
||||||
|
}
|
||||||
HeapFree(GetProcessHeap(), 0, doc->_private);
|
HeapFree(GetProcessHeap(), 0, doc->_private);
|
||||||
|
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
@ -138,6 +177,38 @@ LONG xmldoc_release(xmlDocPtr doc)
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
|
||||||
|
{
|
||||||
|
xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
|
||||||
|
orphan_entry *entry;
|
||||||
|
|
||||||
|
entry = HeapAlloc( GetProcessHeap(), 0, sizeof (*entry) );
|
||||||
|
if(!entry)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
entry->node = node;
|
||||||
|
list_add_head( &priv->orphans, &entry->entry );
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
|
||||||
|
{
|
||||||
|
xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
|
||||||
|
orphan_entry *entry, *entry2;
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
|
||||||
|
{
|
||||||
|
if( entry->node == node )
|
||||||
|
{
|
||||||
|
list_remove( &entry->entry );
|
||||||
|
HeapFree( GetProcessHeap(), 0, entry );
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static inline domdoc *impl_from_IXMLDOMDocument2( IXMLDOMDocument2 *iface )
|
static inline domdoc *impl_from_IXMLDOMDocument2( IXMLDOMDocument2 *iface )
|
||||||
{
|
{
|
||||||
return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtbl));
|
return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtbl));
|
||||||
|
@ -65,6 +65,8 @@ extern BSTR bstr_from_xmlChar( const xmlChar *buf );
|
|||||||
|
|
||||||
extern LONG xmldoc_add_ref( xmlDocPtr doc );
|
extern LONG xmldoc_add_ref( xmlDocPtr doc );
|
||||||
extern LONG xmldoc_release( xmlDocPtr doc );
|
extern LONG xmldoc_release( xmlDocPtr doc );
|
||||||
|
extern HRESULT xmldoc_add_orphan( xmlDocPtr doc, xmlNodePtr node );
|
||||||
|
extern HRESULT xmldoc_remove_orphan( xmlDocPtr doc, xmlNodePtr node );
|
||||||
|
|
||||||
extern HRESULT XMLElement_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj );
|
extern HRESULT XMLElement_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj );
|
||||||
extern HRESULT XMLElementCollection_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj );
|
extern HRESULT XMLElementCollection_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user