Hello developers,

the current implementation of IPersistStream::Load for XMLDOMDocument
takes a copy of the given stream into a hglobal stream, and uses a
helper function to parse that, namely parse_xml that calls xmlReadMemory
if available (since 2.6.0) and uses the old xmlParseMemory call
otherwise.

If libxml2 is new enough, it is possible to parse directly from the
stream using xmlReadIO to avoid copying the whole stream contents to
memory. The function xmlReadIO was introduced in libxml 2.6.0, five
years ago. If I want to use that function, do I have to create an
alternative code path for such ancient libxml implemementations, or is
it OK to require libxml 2.6.0 as minimum for libxml (even Debian Sarge,
i.e. oldstable has it)?

Another question arose on looking at the current implementation. If Wine
is not going the direct-stream-to-libxml2-way, but wants to take a copy,
currently the copying is performed manually, although there is a
function CopyTo in IStream that takes care of creating the copy.

I attached two diff files,
 - load-via-readio.diff shows the way that calls stream callbacks from
libxml2
 - load-use-copyto.diff uses the CopyTo function, but still copies.

Thanks in advance for any feedback,
  Michael Karcher
diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c
index 8ef0db4..969e25e 100644
--- a/dlls/msxml3/domdoc.c
+++ b/dlls/msxml3/domdoc.c
@@ -234,6 +234,29 @@ static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
     return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIObjectSafety));
 }
 
+typedef struct {
+    IStream * stream;
+    HRESULT res;
+} read_context;
+
+static int XMLCALL stream_read_callback(void * c, char * buffer, int len)
+{
+    read_context * ctx = c;
+    HRESULT hr;
+    ULONG gotcnt;
+    hr = IStream_Read(ctx->stream, buffer, len, &gotcnt);
+    if (FAILED(hr))
+    {
+        ctx->res = hr;
+        return -1;
+    }
+    return gotcnt;
+}
+
+static int XMLCALL stream_close_callback(void * c)
+{
+    /* do nothing */
+}
 
 /************************************************************************
  * xmldoc implementation of IPersistStream.
@@ -286,48 +309,23 @@ static HRESULT WINAPI xmldoc_IPersistStream_Load(
     IPersistStream *iface, LPSTREAM pStm)
 {
     domdoc *This = impl_from_IPersistStream(iface);
-    HRESULT hr;
-    HGLOBAL hglobal;
-    DWORD read, written, len;
-    BYTE buf[4096];
-    char *ptr;
     xmlDocPtr xmldoc = NULL;
+    read_context ctx;
 
     TRACE("(%p, %p)\n", iface, pStm);
 
     if (!pStm)
         return E_INVALIDARG;
 
-    hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
-    if (FAILED(hr))
-        return hr;
-
-    do
-    {
-        IStream_Read(pStm, buf, sizeof(buf), &read);
-        hr = IStream_Write(This->stream, buf, read, &written);
-    } while(SUCCEEDED(hr) && written != 0 && read != 0);
-
-    if (FAILED(hr))
-    {
-        ERR("Failed to copy stream\n");
-        return hr;
-    }
-
-    hr = GetHGlobalFromStream(This->stream, &hglobal);
-    if (FAILED(hr))
-        return hr;
-
-    len = GlobalSize(hglobal);
-    ptr = GlobalLock(hglobal);
-    if (len != 0)
-        xmldoc = parse_xml(ptr, len);
-    GlobalUnlock(hglobal);
+    ctx.stream = pStm;
+    ctx.res = S_OK;
+    xmldoc = xmlReadIO(stream_read_callback, NULL, &ctx, NULL, NULL, 
+                       XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS);
 
     if (!xmldoc)
     {
-        ERR("Failed to parse xml\n");
-        return E_FAIL;
+        ERR("Failed to load or parse xml\n");
+        return (ctx.res != S_OK) ? ctx.res : E_FAIL;
     }
 
     xmldoc->_private = create_priv();
diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c
index 8ef0db4..b8d90dc 100644
--- a/dlls/msxml3/domdoc.c
+++ b/dlls/msxml3/domdoc.c
@@ -288,7 +289,8 @@ static HRESULT WINAPI xmldoc_IPersistStream_Load(
     domdoc *This = impl_from_IPersistStream(iface);
     HRESULT hr;
     HGLOBAL hglobal;
-    DWORD read, written, len;
+    ULARGE_INTEGER count;
+    DWORD len; 
     BYTE buf[4096];
     char *ptr;
     xmlDocPtr xmldoc = NULL;
@@ -302,11 +304,8 @@ static HRESULT WINAPI xmldoc_IPersistStream_Load(
     if (FAILED(hr))
         return hr;
 
-    do
-    {
-        IStream_Read(pStm, buf, sizeof(buf), &read);
-        hr = IStream_Write(This->stream, buf, read, &written);
-    } while(SUCCEEDED(hr) && written != 0 && read != 0);
+    count.QuadPart = ~((ULONGLONG)0);
+    hr = IStream_CopyTo(pStm, This->stream, count, NULL, NULL);
 
     if (FAILED(hr))
     {


Reply via email to