>From b3e7f3bb09643b141766919b69dad3e62f502027 Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov@codeweavers.com>
Date: Fri, 9 Dec 2011 21:34:27 +0300
Subject: [PATCH 5/5] Properly handle writer output in a form of BSTR

---
 dlls/msxml3/mxwriter.c        |   87 ++++++++++++++++++++++++++---------------
 dlls/msxml3/tests/saxreader.c |   13 +++++-
 2 files changed, 65 insertions(+), 35 deletions(-)

diff --git a/dlls/msxml3/mxwriter.c b/dlls/msxml3/mxwriter.c
index f4e2960..febabe1 100644
--- a/dlls/msxml3/mxwriter.c
+++ b/dlls/msxml3/mxwriter.c
@@ -78,8 +78,8 @@ typedef struct _mxwriter
     IStream *dest;
     ULONG   dest_written;
 
-    INT decl_count;   /* practically how many times startDocument was called */
-    INT decl_written; /* byte length of document prolog */
+    int decl_count;   /* practically how many times startDocument was called */
+    int decl_written; /* byte length of document prolog */
 
     xmlOutputBufferPtr buffer;
 } mxwriter;
@@ -385,11 +385,6 @@ static HRESULT WINAPI mxwriter_put_output(IMXWriter *iface, VARIANT dest)
     {
         if (This->dest) IStream_Release(This->dest);
         This->dest = NULL;
-
-        /* We need to reset the output buffer to UTF-16, since the only way
-         * the content of the mxwriter can be accessed now is through a BSTR.
-         */
-        This->encoding = xmlParseCharEncoding("UTF-16");
         reset_output_buffer(This);
         break;
     }
@@ -427,48 +422,76 @@ static HRESULT WINAPI mxwriter_get_output(IMXWriter *iface, VARIANT *dest)
 
     if (!This->dest)
     {
-        BSTR output;
+        xmlOutputBufferPtr prolog;
+        BSTR output, body = NULL;
+        xmlBufferPtr buffer;
+        WCHAR *ptr;
         HRESULT hr;
+        int i;
 
         hr = flush_output_buffer(This);
         if (FAILED(hr))
             return hr;
 
-        /* TODO: Windows always seems to re-encode the XML to UTF-16 (this includes
-         * updating the XML decl so it says "UTF-16" instead of "UTF-8"). We don't
-         * support this yet...
-         */
-        if (This->encoding == XML_CHAR_ENCODING_UTF8) {
-            FIXME("XML re-encoding not supported yet\n");
-            return E_NOTIMPL;
+        if (This->decl_count)
+        {
+            prolog = xmlAllocOutputBuffer(xmlGetCharEncodingHandler(xmlParseCharEncoding("UTF-16")));
+            write_prolog_buffer(This, xmlParseCharEncoding("UTF-16"), prolog);
         }
+        else
+            prolog = NULL;
 
-        if (This->decl_count)
+        /* optimize some paticular cases */
+        /* 1. no prolog and UTF-8 buffer */
+        if (This->encoding == XML_CHAR_ENCODING_UTF8 && !prolog)
         {
-            xmlOutputBufferPtr prolog;
-            INT i = This->decl_count;
-            WCHAR *ptr;
+            V_VT(dest)   = VT_BSTR;
+            V_BSTR(dest) = bstr_from_xmlChar(This->buffer->buffer->content);
+            return S_OK;
+        }
 
-            prolog = xmlAllocOutputBuffer(xmlGetCharEncodingHandler(xmlParseCharEncoding("UTF-16")));
+        /* 2. no prolog and UTF-16 buffer */
+        if (!prolog)
+        {
+            V_VT(dest)   = VT_BSTR;
+            V_BSTR(dest) = SysAllocStringLen((const WCHAR*)This->buffer->conv->content,
+                This->buffer->conv->use/sizeof(WCHAR));
+            return S_OK;
+        }
 
-            write_prolog_buffer(This, xmlParseCharEncoding("UTF-16"), prolog);
+        V_BSTR(dest) = NULL;
 
+        if (This->encoding == XML_CHAR_ENCODING_UTF8)
+        {
+            buffer = This->buffer->buffer;
+            body = bstr_from_xmlChar(buffer->content+This->decl_written);
             ptr = output = SysAllocStringByteLen(NULL, prolog->conv->use*This->decl_count +
-                This->buffer->conv->use-This->decl_written);
-            while (i--)
-            {
-                memcpy(ptr, prolog->conv->content, prolog->conv->use);
-                ptr += prolog->conv->use/sizeof(WCHAR);
-            }
-
-            memcpy(ptr, This->buffer->conv->content + This->decl_written, This->buffer->conv->use-This->decl_written);
-            xmlOutputBufferClose(prolog);
+                SysStringByteLen(body));
         }
         else
         {
-            output = SysAllocStringLen((const WCHAR*)This->buffer->conv->content,
-                This->buffer->conv->use/sizeof(WCHAR));
+            buffer = This->buffer->conv;
+            ptr = output = SysAllocStringByteLen(NULL, prolog->conv->use*This->decl_count +
+                buffer->use - This->decl_written);
+        }
+
+        /* write prolog part */
+        i = This->decl_count;
+        while (i--)
+        {
+            memcpy(ptr, prolog->conv->content, prolog->conv->use);
+            ptr += prolog->conv->use/sizeof(WCHAR);
+        }
+        xmlOutputBufferClose(prolog);
+
+        /* write main part */
+        if (body)
+        {
+            memcpy(ptr, body, SysStringByteLen(body));
+            SysFreeString(body);
         }
+        else
+            memcpy(ptr, buffer->content + This->decl_written, buffer->use-This->decl_written);
 
         V_VT(dest)   = VT_BSTR;
         V_BSTR(dest) = output;
diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c
index 0fac3dd..d713fd3 100644
--- a/dlls/msxml3/tests/saxreader.c
+++ b/dlls/msxml3/tests/saxreader.c
@@ -2303,6 +2303,13 @@ static void test_mxwriter_startendelement(void)
     hr = IMXWriter_put_output(writer, dest);
     EXPECT_HR(hr, S_OK);
 
+    V_VT(&dest) = VT_EMPTY;
+    hr = IMXWriter_get_output(writer, &dest);
+    EXPECT_HR(hr, S_OK);
+    ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
+    ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
+    VariantClear(&dest);
+
     hr = ISAXContentHandler_startDocument(content);
     EXPECT_HR(hr, S_OK);
 
@@ -2615,9 +2622,9 @@ static void test_mxwriter_encoding(void)
      */
     V_VT(&dest) = VT_EMPTY;
     hr = IMXWriter_get_output(writer, &dest);
-    todo_wine ok(hr == S_OK, "get_output failed: %08x\n", hr);
-    todo_wine ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
-    if (V_VT(&dest) == VT_BSTR) todo_wine ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
+    EXPECT_HR(hr, S_OK);
+    ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
+    ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
             "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
     VariantClear(&dest);
 
-- 
1.5.6.5


