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  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <sal/macros.h>
24 #include <com/sun/star/embed/XTransactedObject.hpp>
25 #include <com/sun/star/embed/ElementModes.hpp>
26 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/io/NotConnectedException.hpp>
28 #include <com/sun/star/lang/XServiceInfo.hpp>
29 #include <com/sun/star/lang/XInitialization.hpp>
30 #include <comphelper/fileformat.h>
31 #include <comphelper/graphicmimetype.hxx>
32 #include <cppuhelper/compbase.hxx>
33 #include <cppuhelper/implbase.hxx>
34 #include <cppuhelper/supportsservice.hxx>
35 
36 #include <rtl/ref.hxx>
37 #include <unotools/ucbstreamhelper.hxx>
38 #include <unotools/streamwrap.hxx>
39 #include <unotools/tempfile.hxx>
40 #include <unotools/saveopt.hxx>
41 #include <vcl/cvtgrf.hxx>
42 #include <vcl/gfxlink.hxx>
43 #include <vcl/metaact.hxx>
44 #include <tools/zcodec.hxx>
45 
46 #include <vcl/GraphicObject.hxx>
47 #include <vcl/graphicfilter.hxx>
48 #include <svx/xmlgrhlp.hxx>
49 #include <svx/xmleohlp.hxx>
50 
51 #include <algorithm>
52 #include <memory>
53 #include <utility>
54 
55 using namespace com::sun::star;
56 using namespace com::sun::star::uno;
57 using namespace com::sun::star::io;
58 
59 namespace com { namespace sun { namespace star { namespace uno { class XComponentContext; } } } }
60 
61 #define XML_GRAPHICSTORAGE_NAME     "Pictures"
62 #define XML_GRAPHICOBJECT_URL_BASE  "vnd.sun.star.GraphicObject:"
63 
64 namespace {
65 
ImplCheckForEPS(GDIMetaFile const & rMtf)66 const MetaCommentAction* ImplCheckForEPS( GDIMetaFile const & rMtf )
67 {
68     const MetaCommentAction* pComment = nullptr;
69 
70     if ( rMtf.GetActionSize() >= 2
71             && rMtf.GetAction(0)->GetType() == MetaActionType::EPS
72             && rMtf.GetAction(1)->GetType() == MetaActionType::COMMENT
73             && ( static_cast<const MetaCommentAction*>(rMtf.GetAction( 1 ))->GetComment() == "EPSReplacementGraphic" ) )
74         pComment = static_cast<const MetaCommentAction*>(rMtf.GetAction( 1 ));
75 
76     return pComment;
77 }
78 
79 namespace xmloff {
80 
81 class GraphicInputStream : public cppu::WeakImplHelper<XInputStream>
82 {
83 private:
84     virtual sal_Int32 SAL_CALL readBytes(Sequence<sal_Int8> & aData, sal_Int32 nBytesToRead) override;
85     virtual sal_Int32 SAL_CALL readSomeBytes(Sequence<sal_Int8> & aData, sal_Int32 nMaxBytesToRead) override;
86     virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
87     virtual sal_Int32 SAL_CALL available() override;
88     virtual void SAL_CALL closeInput() override;
89 
90 private:
91     utl::TempFile maTempFile;
92     Reference<XInputStream> mxStreamWrapper;
93 
94 public:
95 
96     explicit GraphicInputStream(GraphicObject const & raGraphicObject, const OUString & rMimeType);
97     GraphicInputStream(const GraphicInputStream&) = delete;
98 
99     GraphicInputStream& operator=(const GraphicInputStream&) = delete;
100 
exists() const101     bool exists() const
102     {
103         return mxStreamWrapper.is();
104     }
105 };
106 
107 
GraphicInputStream(GraphicObject const & aGraphicObject,const OUString & rMimeType)108 GraphicInputStream::GraphicInputStream(GraphicObject const & aGraphicObject, const OUString & rMimeType)
109 {
110     maTempFile.EnableKillingFile();
111 
112     if (aGraphicObject.GetType() != GraphicType::NONE)
113     {
114         std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream(maTempFile.GetURL(), StreamMode::WRITE | StreamMode::TRUNC);
115 
116         if (pStream)
117         {
118             const Graphic& aGraphic(aGraphicObject.GetGraphic());
119             const GfxLink aGfxLink(aGraphic.GetGfxLink());
120             bool bRet = false;
121 
122             if (aGfxLink.GetDataSize() && aGfxLink.GetData())
123             {
124                 if (rMimeType.isEmpty())
125                 {
126                     pStream->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
127                     bRet = (pStream->GetError() == ERRCODE_NONE);
128                 }
129                 else
130                 {
131                     GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
132                     bRet = (rFilter.ExportGraphic(aGraphic, "", *pStream, rFilter.GetExportFormatNumberForMediaType(rMimeType)) == ERRCODE_NONE);
133                 }
134             }
135             else
136             {
137                 if (aGraphic.GetType() == GraphicType::Bitmap)
138                 {
139                     GraphicFilter & rFilter = GraphicFilter::GetGraphicFilter();
140                     OUString aFormat = rMimeType;
141 
142                     if (aGraphic.IsAnimated())
143                         aFormat = "image/gif";
144                     else if (aFormat.isEmpty())
145                         aFormat = "image/png";
146 
147                     bRet = (rFilter.ExportGraphic(aGraphic, "", *pStream, rFilter.GetExportFormatNumberForMediaType(aFormat)) == ERRCODE_NONE);
148                 }
149                 else if (rMimeType.isEmpty() && aGraphic.GetType() == GraphicType::GdiMetafile)
150                 {
151                     pStream->SetVersion(SOFFICE_FILEFORMAT_8);
152                     pStream->SetCompressMode(SvStreamCompressFlags::ZBITMAP);
153                     const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()).Write(*pStream);
154                     bRet = (pStream->GetError() == ERRCODE_NONE);
155                 }
156                 else if (!rMimeType.isEmpty())
157                 {
158                     GraphicFilter & rFilter = GraphicFilter::GetGraphicFilter();
159                     bRet = ( rFilter.ExportGraphic( aGraphic, "", *pStream, rFilter.GetExportFormatNumberForMediaType( rMimeType ) ) == ERRCODE_NONE );
160                 }
161             }
162 
163             if (bRet)
164             {
165                 pStream->Seek( 0 );
166                 mxStreamWrapper = new ::utl::OInputStreamWrapper(std::move(pStream));
167             }
168         }
169     }
170 }
171 
readBytes(Sequence<sal_Int8> & rData,sal_Int32 nBytesToRead)172 sal_Int32 SAL_CALL GraphicInputStream::readBytes(Sequence<sal_Int8> & rData, sal_Int32 nBytesToRead)
173 {
174     if (!mxStreamWrapper.is())
175         throw NotConnectedException();
176 
177     return mxStreamWrapper->readBytes(rData, nBytesToRead);
178 }
179 
readSomeBytes(Sequence<sal_Int8> & rData,sal_Int32 nMaxBytesToRead)180 sal_Int32 SAL_CALL GraphicInputStream::readSomeBytes(Sequence<sal_Int8>& rData, sal_Int32 nMaxBytesToRead )
181 {
182     if (!mxStreamWrapper.is())
183         throw NotConnectedException() ;
184 
185     return mxStreamWrapper->readSomeBytes(rData, nMaxBytesToRead);
186 }
187 
skipBytes(sal_Int32 nBytesToSkip)188 void SAL_CALL GraphicInputStream::skipBytes(sal_Int32 nBytesToSkip)
189 {
190     if (!mxStreamWrapper.is())
191         throw NotConnectedException();
192 
193     mxStreamWrapper->skipBytes(nBytesToSkip);
194 }
195 
available()196 sal_Int32 SAL_CALL GraphicInputStream::available()
197 {
198     if (!mxStreamWrapper.is())
199         throw NotConnectedException();
200 
201     return mxStreamWrapper->available();
202 }
203 
closeInput()204 void SAL_CALL GraphicInputStream::closeInput()
205 {
206     if (!mxStreamWrapper.is())
207         throw NotConnectedException();
208 
209     mxStreamWrapper->closeInput();
210 }
211 
212 } // end xmloff namespace
213 
214 class SvXMLGraphicOutputStream:
215     public cppu::WeakImplHelper<XOutputStream>
216 {
217 private:
218 
219     // XOutputStream
220     virtual void SAL_CALL           writeBytes( const Sequence< sal_Int8 >& rData ) override;
221     virtual void SAL_CALL           flush() override;
222     virtual void SAL_CALL           closeOutput() override;
223 
224 private:
225 
226     std::unique_ptr<::utl::TempFile> mpTmp;
227     std::unique_ptr<SvStream>        mpOStm;
228     Reference< XOutputStream >       mxStmWrapper;
229     std::unique_ptr<GraphicObject>   mxGrfObj;
230     bool                             mbClosed;
231 
232 public:
233 
234                                     SvXMLGraphicOutputStream();
235     virtual                         ~SvXMLGraphicOutputStream() override;
236                                     SvXMLGraphicOutputStream(const SvXMLGraphicOutputStream&) = delete;
237     SvXMLGraphicOutputStream&       operator=(const SvXMLGraphicOutputStream&) = delete;
238 
Exists() const239     bool                            Exists() const { return mxStmWrapper.is(); }
240     const GraphicObject&            GetGraphicObject();
241     Graphic GetGraphic();
242 };
243 
SvXMLGraphicOutputStream()244 SvXMLGraphicOutputStream::SvXMLGraphicOutputStream()
245     : mpTmp(new ::utl::TempFile)
246     , mxGrfObj(new GraphicObject)
247     , mbClosed(false)
248 {
249     mpTmp->EnableKillingFile();
250 
251     mpOStm = ::utl::UcbStreamHelper::CreateStream( mpTmp->GetURL(), StreamMode::WRITE | StreamMode::TRUNC );
252 
253     if( mpOStm )
254         mxStmWrapper = new ::utl::OOutputStreamWrapper( *mpOStm );
255 }
256 
~SvXMLGraphicOutputStream()257 SvXMLGraphicOutputStream::~SvXMLGraphicOutputStream()
258 {
259     mpTmp.reset();
260     mpOStm.reset();
261 }
262 
writeBytes(const Sequence<sal_Int8> & rData)263 void SAL_CALL SvXMLGraphicOutputStream::writeBytes( const Sequence< sal_Int8 >& rData )
264 {
265     if( !mxStmWrapper.is() )
266         throw NotConnectedException() ;
267 
268     mxStmWrapper->writeBytes( rData );
269 }
270 
flush()271 void SAL_CALL SvXMLGraphicOutputStream::flush()
272 {
273     if( !mxStmWrapper.is() )
274         throw NotConnectedException() ;
275 
276     mxStmWrapper->flush();
277 }
278 
closeOutput()279 void SAL_CALL SvXMLGraphicOutputStream::closeOutput()
280 {
281     if( !mxStmWrapper.is() )
282         throw NotConnectedException() ;
283 
284     mxStmWrapper->closeOutput();
285     mxStmWrapper.clear();
286 
287     mbClosed = true;
288 }
289 
GetGraphic()290 Graphic SvXMLGraphicOutputStream::GetGraphic()
291 {
292     Graphic aGraphic;
293 
294     if (mbClosed && mxGrfObj->GetType() == GraphicType::NONE && mpOStm)
295     {
296         mpOStm->Seek( 0 );
297         sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
298         sal_uInt16 nDeterminedFormat = GRFILTER_FORMAT_DONTKNOW;
299         GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, "", *mpOStm ,nFormat,&nDeterminedFormat);
300 
301         if (nDeterminedFormat == GRFILTER_FORMAT_DONTKNOW)
302         {
303             //Read the first two byte to check whether it is a gzipped stream, is so it may be in wmz or emz format
304             //unzip them and try again
305 
306             sal_uInt8    sFirstBytes[ 2 ];
307 
308             sal_uIntPtr nStreamLen = mpOStm->TellEnd();
309             mpOStm->Seek( 0 );
310 
311             if ( !nStreamLen )
312             {
313                 SvLockBytes* pLockBytes = mpOStm->GetLockBytes();
314                 if ( pLockBytes  )
315                     pLockBytes->SetSynchronMode();
316 
317                 nStreamLen = mpOStm->TellEnd();
318                 mpOStm->Seek( 0 );
319             }
320             if( nStreamLen >= 2 )
321             {
322                 //read two byte
323                 mpOStm->ReadBytes(sFirstBytes, 2);
324 
325                 if( sFirstBytes[0] == 0x1f && sFirstBytes[1] == 0x8b )
326                 {
327                     std::unique_ptr<SvMemoryStream> pDest(new SvMemoryStream);
328                     ZCodec aZCodec( 0x8000, 0x8000 );
329                     aZCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true);
330                     mpOStm->Seek( 0 );
331                     aZCodec.Decompress( *mpOStm, *pDest );
332 
333                     if (aZCodec.EndCompression())
334                     {
335                         sal_uIntPtr nStreamLen_ = pDest->TellEnd();
336                         if (nStreamLen_)
337                         {
338                             pDest->Seek(0);
339                             GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, "", *pDest ,nFormat,&nDeterminedFormat );
340                         }
341                     }
342                 }
343             }
344         }
345     }
346 
347     if (aGraphic.GetType() != GraphicType::NONE)
348     {
349         mpOStm.reset();
350         mpTmp.reset();
351      }
352     return aGraphic;
353 }
354 
GetGraphicObject()355 const GraphicObject& SvXMLGraphicOutputStream::GetGraphicObject()
356 {
357     Graphic aGraphic(GetGraphic());
358     if (aGraphic.GetType() != GraphicType::NONE)
359     {
360         mxGrfObj.reset(new GraphicObject(aGraphic));
361     }
362     return *mxGrfObj;
363 }
364 
365 }
366 
SvXMLGraphicHelper(SvXMLGraphicHelperMode eCreateMode)367 SvXMLGraphicHelper::SvXMLGraphicHelper(SvXMLGraphicHelperMode eCreateMode)
368     : cppu::WeakComponentImplHelper<document::XGraphicObjectResolver,
369                                     document::XGraphicStorageHandler,
370                                     document::XBinaryStreamResolver>(maMutex)
371 {
372     Init( nullptr, eCreateMode );
373 }
374 
SvXMLGraphicHelper()375 SvXMLGraphicHelper::SvXMLGraphicHelper()
376     : cppu::WeakComponentImplHelper<document::XGraphicObjectResolver,
377                                     document::XGraphicStorageHandler,
378                                     document::XBinaryStreamResolver>(maMutex)
379     , meCreateMode(SvXMLGraphicHelperMode::Read)
380 {
381 }
382 
~SvXMLGraphicHelper()383 SvXMLGraphicHelper::~SvXMLGraphicHelper()
384 {
385 }
386 
disposing()387 void SAL_CALL SvXMLGraphicHelper::disposing()
388 {
389 }
390 
ImplGetStreamNames(const OUString & rURLStr,OUString & rPictureStorageName,OUString & rPictureStreamName)391 bool SvXMLGraphicHelper::ImplGetStreamNames( const OUString& rURLStr,
392                                                  OUString& rPictureStorageName,
393                                                  OUString& rPictureStreamName )
394 {
395     if (rURLStr.isEmpty())
396         return false;
397 
398     const OUString aURLStr {rURLStr.copy(rURLStr.lastIndexOf(':')+1)};
399 
400     if( !aURLStr.isEmpty() && aURLStr.indexOf('/')<0 ) // just one token?
401     {
402         rPictureStorageName = XML_GRAPHICSTORAGE_NAME;
403         rPictureStreamName = aURLStr;
404     }
405     else
406         SvXMLEmbeddedObjectHelper::splitObjectURL(aURLStr, rPictureStorageName, rPictureStreamName);
407 
408     SAL_WARN_IF(rPictureStreamName.isEmpty(), "svx", "SvXMLGraphicHelper::ImplInsertGraphicURL: invalid scheme: " << rURLStr);
409 
410     return !rPictureStreamName.isEmpty();
411 }
412 
ImplGetGraphicStorage(const OUString & rStorageName)413 uno::Reference < embed::XStorage > SvXMLGraphicHelper::ImplGetGraphicStorage( const OUString& rStorageName )
414 {
415     uno::Reference < embed::XStorage > xRetStorage;
416     if( mxRootStorage.is() )
417     {
418         try
419         {
420             maCurStorageName = rStorageName;
421             xRetStorage = mxRootStorage->openStorageElement(
422                 maCurStorageName,
423                 ( SvXMLGraphicHelperMode::Write == meCreateMode )
424                     ? embed::ElementModes::READWRITE
425                     : embed::ElementModes::READ );
426         }
427         catch ( uno::Exception& )
428         {
429         }
430         //#i43196# try again to open the storage element - this time readonly
431         if(!xRetStorage.is())
432         {
433             try
434             {
435                 maCurStorageName = rStorageName;
436                 xRetStorage = mxRootStorage->openStorageElement( maCurStorageName, embed::ElementModes::READ );
437             }
438             catch ( uno::Exception& )
439             {
440             }
441         }
442     }
443 
444     return xRetStorage;
445 }
446 
ImplGetGraphicStream(const OUString & rPictureStorageName,const OUString & rPictureStreamName)447 SvxGraphicHelperStream_Impl SvXMLGraphicHelper::ImplGetGraphicStream( const OUString& rPictureStorageName,
448                                                               const OUString& rPictureStreamName )
449 {
450     SvxGraphicHelperStream_Impl aRet;
451     aRet.xStorage = ImplGetGraphicStorage( rPictureStorageName );
452 
453     if( aRet.xStorage.is() )
454     {
455         sal_Int32 nMode = embed::ElementModes::READ;
456         if ( SvXMLGraphicHelperMode::Write == meCreateMode )
457         {
458             nMode = embed::ElementModes::READWRITE;
459         }
460 
461         aRet.xStream = aRet.xStorage->openStreamElement( rPictureStreamName, nMode );
462         if( aRet.xStream.is() && ( SvXMLGraphicHelperMode::Write == meCreateMode ) )
463         {
464             uno::Reference < beans::XPropertySet > xProps( aRet.xStream, uno::UNO_QUERY );
465             xProps->setPropertyValue( "UseCommonStoragePasswordEncryption", uno::makeAny( true) );
466         }
467     }
468 
469     return aRet;
470 }
471 
ImplGetGraphicMimeType(const OUString & rFileName)472 OUString SvXMLGraphicHelper::ImplGetGraphicMimeType( const OUString& rFileName )
473 {
474     if( ( rFileName.getLength() >= 4 ) && ( rFileName[ rFileName.getLength() - 4 ] == '.' ) )
475     {
476         const OString aExt(OUStringToOString(rFileName.copy(rFileName.getLength() - 3),
477             RTL_TEXTENCODING_ASCII_US));
478         return comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension( aExt );
479     }
480 
481     return OUString();
482 }
483 
ImplReadGraphic(const OUString & rPictureStorageName,const OUString & rPictureStreamName)484 Graphic SvXMLGraphicHelper::ImplReadGraphic( const OUString& rPictureStorageName,
485                                              const OUString& rPictureStreamName )
486 {
487     Graphic aReturnGraphic;
488     SvxGraphicHelperStream_Impl aStream( ImplGetGraphicStream( rPictureStorageName, rPictureStreamName ) );
489     if (aStream.xStream.is())
490     {
491         GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
492         std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(aStream.xStream));
493         Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(*pStream);
494         if (!aGraphic.IsNone())
495             aReturnGraphic = aGraphic;
496         else
497             rGraphicFilter.ImportGraphic(aReturnGraphic, "", *pStream);
498     }
499 
500     return aReturnGraphic;
501 }
502 
Init(const uno::Reference<embed::XStorage> & rXMLStorage,SvXMLGraphicHelperMode eCreateMode,const OUString & rGraphicMimeType)503 void SvXMLGraphicHelper::Init( const uno::Reference < embed::XStorage >& rXMLStorage,
504                                SvXMLGraphicHelperMode eCreateMode,
505                                const OUString& rGraphicMimeType )
506 {
507     mxRootStorage = rXMLStorage;
508     meCreateMode = eCreateMode;
509     maOutputMimeType = rGraphicMimeType;
510 }
511 
Create(const uno::Reference<embed::XStorage> & rXMLStorage,SvXMLGraphicHelperMode eCreateMode)512 rtl::Reference<SvXMLGraphicHelper> SvXMLGraphicHelper::Create( const uno::Reference < embed::XStorage >& rXMLStorage,
513                                                 SvXMLGraphicHelperMode eCreateMode )
514 {
515     rtl::Reference<SvXMLGraphicHelper> pThis = new SvXMLGraphicHelper;
516     pThis->Init( rXMLStorage, eCreateMode, OUString() );
517 
518     return pThis;
519 }
520 
Create(SvXMLGraphicHelperMode eCreateMode,const OUString & rGraphicMimeType)521 rtl::Reference<SvXMLGraphicHelper> SvXMLGraphicHelper::Create( SvXMLGraphicHelperMode eCreateMode,
522                                               const OUString& rGraphicMimeType )
523 {
524     rtl::Reference<SvXMLGraphicHelper> pThis = new SvXMLGraphicHelper;
525 
526     pThis->Init( nullptr, eCreateMode, rGraphicMimeType );
527 
528     return pThis;
529 }
530 
531 namespace
532 {
533 
splitUserDataFromURL(OUString const & rWholeURL,OUString & rJustURL,OUString & rUserData)534 void splitUserDataFromURL(OUString const & rWholeURL, OUString & rJustURL, OUString & rUserData)
535 {
536     sal_Int32 nUser = rWholeURL.indexOf('?');
537     if (nUser >= 0)
538     {
539         rJustURL = rWholeURL.copy(0, nUser);
540         nUser++;
541         rUserData = rWholeURL.copy(nUser);
542     }
543     else
544     {
545         rJustURL = rWholeURL;
546     }
547 }
548 
549 } // end anonymous namespace
550 
551 // XGraphicObjectResolver
resolveGraphicObjectURL(const OUString &)552 OUString SAL_CALL SvXMLGraphicHelper::resolveGraphicObjectURL( const OUString& /*rURL*/ )
553 {
554     throw uno::RuntimeException("XGraphicObjectResolver has been removed in LibreOffice 6.1");
555 }
556 
557 // XGraphicStorageHandler
loadGraphic(OUString const & rURL)558 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicHelper::loadGraphic(OUString const & rURL)
559 {
560     osl::MutexGuard aGuard(maMutex);
561 
562     uno::Reference<graphic::XGraphic> xGraphic;
563 
564     OUString aURLOnly;
565     OUString aUserData;
566     splitUserDataFromURL(rURL, aURLOnly, aUserData);
567 
568     auto aIterator = maGraphicObjects.find(aURLOnly);
569     if (aIterator != maGraphicObjects.end())
570     {
571         return aIterator->second;
572     }
573 
574     OUString aPictureStorageName, aPictureStreamName;
575 
576     if (ImplGetStreamNames(aURLOnly, aPictureStorageName, aPictureStreamName))
577     {
578         const GraphicObject aGraphicObject(ImplReadGraphic(aPictureStorageName, aPictureStreamName));
579 
580         if (aGraphicObject.GetType() != GraphicType::NONE)
581         {
582             xGraphic = aGraphicObject.GetGraphic().GetXGraphic();
583             maGraphicObjects[aURLOnly] = xGraphic;
584         }
585     }
586 
587     return xGraphic;
588 }
589 
loadGraphicFromOutputStream(uno::Reference<io::XOutputStream> const & rxOutputStream)590 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicHelper::loadGraphicFromOutputStream(uno::Reference<io::XOutputStream> const & rxOutputStream)
591 {
592     osl::MutexGuard aGuard(maMutex);
593 
594     uno::Reference<graphic::XGraphic> xGraphic;
595 
596     if ((SvXMLGraphicHelperMode::Read == meCreateMode) && rxOutputStream.is())
597     {
598 
599         SvXMLGraphicOutputStream* pGraphicOutputStream = static_cast<SvXMLGraphicOutputStream*>(rxOutputStream.get());
600         if (pGraphicOutputStream)
601         {
602             xGraphic = pGraphicOutputStream->GetGraphic().GetXGraphic();
603         }
604     }
605     return xGraphic;
606 }
607 
saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,OUString & rOutSavedMimeType,OUString const & rRequestName)608 OUString SAL_CALL SvXMLGraphicHelper::saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
609                                                         OUString & rOutSavedMimeType, OUString const & rRequestName)
610 {
611     return implSaveGraphic(rxGraphic, rOutSavedMimeType, rRequestName);
612 }
613 
saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic)614 OUString SAL_CALL SvXMLGraphicHelper::saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic)
615 {
616     OUString aOutMimeType;
617     return implSaveGraphic(rxGraphic, aOutMimeType, OUString());
618 }
619 
implSaveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,OUString & rOutSavedMimeType,OUString const & rRequestName)620 OUString SvXMLGraphicHelper::implSaveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
621                                              OUString & rOutSavedMimeType, OUString const & rRequestName)
622 {
623     Graphic aGraphic(rxGraphic);
624 
625     auto aIterator = maExportGraphics.find(aGraphic);
626     if (aIterator != maExportGraphics.end())
627     {
628         auto const & aURLAndMimePair = aIterator->second;
629         rOutSavedMimeType = aURLAndMimePair.second;
630         return aURLAndMimePair.first;
631     }
632 
633     GraphicObject aGraphicObject(aGraphic);
634 
635     if (aGraphicObject.GetType() != GraphicType::NONE)
636     {
637         const GfxLink aGfxLink(aGraphic.GetGfxLink());
638         OUString aExtension;
639         bool bUseGfxLink = true;
640 
641         if (aGfxLink.GetDataSize())
642         {
643             switch (aGfxLink.GetType())
644             {
645                 case GfxLinkType::EpsBuffer: aExtension = ".eps"; break;
646                 case GfxLinkType::NativeGif: aExtension = ".gif"; break;
647                 // #i15508# added BMP type for better exports (checked, works)
648                 case GfxLinkType::NativeBmp: aExtension = ".bmp"; break;
649                 case GfxLinkType::NativeJpg: aExtension = ".jpg"; break;
650                 case GfxLinkType::NativePng: aExtension = ".png"; break;
651                 case GfxLinkType::NativeTif: aExtension = ".tif"; break;
652                 case GfxLinkType::NativeWmf:
653                     if (aGfxLink.IsEMF())
654                         aExtension = ".emf";
655                     else
656                         aExtension = ".wmf";
657                     break;
658                 case GfxLinkType::NativeMet: aExtension = ".met"; break;
659                 case GfxLinkType::NativePct: aExtension = ".pct"; break;
660                 case GfxLinkType::NativeSvg:
661                     // backward-compat kludge: since no released OOo
662                     // version to date can handle svg properly, wrap it up
663                     // into an svm. slight catch22 here, since strict ODF
664                     // conformance _recommends_ svg - then again, most old
665                     // ODF consumers are believed to be OOo
666                     if (SvtSaveOptions().GetODFDefaultVersion() <= SvtSaveOptions::ODFVER_012)
667                     {
668                         bUseGfxLink = false;
669                         aExtension = ".svm";
670                     }
671                     else
672                     {
673                         aExtension = ".svg";
674                     }
675                     break;
676                 case GfxLinkType::NativePdf: aExtension = ".pdf"; break;
677 
678                 default:
679                     aExtension = ".grf";
680                 break;
681             }
682         }
683         else
684         {
685             if (aGraphicObject.GetType() == GraphicType::Bitmap)
686             {
687                 if (aGraphicObject.IsAnimated())
688                     aExtension = ".gif";
689                 else
690                     aExtension = ".png";
691             }
692             else if (aGraphicObject.GetType() == GraphicType::GdiMetafile)
693             {
694                 // SJ: first check if this metafile is just an eps file, then we will store the eps instead of svm
695                 GDIMetaFile& rMetafile(const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()));
696 
697                 if (ImplCheckForEPS(rMetafile))
698                     aExtension = ".eps";
699                 else
700                     aExtension = ".svm";
701             }
702         }
703 
704         OUString rPictureStreamName;
705         if (!rRequestName.isEmpty())
706         {
707             rPictureStreamName = rRequestName + aExtension;
708         }
709         else
710         {
711             OUString sId = OStringToOUString(aGraphicObject.GetUniqueID(), RTL_TEXTENCODING_ASCII_US);
712             rPictureStreamName = sId + aExtension;
713         }
714 
715         SvxGraphicHelperStream_Impl aStream(ImplGetGraphicStream(XML_GRAPHICSTORAGE_NAME, rPictureStreamName));
716 
717         if (aStream.xStream.is())
718         {
719             const OUString aMimeType(ImplGetGraphicMimeType(rPictureStreamName));
720             uno::Reference<beans::XPropertySet> xProps(aStream.xStream, uno::UNO_QUERY);
721 
722             // set stream properties (MediaType/Compression)
723             if (!aMimeType.isEmpty())
724             {
725                 xProps->setPropertyValue("MediaType", uno::Any(aMimeType));
726             }
727 
728             // picture formats that actually _do_ benefit from zip
729             // storage compression
730             // .svm pics gets compressed via ZBITMAP old-style stream
731             // option below
732             static const char* aCompressiblePics[] =
733             {
734                 "image/svg+xml",
735                 "image/x-emf",
736                 "image/x-wmf",
737                 "image/tiff",
738                 "image/x-eps",
739                 "image/bmp",
740                 "image/x-pict"
741             };
742 
743             bool bSuccess = false;
744 
745             bool bCompressed = aMimeType.isEmpty();
746             if( !bCompressed )
747             {
748                 for(const char* p : aCompressiblePics)
749                 {
750                     if( aMimeType.equalsIgnoreAsciiCaseAscii(p) )
751                     {
752                         bCompressed = true;
753                         break;
754                     }
755                 }
756             }
757 
758             xProps->setPropertyValue("Compressed", Any(bCompressed));
759 
760             std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(aStream.xStream));
761             if (bUseGfxLink && aGfxLink.GetDataSize() && aGfxLink.GetData())
762             {
763                 const std::shared_ptr<std::vector<sal_Int8>> rPdfData = aGraphic.getPdfData();
764                 if (rPdfData && !rPdfData->empty())
765                 {
766                     // See if we have this PDF already, and avoid duplicate storage.
767                     auto aIt = maExportPdf.find(rPdfData.get());
768                     if (aIt != maExportPdf.end())
769                     {
770                         auto const& aURLAndMimePair = aIt->second;
771                         rOutSavedMimeType = aURLAndMimePair.second;
772                         return aURLAndMimePair.first;
773                     }
774 
775                     // The graphic has PDF data attached to it, use that.
776                     // vcl::ImportPDF() possibly downgraded the PDF data from a
777                     // higher PDF version, while aGfxLink still contains the
778                     // original data provided by the user.
779                     pStream->WriteBytes(rPdfData->data(), rPdfData->size());
780                 }
781                 else
782                 {
783                     pStream->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
784                 }
785 
786                 rOutSavedMimeType = aMimeType;
787                 bSuccess = (pStream->GetError() == ERRCODE_NONE);
788             }
789             else
790             {
791                 if (aGraphic.GetType() == GraphicType::Bitmap)
792                 {
793                     GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
794                     OUString aFormat;
795 
796                     if (aGraphic.IsAnimated())
797                     {
798                         aFormat = "gif";
799                     }
800                     else
801                     {
802                         aFormat = "png";
803                     }
804                     rOutSavedMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension(aFormat.toUtf8());
805 
806                     bSuccess = (rFilter.ExportGraphic(aGraphic, "", *pStream, rFilter.GetExportFormatNumberForShortName(aFormat)) == ERRCODE_NONE);
807                 }
808                 else if (aGraphic.GetType() == GraphicType::GdiMetafile)
809                 {
810                     pStream->SetVersion(SOFFICE_FILEFORMAT_8);
811                     pStream->SetCompressMode(SvStreamCompressFlags::ZBITMAP);
812                     rOutSavedMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension("svm");
813 
814                     // SJ: first check if this metafile is just an eps file, then we will store the eps instead of svm
815                     GDIMetaFile& rMtf(const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()));
816                     const MetaCommentAction* pComment = ImplCheckForEPS(rMtf);
817                     if (pComment)
818                     {
819                         sal_uInt32 nSize = pComment->GetDataSize();
820                         const sal_uInt8* pData = pComment->GetData();
821                         if (nSize && pData)
822                             pStream->WriteBytes(pData, nSize);
823 
824                         const MetaEPSAction* pAct = static_cast<const MetaEPSAction*>(rMtf.FirstAction());
825                         const GfxLink& rLink = pAct->GetLink();
826 
827                         pStream->WriteBytes(rLink.GetData(), rLink.GetDataSize());
828                     }
829                     else
830                     {
831                         rMtf.Write(*pStream);
832                     }
833 
834                     bSuccess = (pStream->GetError() == ERRCODE_NONE);
835                 }
836             }
837 
838             if (!bSuccess)
839                 return OUString();
840 
841             uno::Reference<embed::XTransactedObject> xStorage(aStream.xStorage, uno::UNO_QUERY);
842             pStream.reset();
843             aStream.xStream->getOutputStream()->closeOutput();
844             if (xStorage.is())
845                 xStorage->commit();
846 
847             OUString aStoragePath = "Pictures/" + rPictureStreamName;
848 
849             // put into cache
850             maExportGraphics[aGraphic] = std::make_pair(aStoragePath, rOutSavedMimeType);
851             if (aGraphic.hasPdfData())
852                 maExportPdf[aGraphic.getPdfData().get()] = std::make_pair(aStoragePath, rOutSavedMimeType);
853 
854             return aStoragePath;
855         }
856     }
857 
858     return OUString();
859 }
860 
createInputStream(uno::Reference<graphic::XGraphic> const & rxGraphic)861 uno::Reference<io::XInputStream> SAL_CALL SvXMLGraphicHelper::createInputStream(uno::Reference<graphic::XGraphic> const & rxGraphic)
862 {
863     Reference<XInputStream> xInputStream;
864 
865     Graphic aGraphic(rxGraphic);
866     GraphicObject aGraphicObject(aGraphic);
867 
868     if (SvXMLGraphicHelperMode::Write == meCreateMode)
869     {
870         OUString sMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension(OUStringToOString(maOutputMimeType, RTL_TEXTENCODING_ASCII_US));
871         std::unique_ptr<xmloff::GraphicInputStream> pInputStream(new xmloff::GraphicInputStream(aGraphicObject, sMimeType));
872 
873         // We release the pointer from unique_ptr and assign it to the input stream return type.
874         // In case the stream doesn't exists, unique_ptr will delete the pointer when we go out of scope.
875         if (pInputStream->exists())
876             xInputStream = pInputStream.release();
877     }
878 
879     return xInputStream;
880 }
881 
882 // XBinaryStreamResolver
getInputStream(const OUString &)883 Reference< XInputStream > SAL_CALL SvXMLGraphicHelper::getInputStream( const OUString& /*rURL*/ )
884 {
885     Reference<XInputStream> xRet;
886     return xRet;
887 }
888 
createOutputStream()889 Reference< XOutputStream > SAL_CALL SvXMLGraphicHelper::createOutputStream()
890 {
891     Reference< XOutputStream > xRet;
892 
893     if( SvXMLGraphicHelperMode::Read == meCreateMode )
894     {
895         std::unique_ptr<SvXMLGraphicOutputStream> pOutputStream(new SvXMLGraphicOutputStream);
896 
897         if( pOutputStream->Exists() )
898         {
899             xRet = pOutputStream.release();
900             maGrfStms.push_back( xRet );
901         }
902     }
903 
904     return xRet;
905 }
906 
resolveOutputStream(const Reference<XOutputStream> & rxBinaryStream)907 OUString SAL_CALL SvXMLGraphicHelper::resolveOutputStream( const Reference< XOutputStream >& rxBinaryStream )
908 {
909     OUString aRet;
910 
911     if( ( SvXMLGraphicHelperMode::Read == meCreateMode ) && rxBinaryStream.is() )
912     {
913         if( ::std::find( maGrfStms.begin(), maGrfStms.end(), rxBinaryStream ) != maGrfStms.end() )
914         {
915             SvXMLGraphicOutputStream* pOStm = static_cast< SvXMLGraphicOutputStream* >( rxBinaryStream.get() );
916 
917             if( pOStm )
918             {
919                 const GraphicObject& rGrfObj = pOStm->GetGraphicObject();
920                 const OUString aId(OStringToOUString(
921                     rGrfObj.GetUniqueID(), RTL_TEXTENCODING_ASCII_US));
922 
923                 if( !aId.isEmpty() )
924                 {
925                     aRet = XML_GRAPHICOBJECT_URL_BASE + aId;
926                 }
927             }
928         }
929     }
930 
931     return aRet;
932 }
933 
934 // for instantiation via service manager
935 namespace {
936 
937 namespace impl
938 {
939 typedef cppu::WeakComponentImplHelper<lang::XInitialization,
940                                         document::XGraphicObjectResolver,
941                                         document::XGraphicStorageHandler,
942                                         document::XBinaryStreamResolver,
943                                         lang::XServiceInfo>
944     SvXMLGraphicImportExportHelper_Base;
945 
946 class MutexContainer
947 {
948 public:
949     virtual ~MutexContainer();
950 
951 protected:
952     mutable ::osl::Mutex m_aMutex;
953 };
954 
~MutexContainer()955 MutexContainer::~MutexContainer()
956 {}
957 
958 } // namespace impl
959 
960 class SvXMLGraphicImportExportHelper :
961     public impl::MutexContainer,
962     public impl::SvXMLGraphicImportExportHelper_Base
963 {
964 public:
965     explicit SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode );
966 
967 protected:
968     // is called from WeakComponentImplHelper when XComponent::dispose() was
969     // called from outside
970     virtual void SAL_CALL disposing() override;
971 
972     // ____ XInitialization ____
973     // one argument is allowed, which is the XStorage
974     virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
975 
976     // ____ XGraphicObjectResolver ____
977     virtual OUString SAL_CALL resolveGraphicObjectURL( const OUString& aURL ) override;
978 
979     // ____ XGraphicStorageHandler ____
980     virtual css::uno::Reference<css::graphic::XGraphic> SAL_CALL
981         loadGraphic(const OUString& aURL) override;
982 
983     virtual css::uno::Reference<css::graphic::XGraphic> SAL_CALL
984         loadGraphicFromOutputStream(css::uno::Reference<css::io::XOutputStream> const & rxOutputStream) override;
985 
986     virtual OUString SAL_CALL
987         saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic) override;
988 
989     virtual OUString SAL_CALL
990         saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic, OUString & rOutSavedMimeType, OUString const & rRequestName) override;
991 
992     virtual css::uno::Reference<css::io::XInputStream> SAL_CALL
993         createInputStream(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic) override;
994 
995     // ____ XBinaryStreamResolver ____
996     virtual Reference< io::XInputStream > SAL_CALL getInputStream( const OUString& aURL ) override;
997     virtual Reference< io::XOutputStream > SAL_CALL createOutputStream() override;
998     virtual OUString SAL_CALL resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream ) override;
999 
1000     // ____ XServiceInfo ____
1001     virtual OUString SAL_CALL getImplementationName() override;
1002     virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
1003     virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
1004 
1005 private:
1006     SvXMLGraphicHelperMode const        m_eGraphicHelperMode;
1007     Reference< XGraphicObjectResolver > m_xGraphicObjectResolver;
1008     Reference< XGraphicStorageHandler > m_xGraphicStorageHandler;
1009     Reference< XBinaryStreamResolver >  m_xBinaryStreamResolver;
1010 };
1011 
SvXMLGraphicImportExportHelper(SvXMLGraphicHelperMode eMode)1012 SvXMLGraphicImportExportHelper::SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode ) :
1013         impl::SvXMLGraphicImportExportHelper_Base( m_aMutex ),
1014         m_eGraphicHelperMode( eMode )
1015 {}
1016 
disposing()1017 void SAL_CALL SvXMLGraphicImportExportHelper::disposing()
1018 {
1019     Reference< XComponent > xComp( m_xGraphicObjectResolver, UNO_QUERY );
1020     OSL_ASSERT( xComp.is());
1021     if( xComp.is())
1022         xComp->dispose();
1023     // m_xBinaryStreamResolver and m_xGraphicStorageHandler are a reference to the same object,
1024     // don't call dispose() again
1025 }
1026 
1027 // ____ XInitialization ____
initialize(const Sequence<Any> & aArguments)1028 void SAL_CALL SvXMLGraphicImportExportHelper::initialize(
1029     const Sequence< Any >& aArguments )
1030 {
1031     Reference< embed::XStorage > xStorage;
1032     if( aArguments.hasElements() )
1033         aArguments[0] >>= xStorage;
1034 
1035     rtl::Reference<SvXMLGraphicHelper> pHelper( SvXMLGraphicHelper::Create( xStorage, m_eGraphicHelperMode ));
1036     m_xGraphicObjectResolver.set( pHelper.get() );
1037     m_xGraphicStorageHandler.set( pHelper.get() );
1038     m_xBinaryStreamResolver.set( pHelper.get() );
1039 }
1040 
1041 // ____ XGraphicObjectResolver ____
resolveGraphicObjectURL(const OUString & aURL)1042 OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveGraphicObjectURL( const OUString& aURL )
1043 {
1044     return m_xGraphicObjectResolver->resolveGraphicObjectURL( aURL );
1045 }
1046 
1047 // ____ XGraphicStorageHandler ____
loadGraphic(OUString const & rURL)1048 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicImportExportHelper::loadGraphic(OUString const & rURL)
1049 {
1050     return m_xGraphicStorageHandler->loadGraphic(rURL);
1051 }
1052 
loadGraphicFromOutputStream(uno::Reference<io::XOutputStream> const & rxOutputStream)1053 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicImportExportHelper::loadGraphicFromOutputStream(uno::Reference<io::XOutputStream> const & rxOutputStream)
1054 {
1055     return m_xGraphicStorageHandler->loadGraphicFromOutputStream(rxOutputStream);
1056 }
1057 
saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic)1058 OUString SAL_CALL SvXMLGraphicImportExportHelper::saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic)
1059 {
1060     return m_xGraphicStorageHandler->saveGraphic(rxGraphic);
1061 }
1062 
saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,OUString & rOutSavedMimeType,OUString const & rRequestName)1063 OUString SAL_CALL SvXMLGraphicImportExportHelper::saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
1064                                                                     OUString & rOutSavedMimeType, OUString const & rRequestName)
1065 {
1066     return m_xGraphicStorageHandler->saveGraphicByName(rxGraphic, rOutSavedMimeType, rRequestName);
1067 }
1068 
createInputStream(uno::Reference<graphic::XGraphic> const & rxGraphic)1069 uno::Reference<io::XInputStream> SAL_CALL SvXMLGraphicImportExportHelper::createInputStream(uno::Reference<graphic::XGraphic> const & rxGraphic)
1070 {
1071     return m_xGraphicStorageHandler->createInputStream(rxGraphic);
1072 }
1073 
1074 // ____ XBinaryStreamResolver ____
getInputStream(const OUString & aURL)1075 Reference< io::XInputStream > SAL_CALL SvXMLGraphicImportExportHelper::getInputStream( const OUString& aURL )
1076 {
1077     return m_xBinaryStreamResolver->getInputStream( aURL );
1078 }
createOutputStream()1079 Reference< io::XOutputStream > SAL_CALL SvXMLGraphicImportExportHelper::createOutputStream()
1080 {
1081     return m_xBinaryStreamResolver->createOutputStream();
1082 }
resolveOutputStream(const Reference<io::XOutputStream> & aBinaryStream)1083 OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream )
1084 {
1085     return m_xBinaryStreamResolver->resolveOutputStream( aBinaryStream );
1086 }
1087 
1088 // ____ XServiceInfo ____
getImplementationName()1089 OUString SAL_CALL SvXMLGraphicImportExportHelper::getImplementationName()
1090 {
1091     if( m_eGraphicHelperMode == SvXMLGraphicHelperMode::Read )
1092         return "com.sun.star.comp.Svx.GraphicImportHelper";
1093     return "com.sun.star.comp.Svx.GraphicExportHelper";
1094 }
1095 
supportsService(const OUString & ServiceName)1096 sal_Bool SAL_CALL SvXMLGraphicImportExportHelper::supportsService( const OUString& ServiceName )
1097 {
1098     return cppu::supportsService(this, ServiceName);
1099 }
1100 
getSupportedServiceNames()1101 Sequence< OUString > SAL_CALL SvXMLGraphicImportExportHelper::getSupportedServiceNames()
1102 {
1103     return { "com.sun.star.document.GraphicObjectResolver",
1104              "com.sun.star.document.GraphicStorageHandler",
1105              "com.sun.star.document.BinaryStreamResolver" };
1106 }
1107 
1108 }
1109 
1110 /** Create this with createInstanceWithArguments. service name
1111     "com.sun.star.comp.Svx.GraphicImportHelper", one argument which is the
1112     XStorage.  Without arguments no helper class is created.  With an empty
1113     argument the helper class is created and initialized like in the CTOR to
1114     SvXMLGraphicHelper that only gets the create mode.
1115 
1116     You should call dispose after you no longer need this component.
1117 
1118     uses eCreateMode == SvXMLGraphicHelperMode::Read, bDirect == sal_True in
1119     SvXMLGraphicHelper
1120  */
1121 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_Svx_GraphicImportHelper_get_implementation(css::uno::XComponentContext *,css::uno::Sequence<css::uno::Any> const &)1122 com_sun_star_comp_Svx_GraphicImportHelper_get_implementation(
1123     css::uno::XComponentContext *,
1124     css::uno::Sequence<css::uno::Any> const &)
1125 {
1126     return cppu::acquire(new SvXMLGraphicImportExportHelper(SvXMLGraphicHelperMode::Read));
1127 }
1128 
1129 /** Create this with createInstanceWithArguments. service name
1130     "com.sun.star.comp.Svx.GraphicExportHelper", one argument which is the
1131     XStorage.  Without arguments no helper class is created.  With an empty
1132     argument the helper class is created and initialized like in the CTOR to
1133     SvXMLGraphicHelper that only gets the create mode
1134 
1135     To write the Pictures stream, you have to call dispose at this component.
1136     Make sure you call dispose before you commit the parent storage.
1137 
1138     uses eCreateMode == SvXMLGraphicHelperMode::Write, bDirect == sal_True in
1139     SvXMLGraphicHelper
1140  */
1141 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_Svx_GraphicExportHelper_get_implementation(css::uno::XComponentContext *,css::uno::Sequence<css::uno::Any> const &)1142 com_sun_star_comp_Svx_GraphicExportHelper_get_implementation(
1143     css::uno::XComponentContext *,
1144     css::uno::Sequence<css::uno::Any> const &)
1145 {
1146     return cppu::acquire(new SvXMLGraphicImportExportHelper(SvXMLGraphicHelperMode::Write));
1147 }
1148 
1149 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1150