msxml3: Defer the conversion of XPath expressions to UTF-8. (try 5)
John Chadwick
johnwchadwick at gmail.com
Mon Aug 19 22:02:25 CDT 2013
This try includes a more efficient implementation of tagName_to_XPath,
which performs only a single allocation and does no unnecessary
iterations over any constant or arguments.
-------------- next part --------------
From 97a14e60fd3e9c140b99a11c0793ebb79c2dea9e Mon Sep 17 00:00:00 2001
From: John Chadwick <johnwchadwick at gmail.com>
Date: Sun, 21 Jul 2013 14:41:37 -0400
Subject: msxml3: Defer the conversion of XPath expressions to UTF-8.
This patch changes the create_selection interface to accept a wide string
instead of an xmlChar string. This change will be needed during the transition
from libxml2's XPath query API to a native XPath evaluator.
---
dlls/msxml3/domdoc.c | 54 +++++++++++++++++++++++++++------------------
dlls/msxml3/element.c | 10 ++++++---
dlls/msxml3/msxml_private.h | 6 +++--
dlls/msxml3/node.c | 9 +-------
dlls/msxml3/selection.c | 5 ++++-
5 files changed, 48 insertions(+), 36 deletions(-)
diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c
index a96b5c7..4b838cf 100644
--- a/dlls/msxml3/domdoc.c
+++ b/dlls/msxml3/domdoc.c
@@ -1833,16 +1833,27 @@ static HRESULT WINAPI domdoc_createEntityReference(
return hr;
}
-xmlChar* tagName_to_XPath(const BSTR tagName)
+static void concat_to_query(WCHAR *buffer, const WCHAR *fragment, int fragLen, int *bufPos)
{
- xmlChar *query, *tmp;
- static const xmlChar mod_pre[] = "*[local-name()='";
- static const xmlChar mod_post[] = "']";
- static const xmlChar prefix[] = "descendant::";
+ if (buffer)
+ {
+ memcpy(buffer + *bufPos, fragment, sizeof(WCHAR) * fragLen);
+ buffer[*bufPos + fragLen] = 0;
+ }
+ *bufPos += fragLen;
+}
+
+int tagName_to_XPath(const WCHAR *tagName, WCHAR *buffer)
+{
+ static const WCHAR mod_pre[] = {'*','[','l','o','c','a','l','-','n','a','m','e','(',')','=','\''};
+ static const WCHAR mod_post[] = {'\'',']'};
+ static const WCHAR prefix[] = {'d','e','s','c','e','n','d','a','n','t',':',':'};
+ static const WCHAR slash[] = {'/'};
+ static const WCHAR wildcard[] = {'*'};
const WCHAR *tokBegin, *tokEnd;
- int len;
+ int bufPos = 0;
- query = xmlStrdup(prefix);
+ concat_to_query(buffer, prefix, ARRAY_SIZE(prefix), &bufPos);
tokBegin = tagName;
while (tokBegin && *tokBegin)
@@ -1850,29 +1861,24 @@ xmlChar* tagName_to_XPath(const BSTR tagName)
switch (*tokBegin)
{
case '/':
- query = xmlStrcat(query, BAD_CAST "/");
+ concat_to_query(buffer, slash, ARRAY_SIZE(slash), &bufPos);
++tokBegin;
break;
case '*':
- query = xmlStrcat(query, BAD_CAST "*");
+ concat_to_query(buffer, wildcard, ARRAY_SIZE(wildcard), &bufPos);
++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);
+ while (*tokEnd && *tokEnd != '/') ++tokEnd;
+ concat_to_query(buffer, mod_pre, ARRAY_SIZE(mod_pre), &bufPos);
+ concat_to_query(buffer, tokBegin, tokEnd - tokBegin, &bufPos);
+ concat_to_query(buffer, mod_post, ARRAY_SIZE(mod_post), &bufPos);
tokBegin = tokEnd;
- query = xmlStrcat(query, mod_post);
}
}
- return query;
+ return bufPos;
}
static HRESULT WINAPI domdoc_getElementsByTagName(
@@ -1881,7 +1887,8 @@ static HRESULT WINAPI domdoc_getElementsByTagName(
IXMLDOMNodeList** resultList )
{
domdoc *This = impl_from_IXMLDOMDocument3( iface );
- xmlChar *query;
+ WCHAR *query;
+ int queryLen;
HRESULT hr;
BOOL XPath;
@@ -1891,9 +1898,12 @@ static HRESULT WINAPI domdoc_getElementsByTagName(
XPath = This->properties->XPath;
This->properties->XPath = TRUE;
- query = tagName_to_XPath(tagName);
+ queryLen = tagName_to_XPath(tagName, NULL);
+ query = heap_alloc((queryLen + 1) * sizeof(WCHAR));
+ if (!query) return E_OUTOFMEMORY;
+ tagName_to_XPath(tagName, query);
hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
- xmlFree(query);
+ heap_free(query);
This->properties->XPath = XPath;
return hr;
diff --git a/dlls/msxml3/element.c b/dlls/msxml3/element.c
index 5e8822e..862f02e 100644
--- a/dlls/msxml3/element.c
+++ b/dlls/msxml3/element.c
@@ -1472,7 +1472,8 @@ static HRESULT WINAPI domelem_getElementsByTagName(
BSTR tagName, IXMLDOMNodeList** resultList)
{
domelem *This = impl_from_IXMLDOMElement( iface );
- xmlChar *query;
+ WCHAR *query;
+ int queryLen;
HRESULT hr;
BOOL XPath;
@@ -1482,9 +1483,12 @@ static HRESULT WINAPI domelem_getElementsByTagName(
XPath = is_xpathmode(get_element(This)->doc);
set_xpathmode(get_element(This)->doc, TRUE);
- query = tagName_to_XPath(tagName);
+ queryLen = tagName_to_XPath(tagName, 0);
+ query = heap_alloc((queryLen + 1) * sizeof(WCHAR));
+ if (!query) return E_OUTOFMEMORY;
+ tagName_to_XPath(tagName, query);
hr = create_selection(get_element(This), query, resultList);
- xmlFree(query);
+ heap_free(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 17e19a7..402e072 100644
--- a/dlls/msxml3/msxml_private.h
+++ b/dlls/msxml3/msxml_private.h
@@ -29,6 +29,8 @@
# error You must include config.h to use this header
#endif
+#define ARRAY_SIZE(array) (sizeof(array)/sizeof((array)[0]))
+
typedef enum {
MSXML_DEFAULT = 0,
MSXML2 = 20,
@@ -280,7 +282,7 @@ extern IUnknown *create_doc_Implementation(void) DECLSPEC_HIDDEN;
extern IUnknown *create_doc_fragment( xmlNodePtr ) DECLSPEC_HIDDEN;
extern IUnknown *create_doc_entity_ref( xmlNodePtr ) DECLSPEC_HIDDEN;
extern IUnknown *create_doc_type( xmlNodePtr ) DECLSPEC_HIDDEN;
-extern HRESULT create_selection( xmlNodePtr, xmlChar*, IXMLDOMNodeList** ) DECLSPEC_HIDDEN;
+extern HRESULT create_selection( xmlNodePtr, WCHAR*, IXMLDOMNodeList** ) DECLSPEC_HIDDEN;
extern HRESULT create_enumvariant( IUnknown*, BOOL, const struct enumvariant_funcs*, IEnumVARIANT**) DECLSPEC_HIDDEN;
/* data accessors */
@@ -371,7 +373,7 @@ extern HRESULT dt_validate(XDR_DT dt, xmlChar const* content) DECLSPEC_HIDDEN;
extern BSTR EnsureCorrectEOL(BSTR) DECLSPEC_HIDDEN;
-extern xmlChar* tagName_to_XPath(const BSTR tagName) DECLSPEC_HIDDEN;
+extern int tagName_to_XPath(const WCHAR *tagName, WCHAR *buffer) DECLSPEC_HIDDEN;
static inline BSTR bstr_from_xmlChar(const xmlChar *str)
{
diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c
index 79de75c..a58ffdf 100644
--- a/dlls/msxml3/node.c
+++ b/dlls/msxml3/node.c
@@ -1009,16 +1009,9 @@ HRESULT node_transform_node(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *
HRESULT node_select_nodes(const xmlnode *This, BSTR query, IXMLDOMNodeList **nodes)
{
- xmlChar* str;
- HRESULT hr;
-
if (!query || !nodes) return E_INVALIDARG;
- str = xmlchar_from_wchar(query);
- hr = create_selection(This->node, str, nodes);
- heap_free(str);
-
- return hr;
+ return create_selection(This->node, query, nodes);
}
HRESULT node_select_singlenode(const xmlnode *This, BSTR query, IXMLDOMNode **node)
diff --git a/dlls/msxml3/selection.c b/dlls/msxml3/selection.c
index bb0f42e..c886075 100644
--- a/dlls/msxml3/selection.c
+++ b/dlls/msxml3/selection.c
@@ -766,17 +766,19 @@ static void query_serror(void* ctx, xmlErrorPtr err)
LIBXML2_CALLBACK_SERROR(domselection_create, err);
}
-HRESULT create_selection(xmlNodePtr node, xmlChar* query, IXMLDOMNodeList **out)
+HRESULT create_selection(xmlNodePtr node, WCHAR* str, IXMLDOMNodeList **out)
{
domselection *This = heap_alloc(sizeof(domselection));
xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc);
HRESULT hr;
+ xmlChar *query = xmlchar_from_wchar(str);
TRACE("(%p, %s, %p)\n", node, debugstr_a((char const*)query), out);
*out = NULL;
if (!This || !ctxt || !query)
{
+ heap_free(query);
xmlXPathFreeContext(ctxt);
heap_free(This);
return E_OUTOFMEMORY;
@@ -832,6 +834,7 @@ HRESULT create_selection(xmlNodePtr node, xmlChar* query, IXMLDOMNodeList **out)
TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This->result->nodesetval));
cleanup:
+ heap_free(query);
if (This && FAILED(hr))
IXMLDOMSelection_Release( &This->IXMLDOMSelection_iface );
xmlXPathFreeContext(ctxt);
--
1.8.4.rc2
More information about the wine-patches
mailing list