LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sd / source / filter / eppt / eppt.cxx
blob117c39d344533b63a9677d816844331dd6de6ae7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
55 class SfxObjectShell;
56 // complete SfxObjectShell for SaveVBA under -fsanitize=function
58 using namespace com::sun::star;
59 using namespace ::com::sun::star::uno;
60 using namespace ::com::sun::star::presentation;
62 using ::com::sun::star::beans::XPropertySet;
64 //============================ PPTWriter ==================================
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 )
91 void PPTWriter::exportPPTPre( const std::vector< css::beans::PropertyValue >& rMediaData )
93 if ( !mrStg.is() )
94 return;
96 if ( mXStatusIndicator.is() )
98 mbStatusIndicator = true;
99 mnStatMaxValue = ( mnPages + mnMasterPages ) * 5;
100 mXStatusIndicator->start( "PowerPoint Export", mnStatMaxValue + ( mnStatMaxValue >> 3 ) );
103 SvGlobalName aGName(MSO_PPT8_CLASSID);
104 mrStg->SetClass( aGName, SotClipboardFormatId::NONE, "MS PowerPoint 97" );
106 if ( !ImplCreateCurrentUserStream() )
107 return;
109 mpStrm = mrStg->OpenSotStream( "PowerPoint Document" );
110 if ( !mpStrm )
111 return;
113 if ( !mpPicStrm )
114 mpPicStrm = mrStg->OpenSotStream( "Pictures" );
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 ) );
123 void PPTWriter::exportPPTPost( )
125 if ( !ImplCloseDocument() )
126 return;
128 if ( mbStatusIndicator )
130 mXStatusIndicator->setText( "PowerPoint Export" );
131 sal_uInt32 nValue = mnStatMaxValue + ( mnStatMaxValue >> 3 );
132 if ( nValue > mnLatestStatValue )
134 mXStatusIndicator->setValue( nValue );
135 mnLatestStatValue = nValue;
139 ImplWriteOLE();
141 ImplWriteVBA();
143 ImplWriteAtomEnding();
145 ImplCreateDocumentSummaryInformation();
147 mbStatus = true;
150 static void ImplExportComments( const uno::Reference< drawing::XDrawPage >& xPage, SvMemoryStream& rBinaryTagData10Atom );
152 void PPTWriter::ImplWriteSlide( sal_uInt32 nPageNum, sal_uInt32 nMasterNum, sal_uInt16 nMode,
153 bool bHasBackground, Reference< XPropertySet > const & aXBackgroundPropSet )
155 Any aAny;
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
168 mnDiaMode = 0;
169 bool bVisible = true;
170 css::presentation::FadeEffect eFe = css::presentation::FadeEffect_NONE;
172 if ( GetPropertyValue( aAny, mXPagePropSet, "Visible" ) )
173 aAny >>= bVisible;
174 if ( GetPropertyValue( aAny, mXPagePropSet, "Change" ) )
176 switch ( *o3tl::doAccess<sal_Int32>(aAny) )
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;
189 if ( GetPropertyValue( aAny, mXPagePropSet, "Effect" ) )
190 aAny >>= eFe;
192 sal_uInt32 nSoundRef = 0;
193 bool bIsSound = false;
194 bool bStopSound = false;
195 bool bLoopSound = false;
197 if ( GetPropertyValue( aAny, mXPagePropSet, "Sound" ) )
199 OUString aSoundURL;
200 if ( aAny >>= aSoundURL )
202 nSoundRef = maSoundCollection.GetId( aSoundURL );
203 bIsSound = true;
205 else
206 aAny >>= bStopSound;
208 if ( GetPropertyValue( aAny, mXPagePropSet, "LoopSound" ) )
209 aAny >>= bLoopSound;
211 bool bNeedsSSSlideInfoAtom = !bVisible
212 || ( mnDiaMode == 2 )
213 || bIsSound
214 || bStopSound
215 || ( eFe != css::presentation::FadeEffect_NONE );
216 if ( bNeedsSSSlideInfoAtom )
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;
224 if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionDuration" ) )
226 css::presentation::AnimationSpeed aAs;
227 double fTransitionDuration = -1.0;
228 aAny >>= fTransitionDuration;
230 if (fTransitionDuration >= 0)
232 if (fTransitionDuration <= 0.5)
234 aAs = css::presentation::AnimationSpeed::AnimationSpeed_FAST;
236 else if (fTransitionDuration >= 1.0)
238 aAs = css::presentation::AnimationSpeed::AnimationSpeed_SLOW;
240 else
242 aAs = css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM;
245 else
246 aAs = css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM;
248 nSpeed = static_cast<sal_uInt8>(aAs);
250 sal_Int16 nTT = 0;
251 if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionType" )
252 && ( aAny >>= nTT ) )
254 sal_Int16 nTST = 0;
255 if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionSubtype" )
256 && ( aAny >>= nTST ) )
257 nTransitionType = GetTransition( nTT, nTST, eFe, 0, nDirection );
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;
273 if ( GetPropertyValue( aAny, mXPagePropSet, "Duration" ) )// duration of this slide
274 nSlideTime = *o3tl::doAccess<sal_Int32>(aAny) << 10; // in ticks
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 );
286 ImplCreateHeaderFooters( mXPagePropSet );
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();
295 if ( bHasBackground )
296 ImplWriteBackground( aXBackgroundPropSet );
297 else
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
313 aSolverContainer.WriteSolver( *mpStrm );
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 );
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 )
329 EscherExAtom aMagic2( aBinaryTagData10Atom, 0x2eeb );
330 aBinaryTagData10Atom.WriteUInt32( 0x01c45df9 )
331 .WriteUInt32( 0xe1471b30 );
334 EscherExAtom aMagic( aBinaryTagData10Atom, 0x2b00 );
335 aBinaryTagData10Atom.WriteUInt32( 0 );
337 aBinaryTagData10Atom.WriteBytes(amsofbtAnimGroup.GetData(), amsofbtAnimGroup.Tell());
339 EscherExContainer aMagic2( aBinaryTagData10Atom, 0x2b02 );
342 if ( aBinaryTagData10Atom.Tell() )
344 EscherExContainer aProgTags ( *mpStrm, EPP_ProgTags );
345 EscherExContainer aProgBinaryTag( *mpStrm, EPP_ProgBinaryTag );
347 EscherExAtom aCString( *mpStrm, EPP_CString );
348 mpStrm->WriteUInt32( 0x5f005f )
349 .WriteUInt32( 0x50005f )
350 .WriteUInt32( 0x540050 )
351 .WriteUInt16( 0x31 )
352 .WriteUInt16( 0x30 );
355 EscherExAtom aBinaryTagData( *mpStrm, EPP_BinaryTagData );
356 mpStrm->WriteBytes(aBinaryTagData10Atom.GetData(), aBinaryTagData10Atom.Tell());
359 mpPptEscherEx->CloseContainer(); // EPP_Slide
362 void PPTWriter::ImplWriteSlideMaster( sal_uInt32 nPageNum, Reference< XPropertySet > const & aXBackgroundPropSet )
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
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 );
391 for ( int nInstance = EPP_TEXTTYPE_Title; nInstance <= EPP_TEXTTYPE_QuarterBody; nInstance++ )
393 if ( nInstance == EPP_TEXTTYPE_notUsed )
394 continue;
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);
402 mpPptEscherEx->BeginAtom();
404 bool bSimpleText = false;
406 mpStrm->WriteUInt16( 5 ); // paragraph count
408 for ( sal_uInt16 nLev = 0; nLev < 5; nLev++ )
410 if ( nInstance >= EPP_TEXTTYPE_CenterBody )
412 bSimpleText = true;
413 mpStrm->WriteUInt16( nLev );
415 mpStyleSheet->mpParaSheet[ nInstance ]->Write( *mpStrm, nLev, bSimpleText, mXPagePropSet );
416 mpStyleSheet->mpCharSheet[ nInstance ]->Write( *mpStrm, nLev, bSimpleText, mXPagePropSet );
418 mpPptEscherEx->EndAtom( EPP_TxMasterStyleAtom, 0, nInstance );
420 GetPageByIndex( nPageNum, MASTER );
422 EscherSolverContainer aSolverContainer;
424 mpPptEscherEx->OpenContainer( EPP_PPDrawing );
425 mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
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();
431 ImplWriteBackground( aXBackgroundPropSet );
433 aSolverContainer.WriteSolver( *mpStrm );
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 );
440 if ( aBuExMasterStream.Tell() )
442 ImplProgTagContainer( mpStrm.get(), &aBuExMasterStream );
444 mpPptEscherEx->CloseContainer(); // EPP_MainMaster
447 PPTWriter::~PPTWriter()
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();
460 bool PPTWriter::ImplCreateCurrentUserStream()
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 );
469 mpCurUserStrm->WriteUInt16( 0 ).WriteUInt16( EPP_CurrentUserAtom ).WriteUInt32( nSizeOfRecord );
470 mpCurUserStrm->WriteUInt32( 0x14 ) // Len
471 .WriteUInt32( 0xe391c05f ); // Magic
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++ )
484 mpCurUserStrm->WriteUChar( 0 ); // pad bytes
486 mpCurUserStrm->Seek( nEditPos );
487 return true;
490 void PPTWriter::ImplCreateDocumentSummaryInformation()
492 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
493 mXModel, uno::UNO_QUERY_THROW);
494 uno::Reference<document::XDocumentProperties> xDocProps(
495 xDPS->getDocumentProperties());
497 if (!xDocProps.is())
498 return;
500 // no idea what this is...
501 static const sal_Int8 aGuid[ 0x52 ] =
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
509 // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence
510 uno::Sequence<sal_Int8> aGuidSeq(aGuid, 0x52);
512 SvMemoryStream aHyperBlob;
513 ImplCreateHyperBlob( aHyperBlob );
515 auto nHyperLength = static_cast<sal_Int32>(aHyperBlob.Tell());
516 const sal_Int8* pBlob(
517 static_cast<const sal_Int8*>(aHyperBlob.GetData()));
518 auto aHyperSeq = comphelper::arrayToSequence<sal_Int8>(pBlob, nHyperLength);
520 if ( mnCnvrtFlags & 0x8000 )
522 uno::Sequence<sal_Int8> aThumbSeq;
523 if ( GetPageByIndex( 0, NORMAL ) && ImplGetPropertyValue( mXPagePropSet, "PreviewBitmap" ) )
525 aThumbSeq = *o3tl::doAccess<uno::Sequence<sal_Int8>>(mAny);
527 sfx2::SaveOlePropertySet( xDocProps, mrStg.get(),
528 &aThumbSeq, &aGuidSeq, &aHyperSeq);
530 else
532 sfx2::SaveOlePropertySet( xDocProps, mrStg.get(),
533 nullptr, &aGuidSeq, &aHyperSeq );
537 void PPTWriter::ImplWriteExtParaHeader( SvMemoryStream& rSt, sal_uInt32 nRef, sal_uInt32 nInstance, sal_uInt32 nSlideId )
539 if ( rSt.Tell() )
541 aBuExOutlineStream.WriteUInt32( ( EPP_PST_ExtendedParagraphHeaderAtom << 16 )
542 | ( nRef << 4 ) )
543 .WriteUInt32( 8 )
544 .WriteUInt32( nSlideId )
545 .WriteUInt32( nInstance );
546 aBuExOutlineStream.WriteBytes(rSt.GetData(), rSt.Tell());
550 void PPTWriter::ImplCreateHeaderFooterStrings( SvStream& rStrm, css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet )
552 if ( !rXPagePropSet.is() )
553 return;
555 OUString aString;
556 css::uno::Any aAny;
557 if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "HeaderText", true ) )
559 if ( aAny >>= aString )
560 PPTWriter::WriteCString( rStrm, aString, 1 );
562 if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "FooterText", true ) )
564 if ( aAny >>= aString )
565 PPTWriter::WriteCString( rStrm, aString, 2 );
567 if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "DateTimeText", true ) )
569 if ( aAny >>= aString )
570 PPTWriter::WriteCString( rStrm, aString );
574 void PPTWriter::ImplCreateHeaderFooters( css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet )
576 if ( !rXPagePropSet.is() )
577 return;
579 bool bVal = false;
580 sal_uInt32 nVal = 0;
581 css::uno::Any aAny;
582 if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsHeaderVisible", true ) )
584 if ( ( aAny >>= bVal ) && bVal )
585 nVal |= 0x100000;
587 if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsFooterVisible", true ) )
589 if ( ( aAny >>= bVal ) && bVal )
590 nVal |= 0x200000;
592 if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsDateTimeVisible", true ) )
594 if ( ( aAny >>= bVal ) && bVal )
595 nVal |= 0x010000;
597 if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsPageNumberVisible", true ) )
599 if ( ( aAny >>= bVal ) && bVal )
600 nVal |= 0x080000;
602 if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsDateTimeFixed", true ) )
604 if ( ( aAny >>= bVal ) && !bVal )
605 nVal |= 0x20000;
606 else
607 nVal |= 0x40000;
609 if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "DateTimeFormat", true ) )
611 sal_Int32 nFormat = *o3tl::doAccess<sal_Int32>(aAny);
612 SvxDateFormat eDateFormat = static_cast<SvxDateFormat>( nFormat & 0xf );
613 SvxTimeFormat eTimeFormat = static_cast<SvxTimeFormat>( ( nFormat >> 4 ) & 0xf );
614 switch( eDateFormat )
616 case SvxDateFormat::F :
617 nFormat = 1;
618 break;
619 case SvxDateFormat::D :
620 nFormat = 2;
621 break;
622 case SvxDateFormat::C :
623 nFormat = 4;
624 break;
625 default:
626 case SvxDateFormat::A :
627 nFormat = 0;
629 switch( eTimeFormat )
631 case SvxTimeFormat::HH24_MM :
632 nFormat = 9;
633 break;
634 case SvxTimeFormat::HH12_MM :
635 nFormat = 11;
636 break;
637 case SvxTimeFormat::HH24_MM_SS :
638 nFormat = 10;
639 break;
640 case SvxTimeFormat::HH12_MM_SS :
641 nFormat = 12;
642 break;
643 default:
644 break;
646 nVal |= nFormat;
649 mpPptEscherEx->OpenContainer( EPP_HeadersFooters );
650 mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
651 mpStrm->WriteUInt32( nVal );
652 ImplCreateHeaderFooterStrings( *mpStrm, rXPagePropSet );
653 mpPptEscherEx->CloseContainer();
656 bool PPTWriter::ImplCreateDocument()
658 sal_uInt32 i;
659 sal_uInt16 nSlideType = EPP_SLIDESIZE_TYPECUSTOM;
661 sal_uInt32 nWidth = maDestPageSize.Width;
662 sal_uInt32 nHeight = maDestPageSize.Height;
664 if ( ( nWidth == 0x1680 ) && ( nHeight == 0x10e0 ) )
665 nSlideType = EPP_SLIDESIZE_TYPEONSCREEN;
666 else if ( ( nWidth == 0x1200 ) && ( nHeight == 0x240 ) )
667 nSlideType = EPP_SLIDESIZE_TYPEBANNER;
668 else if ( ( nWidth == 0x1950 ) && ( nHeight == 0x10e0 ) )
669 nSlideType = EPP_SLIDESIZE_TYPE35MM;
670 else if ( ( nWidth == 0x1860 ) && ( nHeight == 0x10e0 ) )
671 nSlideType = EPP_SLIDESIZE_TYPEA4PAPER;
673 mpPptEscherEx->OpenContainer( EPP_Document );
674 // CREATE DOCUMENT ATOM
675 mpPptEscherEx->AddAtom( 40, EPP_DocumentAtom, 1 );
676 mpStrm->WriteUInt32( nWidth ) // Slide Size in Master coordinates X
677 .WriteUInt32( nHeight ) // " " " " " Y
678 .WriteInt32( maNotesPageSize.Width ) // Notes Page Size X
679 .WriteInt32( maNotesPageSize.Height ) // " " " Y
680 .WriteInt32( 1 ).WriteInt32( 2 ); // the scale used when the Powerpoint document is embedded. the default is 1:2
681 mpPptEscherEx->InsertPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY, mpStrm->Tell() );
682 mpStrm->WriteUInt32( 0 ) // Reference to NotesMaster ( 0 if none );
683 .WriteUInt32( 0 ) // Reference to HandoutMaster ( 0 if none );
684 .WriteInt16( 1 ) // Number of the first slide;
685 .WriteUInt16( nSlideType ) // Size of the document slides ( default: EPP_SLIDESIZETYPEONSCREEN )
686 .WriteUChar( 0 ) // bool1 indicates if document was saved with embedded true type fonts
687 .WriteUChar( 0 ) // bool1 indicates if the placeholders on the title slide are omitted
688 .WriteUChar( 0 ) // bool1 right to left ( flag for Bidi version )
689 .WriteUChar( 1 ); // bool1 visibility of comments shapes
691 mpPptEscherEx->PtInsert( EPP_Persist_Document, mpStrm->Tell() );
693 mpPptEscherEx->OpenContainer( EPP_HeadersFooters, 3 ); //Master footer (default)
694 mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
695 mpStrm->WriteUInt32( 0x25000d );
696 if ( GetPageByIndex( 0, MASTER ) )
697 ImplCreateHeaderFooterStrings( *mpStrm, mXPagePropSet );
698 mpPptEscherEx->CloseContainer();
699 mpPptEscherEx->OpenContainer( EPP_HeadersFooters, 4 ); //NotesMaster footer (default)
700 mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
701 mpStrm->WriteUInt32( 0x3d000d );
702 if ( GetPageByIndex( 0, NOTICE ) )
703 ImplCreateHeaderFooterStrings( *mpStrm, mXPagePropSet );
704 mpPptEscherEx->CloseContainer();
706 mpPptEscherEx->OpenContainer( EPP_SlideListWithText ); // animation information for the slides
708 for ( i = 0; i < mnPages; i++ )
710 mpPptEscherEx->AddAtom( 20, EPP_SlidePersistAtom );
711 mpPptEscherEx->InsertPersistOffset( EPP_MAINSLIDE_PERSIST_KEY | i, mpStrm->Tell() );
712 mpStrm->WriteUInt32( 0 ) // psrReference - logical reference to the slide persist object ( EPP_MAINSLIDE_PERSIST_KEY )
713 .WriteUInt32( 4 ) // flags - only bit 3 used, if set then slide contains shapes other than placeholders
714 .WriteInt32( 0 ) // numberTexts - number of placeholder texts stored with the persist object. Allows to display outline view without loading the slide persist objects
715 .WriteInt32( i + 0x100 ) // slideId - Unique slide identifier, used for OLE link monikers for example
716 .WriteUInt32( 0 ); // reserved, usually 0
718 if ( !GetPageByIndex( i, NORMAL ) ) // very exciting: once again through all pages
719 return false;
720 SetCurrentStyleSheet( GetMasterIndex( NORMAL ) );
722 css::uno::Reference< css::container::XNamed >
723 aXName( mXDrawPage, css::uno::UNO_QUERY );
725 if ( aXName.is() )
726 maSlideNameList.push_back( aXName->getName() );
727 else
728 maSlideNameList.emplace_back( );
730 mpPptEscherEx->CloseContainer(); // EPP_SlideListWithText
732 mpPptEscherEx->OpenContainer( EPP_SlideListWithText, 2 ); // animation information for the notes
733 for( i = 0; i < mnPages; i++ )
735 mpPptEscherEx->AddAtom( 20, EPP_SlidePersistAtom );
736 mpPptEscherEx->InsertPersistOffset( EPP_MAINNOTES_PERSIST_KEY | i, mpStrm->Tell() );
737 mpStrm->WriteUInt32( 0 )
738 .WriteUInt32( 4 )
739 .WriteInt32( 0 )
740 .WriteInt32( i + 0x100 )
741 .WriteUInt32( 0 );
743 mpPptEscherEx->CloseContainer(); // EPP_SlideListWithText
745 css::uno::Reference< css::presentation::XPresentationSupplier >
746 aXPresSupplier( mXModel, css::uno::UNO_QUERY );
747 if ( aXPresSupplier.is() )
749 css::uno::Reference< css::presentation::XPresentation > aXPresentation( aXPresSupplier->getPresentation() );
750 if ( aXPresentation.is() )
752 mXPropSet.set( aXPresentation, css::uno::UNO_QUERY );
753 if ( mXPropSet.is() )
755 OUString aCustomShow;
756 sal_uInt32 const nPenColor = 0x1000000;
757 sal_Int32 const nRestartTime = 0x7fffffff;
758 sal_Int16 nStartSlide = 0;
759 sal_Int16 nEndSlide = 0;
760 sal_uInt32 nFlags = 0; // Bit 0: Auto advance
761 // Bit 1 Skip builds ( do not allow slide effects )
762 // Bit 2 Use slide range
763 // Bit 3 Use named show
764 // Bit 4 Browse mode on
765 // Bit 5 Kiosk mode on
766 // Bit 6 Skip narration
767 // Bit 7 loop continuously
768 // Bit 8 show scrollbar
770 if ( ImplGetPropertyValue( "CustomShow" ) )
772 aCustomShow = *o3tl::doAccess<OUString>(mAny);
773 if ( !aCustomShow.isEmpty() )
775 nFlags |= 8;
778 if ( ( nFlags & 8 ) == 0 )
780 if ( ImplGetPropertyValue( "FirstPage" ) )
782 auto aSlideName = o3tl::doAccess<OUString>(mAny);
784 std::vector<OUString>::const_iterator pIter = std::find(
785 maSlideNameList.begin(),maSlideNameList.end(), *aSlideName);
787 if (pIter != maSlideNameList.end())
789 nStartSlide = pIter - maSlideNameList.begin() + 1;
790 nFlags |= 4;
791 nEndSlide = static_cast<sal_uInt16>(mnPages);
796 if ( ImplGetPropertyValue( "IsAutomatic" ) )
798 bool bBool = false;
799 mAny >>= bBool;
800 if ( !bBool )
801 nFlags |= 1;
804 if ( ImplGetPropertyValue( "IsEndless" ) )
806 bool bBool = false;
807 mAny >>= bBool;
808 if ( bBool )
809 nFlags |= 0x80;
811 if ( ImplGetPropertyValue( "IsFullScreen" ) )
813 bool bBool = false;
814 mAny >>= bBool;
815 if ( !bBool )
816 nFlags |= 0x11;
819 mpPptEscherEx->AddAtom( 80, EPP_SSDocInfoAtom, 1 );
820 mpStrm->WriteUInt32( nPenColor ).WriteInt32( nRestartTime ).WriteInt16( nStartSlide ).WriteInt16( nEndSlide );
822 sal_uInt32 nCustomShowNameLen = aCustomShow.getLength();
823 if ( nCustomShowNameLen > 31 )
824 nCustomShowNameLen = 31;
825 if ( nCustomShowNameLen ) // named show identifier
827 const sal_Unicode* pCustomShow = aCustomShow.getStr();
828 for ( i = 0; i < nCustomShowNameLen; i++ )
830 mpStrm->WriteUInt16( pCustomShow[ i ] );
833 for ( i = nCustomShowNameLen; i < 32; i++, mpStrm->WriteUInt16( 0 ) ) ;
835 mpStrm->WriteUInt32( nFlags );
836 css::uno::Reference< css::presentation::XCustomPresentationSupplier > aXCPSup( mXModel, css::uno::UNO_QUERY );
837 if ( aXCPSup.is() )
839 css::uno::Reference< css::container::XNameContainer > aXCont( aXCPSup->getCustomPresentations() );
840 if ( aXCont.is() )
842 const css::uno::Sequence< OUString> aNameSeq( aXCont->getElementNames() );
843 if ( aNameSeq.hasElements() )
845 mpPptEscherEx->OpenContainer( EPP_NamedShows );
846 sal_uInt32 nCustomShowIndex = 0;
847 for( OUString const & customShowName : aNameSeq )
849 if ( !customShowName.isEmpty() )
851 mpPptEscherEx->OpenContainer( EPP_NamedShow, nCustomShowIndex++ );
853 sal_uInt32 nNamedShowLen = customShowName.getLength();
854 if ( nNamedShowLen > 31 )
855 nNamedShowLen = 31;
856 mpPptEscherEx->AddAtom( nNamedShowLen << 1, EPP_CString );
857 const sal_Unicode* pCustomShowName = customShowName.getStr();
858 for ( sal_uInt32 k = 0; k < nNamedShowLen; ++k )
859 mpStrm->WriteUInt16( pCustomShowName[ k ] );
860 mAny = aXCont->getByName( customShowName );
861 css::uno::Reference< css::container::XIndexContainer > aXIC;
862 if ( mAny >>= aXIC )
864 mpPptEscherEx->BeginAtom();
866 sal_Int32 nSlideCount = aXIC->getCount();
867 for ( sal_Int32 j = 0; j < nSlideCount; j++ ) // number of slides
869 mAny = aXIC->getByIndex( j );
870 css::uno::Reference< css::drawing::XDrawPage > aXDrawPage;
871 if ( mAny >>= aXDrawPage )
873 css::uno::Reference< css::container::XNamed > aXName( aXDrawPage, css::uno::UNO_QUERY );
874 if ( aXName.is() )
876 OUString aSlideName( aXName->getName() );
877 std::vector<OUString>::const_iterator pIter = std::find(
878 maSlideNameList.begin(),maSlideNameList.end(),aSlideName);
880 if (pIter != maSlideNameList.end())
882 sal_uInt32 nPageNumber = pIter - maSlideNameList.begin();
883 mpStrm->WriteUInt32( nPageNumber + 0x100 ); // unique slide id
888 mpPptEscherEx->EndAtom( EPP_NamedShowSlides );
890 mpPptEscherEx->CloseContainer(); // EPP_NamedShow
893 mpPptEscherEx->CloseContainer(); // EPP_NamedShows
900 mpPptEscherEx->AddAtom( 0, EPP_EndDocument );
901 mpPptEscherEx->CloseContainer(); // EPP_Document
902 return true;
905 void PPTWriter::ImplCreateHyperBlob( SvMemoryStream& rStrm )
907 sal_uInt32 nCurrentOfs, nParaOfs, nParaCount = 0;
909 nParaOfs = rStrm.Tell();
910 rStrm.WriteUInt32( 0 ); // property size
911 rStrm.WriteUInt32( 0 ); // property count
913 for ( const auto& rHyperlink : maHyperlink )
915 nParaCount += 6;
916 rStrm .WriteUInt32( 3 ) // Type VT_I4
917 .WriteUInt32( 7 ) // (VTI4 - Private1)
918 .WriteUInt32( 3 ) // Type VT_I4
919 .WriteUInt32( 6 ) // (VTI4 - Private2)
920 .WriteUInt32( 3 ) // Type VT_I4
921 .WriteUInt32( 0 ); // (VTI4 - Private3)
923 // INFO
924 // HIWORD: = 0 : do not change anything
925 // = 1 : replace the hyperlink with the target and subaddress in the following two VTLPWSTR
926 // = 2 : delete the hyperlink
927 // LOWORD: = 0 : graphic shown as background (link)
928 // = 1 : graphic shown as shape (link)
929 // = 2 : graphic is used to fill a shape
930 // = 3 : graphic used to fill a shape outline (future use)
931 // = 4 : hyperlink attached to a shape
932 // = 5 : " " " " (Word) field
933 // = 6 : " " " " (Excel) range
934 // = 7 : " " " " (PPT) text range
935 // = 8 : " " " " (Project) task
937 sal_Int32 nUrlLen = rHyperlink.aURL.getLength();
938 const OUString& rUrl = rHyperlink.aURL;
940 sal_uInt32 const nInfo = 7;
942 rStrm .WriteUInt32( 3 ) // Type VT_I4
943 .WriteUInt32( nInfo ); // Info
945 switch( rHyperlink.nType & 0xff )
947 case 1 : // click action to slidenumber
949 rStrm.WriteUInt32( 0x1f ).WriteUInt32( 1 ).WriteUInt32( 0 ); // path
950 rStrm.WriteUInt32( 0x1f ).WriteUInt32( nUrlLen + 1 );
951 for ( sal_Int32 i = 0; i < nUrlLen; i++ )
953 rStrm.WriteUInt16( rUrl[ i ] );
955 rStrm.WriteUInt16( 0 );
957 break;
958 case 2 :
960 sal_Int32 i;
962 rStrm .WriteUInt32( 0x1f )
963 .WriteUInt32( nUrlLen + 1 );
964 for ( i = 0; i < nUrlLen; i++ )
966 rStrm.WriteUInt16( rUrl[ i ] );
968 if ( ! ( i & 1 ) )
969 rStrm.WriteUInt16( 0 );
970 rStrm .WriteUInt16( 0 )
971 .WriteUInt32( 0x1f )
972 .WriteUInt32( 1 )
973 .WriteUInt32( 0 );
975 break;
978 nCurrentOfs = rStrm.Tell();
979 rStrm.Seek( nParaOfs );
980 rStrm.WriteUInt32( nCurrentOfs - ( nParaOfs + 4 ) );
981 rStrm.WriteUInt32( nParaCount );
982 rStrm.Seek( nCurrentOfs );
985 bool PPTWriter::ImplCreateMainNotes()
987 EscherSolverContainer aSolverContainer;
989 mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_MainNotes, mpStrm->Tell() );
990 mpPptEscherEx->OpenContainer( EPP_Notes );
991 mpPptEscherEx->AddAtom( 8, EPP_NotesAtom, 1 );
992 mpStrm->WriteUInt32( 0x80000001 ) // Number that identifies this slide
993 .WriteUInt32( 0 ); // follow nothing
994 mpPptEscherEx->OpenContainer( EPP_PPDrawing );
995 mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
996 mpPptEscherEx->EnterGroup(nullptr,nullptr);
998 ImplWritePage( GetLayout( 20 ), aSolverContainer, NOTICE, true );
1000 mpPptEscherEx->LeaveGroup();
1001 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1002 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
1003 EscherPropertyContainer aPropOpt;
1004 aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0xffffff ); // stock valued fill color
1005 aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0 );
1006 aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, 0x68bdde );
1007 aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, 0x8b9f8e );
1008 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
1009 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0 );
1010 aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow );
1011 aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 ); // if true, this is the background shape
1012 aPropOpt.Commit( *mpStrm );
1013 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
1015 aSolverContainer.WriteSolver( *mpStrm );
1017 mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer
1018 mpPptEscherEx->CloseContainer(); // EPP_Drawing
1019 mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
1020 mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
1021 mpPptEscherEx->CloseContainer(); // EPP_Notes
1022 return true;
1025 static OUString getInitials( const OUString& rName )
1027 OUStringBuffer sInitials;
1029 const sal_Unicode * pStr = rName.getStr();
1030 sal_Int32 nLength = rName.getLength();
1032 while( nLength )
1034 // skip whitespace
1035 while( nLength && (*pStr <= ' ') )
1037 nLength--; pStr++;
1040 // take letter
1041 if( nLength )
1043 sInitials.append( *pStr );
1044 nLength--; pStr++;
1047 // skip letters until whitespace
1048 while( nLength && (*pStr > ' ') )
1050 nLength--; pStr++;
1054 return sInitials.makeStringAndClear();
1057 void ImplExportComments( const uno::Reference< drawing::XDrawPage >& xPage, SvMemoryStream& rBinaryTagData10Atom )
1061 uno::Reference< office::XAnnotationAccess > xAnnotationAccess( xPage, uno::UNO_QUERY_THROW );
1062 uno::Reference< office::XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() );
1064 sal_Int32 nIndex = 1;
1066 while( xAnnotationEnumeration->hasMoreElements() )
1068 EscherExContainer aComment10( rBinaryTagData10Atom, EPP_Comment10 );
1070 uno::Reference< office::XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement() );
1072 geometry::RealPoint2D aRealPoint2D( xAnnotation->getPosition() );
1073 MapMode aMapDest( MapUnit::MapInch, Point(), Fraction( 1, 576 ), Fraction( 1, 576 ) );
1074 Point aPoint( OutputDevice::LogicToLogic( Point( static_cast< sal_Int32 >( aRealPoint2D.X * 100.0 ),
1075 static_cast<sal_Int32>(aRealPoint2D.Y * 100.0)), MapMode(MapUnit::Map100thMM), aMapDest));
1077 OUString sAuthor( xAnnotation->getAuthor() );
1078 uno::Reference< text::XText > xText( xAnnotation->getTextRange() );
1079 OUString sText( xText->getString() );
1080 OUString sInitials( getInitials( sAuthor ) );
1081 util::DateTime aDateTime( xAnnotation->getDateTime() );
1082 if ( !sAuthor.isEmpty() )
1083 PPTWriter::WriteCString( rBinaryTagData10Atom, sAuthor );
1084 if ( !sText.isEmpty() )
1085 PPTWriter::WriteCString( rBinaryTagData10Atom, sText, 1 );
1086 if ( !sInitials.isEmpty() )
1087 PPTWriter::WriteCString( rBinaryTagData10Atom, sInitials, 2 );
1089 sal_Int16 nMilliSeconds = static_cast<sal_Int16>(::rtl::math::round(static_cast<double>(aDateTime.NanoSeconds) / 1000000000.0));
1090 EscherExAtom aCommentAtom10( rBinaryTagData10Atom, EPP_CommentAtom10 );
1091 rBinaryTagData10Atom.WriteInt32( nIndex++ )
1092 .WriteInt16( aDateTime.Year )
1093 .WriteUInt16( aDateTime.Month )
1094 .WriteUInt16( aDateTime.Day ) // todo: day of week
1095 .WriteUInt16( aDateTime.Day )
1096 .WriteUInt16( aDateTime.Hours )
1097 .WriteUInt16( aDateTime.Minutes )
1098 .WriteUInt16( aDateTime.Seconds )
1099 .WriteInt16( nMilliSeconds )
1100 .WriteInt32( aPoint.X() )
1101 .WriteInt32( aPoint.Y() );
1105 catch ( uno::Exception& )
1110 void PPTWriter::ImplWriteNotes( sal_uInt32 nPageNum )
1112 mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_Notes | nPageNum, mpStrm->Tell() );
1113 mpPptEscherEx->OpenContainer( EPP_Notes );
1114 mpPptEscherEx->AddAtom( 8, EPP_NotesAtom, 1 );
1115 mpStrm->WriteUInt32( nPageNum + 0x100 )
1116 .WriteUInt16( 3 ) // follow master...
1117 .WriteUInt16( 0 );
1119 ImplCreateHeaderFooters( mXPagePropSet );
1121 EscherSolverContainer aSolverContainer;
1123 mpPptEscherEx->OpenContainer( EPP_PPDrawing );
1124 mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
1125 mpPptEscherEx->EnterGroup(nullptr,nullptr);
1127 ImplWritePage( GetLayout( 20 ), aSolverContainer, NOTICE, false ); // the shapes of the pages are created in the PPT document
1129 mpPptEscherEx->LeaveGroup();
1130 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1131 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
1132 EscherPropertyContainer aPropOpt;
1133 aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0xffffff ); // stock valued fill color
1134 aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0 );
1135 aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, 0x8b9f8e );
1136 aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, 0x68bdde );
1137 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
1138 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
1139 aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow );
1140 aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 );
1141 aPropOpt.Commit( *mpStrm );
1142 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
1144 aSolverContainer.WriteSolver( *mpStrm );
1146 mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer
1147 mpPptEscherEx->CloseContainer(); // EPP_Drawing
1148 mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
1149 mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
1150 mpPptEscherEx->CloseContainer(); // EPP_Notes
1153 void PPTWriter::ImplWriteBackground( css::uno::Reference< css::beans::XPropertySet > const & rXPropSet )
1155 //************************ ******
1156 //** DEFAULT BACKGROUND SHAPE **
1158 sal_uInt32 nFillColor = 0xffffff;
1159 sal_uInt32 nFillBackColor = 0;
1161 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1162 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
1164 // #i121183# Use real PageSize in 100th mm
1165 ::tools::Rectangle aRect(Point(0, 0), Size(maPageSize.Width, maPageSize.Height));
1167 EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
1168 aPropOpt.AddOpt( ESCHER_Prop_fillType, ESCHER_FillSolid );
1169 css::drawing::FillStyle aFS( css::drawing::FillStyle_NONE );
1170 if ( ImplGetPropertyValue( rXPropSet, "FillStyle" ) )
1171 mAny >>= aFS;
1173 switch( aFS )
1175 case css::drawing::FillStyle_GRADIENT :
1177 aPropOpt.CreateGradientProperties( rXPropSet );
1178 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x1f001e );
1179 aPropOpt.GetOpt( ESCHER_Prop_fillColor, nFillColor );
1180 aPropOpt.GetOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
1182 break;
1184 case css::drawing::FillStyle_BITMAP :
1185 aPropOpt.CreateGraphicProperties( rXPropSet, "FillBitmap", true );
1186 break;
1188 case css::drawing::FillStyle_HATCH :
1189 aPropOpt.CreateGraphicProperties( rXPropSet, "FillHatch", true );
1190 break;
1192 case css::drawing::FillStyle_SOLID :
1194 if ( ImplGetPropertyValue( rXPropSet, "FillColor" ) )
1196 nFillColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(mAny) );
1197 nFillBackColor = nFillColor ^ 0xffffff;
1199 [[fallthrough]];
1201 case css::drawing::FillStyle_NONE :
1202 default:
1203 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
1204 break;
1206 aPropOpt.AddOpt( ESCHER_Prop_fillColor, nFillColor );
1207 aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
1208 aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, PPTtoEMU( maDestPageSize.Width ) );
1209 aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, PPTtoEMU( maDestPageSize.Height ) );
1210 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
1211 aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_bwWhite );
1212 aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 );
1213 aPropOpt.Commit( *mpStrm );
1214 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
1217 void PPTWriter::ImplWriteVBA()
1219 if ( mpVBA )
1221 sal_uInt32 nLen = mpVBA->TellEnd();
1222 if ( nLen > 8 )
1224 nLen -= 8;
1225 mnVBAOleOfs = mpStrm->Tell();
1226 mpPptEscherEx->BeginAtom();
1227 mpStrm->WriteBytes(static_cast<sal_Int8 const *>(mpVBA->GetData()) + 8, nLen);
1228 mpPptEscherEx->EndAtom( EPP_ExOleObjStg, 0, 1 );
1233 void PPTWriter::ImplWriteOLE( )
1236 SvxMSExportOLEObjects aOleExport( mnCnvrtFlags );
1238 for ( const auto& rxExOleObjEntry : maExOleObj )
1240 PPTExOleObjEntry* pPtr = rxExOleObjEntry.get();
1241 std::unique_ptr<SvMemoryStream> pStrm;
1242 pPtr->nOfsB = mpStrm->Tell();
1243 switch ( pPtr->eType )
1245 case NORMAL_OLE_OBJECT :
1247 SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(pPtr->xShape);
1248 if ( auto pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >(pSdrObj) )
1250 const ::uno::Reference < embed::XEmbeddedObject >& xObj( pSdrOle2Obj->GetObjRef() );
1251 if( xObj.is() )
1253 tools::SvRef<SotStorage> xTempStorage( new SotStorage( new SvMemoryStream(), true ) );
1254 aOleExport.ExportOLEObject( xObj, *xTempStorage );
1256 //TODO/MBA: testing
1257 SvMemoryStream aStream;
1258 tools::SvRef<SotStorage> xCleanStorage( new SotStorage( false, aStream ) );
1259 xTempStorage->CopyTo( xCleanStorage.get() );
1260 // create a dummy content stream, the dummy content is necessary for ppt, but not for
1261 // doc files, so we can't share code.
1262 tools::SvRef<SotStorageStream> xStm = xCleanStorage->OpenSotStream( SVEXT_PERSIST_STREAM );
1263 xStm->WriteUInt32( 0 ) // no ClipboardId
1264 .WriteUInt32( 4 ) // no target device
1265 .WriteUInt32( 1 ) // aspect ratio
1266 .WriteInt32( -1 ) // L-Index
1267 .WriteUInt32( 0 ) // Advanced Flags
1268 .WriteUInt32( 0 ) // compression
1269 .WriteUInt32( 0 ) // Size
1270 .WriteUInt32( 0 ) // "
1271 .WriteUInt32( 0 );
1272 pStrm = xCleanStorage->CreateMemoryStream();
1276 break;
1278 case OCX_CONTROL :
1280 if ( pPtr->xControlModel.is() )
1282 OUString aName;
1283 //Initialize the graphic size which will be used on export
1284 css::awt::Size aSize( pPtr->xShape->getSize() );
1285 tools::SvRef<SotStorage> xDest( new SotStorage( new SvMemoryStream(), true ) );
1286 bool bOk = oox::ole::MSConvertOCXControls::WriteOCXStream( mXModel, xDest, pPtr->xControlModel, aSize, aName );
1287 if ( bOk )
1288 pStrm = xDest->CreateMemoryStream();
1292 if ( pStrm )
1294 mpPptEscherEx->BeginAtom();
1295 pStrm->Seek( STREAM_SEEK_TO_END );
1296 sal_uInt32 npStrmSize = pStrm->Tell();
1297 mpStrm->WriteUInt32( npStrmSize ); // uncompressed size
1299 pStrm->Seek( 0 );
1300 ZCodec aZCodec( 0x8000, 0x8000 );
1301 aZCodec.BeginCompression();
1302 aZCodec.Compress( *pStrm, *mpStrm );
1303 aZCodec.EndCompression();
1304 pStrm.reset();
1305 mpPptEscherEx->EndAtom( EPP_ExOleObjStg, 0, 1 );
1310 // write PersistantTable and UserEditAtom
1312 void PPTWriter::ImplWriteAtomEnding()
1315 #define EPP_LastViewTypeSlideView 1
1317 sal_uInt32 i, nPos, nOfs, nPersistOfs = mpStrm->Tell();
1318 sal_uInt32 nPersistEntrys = 0;
1319 mpStrm->WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ); // skip record header and first entry
1321 // write document persist
1322 nPersistEntrys++;
1323 mpStrm->WriteUInt32( 0 );
1324 // write MasterPages persists
1325 for ( i = 0; i < mnMasterPages; i++ )
1327 nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_MainMaster | i );
1328 if ( nOfs )
1330 mpStrm->WriteUInt32( nOfs );
1331 mpPptEscherEx->InsertAtPersistOffset( EPP_MAINMASTER_PERSIST_KEY | i, ++nPersistEntrys );
1334 // write MainNotesMaster persist
1335 nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_MainNotes );
1336 if ( nOfs )
1338 mpStrm->WriteUInt32( nOfs );
1339 mpPptEscherEx->InsertAtPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY, ++nPersistEntrys );
1341 // write slide persists -> we have to write a valid value into EPP_SlidePersistAtome too
1342 for ( i = 0; i < mnPages; i++ )
1344 nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Slide | i );
1345 if ( nOfs )
1347 mpStrm->WriteUInt32( nOfs );
1348 mpPptEscherEx->InsertAtPersistOffset( EPP_MAINSLIDE_PERSIST_KEY | i, ++nPersistEntrys );
1351 // write Notes persists
1352 for ( i = 0; i < mnPages; i++ )
1354 nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Notes | i );
1355 if ( nOfs )
1357 mpStrm->WriteUInt32( nOfs );
1358 mpPptEscherEx->InsertAtPersistOffset( EPP_MAINNOTES_PERSIST_KEY | i, ++nPersistEntrys );
1361 // Ole persists
1362 for ( const auto& rxExOleObjEntry : maExOleObj )
1364 PPTExOleObjEntry* pPtr = rxExOleObjEntry.get();
1365 nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_ExObj );
1366 if ( nOfs )
1368 nPersistEntrys++;
1369 mpStrm->WriteUInt32( pPtr->nOfsB );
1370 sal_uInt32 nOldPos, nPersOfs = nOfs + pPtr->nOfsA + 16 + 8; // 8 bytes atom header, +16 to the persist entry
1371 nOldPos = mpStrm->Tell();
1372 mpStrm->Seek( nPersOfs );
1373 mpStrm->WriteUInt32( nPersistEntrys );
1374 mpStrm->Seek( nOldPos );
1377 // VB persist
1378 if ( mnVBAOleOfs && mpVBA )
1380 nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_VBAInfoAtom );
1381 if ( nOfs )
1383 nPersistEntrys++;
1384 sal_uInt32 n1, n2;
1386 mpVBA->Seek( 0 );
1387 mpVBA->ReadUInt32( n1 )
1388 .ReadUInt32( n2 );
1390 mpStrm->WriteUInt32( mnVBAOleOfs );
1391 sal_uInt32 nOldPos = mpStrm->Tell();
1392 mpStrm->Seek( nOfs ); // Fill the VBAInfoAtom with the correct index to the persisttable
1393 mpStrm->WriteUInt32( nPersistEntrys )
1394 .WriteUInt32( n1 )
1395 .WriteInt32( 2 );
1396 mpStrm->Seek( nOldPos );
1400 nPos = mpStrm->Tell();
1401 mpStrm->Seek( nPersistOfs );
1402 mpPptEscherEx->AddAtom( ( nPersistEntrys + 1 ) << 2, EPP_PersistPtrIncrementalBlock ); // insert Record Header
1403 mpStrm->WriteUInt32( ( nPersistEntrys << 20 ) | 1 );
1404 mpStrm->Seek( nPos );
1406 mpCurUserStrm->WriteUInt32( nPos ); // set offset to current edit
1407 mpPptEscherEx->AddAtom( 28, EPP_UserEditAtom );
1408 mpStrm->WriteInt32( 0x100 ) // last slide ID
1409 .WriteUInt32( 0x03000dbc ) // minor and major app version that did the save
1410 .WriteUInt32( 0 ) // offset last save, 0 after a full save
1411 .WriteUInt32( nPersistOfs ) // File offset to persist pointers for this save operation
1412 .WriteUInt32( 1 ) // Persist reference to the document persist object
1413 .WriteUInt32( nPersistEntrys ) // max persists written, Seed value for persist object id management
1414 .WriteInt16( EPP_LastViewTypeSlideView ) // last view type
1415 .WriteInt16( 0x12 ); // padword
1418 // - exported function -
1420 extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool ExportPPT( const std::vector< css::beans::PropertyValue >& rMediaData,
1421 tools::SvRef<SotStorage> const & rSvStorage,
1422 css::uno::Reference< css::frame::XModel > const & rXModel,
1423 css::uno::Reference< css::task::XStatusIndicator > const & rXStatInd,
1424 SvMemoryStream* pVBA,
1425 sal_uInt32 nCnvrtFlags )
1427 PPTWriter aPPTWriter( rSvStorage, rXModel, rXStatInd, pVBA, nCnvrtFlags );
1428 aPPTWriter.exportPPT(rMediaData);
1429 bool bStatus = aPPTWriter.IsValid();
1430 return bStatus;
1433 extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool SaveVBA( SfxObjectShell& rDocShell, SvMemoryStream*& pBas )
1435 tools::SvRef<SotStorage> xDest( new SotStorage( new SvMemoryStream(), true ) );
1436 SvxImportMSVBasic aMSVBas( rDocShell, *xDest );
1437 aMSVBas.SaveOrDelMSVBAStorage( true, "_MS_VBA_Overhead" );
1439 tools::SvRef<SotStorage> xOverhead = xDest->OpenSotStorage( "_MS_VBA_Overhead" );
1440 if ( xOverhead.is() && ( xOverhead->GetError() == ERRCODE_NONE ) )
1442 tools::SvRef<SotStorage> xOverhead2 = xOverhead->OpenSotStorage( "_MS_VBA_Overhead" );
1443 if ( xOverhead2.is() && ( xOverhead2->GetError() == ERRCODE_NONE ) )
1445 tools::SvRef<SotStorageStream> xTemp = xOverhead2->OpenSotStream( "_MS_VBA_Overhead2" );
1446 if ( xTemp.is() && ( xTemp->GetError() == ERRCODE_NONE ) )
1448 sal_uInt32 nLen = xTemp->GetSize();
1449 if ( nLen )
1451 char* pTemp = new char[ nLen ];
1452 xTemp->Seek( STREAM_SEEK_TO_BEGIN );
1453 xTemp->ReadBytes(pTemp, nLen);
1454 pBas = new SvMemoryStream( pTemp, nLen, StreamMode::READ );
1455 pBas->ObjectOwnsMemory( true );
1456 return true;
1462 return false;
1465 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */