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