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 <vmik...@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 <vmik...@collabora.co.uk> Tested-by: Jenkins <c...@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 <vmik...@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 <vmik...@collabora.co.uk> Tested-by: Jenkins <c...@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 <vmik...@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 <vmik...@collabora.co.uk> Tested-by: Jenkins <c...@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 _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits