[PATCH v4 1/3] msxml3: Implement ::get_attributes() for "xml" processing instruction node.

Dmitry Timoshkov dmitry at baikal.ru
Thu May 20 01:50:10 CDT 2021


v4: Create special XML_ELEMENT_NODE for PI node attributes to avoid
hitting a libxml2 limitation and manual properties management.

Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
---
 dlls/msxml3/nodemap.c |   4 +-
 dlls/msxml3/pi.c      | 114 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/dlls/msxml3/nodemap.c b/dlls/msxml3/nodemap.c
index 5ea083c4495..856f407654a 100644
--- a/dlls/msxml3/nodemap.c
+++ b/dlls/msxml3/nodemap.c
@@ -141,7 +141,7 @@ static ULONG WINAPI xmlnodemap_Release(
     if ( ref == 0 )
     {
         xmlnode_release( This->node );
-        xmldoc_release( This->node->doc );
+        if (This->node->doc) xmldoc_release( This->node->doc );
         if (This->enumvariant) IEnumVARIANT_Release(This->enumvariant);
         heap_free( This );
     }
@@ -452,7 +452,7 @@ IXMLDOMNamedNodeMap *create_nodemap(xmlNodePtr node, const struct nodemap_funcs
     init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMNamedNodeMap_iface, &xmlnodemap_dispex);
 
     xmlnode_add_ref(node);
-    xmldoc_add_ref(node->doc);
+    if (node->doc) xmldoc_add_ref(node->doc);
 
     return &This->IXMLDOMNamedNodeMap_iface;
 }
diff --git a/dlls/msxml3/pi.c b/dlls/msxml3/pi.c
index cea95708087..6bacff12027 100644
--- a/dlls/msxml3/pi.c
+++ b/dlls/msxml3/pi.c
@@ -34,6 +34,7 @@
 #include "ole2.h"
 #include "msxml6.h"
 
+#include "xmlparser.h"
 #include "msxml_private.h"
 
 #include "wine/debug.h"
@@ -45,6 +46,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml);
 typedef struct _dom_pi
 {
     xmlnode node;
+    xmlNodePtr attributes;
     IXMLDOMProcessingInstruction IXMLDOMProcessingInstruction_iface;
     LONG ref;
 } dom_pi;
@@ -114,6 +116,7 @@ static ULONG WINAPI dom_pi_Release(
     TRACE("(%p)->(%d)\n", This, ref);
     if ( ref == 0 )
     {
+        xmlFreeNode(This->attributes);
         destroy_xmlnode(&This->node);
         heap_free( This );
     }
@@ -287,6 +290,107 @@ static HRESULT WINAPI dom_pi_get_nextSibling(
     return node_get_next_sibling(&This->node, domNode);
 }
 
+static HRESULT xml_get_value(xmlChar **p, xmlChar **value)
+{
+    xmlChar *v;
+    int len;
+
+    while (isspace(**p)) *p += 1;
+    if (**p != '=') return XML_E_MISSINGEQUALS;
+    *p += 1;
+
+    while (isspace(**p)) *p += 1;
+    if (**p != '"') return XML_E_MISSINGQUOTE;
+    *p += 1;
+
+    v = *p;
+    while (**p && **p != '"') *p += 1;
+    if (!**p) return XML_E_EXPECTINGCLOSEQUOTE;
+    len = *p - v;
+    if (!len) return XML_E_MISSINGNAME;
+    *p += 1;
+
+    *value = heap_alloc(len + 1);
+    if (!*value) return E_OUTOFMEMORY;
+    memcpy(*value, v, len);
+    *(*value + len) = 0;
+
+    return S_OK;
+}
+
+static HRESULT parse_xml_decl(dom_pi *This)
+{
+    xmlChar *version, *encoding, *standalone, *p;
+    xmlAttrPtr attr;
+    HRESULT hr = S_OK;
+
+    if (!This->node.node->content || This->attributes->properties)
+        return S_OK;
+
+    version = encoding = standalone = NULL;
+
+    p = This->node.node->content;
+
+    while (*p)
+    {
+        while (isspace(*p)) p++;
+        if (!*p) break;
+
+        if (!strncmp((const char *)p, "version", 7))
+        {
+            p += 7;
+            if ((hr = xml_get_value(&p, &version)) != S_OK) goto fail;
+        }
+        else if (!strncmp((const char *)p, "encoding", 8))
+        {
+            p += 8;
+            if ((hr = xml_get_value(&p, &encoding)) != S_OK) goto fail;
+        }
+        else if (!strncmp((const char *)p, "standalone", 10))
+        {
+            p += 10;
+            if ((hr = xml_get_value(&p, &standalone)) != S_OK) goto fail;
+        }
+        else
+        {
+            FIXME("unexpected XML attribute %s\n", debugstr_a((const char *)p));
+            hr = XML_E_UNEXPECTED_ATTRIBUTE;
+            goto fail;
+        }
+    }
+
+    if (version)
+    {
+        attr = xmlSetNsProp(This->attributes, NULL, (const xmlChar *)"version", version);
+        if (!attr)
+            hr = E_OUTOFMEMORY;
+    }
+    if (encoding)
+    {
+        attr = xmlSetNsProp(This->attributes, NULL, (const xmlChar *)"encoding", encoding);
+        if (!attr)
+            hr = E_OUTOFMEMORY;
+    }
+    if (standalone)
+    {
+        attr = xmlSetNsProp(This->attributes, NULL, (const xmlChar *)"standalone", standalone);
+        if (!attr)
+            hr = E_OUTOFMEMORY;
+    }
+
+fail:
+    if (hr != S_OK)
+    {
+        xmlFreePropList(This->attributes->properties);
+        This->attributes->properties = NULL;
+    }
+
+    heap_free(version);
+    heap_free(encoding);
+    heap_free(standalone);
+    return hr;
+}
+
 static HRESULT WINAPI dom_pi_get_attributes(
     IXMLDOMProcessingInstruction *iface,
     IXMLDOMNamedNodeMap** map)
@@ -307,8 +411,10 @@ static HRESULT WINAPI dom_pi_get_attributes(
 
     if (!strcmpW(name, xmlW))
     {
-        FIXME("created dummy map for <?xml ?>\n");
-        *map = create_nodemap(This->node.node, &dom_pi_attr_map);
+        hr = parse_xml_decl(This);
+        if (hr != S_OK) return S_FALSE;
+
+        *map = create_nodemap(This->attributes, &dom_pi_attr_map);
         SysFreeString(name);
         return S_OK;
     }
@@ -761,6 +867,10 @@ IUnknown* create_pi( xmlNodePtr pi )
 
     This->IXMLDOMProcessingInstruction_iface.lpVtbl = &dom_pi_vtbl;
     This->ref = 1;
+    /* xmlSetProp/xmlSetNsProp accept only nodes of type XML_ELEMENT_NODE,
+     * so we have to create special node for attributes.
+     */
+    This->attributes = xmlNewNode(NULL, (const xmlChar *)"attributes");
 
     init_xmlnode(&This->node, pi, (IXMLDOMNode*)&This->IXMLDOMProcessingInstruction_iface, &dompi_dispex);
 
-- 
2.31.1




More information about the wine-devel mailing list