Module: wine Branch: master Commit: b1bf9a62f94f6a6103eba0405ed693d4f8f6a39f URL: http://source.winehq.org/git/wine.git/?a=commit;h=b1bf9a62f94f6a6103eba0405e...
Author: Nikolay Sivov nsivov@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 } };