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