Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/filter/html/htmlreqifreader.cxx
Warning:line 323, column 1
Potential leak of memory pointed to by 'xStorage.pObj'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name htmlreqifreader.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/filter/html/htmlreqifreader.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 */
9
10#include "htmlreqifreader.hxx"
11
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
24namespace
25{
26/// RTF parser that just extracts a single OLE2 object from a file.
27class ReqIfRtfReader : public SvRTFParser
28{
29public:
30 ReqIfRtfReader(SvStream& rStream);
31 void NextToken(int nToken) override;
32 bool WriteObjectData(SvStream& rOLE);
33
34private:
35 bool m_bInObjData = false;
36 OStringBuffer m_aHex;
37};
38
39ReqIfRtfReader::ReqIfRtfReader(SvStream& rStream)
40 : SvRTFParser(rStream)
41{
42}
43
44void ReqIfRtfReader::NextToken(int nToken)
45{
46 switch (nToken)
47 {
48 case '}':
49 m_bInObjData = false;
50 break;
51 case RTF_TEXTTOKEN:
52 if (m_bInObjData)
53 m_aHex.append(OUStringToOString(aToken, RTL_TEXTENCODING_ASCII_US(((rtl_TextEncoding) 11))));
54 break;
55 case RTF_OBJDATA:
56 m_bInObjData = true;
57 break;
58 }
59}
60
61bool ReqIfRtfReader::WriteObjectData(SvStream& rOLE)
62{
63 return msfilter::rtfutil::ExtractOLE2FromObjdata(m_aHex.makeStringAndClear(), rOLE);
64}
65
66/// Looks up what OLE1 calls the ClassName, see [MS-OLEDS] 2.3.8 CompObjStream.
67OString ExtractOLEClassName(const tools::SvRef<SotStorage>& xStorage)
68{
69 OString aRet;
70
71 SotStorageStream* pCompObj = xStorage->OpenSotStream("\1CompObj");
72 if (!pCompObj)
73 return aRet;
74
75 pCompObj->Seek(0);
76 pCompObj->SeekRel(28); // Header
77 if (!pCompObj->good())
78 return aRet;
79
80 sal_uInt32 nData;
81 pCompObj->ReadUInt32(nData); // AnsiUserType
82 pCompObj->SeekRel(nData);
83 if (!pCompObj->good())
84 return aRet;
85
86 pCompObj->ReadUInt32(nData); // AnsiClipboardFormat
87 pCompObj->SeekRel(nData);
88 if (!pCompObj->good())
89 return aRet;
90
91 pCompObj->ReadUInt32(nData); // Reserved1
92 return read_uInt8s_ToOString(*pCompObj, nData - 1); // -1 because it is null-terminated
93}
94
95/// Parses the presentation stream of an OLE2 storage.
96bool ParseOLE2Presentation(SvStream& rOle2, sal_uInt32& nWidth, sal_uInt32& nHeight,
97 SvStream& rPresentationData)
98{
99 // See [MS-OLEDS] 2.3.4, OLEPresentationStream
100 rOle2.Seek(0);
101 tools::SvRef<SotStorage> pStorage = new SotStorage(rOle2);
102 tools::SvRef<SotStorageStream> xOle2Presentation
103 = pStorage->OpenSotStream("\002OlePres000", StreamMode::STD_READ);
104
105 // Read AnsiClipboardFormat.
106 sal_uInt32 nMarkerOrLength = 0;
107 xOle2Presentation->ReadUInt32(nMarkerOrLength);
108 if (nMarkerOrLength != 0xffffffff)
109 // FormatOrAnsiString is not present
110 return false;
111 sal_uInt32 nFormatOrAnsiLength = 0;
112 xOle2Presentation->ReadUInt32(nFormatOrAnsiLength);
113 if (nFormatOrAnsiLength != 0x00000003) // CF_METAFILEPICT
114 return false;
115
116 // Read TargetDeviceSize.
117 sal_uInt32 nTargetDeviceSize = 0;
118 xOle2Presentation->ReadUInt32(nTargetDeviceSize);
119 if (nTargetDeviceSize != 0x00000004)
120 // TargetDevice is present
121 return false;
122
123 sal_uInt32 nAspect = 0;
124 xOle2Presentation->ReadUInt32(nAspect);
125 sal_uInt32 nLindex = 0;
126 xOle2Presentation->ReadUInt32(nLindex);
127 sal_uInt32 nAdvf = 0;
128 xOle2Presentation->ReadUInt32(nAdvf);
129 sal_uInt32 nReserved1 = 0;
130 xOle2Presentation->ReadUInt32(nReserved1);
131 xOle2Presentation->ReadUInt32(nWidth);
132 xOle2Presentation->ReadUInt32(nHeight);
133 sal_uInt32 nSize = 0;
134 xOle2Presentation->ReadUInt32(nSize);
135
136 // Read Data.
137 if (nSize > xOle2Presentation->remainingSize())
138 return false;
139 std::vector<char> aBuffer(nSize);
140 xOle2Presentation->ReadBytes(aBuffer.data(), aBuffer.size());
141 rPresentationData.WriteBytes(aBuffer.data(), aBuffer.size());
142
143 return true;
144}
145
146/**
147 * Inserts an OLE1 header before an OLE2 storage, assuming that the storage has an Ole10Native
148 * stream.
149 */
150OString InsertOLE1HeaderFromOle10NativeStream(const tools::SvRef<SotStorage>& xStorage,
151 SwOLENode& rOLENode, SvStream& rOle1)
152{
153 tools::SvRef<SotStorageStream> xOle1Stream
154 = xStorage->OpenSotStream("\1Ole10Native", StreamMode::STD_READ);
155 sal_uInt32 nOle1Size = 0;
156 xOle1Stream->ReadUInt32(nOle1Size);
157
158 OString aClassName("Package");
159
160 // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
161 rOle1.Seek(0);
162 // OLEVersion.
163 rOle1.WriteUInt32(0x00000501);
164
165 // FormatID is EmbeddedObject.
166 rOle1.WriteUInt32(0x00000002);
167
168 // ClassName
169 rOle1.WriteUInt32(aClassName.isEmpty() ? 0 : aClassName.getLength() + 1);
170 if (!aClassName.isEmpty())
171 {
172 rOle1.WriteOString(aClassName);
173 // Null terminated pascal string.
174 rOle1.WriteChar(0);
175 }
176
177 // TopicName.
178 rOle1.WriteUInt32(0);
179
180 // ItemName.
181 rOle1.WriteUInt32(0);
182
183 // NativeDataSize
184 rOle1.WriteUInt32(nOle1Size);
185
186 // Write the actual native data.
187 rOle1.WriteStream(*xOle1Stream, nOle1Size);
188
189 // Write Presentation.
190 if (!rOLENode.GetGraphic())
191 {
192 return aClassName;
193 }
194
195 const Graphic& rGraphic = *rOLENode.GetGraphic();
196 Size aSize = rOLENode.GetTwipSize();
197 SvMemoryStream aGraphicStream;
198 if (GraphicConverter::Export(aGraphicStream, rGraphic, ConvertDataFormat::WMF) != ERRCODE_NONEErrCode(0))
199 {
200 return aClassName;
201 }
202
203 auto pGraphicAry = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
204 sal_uInt64 nPresentationData = aGraphicStream.TellEnd();
205 msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nPresentationData);
206
207 // OLEVersion.
208 rOle1.WriteUInt32(0x00000501);
209 // FormatID: constant means the ClassName field is present.
210 rOle1.WriteUInt32(0x00000005);
211 // ClassName: null terminated pascal string.
212 OString aPresentationClassName("METAFILEPICT");
213 rOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
214 rOle1.WriteOString(aPresentationClassName);
215 rOle1.WriteChar(0);
216 // Width.
217 rOle1.WriteUInt32(aSize.getWidth());
218 // Height.
219 rOle1.WriteUInt32(aSize.getHeight() * -1);
220 // PresentationDataSize
221 rOle1.WriteUInt32(8 + nPresentationData);
222 // Reserved1-4.
223 rOle1.WriteUInt16(0x0008);
224 rOle1.WriteUInt16(0x31b1);
225 rOle1.WriteUInt16(0x1dd9);
226 rOle1.WriteUInt16(0x0000);
227 rOle1.WriteBytes(pGraphicAry, nPresentationData);
228
229 return aClassName;
230}
231
232/**
233 * Writes an OLE1 header and data from rOle2 to rOle1.
234 *
235 * In case rOle2 has presentation data, then its size is written to nWidth/nHeight. Otherwise
236 * nWidth/nHeight/pPresentationData/nPresentationData is used for the presentation data.
237 */
238OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1, sal_uInt32& nWidth, sal_uInt32& nHeight,
239 SwOLENode& rOLENode, const sal_uInt8* pPresentationData,
240 sal_uInt64 nPresentationData)
241{
242 rOle2.Seek(0);
243 tools::SvRef<SotStorage> xStorage(new SotStorage(rOle2));
4
Memory is allocated
244 if (xStorage->GetError() != ERRCODE_NONEErrCode(0))
5
Taking true branch
245 return OString();
246
247 if (xStorage->IsStream("\1Ole10Native"))
248 {
249 return InsertOLE1HeaderFromOle10NativeStream(xStorage, rOLENode, rOle1);
250 }
251
252 OString aClassName = ExtractOLEClassName(xStorage);
253
254 // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
255 rOle1.Seek(0);
256 // OLEVersion.
257 rOle1.WriteUInt32(0x00000501);
258
259 // FormatID is EmbeddedObject.
260 rOle1.WriteUInt32(0x00000002);
261
262 // ClassName
263 rOle1.WriteUInt32(aClassName.isEmpty() ? 0 : aClassName.getLength() + 1);
264 if (!aClassName.isEmpty())
265 {
266 rOle1.WriteOString(aClassName);
267 // Null terminated pascal string.
268 rOle1.WriteChar(0);
269 }
270
271 // TopicName.
272 rOle1.WriteUInt32(0);
273
274 // ItemName.
275 rOle1.WriteUInt32(0);
276
277 // NativeDataSize
278 rOle1.WriteUInt32(rOle2.TellEnd());
279
280 // Write the actual native data.
281 rOle2.Seek(0);
282 rOle1.WriteStream(rOle2);
283
284 // Write Presentation.
285 SvMemoryStream aPresentationData;
286 // OLEVersion.
287 rOle1.WriteUInt32(0x00000501);
288 // FormatID: constant means the ClassName field is present.
289 rOle1.WriteUInt32(0x00000005);
290 // ClassName: null terminated pascal string.
291 OString aPresentationClassName("METAFILEPICT");
292 rOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
293 rOle1.WriteOString(aPresentationClassName);
294 rOle1.WriteChar(0);
295 const sal_uInt8* pBytes = nullptr;
296 sal_uInt64 nBytes = 0;
297 if (ParseOLE2Presentation(rOle2, nWidth, nHeight, aPresentationData))
298 {
299 // Take presentation data for OLE1 from OLE2.
300 pBytes = static_cast<const sal_uInt8*>(aPresentationData.GetData());
301 nBytes = aPresentationData.Tell();
302 }
303 else
304 {
305 // Take presentation data for OLE1 from RTF.
306 pBytes = pPresentationData;
307 nBytes = nPresentationData;
308 }
309 // Width.
310 rOle1.WriteUInt32(nWidth);
311 // Height.
312 rOle1.WriteUInt32(nHeight * -1);
313 // PresentationDataSize
314 rOle1.WriteUInt32(8 + nPresentationData);
315 // Reserved1-4.
316 rOle1.WriteUInt16(0x0008);
317 rOle1.WriteUInt16(0x31b1);
318 rOle1.WriteUInt16(0x1dd9);
319 rOle1.WriteUInt16(0x0000);
320 rOle1.WriteBytes(pBytes, nBytes);
321
322 return aClassName;
323}
6
Potential leak of memory pointed to by 'xStorage.pObj'
324
325/// Writes presentation data with the specified size to rRtf as an RTF hexdump.
326void WrapOleGraphicInRtf(SvStream& rRtf, sal_uInt32 nWidth, sal_uInt32 nHeight,
327 const sal_uInt8* pPresentationData, sal_uInt64 nPresentationData)
328{
329 // Start result.
330 rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_RESULT"\\result");
331
332 // Start pict.
333 rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_PICT"\\pict");
334
335 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_WMETAFILE"\\wmetafile" "8");
336 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICW"\\picw");
337 rRtf.WriteOString(OString::number(nWidth));
338 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICH"\\pich");
339 rRtf.WriteOString(OString::number(nHeight));
340 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICWGOAL"\\picwgoal");
341 rRtf.WriteOString(OString::number(nWidth));
342 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICHGOAL"\\pichgoal");
343 rRtf.WriteOString(OString::number(nHeight));
344 if (pPresentationData)
345 {
346 rRtf.WriteCharPtr(SAL_NEWLINE_STRING"\n");
347 msfilter::rtfutil::WriteHex(pPresentationData, nPresentationData, &rRtf);
348 }
349
350 // End pict.
351 rRtf.WriteCharPtr("}");
352
353 // End result.
354 rRtf.WriteCharPtr("}");
355}
356}
357
358namespace SwReqIfReader
359{
360bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle, bool& bOwnFormat)
361{
362 // Add missing header/footer.
363 SvMemoryStream aRtf;
364 aRtf.WriteOString("{\\rtf1");
365 aRtf.WriteStream(rRtf);
366 aRtf.WriteOString("}");
367 aRtf.Seek(0);
368
369 // Read the RTF markup.
370 tools::SvRef<ReqIfRtfReader> xReader(new ReqIfRtfReader(aRtf));
371 SvParserState eState = xReader->CallParser();
372 if (eState == SvParserState::Error)
373 return false;
374
375 // Write the OLE2 data.
376 if (!xReader->WriteObjectData(rOle))
377 return false;
378
379 tools::SvRef<SotStorage> pStorage = new SotStorage(rOle);
380 OUString aFilterName = SvxMSDffManager::GetFilterNameFromClassID(pStorage->GetClassName());
381 bOwnFormat = !aFilterName.isEmpty();
382 if (!bOwnFormat)
383 {
384 // Real OLE2 data, we're done.
385 rOle.Seek(0);
386 return true;
387 }
388
389 // ODF-in-OLE2 case, extract actual data.
390 SvMemoryStream aMemory;
391 SvxMSDffManager::ExtractOwnStream(*pStorage, aMemory);
392 rOle.Seek(0);
393 aMemory.Seek(0);
394 rOle.WriteStream(aMemory);
395 // Stream length is current position + 1.
396 rOle.SetStreamSize(aMemory.GetSize() + 1);
397 rOle.Seek(0);
398 return true;
399}
400
401bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode)
402{
403 sal_uInt64 nPos = rOle2.Tell();
404 comphelper::ScopeGuard g([&rOle2, nPos] { rOle2.Seek(nPos); });
405
406 // Write OLE1 header, then the RTF wrapper.
407 SvMemoryStream aOLE1;
408
409 // Prepare presentation data early, so it's available to both OLE1 and RTF.
410 Size aSize(rOLENode.GetTwipSize());
411 sal_uInt32 nWidth = aSize.getWidth();
412 sal_uInt32 nHeight = aSize.getHeight();
413 const Graphic* pGraphic = rOLENode.GetGraphic();
414 const sal_uInt8* pPresentationData = nullptr;
415 sal_uInt64 nPresentationData = 0;
416 SvMemoryStream aGraphicStream;
417 if (pGraphic)
1
Assuming 'pGraphic' is null
2
Taking false branch
418 {
419 if (GraphicConverter::Export(aGraphicStream, *pGraphic, ConvertDataFormat::WMF)
420 == ERRCODE_NONEErrCode(0))
421 {
422 pPresentationData = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
423 nPresentationData = aGraphicStream.TellEnd();
424 msfilter::rtfutil::StripMetafileHeader(pPresentationData, nPresentationData);
425 }
426 }
427 OString aClassName = InsertOLE1Header(rOle2, aOLE1, nWidth, nHeight, rOLENode,
3
Calling 'InsertOLE1Header'
428 pPresentationData, nPresentationData);
429
430 // Start object.
431 rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_OBJECT"\\object");
432 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_OBJEMB"\\objemb");
433
434 // Start objclass.
435 rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_IGNORE"\\*" OOO_STRING_SVTOOLS_RTF_OBJCLASS"\\objclass" " ");
436 rRtf.WriteOString(aClassName);
437 // End objclass.
438 rRtf.WriteCharPtr("}");
439
440 // Object size.
441 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_OBJW"\\objw");
442 rRtf.WriteOString(OString::number(nWidth));
443 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_OBJH"\\objh");
444 rRtf.WriteOString(OString::number(nHeight));
445
446 // Start objdata.
447 rRtf.WriteCharPtr(
448 "{" OOO_STRING_SVTOOLS_RTF_IGNORE"\\*" OOO_STRING_SVTOOLS_RTF_OBJDATA"\\objdata" SAL_NEWLINE_STRING"\n");
449 msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOLE1.GetData()), aOLE1.GetSize(),
450 &rRtf);
451 // End objdata.
452 rRtf.WriteCharPtr("}");
453
454 if (pPresentationData)
455 {
456 WrapOleGraphicInRtf(rRtf, nWidth, nHeight, pPresentationData, nPresentationData);
457 }
458
459 // End object.
460 rRtf.WriteCharPtr("}");
461
462 return true;
463}
464
465bool WrapGraphicInRtf(const Graphic& rGraphic, const Size& rLogicSize, SvStream& rRtf)
466{
467 rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_PICT"\\pict");
468
469 GfxLink aLink = rGraphic.GetGfxLink();
470 const sal_uInt8* pGraphicAry = aLink.GetData();
471 sal_uInt64 nSize = aLink.GetDataSize();
472 OString aBlipType;
473 bool bIsWMF = false;
474 switch (aLink.GetType())
475 {
476 case GfxLinkType::NativeBmp:
477 aBlipType = OOO_STRING_SVTOOLS_RTF_WBITMAP"\\wbitmap";
478 break;
479 case GfxLinkType::NativeJpg:
480 aBlipType = OOO_STRING_SVTOOLS_RTF_JPEGBLIP"\\jpegblip";
481 break;
482 case GfxLinkType::NativePng:
483 aBlipType = OOO_STRING_SVTOOLS_RTF_PNGBLIP"\\pngblip";
484 break;
485 case GfxLinkType::NativeWmf:
486 if (aLink.IsEMF())
487 aBlipType = OOO_STRING_SVTOOLS_RTF_EMFBLIP"\\emfblip";
488 else
489 {
490 aBlipType = OOO_STRING_SVTOOLS_RTF_WMETAFILE"\\wmetafile";
491 bIsWMF = true;
492 }
493 break;
494 default:
495 break;
496 }
497
498 if (aBlipType.isEmpty())
499 return false;
500
501 rRtf.WriteOString(aBlipType);
502
503 Size aMapped(rGraphic.GetPrefSize());
504 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICW"\\picw");
505 rRtf.WriteOString(OString::number(aMapped.Width()));
506 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICH"\\pich");
507 rRtf.WriteOString(OString::number(aMapped.Height()));
508
509 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICWGOAL"\\picwgoal");
510 rRtf.WriteOString(OString::number(rLogicSize.Width()));
511 rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICHGOAL"\\pichgoal");
512 rRtf.WriteOString(OString::number(rLogicSize.Height()));
513
514 if (bIsWMF)
515 {
516 rRtf.WriteOString(OString::number(8));
517 msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nSize);
518 }
519 rRtf.WriteOString(SAL_NEWLINE_STRING"\n");
520
521 msfilter::rtfutil::WriteHex(pGraphicAry, nSize, &rRtf);
522 rRtf.WriteOString(SAL_NEWLINE_STRING"\n");
523
524 // End pict.
525 rRtf.WriteCharPtr("}");
526 return true;
527}
528}
529
530/* vim:set shiftwidth=4 softtabstop=4 expandtab: */