docthemes: Save themes def. to a file when added to ColorSets
[LibreOffice.git] / sw / source / filter / html / htmlreqifreader.cxx
blob9493be474282370ff86ce863c2050e7925bb6e98
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 rtl::Reference<SotStorage>& xStorage)
77 OString aRet;
79 rtl::Reference<SotStorageStream> pCompObj = xStorage->OpenSotStream(u"\1CompObj"_ustr);
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 rtl::Reference<SotStorage> pStorage = new SotStorage(rOle2);
110 rtl::Reference<SotStorageStream> xOle2Presentation
111 = pStorage->OpenSotStream(u"\002OlePres000"_ustr, 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 rtl::Reference<SotStorage>& xStorage,
168 SwOLENode& rOLENode, SvStream& rOle1)
170 rtl::Reference<SotStorageStream> xOle1Stream
171 = xStorage->OpenSotStream(u"\1Ole10Native"_ustr, 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"_ostr;
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"_ostr;
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* pGraphic = rOLENode.GetGraphic();
227 const Graphic rGraphic = pGraphic ? *pGraphic : Graphic();
228 Size aSize = rOLENode.GetTwipSize();
229 SvMemoryStream aGraphicStream;
230 if (GraphicConverter::Export(aGraphicStream, rGraphic, ConvertDataFormat::WMF) != ERRCODE_NONE)
232 return aClassName;
235 auto pGraphicAry = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
236 sal_uInt64 nPresentationData = aGraphicStream.TellEnd();
237 msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nPresentationData);
239 // OLEVersion.
240 rOle1.WriteUInt32(0x00000501);
241 // FormatID: constant means the ClassName field is present.
242 rOle1.WriteUInt32(0x00000005);
243 // ClassName: null terminated pascal string.
244 OString aPresentationClassName("METAFILEPICT"_ostr);
245 rOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
246 rOle1.WriteOString(aPresentationClassName);
247 rOle1.WriteChar(0);
248 // Width.
249 rOle1.WriteUInt32(aSize.getWidth());
250 // Height.
251 rOle1.WriteUInt32(aSize.getHeight() * -1);
252 // PresentationDataSize
253 rOle1.WriteUInt32(8 + nPresentationData);
254 // Reserved1-4.
255 rOle1.WriteUInt16(0x0008);
256 rOle1.WriteUInt16(0x31b1);
257 rOle1.WriteUInt16(0x1dd9);
258 rOle1.WriteUInt16(0x0000);
259 rOle1.WriteBytes(pGraphicAry, nPresentationData);
261 return aClassName;
265 * Writes an OLE1 header and data from rOle2 to rOle1.
267 * In case rOle2 has presentation data, then its size is written to nWidth/nHeight. Otherwise
268 * nWidth/nHeight/pPresentationData/nPresentationData is used for the presentation data.
270 OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1, sal_uInt32& nWidth, sal_uInt32& nHeight,
271 SwOLENode& rOLENode, const sal_uInt8* pPresentationData,
272 sal_uInt64 nPresentationData)
274 rOle2.Seek(0);
275 rtl::Reference<SotStorage> xStorage(new SotStorage(rOle2));
276 if (xStorage->GetError() != ERRCODE_NONE)
277 return {};
279 if (xStorage->IsStream(u"\1Ole10Native"_ustr))
281 return InsertOLE1HeaderFromOle10NativeStream(xStorage, rOLENode, rOle1);
284 OString aClassName = ExtractOLEClassName(xStorage);
286 // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
287 rOle1.Seek(0);
288 // OLEVersion.
289 rOle1.WriteUInt32(0x00000501);
291 // FormatID is EmbeddedObject.
292 rOle1.WriteUInt32(0x00000002);
294 // ClassName
295 rOle1.WriteUInt32(aClassName.isEmpty() ? 0 : aClassName.getLength() + 1);
296 if (!aClassName.isEmpty())
298 rOle1.WriteOString(aClassName);
299 // Null terminated pascal string.
300 rOle1.WriteChar(0);
303 // TopicName.
304 rOle1.WriteUInt32(0);
306 // ItemName.
307 rOle1.WriteUInt32(0);
309 // NativeDataSize
310 rOle1.WriteUInt32(rOle2.TellEnd());
312 // Write the actual native data.
313 rOle2.Seek(0);
314 rOle1.WriteStream(rOle2);
316 // Write Presentation.
317 SvMemoryStream aPresentationData;
318 // OLEVersion.
319 rOle1.WriteUInt32(0x00000501);
320 // FormatID: constant means the ClassName field is present.
321 rOle1.WriteUInt32(0x00000005);
322 // ClassName: null terminated pascal string.
323 OString aPresentationClassName("METAFILEPICT"_ostr);
324 rOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
325 rOle1.WriteOString(aPresentationClassName);
326 rOle1.WriteChar(0);
327 const sal_uInt8* pBytes = nullptr;
328 sal_uInt64 nBytes = 0;
329 if (ParseOLE2Presentation(rOle2, nWidth, nHeight, aPresentationData))
331 // Take presentation data for OLE1 from OLE2.
332 pBytes = static_cast<const sal_uInt8*>(aPresentationData.GetData());
333 nBytes = aPresentationData.Tell();
335 else
337 // Take presentation data for OLE1 from RTF.
338 pBytes = pPresentationData;
339 nBytes = nPresentationData;
341 // Width.
342 rOle1.WriteUInt32(nWidth);
343 // Height.
344 rOle1.WriteUInt32(nHeight * -1);
345 // PresentationDataSize: size of (reserved fields + pBytes).
346 rOle1.WriteUInt32(8 + nBytes);
347 // Reserved1-4.
348 rOle1.WriteUInt16(0x0008);
349 rOle1.WriteUInt16(0x31b1);
350 rOle1.WriteUInt16(0x1dd9);
351 rOle1.WriteUInt16(0x0000);
352 rOle1.WriteBytes(pBytes, nBytes);
354 return aClassName;
357 /// Writes presentation data with the specified size to rRtf as an RTF hexdump.
358 void WrapOleGraphicInRtf(SvStream& rRtf, sal_uInt32 nWidth, sal_uInt32 nHeight,
359 const sal_uInt8* pPresentationData, sal_uInt64 nPresentationData)
361 // Start result.
362 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_RESULT);
364 // Start pict.
365 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_PICT);
367 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_WMETAFILE "8");
368 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICW);
369 rRtf.WriteOString(OString::number(nWidth));
370 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICH);
371 rRtf.WriteOString(OString::number(nHeight));
372 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
373 rRtf.WriteOString(OString::number(nWidth));
374 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
375 rRtf.WriteOString(OString::number(nHeight));
376 if (pPresentationData)
378 rRtf.WriteOString(SAL_NEWLINE_STRING);
379 msfilter::rtfutil::WriteHex(pPresentationData, nPresentationData, &rRtf);
382 // End pict.
383 rRtf.WriteOString("}");
385 // End result.
386 rRtf.WriteOString("}");
390 namespace SwReqIfReader
392 bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle, bool& bOwnFormat)
394 // Add missing header/footer.
395 SvMemoryStream aRtf;
396 aRtf.WriteOString("{\\rtf1");
397 aRtf.WriteStream(rRtf);
398 aRtf.WriteOString("}");
399 aRtf.Seek(0);
401 // Read the RTF markup.
402 tools::SvRef<ReqIfRtfReader> xReader(new ReqIfRtfReader(aRtf));
403 SvParserState eState = xReader->CallParser();
404 if (eState == SvParserState::Error)
405 return false;
407 // Write the OLE2 data.
408 if (!xReader->WriteObjectData(rOle))
409 return false;
411 rtl::Reference<SotStorage> pStorage = new SotStorage(rOle);
412 OUString aFilterName = SvxMSDffManager::GetFilterNameFromClassID(pStorage->GetClassName());
413 bOwnFormat = !aFilterName.isEmpty();
414 if (!bOwnFormat)
416 // Real OLE2 data, we're done.
417 rOle.Seek(0);
418 return true;
421 // ODF-in-OLE2 case, extract actual data.
422 SvMemoryStream aMemory;
423 SvxMSDffManager::ExtractOwnStream(*pStorage, aMemory);
424 rOle.Seek(0);
425 aMemory.Seek(0);
426 rOle.WriteStream(aMemory);
427 // Stream length is current position + 1.
428 rOle.SetStreamSize(aMemory.GetSize() + 1);
429 rOle.Seek(0);
430 return true;
433 bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode,
434 const SwFrameFormat& rFormat)
436 sal_uInt64 nPos = rOle2.Tell();
437 comphelper::ScopeGuard g([&rOle2, nPos] { rOle2.Seek(nPos); });
439 // Write OLE1 header, then the RTF wrapper.
440 SvMemoryStream aOLE1;
442 // Prepare presentation data early, so it's available to both OLE1 and RTF.
443 Size aSize = rFormat.GetFrameSize().GetSize();
444 sal_uInt32 nWidth = aSize.getWidth();
445 sal_uInt32 nHeight = aSize.getHeight();
446 const Graphic* pGraphic = rOLENode.GetGraphic();
447 const sal_uInt8* pPresentationData = nullptr;
448 sal_uInt64 nPresentationData = 0;
449 SvMemoryStream aGraphicStream;
450 if (pGraphic)
452 uno::Sequence<beans::PropertyValue> aFilterData
453 = { comphelper::makePropertyValue(u"EmbedEMF"_ustr, false) };
454 FilterConfigItem aConfigItem(&aFilterData);
455 if (ConvertGraphicToWMF(*pGraphic, aGraphicStream, &aConfigItem))
457 pPresentationData = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
458 nPresentationData = aGraphicStream.TellEnd();
459 msfilter::rtfutil::StripMetafileHeader(pPresentationData, nPresentationData);
462 OString aClassName = InsertOLE1Header(rOle2, aOLE1, nWidth, nHeight, rOLENode,
463 pPresentationData, nPresentationData);
465 // Start object.
466 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_OBJECT);
467 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJEMB);
469 // Start objclass.
470 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJCLASS " ");
471 rRtf.WriteOString(aClassName);
472 // End objclass.
473 rRtf.WriteOString("}");
475 // Object size.
476 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJW);
477 rRtf.WriteOString(OString::number(nWidth));
478 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJH);
479 rRtf.WriteOString(OString::number(nHeight));
481 // Start objdata.
482 rRtf.WriteOString(
483 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJDATA SAL_NEWLINE_STRING);
484 msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOLE1.GetData()), aOLE1.GetSize(),
485 &rRtf);
486 // End objdata.
487 rRtf.WriteOString("}");
489 if (pPresentationData)
491 WrapOleGraphicInRtf(rRtf, nWidth, nHeight, pPresentationData, nPresentationData);
494 // End object.
495 rRtf.WriteOString("}");
497 return true;
500 bool WrapGraphicInRtf(const Graphic& rGraphic, const SwFrameFormat& rFormat, SvStream& rRtf)
502 // Start object.
503 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_OBJECT);
504 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJEMB);
506 // Object size: as used in the document model (not pixel size)
507 Size aSize = rFormat.GetFrameSize().GetSize();
508 sal_uInt32 nWidth = aSize.getWidth();
509 sal_uInt32 nHeight = aSize.getHeight();
510 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJW);
511 rRtf.WriteOString(OString::number(nWidth));
512 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_OBJH);
513 rRtf.WriteOString(OString::number(nHeight));
514 rRtf.WriteOString(SAL_NEWLINE_STRING);
516 // Start objclass.
517 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJCLASS " ");
518 OString aClassName("PBrush"_ostr);
519 rRtf.WriteOString(aClassName);
520 // End objclass.
521 rRtf.WriteOString("}");
522 rRtf.WriteOString(SAL_NEWLINE_STRING);
524 // Start objdata.
525 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJDATA " ");
527 SvMemoryStream aOle1;
528 // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
529 // OLEVersion.
530 aOle1.WriteUInt32(0x00000501);
532 // FormatID is EmbeddedObject.
533 aOle1.WriteUInt32(0x00000002);
535 // ClassName
536 aOle1.WriteUInt32(aClassName.getLength() + 1);
537 aOle1.WriteOString(aClassName);
538 // Null terminated pascal string.
539 aOle1.WriteChar(0);
541 // TopicName.
542 aOle1.WriteUInt32(0);
544 // ItemName.
545 aOle1.WriteUInt32(0);
547 // NativeDataSize
548 SvMemoryStream aNativeData;
550 // Set white background for the semi-transparent pixels.
551 BitmapEx aBitmapEx = rGraphic.GetBitmapEx();
552 Bitmap aBitmap = aBitmapEx.GetBitmap(/*aTransparentReplaceColor=*/COL_WHITE);
554 if (aBitmap.getPixelFormat() != vcl::PixelFormat::N24_BPP)
556 // More exotic pixel formats cause trouble for ms paint.
557 aBitmap.Convert(BmpConversion::N24Bit);
560 if (GraphicConverter::Export(aNativeData, BitmapEx(aBitmap), ConvertDataFormat::BMP)
561 != ERRCODE_NONE)
563 SAL_WARN("sw.html", "WrapGraphicInRtf: bmp conversion failed");
565 aOle1.WriteUInt32(aNativeData.TellEnd());
567 // Write the actual native data.
568 aNativeData.Seek(0);
569 aOle1.WriteStream(aNativeData);
571 // Prepare presentation data.
572 const sal_uInt8* pPresentationData = nullptr;
573 sal_uInt64 nPresentationData = 0;
574 SvMemoryStream aGraphicStream;
575 uno::Sequence<beans::PropertyValue> aFilterData
576 = { comphelper::makePropertyValue(u"EmbedEMF"_ustr, false) };
577 FilterConfigItem aConfigItem(&aFilterData);
578 if (ConvertGraphicToWMF(rGraphic, aGraphicStream, &aConfigItem))
580 pPresentationData = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
581 nPresentationData = aGraphicStream.TellEnd();
582 msfilter::rtfutil::StripMetafileHeader(pPresentationData, nPresentationData);
585 // Write Presentation.
586 // OLEVersion.
587 aOle1.WriteUInt32(0x00000501);
588 // FormatID: constant means the ClassName field is present.
589 aOle1.WriteUInt32(0x00000005);
590 // ClassName: null terminated pascal string.
591 OString aPresentationClassName("METAFILEPICT"_ostr);
592 aOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
593 aOle1.WriteOString(aPresentationClassName);
594 aOle1.WriteChar(0);
595 const sal_uInt8* pBytes = nullptr;
596 sal_uInt64 nBytes = 0;
597 // Take presentation data for OLE1 from RTF.
598 pBytes = pPresentationData;
599 nBytes = nPresentationData;
600 // Width.
601 aOle1.WriteUInt32(nWidth);
602 // Height.
603 aOle1.WriteUInt32(nHeight * -1);
604 // PresentationDataSize: size of (reserved fields + pBytes).
605 aOle1.WriteUInt32(8 + nBytes);
606 // Reserved1-4.
607 aOle1.WriteUInt16(0x0008);
608 aOle1.WriteUInt16(0x31b1);
609 aOle1.WriteUInt16(0x1dd9);
610 aOle1.WriteUInt16(0x0000);
611 aOle1.WriteBytes(pBytes, nBytes);
613 // End objdata.
614 msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOle1.GetData()), aOle1.GetSize(),
615 &rRtf);
616 rRtf.WriteOString("}");
617 rRtf.WriteOString(SAL_NEWLINE_STRING);
619 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_RESULT);
620 rRtf.WriteOString("{" OOO_STRING_SVTOOLS_RTF_PICT);
622 Size aMapped(rGraphic.GetPrefSize());
623 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICW);
624 rRtf.WriteOString(OString::number(aMapped.Width()));
625 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICH);
626 rRtf.WriteOString(OString::number(aMapped.Height()));
628 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
629 rRtf.WriteOString(OString::number(nWidth));
630 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
631 rRtf.WriteOString(OString::number(nHeight));
632 rRtf.WriteOString(OOO_STRING_SVTOOLS_RTF_WMETAFILE "8");
633 rRtf.WriteOString(SAL_NEWLINE_STRING);
635 if (pPresentationData)
637 msfilter::rtfutil::WriteHex(pPresentationData, nPresentationData, &rRtf);
638 rRtf.WriteOString(SAL_NEWLINE_STRING);
641 // End pict.
642 rRtf.WriteOString("}");
644 // End result.
645 rRtf.WriteOString("}");
647 // End object.
648 rRtf.WriteOString("}");
649 return true;
653 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */