Nikolay Sivov : msxml3: Create additional node for xml declaration.

Alexandre Julliard julliard at winehq.org
Mon Jun 28 11:01:20 CDT 2010


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

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Mon Jun 28 12:17:56 2010 +0400

msxml3: Create additional node for xml declaration.

---

 dlls/msxml3/domdoc.c        |   71 ++++++++++++++++++++++++++++++++++++++++---
 dlls/msxml3/msxml_private.h |    2 +
 dlls/msxml3/node.c          |    5 +++
 dlls/msxml3/tests/domdoc.c  |   49 ++++++++++++++++++++++--------
 4 files changed, 109 insertions(+), 18 deletions(-)

diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c
index 54e4728..cec59e8 100644
--- a/dlls/msxml3/domdoc.c
+++ b/dlls/msxml3/domdoc.c
@@ -141,18 +141,75 @@ static xmldoc_priv * create_priv(void)
     return priv;
 }
 
+/* links a "<?xml" node as a first child */
+void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
+{
+    assert(doc != NULL);
+    if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
+}
+
+/* unlinks a first "<?xml" child if it was created */
+xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
+{
+    xmlNodePtr node;
+
+    assert(doc != NULL);
+
+    if (doc->standalone != -1)
+    {
+        node = doc->children;
+        xmlUnlinkNode( node );
+    }
+    else
+        node = NULL;
+
+    return node;
+}
+
 static xmlDocPtr doparse( char *ptr, int len, const char *encoding )
 {
+    xmlDocPtr doc;
+
 #ifdef HAVE_XMLREADMEMORY
     /*
      * use xmlReadMemory if possible so we can suppress
      * writing errors to stderr
      */
-    return xmlReadMemory( ptr, len, NULL, encoding,
-                          XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS );
+    doc = xmlReadMemory( ptr, len, NULL, encoding,
+                           XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS );
 #else
-    return xmlParseMemory( ptr, len );
+    doc = xmlParseMemory( ptr, len );
 #endif
+
+    /* create first child as a <?xml...?> */
+    if (doc && doc->standalone != -1)
+    {
+        xmlNodePtr node;
+        char buff[30];
+        xmlChar *xmlbuff = (xmlChar*)buff;
+
+        node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
+
+        /* version attribute can't be omitted */
+        sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
+        xmlNodeAddContent( node, xmlbuff );
+
+        if (doc->encoding)
+        {
+            sprintf(buff, " encoding=\"%s\"", doc->encoding);
+            xmlNodeAddContent( node, xmlbuff );
+        }
+
+        if (doc->standalone != -2)
+        {
+            sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
+            xmlNodeAddContent( node, xmlbuff );
+        }
+
+        xmldoc_link_xmldecl( doc, node );
+    }
+
+    return doc;
 }
 
 LONG xmldoc_add_ref(xmlDocPtr doc)
@@ -345,7 +402,7 @@ static HRESULT WINAPI xmldoc_IPersistStream_Load(
     len = GlobalSize(hglobal);
     ptr = GlobalLock(hglobal);
     if (len != 0)
-        xmldoc = parse_xml(ptr, len);
+        xmldoc = doparse(ptr, len, NULL);
     GlobalUnlock(hglobal);
 
     if (!xmldoc)
@@ -1524,7 +1581,7 @@ static HRESULT WINAPI domdoc_load(
                 {
                     *isSuccessful = VARIANT_TRUE;
 
-                    TRACE("Using ID_IStream to load Document\n");
+                    TRACE("Using IStream to load Document\n");
                     return S_OK;
                 }
                 else
@@ -1733,6 +1790,7 @@ static HRESULT WINAPI domdoc_save(
     domdoc *This = impl_from_IXMLDOMDocument2( iface );
     HANDLE handle;
     xmlSaveCtxtPtr ctx;
+    xmlNodePtr xmldecl;
     HRESULT ret = S_OK;
 
     TRACE("(%p)->(var(vt %d, %s))\n", This, V_VT(&destination),
@@ -1788,7 +1846,10 @@ static HRESULT WINAPI domdoc_save(
         return S_FALSE;
     }
 
+    xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
+    xmldoc_link_xmldecl(get_doc(This), xmldecl);
+
     /* will close file through close callback */
     xmlSaveClose(ctx);
 
diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h
index 1df3e8b..e0279f1 100644
--- a/dlls/msxml3/msxml_private.h
+++ b/dlls/msxml3/msxml_private.h
@@ -134,6 +134,8 @@ 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 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node);
+extern xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc);
 
 extern HRESULT XMLElement_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj, BOOL own );
 
diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c
index 135844f..bbdcb5d 100644
--- a/dlls/msxml3/node.c
+++ b/dlls/msxml3/node.c
@@ -1382,6 +1382,7 @@ static HRESULT WINAPI xmlnode_get_xml(
 {
     xmlnode *This = impl_from_IXMLDOMNode( iface );
     xmlBufferPtr pXmlBuf;
+    xmlNodePtr xmldecl;
     int nSize;
 
     TRACE("(%p %d)->(%p)\n", This, This->node->type, xmlString);
@@ -1391,6 +1392,8 @@ static HRESULT WINAPI xmlnode_get_xml(
 
     *xmlString = NULL;
 
+    xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
+
     pXmlBuf = xmlBufferCreate();
     if(pXmlBuf)
     {
@@ -1424,6 +1427,8 @@ static HRESULT WINAPI xmlnode_get_xml(
         xmlBufferFree(pXmlBuf);
     }
 
+    xmldoc_link_xmldecl( This->node->doc, xmldecl );
+
     /* Always returns a string. */
     if(*xmlString == NULL)  *xmlString = SysAllocStringLen( NULL, 0 );
 
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index 9c1440c..cde4c81 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -470,20 +470,8 @@ static void node_to_string(IXMLDOMNode *node, char *buf)
         }
         else
         {
-            int pos = get_node_position(node);
-            DOMNodeType parent_type = NODE_INVALID;
             r = IXMLDOMNode_get_parentNode(node, &new_node);
-
-            /* currently wine doesn't create a node for the <?xml ... ?>. To be able to test query
-             * results we "fix" it */
-            if (r == S_OK)
-                ole_check(IXMLDOMNode_get_nodeType(new_node, &parent_type));
-            if ((parent_type == NODE_DOCUMENT) && type != NODE_PROCESSING_INSTRUCTION && pos==1)
-            {
-                todo_wine ok(FALSE, "The first child of the document node in MSXML is the <?xml ... ?> processing instruction\n");
-                pos++;
-            }
-            wsprintf(buf, "%d", pos);
+            wsprintf(buf, "%d", get_node_position(node));
             buf += strlen(buf);
         }
 
@@ -2477,6 +2465,40 @@ static void test_get_childNodes(void)
     IXMLDOMDocument_Release( doc );
 }
 
+static void test_get_firstChild(void)
+{
+    static WCHAR xmlW[] = {'x','m','l',0};
+    IXMLDOMDocument *doc;
+    IXMLDOMNode *node;
+    VARIANT_BOOL b;
+    HRESULT r;
+    BSTR str;
+
+    r = CoCreateInstance( &CLSID_DOMDocument, NULL,
+        CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void**)&doc );
+    ok( r == S_OK, "failed with 0x%08x\n", r );
+    if( r != S_OK )
+        return;
+
+    str = SysAllocString( szComplete4 );
+    r = IXMLDOMDocument_loadXML( doc, str, &b );
+    ok( r == S_OK, "loadXML failed\n");
+    ok( b == VARIANT_TRUE, "failed to load XML string\n");
+    SysFreeString( str );
+
+    r = IXMLDOMDocument_get_firstChild( doc, &node );
+    ok( r == S_OK, "ret %08x\n", r);
+
+    r = IXMLDOMNode_get_nodeName( node, &str );
+    ok( r == S_OK, "ret %08x\n", r);
+
+    ok(memcmp(str, xmlW, sizeof(xmlW)) == 0, "expected \"xml\" node name\n");
+
+    SysFreeString(str);
+    IXMLDOMNode_Release( node );
+    IXMLDOMDocument_Release( doc );
+}
+
 static void test_removeChild(void)
 {
     HRESULT r;
@@ -5581,6 +5603,7 @@ START_TEST(domdoc)
         test_getElementsByTagName();
         test_get_text();
         test_get_childNodes();
+        test_get_firstChild();
         test_removeChild();
         test_replaceChild();
         test_removeNamedItem();




More information about the wine-cvs mailing list