From d80ee5b3ae36275f813b096576b5beecea2c2d60 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Sun, 11 Dec 2011 02:32:51 +0300 Subject: [PATCH] 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 febabe127e9..5c5aca8c320 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 d713fd35a1d..7b3feea8948 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[] = ""; +static const char startendelement_xml[] = ""; + 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", "", S_OK }, /* with attributes */ - { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "", S_OK, &saxattributes }, + { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes }, /* 65 */ - { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "", S_OK, &saxattributes }, - { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "", S_OK, &saxattributes }, - { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "", 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", "", S_OK, &saxattributes }, - { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", "", 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", "", S_OK, &saxattributes }, - { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", "", 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 },