[Libreoffice-commits] core.git: Branch 'distro/vector/vector-5.4' - 3 commits - filter/source include/filter sw/CppunitTest_sw_htmlexport.mk sw/qa sw/source

Miklos Vajna vmiklos at collabora.co.uk
Wed Mar 28 15:23:09 UTC 2018


 filter/source/msfilter/rtfutil.cxx          |   32 ++++++++
 include/filter/msfilter/rtfutil.hxx         |    4 +
 sw/CppunitTest_sw_htmlexport.mk             |   37 ---------
 sw/qa/extras/htmlexport/htmlexport.cxx      |   22 +++++
 sw/qa/extras/htmlimport/htmlimport.cxx      |   17 ----
 sw/source/filter/html/htmlplug.cxx          |   45 ++++++++---
 sw/source/filter/html/htmlreqifreader.cxx   |  107 +++++++++++++++++++++++++++-
 sw/source/filter/html/htmlreqifreader.hxx   |    3 
 sw/source/filter/html/wrthtml.cxx           |   20 +++++
 sw/source/filter/ww8/rtfattributeoutput.cxx |   38 ---------
 sw/source/filter/ww8/rtfattributeoutput.hxx |    3 
 sw/source/filter/ww8/rtfsdrexport.cxx       |    4 -
 12 files changed, 227 insertions(+), 105 deletions(-)

New commits:
commit d6d6dfca7e694a9654d6bdcc048e88804cc0884e
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Mar 27 17:25:47 2018 +0200

    sw HTML paste: add debug env var to capture outgoing content
    
    Similar to existing SW_DEBUG_RTF_PASTE_TO.
    
    Change-Id: I5d6fe72929ab6ddd3e6e175ed344781fc4e3cb31
    Reviewed-on: https://gerrit.libreoffice.org/51961
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit af69f27e812a0e86d256e36154ecef9aaf43a32a)

diff --git a/sw/source/filter/html/wrthtml.cxx b/sw/source/filter/html/wrthtml.cxx
index 42ec9956ef9e..4db9122288b2 100644
--- a/sw/source/filter/html/wrthtml.cxx
+++ b/sw/source/filter/html/wrthtml.cxx
@@ -76,6 +76,8 @@
 #include <IDocumentStylePoolAccess.hxx>
 #include <xmloff/odffields.hxx>
 #include <tools/urlobj.hxx>
+#include <osl/file.hxx>
+#include <comphelper/scopeguard.hxx>
 
 #define MAX_INDENT_LEVEL 20
 
@@ -207,6 +209,24 @@ void SwHTMLWriter::SetupFilterOptions(SfxMedium& rMedium)
 
 sal_uLong SwHTMLWriter::WriteStream()
 {
+    // Intercept paste output if requested.
+    char* pPasteEnv = getenv("SW_DEBUG_HTML_PASTE_TO");
+    std::unique_ptr<SvStream> pPasteStream;
+    SvStream* pOldPasteStream = nullptr;
+    if (pPasteEnv)
+    {
+        OUString aPasteStr;
+        if (pPasteEnv
+            && osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(pPasteEnv), aPasteStr)
+                   == osl::FileBase::E_None)
+        {
+            pPasteStream.reset(new SvFileStream(aPasteStr, StreamMode::WRITE));
+            pOldPasteStream = &Strm();
+            SetStream(pPasteStream.get());
+        }
+    }
+    comphelper::ScopeGuard g([this, pOldPasteStream] { this->SetStream(pOldPasteStream); });
+
     SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
 
     // font heights 1-7
commit b5d51f341c7e1162062ac6adf193edddab2e71c5
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Mar 27 12:06:25 2018 +0200

    msfilter: extract duplicated WriteHex() from HTML/RTF filter
    
    The RtfAttributeOutput one is a superset of the HTML one, so use that.
    
    Reviewed-on: https://gerrit.libreoffice.org/51937
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 6d05579c7fceb0f3ce83abe25bdfe62b26c29671)
    
    Conflicts:
            sw/source/filter/ww8/rtfattributeoutput.cxx
            sw/source/filter/ww8/rtfattributeoutput.hxx
            sw/source/filter/ww8/rtfsdrexport.cxx
    
    Change-Id: I3e342113a7ba26946320f43a164e457d6cbb6946

