From 643cbafabc0535fece63ef0a9f51de164df8e5d3 Mon Sep 17 00:00:00 2001 From: Adam Martinson Date: Mon, 22 Nov 2010 20:57:29 -0600 Subject: [PATCH] msxml3: Validate node content in domelem_put_dataType(). --- dlls/msxml3/element.c | 89 ++++++++++++++++++++++++++++++++++- dlls/msxml3/msxml_private.h | 1 + dlls/msxml3/node.c | 71 +++------------------------- dlls/msxml3/schema.c | 94 ++++++++++++++++++++++++++++++++++--- 4 files changed, 182 insertions(+), 73 deletions(-) diff --git a/dlls/msxml3/element.c b/dlls/msxml3/element.c index 3ab3cefd15d..237604cec8a 100644 --- a/dlls/msxml3/element.c +++ b/dlls/msxml3/element.c @@ -38,6 +38,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml); #ifdef HAVE_LIBXML2 +static const xmlChar DT_prefix[] = "dt"; static const xmlChar DT_nsURI[] = "urn:schemas-microsoft-com:datatypes"; typedef struct _domelem @@ -823,10 +824,94 @@ static HRESULT WINAPI domelem_get_dataType( static HRESULT WINAPI domelem_put_dataType( IXMLDOMElement *iface, - BSTR p) + BSTR dtName) { domelem *This = impl_from_IXMLDOMElement( iface ); - return IXMLDOMNode_put_dataType( IXMLDOMNode_from_impl(&This->node), p ); + HRESULT hr = E_FAIL; + xmlChar *str; + XDR_DT dt; + + TRACE("(%p)->(%s)\n", This, debugstr_w(dtName)); + + if(dtName == NULL) + return E_INVALIDARG; + + dt = bstr_to_dt(dtName, -1); + + /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type. + This applies to changing types (string->bool) or setting a new one + */ + str = xmlNodeGetContent(get_element(This)); + hr = dt_validate(dt, str); + xmlFree(str); + + /* Check all supported types. */ + if (hr == S_OK) + { + switch (dt) + { + case DT_BIN_BASE64: + case DT_BIN_HEX: + case DT_BOOLEAN: + case DT_CHAR: + case DT_DATE: + case DT_DATE_TZ: + case DT_DATETIME: + case DT_DATETIME_TZ: + case DT_FIXED_14_4: + case DT_FLOAT: + case DT_I1: + case DT_I2: + case DT_I4: + case DT_I8: + case DT_INT: + case DT_NMTOKEN: + case DT_NMTOKENS: + case DT_NUMBER: + case DT_R4: + case DT_R8: + case DT_STRING: + case DT_TIME: + case DT_TIME_TZ: + case DT_UI1: + case DT_UI2: + case DT_UI4: + case DT_UI8: + case DT_URI: + case DT_UUID: + { + xmlAttrPtr attr = xmlHasNsProp(get_element(This), DT_prefix, DT_nsURI); + if (attr) + { + attr = xmlSetNsProp(get_element(This), attr->ns, DT_prefix, dt_to_str(dt)); + hr = S_OK; + } + else + { + xmlNsPtr ns = xmlNewNs(get_element(This), DT_nsURI, DT_prefix); + if (ns) + { + attr = xmlNewNsProp(get_element(This), ns, DT_prefix, dt_to_str(dt)); + if (attr) + { + xmlAddChild(get_element(This), (xmlNodePtr)attr); + hr = S_OK; + } + else + ERR("Failed to create Attribute\n"); + } + else + ERR("Failed to create Namespace\n"); + } + } + break; + default: + FIXME("need to handle dt:%s\n", dt_to_str(dt)); + break; + } + } + + return hr; } static HRESULT WINAPI domelem_get_xml( diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index b6938412a45..701f03f3fa1 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -273,6 +273,7 @@ extern XDR_DT bstr_to_dt(OLECHAR const* bstr, int len /* calculated if -1 */); extern xmlChar const* dt_to_str(XDR_DT dt); extern OLECHAR const* dt_to_bstr(XDR_DT dt); extern XDR_DT element_get_dt(xmlNodePtr node); +extern HRESULT dt_validate(XDR_DT dt, xmlChar const* content); extern BSTR EnsureCorrectEOL(BSTR); diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c index c55f34d0e3d..c135f208303 100644 --- a/dlls/msxml3/node.c +++ b/dlls/msxml3/node.c @@ -42,6 +42,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml); #ifdef HAVE_LIBXML2 +/* TODO: get rid of these and use the enum */ static const WCHAR szBinBase64[] = {'b','i','n','.','b','a','s','e','6','4',0}; static const WCHAR szString[] = {'s','t','r','i','n','g',0}; static const WCHAR szNumber[] = {'n','u','m','b','e','r',0}; @@ -883,78 +884,18 @@ static HRESULT WINAPI xmlnode_put_nodeTypedValue( static HRESULT WINAPI xmlnode_put_dataType( IXMLDOMNode *iface, - BSTR dataTypeName) + BSTR dtName) { xmlnode *This = impl_from_IXMLDOMNode( iface ); - HRESULT hr = E_FAIL; - TRACE("(%p)->(%s)\n", This, debugstr_w(dataTypeName)); + TRACE("(%p)->(%s)\n", This, debugstr_w(dtName)); - if(dataTypeName == NULL) + if(!dtName) return E_INVALIDARG; - /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type. - This applies to changing types (string->bool) or setting a new one - */ - FIXME("Need to Validate the data before allowing a type to be set.\n"); + FIXME("need to handle node type %i\n", This->node->type); - /* Check all supported types. */ - if(lstrcmpiW(dataTypeName,szString) == 0 || - lstrcmpiW(dataTypeName,szNumber) == 0 || - lstrcmpiW(dataTypeName,szUUID) == 0 || - lstrcmpiW(dataTypeName,szInt) == 0 || - lstrcmpiW(dataTypeName,szI4) == 0 || - lstrcmpiW(dataTypeName,szFixed) == 0 || - lstrcmpiW(dataTypeName,szBoolean) == 0 || - lstrcmpiW(dataTypeName,szDateTime) == 0 || - lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 || - lstrcmpiW(dataTypeName,szDate) == 0 || - lstrcmpiW(dataTypeName,szTime) == 0 || - lstrcmpiW(dataTypeName,szTimeTZ) == 0 || - lstrcmpiW(dataTypeName,szI1) == 0 || - lstrcmpiW(dataTypeName,szI2) == 0 || - lstrcmpiW(dataTypeName,szIU1) == 0 || - lstrcmpiW(dataTypeName,szIU2) == 0 || - lstrcmpiW(dataTypeName,szIU4) == 0 || - lstrcmpiW(dataTypeName,szR4) == 0 || - lstrcmpiW(dataTypeName,szR8) == 0 || - lstrcmpiW(dataTypeName,szFloat) == 0 || - lstrcmpiW(dataTypeName,szBinHex) == 0 || - lstrcmpiW(dataTypeName,szBinBase64) == 0) - { - xmlChar* str = xmlChar_from_wchar(dataTypeName); - xmlAttrPtr attr; - - if (!str) return E_OUTOFMEMORY; - - attr = xmlHasNsProp(This->node, (const xmlChar*)"dt", - (const xmlChar*)"urn:schemas-microsoft-com:datatypes"); - if (attr) - { - attr = xmlSetNsProp(This->node, attr->ns, (const xmlChar*)"dt", str); - hr = S_OK; - } - else - { - xmlNsPtr ns = xmlNewNs(This->node, (const xmlChar*)"urn:schemas-microsoft-com:datatypes", (const xmlChar*)"dt"); - if (ns) - { - attr = xmlNewNsProp(This->node, ns, (const xmlChar*)"dt", str); - if (attr) - { - xmlAddChild(This->node, (xmlNodePtr)attr); - hr = S_OK; - } - else - ERR("Failed to create Attribute\n"); - } - else - ERR("Failed to create Namespace\n"); - } - heap_free( str ); - } - - return hr; + return E_FAIL; } BSTR EnsureCorrectEOL(BSTR sInput) diff --git a/dlls/msxml3/schema.c b/dlls/msxml3/schema.c index b8e66d31524..e602e29b902 100644 --- a/dlls/msxml3/schema.c +++ b/dlls/msxml3/schema.c @@ -64,9 +64,11 @@ static const xmlChar XDR_schema[] = "Schema"; static const xmlChar XDR_nsURI[] = "urn:schemas-microsoft-com:xml-data"; static const xmlChar DT_nsURI[] = "urn:schemas-microsoft-com:datatypes"; -static xmlChar const* datatypes_schema = NULL; -static HGLOBAL datatypes_handle = NULL; -static HRSRC datatypes_rsrc = NULL; +static xmlChar const* datatypes_src = NULL; +static int datatypes_len = 0; +static HGLOBAL datatypes_handle = NULL; +static HRSRC datatypes_rsrc = NULL; +static xmlSchemaPtr datatypes_schema = NULL; /* Supported Types: * msxml3 - XDR only @@ -484,6 +486,83 @@ OLECHAR const* dt_to_bstr(XDR_DT dt) return DT_wstring_table[dt]; } +HRESULT dt_validate(XDR_DT dt, xmlChar const* content) +{ + xmlDocPtr tmp_doc; + xmlNodePtr node; + xmlNsPtr ns; + xmlSchemaValidCtxtPtr svctx; + BOOL valid; + if (!datatypes_schema) + { + xmlSchemaParserCtxtPtr spctx; + assert(datatypes_src != NULL); + spctx = xmlSchemaNewMemParserCtxt((char const*)datatypes_src, datatypes_len); + datatypes_schema = xmlSchemaParse(spctx); + xmlSchemaFreeParserCtxt(spctx); + } + + switch (dt) + { + case DT_INVALID: + return E_FAIL; + break; + case DT_BIN_BASE64: + case DT_BIN_HEX: + case DT_BOOLEAN: + case DT_CHAR: + case DT_DATE: + case DT_DATE_TZ: + case DT_DATETIME: + case DT_DATETIME_TZ: + case DT_FIXED_14_4: + case DT_FLOAT: + case DT_I1: + case DT_I2: + case DT_I4: + case DT_I8: + case DT_INT: + case DT_NMTOKEN: + case DT_NMTOKENS: + case DT_NUMBER: + case DT_R4: + case DT_R8: + case DT_STRING: + case DT_TIME: + case DT_TIME_TZ: + case DT_UI1: + case DT_UI2: + case DT_UI4: + case DT_UI8: + case DT_URI: + case DT_UUID: + assert(datatypes_schema != NULL); + if (content && xmlStrlen(content)) + { + svctx = xmlSchemaNewValidCtxt(datatypes_schema); + tmp_doc = xmlNewDoc(NULL); + node = xmlNewChild((xmlNodePtr)tmp_doc, NULL, dt_to_str(dt), content); + ns = xmlNewNs(node, DT_nsURI, BAD_CAST "dt"); + xmlSetNs(node, ns); + xmlDocSetRootElement(tmp_doc, node); + + valid = !xmlSchemaValidateDoc(svctx, tmp_doc); + xmlSchemaFreeValidCtxt(svctx); + xmlFreeDoc(tmp_doc); + } + else + { /* probably the node is being created manually and has no content yet */ + valid = TRUE; + } + return valid? S_OK : S_FALSE; + break; + default: + FIXME("need to handle dt:%s\n", dt_to_str(dt)); + return S_OK; + break; + } +} + static inline xmlChar const* get_node_nsURI(xmlNodePtr node) { return (node->ns != NULL)? node->ns->href : NULL; @@ -513,13 +592,13 @@ static xmlParserInputPtr external_entity_loader(const char *URL, const char *ID, assert(MSXML_hInstance != NULL); assert(datatypes_rsrc != NULL); assert(datatypes_handle != NULL); - assert(datatypes_schema != NULL); + assert(datatypes_src != NULL); /* TODO: if the desired schema is in the cache, load it from there */ if (lstrcmpA(URL, "urn:schemas-microsoft-com:datatypes") == 0) { TRACE("loading built-in schema for %s\n", URL); - input = xmlNewStringInputStream(ctxt, datatypes_schema); + input = xmlNewStringInputStream(ctxt, datatypes_src); } else { @@ -551,7 +630,8 @@ void schemasInit(void) * need a null-terminated string */ while (buf[len] != '>') buf[len--] = 0; - datatypes_schema = BAD_CAST buf; + datatypes_src = BAD_CAST buf; + datatypes_len = len + 1; if ((void*)xmlGetExternalEntityLoader() != (void*)external_entity_loader) { @@ -564,6 +644,8 @@ void schemasCleanup(void) { if (datatypes_handle) FreeResource(datatypes_handle); + if (datatypes_schema) + xmlSchemaFree(datatypes_schema); xmlSetExternalEntityLoader(_external_entity_loader); }