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