diff --git a/filter/source/msfilter/rtfutil.cxx b/filter/source/msfilter/rtfutil.cxx
index b209f70a3a3c..57f7ca7ff14b 100644
--- a/filter/source/msfilter/rtfutil.cxx
+++ b/filter/source/msfilter/rtfutil.cxx
@@ -201,6 +201,38 @@ int AsHex(char ch)
     return ret;
 }
 
+OString WriteHex(const sal_uInt8* pData, sal_uInt32 nSize, SvStream* pStream, sal_uInt32 nLimit)
+{
+    OStringBuffer aRet;
+
+    sal_uInt32 nBreak = 0;
+    for (sal_uInt32 i = 0; i < nSize; i++)
+    {
+        OString sNo = OString::number(pData[i], 16);
+        if (sNo.getLength() < 2)
+        {
+            if (pStream)
+                pStream->WriteChar('0');
+            else
+                aRet.append('0');
+        }
+        if (pStream)
+            pStream->WriteCharPtr(sNo.getStr());
+        else
+            aRet.append(sNo);
+        if (++nBreak == nLimit)
+        {
+            if (pStream)
+                pStream->WriteCharPtr(SAL_NEWLINE_STRING);
+            else
+                aRet.append(SAL_NEWLINE_STRING);
+            nBreak = 0;
+        }
+    }
+
+    return aRet.makeStringAndClear();
+}
+
 bool ExtractOLE2FromObjdata(const OString& rObjdata, SvStream& rOle2)
 {
     SvMemoryStream aStream;
diff --git a/include/filter/msfilter/rtfutil.hxx b/include/filter/msfilter/rtfutil.hxx
index 18c38adf7842..f4699169143a 100644
--- a/include/filter/msfilter/rtfutil.hxx
+++ b/include/filter/msfilter/rtfutil.hxx
@@ -58,6 +58,10 @@ MSFILTER_DLLPUBLIC OString OutStringUpr(const sal_Char *pToken, const OUString &
  */
 MSFILTER_DLLPUBLIC int AsHex(char ch);
 
+/// Writes binary data as a hex dump.
+MSFILTER_DLLPUBLIC OString WriteHex(const sal_uInt8* pData, sal_uInt32 nSize,
+                                    SvStream* pStream = nullptr, sal_uInt32 nLimit = 64);
+
 /**
  * Extract OLE2 data from an \objdata hex dump.
  */
diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx
index 2a4519119e31..077483ab158b 100644
--- a/sw/source/filter/html/htmlreqifreader.cxx
+++ b/sw/source/filter/html/htmlreqifreader.cxx
@@ -130,30 +130,6 @@ OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1)
 
     return aClassName;
 }
-
-/// Writes rData on rSteram as a hexdump.
-void WriteHex(SvStream& rStream, SvMemoryStream& rData)
-{
-    rData.Seek(0);
-    sal_uInt64 nSize = rData.remainingSize();
-
-    sal_uInt32 nLimit = 64;
-    sal_uInt32 nBreak = 0;
-
-    for (sal_uInt64 i = 0; i < nSize; i++)
-    {
-        OString sNo = OString::number(static_cast<const sal_uInt8*>(rData.GetBuffer())[i], 16);
-        if (sNo.getLength() < 2)
-            rStream.WriteChar('0');
-        rStream.WriteCharPtr(sNo.getStr());
-
-        if (++nBreak == nLimit)
-        {
-            rStream.WriteCharPtr(SAL_NEWLINE_STRING);
-            nBreak = 0;
-        }
-    }
-}
 }
 
 namespace SwReqIfReader
@@ -199,7 +175,8 @@ bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf)
     // Start objdata.
     rRtf.WriteCharPtr(
         "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJDATA SAL_NEWLINE_STRING);
-    WriteHex(rRtf, aOLE1);
+    msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOLE1.GetData()), aOLE1.GetSize(),
+                                &rRtf);
     // End objdata.
     rRtf.WriteCharPtr("}");
     // End object.
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx
index 5aedd6721559..134eb1735d69 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -3681,38 +3681,6 @@ static bool StripMetafileHeader(const sal_uInt8*& rpGraphicAry, unsigned long& r
     return false;
 }
 
