fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / filter / source / flash / swffilter.cxx
blob4d0ace89759d2db4b8552426abb0d4825bbadc51
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 <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"
39 #include <string.h>
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;
55 namespace swf {
57 typedef ::cppu::WeakImplHelper1<com::sun::star::io::XOutputStream> OslOutputStreamWrapper_Base;
58 // needed for some compilers
59 class OslOutputStreamWrapper : public OslOutputStreamWrapper_Base
61 osl::File mrFile;
63 public:
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);
87 switch( eRC )
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
102 default: break;
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();
118 switch( eRC )
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
128 default: break;
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;
146 public:
147 FlashExportFilter( const Reference< XComponentContext > &rxContext);
149 // XFilter
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);
157 // XExporter
158 virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) throw(IllegalArgumentException, RuntimeException);
160 // XInitialization
161 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException);
163 // XServiceInfo
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 )
194 return STR("NULL");
195 else
196 return STR("slide") + VAL(nCached+1) + STR(suffix) + STR(".swf");
199 return filename;
202 template <typename TYPE>
203 TYPE findPropertyValue(const Sequence< PropertyValue >& aPropertySequence, const sal_Char* name, TYPE def)
205 TYPE temp = TYPE();
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;
215 return temp;
219 return def;
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);
234 else
236 ExportAsSingleFile(aDescriptor);
239 if( mxStatusIndicator.is() )
240 mxStatusIndicator->end();
242 return sal_True;
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())
259 return sal_False;
261 Reference< XIndexAccess > xDrawPages( xDrawPagesSupplier->getDrawPages(), UNO_QUERY );
262 if(!xDrawPages.is())
263 return sal_False;
265 Reference< XDesktop2 > rDesktop = Desktop::create( mxContext );
267 Reference< XStorable > xStorable(rDesktop->getCurrentComponent(), UNO_QUERY);
268 if (!xStorable.is())
269 return sal_False;
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);
300 else
301 sPresentationName = sPresentation.copy(lastslash, lastdot - lastslash);
303 OUString fullpath, swfdirpath, backgroundfilename, objectsfilename;
305 swfdirpath = sPath + STR("/") + sPresentationName + STR(".sxi-swf-files");
307 oslFileError err;
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
315 // screw it up.
316 sal_Bool bExportAll = findPropertyValue<sal_Bool>(aFilterData, "ExportAll", true);
317 if (bExportAll)
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
327 (void) err;
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)
344 continue;
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();
366 if (!ret)
367 osl_removeFile(fullpath.pData);
370 // AS: Write out to the background config what backgrounds and objects this
371 // slide used.
372 if (bExportAll)
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);
384 #ifdef AUGUSTUS
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();
398 if (!ret)
399 osl_removeFile(fullpath.pData);
401 #endif // defined AUGUSTUS
404 if (bExportAll)
405 osl_closeFile(xBackgroundConfig);
407 return sal_True;
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() )
417 OSL_ASSERT ( 0 );
418 return sal_False;
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 // -----------------------------------------------------------------------------
436 // XExporter
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)
440 mxDoc = xDoc;
443 // -----------------------------------------------------------------------------
445 // XInitialization
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 );
477 return aRet;
479 #undef SERVICE_NAME
481 // -----------------------------------------------------------------------------
483 Reference< XInterface > SAL_CALL FlashExportFilter_createInstance( const Reference< XMultiServiceFactory > & rSMgr)
484 throw( Exception )
486 return (cppu::OWeakObject*) new FlashExportFilter( comphelper::getComponentContext(rSMgr) );
489 // -----------------------------------------------------------------------------
491 // XServiceInfo
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: */