xref: /AOO41X/main/filter/source/placeware/exporter.cxx (revision 9e0fc027f109ec4ffcb6033aeec742a099701108)
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