bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / xml / xmlgrhlp.cxx
blobfa21c1728fba907a17ad37bee37d4996d6c02190
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <boost/noncopyable.hpp>
23 #include <comphelper/string.hxx>
24 #include <sal/macros.h>
25 #include <com/sun/star/embed/XTransactedObject.hpp>
26 #include <com/sun/star/embed/ElementModes.hpp>
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
29 #include <com/sun/star/lang/XServiceInfo.hpp>
30 #include <com/sun/star/lang/XInitialization.hpp>
31 #include <cppuhelper/compbase4.hxx>
32 #include <cppuhelper/supportsservice.hxx>
34 #include <rtl/ref.hxx>
35 #include <unotools/ucbstreamhelper.hxx>
36 #include <unotools/streamwrap.hxx>
37 #include <unotools/tempfile.hxx>
38 #include <unotools/saveopt.hxx>
39 #include <vcl/cvtgrf.hxx>
40 #include <vcl/gfxlink.hxx>
41 #include <vcl/metaact.hxx>
42 #include <tools/zcodec.hxx>
44 #include <vcl/graphicfilter.hxx>
45 #include "svx/xmlgrhlp.hxx"
46 #include "svx/xmleohlp.hxx"
48 #include <algorithm>
49 #include <boost/scoped_ptr.hpp>
51 using namespace com::sun::star;
52 using namespace com::sun::star::uno;
53 using namespace com::sun::star::io;
55 using ::com::sun::star::lang::XMultiServiceFactory;
57 #define XML_GRAPHICSTORAGE_NAME "Pictures"
58 #define XML_GRAPHICOBJECT_URL_BASE "vnd.sun.star.GraphicObject:"
60 namespace {
62 const MetaCommentAction* ImplCheckForEPS( GDIMetaFile& rMtf )
64 const MetaCommentAction* pComment = NULL;
66 if ( rMtf.GetActionSize() >= 2
67 && rMtf.GetAction(0)->GetType() == MetaActionType::EPS
68 && rMtf.GetAction(1)->GetType() == MetaActionType::COMMENT
69 && ( static_cast<const MetaCommentAction*>(rMtf.GetAction( 1 ))->GetComment() == "EPSReplacementGraphic" ) )
70 pComment = static_cast<const MetaCommentAction*>(rMtf.GetAction( 1 ));
72 return pComment;
75 class SvXMLGraphicInputStream:
76 public cppu::WeakImplHelper1<XInputStream>, private boost::noncopyable
78 private:
80 virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) throw(NotConnectedException, BufferSizeExceededException, RuntimeException, std::exception) SAL_OVERRIDE;
81 virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw(NotConnectedException, BufferSizeExceededException, RuntimeException, std::exception) SAL_OVERRIDE;
82 virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) throw(NotConnectedException, BufferSizeExceededException, RuntimeException, std::exception) SAL_OVERRIDE;
83 virtual sal_Int32 SAL_CALL available() throw(NotConnectedException, RuntimeException, std::exception) SAL_OVERRIDE;
84 virtual void SAL_CALL closeInput() throw(NotConnectedException, RuntimeException, std::exception) SAL_OVERRIDE;
86 private:
88 ::utl::TempFile maTmp;
89 Reference< XInputStream > mxStmWrapper;
91 public:
93 SvXMLGraphicInputStream( const OUString& rGraphicId );
94 virtual ~SvXMLGraphicInputStream();
96 bool Exists() const { return mxStmWrapper.is(); }
99 SvXMLGraphicInputStream::SvXMLGraphicInputStream( const OUString& rGraphicId )
101 GraphicObject aGrfObject( OUStringToOString(rGraphicId, RTL_TEXTENCODING_ASCII_US) );
103 maTmp.EnableKillingFile();
105 if( aGrfObject.GetType() != GRAPHIC_NONE )
107 SvStream* pStm = ::utl::UcbStreamHelper::CreateStream( maTmp.GetURL(), StreamMode::WRITE | StreamMode::TRUNC );
109 if( pStm )
111 Graphic aGraphic( (Graphic&) aGrfObject.GetGraphic() );
112 const GfxLink aGfxLink( aGraphic.GetLink() );
113 bool bRet = false;
115 if( aGfxLink.GetDataSize() && aGfxLink.GetData() )
117 pStm->Write( aGfxLink.GetData(), aGfxLink.GetDataSize() );
118 bRet = ( pStm->GetError() == 0 );
120 else
122 if( aGraphic.GetType() == GRAPHIC_BITMAP )
124 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
125 OUString aFormat;
127 if( aGraphic.IsAnimated() )
128 aFormat = "gif";
129 else
130 aFormat = "png";
132 bRet = ( rFilter.ExportGraphic( aGraphic, "", *pStm, rFilter.GetExportFormatNumberForShortName( aFormat ) ) == 0 );
134 else if( aGraphic.GetType() == GRAPHIC_GDIMETAFILE )
136 pStm->SetVersion( SOFFICE_FILEFORMAT_8 );
137 pStm->SetCompressMode( SvStreamCompressFlags::ZBITMAP );
138 ( (GDIMetaFile&) aGraphic.GetGDIMetaFile() ).Write( *pStm );
139 bRet = ( pStm->GetError() == 0 );
143 if( bRet )
145 pStm->Seek( 0 );
146 mxStmWrapper = new ::utl::OInputStreamWrapper( pStm, true );
148 else
149 delete pStm;
154 SvXMLGraphicInputStream::~SvXMLGraphicInputStream()
158 sal_Int32 SAL_CALL SvXMLGraphicInputStream::readBytes( Sequence< sal_Int8 >& rData, sal_Int32 nBytesToRead )
159 throw( NotConnectedException, BufferSizeExceededException, RuntimeException, std::exception )
161 if( !mxStmWrapper.is() )
162 throw NotConnectedException();
164 return mxStmWrapper->readBytes( rData, nBytesToRead );
167 sal_Int32 SAL_CALL SvXMLGraphicInputStream::readSomeBytes( Sequence< sal_Int8 >& rData, sal_Int32 nMaxBytesToRead )
168 throw( NotConnectedException, BufferSizeExceededException, RuntimeException, std::exception )
170 if( !mxStmWrapper.is() )
171 throw NotConnectedException() ;
173 return mxStmWrapper->readSomeBytes( rData, nMaxBytesToRead );
176 void SAL_CALL SvXMLGraphicInputStream::skipBytes( sal_Int32 nBytesToSkip )
177 throw( NotConnectedException, BufferSizeExceededException, RuntimeException, std::exception )
179 if( !mxStmWrapper.is() )
180 throw NotConnectedException() ;
182 mxStmWrapper->skipBytes( nBytesToSkip );
185 sal_Int32 SAL_CALL SvXMLGraphicInputStream::available() throw( NotConnectedException, RuntimeException, std::exception )
187 if( !mxStmWrapper.is() )
188 throw NotConnectedException() ;
190 return mxStmWrapper->available();
193 void SAL_CALL SvXMLGraphicInputStream::closeInput() throw( NotConnectedException, RuntimeException, std::exception )
195 if( !mxStmWrapper.is() )
196 throw NotConnectedException() ;
198 mxStmWrapper->closeInput();
201 class SvXMLGraphicOutputStream:
202 public cppu::WeakImplHelper1<XOutputStream>, private boost::noncopyable
204 private:
206 // XOutputStream
207 virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& rData ) throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception ) SAL_OVERRIDE;
208 virtual void SAL_CALL flush() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception ) SAL_OVERRIDE;
209 virtual void SAL_CALL closeOutput() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception ) SAL_OVERRIDE;
211 private:
213 ::utl::TempFile* mpTmp;
214 SvStream* mpOStm;
215 Reference< XOutputStream > mxStmWrapper;
216 GraphicObject maGrfObj;
217 bool mbClosed;
219 public:
221 SvXMLGraphicOutputStream();
222 virtual ~SvXMLGraphicOutputStream();
224 bool Exists() const { return mxStmWrapper.is(); }
225 const GraphicObject& GetGraphicObject();
228 SvXMLGraphicOutputStream::SvXMLGraphicOutputStream() :
229 mpTmp( new ::utl::TempFile ),
230 mbClosed( false )
232 mpTmp->EnableKillingFile();
234 mpOStm = ::utl::UcbStreamHelper::CreateStream( mpTmp->GetURL(), StreamMode::WRITE | StreamMode::TRUNC );
236 if( mpOStm )
237 mxStmWrapper = new ::utl::OOutputStreamWrapper( *mpOStm );
240 SvXMLGraphicOutputStream::~SvXMLGraphicOutputStream()
242 delete mpTmp;
243 delete mpOStm;
246 void SAL_CALL SvXMLGraphicOutputStream::writeBytes( const Sequence< sal_Int8 >& rData )
247 throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception )
249 if( !mxStmWrapper.is() )
250 throw NotConnectedException() ;
252 mxStmWrapper->writeBytes( rData );
255 void SAL_CALL SvXMLGraphicOutputStream::flush()
256 throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception )
258 if( !mxStmWrapper.is() )
259 throw NotConnectedException() ;
261 mxStmWrapper->flush();
264 void SAL_CALL SvXMLGraphicOutputStream::closeOutput()
265 throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception )
267 if( !mxStmWrapper.is() )
268 throw NotConnectedException() ;
270 mxStmWrapper->closeOutput();
271 mxStmWrapper.clear();
273 mbClosed = true;
276 const GraphicObject& SvXMLGraphicOutputStream::GetGraphicObject()
278 if( mbClosed && ( maGrfObj.GetType() == GRAPHIC_NONE ) && mpOStm )
280 Graphic aGraphic;
282 mpOStm->Seek( 0 );
283 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
284 sal_uInt16 pDeterminedFormat = GRFILTER_FORMAT_DONTKNOW;
285 GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, "", *mpOStm ,nFormat,&pDeterminedFormat );
287 if (pDeterminedFormat == GRFILTER_FORMAT_DONTKNOW)
289 //Read the first two byte to check whether it is a gzipped stream, is so it may be in wmz or emz format
290 //unzip them and try again
292 sal_uInt8 sFirstBytes[ 2 ];
294 mpOStm->Seek( STREAM_SEEK_TO_END );
295 sal_uIntPtr nStreamLen = mpOStm->Tell();
296 mpOStm->Seek( 0 );
298 if ( !nStreamLen )
300 SvLockBytes* pLockBytes = mpOStm->GetLockBytes();
301 if ( pLockBytes )
302 pLockBytes->SetSynchronMode( true );
304 mpOStm->Seek( STREAM_SEEK_TO_END );
305 nStreamLen = mpOStm->Tell();
306 mpOStm->Seek( 0 );
308 if( nStreamLen >= 2 )
310 //read two byte
311 mpOStm->Read( sFirstBytes, 2 );
313 if( sFirstBytes[0] == 0x1f && sFirstBytes[1] == 0x8b )
315 boost::scoped_ptr<SvMemoryStream> pDest(new SvMemoryStream);
316 ZCodec aZCodec( 0x8000, 0x8000 );
317 aZCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, false, true);
318 mpOStm->Seek( 0 );
319 aZCodec.Decompress( *mpOStm, *pDest );
321 if (aZCodec.EndCompression() && pDest )
323 pDest->Seek( STREAM_SEEK_TO_END );
324 sal_uIntPtr nStreamLen_ = pDest->Tell();
325 if (nStreamLen_)
327 pDest->Seek(0L);
328 GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, "", *pDest ,nFormat,&pDeterminedFormat );
335 maGrfObj = aGraphic;
336 if( maGrfObj.GetType() != GRAPHIC_NONE )
338 delete mpOStm, mpOStm = NULL;
339 delete mpTmp, mpTmp = NULL;
343 return maGrfObj;
348 SvXMLGraphicHelper::SvXMLGraphicHelper( SvXMLGraphicHelperMode eCreateMode ) :
349 ::cppu::WeakComponentImplHelper2< ::com::sun::star::document::XGraphicObjectResolver,
350 ::com::sun::star::document::XBinaryStreamResolver >( maMutex )
352 Init( NULL, eCreateMode, false );
355 SvXMLGraphicHelper::SvXMLGraphicHelper()
356 : ::cppu::WeakComponentImplHelper2< ::com::sun::star::document::XGraphicObjectResolver,
357 ::com::sun::star::document::XBinaryStreamResolver >( maMutex )
358 , meCreateMode(GRAPHICHELPER_MODE_READ)
359 , mbDirect(false)
363 SvXMLGraphicHelper::~SvXMLGraphicHelper()
367 void SAL_CALL SvXMLGraphicHelper::disposing()
371 bool SvXMLGraphicHelper::ImplGetStreamNames( const OUString& rURLStr,
372 OUString& rPictureStorageName,
373 OUString& rPictureStreamName )
375 OUString aURLStr( rURLStr );
376 bool bRet = false;
378 if( !aURLStr.isEmpty() )
380 aURLStr = aURLStr.getToken( comphelper::string::getTokenCount(aURLStr, ':') - 1, ':' );
382 const sal_uInt32 nTokenCount = comphelper::string::getTokenCount(aURLStr, '/');
384 if( 1 == nTokenCount )
386 rPictureStorageName = XML_GRAPHICSTORAGE_NAME;
387 rPictureStreamName = aURLStr;
389 else
390 SvXMLEmbeddedObjectHelper::splitObjectURL(aURLStr, rPictureStorageName, rPictureStreamName);
392 bRet = !rPictureStreamName.isEmpty();
393 SAL_WARN_IF(!bRet, "svx", "SvXMLGraphicHelper::ImplInsertGraphicURL: invalid scheme: " << rURLStr);
396 return bRet;
399 uno::Reference < embed::XStorage > SvXMLGraphicHelper::ImplGetGraphicStorage( const OUString& rStorageName )
401 uno::Reference < embed::XStorage > xRetStorage;
402 if( mxRootStorage.is() )
406 xRetStorage = mxRootStorage->openStorageElement(
407 maCurStorageName = rStorageName,
408 ( GRAPHICHELPER_MODE_WRITE == meCreateMode )
409 ? embed::ElementModes::READWRITE
410 : embed::ElementModes::READ );
412 catch ( uno::Exception& )
415 //#i43196# try again to open the storage element - this time readonly
416 if(!xRetStorage.is())
420 xRetStorage = mxRootStorage->openStorageElement( maCurStorageName = rStorageName, embed::ElementModes::READ );
422 catch ( uno::Exception& )
428 return xRetStorage;
431 SvxGraphicHelperStream_Impl SvXMLGraphicHelper::ImplGetGraphicStream( const OUString& rPictureStorageName,
432 const OUString& rPictureStreamName,
433 bool bTruncate )
435 SvxGraphicHelperStream_Impl aRet;
436 aRet.xStorage = ImplGetGraphicStorage( rPictureStorageName );
438 if( aRet.xStorage.is() )
440 sal_Int32 nMode = embed::ElementModes::READ;
441 if ( GRAPHICHELPER_MODE_WRITE == meCreateMode )
443 nMode = embed::ElementModes::READWRITE;
444 if ( bTruncate )
445 nMode |= embed::ElementModes::TRUNCATE;
448 aRet.xStream = aRet.xStorage->openStreamElement( rPictureStreamName, nMode );
449 if( aRet.xStream.is() && ( GRAPHICHELPER_MODE_WRITE == meCreateMode ) )
451 OUString aPropName( "UseCommonStoragePasswordEncryption" );
452 uno::Reference < beans::XPropertySet > xProps( aRet.xStream, uno::UNO_QUERY );
453 xProps->setPropertyValue( aPropName, uno::makeAny( sal_True) );
457 return aRet;
460 OUString SvXMLGraphicHelper::ImplGetGraphicMimeType( const OUString& rFileName ) const
462 struct XMLGraphicMimeTypeMapper
464 const char* pExt;
465 const char* pMimeType;
468 static const XMLGraphicMimeTypeMapper aMapper[] =
470 { "gif", "image/gif" },
471 { "png", "image/png" },
472 { "jpg", "image/jpeg" },
473 { "tif", "image/tiff" },
474 { "svg", "image/svg+xml" },
475 { "wmf", "image/x-wmf" },
476 { "eps", "image/x-eps" },
477 { "bmp", "image/bmp" },
478 { "pct", "image/x-pict" }
481 OUString aMimeType;
483 if( ( rFileName.getLength() >= 4 ) && ( rFileName[ rFileName.getLength() - 4 ] == '.' ) )
485 const OString aExt(OUStringToOString(rFileName.copy(rFileName.getLength() - 3),
486 RTL_TEXTENCODING_ASCII_US));
488 for( long i = 0, nCount = sizeof (aMapper) / sizeof (aMapper[0]); ( i < nCount ) && aMimeType.isEmpty(); i++ )
489 if( strcmp(aExt.getStr(), aMapper[ i ].pExt) == 0 )
490 aMimeType = OUString( aMapper[ i ].pMimeType, strlen( aMapper[ i ].pMimeType ), RTL_TEXTENCODING_ASCII_US );
493 return aMimeType;
496 Graphic SvXMLGraphicHelper::ImplReadGraphic( const OUString& rPictureStorageName,
497 const OUString& rPictureStreamName )
499 Graphic aGraphic;
500 SvxGraphicHelperStream_Impl aStream( ImplGetGraphicStream( rPictureStorageName, rPictureStreamName, false ) );
501 if( aStream.xStream.is() )
503 boost::scoped_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream( aStream.xStream ));
504 GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, "", *pStream );
507 return aGraphic;
510 bool SvXMLGraphicHelper::ImplWriteGraphic( const OUString& rPictureStorageName,
511 const OUString& rPictureStreamName,
512 const OUString& rGraphicId,
513 bool bUseGfxLink )
515 GraphicObject aGrfObject( OUStringToOString(rGraphicId, RTL_TEXTENCODING_ASCII_US) );
516 bool bRet = false;
518 if( aGrfObject.GetType() != GRAPHIC_NONE )
520 SvxGraphicHelperStream_Impl aStream( ImplGetGraphicStream( rPictureStorageName, rPictureStreamName, false ) );
521 if( aStream.xStream.is() )
523 Graphic aGraphic( (Graphic&) aGrfObject.GetGraphic() );
524 const GfxLink aGfxLink( aGraphic.GetLink() );
525 const OUString aMimeType( ImplGetGraphicMimeType( rPictureStreamName ) );
526 uno::Any aAny;
527 uno::Reference < beans::XPropertySet > xProps( aStream.xStream, uno::UNO_QUERY );
529 // set stream properties (MediaType/Compression)
530 if( !aMimeType.isEmpty() )
532 aAny <<= aMimeType;
533 xProps->setPropertyValue( "MediaType", aAny );
536 const bool bCompressed = aMimeType.isEmpty() || aMimeType == "image/tiff" || aMimeType == "image/svg+xml";
537 aAny <<= bCompressed;
538 xProps->setPropertyValue( "Compressed", aAny );
540 boost::scoped_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream( aStream.xStream ));
541 if( bUseGfxLink && aGfxLink.GetDataSize() && aGfxLink.GetData() )
542 pStream->Write( aGfxLink.GetData(), aGfxLink.GetDataSize() );
543 else
545 if( aGraphic.GetType() == GRAPHIC_BITMAP )
547 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
548 OUString aFormat;
550 if( aGraphic.IsAnimated() )
551 aFormat = "gif";
552 else
553 aFormat = "png";
555 bRet = ( rFilter.ExportGraphic( aGraphic, "", *pStream,
556 rFilter.GetExportFormatNumberForShortName( aFormat ) ) == 0 );
558 else if( aGraphic.GetType() == GRAPHIC_GDIMETAFILE )
560 pStream->SetVersion( SOFFICE_FILEFORMAT_8 );
561 pStream->SetCompressMode( SvStreamCompressFlags::ZBITMAP );
563 // SJ: first check if this metafile is just a eps file, then we will store the eps instead of svm
564 GDIMetaFile& rMtf( (GDIMetaFile&)aGraphic.GetGDIMetaFile() );
565 const MetaCommentAction* pComment = ImplCheckForEPS( rMtf );
566 if ( pComment )
568 sal_uInt32 nSize = pComment->GetDataSize();
569 const sal_uInt8* pData = pComment->GetData();
570 if ( nSize && pData )
571 pStream->Write( pData, nSize );
573 const MetaEPSAction* pAct = static_cast<const MetaEPSAction*>(rMtf.FirstAction());
574 const GfxLink& rLink = pAct->GetLink();
576 pStream->Write( rLink.GetData(), rLink.GetDataSize() );
578 else
579 rMtf.Write( *pStream );
581 bRet = ( pStream->GetError() == 0 );
584 uno::Reference < embed::XTransactedObject > xStorage(
585 aStream.xStorage, uno::UNO_QUERY);
586 pStream.reset();
587 aStream.xStream->getOutputStream()->closeOutput();
588 if( xStorage.is() )
589 xStorage->commit();
593 return bRet;
596 void SvXMLGraphicHelper::ImplInsertGraphicURL( const OUString& rURLStr, sal_uInt32 nInsertPos, OUString& rRequestedFileName )
598 OUString aURLString( rURLStr );
599 OUString aPictureStorageName, aPictureStreamName;
600 if( ( maURLSet.find( aURLString ) != maURLSet.end() ) )
602 for (URLPairVector::const_iterator aIter( maGrfURLs.begin() ), aEnd( maGrfURLs.end() ); aIter != aEnd ; ++aIter)
604 if( aURLString == (*aIter).first )
606 maGrfURLs[ nInsertPos ].second = (*aIter).second;
607 break;
611 else if( ImplGetStreamNames( aURLString, aPictureStorageName, aPictureStreamName ) )
613 URLPair& rURLPair = maGrfURLs[ nInsertPos ];
615 if( GRAPHICHELPER_MODE_READ == meCreateMode )
617 const GraphicObject aObj( ImplReadGraphic( aPictureStorageName, aPictureStreamName ) );
619 if( aObj.GetType() != GRAPHIC_NONE )
621 maGrfObjs.push_back( aObj );
622 OUString aBaseURL( XML_GRAPHICOBJECT_URL_BASE );
624 rURLPair.second = aBaseURL;
625 rURLPair.second += OStringToOUString(aObj.GetUniqueID(),
626 RTL_TEXTENCODING_ASCII_US);
628 else
629 rURLPair.second.clear();
631 else
633 const OUString aGraphicObjectId( aPictureStreamName );
634 const OString aAsciiObjectID(OUStringToOString(aGraphicObjectId, RTL_TEXTENCODING_ASCII_US));
635 const GraphicObject aGrfObject( aAsciiObjectID );
636 if( aGrfObject.GetType() != GRAPHIC_NONE )
638 OUString aStreamName( aGraphicObjectId );
639 Graphic aGraphic( (Graphic&) aGrfObject.GetGraphic() );
640 const GfxLink aGfxLink( aGraphic.GetLink() );
641 OUString aExtension;
642 bool bUseGfxLink( true );
644 if( aGfxLink.GetDataSize() )
646 switch( aGfxLink.GetType() )
648 case( GFX_LINK_TYPE_EPS_BUFFER ): aExtension = ".eps"; break;
649 case( GFX_LINK_TYPE_NATIVE_GIF ): aExtension = ".gif"; break;
650 // #i15508# added BMP type for better exports (checked, works)
651 case( GFX_LINK_TYPE_NATIVE_BMP ): aExtension = ".bmp"; break;
652 case( GFX_LINK_TYPE_NATIVE_JPG ): aExtension = ".jpg"; break;
653 case( GFX_LINK_TYPE_NATIVE_PNG ): aExtension = ".png"; break;
654 case( GFX_LINK_TYPE_NATIVE_TIF ): aExtension = ".tif"; break;
655 case( GFX_LINK_TYPE_NATIVE_WMF ): aExtension = ".wmf"; break;
656 case( GFX_LINK_TYPE_NATIVE_MET ): aExtension = ".met"; break;
657 case( GFX_LINK_TYPE_NATIVE_PCT ): aExtension = ".pct"; break;
658 case( GFX_LINK_TYPE_NATIVE_SVG ):
659 // backward-compat kludge: since no released OOo
660 // version to date can handle svg properly, wrap it up
661 // into an svm. slight catch22 here, since strict ODF
662 // conformance _recommends_ svg - then again, most old
663 // ODF consumers are believed to be OOo
664 if( SvtSaveOptions().GetODFDefaultVersion() <= SvtSaveOptions::ODFVER_012 )
666 bUseGfxLink = false;
667 aExtension = ".svm";
669 else
670 aExtension = ".svg";
671 break;
673 default:
674 aExtension = ".grf";
675 break;
678 else
680 if( aGrfObject.GetType() == GRAPHIC_BITMAP )
682 if( aGrfObject.IsAnimated() )
683 aExtension = ".gif";
684 else
685 aExtension = ".png";
687 else if( aGrfObject.GetType() == GRAPHIC_GDIMETAFILE )
689 // SJ: first check if this metafile is just a eps file, then we will store the eps instead of svm
690 GDIMetaFile& rMtf( (GDIMetaFile&)aGraphic.GetGDIMetaFile() );
691 if ( ImplCheckForEPS( rMtf ) )
692 aExtension = ".eps";
693 else
694 aExtension = ".svm";
698 OUString aURLEntry;
699 const OUString sPictures( "Pictures/" );
701 if ( !rRequestedFileName.isEmpty() )
703 aURLEntry = sPictures;
704 aURLEntry += rRequestedFileName;
705 aURLEntry += aExtension;
707 URLPairVector::const_iterator aIter( maGrfURLs.begin() ), aEnd( maGrfURLs.end() );
708 for ( ; aIter != aEnd; ++aIter )
710 if( aURLEntry == (*aIter).second )
711 break;
713 if ( aIter == aEnd )
714 aStreamName = rRequestedFileName;
717 aStreamName += aExtension;
719 if( mbDirect && !aStreamName.isEmpty() )
720 ImplWriteGraphic( aPictureStorageName, aStreamName, aGraphicObjectId, bUseGfxLink );
722 rURLPair.second = sPictures;
723 rURLPair.second += aStreamName;
725 #if OSL_DEBUG_LEVEL > 0
726 else
728 OStringBuffer sMessage("graphic object with ID '");
729 sMessage.append(aAsciiObjectID).
730 append("' has an unknown type");
731 OSL_ENSURE( false, sMessage.getStr() );
733 #endif
736 maURLSet.insert( aURLString );
740 void SvXMLGraphicHelper::Init( const uno::Reference < embed::XStorage >& rXMLStorage,
741 SvXMLGraphicHelperMode eCreateMode,
742 bool bDirect )
744 mxRootStorage = rXMLStorage;
745 meCreateMode = eCreateMode;
746 mbDirect = meCreateMode != GRAPHICHELPER_MODE_READ || bDirect;
749 SvXMLGraphicHelper* SvXMLGraphicHelper::Create( const uno::Reference < embed::XStorage >& rXMLStorage,
750 SvXMLGraphicHelperMode eCreateMode,
751 bool bDirect )
753 SvXMLGraphicHelper* pThis = new SvXMLGraphicHelper;
755 pThis->acquire();
756 pThis->Init( rXMLStorage, eCreateMode, bDirect );
758 return pThis;
761 SvXMLGraphicHelper* SvXMLGraphicHelper::Create( SvXMLGraphicHelperMode eCreateMode )
763 SvXMLGraphicHelper* pThis = new SvXMLGraphicHelper;
765 pThis->acquire();
766 pThis->Init( NULL, eCreateMode, false );
768 return pThis;
771 void SvXMLGraphicHelper::Destroy( SvXMLGraphicHelper* pSvXMLGraphicHelper )
773 if( pSvXMLGraphicHelper )
775 pSvXMLGraphicHelper->dispose();
776 pSvXMLGraphicHelper->release();
780 // XGraphicObjectResolver
781 OUString SAL_CALL SvXMLGraphicHelper::resolveGraphicObjectURL( const OUString& rURL )
782 throw(uno::RuntimeException, std::exception)
784 ::osl::MutexGuard aGuard( maMutex );
785 const sal_Int32 nIndex = maGrfURLs.size();
787 OUString aURL( rURL );
788 OUString aUserData;
789 OUString aRequestedFileName;
791 sal_Int32 nUser = rURL.indexOf( '?', 0 );
792 if ( nUser >= 0 )
794 aURL = rURL.copy( 0, nUser );
795 nUser++;
796 aUserData = rURL.copy( nUser, rURL.getLength() - nUser );
798 if ( !aUserData.isEmpty() )
800 sal_Int32 nIndex2 = 0;
803 OUString aToken = aUserData.getToken( 0, ';', nIndex2 );
804 sal_Int32 n = aToken.indexOf( '=' );
805 if ( ( n > 0 ) && ( ( n + 1 ) < aToken.getLength() ) )
807 OUString aParam( aToken.copy( 0, n ) );
808 OUString aValue( aToken.copy( n + 1, aToken.getLength() - ( n + 1 ) ) );
810 const OUString sRequestedName( "requestedName" );
811 if ( aParam.match( sRequestedName ) )
812 aRequestedFileName = aValue;
815 while ( nIndex2 >= 0 );
818 maGrfURLs.push_back( ::std::make_pair( aURL, OUString() ) );
819 ImplInsertGraphicURL( aURL, nIndex, aRequestedFileName );
821 return maGrfURLs[ nIndex ].second;
824 // XBinaryStreamResolver
825 Reference< XInputStream > SAL_CALL SvXMLGraphicHelper::getInputStream( const OUString& rURL )
826 throw( RuntimeException, std::exception )
828 Reference< XInputStream > xRet;
829 OUString aPictureStorageName, aGraphicId;
832 if( ( GRAPHICHELPER_MODE_WRITE == meCreateMode ) &&
833 ImplGetStreamNames( rURL, aPictureStorageName, aGraphicId ) )
835 SvXMLGraphicInputStream* pInputStream = new SvXMLGraphicInputStream( aGraphicId );
837 if( pInputStream->Exists() )
838 xRet = pInputStream;
839 else
840 delete pInputStream;
843 return xRet;
846 Reference< XOutputStream > SAL_CALL SvXMLGraphicHelper::createOutputStream()
847 throw( RuntimeException, std::exception )
849 Reference< XOutputStream > xRet;
851 if( GRAPHICHELPER_MODE_READ == meCreateMode )
853 SvXMLGraphicOutputStream* pOutputStream = new SvXMLGraphicOutputStream;
855 if( pOutputStream->Exists() )
856 maGrfStms.push_back( xRet = pOutputStream );
857 else
858 delete pOutputStream;
861 return xRet;
864 OUString SAL_CALL SvXMLGraphicHelper::resolveOutputStream( const Reference< XOutputStream >& rxBinaryStream )
865 throw( RuntimeException, std::exception )
867 OUString aRet;
869 if( ( GRAPHICHELPER_MODE_READ == meCreateMode ) && rxBinaryStream.is() )
871 if( ::std::find( maGrfStms.begin(), maGrfStms.end(), rxBinaryStream ) != maGrfStms.end() )
873 SvXMLGraphicOutputStream* pOStm = static_cast< SvXMLGraphicOutputStream* >( rxBinaryStream.get() );
875 if( pOStm )
877 const GraphicObject& rGrfObj = pOStm->GetGraphicObject();
878 const OUString aId(OStringToOUString(
879 rGrfObj.GetUniqueID(), RTL_TEXTENCODING_ASCII_US));
881 if( !aId.isEmpty() )
883 aRet = XML_GRAPHICOBJECT_URL_BASE;
884 aRet += aId;
890 return aRet;
893 // for instantiation via service manager
894 namespace {
896 namespace impl
898 typedef ::cppu::WeakComponentImplHelper4<
899 lang::XInitialization,
900 document::XGraphicObjectResolver,
901 document::XBinaryStreamResolver,
902 lang::XServiceInfo >
903 SvXMLGraphicImportExportHelper_Base;
904 class MutexContainer
906 public:
907 virtual ~MutexContainer();
909 protected:
910 mutable ::osl::Mutex m_aMutex;
912 MutexContainer::~MutexContainer()
914 } // namespace impl
916 class SvXMLGraphicImportExportHelper :
917 public impl::MutexContainer,
918 public impl::SvXMLGraphicImportExportHelper_Base
920 public:
921 SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode );
923 protected:
924 // is called from WeakComponentImplHelper when XComponent::dispose() was
925 // called from outside
926 virtual void SAL_CALL disposing() SAL_OVERRIDE;
928 // ____ XInitialization ____
929 // one argument is allowed, which is the XStorage
930 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments )
931 throw (Exception,
932 RuntimeException, std::exception) SAL_OVERRIDE;
934 // ____ XGraphicObjectResolver ____
935 virtual OUString SAL_CALL resolveGraphicObjectURL( const OUString& aURL )
936 throw (RuntimeException, std::exception) SAL_OVERRIDE;
938 // ____ XBinaryStreamResolver ____
939 virtual Reference< io::XInputStream > SAL_CALL getInputStream( const OUString& aURL )
940 throw (RuntimeException, std::exception) SAL_OVERRIDE;
941 virtual Reference< io::XOutputStream > SAL_CALL createOutputStream()
942 throw (RuntimeException, std::exception) SAL_OVERRIDE;
943 virtual OUString SAL_CALL resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream )
944 throw (RuntimeException, std::exception) SAL_OVERRIDE;
946 // ____ XServiceInfo ____
947 virtual OUString SAL_CALL getImplementationName()
948 throw (RuntimeException, std::exception) SAL_OVERRIDE;
949 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName )
950 throw (RuntimeException, std::exception) SAL_OVERRIDE;
951 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
952 throw (RuntimeException, std::exception) SAL_OVERRIDE;
954 private:
955 SvXMLGraphicHelperMode m_eGraphicHelperMode;
956 Reference< XGraphicObjectResolver > m_xGraphicObjectResolver;
957 Reference< XBinaryStreamResolver > m_xBinaryStreamResolver;
960 SvXMLGraphicImportExportHelper::SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode ) :
961 impl::SvXMLGraphicImportExportHelper_Base( m_aMutex ),
962 m_eGraphicHelperMode( eMode )
965 void SAL_CALL SvXMLGraphicImportExportHelper::disposing()
967 Reference< XComponent > xComp( m_xGraphicObjectResolver, UNO_QUERY );
968 OSL_ASSERT( xComp.is());
969 if( xComp.is())
970 xComp->dispose();
971 // m_xBinaryStreamResolver is a reference to the same object => don't call
972 // dispose() again
975 // ____ XInitialization ____
976 void SAL_CALL SvXMLGraphicImportExportHelper::initialize(
977 const Sequence< Any >& aArguments )
978 throw (Exception, RuntimeException, std::exception)
980 Reference< embed::XStorage > xStorage;
981 if( aArguments.getLength() > 0 )
982 aArguments[0] >>= xStorage;
984 SvXMLGraphicHelper * pHelper( SvXMLGraphicHelper::Create( xStorage, m_eGraphicHelperMode ));
985 m_xGraphicObjectResolver.set( pHelper );
986 m_xBinaryStreamResolver.set( pHelper );
987 // SvXMLGraphicHelper::Create calls acquire. Since we have two references
988 // now it is safe (and necessary) to undo this acquire
989 pHelper->release();
992 // ____ XGraphicObjectResolver ____
993 OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveGraphicObjectURL( const OUString& aURL )
994 throw (uno::RuntimeException, std::exception)
996 return m_xGraphicObjectResolver->resolveGraphicObjectURL( aURL );
1000 // ____ XBinaryStreamResolver ____
1001 Reference< io::XInputStream > SAL_CALL SvXMLGraphicImportExportHelper::getInputStream( const OUString& aURL )
1002 throw (uno::RuntimeException, std::exception)
1004 return m_xBinaryStreamResolver->getInputStream( aURL );
1006 Reference< io::XOutputStream > SAL_CALL SvXMLGraphicImportExportHelper::createOutputStream()
1007 throw (uno::RuntimeException, std::exception)
1009 return m_xBinaryStreamResolver->createOutputStream();
1011 OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream )
1012 throw (uno::RuntimeException, std::exception)
1014 return m_xBinaryStreamResolver->resolveOutputStream( aBinaryStream );
1017 // ____ XServiceInfo ____
1018 OUString SAL_CALL SvXMLGraphicImportExportHelper::getImplementationName()
1019 throw (uno::RuntimeException, std::exception)
1021 if( m_eGraphicHelperMode == GRAPHICHELPER_MODE_READ )
1022 return OUString("com.sun.star.comp.Svx.GraphicImportHelper");
1023 return OUString("com.sun.star.comp.Svx.GraphicExportHelper");
1026 sal_Bool SAL_CALL SvXMLGraphicImportExportHelper::supportsService( const OUString& ServiceName )
1027 throw (uno::RuntimeException, std::exception)
1029 return cppu::supportsService(this, ServiceName);
1032 Sequence< OUString > SAL_CALL SvXMLGraphicImportExportHelper::getSupportedServiceNames()
1033 throw (uno::RuntimeException, std::exception)
1035 // XGraphicObjectResolver and XBinaryStreamResolver are not part of any service
1036 Sequence< OUString > aSupportedServiceNames( 2 );
1037 aSupportedServiceNames[0] = "com.sun.star.document.GraphicObjectResolver";
1038 aSupportedServiceNames[1] = "com.sun.star.document.BinaryStreamResolver";
1039 return aSupportedServiceNames;
1044 /** Create this with createInstanceWithArguments. service name
1045 "com.sun.star.comp.Svx.GraphicImportHelper", one argument which is the
1046 XStorage. Without arguments no helper class is created. With an empty
1047 argument the helper class is created and initialized like in the CTOR to
1048 SvXMLGraphicHelper that only gets the create mode.
1050 You should call dispose after you no longer need this component.
1052 uses eCreateMode == GRAPHICHELPER_MODE_READ, bDirect == sal_True in
1053 SvXMLGraphicHelper
1055 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
1056 com_sun_star_comp_Svx_GraphicImportHelper_get_implementation(
1057 css::uno::XComponentContext *,
1058 css::uno::Sequence<css::uno::Any> const &)
1060 return cppu::acquire(new SvXMLGraphicImportExportHelper(GRAPHICHELPER_MODE_READ));
1063 /** Create this with createInstanceWithArguments. service name
1064 "com.sun.star.comp.Svx.GraphicExportHelper", one argument which is the
1065 XStorage. Without arguments no helper class is created. With an empty
1066 argument the helper class is created and initialized like in the CTOR to
1067 SvXMLGraphicHelper that only gets the create mode
1069 To write the Pictures stream, you have to call dispose at this component.
1070 Make sure you call dipose before you commit the parent storage.
1072 uses eCreateMode == GRAPHICHELPER_MODE_WRITE, bDirect == sal_True in
1073 SvXMLGraphicHelper
1075 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
1076 com_sun_star_comp_Svx_GraphicExportHelper_get_implementation(
1077 css::uno::XComponentContext *,
1078 css::uno::Sequence<css::uno::Any> const &)
1080 return cppu::acquire(new SvXMLGraphicImportExportHelper(GRAPHICHELPER_MODE_WRITE));
1083 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */