msxml3: Defer the conversion of XPath expressions to UTF-8. (try 3)

John Chadwick johnwchadwick at gmail.com
Sun Jul 21 13:45:06 CDT 2013


This patch changes the create_selection interface to accept a wide
string instead of an xmlChar string. This is a transitional change,
which will be needed as libxml2's XPath parser is phased out.

The last 2 attempts for this patch had various quality issues that
should be weeded out by now.
-------------- next part --------------
From 27b0f6f79ad9299070d7aebb53f676fcb8f8018b 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 is a transitional change, which will be
needed as libxml2's XPath parser is phased out.

The implementation of tagName_to_XPath also had to be changed as it was using
libxml2's UTF-8 string API. libxml2 contained a strcat that performed
reallocation, so it was replaced with a new function that does the same with
heap_realloc and wide strings (heap_strcatW in msxml_private.h.)
---
 dlls/msxml3/domdoc.c        |   63 ++++++++++++++++++++++++++++++-------------
 dlls/msxml3/element.c       |    5 ++--
 dlls/msxml3/msxml_private.h |   20 ++++++++++++--
 dlls/msxml3/node.c          |    5 +---
 dlls/msxml3/selection.c     |    5 +++-
 5 files changed, 71 insertions(+), 27 deletions(-)

diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c
index 7eae2d4..e04ff00 100644
--- a/dlls/msxml3/domdoc.c
+++ b/dlls/msxml3/domdoc.c
@@ -1833,16 +1833,20 @@ 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::";
+WCHAR *tagName_to_XPath(const BSTR tagName)
+{
+    WCHAR *query, *realloc_buf, *tmp;
+    static const WCHAR mod_pre[] = {'*','[','l','o','c','a','l','-','n','a','m','e','(',')','=','\'',0};
+    static const WCHAR mod_post[] = {'\'',']',0};
+    static const WCHAR prefix[] = {'d','e','s','c','e','n','d','a','n','t',':',':',0};
+    static const WCHAR slash[] = {'/',0};
+    static const WCHAR wildcard[] = {'*',0};
     const WCHAR *tokBegin, *tokEnd;
     int len;
 
-    query = xmlStrdup(prefix);
+    query = heap_strdupW(prefix);
+    if (!query)
+        return NULL;
 
     tokBegin = tagName;
     while (tokBegin && *tokBegin)
@@ -1850,29 +1854,51 @@ xmlChar* tagName_to_XPath(const BSTR tagName)
         switch (*tokBegin)
         {
         case '/':
-            query = xmlStrcat(query, BAD_CAST "/");
+            realloc_buf = heap_strcatW(query, slash);
+            if (realloc_buf == NULL) goto error;
+            query = realloc_buf;
+
             ++tokBegin;
             break;
         case '*':
-            query = xmlStrcat(query, BAD_CAST "*");
+            realloc_buf = heap_strcatW(query, wildcard);
+            if (realloc_buf == NULL) goto error;
+            query = realloc_buf;
+
             ++tokBegin;
             break;
         default:
-            query = xmlStrcat(query, mod_pre);
+            realloc_buf = heap_strcatW(query, mod_pre);
+            if (realloc_buf == NULL) goto error;
+            query = realloc_buf;
+
             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);
+            len = tokEnd - tokBegin;
+
+            tmp = heap_alloc((len + 1) * sizeof(WCHAR));
+            if (tmp == NULL) goto error;
+            memcpy(tmp, tokBegin, len * sizeof(WCHAR));
+            tmp[len] = 0;
+
+            realloc_buf = heap_strcatW(query, tmp);
+            if (realloc_buf == NULL) goto error;
+            query = realloc_buf;
+
+            heap_free(tmp);
             tokBegin = tokEnd;
-            query = xmlStrcat(query, mod_post);
+
+            realloc_buf = heap_strcatW(query, mod_post);
+            if (realloc_buf == NULL) goto error;
+            query = realloc_buf;
         }
     }
 
     return query;
+error:
+    heap_free(query);
+    return NULL;
 }
 
 static HRESULT WINAPI domdoc_getElementsByTagName(
@@ -1881,7 +1907,7 @@ static HRESULT WINAPI domdoc_getElementsByTagName(
     IXMLDOMNodeList** resultList )
 {
     domdoc *This = impl_from_IXMLDOMDocument3( iface );
-    xmlChar *query;
+    WCHAR *query;
     HRESULT hr;
     BOOL XPath;
 
@@ -1892,8 +1918,9 @@ static HRESULT WINAPI domdoc_getElementsByTagName(
     XPath = This->properties->XPath;
     This->properties->XPath = TRUE;
     query = tagName_to_XPath(tagName);
+    if (!query) return E_OUTOFMEMORY;
     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..fdf016a 100644
--- a/dlls/msxml3/element.c
+++ b/dlls/msxml3/element.c
@@ -1472,7 +1472,7 @@ static HRESULT WINAPI domelem_getElementsByTagName(
     BSTR tagName, IXMLDOMNodeList** resultList)
 {
     domelem *This = impl_from_IXMLDOMElement( iface );
-    xmlChar *query;
+    WCHAR *query;
     HRESULT hr;
     BOOL XPath;
 
@@ -1483,8 +1483,9 @@ static HRESULT WINAPI domelem_getElementsByTagName(
     XPath = is_xpathmode(get_element(This)->doc);
     set_xpathmode(get_element(This)->doc, TRUE);
     query = tagName_to_XPath(tagName);
+    if (!query) return E_OUTOFMEMORY;
     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..3b8c1ce 100644
--- a/dlls/msxml3/msxml_private.h
+++ b/dlls/msxml3/msxml_private.h
@@ -217,6 +217,22 @@ static inline LPSTR heap_strdupWtoA(LPCWSTR str)
     return ret;
 }
 
+static inline WCHAR *heap_strcatW(WCHAR *dst, const WCHAR *src)
+{
+    int dst_len = strlenW(dst);
+    int src_len = strlenW(src);
+    int len = dst_len + src_len;
+    dst = heap_realloc(dst, (len + 1) * sizeof(WCHAR));
+    
+    if (dst == NULL)
+        return NULL;
+
+    memcpy(dst + dst_len, src, src_len * sizeof(WCHAR));
+    dst[len] = 0;
+
+    return dst;
+}
+
 #ifdef HAVE_LIBXML2
 
 extern void schemasInit(void) DECLSPEC_HIDDEN;
@@ -280,7 +296,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 +387,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 WCHAR* tagName_to_XPath(const BSTR tagName) 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..9a75aa4 100644
--- a/dlls/msxml3/node.c
+++ b/dlls/msxml3/node.c
@@ -1009,14 +1009,11 @@ 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);
+    hr = create_selection(This->node, query, nodes);
 
     return hr;
 }
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.7.10.4


More information about the wine-patches mailing list