1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26 #include <com/sun/star/frame/XDesktop.hpp>
27 #include <com/sun/star/frame/XStorable.hpp>
28 #include <com/sun/star/document/XFilter.hpp>
29 #include <com/sun/star/document/XExporter.hpp>
30 #include <com/sun/star/lang/XInitialization.hpp>
31 #include <com/sun/star/lang/XServiceInfo.hpp>
32 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
33 #include <com/sun/star/drawing/XDrawView.hpp>
34 #include <com/sun/star/container/XIndexAccess.hpp>
35 #include <com/sun/star/frame/XModel.hpp>
36 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
37 #include <com/sun/star/io/XOutputStream.hpp>
38 #include <cppuhelper/implbase1.hxx>
39 #include <cppuhelper/implbase4.hxx>
40 #include <osl/file.hxx>
41
42 #include "swfexporter.hxx"
43
44 //#include <stdlib.h>
45 //#include <windows.h>
46 #include <string.h>
47
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::presentation;
53 using namespace ::com::sun::star::task;
54
55 using ::rtl::OUString;
56 using ::rtl::OString;
57 using ::com::sun::star::lang::XComponent;
58 using ::com::sun::star::beans::PropertyValue;
59 using ::com::sun::star::io::XOutputStream;
60 using ::com::sun::star::container::XIndexAccess;
61 using ::osl::FileBase;
62 using ::com::sun::star::frame::XModel;
63
64 namespace swf {
65
66 typedef ::cppu::WeakImplHelper1<com::sun::star::io::XOutputStream> OslOutputStreamWrapper_Base;
67 // needed for some compilers
68 class OslOutputStreamWrapper : public OslOutputStreamWrapper_Base
69 {
70 osl::File mrFile;
71
72 public:
OslOutputStreamWrapper(const OUString & sFileName)73 OslOutputStreamWrapper(const OUString& sFileName) : mrFile(sFileName)
74 {
75 osl_removeFile(sFileName.pData);
76 mrFile.open(OpenFlag_Create|OpenFlag_Write);
77 }
78
79 // stario::XOutputStream
80 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);
81 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);
82 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);
83 };
84
writeBytes(const::com::sun::star::uno::Sequence<sal_Int8> & aData)85 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)
86 {
87 sal_uInt64 uBytesToWrite = aData.getLength();
88 sal_uInt64 uBytesWritten = 0;
89
90 sal_Int8 const * pBuffer = aData.getConstArray();
91
92 while( uBytesToWrite )
93 {
94 osl::File::RC eRC = mrFile.write( pBuffer, uBytesToWrite, uBytesWritten);
95
96 switch( eRC )
97 {
98 case osl::File::E_INVAL: // the format of the parameters was not valid
99 case osl::File::E_FBIG: // File too large
100
101 case osl::File::E_AGAIN: // Operation would block
102 case osl::File::E_BADF: // Bad file
103 case osl::File::E_FAULT: // Bad address
104 case osl::File::E_INTR: // function call was interrupted
105 case osl::File::E_IO: // I/O error
106 case osl::File::E_NOLCK: // No record locks available
107 case osl::File::E_NOLINK: // Link has been severed
108 case osl::File::E_NOSPC: // No space left on device
109 case osl::File::E_NXIO: // No such device or address
110 throw com::sun::star::io::IOException(); // TODO: Better error handling
111 default: break;
112 }
113
114 uBytesToWrite -= uBytesWritten;
115 pBuffer += uBytesWritten;
116 }
117 }
118
flush()119 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)
120 {
121 }
122
closeOutput()123 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)
124 {
125 osl::File::RC eRC = mrFile.close();
126
127 switch( eRC )
128 {
129 case osl::File::E_INVAL: // the format of the parameters was not valid
130
131 case osl::File::E_BADF: // Bad file
132 case osl::File::E_INTR: // function call was interrupted
133 case osl::File::E_NOLINK: // Link has been severed
134 case osl::File::E_NOSPC: // No space left on device
135 case osl::File::E_IO: // I/O error
136 throw com::sun::star::io::IOException(); // TODO: Better error handling
137 default: break;
138 }
139 }
140
141 // -----------------------------------------------------------------------------
142
143 class FlashExportFilter : public cppu::WeakImplHelper4
144 <
145 com::sun::star::document::XFilter,
146 com::sun::star::document::XExporter,
147 com::sun::star::lang::XInitialization,
148 com::sun::star::lang::XServiceInfo
149 >
150 {
151 Reference< XComponent > mxDoc;
152 Reference< XMultiServiceFactory > mxMSF;
153 Reference< XStatusIndicator> mxStatusIndicator;
154
155 osl::File* mpFile;
156
157 public:
158 FlashExportFilter( const Reference< XMultiServiceFactory > &rxMSF);
159
160 // XFilter
161 virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& aDescriptor ) throw(RuntimeException);
162
163 sal_Bool ExportAsMultipleFiles( const Sequence< PropertyValue >& aDescriptor );
164 sal_Bool ExportAsSingleFile( const Sequence< PropertyValue >& aDescriptor );
165
166 virtual void SAL_CALL cancel( ) throw (RuntimeException);
167
168 // XExporter
169 virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) throw(IllegalArgumentException, RuntimeException);
170
171 // XInitialization
172 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException);
173
174 // XServiceInfo
175 virtual OUString SAL_CALL getImplementationName() throw(RuntimeException);
176 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw(RuntimeException);
177 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw(RuntimeException);
178 };
179
180 // -----------------------------------------------------------------------------
181
FlashExportFilter(const Reference<XMultiServiceFactory> & rxMSF)182 FlashExportFilter::FlashExportFilter(const Reference< XMultiServiceFactory > &rxMSF)
183 : mxMSF( rxMSF )
184 {
185 }
186
187
188 // -----------------------------------------------------------------------------
189
exportBackground(FlashExporter & aFlashExporter,Reference<XDrawPage> xDrawPage,OUString sPath,sal_uInt32 nPage,const char * suffix)190 OUString exportBackground(FlashExporter &aFlashExporter, Reference< XDrawPage > xDrawPage, OUString sPath, sal_uInt32 nPage, const char* suffix)
191 {
192 OUString filename = STR("slide") + VAL(nPage+1) + STR(suffix) + STR(".swf");
193 OUString fullpath = sPath + STR("/") + filename;
194
195 // AS: If suffix is "o" then the last paramter is true (for exporting objects).
196 Reference<XOutputStream> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath)), UNO_QUERY);
197 sal_uInt16 nCached = aFlashExporter.exportBackgrounds( xDrawPage, xOutputStreamWrap, sal::static_int_cast<sal_uInt16>( nPage ), *suffix == 'o' );
198 aFlashExporter.Flush();
199 xOutputStreamWrap.clear();
200
201 if (nCached != nPage)
202 {
203 osl_removeFile(fullpath.pData);
204 if ( 0xffff == nCached )
205 return STR("NULL");
206 else
207 return STR("slide") + VAL(nCached+1) + STR(suffix) + STR(".swf");
208 }
209
210 return filename;
211 }
212
213 template <typename TYPE>
findPropertyValue(const Sequence<PropertyValue> & aPropertySequence,const sal_Char * name,TYPE def)214 TYPE findPropertyValue(const Sequence< PropertyValue >& aPropertySequence, const sal_Char* name, TYPE def)
215 {
216 TYPE temp = TYPE();
217
218 sal_Int32 nLength = aPropertySequence.getLength();
219 const PropertyValue * pValue = aPropertySequence.getConstArray();
220
221 for ( sal_Int32 i = 0 ; i < nLength; i++)
222 {
223 if ( pValue[i].Name.equalsAsciiL ( name, strlen(name) ) )
224 {
225 pValue[i].Value >>= temp;
226 return temp;
227 }
228 }
229
230 return def;
231 }
232
filter(const::com::sun::star::uno::Sequence<::com::sun::star::beans::PropertyValue> & aDescriptor)233 sal_Bool SAL_CALL FlashExportFilter::filter( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aDescriptor )
234 throw (RuntimeException)
235 {
236 mxStatusIndicator = findPropertyValue<Reference<XStatusIndicator> >(aDescriptor, "StatusIndicator", mxStatusIndicator);
237
238 Sequence< PropertyValue > aFilterData;
239 aFilterData = findPropertyValue<Sequence< PropertyValue > >(aDescriptor, "FilterData", aFilterData);
240
241 if (findPropertyValue<sal_Bool>(aFilterData, "ExportMultipleFiles", false ))
242 {
243 ExportAsMultipleFiles(aDescriptor);
244 }
245 else
246 {
247 ExportAsSingleFile(aDescriptor);
248 }
249
250 if( mxStatusIndicator.is() )
251 mxStatusIndicator->end();
252
253 return sal_True;
254 }
255
256
257 // AS: When exporting as multiple files, each background, object layer, and slide gets its own
258 // file. Additionally, a file called BackgroundConfig.txt is generated, indicating which
259 // background and objects (if any) go with each slide. The files are named slideNb.swf,
260 // slideNo.swf, and slideNp.swf, where N is the slide number, and b=background, o=objects, and
261 // p=slide contents. Note that under normal circumstances, there will be very few b and o files.
262
263 // AS: HACK! Right now, I create a directory as a sibling to the swf file selected in the Export
264 // dialog. This directory is called presentation.sxi-swf-files. The name of the swf file selected
265 // in the Export dialog has no impact on this. All files created are placed in this directory.
ExportAsMultipleFiles(const Sequence<PropertyValue> & aDescriptor)266 sal_Bool FlashExportFilter::ExportAsMultipleFiles(const Sequence< PropertyValue >& aDescriptor)
267 {
268 Reference< XDrawPagesSupplier > xDrawPagesSupplier(mxDoc, UNO_QUERY);
269 if(!xDrawPagesSupplier.is())
270 return sal_False;
271
272 Reference< XIndexAccess > xDrawPages( xDrawPagesSupplier->getDrawPages(), UNO_QUERY );
273 if(!xDrawPages.is())
274 return sal_False;
275
276 Reference< XDesktop > rDesktop( mxMSF->createInstance(OUString::createFromAscii("com.sun.star.frame.Desktop")), UNO_QUERY);
277 if (!rDesktop.is())
278 return sal_False;
279
280 Reference< XStorable > xStorable(rDesktop->getCurrentComponent(), UNO_QUERY);
281 if (!xStorable.is())
282 return sal_False;
283
284 Reference< XDrawPage > xDrawPage;
285
286 Reference< XFrame > rFrame = rDesktop->getCurrentFrame();
287 Reference< XDrawView > rDrawView = Reference< XDrawView >( rFrame->getController(), UNO_QUERY );
288
289 Reference< XDrawPage > rCurrentPage = rDrawView->getCurrentPage();
290
291 Sequence< PropertyValue > aFilterData;
292
293 aFilterData = findPropertyValue<Sequence< PropertyValue > >(aDescriptor, "FilterData", aFilterData);
294
295 //AS: Do a bunch of path mangling to figure out where to put the files.
296
297 OUString sOriginalPath = findPropertyValue<OUString>(aDescriptor, "URL", OUString());
298
299 // AS: sPath is the parent directory, where everything else exists (like the sxi,
300 // the -swf-files folder, the -audio files, etc.
301 int lastslash = sOriginalPath.lastIndexOf('/');
302 OUString sPath( sOriginalPath.copy(0, lastslash) );
303
304 OUString sPresentation(xStorable->getLocation());
305
306 lastslash = sPresentation.lastIndexOf('/') + 1;
307 int lastdot = sPresentation.lastIndexOf('.');
308
309 // AS: The name of the presentation, without 3 character extension.
310 OUString sPresentationName = sPresentation.copy(lastslash, lastdot - lastslash);
311
312 OUString fullpath, swfdirpath, backgroundfilename, objectsfilename;
313
314 swfdirpath = sPath + STR("/") + sPresentationName + STR(".sxi-swf-files");
315
316 oslFileError err;
317 err = osl_createDirectory( swfdirpath.pData );
318
319 fullpath = swfdirpath + STR("/backgroundconfig.txt");
320
321 oslFileHandle xBackgroundConfig( 0 );
322
323 // AS: Only export the background config if we're exporting all of the pages, otherwise we'll
324 // screw it up.
325 sal_Bool bExportAll = findPropertyValue<sal_Bool>(aFilterData, "ExportAll", true);
326 if (bExportAll)
327 {
328 osl_removeFile(fullpath.pData);
329 osl_openFile( fullpath.pData, &xBackgroundConfig, osl_File_OpenFlag_Create | osl_File_OpenFlag_Write );
330
331 sal_uInt64 bytesWritten;
332 err = osl_writeFile(xBackgroundConfig, "slides=", strlen("slides="), &bytesWritten);
333 }
334
335 FlashExporter aFlashExporter( mxMSF, findPropertyValue<sal_Int32>(aFilterData, "CompressMode", 75),
336 findPropertyValue<sal_Bool>(aFilterData, "ExportOLEAsJPEG", false));
337
338 const sal_Int32 nPageCount = xDrawPages->getCount();
339 if ( mxStatusIndicator.is() )
340 mxStatusIndicator->start(OUString( RTL_CONSTASCII_USTRINGPARAM( "Saving :" )), nPageCount);
341
342 for(sal_Int32 nPage = 0; nPage < nPageCount; nPage++)
343 {
344 if ( mxStatusIndicator.is() )
345 mxStatusIndicator->setValue( nPage );
346 xDrawPages->getByIndex(nPage) >>= xDrawPage;
347
348 // AS: If we're only exporting the current page, then skip the rest.
349 if (!bExportAll && xDrawPage != rCurrentPage)
350 continue;
351
352 // AS: Export the background, the background objects, and then the slide contents.
353 if (bExportAll || findPropertyValue<sal_Bool>(aFilterData, "ExportBackgrounds", true))
354 {
355 backgroundfilename = exportBackground(aFlashExporter, xDrawPage, swfdirpath, nPage, "b");
356 }
357
358 if (bExportAll || findPropertyValue<sal_Bool>(aFilterData, "ExportBackgroundObjects", true))
359 {
360 objectsfilename = exportBackground(aFlashExporter, xDrawPage, swfdirpath, nPage, "o");
361 }
362
363 if (bExportAll || findPropertyValue<sal_Bool>(aFilterData, "ExportSlideContents", true))
364 {
365 fullpath = swfdirpath + STR("/slide") + VAL(nPage+1) + STR("p.swf");
366
367 Reference<XOutputStream> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath)), UNO_QUERY);
368 sal_Bool ret = aFlashExporter.exportSlides( xDrawPage, xOutputStreamWrap, sal::static_int_cast<sal_uInt16>( nPage ) );
369 aFlashExporter.Flush();
370 xOutputStreamWrap.clear();
371
372 if (!ret)
373 osl_removeFile(fullpath.pData);
374 }
375
376 // AS: Write out to the background config what backgrounds and objects this
377 // slide used.
378 if (bExportAll)
379 {
380 OUString temp = backgroundfilename + STR("|") + objectsfilename;
381 OString ASCIItemp(temp.getStr(), temp.getLength(), RTL_TEXTENCODING_ASCII_US);
382
383 sal_uInt64 bytesWritten;
384 osl_writeFile(xBackgroundConfig, ASCIItemp.getStr(), ASCIItemp.getLength(), &bytesWritten);
385
386 if (nPage < nPageCount - 1)
387 osl_writeFile(xBackgroundConfig, "|", 1, &bytesWritten);
388 }
389
390 #ifdef AUGUSTUS
391 if (findPropertyValue<sal_Bool>(aFilterData, "ExportSound", true))
392 {
393 fullpath = swfdirpath + STR("/slide") + VAL(nPage+1) + STR("s.swf");
394
395 OUString wavpath = sPath + STR("/") + sPresentationName + STR(".ppt-audio/slide") + VAL(nPage+1) + STR(".wav");
396 FileBase::getSystemPathFromFileURL(wavpath, wavpath);
397 OString sASCIIPath(wavpath.getStr(), wavpath.getLength(), RTL_TEXTENCODING_ASCII_US);
398
399 Reference<XOutputStream> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath)), UNO_QUERY);
400 sal_Bool ret = aFlashExporter.exportSound(xOutputStreamWrap, sASCIIPath.getStr());
401 aFlashExporter.Flush();
402 xOutputStreamWrap.clear();
403
404 if (!ret)
405 osl_removeFile(fullpath.pData);
406 }
407 #endif // defined AUGUSTUS
408 }
409
410 if (bExportAll)
411 osl_closeFile(xBackgroundConfig);
412
413 return sal_True;
414 }
415
ExportAsSingleFile(const Sequence<PropertyValue> & aDescriptor)416 sal_Bool FlashExportFilter::ExportAsSingleFile(const Sequence< PropertyValue >& aDescriptor)
417 {
418 Reference < XOutputStream > xOutputStream = findPropertyValue<Reference<XOutputStream> >(aDescriptor, "OutputStream", 0);
419 Sequence< PropertyValue > aFilterData;
420
421 if (!xOutputStream.is() )
422 {
423 OSL_ASSERT ( 0 );
424 return sal_False;
425 }
426
427 FlashExporter aFlashExporter( mxMSF, findPropertyValue<sal_Int32>(aFilterData, "CompressMode", 75),
428 findPropertyValue<sal_Bool>(aFilterData, "ExportOLEAsJPEG", false));
429
430 return aFlashExporter.exportAll( mxDoc, xOutputStream, mxStatusIndicator );
431 }
432
433 // -----------------------------------------------------------------------------
434
cancel()435 void SAL_CALL FlashExportFilter::cancel( )
436 throw (RuntimeException)
437 {
438 }
439
440 // -----------------------------------------------------------------------------
441
442 // XExporter
setSourceDocument(const::com::sun::star::uno::Reference<::com::sun::star::lang::XComponent> & xDoc)443 void SAL_CALL FlashExportFilter::setSourceDocument( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& xDoc )
444 throw (::com::sun::star::lang::IllegalArgumentException, RuntimeException)
445 {
446 mxDoc = xDoc;
447 }
448
449 // -----------------------------------------------------------------------------
450
451 // XInitialization
initialize(const::com::sun::star::uno::Sequence<::com::sun::star::uno::Any> &)452 void SAL_CALL FlashExportFilter::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& /* aArguments */ )
453 throw (Exception, RuntimeException)
454 {
455 }
456
457 // -----------------------------------------------------------------------------
458
FlashExportFilter_getImplementationName()459 OUString FlashExportFilter_getImplementationName ()
460 throw (RuntimeException)
461 {
462 return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Impress.FlashExportFilter" ) );
463 }
464
465 // -----------------------------------------------------------------------------
466
467 #define SERVICE_NAME "com.sun.star.document.ExportFilter"
468
FlashExportFilter_supportsService(const OUString & ServiceName)469 sal_Bool SAL_CALL FlashExportFilter_supportsService( const OUString& ServiceName )
470 throw (RuntimeException)
471 {
472 return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) );
473 }
474
475 // -----------------------------------------------------------------------------
476
FlashExportFilter_getSupportedServiceNames()477 Sequence< OUString > SAL_CALL FlashExportFilter_getSupportedServiceNames( )
478 throw (RuntimeException)
479 {
480 Sequence < OUString > aRet(1);
481 OUString* pArray = aRet.getArray();
482 pArray[0] = OUString ( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );
483 return aRet;
484 }
485 #undef SERVICE_NAME
486
487 // -----------------------------------------------------------------------------
488
FlashExportFilter_createInstance(const Reference<XMultiServiceFactory> & rSMgr)489 Reference< XInterface > SAL_CALL FlashExportFilter_createInstance( const Reference< XMultiServiceFactory > & rSMgr)
490 throw( Exception )
491 {
492 return (cppu::OWeakObject*) new FlashExportFilter( rSMgr );
493 }
494
495 // -----------------------------------------------------------------------------
496
497 // XServiceInfo
getImplementationName()498 OUString SAL_CALL FlashExportFilter::getImplementationName( )
499 throw (RuntimeException)
500 {
501 return FlashExportFilter_getImplementationName();
502 }
503
504 // -----------------------------------------------------------------------------
505
supportsService(const OUString & rServiceName)506 sal_Bool SAL_CALL FlashExportFilter::supportsService( const OUString& rServiceName )
507 throw (RuntimeException)
508 {
509 return FlashExportFilter_supportsService( rServiceName );
510 }
511
512 // -----------------------------------------------------------------------------
513
getSupportedServiceNames()514 ::com::sun::star::uno::Sequence< OUString > SAL_CALL FlashExportFilter::getSupportedServiceNames( )
515 throw (RuntimeException)
516 {
517 return FlashExportFilter_getSupportedServiceNames();
518 }
519
520 // -----------------------------------------------------------------------------
521
522 }
523