-OString RtfAttributeOutput::WriteHex(const sal_uInt8* pData, sal_uInt32 nSize, SvStream* pStream, sal_uInt32 nLimit)
-{
-    OStringBuffer aRet;
-
-    sal_uInt32 nBreak = 0;
-    for (sal_uInt32 i = 0; i < nSize; i++)
-    {
-        OString sNo = OString::number(pData[i], 16);
-        if (sNo.getLength() < 2)
-        {
-            if (pStream)
-                pStream->WriteChar('0');
-            else
-                aRet.append('0');
-        }
-        if (pStream)
-            pStream->WriteCharPtr(sNo.getStr());
-        else
-            aRet.append(sNo);
-        if (++nBreak == nLimit)
-        {
-            if (pStream)
-                pStream->WriteCharPtr(SAL_NEWLINE_STRING);
-            else
-                aRet.append(SAL_NEWLINE_STRING);
-            nBreak = 0;
-        }
-    }
-
-    return aRet.makeStringAndClear();
-}
-
 static void lcl_AppendSP(OStringBuffer& rBuffer,
                          const char cName[],
                          const OUString& rValue,
@@ -3795,9 +3763,9 @@ static OString ExportPICT(const SwFlyFrameFormat* pFlyFrameFormat, const Size& r
         if (pStream)
             pStream->WriteCharPtr(aRet.makeStringAndClear().getStr());
         if (pStream)
-            RtfAttributeOutput::WriteHex(pGraphicAry, nSize, pStream);
+            msfilter::rtfutil::WriteHex(pGraphicAry, nSize, pStream);
         else
-            aRet.append(RtfAttributeOutput::WriteHex(pGraphicAry, nSize));
+            aRet.append(msfilter::rtfutil::WriteHex(pGraphicAry, nSize));
         aRet.append('}');
         if (pStream)
             pStream->WriteCharPtr(aRet.makeStringAndClear().getStr());
@@ -4090,7 +4058,7 @@ void RtfAttributeOutput::BulletDefinition(int /*nId*/, const Graphic& rGraphic,
     aStream.Seek(STREAM_SEEK_TO_END);
     sal_uInt32 nSize = aStream.Tell();
     pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
-    RtfAttributeOutput::WriteHex(pGraphicAry, nSize, &m_rExport.Strm());
+    msfilter::rtfutil::WriteHex(pGraphicAry, nSize, &m_rExport.Strm());
     m_rExport.Strm().WriteCharPtr("}}");   // pict, shppict
 }
 
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx
index 23e8466681da..1d2027433c95 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -636,9 +636,6 @@ public:
     /// Font pitch.
     void FontPitchType(FontPitch ePitch) const;
 
-    /// Writes binary data as a hex dump.
-    static OString WriteHex(const sal_uInt8* pData, sal_uInt32 nSize, SvStream* pStream = nullptr, sal_uInt32 nLimit = 64);
-
     void BulletDefinition(int nId, const Graphic& rGraphic, Size aSize) override;
 
     /// Handles just the {\shptxt ...} part of a shape export.
diff --git a/sw/source/filter/ww8/rtfsdrexport.cxx b/sw/source/filter/ww8/rtfsdrexport.cxx
index cb5f2c1a90c5..af01b408ac03 100644
--- a/sw/source/filter/ww8/rtfsdrexport.cxx
+++ b/sw/source/filter/ww8/rtfsdrexport.cxx
@@ -393,7 +393,7 @@ void RtfSdrExport::Commit(EscherPropertyContainer& rProps, const tools::Rectangl
             OStringBuffer aBuf;
             aBuf.append('{').append(OOO_STRING_SVTOOLS_RTF_PICT).append(OOO_STRING_SVTOOLS_RTF_PNGBLIP).append(SAL_NEWLINE_STRING);
             int nHeaderSize = 25; // The first bytes are WW8-specific, we're only interested in the PNG
-            aBuf.append(RtfAttributeOutput::WriteHex(rOpt.pBuf + nHeaderSize, rOpt.nPropSize - nHeaderSize));
+            aBuf.append(msfilter::rtfutil::WriteHex(rOpt.pBuf + nHeaderSize, rOpt.nPropSize - nHeaderSize));
             aBuf.append('}');
             m_aShapeProps.insert(std::pair<OString,OString>("fillBlip", aBuf.makeStringAndClear()));
         }
@@ -485,7 +485,7 @@ void RtfSdrExport::impl_writeGraphic()
     aBuf->append('{').append(OOO_STRING_SVTOOLS_RTF_PICT).append(OOO_STRING_SVTOOLS_RTF_PNGBLIP);
     aBuf->append(OOO_STRING_SVTOOLS_RTF_PICW).append(sal_Int32(aMapped.Width()));
     aBuf->append(OOO_STRING_SVTOOLS_RTF_PICH).append(sal_Int32(aMapped.Height())).append(SAL_NEWLINE_STRING);
-    aBuf->append(RtfAttributeOutput::WriteHex(pGraphicAry, nSize));
+    aBuf->append(msfilter::rtfutil::WriteHex(pGraphicAry, nSize));
     aBuf->append('}');
     m_aShapeProps.insert(std::pair<OString,OString>("pib", aBuf.makeStringAndClear()));
 }
commit 743ce5979124d28ee10a566f1462dbb67c8cd5af
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Mon Mar 26 16:25:06 2018 +0200

    sw XHTML export: support OLE2-in-RTF objects
    
    Need to repeat what OLE1 calls the class name in the OLE1 and RTF
    wrappers, so parse our own OLE2 data during export.
    
    Reviewed-on: https://gerrit.libreoffice.org/51906
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 04630f26d06c4d3ec22b2a8b97e6a5e69cc70d5e)
    
    Conflicts:
            sw/CppunitTest_sw_htmlexport.mk
    
    Change-Id: Ic14fa648d1f78c29579bd9ba49ce6f491d4541b5

