Nikolay Sivov : msxml3: Escape '<', '&', '"' and '>' in attribute value.
Alexandre Julliard
julliard at winehq.org
Mon Dec 12 12:25:52 CST 2011
Module: wine
Branch: master
Commit: d80ee5b3ae36275f813b096576b5beecea2c2d60
URL: http://source.winehq.org/git/wine.git/?a=commit;h=d80ee5b3ae36275f813b096576b5beecea2c2d60
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Sun Dec 11 02:32:51 2011 +0300
msxml3: Escape '<','&','"' and '>' in attribute value.
---
dlls/msxml3/mxwriter.c | 72 +++++++++++++++++++++++++++++++++++++++-
dlls/msxml3/tests/saxreader.c | 58 +++++++++++++++++---------------
2 files changed, 101 insertions(+), 29 deletions(-)
diff --git a/dlls/msxml3/mxwriter.c b/dlls/msxml3/mxwriter.c
index febabe1..5c5aca8 100644
--- a/dlls/msxml3/mxwriter.c
+++ b/dlls/msxml3/mxwriter.c
@@ -57,7 +57,7 @@ typedef enum
MXWriter_LastProp
} MXWRITER_PROPS;
-typedef struct _mxwriter
+typedef struct
{
DispatchEx dispex;
IMXWriter IMXWriter_iface;
@@ -106,6 +106,71 @@ static HRESULT bstr_from_xmlCharEncoding(xmlCharEncoding enc, BSTR *encoding)
return *encoding ? S_OK : E_OUTOFMEMORY;
}
+/* escapes special characters like:
+ '<' -> "<"
+ '&' -> "&"
+ '"' -> """
+ '>' -> ">"
+*/
+static WCHAR *get_escaped_string(const WCHAR *str, int *len)
+{
+ static const WCHAR ltW[] = {'&','l','t',';'};
+ static const WCHAR ampW[] = {'&','a','m','p',';'};
+ static const WCHAR quotW[] = {'&','q','u','o','t',';'};
+ static const WCHAR gtW[] = {'&','g','t',';'};
+
+ const int default_alloc = 100;
+ const int grow_thresh = 10;
+ int p = *len, conv_len;
+ WCHAR *ptr, *ret;
+
+ /* default buffer size to something if length is unknown */
+ conv_len = *len == -1 ? default_alloc : max(2**len, default_alloc);
+ ptr = ret = heap_alloc(conv_len*sizeof(WCHAR));
+
+ while (*str && p)
+ {
+ if (ptr - ret > conv_len - grow_thresh)
+ {
+ int written = ptr - ret;
+ conv_len *= 2;
+ ptr = ret = heap_realloc(ret, conv_len*sizeof(WCHAR));
+ ptr += written;
+ }
+
+ switch (*str)
+ {
+ case '<':
+ memcpy(ptr, ltW, sizeof(ltW));
+ ptr += sizeof(ltW)/sizeof(WCHAR);
+ break;
+ case '&':
+ memcpy(ptr, ampW, sizeof(ampW));
+ ptr += sizeof(ampW)/sizeof(WCHAR);
+ break;
+ case '"':
+ memcpy(ptr, quotW, sizeof(quotW));
+ ptr += sizeof(quotW)/sizeof(WCHAR);
+ break;
+ case '>':
+ memcpy(ptr, gtW, sizeof(gtW));
+ ptr += sizeof(gtW)/sizeof(WCHAR);
+ break;
+ default:
+ *ptr++ = *str;
+ break;
+ }
+
+ str++;
+ if (*len != -1) p--;
+ }
+
+ if (*len != -1) *len = ptr-ret;
+ *++ptr = 0;
+
+ return ret;
+}
+
/* creates UTF-8 encoded prolog string with specified or store encoding value */
static int write_prolog_buffer(const mxwriter *This, xmlCharEncoding enc, xmlOutputBufferPtr buffer)
{
@@ -824,6 +889,7 @@ static HRESULT WINAPI mxwriter_saxcontent_startElement(
for (i = 0; i < length; i++)
{
const WCHAR *str;
+ WCHAR *escaped;
INT len = 0;
hr = ISAXAttributes_getQName(attr, i, &str, &len);
@@ -842,8 +908,10 @@ static HRESULT WINAPI mxwriter_saxcontent_startElement(
hr = ISAXAttributes_getValue(attr, i, &str, &len);
if (FAILED(hr)) return hr;
- s = xmlchar_from_wcharn(str, len);
+ escaped = get_escaped_string(str, &len);
+ s = xmlchar_from_wcharn(escaped, len);
write_output_buffer_str(This, (char*)s);
+ heap_free(escaped);
heap_free(s);
write_output_buffer(This, "\"", 1);
diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c
index d713fd3..7b3feea 100644
--- a/dlls/msxml3/tests/saxreader.c
+++ b/dlls/msxml3/tests/saxreader.c
@@ -737,7 +737,7 @@ static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
{
- *length = 2;
+ *length = 3;
return S_OK;
}
@@ -763,17 +763,19 @@ static HRESULT WINAPI isaxattributes_getLocalName(
static HRESULT WINAPI isaxattributes_getQName(
ISAXAttributes* iface,
- int nIndex,
- const WCHAR **pQName,
- int *pQNameLength)
+ int index,
+ const WCHAR **QName,
+ int *QNameLength)
{
- static const WCHAR attr1W[] = {'a',':','a','t','t','r','1','j','u','n','k',0};
- static const WCHAR attr2W[] = {'a','t','t','r','2','j','u','n','k',0};
+ static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
+ {'a','t','t','r','2','j','u','n','k',0},
+ {'a','t','t','r','3',0}};
+ static const int attrqnamelen[] = {7, 5, 5};
- ok(nIndex == 0 || nIndex == 1, "invalid index received %d\n", nIndex);
+ ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
- *pQName = (nIndex == 0) ? attr1W : attr2W;
- *pQNameLength = (nIndex == 0) ? 7 : 5;
+ *QName = attrqnamesW[index];
+ *QNameLength = attrqnamelen[index];
return S_OK;
}
@@ -848,19 +850,18 @@ static HRESULT WINAPI isaxattributes_getTypeFromQName(
return E_NOTIMPL;
}
-static HRESULT WINAPI isaxattributes_getValue(
- ISAXAttributes* iface,
- int nIndex,
- const WCHAR ** pValue,
- int * nValue)
+static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
+ const WCHAR **value, int *nValue)
{
- static const WCHAR attrval1W[] = {'a','1','j','u','n','k',0};
- static const WCHAR attrval2W[] = {'a','2','j','u','n','k',0};
+ static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
+ {'a','2','j','u','n','k',0},
+ {'<','&','"','>',0}};
+ static const int attrvalueslen[] = {2, 2, 4};
- ok(nIndex == 0 || nIndex == 1, "invalid index received %d\n", nIndex);
+ ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
- *pValue = (nIndex == 0) ? attrval1W : attrval2W;
- *nValue = 2;
+ *value = attrvaluesW[index];
+ *nValue = attrvalueslen[index];
return S_OK;
}
@@ -2039,6 +2040,9 @@ struct writer_startendelement_t {
ISAXAttributes *attr;
};
+static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\">";
+static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\"/>";
+
static const struct writer_startendelement_t writer_startendelement[] = {
/* 0 */
{ &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
@@ -2120,17 +2124,17 @@ static const struct writer_startendelement_t writer_startendelement[] = {
{ &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
/* with attributes */
- { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\">", S_OK, &saxattributes },
+ { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
/* 65 */
- { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\">", S_OK, &saxattributes },
- { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\">", S_OK, &saxattributes },
- { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\">", S_OK, &saxattributes },
+ { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
+ { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
+ { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
/* empty elements */
- { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\"/>", S_OK, &saxattributes },
- { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\"/>", S_OK, &saxattributes },
+ { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
+ { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
/* 70 */
- { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\"/>", S_OK, &saxattributes },
- { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\"/>", S_OK, &saxattributes },
+ { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
+ { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
{ &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
{ &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
{ &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
More information about the wine-cvs
mailing list