1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: swffilter.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_filter.hxx"
33 #include <com/sun/star/frame/XDesktop.hpp>
34 #include <com/sun/star/frame/XStorable.hpp>
35 #include <com/sun/star/document/XFilter.hpp>
36 #include <com/sun/star/document/XExporter.hpp>
37 #include <com/sun/star/lang/XInitialization.hpp>
38 #include <com/sun/star/lang/XServiceInfo.hpp>
39 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
40 #include <com/sun/star/drawing/XDrawView.hpp>
41 #include <com/sun/star/container/XIndexAccess.hpp>
42 #include <com/sun/star/frame/XModel.hpp>
43 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
44 #include <com/sun/star/io/XOutputStream.hpp>
45 #include <cppuhelper/implbase1.hxx>
46 #include <cppuhelper/implbase4.hxx>
47 #include <osl/file.hxx>
49 #include "swfexporter.hxx"
52 //#include <windows.h>
55 using namespace ::com::sun::star::uno
;
56 using namespace ::com::sun::star::frame
;
57 using namespace ::com::sun::star::lang
;
58 using namespace ::com::sun::star::drawing
;
59 using namespace ::com::sun::star::presentation
;
60 using namespace ::com::sun::star::task
;
62 using ::rtl::OUString
;
64 using ::com::sun::star::lang::XComponent
;
65 using ::com::sun::star::beans::PropertyValue
;
66 using ::com::sun::star::io::XOutputStream
;
67 using ::com::sun::star::container::XIndexAccess
;
68 using ::osl::FileBase
;
69 using ::com::sun::star::frame::XModel
;
73 typedef ::cppu::WeakImplHelper1
<com::sun::star::io::XOutputStream
> OslOutputStreamWrapper_Base
;
74 // needed for some compilers
75 class OslOutputStreamWrapper
: public OslOutputStreamWrapper_Base
80 OslOutputStreamWrapper(const OUString
& sFileName
) : mrFile(sFileName
)
82 osl_removeFile(sFileName
.pData
);
83 mrFile
.open(OpenFlag_Create
|OpenFlag_Write
);
86 // stario::XOutputStream
87 virtual void SAL_CALL
writeBytes( const ::com::sun::star::uno::Sequence
< sal_Int8
>& aData
) throw (::com::sun::star::io::NotConnectedException
, ::com::sun::star::io::BufferSizeExceededException
, ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
);
88 virtual void SAL_CALL
flush( ) throw (::com::sun::star::io::NotConnectedException
, ::com::sun::star::io::BufferSizeExceededException
, ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
);
89 virtual void SAL_CALL
closeOutput( ) throw (::com::sun::star::io::NotConnectedException
, ::com::sun::star::io::BufferSizeExceededException
, ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
);
92 void SAL_CALL
OslOutputStreamWrapper::writeBytes( const ::com::sun::star::uno::Sequence
< sal_Int8
>& aData
) throw (::com::sun::star::io::NotConnectedException
, ::com::sun::star::io::BufferSizeExceededException
, ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
)
94 sal_uInt64 uBytesToWrite
= aData
.getLength();
95 sal_uInt64 uBytesWritten
= 0;
97 sal_Int8
const * pBuffer
= aData
.getConstArray();
99 while( uBytesToWrite
)
101 osl::File::RC eRC
= mrFile
.write( pBuffer
, uBytesToWrite
, uBytesWritten
);
105 case osl::File::E_INVAL
: // the format of the parameters was not valid
106 case osl::File::E_FBIG
: // File too large
108 case osl::File::E_AGAIN
: // Operation would block
109 case osl::File::E_BADF
: // Bad file
110 case osl::File::E_FAULT
: // Bad address
111 case osl::File::E_INTR
: // function call was interrupted
112 case osl::File::E_IO
: // I/O error
113 case osl::File::E_NOLCK
: // No record locks available
114 case osl::File::E_NOLINK
: // Link has been severed
115 case osl::File::E_NOSPC
: // No space left on device
116 case osl::File::E_NXIO
: // No such device or address
117 throw com::sun::star::io::IOException(); // TODO: Better error handling
121 uBytesToWrite
-= uBytesWritten
;
122 pBuffer
+= uBytesWritten
;
126 void SAL_CALL
OslOutputStreamWrapper::flush( ) throw (::com::sun::star::io::NotConnectedException
, ::com::sun::star::io::BufferSizeExceededException
, ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
)
130 void SAL_CALL
OslOutputStreamWrapper::closeOutput( ) throw (::com::sun::star::io::NotConnectedException
, ::com::sun::star::io::BufferSizeExceededException
, ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
)
132 osl::File::RC eRC
= mrFile
.close();
136 case osl::File::E_INVAL
: // the format of the parameters was not valid
138 case osl::File::E_BADF
: // Bad file
139 case osl::File::E_INTR
: // function call was interrupted
140 case osl::File::E_NOLINK
: // Link has been severed
141 case osl::File::E_NOSPC
: // No space left on device
142 case osl::File::E_IO
: // I/O error
143 throw com::sun::star::io::IOException(); // TODO: Better error handling
148 // -----------------------------------------------------------------------------
150 class FlashExportFilter
: public cppu::WeakImplHelper4
152 com::sun::star::document::XFilter
,
153 com::sun::star::document::XExporter
,
154 com::sun::star::lang::XInitialization
,
155 com::sun::star::lang::XServiceInfo
158 Reference
< XComponent
> mxDoc
;
159 Reference
< XMultiServiceFactory
> mxMSF
;
160 Reference
< XStatusIndicator
> mxStatusIndicator
;
165 FlashExportFilter( const Reference
< XMultiServiceFactory
> &rxMSF
);
168 virtual sal_Bool SAL_CALL
filter( const Sequence
< PropertyValue
>& aDescriptor
) throw(RuntimeException
);
170 sal_Bool
ExportAsMultipleFiles( const Sequence
< PropertyValue
>& aDescriptor
);
171 sal_Bool
ExportAsSingleFile( const Sequence
< PropertyValue
>& aDescriptor
);
173 virtual void SAL_CALL
cancel( ) throw (RuntimeException
);
176 virtual void SAL_CALL
setSourceDocument( const Reference
< XComponent
>& xDoc
) throw(IllegalArgumentException
, RuntimeException
);
179 virtual void SAL_CALL
initialize( const Sequence
< Any
>& aArguments
) throw(Exception
, RuntimeException
);
182 virtual OUString SAL_CALL
getImplementationName() throw(RuntimeException
);
183 virtual sal_Bool SAL_CALL
supportsService( const OUString
& ServiceName
) throw(RuntimeException
);
184 virtual Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() throw(RuntimeException
);
187 // -----------------------------------------------------------------------------
189 FlashExportFilter::FlashExportFilter(const Reference
< XMultiServiceFactory
> &rxMSF
)
195 // -----------------------------------------------------------------------------
197 OUString
exportBackground(FlashExporter
&aFlashExporter
, Reference
< XDrawPage
> xDrawPage
, OUString sPath
, sal_uInt32 nPage
, const char* suffix
)
199 OUString filename
= STR("slide") + VAL(nPage
+1) + STR(suffix
) + STR(".swf");
200 OUString fullpath
= sPath
+ STR("/") + filename
;
202 // AS: If suffix is "o" then the last paramter is true (for exporting objects).
203 Reference
<XOutputStream
> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath
)), UNO_QUERY
);
204 sal_uInt16 nCached
= aFlashExporter
.exportBackgrounds( xDrawPage
, xOutputStreamWrap
, sal::static_int_cast
<sal_uInt16
>( nPage
), *suffix
== 'o' );
205 aFlashExporter
.Flush();
206 xOutputStreamWrap
.clear();
208 if (nCached
!= nPage
)
210 osl_removeFile(fullpath
.pData
);
211 if ( 0xffff == nCached
)
214 return STR("slide") + VAL(nCached
+1) + STR(suffix
) + STR(".swf");
220 template <typename TYPE
>
221 TYPE
findPropertyValue(const Sequence
< PropertyValue
>& aPropertySequence
, const sal_Char
* name
, TYPE def
)
225 sal_Int32 nLength
= aPropertySequence
.getLength();
226 const PropertyValue
* pValue
= aPropertySequence
.getConstArray();
228 for ( sal_Int32 i
= 0 ; i
< nLength
; i
++)
230 if ( pValue
[i
].Name
.equalsAsciiL ( name
, strlen(name
) ) )
232 pValue
[i
].Value
>>= temp
;
240 sal_Bool SAL_CALL
FlashExportFilter::filter( const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& aDescriptor
)
241 throw (RuntimeException
)
243 mxStatusIndicator
= findPropertyValue
<Reference
<XStatusIndicator
> >(aDescriptor
, "StatusIndicator", mxStatusIndicator
);
245 Sequence
< PropertyValue
> aFilterData
;
246 aFilterData
= findPropertyValue
<Sequence
< PropertyValue
> >(aDescriptor
, "FilterData", aFilterData
);
248 if (findPropertyValue
<sal_Bool
>(aFilterData
, "ExportMultipleFiles", false ))
250 ExportAsMultipleFiles(aDescriptor
);
254 ExportAsSingleFile(aDescriptor
);
257 if( mxStatusIndicator
.is() )
258 mxStatusIndicator
->end();
264 // AS: When exporting as multiple files, each background, object layer, and slide gets its own
265 // file. Additionally, a file called BackgroundConfig.txt is generated, indicating which
266 // background and objects (if any) go with each slide. The files are named slideNb.swf,
267 // slideNo.swf, and slideNp.swf, where N is the slide number, and b=background, o=objects, and
268 // p=slide contents. Note that under normal circumstances, there will be very few b and o files.
270 // AS: HACK! Right now, I create a directory as a sibling to the swf file selected in the Export
271 // dialog. This directory is called presentation.sxi-swf-files. The name of the swf file selected
272 // in the Export dialog has no impact on this. All files created are placed in this directory.
273 sal_Bool
FlashExportFilter::ExportAsMultipleFiles(const Sequence
< PropertyValue
>& aDescriptor
)
275 Reference
< XDrawPagesSupplier
> xDrawPagesSupplier(mxDoc
, UNO_QUERY
);
276 if(!xDrawPagesSupplier
.is())
279 Reference
< XIndexAccess
> xDrawPages( xDrawPagesSupplier
->getDrawPages(), UNO_QUERY
);
283 Reference
< XDesktop
> rDesktop( mxMSF
->createInstance(OUString::createFromAscii("com.sun.star.frame.Desktop")), UNO_QUERY
);
287 Reference
< XStorable
> xStorable(rDesktop
->getCurrentComponent(), UNO_QUERY
);
291 Reference
< XDrawPage
> xDrawPage
;
293 Reference
< XFrame
> rFrame
= rDesktop
->getCurrentFrame();
294 Reference
< XDrawView
> rDrawView
= Reference
< XDrawView
>( rFrame
->getController(), UNO_QUERY
);
296 Reference
< XDrawPage
> rCurrentPage
= rDrawView
->getCurrentPage();
298 Sequence
< PropertyValue
> aFilterData
;
300 aFilterData
= findPropertyValue
<Sequence
< PropertyValue
> >(aDescriptor
, "FilterData", aFilterData
);
302 //AS: Do a bunch of path mangling to figure out where to put the files.
304 OUString sOriginalPath
= findPropertyValue
<OUString
>(aDescriptor
, "URL", OUString());
306 // AS: sPath is the parent directory, where everything else exists (like the sxi,
307 // the -swf-files folder, the -audio files, etc.
308 int lastslash
= sOriginalPath
.lastIndexOf('/');
309 OUString
sPath( sOriginalPath
.copy(0, lastslash
) );
311 OUString
sPresentation(xStorable
->getLocation());
313 lastslash
= sPresentation
.lastIndexOf('/') + 1;
314 int lastdot
= sPresentation
.lastIndexOf('.');
316 // AS: The name of the presentation, without 3 character extension.
317 OUString sPresentationName
= sPresentation
.copy(lastslash
, lastdot
- lastslash
);
319 OUString fullpath
, swfdirpath
, backgroundfilename
, objectsfilename
;
321 swfdirpath
= sPath
+ STR("/") + sPresentationName
+ STR(".sxi-swf-files");
324 err
= osl_createDirectory( swfdirpath
.pData
);
326 fullpath
= swfdirpath
+ STR("/backgroundconfig.txt");
328 oslFileHandle
xBackgroundConfig( 0 );
330 // AS: Only export the background config if we're exporting all of the pages, otherwise we'll
332 sal_Bool bExportAll
= findPropertyValue
<sal_Bool
>(aFilterData
, "ExportAll", true);
335 osl_removeFile(fullpath
.pData
);
336 osl_openFile( fullpath
.pData
, &xBackgroundConfig
, osl_File_OpenFlag_Create
| osl_File_OpenFlag_Write
);
338 sal_uInt64 bytesWritten
;
339 err
= osl_writeFile(xBackgroundConfig
, "slides=", strlen("slides="), &bytesWritten
);
342 FlashExporter
aFlashExporter( mxMSF
, findPropertyValue
<sal_Int32
>(aFilterData
, "CompressMode", 75),
343 findPropertyValue
<sal_Bool
>(aFilterData
, "ExportOLEAsJPEG", false));
345 const sal_Int32 nPageCount
= xDrawPages
->getCount();
346 if ( mxStatusIndicator
.is() )
347 mxStatusIndicator
->start(OUString( RTL_CONSTASCII_USTRINGPARAM( "Saving :" )), nPageCount
);
349 for(sal_Int32 nPage
= 0; nPage
< nPageCount
; nPage
++)
351 if ( mxStatusIndicator
.is() )
352 mxStatusIndicator
->setValue( nPage
);
353 xDrawPages
->getByIndex(nPage
) >>= xDrawPage
;
355 // AS: If we're only exporting the current page, then skip the rest.
356 if (!bExportAll
&& xDrawPage
!= rCurrentPage
)
359 // AS: Export the background, the background objects, and then the slide contents.
360 if (bExportAll
|| findPropertyValue
<sal_Bool
>(aFilterData
, "ExportBackgrounds", true))
362 backgroundfilename
= exportBackground(aFlashExporter
, xDrawPage
, swfdirpath
, nPage
, "b");
365 if (bExportAll
|| findPropertyValue
<sal_Bool
>(aFilterData
, "ExportBackgroundObjects", true))
367 objectsfilename
= exportBackground(aFlashExporter
, xDrawPage
, swfdirpath
, nPage
, "o");
370 if (bExportAll
|| findPropertyValue
<sal_Bool
>(aFilterData
, "ExportSlideContents", true))
372 fullpath
= swfdirpath
+ STR("/slide") + VAL(nPage
+1) + STR("p.swf");
374 Reference
<XOutputStream
> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath
)), UNO_QUERY
);
375 sal_Bool ret
= aFlashExporter
.exportSlides( xDrawPage
, xOutputStreamWrap
, sal::static_int_cast
<sal_uInt16
>( nPage
) );
376 aFlashExporter
.Flush();
377 xOutputStreamWrap
.clear();
380 osl_removeFile(fullpath
.pData
);
383 // AS: Write out to the background config what backgrounds and objects this
387 OUString temp
= backgroundfilename
+ STR("|") + objectsfilename
;
388 OString
ASCIItemp(temp
.getStr(), temp
.getLength(), RTL_TEXTENCODING_ASCII_US
);
390 sal_uInt64 bytesWritten
;
391 osl_writeFile(xBackgroundConfig
, ASCIItemp
.getStr(), ASCIItemp
.getLength(), &bytesWritten
);
393 if (nPage
< nPageCount
- 1)
394 osl_writeFile(xBackgroundConfig
, "|", 1, &bytesWritten
);
398 if (findPropertyValue
<sal_Bool
>(aFilterData
, "ExportSound", true))
400 fullpath
= swfdirpath
+ STR("/slide") + VAL(nPage
+1) + STR("s.swf");
402 OUString wavpath
= sPath
+ STR("/") + sPresentationName
+ STR(".ppt-audio/slide") + VAL(nPage
+1) + STR(".wav");
403 FileBase::getSystemPathFromFileURL(wavpath
, wavpath
);
404 OString
sASCIIPath(wavpath
.getStr(), wavpath
.getLength(), RTL_TEXTENCODING_ASCII_US
);
406 Reference
<XOutputStream
> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath
)), UNO_QUERY
);
407 sal_Bool ret
= aFlashExporter
.exportSound(xOutputStreamWrap
, sASCIIPath
.getStr());
408 aFlashExporter
.Flush();
409 xOutputStreamWrap
.clear();
412 osl_removeFile(fullpath
.pData
);
414 #endif // defined AUGUSTUS
418 osl_closeFile(xBackgroundConfig
);
423 sal_Bool
FlashExportFilter::ExportAsSingleFile(const Sequence
< PropertyValue
>& aDescriptor
)
425 Reference
< XOutputStream
> xOutputStream
= findPropertyValue
<Reference
<XOutputStream
> >(aDescriptor
, "OutputStream", 0);
426 Sequence
< PropertyValue
> aFilterData
;
428 if (!xOutputStream
.is() )
434 FlashExporter
aFlashExporter( mxMSF
, findPropertyValue
<sal_Int32
>(aFilterData
, "CompressMode", 75),
435 findPropertyValue
<sal_Bool
>(aFilterData
, "ExportOLEAsJPEG", false));
437 return aFlashExporter
.exportAll( mxDoc
, xOutputStream
, mxStatusIndicator
);
440 // -----------------------------------------------------------------------------
442 void SAL_CALL
FlashExportFilter::cancel( )
443 throw (RuntimeException
)
447 // -----------------------------------------------------------------------------
450 void SAL_CALL
FlashExportFilter::setSourceDocument( const ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XComponent
>& xDoc
)
451 throw (::com::sun::star::lang::IllegalArgumentException
, RuntimeException
)
456 // -----------------------------------------------------------------------------
459 void SAL_CALL
FlashExportFilter::initialize( const ::com::sun::star::uno::Sequence
< ::com::sun::star::uno::Any
>& /* aArguments */ )
460 throw (Exception
, RuntimeException
)
464 // -----------------------------------------------------------------------------
466 OUString
FlashExportFilter_getImplementationName ()
467 throw (RuntimeException
)
469 return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Impress.FlashExportFilter" ) );
472 // -----------------------------------------------------------------------------
474 #define SERVICE_NAME "com.sun.star.document.ExportFilter"
476 sal_Bool SAL_CALL
FlashExportFilter_supportsService( const OUString
& ServiceName
)
477 throw (RuntimeException
)
479 return ServiceName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME
) );
482 // -----------------------------------------------------------------------------
484 Sequence
< OUString
> SAL_CALL
FlashExportFilter_getSupportedServiceNames( )
485 throw (RuntimeException
)
487 Sequence
< OUString
> aRet(1);
488 OUString
* pArray
= aRet
.getArray();
489 pArray
[0] = OUString ( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME
) );
494 // -----------------------------------------------------------------------------
496 Reference
< XInterface
> SAL_CALL
FlashExportFilter_createInstance( const Reference
< XMultiServiceFactory
> & rSMgr
)
499 return (cppu::OWeakObject
*) new FlashExportFilter( rSMgr
);
502 // -----------------------------------------------------------------------------
505 OUString SAL_CALL
FlashExportFilter::getImplementationName( )
506 throw (RuntimeException
)
508 return FlashExportFilter_getImplementationName();
511 // -----------------------------------------------------------------------------
513 sal_Bool SAL_CALL
FlashExportFilter::supportsService( const OUString
& rServiceName
)
514 throw (RuntimeException
)
516 return FlashExportFilter_supportsService( rServiceName
);
519 // -----------------------------------------------------------------------------
521 ::com::sun::star::uno::Sequence
< OUString
> SAL_CALL
FlashExportFilter::getSupportedServiceNames( )
522 throw (RuntimeException
)
524 return FlashExportFilter_getSupportedServiceNames();
527 // -----------------------------------------------------------------------------