Nikolay Sivov : msxml3: Unescape '& ' back to '&' in attribute value.

Alexandre Julliard julliard at winehq.org
Wed Jul 31 15:31:33 CDT 2013


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

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Wed Jul 31 10:31:04 2013 +0400

msxml3: Unescape '&' back to '&' in attribute value.

---

 dlls/msxml3/saxreader.c       |   46 +++++++++++++++++++++++++++++++++++++++-
 dlls/msxml3/tests/saxreader.c |    4 +-
 2 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/dlls/msxml3/saxreader.c b/dlls/msxml3/saxreader.c
index 5a0b1c2..9362941 100644
--- a/dlls/msxml3/saxreader.c
+++ b/dlls/msxml3/saxreader.c
@@ -1265,6 +1265,49 @@ static const struct ISAXAttributesVtbl isaxattributes_vtbl =
     isaxattributes_getValueFromQName
 };
 
+/* Libxml2 escapes '&' back to char reference '&' in attribute value,
+   so when document has escaped value with '&' it's parsed to '&' and then
+   escaped to '&'. This function takes care of ampersands only. */
+static BSTR saxreader_get_unescaped_value(const xmlChar *buf, int len)
+{
+    static const WCHAR ampescW[] = {'&','#','3','8',';',0};
+    WCHAR *dest, *ptrW, *str;
+    DWORD str_len;
+    BSTR bstr;
+
+    if (!buf)
+        return NULL;
+
+    str_len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, NULL, 0);
+    if (len != -1) str_len++;
+
+    str = heap_alloc(str_len*sizeof(WCHAR));
+    if (!str) return NULL;
+
+    MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, str, str_len);
+    if (len != -1) str[str_len-1] = 0;
+
+    ptrW = str;
+    while ((dest = strstrW(ptrW, ampescW)))
+    {
+        WCHAR *src;
+
+        /* leave first '&' from a reference as a value */
+        src = dest + (sizeof(ampescW)/sizeof(WCHAR) - 1);
+        dest++;
+
+        /* move together with null terminator */
+        memmove(dest, src, (strlenW(src) + 1)*sizeof(WCHAR));
+
+        ptrW++;
+    }
+
+    bstr = SysAllocString(str);
+    heap_free(str);
+
+    return bstr;
+}
+
 static HRESULT SAXAttributes_populate(saxlocator *locator,
         int nb_namespaces, const xmlChar **xmlNamespaces,
         int nb_attributes, const xmlChar **xmlAttributes)
@@ -1317,8 +1360,7 @@ static HRESULT SAXAttributes_populate(saxlocator *locator,
             attrs[i].szURI = find_element_uri(locator, xmlAttributes[i*5+2]);
 
         attrs[i].szLocalname = bstr_from_xmlChar(xmlAttributes[i*5]);
-        attrs[i].szValue = bstr_from_xmlCharN(xmlAttributes[i*5+3],
-                xmlAttributes[i*5+4]-xmlAttributes[i*5+3]);
+        attrs[i].szValue = saxreader_get_unescaped_value(xmlAttributes[i*5+3], xmlAttributes[i*5+4]-xmlAttributes[i*5+3]);
         attrs[i].szQName = QName_from_xmlChar(xmlAttributes[i*5+1],
                 xmlAttributes[i*5]);
     }
diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c
index 5c7d080..a6c399d 100644
--- a/dlls/msxml3/tests/saxreader.c
+++ b/dlls/msxml3/tests/saxreader.c
@@ -888,10 +888,10 @@ static struct call_entry xmlspaceattr_test_alternate[] = {
 /* attribute value normalization test */
 static const char attribute_normalize[] =
     "<?xml version=\"1.0\" ?>\n"
-    "<a attr1=\" \r \n \tattr_value A \t \r \n\r\n \n\"/>\n";
+    "<a attr1=\" \r \n \tattr_value A & &\t \r \n\r\n \n\"/>\n";
 
 static struct attribute_entry attribute_norm_attrs[] = {
-    { "", "attr1", "attr1", "      attr_value A         " },
+    { "", "attr1", "attr1", "      attr_value A & &        " },
     { NULL }
 };
 




More information about the wine-cvs mailing list