Bump version to 6.4-15
[LibreOffice.git] / filter / source / flash / swffilter.cxx
blobeac3e9385ad96acaa6b57dd42e2477d2a52cf43a
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/task/XStatusIndicatorFactory.hpp>
30 #include <com/sun/star/io/IOException.hpp>
31 #include <com/sun/star/io/XOutputStream.hpp>
33 #include <com/sun/star/drawing/XDrawPage.hpp>
34 #include <com/sun/star/drawing/XShapes.hpp>
35 #include <com/sun/star/frame/XController.hpp>
36 #include <com/sun/star/view/XSelectionSupplier.hpp>
38 #include <cppuhelper/implbase.hxx>
39 #include <cppuhelper/supportsservice.hxx>
40 #include <comphelper/processfactory.hxx>
41 #include <osl/file.hxx>
43 #include "swfexporter.hxx"
44 #include "swfuno.hxx"
46 #include <string.h>
48 using namespace ::com::sun::star::uno;
49 using namespace ::com::sun::star::frame;
50 using namespace ::com::sun::star::lang;
51 using namespace ::com::sun::star::drawing;
52 using namespace ::com::sun::star::task;
53 using namespace ::com::sun::star::view;
55 using ::com::sun::star::lang::XComponent;
56 using ::com::sun::star::beans::PropertyValue;
57 using ::com::sun::star::io::XOutputStream;
58 using ::com::sun::star::container::XIndexAccess;
60 namespace swf {
62 class OslOutputStreamWrapper : public ::cppu::WeakImplHelper<css::io::XOutputStream>
64 osl::File maFile;
66 public:
67 explicit OslOutputStreamWrapper(const OUString& rFileName) : maFile(rFileName)
69 osl_removeFile(rFileName.pData);
70 (void)maFile.open(osl_File_OpenFlag_Create|osl_File_OpenFlag_Write);
73 // css::io::XOutputStream
74 virtual void SAL_CALL writeBytes( const css::uno::Sequence< sal_Int8 >& aData ) override;
75 virtual void SAL_CALL flush( ) override;
76 virtual void SAL_CALL closeOutput( ) override;
79 void SAL_CALL OslOutputStreamWrapper::writeBytes( const css::uno::Sequence< sal_Int8 >& aData )
81 sal_uInt64 uBytesToWrite = aData.getLength();
82 sal_uInt64 uBytesWritten = 0;
84 sal_Int8 const * pBuffer = aData.getConstArray();
86 while( uBytesToWrite )
88 osl::File::RC eRC = maFile.write( pBuffer, uBytesToWrite, uBytesWritten);
90 switch( eRC )
92 case osl::File::E_INVAL: // the format of the parameters was not valid
93 case osl::File::E_FBIG: // File too large
95 case osl::File::E_AGAIN: // Operation would block
96 case osl::File::E_BADF: // Bad file
97 case osl::File::E_FAULT: // Bad address
98 case osl::File::E_INTR: // function call was interrupted
99 case osl::File::E_IO: // I/O error
100 case osl::File::E_NOLCK: // No record locks available
101 case osl::File::E_NOLINK: // Link has been severed
102 case osl::File::E_NOSPC: // No space left on device
103 case osl::File::E_NXIO: // No such device or address
104 throw css::io::IOException(); // TODO: Better error handling
105 default: break;
108 uBytesToWrite -= uBytesWritten;
109 pBuffer += uBytesWritten;
113 void SAL_CALL OslOutputStreamWrapper::flush( )
117 void SAL_CALL OslOutputStreamWrapper::closeOutput( )
119 osl::File::RC eRC = maFile.close();
121 switch( eRC )
123 case osl::File::E_INVAL: // the format of the parameters was not valid
125 case osl::File::E_BADF: // Bad file
126 case osl::File::E_INTR: // function call was interrupted
127 case osl::File::E_NOLINK: // Link has been severed
128 case osl::File::E_NOSPC: // No space left on device
129 case osl::File::E_IO: // I/O error
130 throw css::io::IOException(); // TODO: Better error handling
131 default: break;
136 class FlashExportFilter : public cppu::WeakImplHelper
138 css::document::XFilter,
139 css::document::XExporter,
140 css::lang::XInitialization,
141 css::lang::XServiceInfo
144 Reference< XComponent > mxDoc;
145 Reference< XComponentContext > mxContext;
146 Reference< XStatusIndicator> mxStatusIndicator;
148 // #i56084# variables for selection export
149 Reference< XShapes > mxSelectedShapes;
150 Reference< XDrawPage > mxSelectedDrawPage;
151 bool mbExportSelection;
153 public:
154 explicit FlashExportFilter( const Reference< XComponentContext > &rxContext);
156 // XFilter
157 virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& aDescriptor ) override;
159 void ExportAsMultipleFiles( const Sequence< PropertyValue >& aDescriptor );
160 void ExportAsSingleFile( const Sequence< PropertyValue >& aDescriptor );
162 virtual void SAL_CALL cancel( ) override;
164 // XExporter
165 virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) override;
167 // XInitialization
168 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
170 // XServiceInfo
171 virtual OUString SAL_CALL getImplementationName() override;
172 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
173 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
176 FlashExportFilter::FlashExportFilter(const Reference< XComponentContext > &rxContext)
177 : mxDoc()
178 , mxContext(rxContext)
179 , mxStatusIndicator()
180 , mxSelectedShapes()
181 , mxSelectedDrawPage()
182 , mbExportSelection(false)
186 static OUString exportBackground(FlashExporter &aFlashExporter, const Reference< XDrawPage >& xDrawPage, const OUString& sPath, sal_uInt32 nPage, const char* suffix)
188 OUString filename = "slide" + OUString::number(nPage+1) + OUString::createFromAscii(suffix) + ".swf";
189 OUString fullpath = sPath + "/" + filename;
191 // AS: If suffix is "o" then the last parameter is true (for exporting objects).
192 Reference<XOutputStream> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath)), UNO_QUERY);
193 sal_uInt16 nCached = aFlashExporter.exportBackgrounds( xDrawPage, xOutputStreamWrap, sal::static_int_cast<sal_uInt16>( nPage ), *suffix == 'o' );
194 aFlashExporter.Flush();
195 xOutputStreamWrap.clear();
197 if (nCached != nPage)
199 osl_removeFile(fullpath.pData);
200 if ( 0xffff == nCached )
201 return "NULL";
202 else
203 return "slide" + OUString::number(nCached+1) + OUString::createFromAscii(suffix) + ".swf";
206 return filename;
209 template <typename TYPE>
210 static TYPE findPropertyValue(const Sequence< PropertyValue >& aPropertySequence, const sal_Char* name, TYPE def)
212 TYPE temp = TYPE();
214 sal_Int32 nLength = aPropertySequence.getLength();
215 const PropertyValue * pValue = aPropertySequence.getConstArray();
217 for ( sal_Int32 i = 0 ; i < nLength; i++)
219 if ( pValue[i].Name.equalsAsciiL ( name, strlen(name) ) )
221 pValue[i].Value >>= temp;
222 return temp;
226 return def;
229 sal_Bool SAL_CALL FlashExportFilter::filter( const css::uno::Sequence< css::beans::PropertyValue >& aDescriptor )
231 mxStatusIndicator = findPropertyValue<Reference<XStatusIndicator> >(aDescriptor, "StatusIndicator", mxStatusIndicator);
233 Sequence< PropertyValue > aFilterData;
234 aFilterData = findPropertyValue<Sequence< PropertyValue > >(aDescriptor, "FilterData", aFilterData);
236 // #i56084# check if selection shall be exported only; if yes, get the selected page and the selection itself
237 if(findPropertyValue<bool>(aDescriptor, "SelectionOnly", false))
239 Reference< XDesktop2 > xDesktop(Desktop::create(mxContext));
241 if(xDesktop.is())
243 Reference< XFrame > xFrame(xDesktop->getCurrentFrame());
245 if(xFrame.is())
247 Reference< XController > xController(xFrame->getController());
249 if(xController.is())
251 Reference< XDrawView > xDrawView(xController, UNO_QUERY);
253 if(xDrawView.is())
255 mxSelectedDrawPage = xDrawView->getCurrentPage();
258 if(mxSelectedDrawPage.is())
260 Reference< XSelectionSupplier > xSelection(xController, UNO_QUERY);
262 if(xSelection.is())
264 xSelection->getSelection() >>= mxSelectedShapes;
272 if(mxSelectedDrawPage.is() && mxSelectedShapes.is() && mxSelectedShapes->getCount())
274 // #i56084# to export selection we need the selected page and the selected shapes.
275 // There must be shapes selected, else fallback to regular export (export all)
276 mbExportSelection = true;
279 // #i56084# no multiple files (suppress) when selection since selection can only export a single page
280 if (!mbExportSelection && findPropertyValue<bool>(aFilterData, "ExportMultipleFiles", false ))
282 ExportAsMultipleFiles(aDescriptor);
284 else
286 ExportAsSingleFile(aDescriptor);
289 if( mxStatusIndicator.is() )
290 mxStatusIndicator->end();
292 return true;
296 // AS: When exporting as multiple files, each background, object layer, and slide gets its own
297 // file. Additionally, a file called BackgroundConfig.txt is generated, indicating which
298 // background and objects (if any) go with each slide. The files are named slideNb.swf,
299 // slideNo.swf, and slideNp.swf, where N is the slide number, and b=background, o=objects, and
300 // p=slide contents. Note that under normal circumstances, there will be very few b and o files.
302 // AS: HACK! Right now, I create a directory as a sibling to the swf file selected in the Export
303 // dialog. This directory is called presentation.sxi-swf-files. The name of the swf file selected
304 // in the Export dialog has no impact on this. All files created are placed in this directory.
305 void FlashExportFilter::ExportAsMultipleFiles(const Sequence< PropertyValue >& aDescriptor)
307 Reference< XDrawPagesSupplier > xDrawPagesSupplier(mxDoc, UNO_QUERY);
308 if(!xDrawPagesSupplier.is())
309 return;
311 Reference< XIndexAccess > xDrawPages = xDrawPagesSupplier->getDrawPages();
312 if(!xDrawPages.is())
313 return;
315 Reference< XDesktop2 > rDesktop = Desktop::create( mxContext );
317 Reference< XStorable > xStorable(rDesktop->getCurrentComponent(), UNO_QUERY);
318 if (!xStorable.is())
319 return;
321 Reference< XDrawPage > xDrawPage;
323 Reference< XFrame > rFrame = rDesktop->getCurrentFrame();
324 Reference< XDrawView > rDrawView( rFrame->getController(), UNO_QUERY );
326 Reference< XDrawPage > rCurrentPage = rDrawView->getCurrentPage();
328 Sequence< PropertyValue > aFilterData;
330 aFilterData = findPropertyValue<Sequence< PropertyValue > >(aDescriptor, "FilterData", aFilterData);
332 //AS: Do a bunch of path mangling to figure out where to put the files.
334 OUString sOriginalPath = findPropertyValue<OUString>(aDescriptor, "URL", OUString());
336 // AS: sPath is the parent directory, where everything else exists (like the sxi,
337 // the -swf-files folder, the -audio files, etc.
338 sal_Int32 lastslash = sOriginalPath.lastIndexOf('/');
339 OUString sPath( sOriginalPath.copy(0, lastslash) );
341 OUString sPresentation(xStorable->getLocation());
343 lastslash = sPresentation.lastIndexOf('/') + 1;
344 sal_Int32 lastdot = sPresentation.lastIndexOf('.');
346 // AS: The name of the presentation, without 3 character extension.
347 OUString sPresentationName;
348 if (lastdot < 0) // fdo#71309 in case file has no name
349 sPresentationName = sPresentation.copy(lastslash);
350 else
351 sPresentationName = sPresentation.copy(lastslash, lastdot - lastslash);
353 OUString fullpath, swfdirpath, backgroundfilename, objectsfilename;
355 swfdirpath = sPath + "/" + sPresentationName + ".sxi-swf-files";
357 osl_createDirectory( swfdirpath.pData );
359 fullpath = swfdirpath + "/backgroundconfig.txt";
361 oslFileHandle aBackgroundConfig( nullptr );
363 // AS: Only export the background config if we're exporting all of the pages, otherwise we'll
364 // screw it up.
365 bool bExportAll = findPropertyValue<bool>(aFilterData, "ExportAll", true);
366 if (bExportAll)
368 osl_removeFile(fullpath.pData);
369 osl_openFile( fullpath.pData, &aBackgroundConfig, osl_File_OpenFlag_Create | osl_File_OpenFlag_Write );
371 sal_uInt64 bytesWritten;
372 osl_writeFile(aBackgroundConfig, "slides=", strlen("slides="), &bytesWritten);
375 // TODO: check for errors
377 FlashExporter aFlashExporter(
378 mxContext,
379 mxSelectedShapes,
380 mxSelectedDrawPage,
381 findPropertyValue<sal_Int32>(aFilterData, "CompressMode", 75),
382 findPropertyValue<bool>(aFilterData, "ExportOLEAsJPEG", false));
384 const sal_Int32 nPageCount = xDrawPages->getCount();
385 if ( mxStatusIndicator.is() )
386 mxStatusIndicator->start( "Saving :", nPageCount);
388 for(sal_Int32 nPage = 0; nPage < nPageCount; nPage++)
390 if ( mxStatusIndicator.is() )
391 mxStatusIndicator->setValue( nPage );
392 xDrawPages->getByIndex(nPage) >>= xDrawPage;
394 // AS: If we're only exporting the current page, then skip the rest.
395 if (!bExportAll && xDrawPage != rCurrentPage)
396 continue;
398 // AS: Export the background, the background objects, and then the slide contents.
399 if (bExportAll || findPropertyValue<bool>(aFilterData, "ExportBackgrounds", true))
401 backgroundfilename = exportBackground(aFlashExporter, xDrawPage, swfdirpath, nPage, "b");
404 if (bExportAll || findPropertyValue<bool>(aFilterData, "ExportBackgroundObjects", true))
406 objectsfilename = exportBackground(aFlashExporter, xDrawPage, swfdirpath, nPage, "o");
409 if (bExportAll || findPropertyValue<bool>(aFilterData, "ExportSlideContents", true))
411 fullpath = swfdirpath + "/slide"+ OUString::number(nPage+1) + "p.swf";
413 Reference<XOutputStream> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath)), UNO_QUERY);
414 bool ret = aFlashExporter.exportSlides( xDrawPage, xOutputStreamWrap );
415 aFlashExporter.Flush();
416 xOutputStreamWrap.clear();
418 if (!ret)
419 osl_removeFile(fullpath.pData);
422 // AS: Write out to the background config what backgrounds and objects this
423 // slide used.
424 if (bExportAll)
426 OUString temp = backgroundfilename + "|" + objectsfilename;
427 OString ASCIItemp(temp.getStr(), temp.getLength(), RTL_TEXTENCODING_ASCII_US);
429 sal_uInt64 bytesWritten;
430 osl_writeFile(aBackgroundConfig, ASCIItemp.getStr(), ASCIItemp.getLength(), &bytesWritten);
432 if (nPage < nPageCount - 1)
433 osl_writeFile(aBackgroundConfig, "|", 1, &bytesWritten);
437 if (bExportAll)
438 osl_closeFile(aBackgroundConfig);
441 void FlashExportFilter::ExportAsSingleFile(const Sequence< PropertyValue >& aDescriptor)
443 Reference < XOutputStream > xOutputStream = findPropertyValue<Reference<XOutputStream> >(aDescriptor, "OutputStream", nullptr);
444 Sequence< PropertyValue > aFilterData;
446 if (!xOutputStream.is() )
448 OSL_ASSERT ( false );
449 return;
452 FlashExporter aFlashExporter(
453 mxContext,
454 mxSelectedShapes,
455 mxSelectedDrawPage,
456 findPropertyValue<sal_Int32>(aFilterData, "CompressMode", 75),
457 findPropertyValue<bool>(aFilterData, "ExportOLEAsJPEG", false));
459 aFlashExporter.exportAll( mxDoc, xOutputStream, mxStatusIndicator );
463 void SAL_CALL FlashExportFilter::cancel( )
468 // XExporter
469 void SAL_CALL FlashExportFilter::setSourceDocument( const css::uno::Reference< css::lang::XComponent >& xDoc )
471 mxDoc = xDoc;
475 // XInitialization
476 void SAL_CALL FlashExportFilter::initialize( const css::uno::Sequence< css::uno::Any >& /* aArguments */ )
480 OUString FlashExportFilter_getImplementationName ()
482 return "com.sun.star.comp.Impress.FlashExportFilter";
485 Sequence< OUString > FlashExportFilter_getSupportedServiceNames( )
487 Sequence<OUString> aRet { "com.sun.star.document.ExportFilter" };
488 return aRet;
491 Reference< XInterface > FlashExportFilter_createInstance( const Reference< XMultiServiceFactory > & rSMgr)
493 return static_cast<cppu::OWeakObject*>(new FlashExportFilter( comphelper::getComponentContext(rSMgr) ));
496 // XServiceInfo
497 OUString SAL_CALL FlashExportFilter::getImplementationName( )
499 return FlashExportFilter_getImplementationName();
502 sal_Bool SAL_CALL FlashExportFilter::supportsService( const OUString& rServiceName )
504 return cppu::supportsService( this, rServiceName );
507 css::uno::Sequence< OUString > SAL_CALL FlashExportFilter::getSupportedServiceNames( )
509 return FlashExportFilter_getSupportedServiceNames();
514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */