summaryrefslogtreecommitdiffstats
path: root/sw/source/filter/html/htmlreqifreader.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter/html/htmlreqifreader.cxx')
-rw-r--r--sw/source/filter/html/htmlreqifreader.cxx652
1 files changed, 652 insertions, 0 deletions
diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx
new file mode 100644
index 0000000000..8df0d5b483
--- /dev/null
+++ b/sw/source/filter/html/htmlreqifreader.cxx
@@ -0,0 +1,652 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "htmlreqifreader.hxx"
+
+#include <comphelper/scopeguard.hxx>
+#include <filter/msfilter/rtfutil.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/msdffimp.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <ndole.hxx>
+#include <sal/log.hxx>
+#include <vcl/FilterConfigItem.hxx>
+#include <vcl/wmf.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <fmtfsize.hxx>
+#include <frmfmt.hxx>
+
+using namespace com::sun::star;
+
+namespace
+{
+/// RTF parser that just extracts a single OLE2 object from a file.
+class ReqIfRtfReader : public SvRTFParser
+{
+public:
+ ReqIfRtfReader(SvStream& rStream);
+ void NextToken(int nToken) override;
+ bool WriteObjectData(SvStream& rOLE);
+
+private:
+ bool m_bInObjData = false;
+ OStringBuffer m_aHex;
+};
+
+ReqIfRtfReader::ReqIfRtfReader(SvStream& rStream)
+ : SvRTFParser(rStream)
+{
+}
+
+void ReqIfRtfReader::NextToken(int nToken)
+{
+ switch (nToken)
+ {
+ case '}':
+ m_bInObjData = false;
+ break;
+ case RTF_TEXTTOKEN:
+ if (m_bInObjData)
+ m_aHex.append(OUStringToOString(aToken, RTL_TEXTENCODING_ASCII_US));
+ break;
+ case RTF_OBJDATA:
+ m_bInObjData = true;
+ break;
+ }
+}
+
+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;
+
+ tools::SvRef<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 - 1); // -1 because it is null-terminated
+}
+
+/// Parses the presentation stream of an OLE2 storage.
+bool ParseOLE2Presentation(SvStream& rOle2, sal_uInt32& nWidth, sal_uInt32& nHeight,
+ SvStream& rPresentationData)
+{
+ // See [MS-OLEDS] 2.3.4, OLEPresentationStream
+ rOle2.Seek(0);
+ tools::SvRef<SotStorage> pStorage = new SotStorage(rOle2);
+ tools::SvRef<SotStorageStream> xOle2Presentation
+ = pStorage->OpenSotStream("\002OlePres000", StreamMode::STD_READ);
+
+ // Read AnsiClipboardFormat.
+ sal_uInt32 nMarkerOrLength = 0;
+ xOle2Presentation->ReadUInt32(nMarkerOrLength);
+ if (nMarkerOrLength != 0xffffffff)
+ // FormatOrAnsiString is not present
+ return false;
+ sal_uInt32 nFormatOrAnsiLength = 0;
+ xOle2Presentation->ReadUInt32(nFormatOrAnsiLength);
+ if (nFormatOrAnsiLength != 0x00000003) // CF_METAFILEPICT
+ return false;
+
+ // Read TargetDeviceSize.
+ sal_uInt32 nTargetDeviceSize = 0;
+ xOle2Presentation->ReadUInt32(nTargetDeviceSize);
+ if (nTargetDeviceSize != 0x00000004)
+ // TargetDevice is present
+ return false;
+
+ sal_uInt32 nAspect = 0;
+ xOle2Presentation->ReadUInt32(nAspect);
+ sal_uInt32 nLindex = 0;
+ xOle2Presentation->ReadUInt32(nLindex);
+ sal_uInt32 nAdvf = 0;
+ xOle2Presentation->ReadUInt32(nAdvf);
+ sal_uInt32 nReserved1 = 0;
+ xOle2Presentation->ReadUInt32(nReserved1);
+ xOle2Presentation->ReadUInt32(nWidth);
+ xOle2Presentation->ReadUInt32(nHeight);
+ sal_uInt32 nSize = 0;
+ xOle2Presentation->ReadUInt32(nSize);
+
+ // Read Data.
+ if (nSize > xOle2Presentation->remainingSize())
+ return false;
+
+ if (nSize <= 64)
+ {
+ SAL_WARN("sw.html",
+ "ParseOLE2Presentation: ignoring potentially broken small preview: size is "
+ << nSize);
+ return false;
+ }
+
+ std::vector<char> aBuffer(nSize);
+ xOle2Presentation->ReadBytes(aBuffer.data(), aBuffer.size());
+ rPresentationData.WriteBytes(aBuffer.data(), aBuffer.size());
+
+ return true;
+}
+
+/**
+ * Inserts an OLE1 header before an OLE2 storage, assuming that the storage has an Ole10Native
+ * stream.
+ */
+OString InsertOLE1HeaderFromOle10NativeStream(const 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;
+ if (xStorage->GetClassName() == SvGlobalName(0x0003000A, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46))
+ {
+ aClassName = "PBrush"_ostr;
+ }
+ else
+ {
+ if (xStorage->GetClassName()
+ != SvGlobalName(0x0003000C, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46))
+ {
+ SAL_WARN("sw.html", "InsertOLE1HeaderFromOle10NativeStream: unexpected class id: "
+ << xStorage->GetClassName().GetHexName());
+ }
+ aClassName = "Package"_ostr;
+ }
+
+ // 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"_ostr);
+ 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;
+}
+
+/**
+ * Writes an OLE1 header and data from rOle2 to rOle1.
+ *
+ * In case rOle2 has presentation data, then its size is written to nWidth/nHeight. Otherwise
+ * nWidth/nHeight/pPresentationData/nPresentationData is used for the presentation data.
+ */
+OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1, sal_uInt32& nWidth, sal_uInt32& nHeight,
+ SwOLENode& rOLENode, const sal_uInt8* pPresentationData,
+ sal_uInt64 nPresentationData)
+{
+ rOle2.Seek(0);
+ tools::SvRef<SotStorage> xStorage(new SotStorage(rOle2));
+ if (xStorage->GetError() != ERRCODE_NONE)
+ return {};
+
+ if (xStorage->IsStream("\1Ole10Native"))
+ {
+ return InsertOLE1HeaderFromOle10NativeStream(xStorage, rOLENode, rOle1);
+ }
+
+ OString aClassName = ExtractOLEClassName(xStorage);
+
+ // 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(rOle2.TellEnd());
+
+ // Write the actual native data.
+ rOle2.Seek(0);
+ rOle1.WriteStream(rOle2);
+
+ // Write Presentation.
+ SvMemoryStream aPresentationData;
+ // OLEVersion.
+ rOle1.WriteUInt32(0x00000501);
+ // FormatID: constant means the ClassName field is present.
+ rOle1.WriteUInt32(0x00000005);
+ // ClassName: null terminated pascal string.
+ OString aPresentationClassName("METAFILEPICT"_ostr);
+ rOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
+ rOle1.WriteOString(aPresentationClassName);
+ rOle1.WriteChar(0);
+ const sal_uInt8* pBytes = nullptr;
+ sal_uInt64 nBytes = 0;
+ if (ParseOLE2Presentation(rOle2, nWidth, nHeight, aPresentationData))
+ {
+ // Take presentation data for OLE1 from OLE2.
+ pBytes = static_cast<const sal_uInt8*>(aPresentationData.GetData());
+ nBytes = aPresentationData.Tell();
+ }
+ else
+ {
+ // Take presentation data for OLE1 from RTF.
+ pBytes = pPresentationData;
+ nBytes = nPresentationData;
+ }
+ // Width.
+ rOle1.WriteUInt32(nWidth);
+ // Height.
+ rOle1.WriteUInt32(nHeight * -1);
+ // PresentationDataSize: size of (reserved fields + pBytes).
+ rOle1.WriteUInt32(8 + nBytes);
+ // Reserved1-4.
+ rOle1.WriteUInt16(0x0008);
+ rOle1.WriteUInt16(0x31b1);
+ rOle1.WriteUInt16(0x1dd9);
+ rOle1.WriteUInt16(0x0000);
+ rOle1.WriteBytes(pBytes, nBytes);
+
+ return aClassName;
+}
+
+/// Writes presentation data with the specified size to rRtf as an RTF hexdump.
+void WrapOleGraphicInRtf(SvStream& rRtf, sal_uInt32 nWidth, sal_uInt32 nHeight,
+ const sal_uInt8* pPresentationData, sal_uInt64 nPresentationData)
+{
+ // Start result.
+ rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_RESULT);
+
+ // Start pict.
+ rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_PICT);
+
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_WMETAFILE "8");
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICW);
+ rRtf.WriteOString(OString::number(nWidth));
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICH);
+ rRtf.WriteOString(OString::number(nHeight));
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
+ rRtf.WriteOString(OString::number(nWidth));
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
+ rRtf.WriteOString(OString::number(nHeight));
+ if (pPresentationData)
+ {
+ rRtf.WriteOString(SAL_NEWLINE_STRING);
+ msfilter::rtfutil::WriteHex(pPresentationData, nPresentationData, &rRtf);
+ }
+
+ // End pict.
+ rRtf.WriteOString("}");
+
+ // End result.
+ rRtf.WriteOString("}");
+}
+}
+
+namespace SwReqIfReader
+{
+bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle, bool& bOwnFormat)
+{
+ // Add missing header/footer.
+ SvMemoryStream aRtf;
+ aRtf.WriteOString("{\\rtf1");
+ aRtf.WriteStream(rRtf);
+ aRtf.WriteOString("}");
+ aRtf.Seek(0);
+
+ // Read the RTF markup.
+ tools::SvRef<ReqIfRtfReader> xReader(new ReqIfRtfReader(aRtf));
+ SvParserState eState = xReader->CallParser();
+ if (eState == SvParserState::Error)
+ return false;
+
+ // Write the OLE2 data.
+ 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, SwOLENode& rOLENode,
+ const SwFrameFormat& rFormat)
+{
+ sal_uInt64 nPos = rOle2.Tell();
+ comphelper::ScopeGuard g([&rOle2, nPos] { rOle2.Seek(nPos); });
+
+ // Write OLE1 header, then the RTF wrapper.
+ SvMemoryStream aOLE1;
+
+ // Prepare presentation data early, so it's available to both OLE1 and RTF.
+ Size aSize = rFormat.GetFrameSize().GetSize();
+ sal_uInt32 nWidth = aSize.getWidth();
+ sal_uInt32 nHeight = aSize.getHeight();
+ const Graphic* pGraphic = rOLENode.GetGraphic();
+ const sal_uInt8* pPresentationData = nullptr;
+ sal_uInt64 nPresentationData = 0;
+ SvMemoryStream aGraphicStream;
+ if (pGraphic)
+ {
+ uno::Sequence<beans::PropertyValue> aFilterData
+ = { comphelper::makePropertyValue("EmbedEMF", false) };
+ FilterConfigItem aConfigItem(&aFilterData);
+ if (ConvertGraphicToWMF(*pGraphic, aGraphicStream, &aConfigItem))
+ {
+ pPresentationData = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
+ nPresentationData = aGraphicStream.TellEnd();
+ msfilter::rtfutil::StripMetafileHeader(pPresentationData, nPresentationData);
+ }
+ }
+ OString aClassName = InsertOLE1Header(rOle2, aOLE1, nWidth, nHeight, rOLENode,
+ pPresentationData, nPresentationData);
+
+ // Start object.
+ rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_OBJECT);
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJEMB);
+
+ // Start objclass.
+ rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJCLASS " ");
+ rRtf.WriteOString(aClassName);
+ // End objclass.
+ rRtf.WriteOString("}");
+
+ // Object size.
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJW);
+ rRtf.WriteOString(OString::number(nWidth));
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJH);
+ rRtf.WriteOString(OString::number(nHeight));
+
+ // Start objdata.
+ rRtf.WriteOString(
+ "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJDATA SAL_NEWLINE_STRING);
+ msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOLE1.GetData()), aOLE1.GetSize(),
+ &rRtf);
+ // End objdata.
+ rRtf.WriteOString("}");
+
+ if (pPresentationData)
+ {
+ WrapOleGraphicInRtf(rRtf, nWidth, nHeight, pPresentationData, nPresentationData);
+ }
+
+ // End object.
+ rRtf.WriteOString("}");
+
+ return true;
+}
+
+bool WrapGraphicInRtf(const Graphic& rGraphic, const SwFrameFormat& rFormat, SvStream& rRtf)
+{
+ // Start object.
+ rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_OBJECT);
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJEMB);
+
+ // Object size: as used in the document model (not pixel size)
+ Size aSize = rFormat.GetFrameSize().GetSize();
+ sal_uInt32 nWidth = aSize.getWidth();
+ sal_uInt32 nHeight = aSize.getHeight();
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJW);
+ rRtf.WriteOString(OString::number(nWidth));
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJH);
+ rRtf.WriteOString(OString::number(nHeight));
+ rRtf.WriteOString(SAL_NEWLINE_STRING);
+
+ // Start objclass.
+ rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJCLASS " ");
+ OString aClassName("PBrush"_ostr);
+ rRtf.WriteOString(aClassName);
+ // End objclass.
+ rRtf.WriteOString("}");
+ rRtf.WriteOString(SAL_NEWLINE_STRING);
+
+ // Start objdata.
+ rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJDATA " ");
+
+ SvMemoryStream aOle1;
+ // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
+ // OLEVersion.
+ aOle1.WriteUInt32(0x00000501);
+
+ // FormatID is EmbeddedObject.
+ aOle1.WriteUInt32(0x00000002);
+
+ // ClassName
+ aOle1.WriteUInt32(aClassName.getLength() + 1);
+ aOle1.WriteOString(aClassName);
+ // Null terminated pascal string.
+ aOle1.WriteChar(0);
+
+ // TopicName.
+ aOle1.WriteUInt32(0);
+
+ // ItemName.
+ aOle1.WriteUInt32(0);
+
+ // NativeDataSize
+ SvMemoryStream aNativeData;
+
+ // Set white background for the semi-transparent pixels.
+ BitmapEx aBitmapEx = rGraphic.GetBitmapEx();
+ Bitmap aBitmap = aBitmapEx.GetBitmap(/*aTransparentReplaceColor=*/COL_WHITE);
+
+ if (aBitmap.getPixelFormat() != vcl::PixelFormat::N24_BPP)
+ {
+ // More exotic pixel formats cause trouble for ms paint.
+ aBitmap.Convert(BmpConversion::N24Bit);
+ }
+
+ if (GraphicConverter::Export(aNativeData, BitmapEx(aBitmap), ConvertDataFormat::BMP)
+ != ERRCODE_NONE)
+ {
+ SAL_WARN("sw.html", "WrapGraphicInRtf: bmp conversion failed");
+ }
+ aOle1.WriteUInt32(aNativeData.TellEnd());
+
+ // Write the actual native data.
+ aNativeData.Seek(0);
+ aOle1.WriteStream(aNativeData);
+
+ // Prepare presentation data.
+ const sal_uInt8* pPresentationData = nullptr;
+ sal_uInt64 nPresentationData = 0;
+ SvMemoryStream aGraphicStream;
+ uno::Sequence<beans::PropertyValue> aFilterData
+ = { comphelper::makePropertyValue("EmbedEMF", false) };
+ FilterConfigItem aConfigItem(&aFilterData);
+ if (ConvertGraphicToWMF(rGraphic, aGraphicStream, &aConfigItem))
+ {
+ pPresentationData = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
+ nPresentationData = aGraphicStream.TellEnd();
+ msfilter::rtfutil::StripMetafileHeader(pPresentationData, nPresentationData);
+ }
+
+ // Write Presentation.
+ // OLEVersion.
+ aOle1.WriteUInt32(0x00000501);
+ // FormatID: constant means the ClassName field is present.
+ aOle1.WriteUInt32(0x00000005);
+ // ClassName: null terminated pascal string.
+ OString aPresentationClassName("METAFILEPICT"_ostr);
+ aOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
+ aOle1.WriteOString(aPresentationClassName);
+ aOle1.WriteChar(0);
+ const sal_uInt8* pBytes = nullptr;
+ sal_uInt64 nBytes = 0;
+ // Take presentation data for OLE1 from RTF.
+ pBytes = pPresentationData;
+ nBytes = nPresentationData;
+ // Width.
+ aOle1.WriteUInt32(nWidth);
+ // Height.
+ aOle1.WriteUInt32(nHeight * -1);
+ // PresentationDataSize: size of (reserved fields + pBytes).
+ aOle1.WriteUInt32(8 + nBytes);
+ // Reserved1-4.
+ aOle1.WriteUInt16(0x0008);
+ aOle1.WriteUInt16(0x31b1);
+ aOle1.WriteUInt16(0x1dd9);
+ aOle1.WriteUInt16(0x0000);
+ aOle1.WriteBytes(pBytes, nBytes);
+
+ // End objdata.
+ msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOle1.GetData()), aOle1.GetSize(),
+ &rRtf);
+ rRtf.WriteOString("}");
+ rRtf.WriteOString(SAL_NEWLINE_STRING);
+
+ rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_RESULT);
+ rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_PICT);
+
+ Size aMapped(rGraphic.GetPrefSize());
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICW);
+ rRtf.WriteOString(OString::number(aMapped.Width()));
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICH);
+ rRtf.WriteOString(OString::number(aMapped.Height()));
+
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
+ rRtf.WriteOString(OString::number(nWidth));
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
+ rRtf.WriteOString(OString::number(nHeight));
+ rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_WMETAFILE "8");
+ rRtf.WriteOString(SAL_NEWLINE_STRING);
+
+ if (pPresentationData)
+ {
+ msfilter::rtfutil::WriteHex(pPresentationData, nPresentationData, &rRtf);
+ rRtf.WriteOString(SAL_NEWLINE_STRING);
+ }
+
+ // End pict.
+ rRtf.WriteOString("}");
+
+ // End result.
+ rRtf.WriteOString("}");
+
+ // End object.
+ rRtf.WriteOString("}");
+ return true;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */