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 "eppt.hxx"
21 #include "epptdef.hxx"
22 #include "pptexanimations.hxx"
23 #include <o3tl/any.hxx>
24 #include <tools/globname.hxx>
25 #include <rtl/ustring.hxx>
26 #include <tools/stream.hxx>
27 #include <svx/unoapi.hxx>
28 #include <svx/svdobj.hxx>
29 #include <svx/svdoole2.hxx>
30 #include <com/sun/star/container/XIndexContainer.hpp>
31 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
32 #include <com/sun/star/drawing/FillStyle.hpp>
33 #include <com/sun/star/frame/XModel.hpp>
34 #include <com/sun/star/office/XAnnotation.hpp>
35 #include <com/sun/star/office/XAnnotationAccess.hpp>
36 #include <com/sun/star/office/XAnnotationEnumeration.hpp>
37 #include <com/sun/star/presentation/AnimationSpeed.hpp>
38 #include <com/sun/star/presentation/XPresentationSupplier.hpp>
39 #include <com/sun/star/presentation/XCustomPresentationSupplier.hpp>
40 #include <com/sun/star/geometry/RealPoint2D.hpp>
41 #include <com/sun/star/util/DateTime.hpp>
42 #include <com/sun/star/task/XStatusIndicator.hpp>
43 #include <comphelper/sequence.hxx>
44 #include <tools/zcodec.hxx>
45 #include <filter/msfilter/classids.hxx>
46 #include <filter/msfilter/msoleexp.hxx>
47 #include <filter/msfilter/msdffimp.hxx>
48 #include <filter/msfilter/svxmsbas.hxx>
49 #include <editeng/flditem.hxx>
50 #include <sfx2/docinf.hxx>
51 #include <oox/export/utils.hxx>
52 #include <oox/ole/olehelper.hxx>
53 #include <memory>
54 
55 class SfxObjectShell;
56     // complete SfxObjectShell for SaveVBA under -fsanitize=function
57 
58 using namespace com::sun::star;
59 using namespace ::com::sun::star::uno;
60 using namespace ::com::sun::star::presentation;
61 
62 using ::com::sun::star::beans::XPropertySet;
63 
64 //============================ PPTWriter ==================================
65 
PPTWriter(tools::SvRef<SotStorage> const & rSvStorage,css::uno::Reference<css::frame::XModel> const & rXModel,css::uno::Reference<css::task::XStatusIndicator> const & rXStatInd,SvMemoryStream * pVBA,sal_uInt32 nCnvrtFlags)66 PPTWriter::PPTWriter( tools::SvRef<SotStorage> const & rSvStorage,
67             css::uno::Reference< css::frame::XModel > const & rXModel,
68             css::uno::Reference< css::task::XStatusIndicator > const & rXStatInd,
69             SvMemoryStream* pVBA, sal_uInt32 nCnvrtFlags ) :
70     PPTWriterBase           ( rXModel, rXStatInd ),
71     mnCnvrtFlags            ( nCnvrtFlags ),
72     mbStatus                ( false ),
73     mnStatMaxValue          ( 0 ),
74     mnLatestStatValue       ( 0 ),
75     mnTextStyle( 0 ),
76     mbFontIndependentLineSpacing( false ),
77     mnTextSize( 0 ),
78     mrStg                   ( rSvStorage ),
79     mnVBAOleOfs             ( 0 ),
80     mpVBA                   ( pVBA ),
81     mnExEmbed               ( 0 ),
82     mpExEmbed               ( new SvMemoryStream ),
83     mnPagesWritten          ( 0 ),
84     mnTxId                  ( 0x7a2f64 ),
85     mnDiaMode               ( 0 ),
86     mnShapeMasterTitle      ( 0 ),
87     mnShapeMasterBody       ( 0 )
88 {
89 }
90 
exportPPTPre(const std::vector<css::beans::PropertyValue> & rMediaData)91 void PPTWriter::exportPPTPre( const std::vector< css::beans::PropertyValue >& rMediaData )
92 {
93     if ( !mrStg.is() )
94         return;
95 
96     if ( mXStatusIndicator.is() )
97     {
98         mbStatusIndicator = true;
99         mnStatMaxValue = ( mnPages + mnMasterPages ) * 5;
100         mXStatusIndicator->start( "PowerPoint Export", mnStatMaxValue + ( mnStatMaxValue >> 3 ) );
101     }
102 
103     SvGlobalName aGName(MSO_PPT8_CLASSID);
104     mrStg->SetClass( aGName, SotClipboardFormatId::NONE, "MS PowerPoint 97" );
105 
106     if ( !ImplCreateCurrentUserStream() )
107         return;
108 
109     mpStrm = mrStg->OpenSotStream( "PowerPoint Document" );
110     if ( !mpStrm )
111         return;
112 
113     if ( !mpPicStrm )
114         mpPicStrm = mrStg->OpenSotStream( "Pictures" );
115 
116     auto aIter = std::find_if(rMediaData.begin(), rMediaData.end(),
117         [](const css::beans::PropertyValue& rProp) { return rProp.Name == "BaseURI"; });
118     if (aIter != rMediaData.end())
119         (*aIter).Value >>= maBaseURI;
120     mpPptEscherEx.reset( new PptEscherEx( *mpStrm, maBaseURI ) );
121 }
122 
exportPPTPost()123 void PPTWriter::exportPPTPost( )
124 {
125     if ( !ImplCloseDocument() )
126         return;
127 
128     if ( mbStatusIndicator )
129     {
130         mXStatusIndicator->setText( "PowerPoint Export" );
131         sal_uInt32 nValue = mnStatMaxValue + ( mnStatMaxValue >> 3 );
132         if ( nValue > mnLatestStatValue )
133         {
134             mXStatusIndicator->setValue( nValue );
135             mnLatestStatValue = nValue;
136         }
137     }
138 
139     ImplWriteOLE();
140 
141     ImplWriteVBA();
142 
143     ImplWriteAtomEnding();
144 
145     ImplCreateDocumentSummaryInformation();
146 
147     mbStatus = true;
148 };
149 
150 static void ImplExportComments( const uno::Reference< drawing::XDrawPage >& xPage, SvMemoryStream& rBinaryTagData10Atom );
151 
ImplWriteSlide(sal_uInt32 nPageNum,sal_uInt32 nMasterNum,sal_uInt16 nMode,bool bHasBackground,Reference<XPropertySet> const & aXBackgroundPropSet)152 void PPTWriter::ImplWriteSlide( sal_uInt32 nPageNum, sal_uInt32 nMasterNum, sal_uInt16 nMode,
153                                 bool bHasBackground, Reference< XPropertySet > const & aXBackgroundPropSet )
154 {
155     Any aAny;
156 
157     const PHLayout& rLayout = GetLayout( mXPagePropSet );
158     mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_Slide | nPageNum, mpStrm->Tell() );
159     mpPptEscherEx->OpenContainer( EPP_Slide );
160     mpPptEscherEx->AddAtom( 24, EPP_SlideAtom, 2 );
161     mpStrm->WriteInt32( static_cast<sal_Int32>(rLayout.nLayout) );
162     mpStrm->WriteBytes(rLayout.nPlaceHolder, 8);    // placeholderIDs (8 parts)
163     mpStrm->WriteUInt32( nMasterNum | 0x80000000 )  // master ID (equals 0x80000000 on a master page)
164            .WriteUInt32( nPageNum + 0x100 )         // notes ID (equals null if no notes are present)
165            .WriteUInt16( nMode )
166            .WriteUInt16( 0 );                       // padword
167 
168     mnDiaMode = 0;
169     bool bVisible = true;
170     css::presentation::FadeEffect eFe = css::presentation::FadeEffect_NONE;
171 
172     if ( GetPropertyValue( aAny, mXPagePropSet, "Visible" ) )
173         aAny >>= bVisible;
174     if ( GetPropertyValue( aAny, mXPagePropSet, "Change" ) )
175     {
176         switch ( *o3tl::doAccess<sal_Int32>(aAny) )
177         {
178             case 1 :        // automatic
179                 mnDiaMode++;
180                 [[fallthrough]];
181             case 2 :        // semi-automatic
182                 mnDiaMode++;
183                 break;
184             default :
185             case 0 :        // manual
186             break;
187         }
188     }
189     if ( GetPropertyValue( aAny, mXPagePropSet, "Effect" ) )
190         aAny >>= eFe;
191 
192     sal_uInt32  nSoundRef = 0;
193     bool    bIsSound = false;
194     bool    bStopSound = false;
195     bool    bLoopSound = false;
196 
197     if ( GetPropertyValue( aAny, mXPagePropSet, "Sound" ) )
198     {
199         OUString aSoundURL;
200         if ( aAny >>= aSoundURL )
201         {
202             nSoundRef = maSoundCollection.GetId( aSoundURL );
203             bIsSound = true;
204         }
205         else
206             aAny >>= bStopSound;
207     }
208     if ( GetPropertyValue( aAny, mXPagePropSet, "LoopSound" ) )
209         aAny >>= bLoopSound;
210 
211     bool bNeedsSSSlideInfoAtom = !bVisible
212                                 || ( mnDiaMode == 2 )
213                                 || bIsSound
214                                 || bStopSound
215                                 || ( eFe != css::presentation::FadeEffect_NONE );
216     if ( bNeedsSSSlideInfoAtom )
217     {
218         sal_uInt8   nDirection = 0;
219         sal_uInt8   nTransitionType = 0;
220         sal_uInt16  nBuildFlags = 1;        // advance by mouseclick
221         sal_Int32   nSlideTime = 0;         // still has to !!!
222         sal_uInt8   nSpeed = 1;
223 
224         if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionDuration" ) )
225         {
226             css::presentation::AnimationSpeed aAs;
227             double fTransitionDuration = -1.0;
228             aAny >>= fTransitionDuration;
229 
230             if (fTransitionDuration >= 0)
231             {
232                 if (fTransitionDuration <= 0.5)
233                 {
234                     aAs = css::presentation::AnimationSpeed::AnimationSpeed_FAST;
235                 }
236                 else if (fTransitionDuration >= 1.0)
237                 {
238                     aAs = css::presentation::AnimationSpeed::AnimationSpeed_SLOW;
239                 }
240                 else
241                 {
242                     aAs = css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM;
243                 }
244             }
245             else
246                 aAs = css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM;
247 
248             nSpeed = static_cast<sal_uInt8>(aAs);
249         }
250         sal_Int16 nTT = 0;
251         if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionType" )
252             && ( aAny >>= nTT ) )
253         {
254             sal_Int16 nTST = 0;
255             if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionSubtype" )
256                 && ( aAny >>= nTST ) )
257                 nTransitionType = GetTransition( nTT, nTST, eFe, 0, nDirection );
258 
259         }
260         if ( !nTransitionType )
261             nTransitionType = GetTransition( eFe, nDirection );
262         if ( mnDiaMode == 2 )                                   // automatic ?
263             nBuildFlags |= 0x400;
264         if ( !bVisible )
265             nBuildFlags |= 4;
266         if ( bIsSound )
267             nBuildFlags |= 16;
268         if ( bLoopSound )
269             nBuildFlags |= 64;
270         if ( bStopSound )
271             nBuildFlags |= 256;
272 
273         if ( GetPropertyValue( aAny, mXPagePropSet, "Duration" ) )// duration of this slide
274             nSlideTime = *o3tl::doAccess<sal_Int32>(aAny) << 10;        // in ticks
275 
276         mpPptEscherEx->AddAtom( 16, EPP_SSSlideInfoAtom );
277         mpStrm->WriteInt32( nSlideTime )       // standtime in ticks
278                .WriteUInt32( nSoundRef )
279                .WriteUChar( nDirection )
280                .WriteUChar( nTransitionType )
281                .WriteUInt16( nBuildFlags )
282                .WriteUChar( nSpeed )
283                .WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
284     }
285 
286     ImplCreateHeaderFooters( mXPagePropSet );
287 
288     EscherSolverContainer aSolverContainer;
289     mpPptEscherEx->OpenContainer( EPP_PPDrawing );
290     mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
291     mpPptEscherEx->EnterGroup(nullptr,nullptr);
292     ImplWritePage( rLayout, aSolverContainer, NORMAL, false, nPageNum );    // the shapes of the pages are created in the PPT document
293     mpPptEscherEx->LeaveGroup();
294 
295     if ( bHasBackground )
296         ImplWriteBackground( aXBackgroundPropSet );
297     else
298     {
299         mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
300         mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
301                                  ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
302         EscherPropertyContainer aPropOpt;
303         aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, PPTtoEMU( maDestPageSize.Width ) );
304         aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, PPTtoEMU( maDestPageSize.Width ) );
305         aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
306         aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
307         aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow );
308         aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 );                // if true, this is the background shape
309         aPropOpt.Commit( *mpStrm );
310         mpPptEscherEx->CloseContainer();    // ESCHER_SpContainer
311     }
312 
313     aSolverContainer.WriteSolver( *mpStrm );
314 
315     mpPptEscherEx->CloseContainer();    // ESCHER_DgContainer
316     mpPptEscherEx->CloseContainer();    // EPP_Drawing
317     mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
318     mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
319 
320     SvMemoryStream aBinaryTagData10Atom;
321     ImplExportComments( mXDrawPage, aBinaryTagData10Atom );
322     SvMemoryStream amsofbtAnimGroup;
323     ppt::AnimationExporter aExporter( aSolverContainer, maSoundCollection );
324     aExporter.doexport( mXDrawPage, amsofbtAnimGroup );
325     sal_uInt32 nmsofbtAnimGroupSize = amsofbtAnimGroup.Tell();
326     if ( nmsofbtAnimGroupSize )
327     {
328         {
329             EscherExAtom aMagic2( aBinaryTagData10Atom, 0x2eeb );
330             aBinaryTagData10Atom.WriteUInt32( 0x01c45df9 )
331                                 .WriteUInt32( 0xe1471b30 );
332         }
333         {
334             EscherExAtom aMagic( aBinaryTagData10Atom, 0x2b00 );
335             aBinaryTagData10Atom.WriteUInt32( 0 );
336         }
337         aBinaryTagData10Atom.WriteBytes(amsofbtAnimGroup.GetData(), amsofbtAnimGroup.Tell());
338         {
339             EscherExContainer aMagic2( aBinaryTagData10Atom, 0x2b02 );
340         }
341     }
342     if ( aBinaryTagData10Atom.Tell() )
343     {
344         EscherExContainer aProgTags     ( *mpStrm, EPP_ProgTags );
345         EscherExContainer aProgBinaryTag( *mpStrm, EPP_ProgBinaryTag );
346         {
347             EscherExAtom aCString( *mpStrm, EPP_CString );
348             mpStrm->WriteUInt32( 0x5f005f )
349                    .WriteUInt32( 0x50005f )
350                    .WriteUInt32( 0x540050 )
351                    .WriteUInt16( 0x31 )
352                    .WriteUInt16( 0x30 );
353         }
354         {
355             EscherExAtom aBinaryTagData( *mpStrm, EPP_BinaryTagData );
356             mpStrm->WriteBytes(aBinaryTagData10Atom.GetData(), aBinaryTagData10Atom.Tell());
357         }
358     }
359     mpPptEscherEx->CloseContainer();    // EPP_Slide
360 }
361 
ImplWriteSlideMaster(sal_uInt32 nPageNum,Reference<XPropertySet> const & aXBackgroundPropSet)362 void PPTWriter::ImplWriteSlideMaster( sal_uInt32 nPageNum, Reference< XPropertySet > const & aXBackgroundPropSet )
363 {
364     if (!aXBackgroundPropSet)
365         return;
366     mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_MainMaster | nPageNum, mpStrm->Tell() );
367     mpPptEscherEx->OpenContainer( EPP_MainMaster );
368     mpPptEscherEx->AddAtom( 24, EPP_SlideAtom, 2 );
369     mpStrm->WriteInt32( static_cast<sal_Int32>(EppLayout::TITLEANDBODYSLIDE) )  // slide layout -> title and body slide
370            .WriteUChar( 1 ).WriteUChar( 2 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 )     // placeholderID
371            .WriteUInt32( 0 )        // master ID (equals null at a master page)
372            .WriteUInt32( 0 )        // notes ID (equals null if no notes are present)
373            .WriteUInt16( 0 )        // Bit 1: Follow master objects, Bit 2: Follow master scheme, Bit 3: Follow master background
374            .WriteUInt16( 0 );       // padword
375 
376     mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
377     mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
378     mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
379     mpStrm->WriteUInt32( 0xff0000 ).WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x00ffff ).WriteUInt32( 0x0099ff ).WriteUInt32( 0xffff00 ).WriteUInt32( 0x0000ff ).WriteUInt32( 0x969696 );
380     mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
381     mpStrm->WriteUInt32( 0xccffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x336666 ).WriteUInt32( 0x008080 ).WriteUInt32( 0x339933 ).WriteUInt32( 0x000080 ).WriteUInt32( 0xcc3300 ).WriteUInt32( 0x66ccff );
382     mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
383     mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x333333 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xdddddd ).WriteUInt32( 0x808080 ).WriteUInt32( 0x4d4d4d ).WriteUInt32( 0xeaeaea );
384     mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
385     mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x66ccff ).WriteUInt32( 0xff0000 ).WriteUInt32( 0xcc00cc ).WriteUInt32( 0xc0c0c0 );
386     mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
387     mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xc0c0c0 ).WriteUInt32( 0xff6600 ).WriteUInt32( 0x0000ff ).WriteUInt32( 0x009900 );
388     mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
389     mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xff9933 ).WriteUInt32( 0xccff99 ).WriteUInt32( 0xcc00cc ).WriteUInt32( 0xb2b2b2 );
390 
391     for ( int nInstance = EPP_TEXTTYPE_Title; nInstance <= EPP_TEXTTYPE_QuarterBody; nInstance++ )
392     {
393         if ( nInstance == EPP_TEXTTYPE_notUsed )
394             continue;
395 
396         // the auto color is dependent to the page background,so we have to set a page that is in the right context
397         if ( nInstance == EPP_TEXTTYPE_Notes )
398             (void)GetPageByIndex(0, NOTICE);
399         else
400             (void)GetPageByIndex(0, MASTER);
401 
402         mpPptEscherEx->BeginAtom();
403 
404         bool bSimpleText = false;
405 
406         mpStrm->WriteUInt16( 5 );                           // paragraph count
407 
408         for ( sal_uInt16 nLev = 0; nLev < 5; nLev++ )
409         {
410             if ( nInstance >= EPP_TEXTTYPE_CenterBody )
411             {
412                 bSimpleText = true;
413                 mpStrm->WriteUInt16( nLev );
414             }
415             mpStyleSheet->mpParaSheet[ nInstance ]->Write( *mpStrm, nLev, bSimpleText, mXPagePropSet );
416             mpStyleSheet->mpCharSheet[ nInstance ]->Write( *mpStrm, nLev, bSimpleText, mXPagePropSet );
417         }
418         mpPptEscherEx->EndAtom( EPP_TxMasterStyleAtom, 0, nInstance );
419     }
420     GetPageByIndex( nPageNum, MASTER );
421 
422     EscherSolverContainer aSolverContainer;
423 
424     mpPptEscherEx->OpenContainer( EPP_PPDrawing );
425     mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
426 
427     mpPptEscherEx->EnterGroup(nullptr,nullptr);
428     ImplWritePage( GetLayout( 0 ), aSolverContainer, MASTER, true );    // the shapes of the pages are created in the PPT document
429     mpPptEscherEx->LeaveGroup();
430 
431     ImplWriteBackground( aXBackgroundPropSet );
432 
433     aSolverContainer.WriteSolver( *mpStrm );
434 
435     mpPptEscherEx->CloseContainer();    // ESCHER_DgContainer
436     mpPptEscherEx->CloseContainer();    // EPP_Drawing
437     mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
438     mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
439 
440     if ( aBuExMasterStream.Tell() )
441     {
442         ImplProgTagContainer( mpStrm.get(), &aBuExMasterStream );
443     }
444     mpPptEscherEx->CloseContainer();    // EPP_MainMaster
445 };
446 
~PPTWriter()447 PPTWriter::~PPTWriter()
448 {
449     mpExEmbed.reset();
450     mpPptEscherEx.reset();
451     mpCurUserStrm.clear();
452     mpPicStrm.clear();
453     mpStrm.clear();
454     maStyleSheetList.clear();
455     maExOleObj.clear();
456     if ( mbStatusIndicator )
457         mXStatusIndicator->end();
458 }
459 
ImplCreateCurrentUserStream()460 bool PPTWriter::ImplCreateCurrentUserStream()
461 {
462     mpCurUserStrm = mrStg->OpenSotStream( "Current User" );
463     if ( !mpCurUserStrm )
464         return false;
465     char pUserName[] = "Current User";
466     sal_uInt32 nLenOfUserName = strlen( pUserName );
467     sal_uInt32 nSizeOfRecord = 0x14 + ( ( nLenOfUserName + 4 ) & ~ 3 );
468 
469     mpCurUserStrm->WriteUInt16( 0 ).WriteUInt16( EPP_CurrentUserAtom ).WriteUInt32( nSizeOfRecord );
470     mpCurUserStrm->WriteUInt32( 0x14 )                  // Len
471                   .WriteUInt32( 0xe391c05f );           // Magic
472 
473     sal_uInt32 nEditPos = mpCurUserStrm->Tell();
474     mpCurUserStrm->WriteUInt32( 0x0 )                   // OffsetToCurrentEdit;
475                   .WriteUInt16( nLenOfUserName )
476                   .WriteUInt16( 0x3f4 )                 // DocFileVersion
477                   .WriteUChar( 3 )                      // MajorVersion
478                   .WriteUChar( 0 )                      // MinorVersion
479                   .WriteUInt16( 0 );                    // Pad Word
480     pUserName[ nLenOfUserName ] = 8;
481     mpCurUserStrm->WriteBytes(pUserName, nLenOfUserName + 1);
482     for ( sal_uInt32 i = 0x15 + nLenOfUserName; i < nSizeOfRecord; i++ )
483     {
484         mpCurUserStrm->WriteUChar( 0 );                 // pad bytes
485     }
486     mpCurUserStrm->Seek( nEditPos );
487     return true;
488 };
489 
ImplCreateDocumentSummaryInformation()490 void PPTWriter::ImplCreateDocumentSummaryInformation()
491 {
492     uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
493         mXModel, uno::UNO_QUERY_THROW);
494     uno::Reference<document::XDocumentProperties> xDocProps(
495         xDPS->getDocumentProperties());
496 
497     if (!xDocProps.is())
498         return;
499 
500     // no idea what this is...
501     static const sal_Int8 aGuid[ 0x52 ] =
502     {
503         0x4e, 0x00, 0x00, 0x00,
504         '{',0,'D',0,'B',0,'1',0,'A',0,'C',0,'9',0,'6',0,'4',0,'-',0,
505         'E',0,'3',0,'9',0,'C',0,'-',0,'1',0,'1',0,'D',0,'2',0,'-',0,
506         'A',0,'1',0,'E',0,'F',0,'-',0,'0',0,'0',0,'6',0,'0',0,'9',0,
507         '7',0,'D',0,'A',0,'5',0,'6',0,'8',0,'9',0,'}',0
508     };
509     uno::Sequence<sal_Int8> aGuidSeq(aGuid, 0x52);
510 
511     SvMemoryStream  aHyperBlob;
512     ImplCreateHyperBlob( aHyperBlob );
513 
514     auto nHyperLength = static_cast<sal_Int32>(aHyperBlob.Tell());
515     const sal_Int8* pBlob(
516         static_cast<const sal_Int8*>(aHyperBlob.GetData()));
517     auto aHyperSeq = comphelper::arrayToSequence<sal_Int8>(pBlob, nHyperLength);
518 
519     if ( mnCnvrtFlags & 0x8000 )
520     {
521         uno::Sequence<sal_Int8> aThumbSeq;
522         if ( GetPageByIndex( 0, NORMAL ) && ImplGetPropertyValue( mXPagePropSet, "PreviewBitmap" ) )
523         {
524             aThumbSeq = *o3tl::doAccess<uno::Sequence<sal_Int8>>(mAny);
525         }
526         sfx2::SaveOlePropertySet( xDocProps, mrStg.get(),
527                 &aThumbSeq, &aGuidSeq, &aHyperSeq);
528     }
529     else
530     {
531         sfx2::SaveOlePropertySet( xDocProps, mrStg.get(),
532                 nullptr, &aGuidSeq, &aHyperSeq );
533     }
534 }
535 
ImplWriteExtParaHeader(SvMemoryStream & rSt,sal_uInt32 nRef,sal_uInt32 nInstance,sal_uInt32 nSlideId)536 void PPTWriter::ImplWriteExtParaHeader( SvMemoryStream& rSt, sal_uInt32 nRef, sal_uInt32 nInstance, sal_uInt32 nSlideId )
537 {
538     if ( rSt.Tell() )
539     {
540         aBuExOutlineStream.WriteUInt32( ( EPP_PST_ExtendedParagraphHeaderAtom << 16 )
541                                         | ( nRef << 4 ) )
542                            .WriteUInt32( 8 )
543                            .WriteUInt32( nSlideId )
544                            .WriteUInt32( nInstance );
545         aBuExOutlineStream.WriteBytes(rSt.GetData(), rSt.Tell());
546     }
547 }
548 
ImplCreateHeaderFooterStrings(SvStream & rStrm,css::uno::Reference<css::beans::XPropertySet> const & rXPagePropSet)549 void PPTWriter::ImplCreateHeaderFooterStrings( SvStream& rStrm, css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet )
550 {
551     if ( !rXPagePropSet.is() )
552         return;
553 
554     OUString aString;
555     css::uno::Any aAny;
556     if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "HeaderText", true ) )
557     {
558         if ( aAny >>= aString )
559             PPTWriter::WriteCString( rStrm, aString, 1 );
560     }
561     if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "FooterText", true ) )
562     {
563         if ( aAny >>= aString )
564             PPTWriter::WriteCString( rStrm, aString, 2 );
565     }
566     if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "DateTimeText", true ) )
567     {
568         if ( aAny >>= aString )
569             PPTWriter::WriteCString( rStrm, aString );
570     }
571 }
572 
ImplCreateHeaderFooters(css::uno::Reference<css::beans::XPropertySet> const & rXPagePropSet)573 void PPTWriter::ImplCreateHeaderFooters( css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet )
574 {
575     if ( !rXPagePropSet.is() )
576         return;
577 
578     bool bVal = false;
579     sal_uInt32 nVal = 0;
580     css::uno::Any aAny;
581     if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsHeaderVisible", true ) )
582     {
583         if ( ( aAny >>= bVal ) && bVal )
584             nVal |= 0x100000;
585     }
586     if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsFooterVisible", true ) )
587     {
588         if ( ( aAny >>= bVal ) && bVal )
589             nVal |= 0x200000;
590     }
591     if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsDateTimeVisible", true ) )
592     {
593         if ( ( aAny >>= bVal ) && bVal )
594             nVal |= 0x010000;
595     }
596     if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsPageNumberVisible", true ) )
597     {
598         if ( ( aAny >>= bVal ) && bVal )
599             nVal |= 0x080000;
600     }
601     if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsDateTimeFixed", true ) )
602     {
603         if ( ( aAny >>= bVal ) && !bVal )
604             nVal |= 0x20000;
605         else
606             nVal |= 0x40000;
607     }
608     if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "DateTimeFormat", true ) )
609     {
610         sal_Int32 nFormat = *o3tl::doAccess<sal_Int32>(aAny);
611         SvxDateFormat eDateFormat = static_cast<SvxDateFormat>( nFormat & 0xf );
612         SvxTimeFormat eTimeFormat = static_cast<SvxTimeFormat>( ( nFormat >> 4 ) & 0xf );
613         switch( eDateFormat )
614         {
615             case SvxDateFormat::F :
616                 nFormat = 1;
617             break;
618             case SvxDateFormat::D :
619                 nFormat = 2;
620             break;
621             case SvxDateFormat::C :
622                 nFormat = 4;
623             break;
624             default:
625             case SvxDateFormat::A :
626                 nFormat = 0;
627         }
628         switch( eTimeFormat )
629         {
630             case SvxTimeFormat::HH24_MM :
631                 nFormat = 9;
632             break;
633             case SvxTimeFormat::HH12_MM :
634                 nFormat = 11;
635             break;
636             case SvxTimeFormat::HH24_MM_SS :
637                 nFormat = 10;
638             break;
639             case SvxTimeFormat::HH12_MM_SS :
640                 nFormat = 12;
641             break;
642             default:
643                 break;
644         }
645         nVal |= nFormat;
646     }
647 
648     mpPptEscherEx->OpenContainer( EPP_HeadersFooters );
649     mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
650     mpStrm->WriteUInt32( nVal );
651     ImplCreateHeaderFooterStrings( *mpStrm, rXPagePropSet );
652     mpPptEscherEx->CloseContainer();
653 }
654 
ImplCreateDocument()655 bool PPTWriter::ImplCreateDocument()
656 {
657     sal_uInt32 i;
658     sal_uInt16 nSlideType = EPP_SLIDESIZE_TYPECUSTOM;
659 
660     sal_uInt32 nWidth = maDestPageSize.Width;
661     sal_uInt32 nHeight = maDestPageSize.Height;
662 
663     if ( ( nWidth == 0x1680 ) && ( nHeight == 0x10e0 ) )
664         nSlideType = EPP_SLIDESIZE_TYPEONSCREEN;
665     else if ( ( nWidth == 0x1200 ) && ( nHeight == 0x240 ) )
666         nSlideType = EPP_SLIDESIZE_TYPEBANNER;
667     else if ( ( nWidth == 0x1950 ) && ( nHeight == 0x10e0 ) )
668         nSlideType = EPP_SLIDESIZE_TYPE35MM;
669     else if ( ( nWidth == 0x1860 ) && ( nHeight == 0x10e0 ) )
670         nSlideType = EPP_SLIDESIZE_TYPEA4PAPER;
671 
672     mpPptEscherEx->OpenContainer( EPP_Document );
673     // CREATE DOCUMENT ATOM
674     mpPptEscherEx->AddAtom( 40, EPP_DocumentAtom, 1 );
675     mpStrm->WriteUInt32( nWidth )                           // Slide Size in Master coordinates X
676            .WriteUInt32( nHeight )                          //   "     "   "    "        "      Y
677            .WriteInt32( maNotesPageSize.Width )     // Notes Page Size                  X
678            .WriteInt32( maNotesPageSize.Height )    //   "     "   "                    Y
679            .WriteInt32( 1 ).WriteInt32( 2 );            // the scale used when the Powerpoint document is embedded. the default is 1:2
680     mpPptEscherEx->InsertPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY, mpStrm->Tell() );
681     mpStrm->WriteUInt32( 0 )                        // Reference to NotesMaster ( 0 if none );
682            .WriteUInt32( 0 )                        // Reference to HandoutMaster ( 0 if none );
683            .WriteInt16( 1 )                         // Number of the first slide;
684            .WriteUInt16( nSlideType )                           // Size of the document slides ( default: EPP_SLIDESIZETYPEONSCREEN )
685            .WriteUChar( 0 )                         // bool1 indicates if document was saved with embedded true type fonts
686            .WriteUChar( 0 )                         // bool1 indicates if the placeholders on the title slide are omitted
687            .WriteUChar( 0 )                         // bool1 right to left ( flag for Bidi version )
688            .WriteUChar( 1 );                            // bool1 visibility of comments shapes
689 
690     mpPptEscherEx->PtInsert( EPP_Persist_Document, mpStrm->Tell() );
691 
692     mpPptEscherEx->OpenContainer( EPP_HeadersFooters, 3 );  //Master footer (default)
693     mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
694     mpStrm->WriteUInt32( 0x25000d );
695     if ( GetPageByIndex( 0, MASTER ) )
696         ImplCreateHeaderFooterStrings( *mpStrm, mXPagePropSet );
697     mpPptEscherEx->CloseContainer();
698     mpPptEscherEx->OpenContainer( EPP_HeadersFooters, 4 );  //NotesMaster footer (default)
699     mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
700     mpStrm->WriteUInt32( 0x3d000d );
701     if ( GetPageByIndex( 0, NOTICE ) )
702         ImplCreateHeaderFooterStrings( *mpStrm, mXPagePropSet );
703     mpPptEscherEx->CloseContainer();
704 
705     mpPptEscherEx->OpenContainer( EPP_SlideListWithText );      // animation information for the slides
706 
707     for ( i = 0; i < mnPages; i++ )
708     {
709         mpPptEscherEx->AddAtom( 20, EPP_SlidePersistAtom );
710         mpPptEscherEx->InsertPersistOffset( EPP_MAINSLIDE_PERSIST_KEY | i, mpStrm->Tell() );
711         mpStrm->WriteUInt32( 0 )                                // psrReference - logical reference to the slide persist object ( EPP_MAINSLIDE_PERSIST_KEY )
712                .WriteUInt32( 4 )                                // flags - only bit 3 used, if set then slide contains shapes other than placeholders
713                .WriteInt32( 0 )                                     // numberTexts - number of placeholder texts stored with the persist object.  Allows to display outline view without loading the slide persist objects
714                .WriteInt32( i + 0x100 )                             // slideId - Unique slide identifier, used for OLE link monikers for example
715                .WriteUInt32( 0 );                               // reserved, usually 0
716 
717         if ( !GetPageByIndex( i, NORMAL ) )                     // very exciting: once again through all pages
718             return false;
719         SetCurrentStyleSheet( GetMasterIndex( NORMAL ) );
720 
721         css::uno::Reference< css::container::XNamed >
722             aXName( mXDrawPage, css::uno::UNO_QUERY );
723 
724         if ( aXName.is() )
725             maSlideNameList.push_back( aXName->getName() );
726         else
727             maSlideNameList.emplace_back( );
728     }
729     mpPptEscherEx->CloseContainer();    // EPP_SlideListWithText
730 
731     mpPptEscherEx->OpenContainer( EPP_SlideListWithText, 2 );   // animation information for the notes
732     for( i = 0; i < mnPages; i++ )
733     {
734         mpPptEscherEx->AddAtom( 20, EPP_SlidePersistAtom );
735         mpPptEscherEx->InsertPersistOffset( EPP_MAINNOTES_PERSIST_KEY | i, mpStrm->Tell() );
736         mpStrm->WriteUInt32( 0 )
737                .WriteUInt32( 4 )
738                .WriteInt32( 0 )
739                .WriteInt32( i + 0x100 )
740                .WriteUInt32( 0 );
741     }
742     mpPptEscherEx->CloseContainer();        // EPP_SlideListWithText
743 
744     css::uno::Reference< css::presentation::XPresentationSupplier >
745         aXPresSupplier( mXModel, css::uno::UNO_QUERY );
746     if ( aXPresSupplier.is() )
747     {
748         css::uno::Reference< css::presentation::XPresentation > aXPresentation( aXPresSupplier->getPresentation() );
749         if ( aXPresentation.is() )
750         {
751             mXPropSet.set( aXPresentation, css::uno::UNO_QUERY );
752             if ( mXPropSet.is() )
753             {
754                 OUString aCustomShow;
755                 sal_uInt32 const nPenColor = 0x1000000;
756                 sal_Int32 const  nRestartTime = 0x7fffffff;
757                 sal_Int16   nStartSlide = 0;
758                 sal_Int16   nEndSlide = 0;
759                 sal_uInt32  nFlags = 0;             // Bit 0:   Auto advance
760                                                     // Bit 1    Skip builds ( do not allow slide effects )
761                                                     // Bit 2    Use slide range
762                                                     // Bit 3    Use named show
763                                                     // Bit 4    Browse mode on
764                                                     // Bit 5    Kiosk mode on
765                                                     // Bit 6    Skip narration
766                                                     // Bit 7    loop continuously
767                                                     // Bit 8    show scrollbar
768 
769                 if ( ImplGetPropertyValue( "CustomShow" ) )
770                 {
771                     aCustomShow = *o3tl::doAccess<OUString>(mAny);
772                     if ( !aCustomShow.isEmpty() )
773                     {
774                         nFlags |= 8;
775                     }
776                 }
777                 if ( ( nFlags & 8 ) == 0 )
778                 {
779                     if ( ImplGetPropertyValue( "FirstPage" ) )
780                     {
781                         auto aSlideName = o3tl::doAccess<OUString>(mAny);
782 
783                         std::vector<OUString>::const_iterator pIter = std::find(
784                                     maSlideNameList.begin(),maSlideNameList.end(), *aSlideName);
785 
786                         if (pIter != maSlideNameList.end())
787                         {
788                             nStartSlide = pIter - maSlideNameList.begin() + 1;
789                             nFlags |= 4;
790                             nEndSlide = static_cast<sal_uInt16>(mnPages);
791                         }
792                     }
793                 }
794 
795                 if ( ImplGetPropertyValue( "IsAutomatic" ) )
796                 {
797                     bool bBool = false;
798                     mAny >>= bBool;
799                     if ( !bBool )
800                         nFlags |= 1;
801                 }
802 
803                 if ( ImplGetPropertyValue( "IsEndless" ) )
804                 {
805                     bool bBool = false;
806                     mAny >>= bBool;
807                     if ( bBool )
808                         nFlags |= 0x80;
809                 }
810                 if ( ImplGetPropertyValue( "IsFullScreen" ) )
811                 {
812                     bool bBool = false;
813                     mAny >>= bBool;
814                     if ( !bBool )
815                         nFlags |= 0x11;
816                 }
817 
818                 mpPptEscherEx->AddAtom( 80, EPP_SSDocInfoAtom, 1 );
819                 mpStrm->WriteUInt32( nPenColor ).WriteInt32( nRestartTime ).WriteInt16( nStartSlide ).WriteInt16( nEndSlide );
820 
821                 sal_uInt32 nCustomShowNameLen = aCustomShow.getLength();
822                 if ( nCustomShowNameLen > 31 )
823                     nCustomShowNameLen = 31;
824                 if ( nCustomShowNameLen )       // named show identifier
825                 {
826                     const sal_Unicode* pCustomShow = aCustomShow.getStr();
827                     for ( i = 0; i < nCustomShowNameLen; i++ )
828                     {
829                         mpStrm->WriteUInt16( pCustomShow[ i ] );
830                     }
831                 }
832                 for ( i = nCustomShowNameLen; i < 32; i++, mpStrm->WriteUInt16( 0 ) ) ;
833 
834                 mpStrm->WriteUInt32( nFlags );
835                 css::uno::Reference< css::presentation::XCustomPresentationSupplier > aXCPSup( mXModel, css::uno::UNO_QUERY );
836                 if ( aXCPSup.is() )
837                 {
838                     css::uno::Reference< css::container::XNameContainer > aXCont( aXCPSup->getCustomPresentations() );
839                     if ( aXCont.is() )
840                     {
841                         const css::uno::Sequence< OUString> aNameSeq( aXCont->getElementNames() );
842                         if ( aNameSeq.hasElements() )
843                         {
844                             mpPptEscherEx->OpenContainer( EPP_NamedShows );
845                             sal_uInt32 nCustomShowIndex = 0;
846                             for( OUString const & customShowName : aNameSeq )
847                             {
848                                 if ( !customShowName.isEmpty() )
849                                 {
850                                     mpPptEscherEx->OpenContainer( EPP_NamedShow, nCustomShowIndex++ );
851 
852                                     sal_uInt32 nNamedShowLen = customShowName.getLength();
853                                     if ( nNamedShowLen > 31 )
854                                         nNamedShowLen = 31;
855                                     mpPptEscherEx->AddAtom( nNamedShowLen << 1, EPP_CString );
856                                     const sal_Unicode* pCustomShowName = customShowName.getStr();
857                                     for ( sal_uInt32 k = 0; k < nNamedShowLen; ++k )
858                                         mpStrm->WriteUInt16( pCustomShowName[ k ] );
859                                     mAny = aXCont->getByName( customShowName );
860                                     css::uno::Reference< css::container::XIndexContainer > aXIC;
861                                     if ( mAny >>= aXIC )
862                                     {
863                                         mpPptEscherEx->BeginAtom();
864 
865                                         sal_Int32 nSlideCount = aXIC->getCount();
866                                         for ( sal_Int32 j = 0; j < nSlideCount; j++ )   // number of slides
867                                         {
868                                             mAny = aXIC->getByIndex( j );
869                                             css::uno::Reference< css::drawing::XDrawPage > aXDrawPage;
870                                             if ( mAny >>= aXDrawPage )
871                                             {
872                                                 css::uno::Reference< css::container::XNamed > aXName( aXDrawPage, css::uno::UNO_QUERY );
873                                                 if ( aXName.is() )
874                                                 {
875                                                     OUString aSlideName( aXName->getName() );
876                                                     std::vector<OUString>::const_iterator pIter = std::find(
877                                                         maSlideNameList.begin(),maSlideNameList.end(),aSlideName);
878 
879                                                     if (pIter != maSlideNameList.end())
880                                                     {
881                                                         sal_uInt32 nPageNumber = pIter - maSlideNameList.begin();
882                                                         mpStrm->WriteUInt32( nPageNumber + 0x100 ); // unique slide id
883                                                     }
884                                                 }
885                                             }
886                                         }
887                                         mpPptEscherEx->EndAtom( EPP_NamedShowSlides );
888                                     }
889                                     mpPptEscherEx->CloseContainer();            // EPP_NamedShow
890                                 }
891                             }
892                             mpPptEscherEx->CloseContainer();                // EPP_NamedShows
893                         }
894                     }
895                 }
896             }
897         }
898     }
899     mpPptEscherEx->AddAtom( 0, EPP_EndDocument );
900     mpPptEscherEx->CloseContainer();    // EPP_Document
901     return true;
902 };
903 
ImplCreateHyperBlob(SvMemoryStream & rStrm)904 void PPTWriter::ImplCreateHyperBlob( SvMemoryStream& rStrm )
905 {
906     sal_uInt32 nCurrentOfs, nParaOfs, nParaCount = 0;
907 
908     nParaOfs = rStrm.Tell();
909     rStrm.WriteUInt32( 0 );         // property size
910     rStrm.WriteUInt32( 0 );         // property count
911 
912     for ( const auto& rHyperlink : maHyperlink )
913     {
914         nParaCount += 6;
915         rStrm  .WriteUInt32( 3 )    // Type VT_I4
916                .WriteUInt32( 7 )    // (VTI4 - Private1)
917                .WriteUInt32( 3 )    // Type VT_I4
918                .WriteUInt32( 6 )    // (VTI4 - Private2)
919                .WriteUInt32( 3 )    // Type VT_I4
920                .WriteUInt32( 0 );   // (VTI4 - Private3)
921 
922         // INFO
923         // HIWORD:  = 0 : do not change anything
924         //          = 1 : replace the hyperlink with the target and subaddress in the following two VTLPWSTR
925         //          = 2 : delete the hyperlink
926         // LOWORD:  = 0 : graphic shown as background (link)
927         //          = 1 : graphic shown as shape (link)
928         //          = 2 : graphic is used to fill a shape
929         //          = 3 : graphic used to fill a shape outline (future use)
930         //          = 4 : hyperlink attached to a shape
931         //          = 5 :    "         "      " " (Word) field
932         //          = 6 :    "         "      " " (Excel) range
933         //          = 7 :    "         "      " " (PPT) text range
934         //          = 8 :    "         "      " " (Project) task
935 
936         sal_Int32 nUrlLen = rHyperlink.aURL.getLength();
937         const OUString& rUrl = rHyperlink.aURL;
938 
939         sal_uInt32 const nInfo = 7;
940 
941         rStrm  .WriteUInt32( 3 )    // Type VT_I4
942                .WriteUInt32( nInfo );       // Info
943 
944         switch( rHyperlink.nType & 0xff )
945         {
946             case 1 :        // click action to slidenumber
947             {
948                 rStrm.WriteUInt32( 0x1f ).WriteUInt32( 1 ).WriteUInt32( 0 );    // path
949                 rStrm.WriteUInt32( 0x1f ).WriteUInt32( nUrlLen + 1 );
950                 for ( sal_Int32 i = 0; i < nUrlLen; i++ )
951                 {
952                     rStrm.WriteUInt16( rUrl[ i ] );
953                 }
954                 rStrm.WriteUInt16( 0 );
955             }
956             break;
957             case 2 :
958             {
959                 sal_Int32 i;
960 
961                 rStrm  .WriteUInt32( 0x1f )
962                        .WriteUInt32( nUrlLen + 1 );
963                 for ( i = 0; i < nUrlLen; i++ )
964                 {
965                     rStrm.WriteUInt16( rUrl[ i ] );
966                 }
967                 if ( ! ( i & 1 ) )
968                     rStrm.WriteUInt16( 0 );
969                 rStrm  .WriteUInt16( 0 )
970                        .WriteUInt32( 0x1f )
971                        .WriteUInt32( 1 )
972                        .WriteUInt32( 0 );
973             }
974             break;
975         }
976     }
977     nCurrentOfs = rStrm.Tell();
978     rStrm.Seek( nParaOfs );
979     rStrm.WriteUInt32( nCurrentOfs - ( nParaOfs + 4 ) );
980     rStrm.WriteUInt32( nParaCount );
981     rStrm.Seek( nCurrentOfs );
982 }
983 
ImplCreateMainNotes()984 bool PPTWriter::ImplCreateMainNotes()
985 {
986     EscherSolverContainer aSolverContainer;
987 
988     mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_MainNotes, mpStrm->Tell() );
989     mpPptEscherEx->OpenContainer( EPP_Notes );
990     mpPptEscherEx->AddAtom( 8, EPP_NotesAtom, 1 );
991     mpStrm->WriteUInt32( 0x80000001 )                                               // Number that identifies this slide
992            .WriteUInt32( 0 );                                                       // follow nothing
993     mpPptEscherEx->OpenContainer( EPP_PPDrawing );
994     mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
995     mpPptEscherEx->EnterGroup(nullptr,nullptr);
996 
997     ImplWritePage( GetLayout( 20 ), aSolverContainer, NOTICE, true );
998 
999     mpPptEscherEx->LeaveGroup();
1000     mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1001     mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
1002     EscherPropertyContainer aPropOpt;
1003     aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0xffffff );                             // stock valued fill color
1004     aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0 );
1005     aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, 0x68bdde );
1006     aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, 0x8b9f8e );
1007     aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
1008     aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0 );
1009     aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow );
1010     aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 );                            // if true, this is the background shape
1011     aPropOpt.Commit( *mpStrm );
1012     mpPptEscherEx->CloseContainer();    // ESCHER_SpContainer
1013 
1014     aSolverContainer.WriteSolver( *mpStrm );
1015 
1016     mpPptEscherEx->CloseContainer();    // ESCHER_DgContainer
1017     mpPptEscherEx->CloseContainer();    // EPP_Drawing
1018     mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
1019     mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
1020     mpPptEscherEx->CloseContainer();    // EPP_Notes
1021     return true;
1022 }
1023 
getInitials(const OUString & rName)1024 static OUString getInitials( const OUString& rName )
1025 {
1026     OUStringBuffer sInitials;
1027 
1028     const sal_Unicode * pStr = rName.getStr();
1029     sal_Int32 nLength = rName.getLength();
1030 
1031     while( nLength )
1032     {
1033         // skip whitespace
1034         while( nLength && (*pStr <= ' ') )
1035         {
1036             nLength--; pStr++;
1037         }
1038 
1039         // take letter
1040         if( nLength )
1041         {
1042             sInitials.append( *pStr );
1043             nLength--; pStr++;
1044         }
1045 
1046         // skip letters until whitespace
1047         while( nLength && (*pStr > ' ') )
1048         {
1049             nLength--; pStr++;
1050         }
1051     }
1052 
1053     return sInitials.makeStringAndClear();
1054 }
1055 
ImplExportComments(const uno::Reference<drawing::XDrawPage> & xPage,SvMemoryStream & rBinaryTagData10Atom)1056 void ImplExportComments( const uno::Reference< drawing::XDrawPage >& xPage, SvMemoryStream& rBinaryTagData10Atom )
1057 {
1058     try
1059     {
1060         uno::Reference< office::XAnnotationAccess > xAnnotationAccess( xPage, uno::UNO_QUERY_THROW );
1061         uno::Reference< office::XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() );
1062 
1063         sal_Int32 nIndex = 1;
1064 
1065         while( xAnnotationEnumeration->hasMoreElements() )
1066         {
1067             EscherExContainer aComment10( rBinaryTagData10Atom, EPP_Comment10 );
1068             {
1069                 uno::Reference< office::XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement() );
1070 
1071                 geometry::RealPoint2D aRealPoint2D( xAnnotation->getPosition() );
1072                 MapMode aMapDest( MapUnit::MapInch, Point(), Fraction( 1, 576 ), Fraction( 1, 576 ) );
1073                 Point aPoint( OutputDevice::LogicToLogic( Point( static_cast< sal_Int32 >( aRealPoint2D.X * 100.0 ),
1074                     static_cast<sal_Int32>(aRealPoint2D.Y * 100.0)), MapMode(MapUnit::Map100thMM), aMapDest));
1075 
1076                 OUString sAuthor( xAnnotation->getAuthor() );
1077                 uno::Reference< text::XText > xText( xAnnotation->getTextRange() );
1078                 OUString sText( xText->getString() );
1079                 OUString sInitials( getInitials( sAuthor ) );
1080                 util::DateTime aDateTime( xAnnotation->getDateTime() );
1081                 if ( !sAuthor.isEmpty() )
1082                     PPTWriter::WriteCString( rBinaryTagData10Atom, sAuthor );
1083                 if ( !sText.isEmpty() )
1084                     PPTWriter::WriteCString( rBinaryTagData10Atom, sText, 1 );
1085                 if ( !sInitials.isEmpty() )
1086                     PPTWriter::WriteCString( rBinaryTagData10Atom, sInitials, 2 );
1087 
1088                 sal_Int16 nMilliSeconds = static_cast<sal_Int16>(::rtl::math::round(static_cast<double>(aDateTime.NanoSeconds) / 1000000000.0));
1089                 EscherExAtom aCommentAtom10( rBinaryTagData10Atom, EPP_CommentAtom10 );
1090                 rBinaryTagData10Atom.WriteInt32( nIndex++ )
1091                                     .WriteInt16( aDateTime.Year )
1092                                     .WriteUInt16( aDateTime.Month )
1093                                     .WriteUInt16( aDateTime.Day )   // todo: day of week
1094                                     .WriteUInt16( aDateTime.Day )
1095                                     .WriteUInt16( aDateTime.Hours )
1096                                     .WriteUInt16( aDateTime.Minutes )
1097                                     .WriteUInt16( aDateTime.Seconds )
1098                                     .WriteInt16( nMilliSeconds )
1099                                     .WriteInt32( aPoint.X() )
1100                                     .WriteInt32( aPoint.Y() );
1101             }
1102         }
1103     }
1104     catch ( uno::Exception& )
1105     {
1106     }
1107 }
1108 
ImplWriteNotes(sal_uInt32 nPageNum)1109 void PPTWriter::ImplWriteNotes( sal_uInt32 nPageNum )
1110 {
1111     mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_Notes | nPageNum, mpStrm->Tell() );
1112     mpPptEscherEx->OpenContainer( EPP_Notes );
1113     mpPptEscherEx->AddAtom( 8, EPP_NotesAtom, 1 );
1114     mpStrm->WriteUInt32( nPageNum + 0x100 )
1115            .WriteUInt16( 3 )                                        // follow master...
1116            .WriteUInt16( 0 );
1117 
1118     ImplCreateHeaderFooters( mXPagePropSet );
1119 
1120     EscherSolverContainer aSolverContainer;
1121 
1122     mpPptEscherEx->OpenContainer( EPP_PPDrawing );
1123     mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
1124     mpPptEscherEx->EnterGroup(nullptr,nullptr);
1125 
1126     ImplWritePage( GetLayout( 20 ), aSolverContainer, NOTICE, false );  // the shapes of the pages are created in the PPT document
1127 
1128     mpPptEscherEx->LeaveGroup();
1129     mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1130     mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
1131     EscherPropertyContainer aPropOpt;
1132     aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0xffffff );     // stock valued fill color
1133     aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0 );
1134     aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, 0x8b9f8e );
1135     aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, 0x68bdde );
1136     aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
1137     aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
1138     aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow );
1139     aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 );
1140     aPropOpt.Commit( *mpStrm );
1141     mpPptEscherEx->CloseContainer();    // ESCHER_SpContainer
1142 
1143     aSolverContainer.WriteSolver( *mpStrm );
1144 
1145     mpPptEscherEx->CloseContainer();    // ESCHER_DgContainer
1146     mpPptEscherEx->CloseContainer();    // EPP_Drawing
1147     mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
1148     mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
1149     mpPptEscherEx->CloseContainer();    // EPP_Notes
1150 };
1151 
ImplWriteBackground(css::uno::Reference<css::beans::XPropertySet> const & rXPropSet)1152 void PPTWriter::ImplWriteBackground( css::uno::Reference< css::beans::XPropertySet > const & rXPropSet )
1153 {
1154     //************************ ******
1155     //** DEFAULT BACKGROUND SHAPE **
1156 
1157     sal_uInt32 nFillColor = 0xffffff;
1158     sal_uInt32 nFillBackColor = 0;
1159 
1160     mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1161     mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
1162 
1163     // #i121183# Use real PageSize in 100th mm
1164     ::tools::Rectangle aRect(Point(0, 0), Size(maPageSize.Width, maPageSize.Height));
1165 
1166     EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
1167     aPropOpt.AddOpt( ESCHER_Prop_fillType, ESCHER_FillSolid );
1168     css::drawing::FillStyle aFS( css::drawing::FillStyle_NONE );
1169     if ( ImplGetPropertyValue( rXPropSet, "FillStyle" ) )
1170         mAny >>= aFS;
1171 
1172     switch( aFS )
1173     {
1174         case css::drawing::FillStyle_GRADIENT :
1175         {
1176             aPropOpt.CreateGradientProperties( rXPropSet );
1177             aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x1f001e );
1178             aPropOpt.GetOpt( ESCHER_Prop_fillColor, nFillColor );
1179             aPropOpt.GetOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
1180         }
1181         break;
1182 
1183         case css::drawing::FillStyle_BITMAP :
1184             aPropOpt.CreateGraphicProperties( rXPropSet, "FillBitmap", true );
1185         break;
1186 
1187         case css::drawing::FillStyle_HATCH :
1188             aPropOpt.CreateGraphicProperties( rXPropSet, "FillHatch", true );
1189         break;
1190 
1191         case css::drawing::FillStyle_SOLID :
1192         {
1193             if ( ImplGetPropertyValue( rXPropSet, "FillColor" ) )
1194             {
1195                 nFillColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(mAny) );
1196                 nFillBackColor = nFillColor ^ 0xffffff;
1197             }
1198             [[fallthrough]];
1199         }
1200         case css::drawing::FillStyle_NONE :
1201         default:
1202             aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
1203         break;
1204     }
1205     aPropOpt.AddOpt( ESCHER_Prop_fillColor, nFillColor );
1206     aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
1207     aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, PPTtoEMU( maDestPageSize.Width ) );
1208     aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, PPTtoEMU( maDestPageSize.Height ) );
1209     aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
1210     aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_bwWhite );
1211     aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 );
1212     aPropOpt.Commit( *mpStrm );
1213     mpPptEscherEx->CloseContainer();    // ESCHER_SpContainer
1214 }
1215 
ImplWriteVBA()1216 void PPTWriter::ImplWriteVBA()
1217 {
1218     if ( mpVBA )
1219     {
1220         sal_uInt32 nLen = mpVBA->TellEnd();
1221         if ( nLen > 8 )
1222         {
1223             nLen -= 8;
1224             mnVBAOleOfs = mpStrm->Tell();
1225             mpPptEscherEx->BeginAtom();
1226             mpStrm->WriteBytes(static_cast<sal_Int8 const *>(mpVBA->GetData()) + 8, nLen);
1227             mpPptEscherEx->EndAtom( EPP_ExOleObjStg, 0, 1 );
1228         }
1229     }
1230 }
1231 
ImplWriteOLE()1232 void PPTWriter::ImplWriteOLE( )
1233 {
1234 
1235     SvxMSExportOLEObjects aOleExport( mnCnvrtFlags );
1236 
1237     for ( const auto& rxExOleObjEntry : maExOleObj )
1238     {
1239         PPTExOleObjEntry* pPtr = rxExOleObjEntry.get();
1240         std::unique_ptr<SvMemoryStream> pStrm;
1241         pPtr->nOfsB = mpStrm->Tell();
1242         switch ( pPtr->eType )
1243         {
1244             case NORMAL_OLE_OBJECT :
1245             {
1246                 SdrObject* pSdrObj = GetSdrObjectFromXShape( pPtr->xShape );
1247                 if ( auto pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >(pSdrObj) )
1248                 {
1249                     const ::uno::Reference < embed::XEmbeddedObject >& xObj( pSdrOle2Obj->GetObjRef() );
1250                     if( xObj.is() )
1251                     {
1252                         tools::SvRef<SotStorage> xTempStorage( new SotStorage( new SvMemoryStream(), true ) );
1253                         aOleExport.ExportOLEObject( xObj, *xTempStorage );
1254 
1255                         //TODO/MBA: testing
1256                         SvMemoryStream aStream;
1257                         tools::SvRef<SotStorage> xCleanStorage( new SotStorage( false, aStream ) );
1258                         xTempStorage->CopyTo( xCleanStorage.get() );
1259                         // create a dummy content stream, the dummy content is necessary for ppt, but not for
1260                         // doc files, so we can't share code.
1261                         tools::SvRef<SotStorageStream> xStm = xCleanStorage->OpenSotStream( SVEXT_PERSIST_STREAM );
1262                         xStm->WriteUInt32( 0 )        // no ClipboardId
1263                                .WriteUInt32( 4 )        // no target device
1264                                .WriteUInt32( 1 )        // aspect ratio
1265                                .WriteInt32( -1 )        // L-Index
1266                                .WriteUInt32( 0 )        // Advanced Flags
1267                                .WriteUInt32( 0 )        // compression
1268                                .WriteUInt32( 0 )        // Size
1269                                .WriteUInt32( 0 )        //  "
1270                                .WriteUInt32( 0 );
1271                         pStrm = xCleanStorage->CreateMemoryStream();
1272                     }
1273                 }
1274             }
1275             break;
1276 
1277             case OCX_CONTROL :
1278             {
1279                 if ( pPtr->xControlModel.is() )
1280                 {
1281                     OUString aName;
1282                     //Initialize the graphic size which will be used on export
1283                     css::awt::Size  aSize( pPtr->xShape->getSize() );
1284                     tools::SvRef<SotStorage> xDest( new SotStorage( new SvMemoryStream(), true ) );
1285                     bool bOk = oox::ole::MSConvertOCXControls::WriteOCXStream( mXModel, xDest, pPtr->xControlModel, aSize, aName );
1286                     if ( bOk )
1287                         pStrm = xDest->CreateMemoryStream();
1288                 }
1289             }
1290         }
1291         if ( pStrm )
1292         {
1293             mpPptEscherEx->BeginAtom();
1294             pStrm->Seek( STREAM_SEEK_TO_END );
1295             sal_uInt32 npStrmSize = pStrm->Tell();
1296             mpStrm->WriteUInt32( npStrmSize );                  // uncompressed size
1297 
1298             pStrm->Seek( 0 );
1299             ZCodec aZCodec( 0x8000, 0x8000 );
1300             aZCodec.BeginCompression();
1301             aZCodec.Compress( *pStrm, *mpStrm );
1302             aZCodec.EndCompression();
1303             pStrm.reset();
1304             mpPptEscherEx->EndAtom( EPP_ExOleObjStg, 0, 1 );
1305         }
1306     }
1307 }
1308 
1309 // write PersistantTable and UserEditAtom
1310 
ImplWriteAtomEnding()1311 void PPTWriter::ImplWriteAtomEnding()
1312 {
1313 
1314 #define EPP_LastViewTypeSlideView   1
1315 
1316     sal_uInt32  i, nPos, nOfs, nPersistOfs = mpStrm->Tell();
1317     sal_uInt32  nPersistEntrys = 0;
1318     mpStrm->WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 );         // skip record header and first entry
1319 
1320     // write document persist
1321     nPersistEntrys++;
1322     mpStrm->WriteUInt32( 0 );
1323     // write MasterPages persists
1324     for ( i = 0; i < mnMasterPages; i++ )
1325     {
1326         nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_MainMaster | i );
1327         if ( nOfs )
1328         {
1329             mpStrm->WriteUInt32( nOfs );
1330             mpPptEscherEx->InsertAtPersistOffset( EPP_MAINMASTER_PERSIST_KEY | i, ++nPersistEntrys );
1331         }
1332     }
1333     // write MainNotesMaster persist
1334     nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_MainNotes );
1335     if ( nOfs )
1336     {
1337         mpStrm->WriteUInt32( nOfs );
1338         mpPptEscherEx->InsertAtPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY, ++nPersistEntrys );
1339     }
1340     // write slide persists -> we have to write a valid value into EPP_SlidePersistAtome too
1341     for ( i = 0; i < mnPages; i++ )
1342     {
1343         nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Slide | i );
1344         if ( nOfs )
1345         {
1346             mpStrm->WriteUInt32( nOfs );
1347             mpPptEscherEx->InsertAtPersistOffset( EPP_MAINSLIDE_PERSIST_KEY | i, ++nPersistEntrys );
1348         }
1349     }
1350     // write Notes persists
1351     for ( i = 0; i < mnPages; i++ )
1352     {
1353         nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Notes | i );
1354         if ( nOfs )
1355         {
1356             mpStrm->WriteUInt32( nOfs );
1357             mpPptEscherEx->InsertAtPersistOffset( EPP_MAINNOTES_PERSIST_KEY | i, ++nPersistEntrys );
1358         }
1359     }
1360     // Ole persists
1361     for ( const auto& rxExOleObjEntry : maExOleObj )
1362     {
1363         PPTExOleObjEntry* pPtr = rxExOleObjEntry.get();
1364         nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_ExObj );
1365         if ( nOfs )
1366         {
1367             nPersistEntrys++;
1368             mpStrm->WriteUInt32( pPtr->nOfsB );
1369             sal_uInt32 nOldPos, nPersOfs = nOfs + pPtr->nOfsA + 16 + 8;     // 8 bytes atom header, +16 to the persist entry
1370             nOldPos = mpStrm->Tell();
1371             mpStrm->Seek( nPersOfs );
1372             mpStrm->WriteUInt32( nPersistEntrys );
1373             mpStrm->Seek( nOldPos );
1374         }
1375     }
1376     // VB persist
1377     if ( mnVBAOleOfs && mpVBA )
1378     {
1379         nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_VBAInfoAtom );
1380         if ( nOfs )
1381         {
1382             nPersistEntrys++;
1383             sal_uInt32 n1, n2;
1384 
1385             mpVBA->Seek( 0 );
1386             mpVBA->ReadUInt32( n1 )
1387                   .ReadUInt32( n2 );
1388 
1389             mpStrm->WriteUInt32( mnVBAOleOfs );
1390             sal_uInt32 nOldPos = mpStrm->Tell();
1391             mpStrm->Seek( nOfs );               // Fill the VBAInfoAtom with the correct index to the persisttable
1392             mpStrm->WriteUInt32( nPersistEntrys )
1393                    .WriteUInt32( n1 )
1394                    .WriteInt32( 2 );
1395             mpStrm->Seek( nOldPos );
1396 
1397         }
1398     }
1399     nPos = mpStrm->Tell();
1400     mpStrm->Seek( nPersistOfs );
1401     mpPptEscherEx->AddAtom( ( nPersistEntrys + 1 ) << 2, EPP_PersistPtrIncrementalBlock );      // insert Record Header
1402     mpStrm->WriteUInt32( ( nPersistEntrys << 20 ) | 1 );
1403     mpStrm->Seek( nPos );
1404 
1405     mpCurUserStrm->WriteUInt32( nPos );             // set offset to current edit
1406     mpPptEscherEx->AddAtom( 28, EPP_UserEditAtom );
1407     mpStrm->WriteInt32( 0x100 )                     // last slide ID
1408            .WriteUInt32( 0x03000dbc )               // minor and major app version that did the save
1409            .WriteUInt32( 0 )                        // offset last save, 0 after a full save
1410            .WriteUInt32( nPersistOfs )                      // File offset to persist pointers for this save operation
1411            .WriteUInt32( 1 )                        // Persist reference to the document persist object
1412            .WriteUInt32( nPersistEntrys )           // max persists written, Seed value for persist object id management
1413            .WriteInt16( EPP_LastViewTypeSlideView ) // last view type
1414            .WriteInt16( 0x12 );                     // padword
1415 }
1416 
1417 // - exported function -
1418 
ExportPPT(const std::vector<css::beans::PropertyValue> & rMediaData,tools::SvRef<SotStorage> const & rSvStorage,css::uno::Reference<css::frame::XModel> const & rXModel,css::uno::Reference<css::task::XStatusIndicator> const & rXStatInd,SvMemoryStream * pVBA,sal_uInt32 nCnvrtFlags)1419 extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool ExportPPT( const std::vector< css::beans::PropertyValue >& rMediaData,
1420                     tools::SvRef<SotStorage> const & rSvStorage,
1421                     css::uno::Reference< css::frame::XModel > const & rXModel,
1422                     css::uno::Reference< css::task::XStatusIndicator > const & rXStatInd,
1423                     SvMemoryStream* pVBA,
1424                     sal_uInt32 nCnvrtFlags )
1425 {
1426     PPTWriter aPPTWriter( rSvStorage, rXModel, rXStatInd, pVBA, nCnvrtFlags );
1427     aPPTWriter.exportPPT(rMediaData);
1428     bool bStatus = aPPTWriter.IsValid();
1429     return bStatus;
1430 }
1431 
SaveVBA(SfxObjectShell & rDocShell,SvMemoryStream * & pBas)1432 extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool SaveVBA( SfxObjectShell& rDocShell, SvMemoryStream*& pBas )
1433 {
1434     tools::SvRef<SotStorage> xDest( new SotStorage( new SvMemoryStream(), true ) );
1435     SvxImportMSVBasic aMSVBas( rDocShell, *xDest );
1436     aMSVBas.SaveOrDelMSVBAStorage( true, "_MS_VBA_Overhead" );
1437 
1438     tools::SvRef<SotStorage> xOverhead = xDest->OpenSotStorage( "_MS_VBA_Overhead" );
1439     if ( xOverhead.is() && ( xOverhead->GetError() == ERRCODE_NONE ) )
1440     {
1441         tools::SvRef<SotStorage> xOverhead2 = xOverhead->OpenSotStorage( "_MS_VBA_Overhead" );
1442         if ( xOverhead2.is() && ( xOverhead2->GetError() == ERRCODE_NONE ) )
1443         {
1444             tools::SvRef<SotStorageStream> xTemp = xOverhead2->OpenSotStream( "_MS_VBA_Overhead2" );
1445             if ( xTemp.is() && ( xTemp->GetError() == ERRCODE_NONE ) )
1446             {
1447                 sal_uInt32 nLen = xTemp->GetSize();
1448                 if ( nLen )
1449                 {
1450                     char* pTemp = new char[ nLen ];
1451                     xTemp->Seek( STREAM_SEEK_TO_BEGIN );
1452                     xTemp->ReadBytes(pTemp, nLen);
1453                     pBas = new SvMemoryStream( pTemp, nLen, StreamMode::READ );
1454                     pBas->ObjectOwnsMemory( true );
1455                     return true;
1456                 }
1457             }
1458         }
1459     }
1460 
1461     return false;
1462 }
1463 
1464 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1465