[PATCH] msxml3: Support IPersistStream* as IXSLProcessor output

Nikolay Sivov nsivov at codeweavers.com
Sun Mar 26 05:56:29 CDT 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/msxml3/msxml_private.h |   3 +-
 dlls/msxml3/node.c          |   6 +--
 dlls/msxml3/stylesheet.c    | 105 ++++++++++++++++++++++++++++++++++----------
 dlls/msxml3/tests/domdoc.c  |  54 +++++++++++++++++++++--
 4 files changed, 138 insertions(+), 30 deletions(-)

diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h
index 74f6df5476..4bcac932d0 100644
--- a/dlls/msxml3/msxml_private.h
+++ b/dlls/msxml3/msxml_private.h
@@ -358,7 +358,8 @@ extern HRESULT node_get_text(const xmlnode*,BSTR*) DECLSPEC_HIDDEN;
 extern HRESULT node_select_nodes(const xmlnode*,BSTR,IXMLDOMNodeList**) DECLSPEC_HIDDEN;
 extern HRESULT node_select_singlenode(const xmlnode*,BSTR,IXMLDOMNode**) DECLSPEC_HIDDEN;
 extern HRESULT node_transform_node(const xmlnode*,IXMLDOMNode*,BSTR*) DECLSPEC_HIDDEN;
-extern HRESULT node_transform_node_params(const xmlnode*,IXMLDOMNode*,BSTR*,IStream*,const struct xslprocessor_params*) DECLSPEC_HIDDEN;
+extern HRESULT node_transform_node_params(const xmlnode*,IXMLDOMNode*,BSTR*,ISequentialStream*,
+    const struct xslprocessor_params*) DECLSPEC_HIDDEN;
 extern HRESULT node_create_supporterrorinfo(const tid_t*,void**) DECLSPEC_HIDDEN;
 
 extern HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document) DECLSPEC_HIDDEN;
diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c
index c5a180b47b..ece82efa10 100644
--- a/dlls/msxml3/node.c
+++ b/dlls/msxml3/node.c
@@ -1035,7 +1035,7 @@ static void xml_write_quotedstring(xmlOutputBufferPtr buf, const xmlChar *string
 static int XMLCALL transform_to_stream_write(void *context, const char *buffer, int len)
 {
     DWORD written;
-    HRESULT hr = IStream_Write((IStream*)context, buffer, len, &written);
+    HRESULT hr = ISequentialStream_Write((ISequentialStream *)context, buffer, len, &written);
     return hr == S_OK ? written : -1;
 }
 
@@ -1280,7 +1280,7 @@ static HRESULT node_transform_write_to_bstr(xsltStylesheetPtr style, xmlDocPtr r
     return *str ? hr : E_OUTOFMEMORY;
 }
 
-static HRESULT node_transform_write_to_stream(xsltStylesheetPtr style, xmlDocPtr result, IStream *stream)
+static HRESULT node_transform_write_to_stream(xsltStylesheetPtr style, xmlDocPtr result, ISequentialStream *stream)
 {
     static const xmlChar *utf16 = (const xmlChar*)"UTF-16";
     xmlOutputBufferPtr output;
@@ -1316,7 +1316,7 @@ static HRESULT node_transform_write_to_stream(xsltStylesheetPtr style, xmlDocPtr
 #endif
 
 HRESULT node_transform_node_params(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p,
-    IStream *stream, const struct xslprocessor_params *params)
+    ISequentialStream *stream, const struct xslprocessor_params *params)
 {
 #ifdef SONAME_LIBXSLT
     xsltStylesheetPtr xsltSS;
diff --git a/dlls/msxml3/stylesheet.c b/dlls/msxml3/stylesheet.c
index 000199f2aa..74a91808f8 100644
--- a/dlls/msxml3/stylesheet.c
+++ b/dlls/msxml3/stylesheet.c
@@ -49,6 +49,13 @@ typedef struct
     IXMLDOMNode *node;
 } xsltemplate;
 
+enum output_type
+{
+    PROCESSOR_OUTPUT_NOT_SET,
+    PROCESSOR_OUTPUT_STREAM,        /* IStream or ISequentialStream */
+    PROCESSOR_OUTPUT_PERSISTSTREAM, /* IPersistStream or IPersistStreamInit */
+};
+
 typedef struct
 {
     DispatchEx dispex;
@@ -58,8 +65,14 @@ typedef struct
     xsltemplate *stylesheet;
     IXMLDOMNode *input;
 
-    IStream     *output;
-    BSTR         outstr;
+    union
+    {
+        IUnknown *unk;
+        ISequentialStream *stream;
+        IPersistStream *persiststream;
+    } output;
+    enum output_type output_type;
+    BSTR outstr;
 
     struct xslprocessor_params params;
 } xslprocessor;
@@ -318,7 +331,8 @@ static ULONG WINAPI xslprocessor_Release( IXSLProcessor *iface )
         struct xslprocessor_par *par, *par2;
 
         if (This->input) IXMLDOMNode_Release(This->input);
-        if (This->output) IStream_Release(This->output);
+        if (This->output.unk)
+            IUnknown_Release(This->output.unk);
         SysFreeString(This->outstr);
 
         LIST_FOR_EACH_ENTRY_SAFE(par, par2, &This->params.list, struct xslprocessor_par, entry)
@@ -457,34 +471,53 @@ static HRESULT WINAPI xslprocessor_get_startModeURI(
 
 static HRESULT WINAPI xslprocessor_put_output(
     IXSLProcessor *iface,
-    VARIANT output)
+    VARIANT var)
 {
     xslprocessor *This = impl_from_IXSLProcessor( iface );
-    IStream *stream;
-    HRESULT hr;
+    enum output_type output_type = PROCESSOR_OUTPUT_NOT_SET;
+    IUnknown *output = NULL;
+    HRESULT hr = S_OK;
 
-    TRACE("(%p)->(%s)\n", This, debugstr_variant(&output));
+    TRACE("(%p)->(%s)\n", This, debugstr_variant(&var));
 
-    switch (V_VT(&output))
+    switch (V_VT(&var))
     {
-      case VT_EMPTY:
-        stream = NULL;
-        hr = S_OK;
+    case VT_EMPTY:
         break;
-      case VT_UNKNOWN:
-        hr = IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_IStream, (void**)&stream);
+    case VT_UNKNOWN:
+    case VT_DISPATCH:
+        if (!V_UNKNOWN(&var))
+            break;
+
+        output_type = PROCESSOR_OUTPUT_STREAM;
+        hr = IUnknown_QueryInterface(V_UNKNOWN(&var), &IID_IStream, (void **)&output);
+        if (FAILED(hr))
+            hr = IUnknown_QueryInterface(V_UNKNOWN(&var), &IID_ISequentialStream, (void **)&output);
+        /* FIXME: try IResponse */
+        if (FAILED(hr))
+        {
+            output_type = PROCESSOR_OUTPUT_PERSISTSTREAM;
+            hr = IUnknown_QueryInterface(V_UNKNOWN(&var), &IID_IPersistStream, (void **)&output);
+        }
+        if (FAILED(hr))
+            hr = IUnknown_QueryInterface(V_UNKNOWN(&var), &IID_IPersistStreamInit, (void **)&output);
         if (FAILED(hr))
-            WARN("failed to get IStream from output, 0x%08x\n", hr);
+        {
+            output_type = PROCESSOR_OUTPUT_NOT_SET;
+            WARN("failed to get output interface, 0x%08x\n", hr);
+        }
         break;
-      default:
-        FIXME("output type %d not handled\n", V_VT(&output));
+    default:
+        FIXME("output type %d not handled\n", V_VT(&var));
         hr = E_FAIL;
     }
 
     if (hr == S_OK)
     {
-        if (This->output) IStream_Release(This->output);
-        This->output = stream;
+        if (This->output.unk)
+            IUnknown_Release(This->output.unk);
+        This->output.unk = output;
+        This->output_type = output_type;
     }
 
     return hr;
@@ -500,11 +533,11 @@ static HRESULT WINAPI xslprocessor_get_output(
 
     if (!output) return E_INVALIDARG;
 
-    if (This->output)
+    if (This->output.unk)
     {
         V_VT(output) = VT_UNKNOWN;
-        V_UNKNOWN(output) = (IUnknown*)This->output;
-        IStream_AddRef(This->output);
+        V_UNKNOWN(output) = This->output.unk;
+        IUnknown_AddRef(This->output.unk);
     }
     else if (This->outstr)
     {
@@ -523,6 +556,7 @@ static HRESULT WINAPI xslprocessor_transform(
 {
 #ifdef HAVE_LIBXML2
     xslprocessor *This = impl_from_IXSLProcessor( iface );
+    ISequentialStream *stream = NULL;
     HRESULT hr;
 
     TRACE("(%p)->(%p)\n", This, ret);
@@ -530,7 +564,31 @@ static HRESULT WINAPI xslprocessor_transform(
     if (!ret) return E_INVALIDARG;
 
     SysFreeString(This->outstr);
-    hr = node_transform_node_params(get_node_obj(This->input), This->stylesheet->node, &This->outstr, This->output, &This->params);
+
+    if (This->output_type == PROCESSOR_OUTPUT_STREAM)
+    {
+        stream = This->output.stream;
+        ISequentialStream_AddRef(stream);
+    }
+    else if (This->output_type == PROCESSOR_OUTPUT_PERSISTSTREAM)
+        CreateStreamOnHGlobal(NULL, TRUE, (IStream **)&stream);
+
+    hr = node_transform_node_params(get_node_obj(This->input), This->stylesheet->node,
+            &This->outstr, stream, &This->params);
+    if (SUCCEEDED(hr) && This->output_type == PROCESSOR_OUTPUT_PERSISTSTREAM)
+    {
+        IStream *src = (IStream *)stream;
+        LARGE_INTEGER zero;
+
+        /* for IPersistStream* output seekable stream is used */
+        zero.QuadPart = 0;
+        IStream_Seek(src, zero, STREAM_SEEK_SET, NULL);
+        hr = IPersistStream_Load(This->output.persiststream, src);
+    }
+
+    if (stream)
+        ISequentialStream_Release(stream);
+
     *ret = hr == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
     return hr;
 #else
@@ -709,7 +767,8 @@ HRESULT XSLProcessor_create(xsltemplate *template, IXSLProcessor **ppObj)
     This->IXSLProcessor_iface.lpVtbl = &XSLProcessorVtbl;
     This->ref = 1;
     This->input = NULL;
-    This->output = NULL;
+    This->output.unk = NULL;
+    This->output_type = PROCESSOR_OUTPUT_NOT_SET;
     This->outstr = NULL;
     list_init(&This->params.list);
     This->params.count = 0;
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index 611d48ef04..4b2cc270e2 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -8496,14 +8496,15 @@ static void test_get_xml(void)
 
 static void test_xsltemplate(void)
 {
+    IXMLDOMDocument *doc, *doc2, *doc3;
     IXSLTemplate *template;
     IXSLProcessor *processor;
-    IXMLDOMDocument *doc, *doc2;
     IStream *stream;
     VARIANT_BOOL b;
     HRESULT hr;
     ULONG ref1, ref2;
     VARIANT v;
+    BSTR str;
 
     if (!is_clsid_supported(&CLSID_XSLTemplate, &IID_IXSLTemplate)) return;
     template = create_xsltemplate(&IID_IXSLTemplate);
@@ -8583,6 +8584,16 @@ todo_wine {
     hr = IXSLProcessor_put_output(processor, v);
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
+    V_VT(&v) = VT_UNKNOWN;
+    V_UNKNOWN(&v) = NULL;
+    hr = IXSLProcessor_put_output(processor, v);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    V_VT(&v) = VT_UNKNOWN;
+    V_DISPATCH(&v) = NULL;
+    hr = IXSLProcessor_put_output(processor, v);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
     ok(hr == S_OK, "got 0x%08x\n", hr);
     EXPECT_REF(stream, 1);
@@ -8619,7 +8630,7 @@ todo_wine {
     /* no output interface set, check output */
     doc2 = create_document(&IID_IXMLDOMDocument);
 
-    b = VARIANT_TRUE;
+    b = VARIANT_FALSE;
     hr = IXMLDOMDocument_loadXML( doc2, _bstr_("<a>test</a>"), &b );
     ok(hr == S_OK, "got 0x%08x\n", hr);
     ok( b == VARIANT_TRUE, "got %d\n", b);
@@ -8637,10 +8648,47 @@ todo_wine {
     ok(hr == S_OK, "got 0x%08x\n", hr);
     ok(V_VT(&v) == VT_BSTR, "got type %d\n", V_VT(&v));
     ok(*V_BSTR(&v) == 0, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
-    IXMLDOMDocument_Release(doc2);
     VariantClear(&v);
 
+    /* transform to document */
+    b = VARIANT_FALSE;
+    hr = IXMLDOMDocument_loadXML(doc2, _bstr_(szTransformXML), &b);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(b == VARIANT_TRUE, "got %d\n", b);
+
+    V_VT(&v) = VT_UNKNOWN;
+    V_UNKNOWN(&v) = (IUnknown*)doc2;
+    hr = IXSLProcessor_put_input(processor, v);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    doc3 = create_document(&IID_IXMLDOMDocument);
+    V_VT(&v) = VT_UNKNOWN;
+    V_UNKNOWN(&v) = (IUnknown *)doc3;
+    hr = IXSLProcessor_put_output(processor, v);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = IXMLDOMDocument_get_xml(doc3, &str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!*str, "Expected empty document\n");
+    SysFreeString(str);
+
+    hr = IXSLProcessor_transform(processor, &b);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    V_VT(&v) = VT_EMPTY;
+    hr = IXSLProcessor_get_output(processor, &v);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(V_VT(&v) == VT_UNKNOWN, "got type %d\n", V_VT(&v));
+    VariantClear(&v);
+
+    hr = IXMLDOMDocument_get_xml(doc3, &str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!!*str, "Expected document\n");
+    SysFreeString(str);
+
     IXSLProcessor_Release(processor);
+    IXMLDOMDocument_Release(doc2);
+    IXMLDOMDocument_Release(doc3);
 
     /* drop reference */
     hr = IXSLTemplate_putref_stylesheet(template, NULL);
-- 
2.11.0




More information about the wine-patches mailing list