Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / filter / html / htmlreqifreader.cxx
blobf42c87e3e1763aaaaf7e3593072a159411ef3aaf
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include "htmlreqifreader.hxx"
12 #include <comphelper/scopeguard.hxx>
13 #include <filter/msfilter/rtfutil.hxx>
14 #include <rtl/strbuf.hxx>
15 #include <sot/storage.hxx>
16 #include <svtools/parrtf.hxx>
17 #include <svtools/rtfkeywd.hxx>
18 #include <svtools/rtftoken.h>
19 #include <tools/stream.hxx>
20 #include <filter/msfilter/msdffimp.hxx>
21 #include <vcl/cvtgrf.hxx>
22 #include <ndole.hxx>
23 #include <sal/log.hxx>
24 #include <vcl/FilterConfigItem.hxx>
25 #include <vcl/wmf.hxx>
26 #include <comphelper/propertyvalue.hxx>
27 #include <fmtfsize.hxx>
28 #include <frmfmt.hxx>
30 using namespace com::sun::star;
32 namespace
34 /// RTF parser that just extracts a single OLE2 object from a file.
35 class ReqIfRtfReader : public SvRTFParser
37 public:
38 ReqIfRtfReader(SvStream& rStream);
39 void NextToken(int nToken) override;
40 bool WriteObjectData(SvStream& rOLE);
42 private:
43 bool m_bInObjData = false;
44 OStringBuffer m_aHex;
47 ReqIfRtfReader::ReqIfRtfReader(SvStream& rStream)
48 : SvRTFParser(rStream)
52 void ReqIfRtfReader::NextToken(int nToken)
54 switch (nToken)
56 case '}':
57 m_bInObjData = false;
58 break;
59 case RTF_TEXTTOKEN:
60 if (m_bInObjData)
61 m_aHex.append(OUStringToOString(aToken, RTL_TEXTENCODING_ASCII_US));
62 break;
63 case RTF_OBJDATA:
64 m_bInObjData = true;
65 break;
69 bool ReqIfRtfReader::WriteObjectData(SvStream& rOLE)
71 return msfilter::rtfutil::ExtractOLE2FromObjdata(m_aHex.makeStringAndClear(), rOLE);
74 /// Looks up what OLE1 calls the ClassName, see [MS-OLEDS] 2.3.8 CompObjStream.
75 OString ExtractOLEClassName(const tools::SvRef<SotStorage>& xStorage)
77 OString aRet;
79 tools::SvRef<SotStorageStream> pCompObj = xStorage->OpenSotStream("\1CompObj");
80 if (!pCompObj)
81 return aRet;
83 pCompObj->Seek(0);
84 pCompObj->SeekRel(28); // Header
85 if (!pCompObj->good())
86 return aRet;
88 sal_uInt32 nData;
89 pCompObj->ReadUInt32(nData); // AnsiUserType
90 pCompObj->SeekRel(nData);
91 if (!pCompObj->good())
92 return aRet;
94 pCompObj->ReadUInt32(nData); // AnsiClipboardFormat
95 pCompObj->SeekRel(nData);
96 if (!pCompObj->good())
97 return aRet;
99 pCompObj->ReadUInt32(nData); // Reserved1
100 return read_uInt8s_ToOString(*pCompObj, nData - 1); // -1 because it is null-terminated
103 /// Parses the presentation stream of an OLE2 storage.
104 bool ParseOLE2Presentation(SvStream& rOle2, sal_uInt32& nWidth, sal_uInt32& nHeight,
105 SvStream& rPresentationData)
107 // See [MS-OLEDS] 2.3.4, OLEPresentationStream
108 rOle2.Seek(0);
109 tools::SvRef<SotStorage> pStorage = new SotStorage(rOle2);
110 tools::SvRef<SotStorageStream> xOle2Presentation
111 = pStorage->OpenSotStream("\002OlePres000", StreamMode::STD_READ);
113 // Read AnsiClipboardFormat.
114 sal_uInt32 nMarkerOrLength = 0;
115 xOle2Presentation->ReadUInt32(nMarkerOrLength);
116 if (nMarkerOrLength != 0xffffffff)
117 // FormatOrAnsiString is not present
118 return false;
119 sal_uInt32 nFormatOrAnsiLength = 0;
120 xOle2Presentation->ReadUInt32(nFormatOrAnsiLength);
121 if (nFormatOrAnsiLength != 0x00000003) // CF_METAFILEPICT
122 return false;
124 // Read TargetDeviceSize.
125 sal_uInt32 nTargetDeviceSize = 0;
126 xOle2Presentation->ReadUInt32(nTargetDeviceSize);
127 if (nTargetDeviceSize != 0x00000004)
128 // TargetDevice is present
129 return false;
131 sal_uInt32 nAspect = 0;
132 xOle2Presentation->ReadUInt32(nAspect);
133 sal_uInt32 nLindex = 0;
134 xOle2Presentation->ReadUInt32(nLindex);
135 sal_uInt32 nAdvf = 0;
136 xOle2Presentation->ReadUInt32(nAdvf);
137 sal_uInt32 nReserved1 = 0;
138 xOle2Presentation->ReadUInt32(nReserved1);
139 xOle2Presentation->ReadUInt32(nWidth);
140 xOle2Presentation->ReadUInt32(nHeight);
141 sal_uInt32 nSize = 0;
142 xOle2Presentation->ReadUInt32(nSize);
144 // Read Data.
145 if (nSize > xOle2Presentation->remainingSize())
146 return false;
148 if (nSize <= 64)
150 SAL_WARN("sw.html",
151 "ParseOLE2Presentation: ignoring potentially broken small preview: size is "
152 << nSize);
153 return false;
156 std::vector<char> aBuffer(nSize);
157 xOle2Presentation->ReadBytes(aBuffer.data(), aBuffer.size());
158 rPresentationData.WriteBytes(aBuffer.data(), aBuffer.size());
160 return true;
164 * Inserts an OLE1 header before an OLE2 storage, assuming that the storage has an Ole10Native
165 * stream.
167 OString InsertOLE1HeaderFromOle10NativeStream(const tools::SvRef<SotStorage>& xStorage,
168 SwOLENode& rOLENode, SvStream& rOle1)
170 tools::SvRef<SotStorageStream> xOle1Stream
171 = xStorage->OpenSotStream("\1Ole10Native", StreamMode::STD_READ);
172 sal_uInt32 nOle1Size = 0;
173 xOle1Stream->ReadUInt32(nOle1Size);
175 OString aClassName;
176 if (xStorage->GetClassName() == SvGlobalName(0x0003000A, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46))
178 aClassName = "PBrush";
180 else
182 if (xStorage->GetClassName()
183 != SvGlobalName(0x0003000C, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46))
185 SAL_WARN("sw.html", "InsertOLE1HeaderFromOle10NativeStream: unexpected class id: "
186 << xStorage->GetClassName().GetHexName());
188 aClassName = "Package";
191 // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
192 rOle1.Seek(0);
193 // OLEVersion.
194 rOle1.WriteUInt32(0x00000501);
196 // FormatID is EmbeddedObject.
197 rOle1.WriteUInt32(0x00000002);
199 // ClassName
200 rOle1.WriteUInt32(aClassName.isEmpty() ? 0 : aClassName.getLength() + 1);
201 if (!aClassName.isEmpty())
203 rOle1.WriteOString(aClassName);
204 // Null terminated pascal string.
205 rOle1.WriteChar(0);
208 // TopicName.
209 rOle1.WriteUInt32(0);
211 // ItemName.
212 rOle1.WriteUInt32(0);
214 // NativeDataSize
215 rOle1.WriteUInt32(nOle1Size);
217 // Write the actual native data.
218 rOle1.WriteStream(*xOle1Stream, nOle1Size);
220 // Write Presentation.
221 if (!rOLENode.GetGraphic())
223 return aClassName;
226 const Graphic& rGraphic = *rOLENode.GetGraphic();
227 Size aSize = rOLENode.GetTwipSize();
228 SvMemoryStream aGraphicStream;
229 if (GraphicConverter::Export(aGraphicStream, rGraphic, ConvertDataFormat::WMF) != ERRCODE_NONE)
231 return aClassName;
234 auto pGraphicAry = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
235 sal_uInt64 nPresentationData = aGraphicStream.TellEnd();
236 msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nPresentationData);
238 // OLEVersion.
239 rOle1.WriteUInt32(0x00000501);
240 // FormatID: constant means the ClassName field is present.
241 rOle1.WriteUInt32(0x00000005);
242 // ClassName: null terminated pascal string.
243 OString aPresentationClassName("METAFILEPICT");
244 rOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
245 rOle1.WriteOString(aPresentationClassName);
246 rOle1.WriteChar(0);
247 // Width.
248 rOle1.WriteUInt32(aSize.getWidth());
249 // Height.
250 rOle1.WriteUInt32(aSize.getHeight() * -1);
251 // PresentationDataSize
252 rOle1.WriteUInt32(8 + nPresentationData);
253 // Reserved1-4.
254 rOle1.WriteUInt16(0x0008);
255 rOle1.WriteUInt16(0x31b1);
256 rOle1.WriteUInt16(0x1dd9);
257 rOle1.WriteUInt16(0x0000);
258 rOle1.WriteBytes(pGraphicAry, nPresentationData);
260 return aClassName;
264 * Writes an OLE1 header and data from rOle2 to rOle1.
266 * In case rOle2 has presentation data, then its size is written to nWidth/nHeight. Otherwise
267 * nWidth/nHeight/pPresentationData/nPresentationData is used for the presentation data.
269 OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1, sal_uInt32& nWidth, sal_uInt32& nHeight,
270 SwOLENode& rOLENode, const sal_uInt8* pPresentationData,
271 sal_uInt64 nPresentationData)
273 rOle2.Seek(0);
274 tools::SvRef<SotStorage> xStorage(new SotStorage(rOle2));
275 if (xStorage->GetError() != ERRCODE_NONE)
276 return {};
278 if (xStorage->IsStream("\1Ole10Native"))
280 return InsertOLE1HeaderFromOle10NativeStream(xStorage, rOLENode, rOle1);
283 OString aClassName = ExtractOLEClassName(xStorage);
285 // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
286 rOle1.Seek(0);
287 // OLEVersion.
288 rOle1.WriteUInt32(0x00000501);
290 // FormatID is EmbeddedObject.
291 rOle1.WriteUInt32(0x00000002);
293 // ClassName
294 rOle1.WriteUInt32(aClassName.isEmpty() ? 0 : aClassName.getLength() + 1);
295 if (!aClassName.isEmpty())
297 rOle1.WriteOString(aClassName);
298 // Null terminated pascal string.
299 rOle1.WriteChar(0);
302 // TopicName.
303 rOle1.WriteUInt32(0);
305 // ItemName.
306 rOle1.WriteUInt32(0);
308 // NativeDataSize
309 rOle1.WriteUInt32(rOle2.TellEnd());
311 // Write the actual native data.
312 rOle2.Seek(0);
313 rOle1.WriteStream(rOle2);
315 // Write Presentation.
316 SvMemoryStream aPresentationData;
317 // OLEVersion.
318 rOle1.WriteUInt32(0x00000501);
319 // FormatID: constant means the ClassName field is present.
320 rOle1.WriteUInt32(0x00000005);
321 // ClassName: null terminated pascal string.
322 OString aPresentationClassName("METAFILEPICT");
323 rOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
324 rOle1.WriteOString(aPresentationClassName);
325 rOle1.WriteChar(0);
326 const sal_uInt8* pBytes = nullptr;
327 sal_uInt64 nBytes = 0;
328 if (ParseOLE2Presentation(rOle2, nWidth, nHeight, aPresentationData))
330 // Take presentation data for OLE1 from OLE2.
331 pBytes = static_cast<const sal_uInt8*>(aPresentationData.GetData());
332 nBytes = aPresentationData.Tell();
334 else
336 // Take presentation data for OLE1 from RTF.
337 pBytes = pPresentationData;
338 nBytes = nPresentationData;
340 // Width.
341 rOle1.WriteUInt32(nWidth);
342 // Height.
343 rOle1.WriteUInt32(nHeight * -1);
344 // PresentationDataSize: size of (reserved fields + pBytes).
345 rOle1.WriteUInt32(8 + nBytes);
346 // Reserved1-4.
347 rOle1.WriteUInt16(0x0008);
348 rOle1.WriteUInt16(0x31b1);
349 rOle1.WriteUInt16(0x1dd9);
350 rOle1.WriteUInt16(0x0000);
351 rOle1.WriteBytes(pBytes, nBytes);
353 return aClassName;
356 /// Writes presentation data with the specified size to rRtf as an RTF hexdump.
357 void WrapOleGraphicInRtf(SvStream& rRtf, sal_uInt32 nWidth, sal_uInt32 nHeight,
358 const sal_uInt8* pPresentationData, sal_uInt64 nPresentationData)
360 // Start result.
361 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_RESULT);
363 // Start pict.
364 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_PICT);
366 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_WMETAFILE "8");
367 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICW);
368 rRtf.WriteOString(OString::number(nWidth));
369 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICH);
370 rRtf.WriteOString(OString::number(nHeight));
371 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
372 rRtf.WriteOString(OString::number(nWidth));
373 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
374 rRtf.WriteOString(OString::number(nHeight));
375 if (pPresentationData)
377 rRtf.WriteOString(SAL_NEWLINE_STRING);
378 msfilter::rtfutil::WriteHex(pPresentationData, nPresentationData, &rRtf);
381 // End pict.
382 rRtf.WriteOString("}");
384 // End result.
385 rRtf.WriteOString("}");
389 namespace SwReqIfReader
391 bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle, bool& bOwnFormat)
393 // Add missing header/footer.
394 SvMemoryStream aRtf;
395 aRtf.WriteOString("{\\rtf1");
396 aRtf.WriteStream(rRtf);
397 aRtf.WriteOString("}");
398 aRtf.Seek(0);
400 // Read the RTF markup.
401 tools::SvRef<ReqIfRtfReader> xReader(new ReqIfRtfReader(aRtf));
402 SvParserState eState = xReader->CallParser();
403 if (eState == SvParserState::Error)
404 return false;
406 // Write the OLE2 data.
407 if (!xReader->WriteObjectData(rOle))
408 return false;
410 tools::SvRef<SotStorage> pStorage = new SotStorage(rOle);
411 OUString aFilterName = SvxMSDffManager::GetFilterNameFromClassID(pStorage->GetClassName());
412 bOwnFormat = !aFilterName.isEmpty();
413 if (!bOwnFormat)
415 // Real OLE2 data, we're done.
416 rOle.Seek(0);
417 return true;
420 // ODF-in-OLE2 case, extract actual data.
421 SvMemoryStream aMemory;
422 SvxMSDffManager::ExtractOwnStream(*pStorage, aMemory);
423 rOle.Seek(0);
424 aMemory.Seek(0);
425 rOle.WriteStream(aMemory);
426 // Stream length is current position + 1.
427 rOle.SetStreamSize(aMemory.GetSize() + 1);
428 rOle.Seek(0);
429 return true;
432 bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode,
433 const SwFrameFormat& rFormat)
435 sal_uInt64 nPos = rOle2.Tell();
436 comphelper::ScopeGuard g([&rOle2, nPos] { rOle2.Seek(nPos); });
438 // Write OLE1 header, then the RTF wrapper.
439 SvMemoryStream aOLE1;
441 // Prepare presentation data early, so it's available to both OLE1 and RTF.
442 Size aSize = rFormat.GetFrameSize().GetSize();
443 sal_uInt32 nWidth = aSize.getWidth();
444 sal_uInt32 nHeight = aSize.getHeight();
445 const Graphic* pGraphic = rOLENode.GetGraphic();
446 const sal_uInt8* pPresentationData = nullptr;
447 sal_uInt64 nPresentationData = 0;
448 SvMemoryStream aGraphicStream;
449 if (pGraphic)
451 uno::Sequence<beans::PropertyValue> aFilterData
452 = { comphelper::makePropertyValue("EmbedEMF", false) };
453 FilterConfigItem aConfigItem(&aFilterData);
454 if (ConvertGraphicToWMF(*pGraphic, aGraphicStream, &aConfigItem))
456 pPresentationData = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
457 nPresentationData = aGraphicStream.TellEnd();
458 msfilter::rtfutil::StripMetafileHeader(pPresentationData, nPresentationData);
461 OString aClassName = InsertOLE1Header(rOle2, aOLE1, nWidth, nHeight, rOLENode,
462 pPresentationData, nPresentationData);
464 // Start object.
465 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_OBJECT);
466 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJEMB);
468 // Start objclass.
469 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJCLASS " ");
470 rRtf.WriteOString(aClassName);
471 // End objclass.
472 rRtf.WriteOString("}");
474 // Object size.
475 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJW);
476 rRtf.WriteOString(OString::number(nWidth));
477 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJH);
478 rRtf.WriteOString(OString::number(nHeight));
480 // Start objdata.
481 rRtf.WriteOString(
482 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJDATA SAL_NEWLINE_STRING);
483 msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOLE1.GetData()), aOLE1.GetSize(),
484 &rRtf);
485 // End objdata.
486 rRtf.WriteOString("}");
488 if (pPresentationData)
490 WrapOleGraphicInRtf(rRtf, nWidth, nHeight, pPresentationData, nPresentationData);
493 // End object.
494 rRtf.WriteOString("}");
496 return true;
499 bool WrapGraphicInRtf(const Graphic& rGraphic, const SwFrameFormat& rFormat, SvStream& rRtf)
501 // Start object.
502 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_OBJECT);
503 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJEMB);
505 // Object size: as used in the document model (not pixel size)
506 Size aSize = rFormat.GetFrameSize().GetSize();
507 sal_uInt32 nWidth = aSize.getWidth();
508 sal_uInt32 nHeight = aSize.getHeight();
509 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJW);
510 rRtf.WriteOString(OString::number(nWidth));
511 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJH);
512 rRtf.WriteOString(OString::number(nHeight));
513 rRtf.WriteOString(SAL_NEWLINE_STRING);
515 // Start objclass.
516 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJCLASS " ");
517 OString aClassName("PBrush");
518 rRtf.WriteOString(aClassName);
519 // End objclass.
520 rRtf.WriteOString("}");
521 rRtf.WriteOString(SAL_NEWLINE_STRING);
523 // Start objdata.
524 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJDATA " ");
526 SvMemoryStream aOle1;
527 // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
528 // OLEVersion.
529 aOle1.WriteUInt32(0x00000501);
531 // FormatID is EmbeddedObject.
532 aOle1.WriteUInt32(0x00000002);
534 // ClassName
535 aOle1.WriteUInt32(aClassName.getLength() + 1);
536 aOle1.WriteOString(aClassName);
537 // Null terminated pascal string.
538 aOle1.WriteChar(0);
540 // TopicName.
541 aOle1.WriteUInt32(0);
543 // ItemName.
544 aOle1.WriteUInt32(0);
546 // NativeDataSize
547 SvMemoryStream aNativeData;
549 // Set white background for the semi-transparent pixels.
550 BitmapEx aBitmapEx = rGraphic.GetBitmapEx();
551 Bitmap aBitmap = aBitmapEx.GetBitmap(/*aTransparentReplaceColor=*/COL_WHITE);
553 if (aBitmap.getPixelFormat() != vcl::PixelFormat::N24_BPP)
555 // More exotic pixel formats cause trouble for ms paint.
556 aBitmap.Convert(BmpConversion::N24Bit);
559 if (GraphicConverter::Export(aNativeData, BitmapEx(aBitmap), ConvertDataFormat::BMP)
560 != ERRCODE_NONE)
562 SAL_WARN("sw.html", "WrapGraphicInRtf: bmp conversion failed");
564 aOle1.WriteUInt32(aNativeData.TellEnd());
566 // Write the actual native data.
567 aNativeData.Seek(0);
568 aOle1.WriteStream(aNativeData);
570 // Prepare presentation data.
571 const sal_uInt8* pPresentationData = nullptr;
572 sal_uInt64 nPresentationData = 0;
573 SvMemoryStream aGraphicStream;
574 uno::Sequence<beans::PropertyValue> aFilterData
575 = { comphelper::makePropertyValue("EmbedEMF", false) };
576 FilterConfigItem aConfigItem(&aFilterData);
577 if (ConvertGraphicToWMF(rGraphic, aGraphicStream, &aConfigItem))
579 pPresentationData = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
580 nPresentationData = aGraphicStream.TellEnd();
581 msfilter::rtfutil::StripMetafileHeader(pPresentationData, nPresentationData);
584 // Write Presentation.
585 // OLEVersion.
586 aOle1.WriteUInt32(0x00000501);
587 // FormatID: constant means the ClassName field is present.
588 aOle1.WriteUInt32(0x00000005);
589 // ClassName: null terminated pascal string.
590 OString aPresentationClassName("METAFILEPICT");
591 aOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
592 aOle1.WriteOString(aPresentationClassName);
593 aOle1.WriteChar(0);
594 const sal_uInt8* pBytes = nullptr;
595 sal_uInt64 nBytes = 0;
596 // Take presentation data for OLE1 from RTF.
597 pBytes = pPresentationData;
598 nBytes = nPresentationData;
599 // Width.
600 aOle1.WriteUInt32(nWidth);
601 // Height.
602 aOle1.WriteUInt32(nHeight * -1);
603 // PresentationDataSize: size of (reserved fields + pBytes).
604 aOle1.WriteUInt32(8 + nBytes);
605 // Reserved1-4.
606 aOle1.WriteUInt16(0x0008);
607 aOle1.WriteUInt16(0x31b1);
608 aOle1.WriteUInt16(0x1dd9);
609 aOle1.WriteUInt16(0x0000);
610 aOle1.WriteBytes(pBytes, nBytes);
612 // End objdata.
613 msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOle1.GetData()), aOle1.GetSize(),
614 &rRtf);
615 rRtf.WriteOString("}");
616 rRtf.WriteOString(SAL_NEWLINE_STRING);
618 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_RESULT);
619 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_PICT);
621 Size aMapped(rGraphic.GetPrefSize());
622 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICW);
623 rRtf.WriteOString(OString::number(aMapped.Width()));
624 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICH);
625 rRtf.WriteOString(OString::number(aMapped.Height()));
627 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
628 rRtf.WriteOString(OString::number(nWidth));
629 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
630 rRtf.WriteOString(OString::number(nHeight));
631 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_WMETAFILE "8");
632 rRtf.WriteOString(SAL_NEWLINE_STRING);
634 if (pPresentationData)
636 msfilter::rtfutil::WriteHex(pPresentationData, nPresentationData, &rRtf);
637 rRtf.WriteOString(SAL_NEWLINE_STRING);
640 // End pict.
641 rRtf.WriteOString("}");
643 // End result.
644 rRtf.WriteOString("}");
646 // End object.
647 rRtf.WriteOString("}");
648 return true;
652 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */