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