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/container/XNamed.hpp>
27 #include <com/sun/star/beans/PropertyValue.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
30 #ifndef _COM_SUN_STAR_PRESENTATION_PRESENTATIONPAGE_HPP_
31 #include <com/sun/star/presentation/XPresentationPage.hpp>
32 #endif
33 #include <com/sun/star/container/XIndexAccess.hpp>
34 #include <com/sun/star/document/XFilter.hpp>
35 #include <com/sun/star/text/XText.hpp>
36 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
37 #include <com/sun/star/frame/XModel.hpp>
38 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
39 #include <rtl/ustrbuf.hxx>
40 #include <rtl/string.hxx>
41 #include <osl/diagnose.h>
42
43 #include <vector>
44
45 #include "exporter.hxx"
46 #include "Base64Codec.hxx"
47 #include "zip.hxx"
48 #include "tempfile.hxx"
49
50 using rtl::OUString;
51 using rtl::OString;
52 using namespace ::com::sun::star::uno;
53 using namespace ::com::sun::star::drawing;
54 using namespace ::com::sun::star::container;
55 using namespace ::com::sun::star::document;
56 using namespace ::com::sun::star::io;
57 using namespace ::com::sun::star::lang;
58 using namespace ::com::sun::star::text;
59 using namespace ::std;
60
61 using com::sun::star::beans::PropertyValue;
62 using com::sun::star::beans::XPropertySet;
63 using com::sun::star::presentation::XPresentationPage;
64 using com::sun::star::task::XStatusIndicator;
65
66 // -----------------------------------------------------------------------------
67
PlaceWareExporter(const Reference<XMultiServiceFactory> & rxMSF)68 PlaceWareExporter::PlaceWareExporter(const Reference< XMultiServiceFactory > &rxMSF)
69 : mxMSF( rxMSF )
70 {
71 }
72
73 // -----------------------------------------------------------------------------
74
~PlaceWareExporter()75 PlaceWareExporter::~PlaceWareExporter()
76 {
77 }
78
79 // -----------------------------------------------------------------------------
80 class PageEntry
81 {
82 private:
83 TempFile maTempFile;
84 rtl::OUString maName;
85 rtl::OUString maTitle;
86 rtl::OUString maNotes;
87 rtl::OUString maURL;
88
89 public:
90 PageEntry();
91 ~PageEntry();
92
getTempURL()93 OUString getTempURL() { return maTempFile.getFileURL(); }
94
setName(const rtl::OUString & rName)95 void setName( const rtl::OUString& rName ) { maName = rName; }
getName() const96 const rtl::OUString& getName() const { return maName; }
97
setTitle(const rtl::OUString & rTitle)98 void setTitle( const rtl::OUString& rTitle ) { maTitle = rTitle; }
getTitle() const99 const rtl::OUString& getTitle() const { return maTitle; }
100
setNotes(const rtl::OUString & rNotes)101 void setNotes( const rtl::OUString& rNotes ) { maNotes = rNotes; }
getNotes() const102 const rtl::OUString& getNotes() const { return maNotes; }
103
setURL(const rtl::OUString & rURL)104 void setURL( const rtl::OUString& rURL ) { maURL = rURL; }
getURL() const105 const rtl::OUString& getURL() const { return maURL; }
106 };
107
PageEntry()108 PageEntry::PageEntry()
109 : maTempFile( TempFile::createTempFileURL() )
110 {
111 }
112
~PageEntry()113 PageEntry::~PageEntry()
114 {
115 }
116
117
encodeFile(osl::File & rSourceFile,Reference<XOutputStream> & xOutputStream)118 static void encodeFile( osl::File& rSourceFile, Reference< XOutputStream >& xOutputStream ) throw( ::com::sun::star::uno::Exception )
119 {
120 if( xOutputStream.is() )
121 {
122 sal_uInt64 nTemp( 0 );
123
124 osl::File::RC nRC = rSourceFile.setPos( osl_Pos_End, 0 );
125 if( osl::File::E_None == nRC )
126 {
127 nRC = rSourceFile.getPos( nTemp );
128 if( osl::File::E_None == nRC )
129 {
130 nRC = rSourceFile.setPos( osl_Pos_Absolut, 0 );
131 }
132 }
133
134 sal_Int32 nLen = static_cast<sal_Int32>(nTemp);
135
136 if( osl::File::E_None != nRC )
137 throw IOException();
138
139 sal_Int32 nBufferSize = 3*1024; // !!! buffer size must be a factor of 3 for base64 to work
140 Sequence< sal_Int8 > aInBuffer( nBufferSize < nLen ? nBufferSize : nLen );
141 void* pInBuffer = aInBuffer.getArray();
142
143 Sequence< sal_Int8 > aOutBuffer;
144 sal_Int32 nRead;
145 while( nLen )
146 {
147 nRC = rSourceFile.read( pInBuffer, aInBuffer.getLength(), nTemp );
148
149 if( (nRC != osl::File::E_None) || (0 == nTemp) )
150 throw IOException();
151
152 nRead = static_cast<sal_Int32>( nTemp );
153
154 if( nRead < aInBuffer.getLength() )
155 {
156 aInBuffer.realloc( nRead );
157 pInBuffer = aInBuffer.getArray();
158 }
159
160 nLen -= nRead;
161
162 rtl::OUStringBuffer aStrBuffer;
163 Base64Codec::encodeBase64( aStrBuffer, aInBuffer );
164
165 sal_Int32 nCount = aStrBuffer.getLength();
166
167 if( aOutBuffer.getLength() != nCount )
168 aOutBuffer.realloc( nCount );
169
170 sal_Int8* pBytes = aOutBuffer.getArray();
171 const sal_Unicode* pUnicode = aStrBuffer.getStr();
172
173 while( nCount-- )
174 {
175 // since base64 is always ascii, we can cast safely
176 *pBytes++ = static_cast<sal_Int8>(*pUnicode++);
177 }
178
179 xOutputStream->writeBytes( aOutBuffer );
180 }
181 }
182 }
183
convertString(OUString aInput)184 static OString convertString( OUString aInput )
185 {
186 OString aRet( aInput.getStr(), aInput.getLength(), RTL_TEXTENCODING_ASCII_US );
187 aRet = aRet.replace( '\r', ' ' );
188 aRet = aRet.replace( '\n', ' ' );
189
190 return aRet;
191 }
192
createSlideFile(Reference<XComponent> xDoc,ZipFile & rZipFile,const rtl::OUString & rURL,vector<PageEntry * > & rPageEntries)193 static void createSlideFile( Reference< XComponent > xDoc, ZipFile& rZipFile, const rtl::OUString& rURL, vector< PageEntry* >& rPageEntries ) throw( ::com::sun::star::uno::Exception )
194 {
195 OString aInfo;
196
197 const OString aNewLine( "\r\n" );
198 OUString aTemp;
199
200 Reference< XDocumentPropertiesSupplier > xDPS( xDoc, UNO_QUERY );
201 Reference< XDocumentProperties > xDocProps( xDPS->getDocumentProperties() );
202
203 aTemp = xDocProps->getTitle();
204 if( 0 == aTemp.getLength() )
205 {
206 sal_Int32 nPos1 = rURL.lastIndexOf( (sal_Unicode)'/' );
207 if( -1 != nPos1 )
208 {
209 sal_Int32 nPos2 = rURL.lastIndexOf( (sal_Unicode)'.' );
210 if( nPos2 > nPos1 )
211 {
212 aTemp = rURL.copy( nPos1 + 1, nPos2 - nPos1 - 1 );
213 }
214 else
215 {
216 aTemp = rURL.copy( nPos1 + 1 );
217 }
218 }
219 else
220 {
221 aTemp = rURL;
222 }
223 }
224
225 aInfo += OString( "SlideSetName: " );
226 aInfo += convertString( aTemp );
227 aInfo += aNewLine;
228
229 aTemp = xDocProps->getAuthor();
230
231 if( aTemp.getLength() )
232 {
233 aInfo += OString( "PresenterName: " );
234 aInfo += convertString( aTemp );
235 aInfo += aNewLine;
236 }
237
238 vector< PageEntry* >::iterator aIter( rPageEntries.begin() );
239 vector< PageEntry* >::iterator aEnd( rPageEntries.end() );
240 while( aIter != aEnd )
241 {
242 PageEntry* pEntry = (*aIter++);
243
244 aInfo += OString( "slide: " );
245 if( pEntry->getTitle().getLength() )
246 {
247 aInfo += convertString( pEntry->getTitle() );
248 }
249 else
250 {
251 aInfo += convertString( pEntry->getName() );
252 }
253 aInfo += aNewLine;
254
255 aInfo += OString( "type: gif");
256 aInfo += aNewLine;
257
258 aInfo += OString( "url: " );
259 aInfo += convertString( pEntry->getURL() );
260 aInfo += aNewLine;
261
262
263 if( pEntry->getNotes().getLength() )
264 {
265 aInfo += OString( "notes: " );
266 aInfo += convertString( pEntry->getNotes() );
267 aInfo += aNewLine;
268 }
269 }
270
271 TempFile aInfoFile( TempFile::createTempFileURL() );
272
273 osl::File::RC nRC;
274 sal_uInt64 nTemp;
275
276 nRC = aInfoFile.open( OpenFlag_Write );
277 if( osl::File::E_None == nRC )
278 {
279 nRC = aInfoFile.write( aInfo.getStr(), aInfo.getLength(), nTemp );
280 if( osl::File::E_None == nRC )
281 {
282 nRC = aInfoFile.setPos( osl_Pos_Absolut, 0 );
283 if( osl::File::E_None == nRC )
284 {
285 nRC = aInfoFile.close();
286 }
287 }
288 }
289
290 if( (osl::File::E_None != nRC) || !rZipFile.addFile( aInfoFile, OString( RTL_CONSTASCII_STRINGPARAM("slides.txt") ) ))
291 throw IOException();
292 }
293
294 //#define PLACEWARE_DEBUG 1
295
doExport(Reference<XComponent> xDoc,Reference<XOutputStream> xOutputStream,const rtl::OUString & rURL,Reference<XInterface>,Reference<XStatusIndicator> & xStatusIndicator)296 sal_Bool PlaceWareExporter::doExport( Reference< XComponent > xDoc, Reference < XOutputStream > xOutputStream,
297 const rtl::OUString& rURL, Reference < XInterface > /* xHandler */, Reference < XStatusIndicator >& xStatusIndicator )
298 {
299 sal_Bool bRet = sal_False;
300
301 mxGraphicExporter = Reference< XExporter >::query( mxMSF->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.GraphicExportFilter") ) ) );
302 Reference< XDrawPagesSupplier > xDrawPagesSupplier(xDoc, UNO_QUERY);
303 if(!xDrawPagesSupplier.is())
304 return sal_False;
305
306 Reference< XIndexAccess > xDrawPages( xDrawPagesSupplier->getDrawPages(), UNO_QUERY );
307 if(!xDrawPages.is())
308 return sal_False;
309
310 if(xStatusIndicator.is())
311 {
312 xStatusIndicator->start(OUString( RTL_CONSTASCII_USTRINGPARAM( "PlaceWare:" )),xDrawPages->getCount());
313 }
314
315 Reference< XDrawPage > xDrawPage;
316
317 osl::File::RC nRC;
318
319 #ifndef PLACEWARE_DEBUG
320 TempFile aTempFile( TempFile::createTempFileURL() );
321 nRC = aTempFile.open( osl_File_OpenFlag_Write|osl_File_OpenFlag_Read );
322 OUString aURL( aTempFile.getFileURL() );
323 #else
324 OUString aURL( RTL_CONSTASCII_USTRINGPARAM("file:///e:/test.zip") );
325 osl::File::remove( aURL );
326 osl::File aTempFile( aURL );
327 nRC = aTempFile.open( osl_File_OpenFlag_Create|osl_File_OpenFlag_Write|osl_File_OpenFlag_Read );
328 #endif
329
330 if( osl::File::E_None != nRC )
331 return sal_False;
332
333 vector< PageEntry* > aPageEntries;
334
335 // Create new package...
336 try
337 {
338 ZipFile aZipFile(aTempFile);
339
340 // export slides as gifs and collect information for slides
341
342 const sal_Int32 nPageCount = xDrawPages->getCount();
343 sal_Int32 nPage;
344
345 for( nPage = 0; nPage < nPageCount; nPage++)
346 {
347 xDrawPages->getByIndex(nPage) >>= xDrawPage;
348
349 if( !xDrawPage.is() )
350 continue;
351
352 PageEntry* pEntry = exportPage( xDrawPage );
353 aPageEntries.push_back( pEntry );
354
355 OUString aName( RTL_CONSTASCII_USTRINGPARAM("i") );
356 aName += OUString::valueOf( nPage );
357 aName += OUString( RTL_CONSTASCII_USTRINGPARAM(".gif") );
358 pEntry->setURL( aName );
359
360 if(xStatusIndicator.is())
361 {
362 xStatusIndicator->setValue( nPage + 1 );
363 }
364 }
365
366 // create the slide.txt file
367
368 createSlideFile( xDoc, aZipFile, rURL, aPageEntries );
369
370 // add gifs to zip
371 vector< PageEntry* >::iterator aIter( aPageEntries.begin() );
372 vector< PageEntry* >::iterator aEnd( aPageEntries.end() );
373 while( aIter != aEnd )
374 {
375 PageEntry* pEntry = (*aIter++);
376
377 osl::File aFile(pEntry->getTempURL() );
378 const OUString aTemp( pEntry->getURL() );
379
380 if( (osl::File::E_None != nRC) || !aZipFile.addFile( aFile, OString( aTemp.getStr(), aTemp.getLength(), RTL_TEXTENCODING_ASCII_US ) ) )
381 throw IOException();
382 }
383
384 if(!aZipFile.close())
385 throw IOException();
386
387 encodeFile( aTempFile, xOutputStream );
388
389 bRet = sal_True;
390 }
391 catch ( RuntimeException const & )
392 {
393 }
394 catch ( Exception const & )
395 {
396 }
397
398 vector< PageEntry* >::iterator aIter( aPageEntries.begin() );
399 vector< PageEntry* >::iterator aEnd( aPageEntries.end() );
400 while( aIter != aEnd )
401 {
402 delete (*aIter++);
403 }
404
405 if( xStatusIndicator.is() )
406 xStatusIndicator->end();
407
408 return bRet;
409 }
410
411 // -----------------------------------------------------------------------------
412
exportPage(Reference<XDrawPage> & xDrawPage)413 PageEntry* PlaceWareExporter::exportPage( Reference< XDrawPage >&xDrawPage )
414 {
415 Reference< XComponent > xComp( xDrawPage, UNO_QUERY );
416
417 PageEntry* pEntry = new PageEntry();
418
419 // get page name
420 Reference< XNamed > xNamed( xDrawPage, UNO_QUERY );
421 if( xNamed.is() )
422 pEntry->setName( xNamed->getName() );
423
424 // get title text from title presentation shape if available
425 const OUString szTitleTextShape( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.presentation.TitleTextShape") );
426 const OUString szIsEmptyPresObj( RTL_CONSTASCII_USTRINGPARAM("IsEmptyPresentationObject") );
427
428 sal_Int32 nShapeCount = xDrawPage->getCount();
429 sal_Int32 nShape;
430 for( nShape = 0; nShape < nShapeCount; nShape++ )
431 {
432 Reference< XShape > xShape;
433 xDrawPage->getByIndex( nShape ) >>= xShape;
434
435 if( xShape.is() && xShape->getShapeType() == szTitleTextShape )
436 {
437 Reference< XPropertySet > xPropSet( xShape, UNO_QUERY );
438 if( xPropSet.is() )
439 {
440 sal_Bool bIsEmpty = true;
441 xPropSet->getPropertyValue( szIsEmptyPresObj ) >>= bIsEmpty;
442
443 if( !bIsEmpty )
444 {
445 Reference< XText > xText( xShape, UNO_QUERY );
446 if( xText.is() )
447 {
448 pEntry->setTitle( xText->getString() );
449 }
450 }
451 }
452 break;
453 }
454 }
455
456 // get notes text if available
457 Reference< XPresentationPage > xPresPage( xDrawPage, UNO_QUERY );
458 if( xPresPage.is() )
459 {
460 Reference< XDrawPage > xNotesPage( xPresPage->getNotesPage() );
461
462 const OUString szNotesShape( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.presentation.NotesShape") );
463
464 nShapeCount = xNotesPage->getCount();
465 for( nShape = 0; nShape < nShapeCount; nShape++ )
466 {
467 Reference< XShape > xShape;
468 xNotesPage->getByIndex( nShape ) >>= xShape;
469
470 if( xShape.is() && (xShape->getShapeType() == szNotesShape) )
471 {
472 Reference< XPropertySet > xPropSet( xShape, UNO_QUERY );
473 if( xPropSet.is() )
474 {
475 sal_Bool bIsEmpty = true;
476 xPropSet->getPropertyValue( szIsEmptyPresObj ) >>= bIsEmpty;
477
478 if( !bIsEmpty )
479 {
480 Reference< XText > xText( xShape, UNO_QUERY );
481 if( xText.is() )
482 {
483 pEntry->setNotes( xText->getString() );
484 }
485 }
486 }
487 break;
488 }
489 }
490 }
491
492 // create the gif
493 Reference< XFilter > xFilter( mxGraphicExporter, UNO_QUERY );
494
495 Sequence< PropertyValue > aFilterData( 2 );
496 aFilterData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("Width") );
497 aFilterData[0].Value <<= (sal_Int32)704;
498 aFilterData[1].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("Translucent") );
499 aFilterData[1].Value <<= (sal_Bool)sal_False;
500
501 Sequence< PropertyValue > aDescriptor( 3 );
502 aDescriptor[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("FilterName") );
503 aDescriptor[0].Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM("GIF") );
504 aDescriptor[1].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("URL") );
505 aDescriptor[1].Value <<= OUString( pEntry->getTempURL() );
506 aDescriptor[2].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("FilterData") );
507 aDescriptor[2].Value <<= aFilterData;
508 mxGraphicExporter->setSourceDocument( xComp );
509 xFilter->filter( aDescriptor );
510
511 return pEntry;
512 }
513