summaryrefslogtreecommitdiff
path: root/sw/source/filter/html
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2020-04-30 12:40:24 +0200
committerMiklos Vajna <vmiklos@collabora.com>2020-04-30 13:20:15 +0200
commit1392fd6a7eaf9f507639096984c2a0108f254795 (patch)
treed8168e8dfcae0a7de14d0eefe4e5eea54c95c5af /sw/source/filter/html
parente00c87caa399d37426d839f5264a747c115d0b12 (diff)
sw reqif-xhtml export, embedded objects: handle Ole10Native stream
Normally the embedded object has some OLE2 native data, and we insert our OLE1 header before that. But in case the OLE2 data already has an Ole10Native stream, then don't create an OLE1-in-OLE2-in-OLE1 output: it's pointless and some consumers have trouble parsing that. Change-Id: Ifc8b37494f97da89ce66a147e08a49eaa2f7ae1e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/93200 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
Diffstat (limited to 'sw/source/filter/html')
-rw-r--r--sw/source/filter/html/htmlreqifreader.cxx96
1 files changed, 94 insertions, 2 deletions
diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx
index 02f0e112ef0a..523bc973c587 100644
--- a/sw/source/filter/html/htmlreqifreader.cxx
+++ b/sw/source/filter/html/htmlreqifreader.cxx
@@ -143,14 +143,106 @@ bool ParseOLE2Presentation(SvStream& rOle2, sal_uInt32& nWidth, sal_uInt32& nHei
return true;
}
+/**
+ * Inserts an OLE1 header before an OLE2 storage, assuming that the storage has an Ole10Native
+ * stream.
+ */
+OString InsertOLE1HeaderFromOle10NativeStream(tools::SvRef<SotStorage>& xStorage,
+ SwOLENode& rOLENode, SvStream& rOle1)
+{
+ tools::SvRef<SotStorageStream> xOle1Stream
+ = xStorage->OpenSotStream("\1Ole10Native", StreamMode::STD_READ);
+ sal_uInt32 nOle1Size = 0;
+ xOle1Stream->ReadUInt32(nOle1Size);
+
+ OString aClassName("Package");
+
+ // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
+ rOle1.Seek(0);
+ // OLEVersion.
+ rOle1.WriteUInt32(0x00000501);
+
+ // FormatID is EmbeddedObject.
+ rOle1.WriteUInt32(0x00000002);
+
+ // ClassName
+ rOle1.WriteUInt32(aClassName.isEmpty() ? 0 : aClassName.getLength() + 1);
+ if (!aClassName.isEmpty())
+ {
+ rOle1.WriteOString(aClassName);
+ // Null terminated pascal string.
+ rOle1.WriteChar(0);
+ }
+
+ // TopicName.
+ rOle1.WriteUInt32(0);
+
+ // ItemName.
+ rOle1.WriteUInt32(0);
+
+ // NativeDataSize
+ rOle1.WriteUInt32(nOle1Size);
+
+ // Write the actual native data.
+ rOle1.WriteStream(*xOle1Stream, nOle1Size);
+
+ // Write Presentation.
+ if (!rOLENode.GetGraphic())
+ {
+ return aClassName;
+ }
+
+ const Graphic& rGraphic = *rOLENode.GetGraphic();
+ Size aSize = rOLENode.GetTwipSize();
+ SvMemoryStream aGraphicStream;
+ if (GraphicConverter::Export(aGraphicStream, rGraphic, ConvertDataFormat::WMF) != ERRCODE_NONE)
+ {
+ return aClassName;
+ }
+
+ auto pGraphicAry = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
+ sal_uInt64 nPresentationData = aGraphicStream.TellEnd();
+ msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nPresentationData);
+
+ // OLEVersion.
+ rOle1.WriteUInt32(0x00000501);
+ // FormatID: constant means the ClassName field is present.
+ rOle1.WriteUInt32(0x00000005);
+ // ClassName: null terminated pascal string.
+ OString aPresentationClassName("METAFILEPICT");
+ rOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
+ rOle1.WriteOString(aPresentationClassName);
+ rOle1.WriteChar(0);
+ // Width.
+ rOle1.WriteUInt32(aSize.getWidth());
+ // Height.
+ rOle1.WriteUInt32(aSize.getHeight() * -1);
+ // PresentationDataSize
+ rOle1.WriteUInt32(8 + nPresentationData);
+ // Reserved1-4.
+ rOle1.WriteUInt16(0x0008);
+ rOle1.WriteUInt16(0x31b1);
+ rOle1.WriteUInt16(0x1dd9);
+ rOle1.WriteUInt16(0x0000);
+ rOle1.WriteBytes(pGraphicAry, nPresentationData);
+
+ return aClassName;
+}
+
/// Inserts an OLE1 header before an OLE2 storage.
-OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1, sal_uInt32& nWidth, sal_uInt32& nHeight)
+OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1, sal_uInt32& nWidth, sal_uInt32& nHeight,
+ SwOLENode& rOLENode)
{
rOle2.Seek(0);
tools::SvRef<SotStorage> xStorage(new SotStorage(rOle2));
if (xStorage->GetError() != ERRCODE_NONE)
return OString();
+ if (xStorage->IsStream("\1Ole10Native"))
+ {
+ return InsertOLE1HeaderFromOle10NativeStream(xStorage, rOLENode, rOle1);
+ }
+
OString aClassName = ExtractOLEClassName(xStorage);
// Write ObjectHeader, see [MS-OLEDS] 2.2.4.
@@ -304,7 +396,7 @@ bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode)
SvMemoryStream aOLE1;
sal_uInt32 nWidth = 0;
sal_uInt32 nHeight = 0;
- OString aClassName = InsertOLE1Header(rOle2, aOLE1, nWidth, nHeight);
+ OString aClassName = InsertOLE1Header(rOle2, aOLE1, nWidth, nHeight, rOLENode);
// Start object.
rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_OBJECT);