diff --git a/sw/CppunitTest_sw_htmlexport.mk b/sw/CppunitTest_sw_htmlexport.mk
index c9934c5b5bf9..4dabbe61606f 100644
--- a/sw/CppunitTest_sw_htmlexport.mk
+++ b/sw/CppunitTest_sw_htmlexport.mk
@@ -48,42 +48,7 @@ $(eval $(call gb_CppunitTest_use_sdk_api,sw_htmlexport))
 $(eval $(call gb_CppunitTest_use_ure,sw_htmlexport))
 $(eval $(call gb_CppunitTest_use_vcl,sw_htmlexport))
 
-$(eval $(call gb_CppunitTest_use_components,sw_htmlexport,\
-	basic/util/sb \
-	canvas/source/factory/canvasfactory \
-    comphelper/util/comphelp \
-    configmgr/source/configmgr \
-    dbaccess/util/dba \
-    embeddedobj/util/embobj \
-    filter/source/config/cache/filterconfig1 \
-    filter/source/storagefilterdetect/storagefd \
-    filter/source/textfilterdetect/textfd \
-	forms/util/frm \
-    framework/util/fwk \
-    i18npool/util/i18npool \
-    linguistic/source/lng \
-    oox/util/oox \
-    package/source/xstor/xstor \
-	sc/util/sc \
-	sc/util/scfilt \
-    package/util/package2 \
-    sax/source/expatwrap/expwrap \
-    sw/util/sw \
-    sw/util/swd \
-    sw/util/msword \
-    sfx2/util/sfx \
-    starmath/util/sm \
-    svl/source/fsstor/fsstorage \
-    svtools/util/svt \
-    toolkit/util/tk \
-    ucb/source/core/ucb1 \
-    ucb/source/ucp/file/ucpfile1 \
-    unotools/util/utl \
-    unoxml/source/service/unoxml \
-    uui/util/uui \
-    writerfilter/util/writerfilter \
-    xmloff/util/xo \
-))
+$(eval $(call gb_CppunitTest_use_rdb,sw_htmlexport,services))
 
 $(eval $(call gb_CppunitTest_use_configuration,sw_htmlexport))
 
diff --git a/sw/qa/extras/htmlimport/data/ole2.ole b/sw/qa/extras/htmlexport/data/ole2.ole
similarity index 100%
rename from sw/qa/extras/htmlimport/data/ole2.ole
rename to sw/qa/extras/htmlexport/data/ole2.ole
diff --git a/sw/qa/extras/htmlimport/data/ole2.png b/sw/qa/extras/htmlexport/data/ole2.png
similarity index 100%
rename from sw/qa/extras/htmlimport/data/ole2.png
rename to sw/qa/extras/htmlexport/data/ole2.png
diff --git a/sw/qa/extras/htmlimport/data/reqif-ole2.xhtml b/sw/qa/extras/htmlexport/data/reqif-ole2.xhtml
similarity index 100%
rename from sw/qa/extras/htmlimport/data/reqif-ole2.xhtml
rename to sw/qa/extras/htmlexport/data/reqif-ole2.xhtml
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index 0cac2dad965c..8072e530859d 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -14,6 +14,8 @@
 #include <com/sun/star/drawing/FillStyle.hpp>
 #include <com/sun/star/document/XEmbeddedObjectSupplier2.hpp>
 #include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/io/XActiveDataStreamer.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
 #include <rtl/byteseq.hxx>
 
 #include <swmodule.hxx>
