Commit e497ed82 authored by Michael Karcher's avatar Michael Karcher Committed by Alexandre Julliard

msxml3: Add an orphan node list to xmlDoc.

parent 0f8950d6
......@@ -39,6 +39,7 @@
#include "dispex.h"
#include "wine/debug.h"
#include "wine/list.h"
#include "msxml_private.h"
......@@ -81,10 +82,38 @@ typedef struct _domdoc
DispatchEx dispex;
} 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 {
LONG refs;
struct list orphans;
} xmldoc_priv;
typedef struct _orphan_entry {
struct list entry;
xmlNode * node;
} orphan_entry;
static inline xmldoc_priv * priv_from_xmlDocPtr(xmlDocPtr doc)
{
return doc->_private;
......@@ -96,7 +125,10 @@ static xmldoc_priv * create_priv(void)
priv = HeapAlloc( GetProcessHeap(), 0, sizeof (*priv) );
if(priv)
{
priv->refs = 0;
list_init( &priv->orphans );
}
return priv;
}
......@@ -129,7 +161,14 @@ LONG xmldoc_release(xmlDocPtr doc)
TRACE("%d\n", ref);
if(ref == 0)
{
orphan_entry *orphan, *orphan2;
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);
xmlFreeDoc(doc);
......@@ -138,6 +177,38 @@ LONG xmldoc_release(xmlDocPtr doc)
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 )
{
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_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 XMLElementCollection_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj );
......
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