xref: /trunk/main/svx/source/xml/xmlgrhlp.cxx (revision 45c5a00162811bd03b87fcb4fe9996782f2b59ec)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26 #include <com/sun/star/embed/XTransactedObject.hpp>
27 #ifndef _COM_SUN_STAR_EMBED_ElementModes_HPP_
28 #include <com/sun/star/embed/ElementModes.hpp>
29 #endif
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/lang/XServiceInfo.hpp>
33 #include <com/sun/star/lang/XInitialization.hpp>
34 #include <cppuhelper/compbase4.hxx>
35 
36 #include <unotools/ucbstreamhelper.hxx>
37 #include <unotools/streamwrap.hxx>
38 #include <unotools/tempfile.hxx>
39 #include <tools/debug.hxx>
40 #include <vcl/cvtgrf.hxx>
41 #include <vcl/gfxlink.hxx>
42 #include <vcl/metaact.hxx>
43 #include <tools/zcodec.hxx>
44 
45 #include "svtools/filter.hxx"
46 #include "svx/xmlgrhlp.hxx"
47 
48 #include <algorithm>
49 
50 // -----------
51 // - Defines -
52 // -----------
53 
54 using namespace com::sun::star;
55 using namespace com::sun::star::uno;
56 using namespace com::sun::star::io;
57 
58 using ::com::sun::star::lang::XMultiServiceFactory;
59 
60 #define XML_GRAPHICSTORAGE_NAME     "Pictures"
61 #define XML_PACKAGE_URL_BASE        "vnd.sun.star.Package:"
62 #define XML_GRAPHICOBJECT_URL_BASE  "vnd.sun.star.GraphicObject:"
63 
64 // ---------------------------
65 // - SvXMLGraphicInputStream -
66 // ---------------------------
67 
68 const MetaCommentAction* ImplCheckForEPS( GDIMetaFile& rMtf )
69 {
70     static ByteString aComment( (const sal_Char*)"EPSReplacementGraphic" );
71     const MetaCommentAction* pComment = NULL;
72 
73     if ( ( rMtf.GetActionCount() >= 2 )
74             && ( rMtf.FirstAction()->GetType() == META_EPS_ACTION )
75             && ( ((const MetaAction*)rMtf.GetAction( 1 ))->GetType() == META_COMMENT_ACTION )
76             && ( ((const MetaCommentAction*)rMtf.GetAction( 1 ))->GetComment() == aComment ) )
77         pComment = (const MetaCommentAction*)rMtf.GetAction( 1 );
78 
79     return pComment;
80 }
81 
82 class SvXMLGraphicInputStream : public::cppu::WeakImplHelper1< XInputStream >
83 {
84 private:
85 
86     virtual sal_Int32   SAL_CALL    readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead);
87     virtual sal_Int32   SAL_CALL    readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead);
88     virtual void        SAL_CALL    skipBytes(sal_Int32 nBytesToSkip);
89     virtual sal_Int32   SAL_CALL    available();
90     virtual void        SAL_CALL    closeInput();
91 
92 private:
93 
94     ::utl::TempFile                 maTmp;
95     Reference< XInputStream >       mxStmWrapper;
96 
97                                     // not available
98                                     SvXMLGraphicInputStream();
99                                     SvXMLGraphicInputStream( const SvXMLGraphicInputStream& );
100     SvXMLGraphicInputStream&        operator==( SvXMLGraphicInputStream& );
101 
102 public:
103 
104                                     SvXMLGraphicInputStream( const ::rtl::OUString& rGraphicId );
105     virtual                         ~SvXMLGraphicInputStream();
106 
107     sal_Bool                        Exists() const { return mxStmWrapper.is(); }
108 };
109 
110 // -----------------------------------------------------------------------------
111 
112 SvXMLGraphicInputStream::SvXMLGraphicInputStream( const ::rtl::OUString& rGraphicId )
113 {
114     String          aGraphicId( rGraphicId );
115     GraphicObject   aGrfObject( ByteString( aGraphicId, RTL_TEXTENCODING_ASCII_US ) );
116 
117     maTmp.EnableKillingFile();
118 
119     if( aGrfObject.GetType() != GRAPHIC_NONE )
120     {
121         SvStream* pStm = ::utl::UcbStreamHelper::CreateStream( maTmp.GetURL(), STREAM_WRITE | STREAM_TRUNC );
122 
123         if( pStm )
124         {
125             Graphic         aGraphic( (Graphic&) aGrfObject.GetGraphic() );
126             const GfxLink   aGfxLink( aGraphic.GetLink() );
127             sal_Bool        bRet = sal_False;
128 
129             if( aGfxLink.GetDataSize() && aGfxLink.GetData() )
130             {
131                 pStm->Write( aGfxLink.GetData(), aGfxLink.GetDataSize() );
132                 bRet = ( pStm->GetError() == 0 );
133             }
134             else
135             {
136                 if( aGraphic.GetType() == GRAPHIC_BITMAP )
137                 {
138                     GraphicFilter*  pFilter = GraphicFilter::GetGraphicFilter();
139                     String          aFormat;
140 
141                     if( aGraphic.IsAnimated() )
142                         aFormat = String( RTL_CONSTASCII_USTRINGPARAM( "gif" ) );
143                     else
144                         aFormat = String( RTL_CONSTASCII_USTRINGPARAM( "png" ) );
145 
146                     bRet = ( pFilter->ExportGraphic( aGraphic, String(), *pStm, pFilter->GetExportFormatNumberForShortName( aFormat ) ) == 0 );
147                 }
148                 else if( aGraphic.GetType() == GRAPHIC_GDIMETAFILE )
149                 {
150                     pStm->SetVersion( SOFFICE_FILEFORMAT_8 );
151                     pStm->SetCompressMode( COMPRESSMODE_ZBITMAP );
152                     ( (GDIMetaFile&) aGraphic.GetGDIMetaFile() ).Write( *pStm );
153                     bRet = ( pStm->GetError() == 0 );
154                 }
155             }
156 
157             if( bRet )
158             {
159                 pStm->Seek( 0 );
160                 mxStmWrapper = new ::utl::OInputStreamWrapper( pStm, sal_True );
161             }
162             else
163                 delete pStm;
164         }
165     }
166 }
167 
168 // -----------------------------------------------------------------------------
169 
170 SvXMLGraphicInputStream::~SvXMLGraphicInputStream()
171 {
172 }
173 
174 // -----------------------------------------------------------------------------
175 
176 sal_Int32 SAL_CALL SvXMLGraphicInputStream::readBytes( Sequence< sal_Int8 >& rData, sal_Int32 nBytesToRead )
177 {
178     if( !mxStmWrapper.is() )
179         throw NotConnectedException();
180 
181     return mxStmWrapper->readBytes( rData, nBytesToRead );
182 }
183 
184 // -----------------------------------------------------------------------------
185 
186 sal_Int32 SAL_CALL SvXMLGraphicInputStream::readSomeBytes( Sequence< sal_Int8 >& rData, sal_Int32 nMaxBytesToRead )
187 {
188     if( !mxStmWrapper.is() )
189         throw NotConnectedException() ;
190 
191     return mxStmWrapper->readSomeBytes( rData, nMaxBytesToRead );
192 }
193 
194 // -----------------------------------------------------------------------------
195 
196 void SAL_CALL SvXMLGraphicInputStream::skipBytes( sal_Int32 nBytesToSkip )
197 {
198     if( !mxStmWrapper.is() )
199         throw NotConnectedException() ;
200 
201     mxStmWrapper->skipBytes( nBytesToSkip );
202 }
203 
204 // -----------------------------------------------------------------------------
205 
206 sal_Int32 SAL_CALL SvXMLGraphicInputStream::available()
207 {
208     if( !mxStmWrapper.is() )
209         throw NotConnectedException() ;
210 
211     return mxStmWrapper->available();
212 }
213 
214 // -----------------------------------------------------------------------------
215 
216 void SAL_CALL SvXMLGraphicInputStream::closeInput()
217 {
218     if( !mxStmWrapper.is() )
219         throw NotConnectedException() ;
220 
221     mxStmWrapper->closeInput();
222 }
223 
224 // ----------------------------
225 // - SvXMLGraphicOutputStream -
226 // ----------------------------
227 
228 class SvXMLGraphicOutputStream : public::cppu::WeakImplHelper1< XOutputStream >
229 {
230 private:
231 
232     // XOutputStream
233     virtual void SAL_CALL           writeBytes( const Sequence< sal_Int8 >& rData );
234     virtual void SAL_CALL           flush();
235     virtual void SAL_CALL           closeOutput();
236 
237 private:
238 
239     ::utl::TempFile*                mpTmp;
240     SvStream*                       mpOStm;
241     Reference< XOutputStream >      mxStmWrapper;
242     GraphicObject                   maGrfObj;
243     sal_Bool                        mbClosed;
244 
245                                     // not available
246                                     SvXMLGraphicOutputStream( const SvXMLGraphicOutputStream& );
247     SvXMLGraphicOutputStream&       operator==( SvXMLGraphicOutputStream& );
248 
249 public:
250 
251                                     SvXMLGraphicOutputStream();
252     virtual                         ~SvXMLGraphicOutputStream();
253 
254     sal_Bool                        Exists() const { return mxStmWrapper.is(); }
255     const GraphicObject&            GetGraphicObject();
256 };
257 
258 // -----------------------------------------------------------------------------
259 
260 SvXMLGraphicOutputStream::SvXMLGraphicOutputStream() :
261     mpTmp( new ::utl::TempFile ),
262     mbClosed( sal_False )
263 {
264     mpTmp->EnableKillingFile();
265 
266     mpOStm = ::utl::UcbStreamHelper::CreateStream( mpTmp->GetURL(), STREAM_WRITE | STREAM_TRUNC );
267 
268     if( mpOStm )
269         mxStmWrapper = new ::utl::OOutputStreamWrapper( *mpOStm );
270 }
271 
272 // -----------------------------------------------------------------------------
273 
274 SvXMLGraphicOutputStream::~SvXMLGraphicOutputStream()
275 {
276     delete mpTmp;
277     delete mpOStm;
278 }
279 
280 // -----------------------------------------------------------------------------
281 
282 void SAL_CALL SvXMLGraphicOutputStream::writeBytes( const Sequence< sal_Int8 >& rData )
283 {
284     if( !mxStmWrapper.is() )
285         throw NotConnectedException() ;
286 
287     mxStmWrapper->writeBytes( rData );
288 }
289 
290 // -----------------------------------------------------------------------------
291 
292 void SAL_CALL SvXMLGraphicOutputStream::flush()
293 {
294     if( !mxStmWrapper.is() )
295         throw NotConnectedException() ;
296 
297     mxStmWrapper->flush();
298 }
299 
300 // -----------------------------------------------------------------------------
301 
302 void SAL_CALL SvXMLGraphicOutputStream::closeOutput()
303 {
304     if( !mxStmWrapper.is() )
305         throw NotConnectedException() ;
306 
307     mxStmWrapper->closeOutput();
308     mxStmWrapper = Reference< XOutputStream >();
309 
310     mbClosed = sal_True;
311 }
312 
313 // ------------------------------------------------------------------------------
314 
315 const GraphicObject& SvXMLGraphicOutputStream::GetGraphicObject()
316 {
317     if( mbClosed && ( maGrfObj.GetType() == GRAPHIC_NONE ) && mpOStm )
318     {
319         Graphic aGraphic;
320 
321         mpOStm->Seek( 0 );
322         sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
323         sal_uInt16 pDeterminedFormat = GRFILTER_FORMAT_DONTKNOW;
324         GraphicFilter::GetGraphicFilter()->ImportGraphic( aGraphic, String(), *mpOStm ,nFormat,&pDeterminedFormat );
325 
326         if (pDeterminedFormat == GRFILTER_FORMAT_DONTKNOW)
327         {
328             //Read the first two byte to check whether it is a gzipped stream, is so it may be in wmz or emz format
329             //unzip them and try again
330 
331             sal_uInt8    sFirstBytes[ 2 ];
332 
333             mpOStm->Seek( STREAM_SEEK_TO_END );
334             sal_uIntPtr nStreamLen = mpOStm->Tell();
335             mpOStm->Seek( 0 );
336 
337             if ( !nStreamLen )
338             {
339                 SvLockBytes* pLockBytes = mpOStm->GetLockBytes();
340                 if ( pLockBytes  )
341                     pLockBytes->SetSynchronMode( sal_True );
342 
343                 mpOStm->Seek( STREAM_SEEK_TO_END );
344                 nStreamLen = mpOStm->Tell();
345                 mpOStm->Seek( 0 );
346             }
347             if( nStreamLen >= 2 )
348             {
349                 //read two byte
350                 mpOStm->Read( sFirstBytes, 2 );
351 
352                 if( sFirstBytes[0] == 0x1f && sFirstBytes[1] == 0x8b )
353                 {
354                     SvMemoryStream* pDest = new SvMemoryStream;
355                     ZCodec aZCodec( 0x8000, 0x8000 );
356                     aZCodec.BeginCompression(ZCODEC_GZ_LIB);
357                     mpOStm->Seek( 0 );
358                     aZCodec.Decompress( *mpOStm, *pDest );
359 
360                     if (aZCodec.EndCompression() && pDest )
361                     {
362                         pDest->Seek( STREAM_SEEK_TO_END );
363                         sal_uIntPtr nStreamLen_ = pDest->Tell();
364                         if (nStreamLen_)
365                         {
366                             pDest->Seek(0L);
367                             GraphicFilter::GetGraphicFilter()->ImportGraphic( aGraphic, String(), *pDest ,nFormat,&pDeterminedFormat );
368                         }
369                     }
370                     delete pDest;
371                 }
372             }
373         }
374 
375         maGrfObj = aGraphic;
376         if( maGrfObj.GetType() != GRAPHIC_NONE )
377         {
378             delete mpOStm, mpOStm = NULL;
379             delete mpTmp, mpTmp = NULL;
380         }
381     }
382 
383     return maGrfObj;
384 }
385 
386 // ----------------------
387 // - SvXMLGraphicHelper -
388 // ----------------------
389 
390 SvXMLGraphicHelper::SvXMLGraphicHelper( SvXMLGraphicHelperMode eCreateMode ) :
391     ::cppu::WeakComponentImplHelper2< ::com::sun::star::document::XGraphicObjectResolver,
392                                       ::com::sun::star::document::XBinaryStreamResolver >( maMutex )
393 {
394     Init( NULL, eCreateMode, sal_False );
395 }
396 
397 SvXMLGraphicHelper::SvXMLGraphicHelper() :
398     ::cppu::WeakComponentImplHelper2< ::com::sun::star::document::XGraphicObjectResolver,
399                                       ::com::sun::star::document::XBinaryStreamResolver >( maMutex )
400 {
401 }
402 
403 // -----------------------------------------------------------------------------
404 
405 SvXMLGraphicHelper::~SvXMLGraphicHelper()
406 {
407 }
408 
409 // -----------------------------------------------------------------------------
410 
411 void SAL_CALL SvXMLGraphicHelper::disposing()
412 {
413 }
414 
415 // -----------------------------------------------------------------------------
416 
417 sal_Bool SvXMLGraphicHelper::ImplGetStreamNames( const ::rtl::OUString& rURLStr,
418                                                  ::rtl::OUString& rPictureStorageName,
419                                                  ::rtl::OUString& rPictureStreamName )
420 {
421     String      aURLStr( rURLStr );
422     sal_Bool    bRet = sal_False;
423 
424     if( aURLStr.Len() )
425     {
426         aURLStr = aURLStr.GetToken( aURLStr.GetTokenCount( ':' ) - 1, ':' );
427         const sal_uInt32 nTokenCount = aURLStr.GetTokenCount( '/' );
428 
429         if( 1 == nTokenCount )
430         {
431             rPictureStorageName = String( RTL_CONSTASCII_USTRINGPARAM( XML_GRAPHICSTORAGE_NAME ) );
432             rPictureStreamName = aURLStr;
433             bRet = sal_True;
434         }
435         else if( 2 == nTokenCount )
436         {
437             rPictureStorageName = aURLStr.GetToken( 0, '/' );
438 
439             DBG_ASSERT( rPictureStorageName.getLength() &&
440                        rPictureStorageName.getStr()[ 0 ] != '#',
441                        "invalid relative URL" );
442 
443             rPictureStreamName = aURLStr.GetToken( 1, '/' );
444             bRet = sal_True;
445         }
446         else
447         {
448             DBG_ERROR( "SvXMLGraphicHelper::ImplInsertGraphicURL: invalid scheme" );
449         }
450     }
451 
452     return bRet;
453 }
454 
455 // -----------------------------------------------------------------------------
456 
457 uno::Reference < embed::XStorage > SvXMLGraphicHelper::ImplGetGraphicStorage( const ::rtl::OUString& rStorageName )
458 {
459     uno::Reference < embed::XStorage > xRetStorage;
460     if( mxRootStorage.is() )
461     {
462         try
463         {
464             xRetStorage = mxRootStorage->openStorageElement(
465                 maCurStorageName = rStorageName,
466                 ( GRAPHICHELPER_MODE_WRITE == meCreateMode )
467                     ? embed::ElementModes::READWRITE
468                     : embed::ElementModes::READ );
469         }
470         catch ( uno::Exception& )
471         {
472         }
473         //#i43196# try again to open the storage element - this time readonly
474         if(!xRetStorage.is())
475         {
476             try
477             {
478                 xRetStorage = mxRootStorage->openStorageElement( maCurStorageName = rStorageName, embed::ElementModes::READ );
479             }
480             catch ( uno::Exception& )
481             {
482             }
483         }
484     }
485 
486     return xRetStorage;
487 }
488 
489 // -----------------------------------------------------------------------------
490 
491 SvxGraphicHelperStream_Impl SvXMLGraphicHelper::ImplGetGraphicStream( const ::rtl::OUString& rPictureStorageName,
492                                                               const ::rtl::OUString& rPictureStreamName,
493                                                               sal_Bool bTruncate )
494 {
495     SvxGraphicHelperStream_Impl aRet;
496     aRet.xStorage = ImplGetGraphicStorage( rPictureStorageName );
497 
498     if( aRet.xStorage.is() )
499     {
500         sal_Int32 nMode = embed::ElementModes::READ;
501         if ( GRAPHICHELPER_MODE_WRITE == meCreateMode )
502         {
503             nMode = embed::ElementModes::READWRITE;
504             if ( bTruncate )
505                 nMode |= embed::ElementModes::TRUNCATE;
506         }
507 
508         aRet.xStream = aRet.xStorage->openStreamElement( rPictureStreamName, nMode );
509         if( aRet.xStream.is() && ( GRAPHICHELPER_MODE_WRITE == meCreateMode ) )
510         {
511 //REMOVE                ::rtl::OUString aPropName( RTL_CONSTASCII_USTRINGPARAM("Encrypted") );
512             ::rtl::OUString aPropName( RTL_CONSTASCII_USTRINGPARAM("UseCommonStoragePasswordEncryption") );
513             uno::Reference < beans::XPropertySet > xProps( aRet.xStream, uno::UNO_QUERY );
514             xProps->setPropertyValue( aPropName, uno::makeAny( sal_True) );
515         }
516     }
517 
518     return aRet;
519 }
520 
521 // -----------------------------------------------------------------------------
522 
523 String SvXMLGraphicHelper::ImplGetGraphicMimeType( const String& rFileName ) const
524 {
525     struct XMLGraphicMimeTypeMapper
526     {
527         const char* pExt;
528         const char* pMimeType;
529     };
530 
531     static XMLGraphicMimeTypeMapper aMapper[] =
532     {
533         { "gif", "image/gif" },
534         { "png", "image/png" },
535         { "jpg", "image/jpeg" },
536         { "tif", "image/tiff" },
537         { "svg", "image/svg+xml" }
538     };
539 
540     String aMimeType;
541 
542     if( ( rFileName.Len() >= 4 ) && ( rFileName.GetChar( rFileName.Len() - 4 ) == '.' ) )
543     {
544         const ByteString aExt( rFileName.Copy( rFileName.Len() - 3 ), RTL_TEXTENCODING_ASCII_US );
545 
546         for( long i = 0, nCount = sizeof( aMapper ) / sizeof( aMapper[ 0 ] ); ( i < nCount ) && !aMimeType.Len(); i++ )
547             if( aExt == aMapper[ i ].pExt )
548                 aMimeType = String( aMapper[ i ].pMimeType, RTL_TEXTENCODING_ASCII_US );
549     }
550 
551     return aMimeType;
552 }
553 
554 // -----------------------------------------------------------------------------
555 
556 Graphic SvXMLGraphicHelper::ImplReadGraphic( const ::rtl::OUString& rPictureStorageName,
557                                              const ::rtl::OUString& rPictureStreamName )
558 {
559     Graphic             aGraphic;
560     SvxGraphicHelperStream_Impl aStream( ImplGetGraphicStream( rPictureStorageName, rPictureStreamName, sal_False ) );
561     if( aStream.xStream.is() )
562     {
563         SvStream* pStream = utl::UcbStreamHelper::CreateStream( aStream.xStream );
564         GraphicFilter::GetGraphicFilter()->ImportGraphic( aGraphic, String(), *pStream );
565         delete pStream;
566     }
567 
568     return aGraphic;
569 }
570 
571 // -----------------------------------------------------------------------------
572 
573 sal_Bool SvXMLGraphicHelper::ImplWriteGraphic( const ::rtl::OUString& rPictureStorageName,
574                                                const ::rtl::OUString& rPictureStreamName,
575                                                const ::rtl::OUString& rGraphicId )
576 {
577     String          aGraphicId( rGraphicId );
578     GraphicObject   aGrfObject( ByteString( aGraphicId, RTL_TEXTENCODING_ASCII_US ) );
579     sal_Bool        bRet = sal_False;
580 
581     if( aGrfObject.GetType() != GRAPHIC_NONE )
582     {
583         SvxGraphicHelperStream_Impl aStream( ImplGetGraphicStream( rPictureStorageName, rPictureStreamName, sal_False ) );
584         if( aStream.xStream.is() )
585         {
586             Graphic         aGraphic( (Graphic&) aGrfObject.GetGraphic() );
587             const GfxLink   aGfxLink( aGraphic.GetLink() );
588             const ::rtl::OUString  aMimeType( ImplGetGraphicMimeType( rPictureStreamName ) );
589             uno::Any        aAny;
590             uno::Reference < beans::XPropertySet > xProps( aStream.xStream, uno::UNO_QUERY );
591 
592             // set stream properties (MediaType/Compression)
593             if( aMimeType.getLength() )
594             {
595                 aAny <<= aMimeType;
596                 xProps->setPropertyValue( String( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), aAny );
597             }
598 
599             const sal_Bool bCompressed = ( ( 0 == aMimeType.getLength() ) || ( aMimeType == ::rtl::OUString::createFromAscii( "image/tiff" ) ) );
600             aAny <<= bCompressed;
601             xProps->setPropertyValue( String( RTL_CONSTASCII_USTRINGPARAM( "Compressed" ) ), aAny );
602 
603             SvStream* pStream = utl::UcbStreamHelper::CreateStream( aStream.xStream );
604             if( aGfxLink.GetDataSize() && aGfxLink.GetData() )
605                 pStream->Write( aGfxLink.GetData(), aGfxLink.GetDataSize() );
606             else
607             {
608                 if( aGraphic.GetType() == GRAPHIC_BITMAP )
609                 {
610                     GraphicFilter*  pFilter = GraphicFilter::GetGraphicFilter();
611                     String          aFormat;
612 
613                     if( aGraphic.IsAnimated() )
614                         aFormat = String( RTL_CONSTASCII_USTRINGPARAM( "gif" ) );
615                     else
616                         aFormat = String( RTL_CONSTASCII_USTRINGPARAM( "png" ) );
617 
618                     bRet = ( pFilter->ExportGraphic( aGraphic, String(), *pStream,
619                                                      pFilter->GetExportFormatNumberForShortName( aFormat ) ) == 0 );
620                 }
621                 else if( aGraphic.GetType() == GRAPHIC_GDIMETAFILE )
622                 {
623                     pStream->SetVersion( SOFFICE_FILEFORMAT_8 );
624                     pStream->SetCompressMode( COMPRESSMODE_ZBITMAP );
625 
626                     // SJ: first check if this metafile is just a eps file, then we will store the eps instead of svm
627                     GDIMetaFile& rMtf( (GDIMetaFile&)aGraphic.GetGDIMetaFile() );
628                     const MetaCommentAction* pComment = ImplCheckForEPS( rMtf );
629                     if ( pComment )
630                     {
631                         sal_uInt32  nSize = pComment->GetDataSize();
632                         const sal_uInt8* pData = pComment->GetData();
633                         if ( nSize && pData )
634                             pStream->Write( pData, nSize );
635 
636                         const MetaEPSAction* pAct = ( (const MetaEPSAction*)rMtf.FirstAction() );
637                         const GfxLink&       rLink = pAct->GetLink();
638 
639                         pStream->Write( rLink.GetData(), rLink.GetDataSize() );
640                     }
641                     else
642                         rMtf.Write( *pStream );
643 
644                     bRet = ( pStream->GetError() == 0 );
645                 }
646             }
647             uno::Reference < embed::XTransactedObject > xStorage(
648                                     aStream.xStorage, uno::UNO_QUERY);
649             delete pStream;
650             aStream.xStream->getOutputStream()->closeOutput();
651             if( xStorage.is() )
652                 xStorage->commit();
653         }
654     }
655 
656     return bRet;
657 }
658 
659 // -----------------------------------------------------------------------------
660 
661 void SvXMLGraphicHelper::ImplInsertGraphicURL( const ::rtl::OUString& rURLStr, sal_uInt32 nInsertPos, rtl::OUString& rRequestedFileName )
662 {
663     rtl::OUString aURLString( rURLStr );
664     ::rtl::OUString aPictureStorageName, aPictureStreamName;
665     if( ( maURLSet.find( aURLString ) != maURLSet.end() ) )
666     {
667         URLPairVector::iterator aIter( maGrfURLs.begin() ), aEnd( maGrfURLs.end() );
668         while( aIter != aEnd )
669         {
670             if( aURLString == (*aIter).first )
671             {
672                 maGrfURLs[ nInsertPos ].second = (*aIter).second;
673                 aIter = aEnd;
674             }
675             else
676                 aIter++;
677         }
678     }
679     else if( ImplGetStreamNames( aURLString, aPictureStorageName, aPictureStreamName ) )
680     {
681         URLPair& rURLPair = maGrfURLs[ nInsertPos ];
682 
683         if( GRAPHICHELPER_MODE_READ == meCreateMode )
684         {
685             const GraphicObject aObj( ImplReadGraphic( aPictureStorageName, aPictureStreamName ) );
686 
687             if( aObj.GetType() != GRAPHIC_NONE )
688             {
689                 const static ::rtl::OUString aBaseURL( RTL_CONSTASCII_USTRINGPARAM( XML_GRAPHICOBJECT_URL_BASE ) );
690 
691                 maGrfObjs.push_back( aObj );
692                 rURLPair.second = aBaseURL;
693                 rURLPair.second += String( aObj.GetUniqueID().GetBuffer(), RTL_TEXTENCODING_ASCII_US );
694             }
695             else
696                 rURLPair.second = String();
697         }
698         else
699         {
700             const String        aGraphicObjectId( aPictureStreamName );
701             const ByteString    aAsciiObjectID( aGraphicObjectId, RTL_TEXTENCODING_ASCII_US );
702             const GraphicObject aGrfObject( aAsciiObjectID );
703             if( aGrfObject.GetType() != GRAPHIC_NONE )
704             {
705                 String          aStreamName( aGraphicObjectId );
706                 Graphic         aGraphic( (Graphic&) aGrfObject.GetGraphic() );
707                 const GfxLink   aGfxLink( aGraphic.GetLink() );
708                 String          aExtension;
709 
710                 if( aGfxLink.GetDataSize() )
711                 {
712                     switch( aGfxLink.GetType() )
713                     {
714                         case( GFX_LINK_TYPE_EPS_BUFFER ): aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".eps" ) ); break;
715                         case( GFX_LINK_TYPE_NATIVE_GIF ): aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".gif" ) ); break;
716 
717                         // #15508# added BMP type for better exports (checked, works)
718                         case( GFX_LINK_TYPE_NATIVE_BMP ): aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".bmp" ) ); break;
719 
720                         case( GFX_LINK_TYPE_NATIVE_JPG ): aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".jpg" ) ); break;
721                         case( GFX_LINK_TYPE_NATIVE_PNG ): aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".png" ) ); break;
722                         case( GFX_LINK_TYPE_NATIVE_TIF ): aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".tif" ) ); break;
723                         case( GFX_LINK_TYPE_NATIVE_WMF ): aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".wmf" ) ); break;
724                         case( GFX_LINK_TYPE_NATIVE_MET ): aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".met" ) ); break;
725                         case( GFX_LINK_TYPE_NATIVE_PCT ): aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".pct" ) ); break;
726                         case( GFX_LINK_TYPE_NATIVE_SVG ): aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".svg" ) ); break;
727 
728                         default:
729                             aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".grf" ) );
730                         break;
731                     }
732                 }
733                 else
734                 {
735                     if( aGrfObject.GetType() == GRAPHIC_BITMAP )
736                     {
737                         if( aGrfObject.IsAnimated() )
738                             aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".gif" ) );
739                         else
740                             aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".png" ) );
741                     }
742                     else if( aGrfObject.GetType() == GRAPHIC_GDIMETAFILE )
743                     {
744                         // SJ: first check if this metafile is just a eps file, then we will store the eps instead of svm
745                         GDIMetaFile& rMtf( (GDIMetaFile&)aGraphic.GetGDIMetaFile() );
746                         if ( ImplCheckForEPS( rMtf ) )
747                             aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".eps" ) );
748                         else
749                             aExtension = String( RTL_CONSTASCII_USTRINGPARAM( ".svm" ) );
750                     }
751                 }
752 
753                 rtl::OUString aURLEntry;
754                 const String sPictures( RTL_CONSTASCII_USTRINGPARAM( "Pictures/" ) );
755 
756                 if ( rRequestedFileName.getLength() )
757                 {
758                     aURLEntry = sPictures;
759                     aURLEntry += rRequestedFileName;
760                     aURLEntry += aExtension;
761 
762                     URLPairVector::iterator aIter( maGrfURLs.begin() ), aEnd( maGrfURLs.end() );
763                     while( aIter != aEnd )
764                     {
765                         if( aURLEntry == (*aIter).second )
766                             break;
767                         aIter++;
768                     }
769                     if ( aIter == aEnd )
770                         aStreamName = rRequestedFileName;
771                 }
772 
773                 aStreamName += aExtension;
774 
775                 if( mbDirect && aStreamName.Len() )
776                     ImplWriteGraphic( aPictureStorageName, aStreamName, aGraphicObjectId );
777 
778                 rURLPair.second = sPictures;
779                 rURLPair.second += aStreamName;
780             }
781 #if OSL_DEBUG_LEVEL > 0
782             else
783             {
784                 ByteString sMessage = "graphic object with ID '";
785                 sMessage += aAsciiObjectID;
786                 sMessage += "' has an unknown type";
787                 OSL_ENSURE( false, sMessage.GetBuffer() );
788             }
789 #endif
790         }
791 
792         maURLSet.insert( aURLString );
793     }
794 }
795 
796 // -----------------------------------------------------------------------------
797 
798 void SvXMLGraphicHelper::Init( const uno::Reference < embed::XStorage >& rXMLStorage,
799                                SvXMLGraphicHelperMode eCreateMode,
800                                sal_Bool bDirect )
801 {
802     mxRootStorage = rXMLStorage;
803     meCreateMode = eCreateMode;
804     mbDirect = ( ( GRAPHICHELPER_MODE_READ == meCreateMode ) ? bDirect : sal_True );
805 }
806 
807 // -----------------------------------------------------------------------------
808 
809 SvXMLGraphicHelper* SvXMLGraphicHelper::Create( const uno::Reference < embed::XStorage >& rXMLStorage,
810                                                 SvXMLGraphicHelperMode eCreateMode,
811                                                 sal_Bool bDirect )
812 {
813     SvXMLGraphicHelper* pThis = new SvXMLGraphicHelper;
814 
815     pThis->acquire();
816     pThis->Init( rXMLStorage, eCreateMode, bDirect );
817 
818     return pThis;
819 }
820 
821 // -----------------------------------------------------------------------------
822 
823 SvXMLGraphicHelper* SvXMLGraphicHelper::Create( SvXMLGraphicHelperMode eCreateMode )
824 {
825     SvXMLGraphicHelper* pThis = new SvXMLGraphicHelper;
826 
827     pThis->acquire();
828     pThis->Init( NULL, eCreateMode, sal_False );
829 
830     return pThis;
831 }
832 
833 // -----------------------------------------------------------------------------
834 
835 void SvXMLGraphicHelper::Destroy( SvXMLGraphicHelper* pSvXMLGraphicHelper )
836 {
837     if( pSvXMLGraphicHelper )
838     {
839         pSvXMLGraphicHelper->dispose();
840         pSvXMLGraphicHelper->release();
841     }
842 }
843 
844 // -----------------------------------------------------------------------------
845 
846 // XGraphicObjectResolver
847 ::rtl::OUString SAL_CALL SvXMLGraphicHelper::resolveGraphicObjectURL( const ::rtl::OUString& rURL )
848 {
849     ::osl::MutexGuard   aGuard( maMutex );
850     const sal_Int32     nIndex = maGrfURLs.size();
851 
852     rtl::OUString aURL( rURL );
853     rtl::OUString aUserData;
854     rtl::OUString aRequestedFileName;
855 
856     sal_Int32 nUser = rURL.indexOf( '?', 0 );
857     if ( nUser >= 0 )
858     {
859         aURL = rtl::OUString( rURL.copy( 0, nUser ) );
860         nUser++;
861         aUserData = rURL.copy( nUser, rURL.getLength() - nUser );
862     }
863     if ( aUserData.getLength() )
864     {
865         sal_Int32 nIndex2 = 0;
866         do
867         {
868             rtl::OUString aToken = aUserData.getToken( 0, ';', nIndex2 );
869             sal_Int32 n = aToken.indexOf( '=' );
870             if ( ( n > 0 ) && ( ( n + 1 ) < aToken.getLength() ) )
871             {
872                 rtl::OUString aParam( aToken.copy( 0, n ) );
873                 rtl::OUString aValue( aToken.copy( n + 1, aToken.getLength() - ( n + 1 ) ) );
874 
875                 const rtl::OUString sRequestedName( RTL_CONSTASCII_USTRINGPARAM("requestedName") );
876                 if ( aParam.match( sRequestedName ) )
877                     aRequestedFileName = aValue;
878             }
879         }
880         while ( nIndex2 >= 0 );
881     }
882 
883     maGrfURLs.push_back( ::std::make_pair( aURL, ::rtl::OUString() ) );
884     ImplInsertGraphicURL( aURL, nIndex, aRequestedFileName );
885 
886     return maGrfURLs[ nIndex ].second;
887 }
888 
889 // -----------------------------------------------------------------------------
890 
891 // XBinaryStreamResolver
892 Reference< XInputStream > SAL_CALL SvXMLGraphicHelper::getInputStream( const ::rtl::OUString& rURL )
893 {
894     Reference< XInputStream >   xRet;
895     ::rtl::OUString                    aPictureStorageName, aGraphicId;
896 
897 
898     if( ( GRAPHICHELPER_MODE_WRITE == meCreateMode ) &&
899         ImplGetStreamNames( rURL, aPictureStorageName, aGraphicId ) )
900     {
901         SvXMLGraphicInputStream* pInputStream = new SvXMLGraphicInputStream( aGraphicId );
902 
903         if( pInputStream->Exists() )
904             xRet = pInputStream;
905         else
906             delete pInputStream;
907     }
908 
909     return xRet;
910 }
911 
912 // -----------------------------------------------------------------------------
913 
914 Reference< XOutputStream > SAL_CALL SvXMLGraphicHelper::createOutputStream()
915 {
916     Reference< XOutputStream > xRet;
917 
918     if( GRAPHICHELPER_MODE_READ == meCreateMode )
919     {
920         SvXMLGraphicOutputStream* pOutputStream = new SvXMLGraphicOutputStream;
921 
922         if( pOutputStream->Exists() )
923             maGrfStms.push_back( xRet = pOutputStream );
924         else
925             delete pOutputStream;
926     }
927 
928     return xRet;
929 }
930 
931 // -----------------------------------------------------------------------------
932 
933 ::rtl::OUString SAL_CALL SvXMLGraphicHelper::resolveOutputStream( const Reference< XOutputStream >& rxBinaryStream )
934 {
935     ::rtl::OUString aRet;
936 
937     if( ( GRAPHICHELPER_MODE_READ == meCreateMode ) && rxBinaryStream.is() )
938     {
939         if( ::std::find( maGrfStms.begin(), maGrfStms.end(), rxBinaryStream ) != maGrfStms.end() )
940         {
941             SvXMLGraphicOutputStream* pOStm = static_cast< SvXMLGraphicOutputStream* >( rxBinaryStream.get() );
942 
943             if( pOStm )
944             {
945                 const GraphicObject&    rGrfObj = pOStm->GetGraphicObject();
946                 const ::rtl::OUString          aId( ::rtl::OUString::createFromAscii( rGrfObj.GetUniqueID().GetBuffer() ) );
947 
948                 if( aId.getLength() )
949                 {
950                     aRet = ::rtl::OUString::createFromAscii( XML_GRAPHICOBJECT_URL_BASE );
951                     aRet += aId;
952                 }
953             }
954         }
955     }
956 
957     return aRet;
958 }
959 
960 
961 // --------------------------------------------------------------------------------
962 
963 // for instantiation via service manager
964 namespace svx
965 {
966 
967 namespace impl
968 {
969 typedef ::cppu::WeakComponentImplHelper4<
970         lang::XInitialization,
971         document::XGraphicObjectResolver,
972         document::XBinaryStreamResolver,
973         lang::XServiceInfo >
974     SvXMLGraphicImportExportHelper_Base;
975 class MutexContainer
976 {
977 public:
978     virtual ~MutexContainer();
979 
980 protected:
981     mutable ::osl::Mutex m_aMutex;
982 };
983 MutexContainer::~MutexContainer()
984 {}
985 } // namespace impl
986 
987 class SvXMLGraphicImportExportHelper :
988     public impl::MutexContainer,
989     public impl::SvXMLGraphicImportExportHelper_Base
990 {
991 public:
992     SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode );
993 
994 protected:
995     // is called from WeakComponentImplHelper when XComponent::dispose() was
996     // called from outside
997     virtual void SAL_CALL disposing();
998 
999     // ____ XInitialization ____
1000     // one argument is allowed, which is the XStorage
1001     virtual void SAL_CALL initialize( const Sequence< Any >& aArguments );
1002 
1003     // ____ XGraphicObjectResolver ____
1004     virtual ::rtl::OUString SAL_CALL resolveGraphicObjectURL( const ::rtl::OUString& aURL );
1005 
1006     // ____ XBinaryStreamResolver ____
1007     virtual Reference< io::XInputStream > SAL_CALL getInputStream( const ::rtl::OUString& aURL );
1008     virtual Reference< io::XOutputStream > SAL_CALL createOutputStream();
1009     virtual ::rtl::OUString SAL_CALL resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream );
1010 
1011     // ____ XServiceInfo ____
1012     virtual ::rtl::OUString SAL_CALL getImplementationName();
1013     virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName );
1014     virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames();
1015 
1016 private:
1017     SvXMLGraphicHelperMode              m_eGraphicHelperMode;
1018     Reference< XGraphicObjectResolver > m_xGraphicObjectResolver;
1019     Reference< XBinaryStreamResolver >  m_xBinaryStreamResolver;
1020 };
1021 
1022 SvXMLGraphicImportExportHelper::SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode ) :
1023         impl::SvXMLGraphicImportExportHelper_Base( m_aMutex ),
1024         m_eGraphicHelperMode( eMode )
1025 {}
1026 
1027 void SAL_CALL SvXMLGraphicImportExportHelper::disposing()
1028 {
1029     Reference< XComponent > xComp( m_xGraphicObjectResolver, UNO_QUERY );
1030     OSL_ASSERT( xComp.is());
1031     if( xComp.is())
1032         xComp->dispose();
1033     // m_xBinaryStreamResolver is a reference to the same object => don't call
1034     // dispose() again
1035 }
1036 
1037 // ____ XInitialization ____
1038 void SAL_CALL SvXMLGraphicImportExportHelper::initialize(
1039     const Sequence< Any >& aArguments )
1040 {
1041     Reference< embed::XStorage > xStorage;
1042     if( aArguments.getLength() > 0 )
1043         aArguments[0] >>= xStorage;
1044 
1045     SvXMLGraphicHelper * pHelper( SvXMLGraphicHelper::Create( xStorage, m_eGraphicHelperMode ));
1046     m_xGraphicObjectResolver.set( pHelper );
1047     m_xBinaryStreamResolver.set( pHelper );
1048     // SvXMLGraphicHelper::Create calls acquire.  Since we have two references
1049     // now it is safe (and necessary) to undo this acquire
1050     pHelper->release();
1051 }
1052 
1053 // ____ XGraphicObjectResolver ____
1054 ::rtl::OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveGraphicObjectURL( const ::rtl::OUString& aURL )
1055 {
1056     return m_xGraphicObjectResolver->resolveGraphicObjectURL( aURL );
1057 }
1058 
1059 
1060 // ____ XBinaryStreamResolver ____
1061 Reference< io::XInputStream > SAL_CALL SvXMLGraphicImportExportHelper::getInputStream( const ::rtl::OUString& aURL )
1062 {
1063     return m_xBinaryStreamResolver->getInputStream( aURL );
1064 }
1065 Reference< io::XOutputStream > SAL_CALL SvXMLGraphicImportExportHelper::createOutputStream()
1066 {
1067     return m_xBinaryStreamResolver->createOutputStream();
1068 }
1069 ::rtl::OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream )
1070 {
1071     return m_xBinaryStreamResolver->resolveOutputStream( aBinaryStream );
1072 }
1073 
1074 // ____ XServiceInfo ____
1075 ::rtl::OUString SAL_CALL SvXMLGraphicImportExportHelper::getImplementationName()
1076 {
1077     if( m_eGraphicHelperMode == GRAPHICHELPER_MODE_READ )
1078         return SvXMLGraphicImportHelper_getImplementationName();
1079     return SvXMLGraphicExportHelper_getImplementationName();
1080 }
1081 ::sal_Bool SAL_CALL SvXMLGraphicImportExportHelper::supportsService( const ::rtl::OUString& ServiceName )
1082 {
1083     Sequence< ::rtl::OUString > aServiceNames( getSupportedServiceNames());
1084     const ::rtl::OUString * pBegin = aServiceNames.getConstArray();
1085     const ::rtl::OUString * pEnd = pBegin + aServiceNames.getLength();
1086     return (::std::find( pBegin, pEnd, ServiceName ) != pEnd);
1087 }
1088 Sequence< ::rtl::OUString > SAL_CALL SvXMLGraphicImportExportHelper::getSupportedServiceNames()
1089 {
1090     if( m_eGraphicHelperMode == GRAPHICHELPER_MODE_READ )
1091         return SvXMLGraphicImportHelper_getSupportedServiceNames();
1092     return SvXMLGraphicExportHelper_getSupportedServiceNames();
1093 }
1094 
1095 // import
1096 Reference< XInterface > SAL_CALL SvXMLGraphicImportHelper_createInstance(const Reference< XMultiServiceFactory > & /* rSMgr */ )
1097 {
1098     return static_cast< XWeak* >( new SvXMLGraphicImportExportHelper( GRAPHICHELPER_MODE_READ ));
1099 }
1100 ::rtl::OUString SAL_CALL SvXMLGraphicImportHelper_getImplementationName()
1101     throw()
1102 {
1103     return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Svx.GraphicImportHelper" ));
1104 }
1105 Sequence< ::rtl::OUString > SAL_CALL SvXMLGraphicImportHelper_getSupportedServiceNames()
1106     throw()
1107 {
1108     // XGraphicObjectResolver and XBinaryStreamResolver are not part of any service
1109     Sequence< ::rtl::OUString > aSupportedServiceNames( 2 );
1110     aSupportedServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.GraphicObjectResolver" ) );
1111     aSupportedServiceNames[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.BinaryStreamResolver" ) );
1112     return aSupportedServiceNames;
1113 }
1114 
1115 // export
1116 Reference< XInterface > SAL_CALL SvXMLGraphicExportHelper_createInstance(const Reference< XMultiServiceFactory > & /* rSMgr */ )
1117 {
1118     return static_cast< XWeak* >( new SvXMLGraphicImportExportHelper( GRAPHICHELPER_MODE_WRITE ));
1119 }
1120 ::rtl::OUString SAL_CALL SvXMLGraphicExportHelper_getImplementationName()
1121     throw()
1122 {
1123     return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Svx.GraphicExportHelper" ));
1124 }
1125 Sequence< ::rtl::OUString > SAL_CALL SvXMLGraphicExportHelper_getSupportedServiceNames()
1126     throw()
1127 {
1128     // XGraphicObjectResolver and XBinaryStreamResolver are not part of any service
1129     Sequence< ::rtl::OUString > aSupportedServiceNames( 2 );
1130     aSupportedServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.GraphicObjectResolver" ) );
1131     aSupportedServiceNames[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.BinaryStreamResolver" ) );
1132     return aSupportedServiceNames;
1133 }
1134 
1135 } // namespace svx
1136