@@ -476,6 +478,26 @@ DECLARE_HTMLEXPORT_TEST(testReqIfTable, "reqif-table.xhtml")
     assertXPathNoAttribute(pDoc, "/html/body/div/table/tr/th", "bgcolor");
 }
 
+DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testReqIfOle2, "reqif-ole2.xhtml")
+{
+    uno::Reference<text::XTextEmbeddedObjectsSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> xObjects(xSupplier->getEmbeddedObjects(),
+                                                     uno::UNO_QUERY);
+    uno::Reference<document::XEmbeddedObjectSupplier2> xObject(xObjects->getByIndex(0),
+                                                               uno::UNO_QUERY);
+    uno::Reference<io::XActiveDataStreamer> xEmbeddedObject(xObject->getExtendedControlOverEmbeddedObject(), uno::UNO_QUERY);
+    // This failed, the "RTF fragment" native data was loaded as-is, we had no
+    // filter to handle it, so nothing happened on double-click.
+    CPPUNIT_ASSERT(xEmbeddedObject.is());
+    uno::Reference<io::XSeekable> xStream(xEmbeddedObject->getStream(), uno::UNO_QUERY);
+    // This was 80913, the RTF hexdump -> OLE1 binary -> OLE2 conversion was
+    // missing.
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int64>(38912), xStream->getLength());
+    // Finally the export also failed as it tried to open the stream from the
+    // document storage, but the embedded object already opened it, so an
+    // exception of type com.sun.star.io.IOException was thrown.
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/htmlimport/htmlimport.cxx b/sw/qa/extras/htmlimport/htmlimport.cxx
index 9c5e2ce63aa8..02e2417a2b0e 100644
--- a/sw/qa/extras/htmlimport/htmlimport.cxx
+++ b/sw/qa/extras/htmlimport/htmlimport.cxx
@@ -251,23 +251,6 @@ DECLARE_HTMLIMPORT_TEST(testReqIfBr, "reqif-br.xhtml")
     CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("aaa\nbbb"));
 }
 
-DECLARE_HTMLIMPORT_TEST(testReqIfOle2, "reqif-ole2.xhtml")
-{
-    uno::Reference<text::XTextEmbeddedObjectsSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
-    uno::Reference<container::XIndexAccess> xObjects(xSupplier->getEmbeddedObjects(),
-                                                     uno::UNO_QUERY);
-    uno::Reference<document::XEmbeddedObjectSupplier2> xObject(xObjects->getByIndex(0),
-                                                               uno::UNO_QUERY);
-    uno::Reference<io::XActiveDataStreamer> xEmbeddedObject(xObject->getExtendedControlOverEmbeddedObject(), uno::UNO_QUERY);
-    // This failed, the "RTF fragment" native data was loaded as-is, we had no
-    // filter to handle it, so nothing happened on double-click.
-    CPPUNIT_ASSERT(xEmbeddedObject.is());
-    uno::Reference<io::XSeekable> xStream(xEmbeddedObject->getStream(), uno::UNO_QUERY);
-    // This was 80913, the RTF hexdump -> OLE1 binary -> OLE2 conversion was
-    // missing.
-    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int64>(38912), xStream->getLength());
-}
-
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx
index 8ffc189d3446..68ad0c0be432 100644
--- a/sw/source/filter/html/htmlplug.cxx
+++ b/sw/source/filter/html/htmlplug.cxx
@@ -61,12 +61,14 @@
 #include <com/sun/star/beans/XPropertySet.hpp>
 #include <com/sun/star/frame/XStorable.hpp>
 #include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/io/XActiveDataStreamer.hpp>
 
 #include <comphelper/embeddedobjectcontainer.hxx>
 #include <comphelper/classids.hxx>
 #include <rtl/uri.hxx>
 #include <comphelper/storagehelper.hxx>
 #include <vcl/graphicfilter.hxx>
+#include <unotools/ucbstreamhelper.hxx>
 
 using namespace com::sun::star;
 
@@ -1453,19 +1455,40 @@ Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFrame
         aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
 
         // Write the data.
-        OUString aStreamName = pOLENd->GetOLEObj().GetCurrentPersistName();
-        uno::Reference<embed::XStorage> xStorage = pDocSh->GetStorage();
-        uno::Reference<io::XStream> xInStream
-            = xStorage->openStreamElement(aStreamName, embed::ElementModes::READ);
+        SwOLEObj& rOLEObj = pOLENd->GetOLEObj();
+        uno::Reference<embed::XEmbeddedObject> xEmbeddedObject = rOLEObj.GetOleRef();
+        OUString aFileType;
         SvFileStream aOutStream(aFileName, StreamMode::WRITE);
-        uno::Reference<io::XStream> xOutStream(new utl::OStreamWrapper(aOutStream));
-        comphelper::OStorageHelper::CopyInputToOutput(xInStream->getInputStream(),
-                                                      xOutStream->getOutputStream());
+        uno::Reference<io::XActiveDataStreamer> xStreamProvider;
+        if (xEmbeddedObject.is())
+            xStreamProvider.set(xEmbeddedObject, uno::UNO_QUERY);
+        if (xStreamProvider.is())
+        {
+            uno::Reference<io::XInputStream> xStream(xStreamProvider->getStream(), uno::UNO_QUERY);
+            if (xStream.is())
+            {
+                std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xStream));
+                if (SwReqIfReader::WrapOleInRtf(*pStream, aOutStream))
+                {
+                    // OLE2 is always wrapped in RTF.
+                    aFileType = "text/rtf";
+                }
+            }
+        }
+        else
+        {
+            OUString aStreamName = rOLEObj.GetCurrentPersistName();
+            uno::Reference<embed::XStorage> xStorage = pDocSh->GetStorage();
+            uno::Reference<io::XStream> xInStream
+                = xStorage->openStreamElement(aStreamName, embed::ElementModes::READ);
+            uno::Reference<io::XStream> xOutStream(new utl::OStreamWrapper(aOutStream));
+            comphelper::OStorageHelper::CopyInputToOutput(xInStream->getInputStream(),
+                                                          xOutStream->getOutputStream());
+            uno::Reference<beans::XPropertySet> xOutStreamProps(xInStream, uno::UNO_QUERY);
+            if (xOutStreamProps.is())
+                xOutStreamProps->getPropertyValue("MediaType") >>= aFileType;
+        }
         aFileName = URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), aFileName);
-        uno::Reference<beans::XPropertySet> xOutStreamProps(xInStream, uno::UNO_QUERY);
-        OUString aFileType;
-        if (xOutStreamProps.is())
-            xOutStreamProps->getPropertyValue("MediaType") >>= aFileType;
 
         // Refer to this data.
         if (rHTMLWrt.m_bLFPossible)
diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx
index eef33d93b293..2a4519119e31 100644
--- a/sw/source/filter/html/htmlreqifreader.cxx
+++ b/sw/source/filter/html/htmlreqifreader.cxx
@@ -9,12 +9,15 @@
 
 #include "htmlreqifreader.hxx"
 
+#include <comphelper/scopeguard.hxx>
+#include <filter/msfilter/rtfutil.hxx>
 #include <rtl/character.hxx>
 #include <rtl/strbuf.hxx>
+#include <sot/storage.hxx>
 #include <svtools/parrtf.hxx>
+#include <svtools/rtfkeywd.hxx>
 #include <svtools/rtftoken.h>
 #include <tools/stream.hxx>
