Michael Karcher : msxml3: Add an orphan node list to xmlDoc.

Alexandre Julliard julliard at winehq.org
Mon Oct 13 06:39:03 CDT 2008


Module: wine
Branch: master
Commit: e497ed823ef9f7e7da80afa6023e974dfa134037
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=e497ed823ef9f7e7da80afa6023e974dfa134037

Author: Michael Karcher <wine at 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 );




More information about the wine-cvs mailing list