Module: wine Branch: master Commit: e497ed823ef9f7e7da80afa6023e974dfa134037 URL: http://source.winehq.org/git/wine.git/?a=commit;h=e497ed823ef9f7e7da80afa602...
Author: Michael Karcher wine@mkarcher.dialup.fu-berlin.de Date: Sat Oct 11 23:59:19 2008 +0200
msxml3: Add an orphan node list to xmlDoc.
---
dlls/msxml3/domdoc.c | 71 +++++++++++++++++++++++++++++++++++++++++++ dlls/msxml3/msxml_private.h | 2 + 2 files changed, 73 insertions(+), 0 deletions(-)
diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index 77ad06f..93795d3 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -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)); diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index b342742..45d68cf 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -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 );