diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index c485e14ff95..45a495d80a1 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -198,6 +198,11 @@ BOOL is_xpathmode(const xmlDocPtr doc) return properties_from_xmlDocPtr(doc)->XPath; } +void set_xpathmode(xmlDocPtr doc, BOOL xpath) +{ + properties_from_xmlDocPtr(doc)->XPath = xpath; +} + int registerNamespaces(xmlXPathContextPtr ctxt) { int n = 0; @@ -1766,6 +1771,47 @@ static HRESULT WINAPI domdoc_createEntityReference( return hr; } +xmlChar* tagName_to_XPath(const BSTR tagName) +{ + xmlChar *query, *tmp; + static const xmlChar mod_pre[] = "*[local-name()='"; + static const xmlChar mod_post[] = "']"; + static const xmlChar prefix[] = "descendant::"; + const WCHAR *tokBegin, *tokEnd; + int len; + + query = xmlStrdup(prefix); + + tokBegin = tagName; + while (tokBegin && *tokBegin) + { + switch (*tokBegin) + { + case '/': + query = xmlStrcat(query, BAD_CAST "/"); + ++tokBegin; + break; + case '*': + query = xmlStrcat(query, BAD_CAST "*"); + ++tokBegin; + break; + default: + query = xmlStrcat(query, mod_pre); + tokEnd = tokBegin; + while (*tokEnd && *tokEnd != '/') + ++tokEnd; + len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL); + tmp = xmlMalloc(len); + WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL); + query = xmlStrncat(query, tmp, len); + xmlFree(tmp); + tokBegin = tokEnd; + query = xmlStrcat(query, mod_post); + } + } + + return query; +} static HRESULT WINAPI domdoc_getElementsByTagName( IXMLDOMDocument3 *iface, @@ -1773,41 +1819,20 @@ static HRESULT WINAPI domdoc_getElementsByTagName( IXMLDOMNodeList** resultList ) { domdoc *This = impl_from_IXMLDOMDocument3( iface ); + xmlChar *query; HRESULT hr; + BOOL XPath; - TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagName), resultList); + TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList); if (!tagName || !resultList) return E_INVALIDARG; - if (tagName[0] == '*' && tagName[1] == 0) - { - static const WCHAR formatallW[] = {'/','/','*',0}; - hr = queryresult_create((xmlNodePtr)get_doc(This), formatallW, resultList); - } - else - { - static const WCHAR xpathformat[] = - { '/','/','*','[','l','o','c','a','l','-','n','a','m','e','(',')','=','\'' }; - static const WCHAR closeW[] = { '\'',']',0 }; - - LPWSTR pattern; - WCHAR *ptr; - INT length; - - length = lstrlenW(tagName); - - /* without two WCHARs from format specifier */ - ptr = pattern = heap_alloc(sizeof(xpathformat) + length*sizeof(WCHAR) + sizeof(closeW)); - - memcpy(ptr, xpathformat, sizeof(xpathformat)); - ptr += sizeof(xpathformat)/sizeof(WCHAR); - memcpy(ptr, tagName, length*sizeof(WCHAR)); - ptr += length; - memcpy(ptr, closeW, sizeof(closeW)); - - hr = queryresult_create((xmlNodePtr)get_doc(This), pattern, resultList); - heap_free(pattern); - } + XPath = This->properties->XPath; + This->properties->XPath = TRUE; + query = tagName_to_XPath(tagName); + hr = queryresult_create((xmlNodePtr)get_doc(This), query, resultList); + xmlFree(query); + This->properties->XPath = XPath; return hr; } diff --git a/dlls/msxml3/element.c b/dlls/msxml3/element.c index 237604cec8a..adb2bb3b371 100644 --- a/dlls/msxml3/element.c +++ b/dlls/msxml3/element.c @@ -1231,44 +1231,20 @@ static HRESULT WINAPI domelem_getElementsByTagName( BSTR tagName, IXMLDOMNodeList** resultList) { domelem *This = impl_from_IXMLDOMElement( iface ); - xmlNodePtr element; + xmlChar *query; HRESULT hr; + BOOL XPath; - TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagName), resultList); + TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList); if (!tagName || !resultList) return E_INVALIDARG; - if (!(element = get_element(This))) return E_FAIL; - if (tagName[0] == '*' && tagName[1] == 0) - { - static const WCHAR formatallW[] = {'/','/','*',0}; - hr = queryresult_create(element, formatallW, resultList); - } - else - { - static const WCHAR xpathformat[] = - { '/','/','*','[','l','o','c','a','l','-','n','a','m','e','(',')','=','\'' }; - static const WCHAR closeW[] = { '\'',']',0 }; - - LPWSTR pattern; - WCHAR *ptr; - INT length; - - length = lstrlenW(tagName); - - /* without two WCHARs from format specifier */ - ptr = pattern = heap_alloc(sizeof(xpathformat) + length*sizeof(WCHAR) + sizeof(closeW)); - - memcpy(ptr, xpathformat, sizeof(xpathformat)); - ptr += sizeof(xpathformat)/sizeof(WCHAR); - memcpy(ptr, tagName, length*sizeof(WCHAR)); - ptr += length; - memcpy(ptr, closeW, sizeof(closeW)); - - TRACE("%s\n", debugstr_w(pattern)); - hr = queryresult_create(element, pattern, resultList); - heap_free(pattern); - } + XPath = is_xpathmode(get_element(This)->doc); + set_xpathmode(get_element(This)->doc, TRUE); + query = tagName_to_XPath(tagName); + hr = queryresult_create(get_element(This), query, resultList); + xmlFree(query); + set_xpathmode(get_element(This)->doc, XPath); return hr; } diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index 701f03f3fa1..8a2b1b59e09 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -190,7 +190,7 @@ extern IUnknown *create_doc_fragment( xmlNodePtr fragment ); extern IUnknown *create_doc_entity_ref( xmlNodePtr entity ); extern IUnknown *create_doc_type( xmlNodePtr doctype ); -extern HRESULT queryresult_create( xmlNodePtr, LPCWSTR, IXMLDOMNodeList ** ); +extern HRESULT queryresult_create( xmlNodePtr node, xmlChar* szQuery, IXMLDOMNodeList** out ); /* data accessors */ xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type ); @@ -225,6 +225,8 @@ extern void wineXmlCallbackError(char const* caller, xmlErrorPtr err); #define LIBXML2_CALLBACK_SERROR(caller, err) wineXmlCallbackError(#caller, err) extern BOOL is_preserving_whitespace(xmlNodePtr node); +extern BOOL is_xpathmode(const xmlDocPtr doc); +extern void set_xpathmode(xmlDocPtr doc, BOOL xpath); /* IXMLDOMNode Internal Structure */ typedef struct _xmlnode @@ -277,6 +279,8 @@ extern HRESULT dt_validate(XDR_DT dt, xmlChar const* content); extern BSTR EnsureCorrectEOL(BSTR); +extern xmlChar* tagName_to_XPath(const BSTR tagName); + static inline BSTR bstr_from_xmlChar(const xmlChar *str) { BSTR ret = NULL; diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c index 2db71155e0b..43aec69ccdb 100644 --- a/dlls/msxml3/node.c +++ b/dlls/msxml3/node.c @@ -1107,12 +1107,18 @@ static HRESULT WINAPI xmlnode_selectNodes( IXMLDOMNodeList** resultList) { xmlnode *This = impl_from_IXMLDOMNode( iface ); + xmlChar* str; + HRESULT hr; TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList ); if (!queryString || !resultList) return E_INVALIDARG; - return queryresult_create( This->node, queryString, resultList ); + str = xmlChar_from_wchar(queryString); + hr = queryresult_create(This->node, str, resultList); + heap_free(str); + + return hr; } static HRESULT WINAPI xmlnode_selectSingleNode( diff --git a/dlls/msxml3/queryresult.c b/dlls/msxml3/queryresult.c index 44d218f36e7..7dc6899e21a 100644 --- a/dlls/msxml3/queryresult.c +++ b/dlls/msxml3/queryresult.c @@ -52,7 +52,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml); #include int registerNamespaces(xmlXPathContextPtr ctxt); -BOOL is_xpathmode(const xmlDocPtr doc); xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr ctxt, xmlChar const* xslpat_str); typedef struct _queryresult @@ -488,17 +487,16 @@ static void query_serror(void* ctx, xmlErrorPtr err) LIBXML2_CALLBACK_SERROR(queryresult_create, err); } -HRESULT queryresult_create(xmlNodePtr node, LPCWSTR szQuery, IXMLDOMNodeList **out) +HRESULT queryresult_create(xmlNodePtr node, xmlChar* szQuery, IXMLDOMNodeList **out) { queryresult *This = heap_alloc_zero(sizeof(queryresult)); xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc); - xmlChar *str = xmlChar_from_wchar(szQuery); HRESULT hr; - TRACE("(%p, %s, %p)\n", node, wine_dbgstr_w(szQuery), out); + TRACE("(%p, %s, %p)\n", node, wine_dbgstr_a((char const*)szQuery), out); *out = NULL; - if (This == NULL || ctxt == NULL || str == NULL) + if (This == NULL || ctxt == NULL || szQuery == NULL) { hr = E_OUTOFMEMORY; goto cleanup; @@ -517,16 +515,11 @@ HRESULT queryresult_create(xmlNodePtr node, LPCWSTR szQuery, IXMLDOMNodeList **o if (is_xpathmode(This->node->doc)) { xmlXPathRegisterAllFunctions(ctxt); + This->result = xmlXPathEvalExpression(szQuery, ctxt); } else { - xmlChar* tmp; - int len; - tmp = XSLPattern_to_XPath(ctxt, str); - len = (xmlStrlen(tmp)+1)*sizeof(xmlChar); - str = heap_realloc(str, len); - memcpy(str, tmp, len); - xmlFree(tmp); + xmlChar* xslpQuery = XSLPattern_to_XPath(ctxt, szQuery); xmlXPathRegisterFunc(ctxt, (xmlChar const*)"not", xmlXPathNotFunction); xmlXPathRegisterFunc(ctxt, (xmlChar const*)"boolean", xmlXPathBooleanFunction); @@ -541,9 +534,11 @@ HRESULT queryresult_create(xmlNodePtr node, LPCWSTR szQuery, IXMLDOMNodeList **o xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_ILEq", XSLPattern_OP_ILEq); xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGt", XSLPattern_OP_IGt); xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGEq", XSLPattern_OP_IGEq); + + This->result = xmlXPathEvalExpression(xslpQuery, ctxt); + xmlFree(xslpQuery); } - This->result = xmlXPathEvalExpression(str, ctxt); if (!This->result || This->result->type != XPATH_NODESET) { hr = E_FAIL; @@ -560,7 +555,6 @@ cleanup: if (This != NULL && FAILED(hr)) IXMLDOMNodeList_Release( (IXMLDOMNodeList*) &This->lpVtbl ); xmlXPathFreeContext(ctxt); - heap_free(str); return hr; } diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index ebad3360a94..dda63a267e7 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -2962,9 +2962,8 @@ static void test_getElementsByTagName(void) ok( r == S_OK, "ret %08x\n", r ); r = IXMLDOMNodeList_get_length( node_list, &len ); ok( r == S_OK, "ret %08x\n", r ); - todo_wine ok( len == 5, "len %d\n", len ); - - IXMLDOMNodeList_Release( node_list ); + ok( len == 5, "len %d\n", len ); + expect_list_and_release(node_list, "E1.E2.D1 E2.E2.D1 E3.E2.D1 E4.E2.D1 E1.E4.E2.D1"); SysFreeString( str ); /* broken query BSTR */ @@ -2975,7 +2974,7 @@ static void test_getElementsByTagName(void) ok( r == S_OK, "ret %08x\n", r ); r = IXMLDOMNodeList_get_length( node_list, &len ); ok( r == S_OK, "ret %08x\n", r ); - todo_wine ok( len == 5, "len %d\n", len ); + ok( len == 5, "len %d\n", len ); IXMLDOMNodeList_Release( node_list ); IXMLDOMElement_Release(elem);