diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2020-04-30 12:40:24 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2020-04-30 13:20:15 +0200 |
commit | 1392fd6a7eaf9f507639096984c2a0108f254795 (patch) | |
tree | d8168e8dfcae0a7de14d0eefe4e5eea54c95c5af /sw/source/filter/html | |
parent | e00c87caa399d37426d839f5264a747c115d0b12 (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.cxx | 96 |
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); |