1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <com/sun/star/frame/Desktop.hpp>
21 #include <com/sun/star/frame/XStorable.hpp>
22 #include <com/sun/star/document/XFilter.hpp>
23 #include <com/sun/star/document/XExporter.hpp>
24 #include <com/sun/star/lang/XInitialization.hpp>
25 #include <com/sun/star/lang/XServiceInfo.hpp>
26 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
27 #include <com/sun/star/drawing/XDrawView.hpp>
28 #include <com/sun/star/container/XIndexAccess.hpp>
29 #include <com/sun/star/frame/XModel.hpp>
30 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
31 #include <com/sun/star/io/XOutputStream.hpp>
32 #include <cppuhelper/implbase1.hxx>
33 #include <cppuhelper/implbase4.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <osl/file.hxx>
37 #include "swfexporter.hxx"
41 using namespace ::com::sun::star::uno
;
42 using namespace ::com::sun::star::frame
;
43 using namespace ::com::sun::star::lang
;
44 using namespace ::com::sun::star::drawing
;
45 using namespace ::com::sun::star::presentation
;
46 using namespace ::com::sun::star::task
;
48 using ::com::sun::star::lang::XComponent
;
49 using ::com::sun::star::beans::PropertyValue
;
50 using ::com::sun::star::io::XOutputStream
;
51 using ::com::sun::star::container::XIndexAccess
;
52 using ::osl::FileBase
;
53 using ::com::sun::star::frame::XModel
;
57 typedef ::cppu::WeakImplHelper1
<com::sun::star::io::XOutputStream
> OslOutputStreamWrapper_Base
;
58 // needed for some compilers
59 class OslOutputStreamWrapper
: public OslOutputStreamWrapper_Base
64 OslOutputStreamWrapper(const OUString
& sFileName
) : mrFile(sFileName
)
66 osl_removeFile(sFileName
.pData
);
67 mrFile
.open( osl_File_OpenFlag_Create
|osl_File_OpenFlag_Write
);
70 // stario::XOutputStream
71 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
);
72 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
);
73 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
);
76 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
)
78 sal_uInt64 uBytesToWrite
= aData
.getLength();
79 sal_uInt64 uBytesWritten
= 0;
81 sal_Int8
const * pBuffer
= aData
.getConstArray();
83 while( uBytesToWrite
)
85 osl::File::RC eRC
= mrFile
.write( pBuffer
, uBytesToWrite
, uBytesWritten
);
89 case osl::File::E_INVAL
: // the format of the parameters was not valid
90 case osl::File::E_FBIG
: // File too large
92 case osl::File::E_AGAIN
: // Operation would block
93 case osl::File::E_BADF
: // Bad file
94 case osl::File::E_FAULT
: // Bad address
95 case osl::File::E_INTR
: // function call was interrupted
96 case osl::File::E_IO
: // I/O error
97 case osl::File::E_NOLCK
: // No record locks available
98 case osl::File::E_NOLINK
: // Link has been severed
99 case osl::File::E_NOSPC
: // No space left on device
100 case osl::File::E_NXIO
: // No such device or address
101 throw com::sun::star::io::IOException(); // TODO: Better error handling
105 uBytesToWrite
-= uBytesWritten
;
106 pBuffer
+= uBytesWritten
;
110 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
)
114 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
)
116 osl::File::RC eRC
= mrFile
.close();
120 case osl::File::E_INVAL
: // the format of the parameters was not valid
122 case osl::File::E_BADF
: // Bad file
123 case osl::File::E_INTR
: // function call was interrupted
124 case osl::File::E_NOLINK
: // Link has been severed
125 case osl::File::E_NOSPC
: // No space left on device
126 case osl::File::E_IO
: // I/O error
127 throw com::sun::star::io::IOException(); // TODO: Better error handling
132 // -----------------------------------------------------------------------------
134 class FlashExportFilter
: public cppu::WeakImplHelper4
136 com::sun::star::document::XFilter
,
137 com::sun::star::document::XExporter
,
138 com::sun::star::lang::XInitialization
,
139 com::sun::star::lang::XServiceInfo
142 Reference
< XComponent
> mxDoc
;
143 Reference
< XComponentContext
> mxContext
;
144 Reference
< XStatusIndicator
> mxStatusIndicator
;
147 FlashExportFilter( const Reference
< XComponentContext
> &rxContext
);
150 virtual sal_Bool SAL_CALL
filter( const Sequence
< PropertyValue
>& aDescriptor
) throw(RuntimeException
);
152 sal_Bool
ExportAsMultipleFiles( const Sequence
< PropertyValue
>& aDescriptor
);
153 sal_Bool
ExportAsSingleFile( const Sequence
< PropertyValue
>& aDescriptor
);
155 virtual void SAL_CALL
cancel( ) throw (RuntimeException
);
158 virtual void SAL_CALL
setSourceDocument( const Reference
< XComponent
>& xDoc
) throw(IllegalArgumentException
, RuntimeException
);
161 virtual void SAL_CALL
initialize( const Sequence
< Any
>& aArguments
) throw(Exception
, RuntimeException
);
164 virtual OUString SAL_CALL
getImplementationName() throw(RuntimeException
);
165 virtual sal_Bool SAL_CALL
supportsService( const OUString
& ServiceName
) throw(RuntimeException
);
166 virtual Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() throw(RuntimeException
);
169 // -----------------------------------------------------------------------------
171 FlashExportFilter::FlashExportFilter(const Reference
< XComponentContext
> &rxContext
)
172 : mxContext( rxContext
)
177 // -----------------------------------------------------------------------------
179 OUString
exportBackground(FlashExporter
&aFlashExporter
, Reference
< XDrawPage
> xDrawPage
, OUString sPath
, sal_uInt32 nPage
, const char* suffix
)
181 OUString filename
= STR("slide") + VAL(nPage
+1) + STR(suffix
) + STR(".swf");
182 OUString fullpath
= sPath
+ STR("/") + filename
;
184 // AS: If suffix is "o" then the last paramter is true (for exporting objects).
185 Reference
<XOutputStream
> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath
)), UNO_QUERY
);
186 sal_uInt16 nCached
= aFlashExporter
.exportBackgrounds( xDrawPage
, xOutputStreamWrap
, sal::static_int_cast
<sal_uInt16
>( nPage
), *suffix
== 'o' );
187 aFlashExporter
.Flush();
188 xOutputStreamWrap
.clear();
190 if (nCached
!= nPage
)
192 osl_removeFile(fullpath
.pData
);
193 if ( 0xffff == nCached
)
196 return STR("slide") + VAL(nCached
+1) + STR(suffix
) + STR(".swf");
202 template <typename TYPE
>
203 TYPE
findPropertyValue(const Sequence
< PropertyValue
>& aPropertySequence
, const sal_Char
* name
, TYPE def
)
207 sal_Int32 nLength
= aPropertySequence
.getLength();
208 const PropertyValue
* pValue
= aPropertySequence
.getConstArray();
210 for ( sal_Int32 i
= 0 ; i
< nLength
; i
++)
212 if ( pValue
[i
].Name
.equalsAsciiL ( name
, strlen(name
) ) )
214 pValue
[i
].Value
>>= temp
;
222 sal_Bool SAL_CALL
FlashExportFilter::filter( const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& aDescriptor
)
223 throw (RuntimeException
)
225 mxStatusIndicator
= findPropertyValue
<Reference
<XStatusIndicator
> >(aDescriptor
, "StatusIndicator", mxStatusIndicator
);
227 Sequence
< PropertyValue
> aFilterData
;
228 aFilterData
= findPropertyValue
<Sequence
< PropertyValue
> >(aDescriptor
, "FilterData", aFilterData
);
230 if (findPropertyValue
<sal_Bool
>(aFilterData
, "ExportMultipleFiles", false ))
232 ExportAsMultipleFiles(aDescriptor
);
236 ExportAsSingleFile(aDescriptor
);
239 if( mxStatusIndicator
.is() )
240 mxStatusIndicator
->end();
246 // AS: When exporting as multiple files, each background, object layer, and slide gets its own
247 // file. Additionally, a file called BackgroundConfig.txt is generated, indicating which
248 // background and objects (if any) go with each slide. The files are named slideNb.swf,
249 // slideNo.swf, and slideNp.swf, where N is the slide number, and b=background, o=objects, and
250 // p=slide contents. Note that under normal circumstances, there will be very few b and o files.
252 // AS: HACK! Right now, I create a directory as a sibling to the swf file selected in the Export
253 // dialog. This directory is called presentation.sxi-swf-files. The name of the swf file selected
254 // in the Export dialog has no impact on this. All files created are placed in this directory.
255 sal_Bool
FlashExportFilter::ExportAsMultipleFiles(const Sequence
< PropertyValue
>& aDescriptor
)
257 Reference
< XDrawPagesSupplier
> xDrawPagesSupplier(mxDoc
, UNO_QUERY
);
258 if(!xDrawPagesSupplier
.is())
261 Reference
< XIndexAccess
> xDrawPages( xDrawPagesSupplier
->getDrawPages(), UNO_QUERY
);
265 Reference
< XDesktop2
> rDesktop
= Desktop::create( mxContext
);
267 Reference
< XStorable
> xStorable(rDesktop
->getCurrentComponent(), UNO_QUERY
);
271 Reference
< XDrawPage
> xDrawPage
;
273 Reference
< XFrame
> rFrame
= rDesktop
->getCurrentFrame();
274 Reference
< XDrawView
> rDrawView
= Reference
< XDrawView
>( rFrame
->getController(), UNO_QUERY
);
276 Reference
< XDrawPage
> rCurrentPage
= rDrawView
->getCurrentPage();
278 Sequence
< PropertyValue
> aFilterData
;
280 aFilterData
= findPropertyValue
<Sequence
< PropertyValue
> >(aDescriptor
, "FilterData", aFilterData
);
282 //AS: Do a bunch of path mangling to figure out where to put the files.
284 OUString sOriginalPath
= findPropertyValue
<OUString
>(aDescriptor
, "URL", OUString());
286 // AS: sPath is the parent directory, where everything else exists (like the sxi,
287 // the -swf-files folder, the -audio files, etc.
288 sal_Int32 lastslash
= sOriginalPath
.lastIndexOf('/');
289 OUString
sPath( sOriginalPath
.copy(0, lastslash
) );
291 OUString
sPresentation(xStorable
->getLocation());
293 lastslash
= sPresentation
.lastIndexOf('/') + 1;
294 sal_Int32 lastdot
= sPresentation
.lastIndexOf('.');
296 // AS: The name of the presentation, without 3 character extension.
297 OUString sPresentationName
;
298 if (lastdot
< 0) // fdo#71309 in case file has no name
299 sPresentationName
= sPresentation
.copy(lastslash
);
301 sPresentationName
= sPresentation
.copy(lastslash
, lastdot
- lastslash
);
303 OUString fullpath
, swfdirpath
, backgroundfilename
, objectsfilename
;
305 swfdirpath
= sPath
+ STR("/") + sPresentationName
+ STR(".sxi-swf-files");
308 err
= osl_createDirectory( swfdirpath
.pData
);
310 fullpath
= swfdirpath
+ STR("/backgroundconfig.txt");
312 oslFileHandle
xBackgroundConfig( 0 );
314 // AS: Only export the background config if we're exporting all of the pages, otherwise we'll
316 sal_Bool bExportAll
= findPropertyValue
<sal_Bool
>(aFilterData
, "ExportAll", true);
319 osl_removeFile(fullpath
.pData
);
320 osl_openFile( fullpath
.pData
, &xBackgroundConfig
, osl_File_OpenFlag_Create
| osl_File_OpenFlag_Write
);
322 sal_uInt64 bytesWritten
;
323 err
= osl_writeFile(xBackgroundConfig
, "slides=", strlen("slides="), &bytesWritten
);
326 // TODO: check for errors
329 FlashExporter
aFlashExporter( mxContext
, findPropertyValue
<sal_Int32
>(aFilterData
, "CompressMode", 75),
330 findPropertyValue
<sal_Bool
>(aFilterData
, "ExportOLEAsJPEG", false));
332 const sal_Int32 nPageCount
= xDrawPages
->getCount();
333 if ( mxStatusIndicator
.is() )
334 mxStatusIndicator
->start( "Saving :", nPageCount
);
336 for(sal_Int32 nPage
= 0; nPage
< nPageCount
; nPage
++)
338 if ( mxStatusIndicator
.is() )
339 mxStatusIndicator
->setValue( nPage
);
340 xDrawPages
->getByIndex(nPage
) >>= xDrawPage
;
342 // AS: If we're only exporting the current page, then skip the rest.
343 if (!bExportAll
&& xDrawPage
!= rCurrentPage
)
346 // AS: Export the background, the background objects, and then the slide contents.
347 if (bExportAll
|| findPropertyValue
<sal_Bool
>(aFilterData
, "ExportBackgrounds", true))
349 backgroundfilename
= exportBackground(aFlashExporter
, xDrawPage
, swfdirpath
, nPage
, "b");
352 if (bExportAll
|| findPropertyValue
<sal_Bool
>(aFilterData
, "ExportBackgroundObjects", true))
354 objectsfilename
= exportBackground(aFlashExporter
, xDrawPage
, swfdirpath
, nPage
, "o");
357 if (bExportAll
|| findPropertyValue
<sal_Bool
>(aFilterData
, "ExportSlideContents", true))
359 fullpath
= swfdirpath
+ STR("/slide") + VAL(nPage
+1) + STR("p.swf");
361 Reference
<XOutputStream
> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath
)), UNO_QUERY
);
362 sal_Bool ret
= aFlashExporter
.exportSlides( xDrawPage
, xOutputStreamWrap
, sal::static_int_cast
<sal_uInt16
>( nPage
) );
363 aFlashExporter
.Flush();
364 xOutputStreamWrap
.clear();
367 osl_removeFile(fullpath
.pData
);
370 // AS: Write out to the background config what backgrounds and objects this
374 OUString temp
= backgroundfilename
+ STR("|") + objectsfilename
;
375 OString
ASCIItemp(temp
.getStr(), temp
.getLength(), RTL_TEXTENCODING_ASCII_US
);
377 sal_uInt64 bytesWritten
;
378 osl_writeFile(xBackgroundConfig
, ASCIItemp
.getStr(), ASCIItemp
.getLength(), &bytesWritten
);
380 if (nPage
< nPageCount
- 1)
381 osl_writeFile(xBackgroundConfig
, "|", 1, &bytesWritten
);
385 if (findPropertyValue
<sal_Bool
>(aFilterData
, "ExportSound", true))
387 fullpath
= swfdirpath
+ STR("/slide") + VAL(nPage
+1) + STR("s.swf");
389 OUString wavpath
= sPath
+ STR("/") + sPresentationName
+ STR(".ppt-audio/slide") + VAL(nPage
+1) + STR(".wav");
390 FileBase::getSystemPathFromFileURL(wavpath
, wavpath
);
391 OString
sASCIIPath(wavpath
.getStr(), wavpath
.getLength(), RTL_TEXTENCODING_ASCII_US
);
393 Reference
<XOutputStream
> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath
)), UNO_QUERY
);
394 sal_Bool ret
= aFlashExporter
.exportSound(xOutputStreamWrap
, sASCIIPath
.getStr());
395 aFlashExporter
.Flush();
396 xOutputStreamWrap
.clear();
399 osl_removeFile(fullpath
.pData
);
401 #endif // defined AUGUSTUS
405 osl_closeFile(xBackgroundConfig
);
410 sal_Bool
FlashExportFilter::ExportAsSingleFile(const Sequence
< PropertyValue
>& aDescriptor
)
412 Reference
< XOutputStream
> xOutputStream
= findPropertyValue
<Reference
<XOutputStream
> >(aDescriptor
, "OutputStream", 0);
413 Sequence
< PropertyValue
> aFilterData
;
415 if (!xOutputStream
.is() )
421 FlashExporter
aFlashExporter( mxContext
, findPropertyValue
<sal_Int32
>(aFilterData
, "CompressMode", 75),
422 findPropertyValue
<sal_Bool
>(aFilterData
, "ExportOLEAsJPEG", false));
424 return aFlashExporter
.exportAll( mxDoc
, xOutputStream
, mxStatusIndicator
);
427 // -----------------------------------------------------------------------------
429 void SAL_CALL
FlashExportFilter::cancel( )
430 throw (RuntimeException
)
434 // -----------------------------------------------------------------------------
437 void SAL_CALL
FlashExportFilter::setSourceDocument( const ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XComponent
>& xDoc
)
438 throw (::com::sun::star::lang::IllegalArgumentException
, RuntimeException
)
443 // -----------------------------------------------------------------------------
446 void SAL_CALL
FlashExportFilter::initialize( const ::com::sun::star::uno::Sequence
< ::com::sun::star::uno::Any
>& /* aArguments */ )
447 throw (Exception
, RuntimeException
)
451 // -----------------------------------------------------------------------------
453 OUString
FlashExportFilter_getImplementationName ()
454 throw (RuntimeException
)
456 return OUString ( "com.sun.star.comp.Impress.FlashExportFilter" );
459 // -----------------------------------------------------------------------------
461 #define SERVICE_NAME "com.sun.star.document.ExportFilter"
463 sal_Bool SAL_CALL
FlashExportFilter_supportsService( const OUString
& ServiceName
)
464 throw (RuntimeException
)
466 return ServiceName
== SERVICE_NAME
;
469 // -----------------------------------------------------------------------------
471 Sequence
< OUString
> SAL_CALL
FlashExportFilter_getSupportedServiceNames( )
472 throw (RuntimeException
)
474 Sequence
< OUString
> aRet(1);
475 OUString
* pArray
= aRet
.getArray();
476 pArray
[0] = OUString ( SERVICE_NAME
);
481 // -----------------------------------------------------------------------------
483 Reference
< XInterface
> SAL_CALL
FlashExportFilter_createInstance( const Reference
< XMultiServiceFactory
> & rSMgr
)
486 return (cppu::OWeakObject
*) new FlashExportFilter( comphelper::getComponentContext(rSMgr
) );
489 // -----------------------------------------------------------------------------
492 OUString SAL_CALL
FlashExportFilter::getImplementationName( )
493 throw (RuntimeException
)
495 return FlashExportFilter_getImplementationName();
498 // -----------------------------------------------------------------------------
500 sal_Bool SAL_CALL
FlashExportFilter::supportsService( const OUString
& rServiceName
)
501 throw (RuntimeException
)
503 return FlashExportFilter_supportsService( rServiceName
);
506 // -----------------------------------------------------------------------------
508 ::com::sun::star::uno::Sequence
< OUString
> SAL_CALL
FlashExportFilter::getSupportedServiceNames( )
509 throw (RuntimeException
)
511 return FlashExportFilter_getSupportedServiceNames();
514 // -----------------------------------------------------------------------------
518 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */