xref: /aoo4110/main/oox/source/core/filterbase.cxx (revision b1cdbd2c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "oox/core/filterbase.hxx"
25 
26 #include <set>
27 #include <com/sun/star/frame/XModel.hpp>
28 #include <com/sun/star/task/XStatusIndicator.hpp>
29 #include <com/sun/star/task/XInteractionHandler.hpp>
30 #include <comphelper/docpasswordhelper.hxx>
31 #include <comphelper/mediadescriptor.hxx>
32 #include <osl/mutex.hxx>
33 #include <rtl/instance.hxx>
34 #include <rtl/uri.hxx>
35 #include "oox/helper/binaryinputstream.hxx"
36 #include "oox/helper/binaryoutputstream.hxx"
37 #include "oox/helper/graphichelper.hxx"
38 #include "oox/helper/modelobjecthelper.hxx"
39 #include "oox/ole/oleobjecthelper.hxx"
40 #include "oox/ole/vbaproject.hxx"
41 
42 namespace oox {
43 namespace core {
44 
45 // ============================================================================
46 
47 using namespace ::com::sun::star::beans;
48 using namespace ::com::sun::star::frame;
49 using namespace ::com::sun::star::graphic;
50 using namespace ::com::sun::star::io;
51 using namespace ::com::sun::star::lang;
52 using namespace ::com::sun::star::task;
53 using namespace ::com::sun::star::uno;
54 
55 using ::comphelper::MediaDescriptor;
56 using ::comphelper::SequenceAsHashMap;
57 using ::oox::ole::OleObjectHelper;
58 using ::oox::ole::VbaProject;
59 using ::rtl::OUString;
60 
61 // ============================================================================
62 
63 namespace {
64 
65 struct UrlPool
66 {
67     ::osl::Mutex        maMutex;
68     ::std::set< OUString > maUrls;
69 };
70 
71 struct StaticUrlPool : public ::rtl::Static< UrlPool, StaticUrlPool > {};
72 
73 // ----------------------------------------------------------------------------
74 
75 /** This guard prevents recursive loading/saving of the same document. */
76 class DocumentOpenedGuard
77 {
78 public:
79     explicit            DocumentOpenedGuard( const OUString& rUrl );
80                         ~DocumentOpenedGuard();
81 
isValid() const82     inline bool         isValid() const { return mbValid; }
83 
84 private:
85                         DocumentOpenedGuard( const DocumentOpenedGuard& );
86     DocumentOpenedGuard& operator=( const DocumentOpenedGuard& );
87 
88     OUString            maUrl;
89     bool                mbValid;
90 };
91 
DocumentOpenedGuard(const OUString & rUrl)92 DocumentOpenedGuard::DocumentOpenedGuard( const OUString& rUrl )
93 {
94     UrlPool& rUrlPool = StaticUrlPool::get();
95     ::osl::MutexGuard aGuard( rUrlPool.maMutex );
96     mbValid = (rUrl.getLength() == 0) || (rUrlPool.maUrls.count( rUrl ) == 0);
97     if( mbValid && (rUrl.getLength() > 0) )
98     {
99         rUrlPool.maUrls.insert( rUrl );
100         maUrl = rUrl;
101     }
102 }
103 
~DocumentOpenedGuard()104 DocumentOpenedGuard::~DocumentOpenedGuard()
105 {
106     UrlPool& rUrlPool = StaticUrlPool::get();
107     ::osl::MutexGuard aGuard( rUrlPool.maMutex );
108     if( maUrl.getLength() > 0 )
109         rUrlPool.maUrls.erase( maUrl );
110 }
111 
112 } // namespace
113 
114 // ============================================================================
115 
116 /** Specifies whether this filter is an import or export filter. */
117 enum FilterDirection
118 {
119     FILTERDIRECTION_UNKNOWN,
120     FILTERDIRECTION_IMPORT,
121     FILTERDIRECTION_EXPORT
122 };
123 
124 // ----------------------------------------------------------------------------
125 
126 struct FilterBaseImpl
127 {
128     typedef ::boost::shared_ptr< GraphicHelper >        GraphicHelperRef;
129     typedef ::boost::shared_ptr< ModelObjectHelper >    ModelObjHelperRef;
130     typedef ::boost::shared_ptr< OleObjectHelper >      OleObjHelperRef;
131     typedef ::boost::shared_ptr< VbaProject >           VbaProjectRef;
132 
133     FilterDirection     meDirection;
134     SequenceAsHashMap   maArguments;
135     MediaDescriptor     maMediaDesc;
136     OUString            maFileUrl;
137     StorageRef          mxStorage;
138 
139     GraphicHelperRef    mxGraphicHelper;        /// Graphic and graphic object handling.
140     ModelObjHelperRef   mxModelObjHelper;       /// Tables to create new named drawing objects.
141     OleObjHelperRef     mxOleObjHelper;         /// OLE object handling.
142     VbaProjectRef       mxVbaProject;           /// VBA project manager.
143 
144     Reference< XComponentContext >      mxComponentContext;
145     Reference< XMultiComponentFactory > mxComponentFactory;
146     Reference< XMultiServiceFactory >   mxServiceFactory;
147     Reference< XModel >                 mxModel;
148     Reference< XMultiServiceFactory >   mxModelFactory;
149     Reference< XFrame >                 mxTargetFrame;
150     Reference< XInputStream >           mxInStream;
151     Reference< XStream >                mxOutStream;
152     Reference< XStatusIndicator >       mxStatusIndicator;
153     Reference< XInteractionHandler >    mxInteractionHandler;
154 
155     explicit            FilterBaseImpl( const Reference< XComponentContext >& rxContext ) throw( RuntimeException );
156 
157     void                setDocumentModel( const Reference< XComponent >& rxComponent ) throw( IllegalArgumentException );
158 
159     void                initializeFilter();
160     void                finalizeFilter();
161 };
162 
163 // ----------------------------------------------------------------------------
164 
FilterBaseImpl(const Reference<XComponentContext> & rxContext)165 FilterBaseImpl::FilterBaseImpl( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
166     meDirection( FILTERDIRECTION_UNKNOWN ),
167     mxComponentContext( rxContext, UNO_SET_THROW ),
168     mxComponentFactory( rxContext->getServiceManager(), UNO_SET_THROW ),
169     mxServiceFactory( rxContext->getServiceManager(), UNO_QUERY_THROW )
170 {
171 }
172 
setDocumentModel(const Reference<XComponent> & rxComponent)173 void FilterBaseImpl::setDocumentModel( const Reference< XComponent >& rxComponent ) throw( IllegalArgumentException )
174 {
175     try
176     {
177         mxModel.set( rxComponent, UNO_QUERY_THROW );
178         mxModelFactory.set( rxComponent, UNO_QUERY_THROW );
179     }
180     catch( Exception& )
181     {
182         throw IllegalArgumentException();
183     }
184 }
185 
initializeFilter()186 void FilterBaseImpl::initializeFilter()
187 {
188     try
189     {
190         // lock the model controllers
191         mxModel->lockControllers();
192     }
193     catch( Exception& )
194     {
195     }
196 }
197 
finalizeFilter()198 void FilterBaseImpl::finalizeFilter()
199 {
200     try
201     {
202         // write the descriptor back to the document model (adds the passwords)
203         mxModel->attachResource( maFileUrl, maMediaDesc.getAsConstPropertyValueList() );
204         // unlock the model controllers
205         mxModel->unlockControllers();
206     }
207     catch( Exception& )
208     {
209     }
210 }
211 
212 // ============================================================================
213 
FilterBase(const Reference<XComponentContext> & rxContext)214 FilterBase::FilterBase( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
215     mxImpl( new FilterBaseImpl( rxContext ) )
216 {
217 }
218 
~FilterBase()219 FilterBase::~FilterBase()
220 {
221 }
222 
isImportFilter() const223 bool FilterBase::isImportFilter() const
224 {
225     return mxImpl->meDirection == FILTERDIRECTION_IMPORT;
226 }
227 
isExportFilter() const228 bool FilterBase::isExportFilter() const
229 {
230     return mxImpl->meDirection == FILTERDIRECTION_EXPORT;
231 }
232 
233 // ----------------------------------------------------------------------------
234 
getArgument(const OUString & rArgName) const235 Any FilterBase::getArgument( const OUString& rArgName ) const
236 {
237     SequenceAsHashMap::const_iterator aIt = mxImpl->maArguments.find( rArgName );
238     return (aIt == mxImpl->maArguments.end()) ? Any() : aIt->second;
239 }
240 
getComponentContext() const241 const Reference< XComponentContext >& FilterBase::getComponentContext() const
242 {
243     return mxImpl->mxComponentContext;
244 }
245 
getComponentFactory() const246 const Reference< XMultiComponentFactory >& FilterBase::getComponentFactory() const
247 {
248     return mxImpl->mxComponentFactory;
249 }
250 
getServiceFactory() const251 const Reference< XMultiServiceFactory >& FilterBase::getServiceFactory() const
252 {
253     return mxImpl->mxServiceFactory;
254 }
255 
getModel() const256 const Reference< XModel >& FilterBase::getModel() const
257 {
258     return mxImpl->mxModel;
259 }
260 
getModelFactory() const261 const Reference< XMultiServiceFactory >& FilterBase::getModelFactory() const
262 {
263     return mxImpl->mxModelFactory;
264 }
265 
getTargetFrame() const266 const Reference< XFrame >& FilterBase::getTargetFrame() const
267 {
268     return mxImpl->mxTargetFrame;
269 }
270 
getStatusIndicator() const271 const Reference< XStatusIndicator >& FilterBase::getStatusIndicator() const
272 {
273     return mxImpl->mxStatusIndicator;
274 }
275 
getInteractionHandler() const276 const Reference< XInteractionHandler >& FilterBase::getInteractionHandler() const
277 {
278     return mxImpl->mxInteractionHandler;
279 }
280 
getMediaDescriptor() const281 MediaDescriptor& FilterBase::getMediaDescriptor() const
282 {
283     return mxImpl->maMediaDesc;
284 }
285 
getFileUrl() const286 const OUString& FilterBase::getFileUrl() const
287 {
288     return mxImpl->maFileUrl;
289 }
290 
291 namespace {
292 
lclIsDosDrive(const OUString & rUrl,sal_Int32 nPos=0)293 inline bool lclIsDosDrive( const OUString& rUrl, sal_Int32 nPos = 0 )
294 {
295     return
296         (rUrl.getLength() >= nPos + 3) &&
297         ((('A' <= rUrl[ nPos ]) && (rUrl[ nPos ] <= 'Z')) || (('a' <= rUrl[ nPos ]) && (rUrl[ nPos ] <= 'z'))) &&
298         (rUrl[ nPos + 1 ] == ':') &&
299         (rUrl[ nPos + 2 ] == '/');
300 }
301 
302 } // namespace
303 
getAbsoluteUrl(const OUString & rUrl) const304 OUString FilterBase::getAbsoluteUrl( const OUString& rUrl ) const
305 {
306     // handle some special cases before calling ::rtl::Uri::convertRelToAbs()
307 
308     const OUString aFileSchema = CREATE_OUSTRING( "file:" );
309     const OUString aFilePrefix = CREATE_OUSTRING( "file:///" );
310     const sal_Int32 nFilePrefixLen = aFilePrefix.getLength();
311     const OUString aUncPrefix = CREATE_OUSTRING( "//" );
312 
313     /*  (1) convert all backslashes to slashes, and check that passed URL is
314         not empty. */
315     OUString aUrl = rUrl.replace( '\\', '/' );
316     if( aUrl.getLength() == 0 )
317         return aUrl;
318 
319     /*  (2) add 'file:///' to absolute Windows paths, e.g. convert
320         'C:/path/file' to 'file:///c:/path/file'. */
321     if( lclIsDosDrive( aUrl ) )
322         return aFilePrefix + aUrl;
323 
324     /*  (3) add 'file:' to UNC paths, e.g. convert '//server/path/file' to
325         'file://server/path/file'. */
326     if( aUrl.match( aUncPrefix ) )
327         return aFileSchema + aUrl;
328 
329     /*  (4) remove additional slashes from UNC paths, e.g. convert
330         'file://///server/path/file' to 'file://server/path/file'. */
331     if( (aUrl.getLength() >= nFilePrefixLen + 2) &&
332         aUrl.match( aFilePrefix ) &&
333         aUrl.match( aUncPrefix, nFilePrefixLen ) )
334     {
335         return aFileSchema + aUrl.copy( nFilePrefixLen );
336     }
337 
338     /*  (5) handle URLs relative to current drive, e.g. the URL '/path1/file1'
339         relative to the base URL 'file:///C:/path2/file2' does not result in
340         the expected 'file:///C:/path1/file1', but in 'file:///path1/file1'. */
341     if( (aUrl.getLength() >= 1) && (aUrl[ 0 ] == '/') &&
342         mxImpl->maFileUrl.match( aFilePrefix ) &&
343         lclIsDosDrive( mxImpl->maFileUrl, nFilePrefixLen ) )
344     {
345         return mxImpl->maFileUrl.copy( 0, nFilePrefixLen + 3 ) + aUrl.copy( 1 );
346     }
347 
348     try
349     {
350         return ::rtl::Uri::convertRelToAbs( mxImpl->maFileUrl, aUrl );
351     }
352     catch( ::rtl::MalformedUriException& )
353     {
354     }
355     return aUrl;
356 }
357 
getStorage() const358 StorageRef FilterBase::getStorage() const
359 {
360     return mxImpl->mxStorage;
361 }
362 
openSubStorage(const OUString & rStorageName,bool bCreateMissing) const363 StorageRef FilterBase::openSubStorage( const OUString& rStorageName, bool bCreateMissing ) const
364 {
365     return mxImpl->mxStorage->openSubStorage( rStorageName, bCreateMissing );
366 }
367 
openInputStream(const OUString & rStreamName) const368 Reference< XInputStream > FilterBase::openInputStream( const OUString& rStreamName ) const
369 {
370     return mxImpl->mxStorage->openInputStream( rStreamName );
371 }
372 
openOutputStream(const OUString & rStreamName) const373 Reference< XOutputStream > FilterBase::openOutputStream( const OUString& rStreamName ) const
374 {
375     return mxImpl->mxStorage->openOutputStream( rStreamName );
376 }
377 
commitStorage() const378 void FilterBase::commitStorage() const
379 {
380     mxImpl->mxStorage->commit();
381 }
382 
383 // helpers --------------------------------------------------------------------
384 
getGraphicHelper() const385 GraphicHelper& FilterBase::getGraphicHelper() const
386 {
387     if( !mxImpl->mxGraphicHelper )
388         mxImpl->mxGraphicHelper.reset( implCreateGraphicHelper() );
389     return *mxImpl->mxGraphicHelper;
390 }
391 
getModelObjectHelper() const392 ModelObjectHelper& FilterBase::getModelObjectHelper() const
393 {
394     if( !mxImpl->mxModelObjHelper )
395         mxImpl->mxModelObjHelper.reset( new ModelObjectHelper( mxImpl->mxModelFactory ) );
396     return *mxImpl->mxModelObjHelper;
397 }
398 
getOleObjectHelper() const399 OleObjectHelper& FilterBase::getOleObjectHelper() const
400 {
401     if( !mxImpl->mxOleObjHelper )
402         mxImpl->mxOleObjHelper.reset( new OleObjectHelper( mxImpl->mxModelFactory ) );
403     return *mxImpl->mxOleObjHelper;
404 }
405 
getVbaProject() const406 VbaProject& FilterBase::getVbaProject() const
407 {
408     if( !mxImpl->mxVbaProject )
409         mxImpl->mxVbaProject.reset( implCreateVbaProject() );
410     return *mxImpl->mxVbaProject;
411 }
412 
requestEncryptionData(::comphelper::IDocPasswordVerifier & rVerifier) const413 Sequence< NamedValue > FilterBase::requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier ) const
414 {
415     ::std::vector< OUString > aDefaultPasswords;
416     aDefaultPasswords.push_back( CREATE_OUSTRING( "VelvetSweatshop" ) );
417     return ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
418         rVerifier, mxImpl->maMediaDesc, ::comphelper::DocPasswordRequestType_MS, &aDefaultPasswords );
419 }
420 
importBinaryData(StreamDataSequence & orDataSeq,const OUString & rStreamName)421 bool FilterBase::importBinaryData( StreamDataSequence& orDataSeq, const OUString& rStreamName )
422 {
423     OSL_ENSURE( rStreamName.getLength() > 0, "FilterBase::importBinaryData - empty stream name" );
424     if( rStreamName.getLength() == 0 )
425         return false;
426 
427     // try to open the stream (this may fail - do not assert)
428     BinaryXInputStream aInStrm( openInputStream( rStreamName ), true );
429     if( aInStrm.isEof() )
430         return false;
431 
432     // copy the entire stream to the passed sequence
433     SequenceOutputStream aOutStrm( orDataSeq );
434     aInStrm.copyToStream( aOutStrm );
435     return true;
436 }
437 
438 // com.sun.star.lang.XServiceInfo interface -----------------------------------
439 
getImplementationName()440 OUString SAL_CALL FilterBase::getImplementationName() throw( RuntimeException )
441 {
442     return implGetImplementationName();
443 }
444 
supportsService(const OUString & rServiceName)445 sal_Bool SAL_CALL FilterBase::supportsService( const OUString& rServiceName ) throw( RuntimeException )
446 {
447     return
448         (rServiceName == CREATE_OUSTRING( "com.sun.star.document.ImportFilter" )) ||
449         (rServiceName == CREATE_OUSTRING( "com.sun.star.document.ExportFilter" ));
450 }
451 
getSupportedServiceNames()452 Sequence< OUString > SAL_CALL FilterBase::getSupportedServiceNames() throw( RuntimeException )
453 {
454     Sequence< OUString > aServiceNames( 2 );
455     aServiceNames[ 0 ] = CREATE_OUSTRING( "com.sun.star.document.ImportFilter" );
456     aServiceNames[ 1 ] = CREATE_OUSTRING( "com.sun.star.document.ExportFilter" );
457     return aServiceNames;
458 }
459 
460 // com.sun.star.lang.XInitialization interface --------------------------------
461 
initialize(const Sequence<Any> & rArgs)462 void SAL_CALL FilterBase::initialize( const Sequence< Any >& rArgs ) throw( Exception, RuntimeException )
463 {
464     if( rArgs.getLength() >= 2 ) try
465     {
466         mxImpl->maArguments << rArgs[ 1 ];
467     }
468     catch( Exception& )
469     {
470     }
471 }
472 
473 // com.sun.star.document.XImporter interface ----------------------------------
474 
setTargetDocument(const Reference<XComponent> & rxDocument)475 void SAL_CALL FilterBase::setTargetDocument( const Reference< XComponent >& rxDocument ) throw( IllegalArgumentException, RuntimeException )
476 {
477     mxImpl->setDocumentModel( rxDocument );
478     mxImpl->meDirection = FILTERDIRECTION_IMPORT;
479 }
480 
481 // com.sun.star.document.XExporter interface ----------------------------------
482 
setSourceDocument(const Reference<XComponent> & rxDocument)483 void SAL_CALL FilterBase::setSourceDocument( const Reference< XComponent >& rxDocument ) throw( IllegalArgumentException, RuntimeException )
484 {
485     mxImpl->setDocumentModel( rxDocument );
486     mxImpl->meDirection = FILTERDIRECTION_EXPORT;
487 }
488 
489 // com.sun.star.document.XFilter interface ------------------------------------
490 
filter(const Sequence<PropertyValue> & rMediaDescSeq)491 sal_Bool SAL_CALL FilterBase::filter( const Sequence< PropertyValue >& rMediaDescSeq ) throw( RuntimeException )
492 {
493     if( !mxImpl->mxModel.is() || !mxImpl->mxModelFactory.is() || (mxImpl->meDirection == FILTERDIRECTION_UNKNOWN) )
494         throw RuntimeException();
495 
496     sal_Bool bRet = sal_False;
497     setMediaDescriptor( rMediaDescSeq );
498     DocumentOpenedGuard aOpenedGuard( mxImpl->maFileUrl );
499     if( aOpenedGuard.isValid() || !mxImpl->maFileUrl.getLength() )
500     {
501         mxImpl->initializeFilter();
502         switch( mxImpl->meDirection )
503         {
504             case FILTERDIRECTION_UNKNOWN:
505             break;
506             case FILTERDIRECTION_IMPORT:
507                 if( mxImpl->mxInStream.is() )
508                 {
509                     mxImpl->mxStorage = implCreateStorage( mxImpl->mxInStream );
510                     bRet = mxImpl->mxStorage.get() && importDocument();
511                 }
512             break;
513             case FILTERDIRECTION_EXPORT:
514                 if( mxImpl->mxOutStream.is() )
515                 {
516                     mxImpl->mxStorage = implCreateStorage( mxImpl->mxOutStream );
517                     bRet = mxImpl->mxStorage.get() && exportDocument();
518                 }
519             break;
520         }
521         mxImpl->finalizeFilter();
522     }
523     return bRet;
524 }
525 
cancel()526 void SAL_CALL FilterBase::cancel() throw( RuntimeException )
527 {
528 }
529 
530 // protected ------------------------------------------------------------------
531 
implGetInputStream(MediaDescriptor & rMediaDesc) const532 Reference< XInputStream > FilterBase::implGetInputStream( MediaDescriptor& rMediaDesc ) const
533 {
534     return rMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_INPUTSTREAM(), Reference< XInputStream >() );
535 }
536 
implGetOutputStream(MediaDescriptor & rMediaDesc) const537 Reference< XStream > FilterBase::implGetOutputStream( MediaDescriptor& rMediaDesc ) const
538 {
539     return rMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_STREAMFOROUTPUT(), Reference< XStream >() );
540 }
541 
542 // private --------------------------------------------------------------------
543 
setMediaDescriptor(const Sequence<PropertyValue> & rMediaDescSeq)544 void FilterBase::setMediaDescriptor( const Sequence< PropertyValue >& rMediaDescSeq )
545 {
546     mxImpl->maMediaDesc << rMediaDescSeq;
547 
548     switch( mxImpl->meDirection )
549     {
550         case FILTERDIRECTION_UNKNOWN:
551             OSL_ENSURE( false, "FilterBase::setMediaDescriptor - invalid filter direction" );
552         break;
553         case FILTERDIRECTION_IMPORT:
554             mxImpl->maMediaDesc.addInputStream();
555             mxImpl->mxInStream = implGetInputStream( mxImpl->maMediaDesc );
556             OSL_ENSURE( mxImpl->mxInStream.is(), "FilterBase::setMediaDescriptor - missing input stream" );
557         break;
558         case FILTERDIRECTION_EXPORT:
559             mxImpl->mxOutStream = implGetOutputStream( mxImpl->maMediaDesc );
560             OSL_ENSURE( mxImpl->mxOutStream.is(), "FilterBase::setMediaDescriptor - missing output stream" );
561         break;
562     }
563 
564     mxImpl->maFileUrl = mxImpl->maMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_URL(), OUString() );
565     mxImpl->mxTargetFrame = mxImpl->maMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_FRAME(), Reference< XFrame >() );
566     mxImpl->mxStatusIndicator = mxImpl->maMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_STATUSINDICATOR(), Reference< XStatusIndicator >() );
567     mxImpl->mxInteractionHandler = mxImpl->maMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_INTERACTIONHANDLER(), Reference< XInteractionHandler >() );
568 }
569 
implCreateGraphicHelper() const570 GraphicHelper* FilterBase::implCreateGraphicHelper() const
571 {
572     // default: return base implementation without any special behaviour
573     return new GraphicHelper( mxImpl->mxComponentContext, mxImpl->mxTargetFrame, mxImpl->mxStorage );
574 }
575 
576 // ============================================================================
577 
578 } // namespace core
579 } // namespace oox
580