-#include <filter/msfilter/rtfutil.hxx>
 
 namespace
 {
@@ -57,6 +60,100 @@ bool ReqIfRtfReader::WriteObjectData(SvStream& rOLE)
 {
     return msfilter::rtfutil::ExtractOLE2FromObjdata(m_aHex.makeStringAndClear(), rOLE);
 }
+
+/// Looks up what OLE1 calls the ClassName, see [MS-OLEDS] 2.3.8 CompObjStream.
+OString ExtractOLEClassName(const tools::SvRef<SotStorage>& xStorage)
+{
+    OString aRet;
+
+    SotStorageStream* pCompObj = xStorage->OpenSotStream("\1CompObj");
+    if (!pCompObj)
+        return aRet;
+
+    pCompObj->Seek(0);
+    pCompObj->SeekRel(28); // Header
+    if (!pCompObj->good())
+        return aRet;
+
+    sal_uInt32 nData;
+    pCompObj->ReadUInt32(nData); // AnsiUserType
+    pCompObj->SeekRel(nData);
+    if (!pCompObj->good())
+        return aRet;
+
+    pCompObj->ReadUInt32(nData); // AnsiClipboardFormat
+    pCompObj->SeekRel(nData);
+    if (!pCompObj->good())
+        return aRet;
+
+    pCompObj->ReadUInt32(nData); // Reserved1
+    return read_uInt8s_ToOString(*pCompObj, nData);
+}
+
+/// Inserts an OLE1 header before an OLE2 storage.
+OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1)
+{
+    rOle2.Seek(0);
+    tools::SvRef<SotStorage> xStorage(new SotStorage(rOle2));
+    if (xStorage->GetError() != ERRCODE_NONE)
+        return OString();
+
+    OString aClassName = ExtractOLEClassName(xStorage);
+
+    // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
+    rOle1.Seek(0);
+    // OLEVersion.
+    rOle1.WriteUInt32(0);
+
+    // FormatID is EmbeddedObject.
+    rOle1.WriteUInt32(0x00000002);
+
+    // ClassName
+    rOle1.WriteUInt32(aClassName.getLength());
+    rOle1.WriteOString(aClassName);
+    // Null terminated pascal string.
+    rOle1.WriteChar(0);
+
+    // TopicName.
+    rOle1.WriteUInt32(0);
+
+    // ItemName.
+    rOle1.WriteUInt32(0);
+
+    // NativeDataSize
+    rOle2.Seek(STREAM_SEEK_TO_END);
+    rOle1.WriteUInt32(rOle2.Tell());
+
+    // Write the actual native data.
+    rOle2.Seek(0);
+    rOle1.WriteStream(rOle2);
+
+    return aClassName;
+}
+
+/// Writes rData on rSteram as a hexdump.
+void WriteHex(SvStream& rStream, SvMemoryStream& rData)
+{
+    rData.Seek(0);
+    sal_uInt64 nSize = rData.remainingSize();
+
+    sal_uInt32 nLimit = 64;
+    sal_uInt32 nBreak = 0;
+
+    for (sal_uInt64 i = 0; i < nSize; i++)
+    {
+        OString sNo = OString::number(static_cast<const sal_uInt8*>(rData.GetBuffer())[i], 16);
+        if (sNo.getLength() < 2)
+            rStream.WriteChar('0');
+        rStream.WriteCharPtr(sNo.getStr());
+
+        if (++nBreak == nLimit)
+        {
+            rStream.WriteCharPtr(SAL_NEWLINE_STRING);
+            nBreak = 0;
+        }
+    }
+}
 }
 
 namespace SwReqIfReader
@@ -79,6 +176,37 @@ bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle)
     // Write the OLE2 data.
     return xReader->WriteObjectData(rOle);
 }
+
+bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf)
+{
+    sal_uInt64 nPos = rOle2.Tell();
+    comphelper::ScopeGuard g([&rOle2, nPos] { rOle2.Seek(nPos); });
+
+    // Write OLE1 header, then the RTF wrapper.
+    SvMemoryStream aOLE1;
+    OString aClassName = InsertOLE1Header(rOle2, aOLE1);
+
+    // Start object.
+    rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_OBJECT);
+    rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_OBJEMB);
+
+    // Start objclass.
+    rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJCLASS " ");
+    rRtf.WriteOString(aClassName);
+    // End objclass.
+    rRtf.WriteCharPtr("}");
+
+    // Start objdata.
+    rRtf.WriteCharPtr(
+        "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJDATA SAL_NEWLINE_STRING);
+    WriteHex(rRtf, aOLE1);
+    // End objdata.
+    rRtf.WriteCharPtr("}");
+    // End object.
+    rRtf.WriteCharPtr("}");
+
+    return true;
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlreqifreader.hxx b/sw/source/filter/html/htmlreqifreader.hxx
index 97d391a8efb0..ad8399edbf0e 100644
--- a/sw/source/filter/html/htmlreqifreader.hxx
+++ b/sw/source/filter/html/htmlreqifreader.hxx
@@ -15,6 +15,9 @@ namespace SwReqIfReader
 {
 /// Extracts an OLE2 container binary from an RTF fragment.
 bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle);
+
+/// Wraps an OLE2 container binary in an RTF fragment.
+bool WrapOleInRtf(SvStream& rOle, SvStream& rRtf);
 }
 
 #endif // INCLUDED_SW_SOURCE_FILTER_HTML_HTMLREQIFREADER_HXX


More information about the Libreoffice-commits mailing list