Kaydet (Commit) 0258bcde authored tarafından Miklos Vajna's avatar Miklos Vajna

sw HTML filter: handle embedded ODF content in xhtml/reqif mode

Embedded native data (what we don't parse just carry on) and real OLE2
embedding already worked, this adds the case where the actual content is
ODF, just inside OLE2.

The DOC import/export had support for handleing ODF content inside OLE2,
so reuse that code: add new functions to SvxMSDffManager for import
purposes and reuse SvxMSExportOLEObjects for export purposes.

Change-Id: I0acf65d4bf29af896b8f1dd625e8672050aae350
Reviewed-on: https://gerrit.libreoffice.org/55088Reviewed-by: 's avatarMiklos Vajna <vmiklos@collabora.co.uk>
Tested-by: 's avatarJenkins <ci@libreoffice.org>
üst 46ac3e24
...@@ -106,6 +106,10 @@ public: ...@@ -106,6 +106,10 @@ public:
class OleComponent; class OleComponent;
class OwnView_Impl; class OwnView_Impl;
/**
* Represents an OLE object that has native data and we try to let an external
* application handle that data.
*/
class OleEmbeddedObject : public ::cppu::WeakImplHelper class OleEmbeddedObject : public ::cppu::WeakImplHelper
< css::embed::XEmbeddedObject < css::embed::XEmbeddedObject
, css::embed::XEmbeddedOleObject , css::embed::XEmbeddedOleObject
......
...@@ -6936,7 +6936,7 @@ const char* GetInternalServerName_Impl( const SvGlobalName& aGlobName ) ...@@ -6936,7 +6936,7 @@ const char* GetInternalServerName_Impl( const SvGlobalName& aGlobName )
return nullptr; return nullptr;
} }
OUString GetFilterNameFromClassID_Impl( const SvGlobalName& aGlobName ) OUString SvxMSDffManager::GetFilterNameFromClassID( const SvGlobalName& aGlobName )
{ {
if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 ) ) if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 ) )
return OUString( "StarOffice XML (Writer)" ); return OUString( "StarOffice XML (Writer)" );
...@@ -6977,6 +6977,13 @@ OUString GetFilterNameFromClassID_Impl( const SvGlobalName& aGlobName ) ...@@ -6977,6 +6977,13 @@ OUString GetFilterNameFromClassID_Impl( const SvGlobalName& aGlobName )
return OUString(); return OUString();
} }
void SvxMSDffManager::ExtractOwnStream(SotStorage& rSrcStg, SvMemoryStream& rMemStream)
{
tools::SvRef<SotStorageStream> xStr
= rSrcStg.OpenSotStream("package_stream", StreamMode::STD_READ);
xStr->ReadStream(rMemStream);
}
css::uno::Reference < css::embed::XEmbeddedObject > SvxMSDffManager::CheckForConvertToSOObj( sal_uInt32 nConvertFlags, css::uno::Reference < css::embed::XEmbeddedObject > SvxMSDffManager::CheckForConvertToSOObj( sal_uInt32 nConvertFlags,
SotStorage& rSrcStg, const uno::Reference < embed::XStorage >& rDestStorage, SotStorage& rSrcStg, const uno::Reference < embed::XStorage >& rDestStorage,
const Graphic& rGrf, const Graphic& rGrf,
...@@ -7041,8 +7048,7 @@ css::uno::Reference < css::embed::XEmbeddedObject > SvxMSDffManager::CheckForCo ...@@ -7041,8 +7048,7 @@ css::uno::Reference < css::embed::XEmbeddedObject > SvxMSDffManager::CheckForCo
if ( pName ) if ( pName )
{ {
// TODO/LATER: perhaps we need to retrieve VisArea and Metafile from the storage also // TODO/LATER: perhaps we need to retrieve VisArea and Metafile from the storage also
tools::SvRef<SotStorageStream> xStr = rSrcStg.OpenSotStream( "package_stream", StreamMode::STD_READ ); SvxMSDffManager::ExtractOwnStream(rSrcStg, *xMemStream);
xStr->ReadStream( *xMemStream );
} }
else else
{ {
...@@ -7077,7 +7083,7 @@ css::uno::Reference < css::embed::XEmbeddedObject > SvxMSDffManager::CheckForCo ...@@ -7077,7 +7083,7 @@ css::uno::Reference < css::embed::XEmbeddedObject > SvxMSDffManager::CheckForCo
if ( pFilter ) if ( pFilter )
aFilterName = pFilter->GetName(); aFilterName = pFilter->GetName();
else else
aFilterName = GetFilterNameFromClassID_Impl( aStgNm ); aFilterName = SvxMSDffManager::GetFilterNameFromClassID( aStgNm );
uno::Sequence<beans::PropertyValue> aMedium(aFilterName.isEmpty() ? 3 : 4); uno::Sequence<beans::PropertyValue> aMedium(aFilterName.isEmpty() ? 3 : 4);
aMedium[0].Name = "InputStream"; aMedium[0].Name = "InputStream";
......
...@@ -65,6 +65,7 @@ struct SvxMSDffShapeOrder; ...@@ -65,6 +65,7 @@ struct SvxMSDffShapeOrder;
class SvxMSDffManager; class SvxMSDffManager;
class SfxItemSet; class SfxItemSet;
struct DffObjData; struct DffObjData;
class SvGlobalName;
namespace com { namespace sun { namespace star { namespace com { namespace sun { namespace star {
namespace beans { class XPropertySet; } namespace beans { class XPropertySet; }
...@@ -735,6 +736,11 @@ public: ...@@ -735,6 +736,11 @@ public:
const OUString& rPropertyName const OUString& rPropertyName
); );
/// Determines an ODF filter name (if there is one) for aGlobName.
static OUString GetFilterNameFromClassID(const SvGlobalName& aGlobName);
/// Extracts ODF data from rSrcStg.
static void ExtractOwnStream(SotStorage& rSrcStg, SvMemoryStream& rMemStream);
void insertShapeId( sal_Int32 nShapeId, SdrObject* pShape ); void insertShapeId( sal_Int32 nShapeId, SdrObject* pShape );
void removeShapeId( SdrObject const * pShape ); void removeShapeId( SdrObject const * pShape );
SdrObject* getShapeForId( sal_Int32 nShapeId ); SdrObject* getShapeForId( sal_Int32 nShapeId );
......
This diff is collapsed.
<reqif-xhtml:div><reqif-xhtml:p><reqif-xhtml:br/>
</reqif-xhtml:p>
<reqif-xhtml:p><reqif-xhtml:object data="reqif-ole-odg.ole" type="text/rtf">
<reqif-xhtml:object data="reqif-ole-odg.png" type="image/png" width="533" height="378"/>
</reqif-xhtml:object><reqif-xhtml:br/>
</reqif-xhtml:p>
</reqif-xhtml:div>
...@@ -529,6 +529,21 @@ DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testReqIfOle2, "reqif-ole2.xhtml") ...@@ -529,6 +529,21 @@ DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testReqIfOle2, "reqif-ole2.xhtml")
// exception of type com.sun.star.io.IOException was thrown. // exception of type com.sun.star.io.IOException was thrown.
} }
DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testReqIfOle2Odg, "reqif-ole-odg.xhtml")
{
uno::Reference<text::XTextEmbeddedObjectsSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<container::XIndexAccess> xObjects(xSupplier->getEmbeddedObjects(),
uno::UNO_QUERY);
uno::Reference<document::XEmbeddedObjectSupplier> xTextEmbeddedObject(xObjects->getByIndex(0),
uno::UNO_QUERY);
uno::Reference<lang::XServiceInfo> xObject(xTextEmbeddedObject->getEmbeddedObject(),
uno::UNO_QUERY);
// This failed, both import and export failed to handle OLE2 that contains
// just ODF.
CPPUNIT_ASSERT(xObject.is());
CPPUNIT_ASSERT(xObject->supportsService("com.sun.star.drawing.DrawingDocument"));
}
DECLARE_HTMLEXPORT_TEST(testList, "list.html") DECLARE_HTMLEXPORT_TEST(testList, "list.html")
{ {
SvStream* pStream = maTempFile.GetStream(StreamMode::READ); SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
......
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
#include <com/sun/star/frame/XStorable.hpp> #include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/embed/ElementModes.hpp> #include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/io/XActiveDataStreamer.hpp> #include <com/sun/star/io/XActiveDataStreamer.hpp>
#include <com/sun/star/embed/XEmbedPersist2.hpp>
#include <comphelper/embeddedobjectcontainer.hxx> #include <comphelper/embeddedobjectcontainer.hxx>
#include <comphelper/classids.hxx> #include <comphelper/classids.hxx>
...@@ -69,6 +70,8 @@ ...@@ -69,6 +70,8 @@
#include <comphelper/storagehelper.hxx> #include <comphelper/storagehelper.hxx>
#include <vcl/graphicfilter.hxx> #include <vcl/graphicfilter.hxx>
#include <unotools/ucbstreamhelper.hxx> #include <unotools/ucbstreamhelper.hxx>
#include <comphelper/propertysequence.hxx>
#include <filter/msfilter/msoleexp.hxx>
using namespace com::sun::star; using namespace com::sun::star;
...@@ -508,11 +511,23 @@ bool SwHTMLParser::InsertEmbed() ...@@ -508,11 +511,23 @@ bool SwHTMLParser::InsertEmbed()
aFileStream.Seek(0); aFileStream.Seek(0);
if (aHeader == aMagic) if (aHeader == aMagic)
{ {
// OLE2 wrapped in RTF. // OLE2 wrapped in RTF: either own format or real OLE2 embedding.
if (SwReqIfReader::ExtractOleFromRtf(aFileStream, aMemoryStream)) bool bOwnFormat = false;
if (SwReqIfReader::ExtractOleFromRtf(aFileStream, aMemoryStream, bOwnFormat))
{ {
xInStream.set(new utl::OStreamWrapper(aMemoryStream)); xInStream.set(new utl::OStreamWrapper(aMemoryStream));
}
if (bOwnFormat)
{
uno::Sequence<beans::PropertyValue> aMedium = comphelper::InitPropertySequence(
{ { "InputStream", uno::makeAny(xInStream) },
{ "URL", uno::makeAny(OUString("private:stream")) },
{ "DocumentBaseURL", uno::makeAny(m_sBaseURL) } });
xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &m_sBaseURL);
}
else
{
// The type is now an OLE2 container, not the original XHTML type. // The type is now an OLE2 container, not the original XHTML type.
aType = "application/vnd.sun.star.oleobject"; aType = "application/vnd.sun.star.oleobject";
} }
...@@ -523,19 +538,24 @@ bool SwHTMLParser::InsertEmbed() ...@@ -523,19 +538,24 @@ bool SwHTMLParser::InsertEmbed()
// Non-RTF case. // Non-RTF case.
xInStream.set(new utl::OStreamWrapper(aFileStream)); xInStream.set(new utl::OStreamWrapper(aFileStream));
uno::Reference<io::XStream> xOutStream if (!xObj.is())
= xStorage->openStreamElement(aObjName, embed::ElementModes::READWRITE);
comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream->getOutputStream());
if (!aType.isEmpty())
{ {
// Set media type of the native data. uno::Reference<io::XStream> xOutStream
uno::Reference<beans::XPropertySet> xOutStreamProps(xOutStream, uno::UNO_QUERY); = xStorage->openStreamElement(aObjName, embed::ElementModes::READWRITE);
if (xOutStreamProps.is()) if (aFileStream.IsOpen())
xOutStreamProps->setPropertyValue("MediaType", uno::makeAny(aType)); comphelper::OStorageHelper::CopyInputToOutput(xInStream,
xOutStream->getOutputStream());
if (!aType.isEmpty())
{
// Set media type of the native data.
uno::Reference<beans::XPropertySet> xOutStreamProps(xOutStream, uno::UNO_QUERY);
if (xOutStreamProps.is())
xOutStreamProps->setPropertyValue("MediaType", uno::makeAny(aType));
}
} }
xObj = aCnt.GetEmbeddedObject(aObjName);
} }
xObj = aCnt.GetEmbeddedObject(aObjName);
} }
SfxItemSet aFrameSet( m_xDoc->GetAttrPool(), SfxItemSet aFrameSet( m_xDoc->GetAttrPool(),
...@@ -1451,23 +1471,47 @@ Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFrame ...@@ -1451,23 +1471,47 @@ Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFrame
OUString aFileType; OUString aFileType;
SvFileStream aOutStream(aFileName, StreamMode::WRITE); SvFileStream aOutStream(aFileName, StreamMode::WRITE);
uno::Reference<io::XActiveDataStreamer> xStreamProvider; uno::Reference<io::XActiveDataStreamer> xStreamProvider;
uno::Reference<embed::XEmbedPersist2> xOwnEmbedded;
if (xEmbeddedObject.is()) if (xEmbeddedObject.is())
{
xStreamProvider.set(xEmbeddedObject, uno::UNO_QUERY); xStreamProvider.set(xEmbeddedObject, uno::UNO_QUERY);
xOwnEmbedded.set(xEmbeddedObject, uno::UNO_QUERY);
}
if (xStreamProvider.is()) if (xStreamProvider.is())
{ {
// Real OLE2 case: OleEmbeddedObject.
uno::Reference<io::XInputStream> xStream(xStreamProvider->getStream(), uno::UNO_QUERY); uno::Reference<io::XInputStream> xStream(xStreamProvider->getStream(), uno::UNO_QUERY);
if (xStream.is()) if (xStream.is())
{ {
std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xStream)); std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xStream));
if (SwReqIfReader::WrapOleInRtf(*pStream, aOutStream)) if (SwReqIfReader::WrapOleInRtf(*pStream, aOutStream))
{ {
// OLE2 is always wrapped in RTF. // Data always wrapped in RTF.
aFileType = "text/rtf"; aFileType = "text/rtf";
} }
} }
} }
else if (xOwnEmbedded.is())
{
// Our own embedded object: OCommonEmbeddedObject.
SvxMSExportOLEObjects aOLEExp(0);
// Trigger the load of the OLE object if needed, otherwise we can't
// export it.
pOLENd->GetTwipSize();
SvMemoryStream aMemory;
tools::SvRef<SotStorage> pStorage = new SotStorage(aMemory);
aOLEExp.ExportOLEObject(rOLEObj.GetObject(), *pStorage);
pStorage->Commit();
aMemory.Seek(0);
if (SwReqIfReader::WrapOleInRtf(aMemory, aOutStream))
{
// Data always wrapped in RTF.
aFileType = "text/rtf";
}
}
else else
{ {
// Otherwise the native data is just a grab-bag: ODummyEmbeddedObject.
OUString aStreamName = rOLEObj.GetCurrentPersistName(); OUString aStreamName = rOLEObj.GetCurrentPersistName();
uno::Reference<embed::XStorage> xStorage = pDocSh->GetStorage(); uno::Reference<embed::XStorage> xStorage = pDocSh->GetStorage();
uno::Reference<io::XStream> xInStream uno::Reference<io::XStream> xInStream
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <svtools/rtfkeywd.hxx> #include <svtools/rtfkeywd.hxx>
#include <svtools/rtftoken.h> #include <svtools/rtftoken.h>
#include <tools/stream.hxx> #include <tools/stream.hxx>
#include <filter/msfilter/msdffimp.hxx>
namespace namespace
{ {
...@@ -109,9 +110,12 @@ OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1) ...@@ -109,9 +110,12 @@ OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1)
// ClassName // ClassName
rOle1.WriteUInt32(aClassName.getLength()); rOle1.WriteUInt32(aClassName.getLength());
rOle1.WriteOString(aClassName); if (!aClassName.isEmpty())
// Null terminated pascal string. {
rOle1.WriteChar(0); rOle1.WriteOString(aClassName);
// Null terminated pascal string.
rOle1.WriteChar(0);
}
// TopicName. // TopicName.
rOle1.WriteUInt32(0); rOle1.WriteUInt32(0);
...@@ -133,7 +137,7 @@ OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1) ...@@ -133,7 +137,7 @@ OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1)
namespace SwReqIfReader namespace SwReqIfReader
{ {
bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle) bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle, bool& bOwnFormat)
{ {
// Add missing header/footer. // Add missing header/footer.
SvMemoryStream aRtf; SvMemoryStream aRtf;
...@@ -149,7 +153,29 @@ bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle) ...@@ -149,7 +153,29 @@ bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle)
return false; return false;
// Write the OLE2 data. // Write the OLE2 data.
return xReader->WriteObjectData(rOle); if (!xReader->WriteObjectData(rOle))
return false;
tools::SvRef<SotStorage> pStorage = new SotStorage(rOle);
OUString aFilterName = SvxMSDffManager::GetFilterNameFromClassID(pStorage->GetClassName());
bOwnFormat = !aFilterName.isEmpty();
if (!bOwnFormat)
{
// Real OLE2 data, we're done.
rOle.Seek(0);
return true;
}
// ODF-in-OLE2 case, extract actual data.
SvMemoryStream aMemory;
SvxMSDffManager::ExtractOwnStream(*pStorage, aMemory);
rOle.Seek(0);
aMemory.Seek(0);
rOle.WriteStream(aMemory);
// Stream length is current position + 1.
rOle.SetStreamSize(aMemory.GetSize() + 1);
rOle.Seek(0);
return true;
} }
bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf) bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf)
......
...@@ -13,8 +13,12 @@ class SvStream; ...@@ -13,8 +13,12 @@ class SvStream;
namespace SwReqIfReader namespace SwReqIfReader
{ {
/// Extracts an OLE2 container binary from an RTF fragment. /**
bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle); * Extracts an OLE2 container binary from an RTF fragment.
*
* @param bOwnFormat if the extracted data has an ODF class ID or not.
*/
bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle, bool& bOwnFormat);
/// Wraps an OLE2 container binary in an RTF fragment. /// Wraps an OLE2 container binary in an RTF fragment.
bool WrapOleInRtf(SvStream& rOle, SvStream& rRtf); bool WrapOleInRtf(SvStream& rOle, SvStream& rRtf);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment