1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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/svdobj.hxx>
28 #include <svx/svdoole2.hxx>
29 #include <com/sun/star/container/XIndexContainer.hpp>
30 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
31 #include <com/sun/star/drawing/FillStyle.hpp>
32 #include <com/sun/star/drawing/XDrawPage.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 <unotools/securityoptions.hxx>
46 #include <filter/msfilter/classids.hxx>
47 #include <filter/msfilter/msoleexp.hxx>
48 #include <filter/msfilter/msdffimp.hxx>
49 #include <filter/msfilter/svxmsbas.hxx>
50 #include <editeng/flditem.hxx>
51 #include <sfx2/docinf.hxx>
52 #include <oox/export/utils.hxx>
53 #include <oox/ole/olehelper.hxx>
54 #include <sdfilter.hxx>
59 // complete SfxObjectShell for SaveVBA under -fsanitize=function
61 using namespace com::sun::star
;
62 using namespace ::com::sun::star::uno
;
63 using namespace ::com::sun::star::presentation
;
65 using ::com::sun::star::beans::XPropertySet
;
67 //============================ PPTWriter ==================================
69 PPTWriter::PPTWriter( rtl::Reference
<SotStorage
> xSvStorage
,
70 css::uno::Reference
< css::frame::XModel
> const & rXModel
,
71 css::uno::Reference
< css::task::XStatusIndicator
> const & rXStatInd
,
72 SvMemoryStream
* pVBA
, sal_uInt32 nCnvrtFlags
) :
73 PPTWriterBase ( rXModel
, rXStatInd
),
74 mnCnvrtFlags ( nCnvrtFlags
),
77 mnLatestStatValue ( 0 ),
79 mbFontIndependentLineSpacing( false ),
81 mrStg (std::move( xSvStorage
)),
85 mpExEmbed ( new SvMemoryStream
),
86 mpAuthorIDs ( new SvtSecurityMapPersonalInfo
),
90 mnShapeMasterTitle ( 0 ),
91 mnShapeMasterBody ( 0 )
95 void PPTWriter::exportPPTPre( const std::vector
< css::beans::PropertyValue
>& rMediaData
)
100 if ( mXStatusIndicator
.is() )
102 mbStatusIndicator
= true;
103 mnStatMaxValue
= ( mnPages
+ mnMasterPages
) * 5;
104 mXStatusIndicator
->start( u
"PowerPoint Export"_ustr
, mnStatMaxValue
+ ( mnStatMaxValue
>> 3 ) );
107 SvGlobalName
aGName(MSO_PPT8_CLASSID
);
108 mrStg
->SetClass( aGName
, SotClipboardFormatId::NONE
, u
"MS PowerPoint 97"_ustr
);
110 if ( !ImplCreateCurrentUserStream() )
113 mpStrm
= mrStg
->OpenSotStream( u
"PowerPoint Document"_ustr
);
118 mpPicStrm
= mrStg
->OpenSotStream( u
"Pictures"_ustr
);
120 auto aIter
= std::find_if(rMediaData
.begin(), rMediaData
.end(),
121 [](const css::beans::PropertyValue
& rProp
) { return rProp
.Name
== "BaseURI"; });
122 if (aIter
!= rMediaData
.end())
123 (*aIter
).Value
>>= maBaseURI
;
124 mpPptEscherEx
.reset( new PptEscherEx( *mpStrm
, maBaseURI
) );
127 void PPTWriter::exportPPTPost( )
129 if ( !ImplCloseDocument() )
132 if ( mbStatusIndicator
)
134 mXStatusIndicator
->setText( u
"PowerPoint Export"_ustr
);
135 sal_uInt32 nValue
= mnStatMaxValue
+ ( mnStatMaxValue
>> 3 );
136 if ( nValue
> mnLatestStatValue
)
138 mXStatusIndicator
->setValue( nValue
);
139 mnLatestStatValue
= nValue
;
147 ImplWriteAtomEnding();
149 ImplCreateDocumentSummaryInformation();
154 void PPTWriter::ImplWriteSlide( sal_uInt32 nPageNum
, sal_uInt32 nMasterNum
, sal_uInt16 nMode
,
155 bool bHasBackground
, Reference
< XPropertySet
> const & aXBackgroundPropSet
)
159 const PHLayout
& rLayout
= GetLayout( mXPagePropSet
);
160 mpPptEscherEx
->PtReplaceOrInsert( EPP_Persist_Slide
| nPageNum
, mpStrm
->Tell() );
161 mpPptEscherEx
->OpenContainer( EPP_Slide
);
162 mpPptEscherEx
->AddAtom( 24, EPP_SlideAtom
, 2 );
163 mpStrm
->WriteInt32( static_cast<sal_Int32
>(rLayout
.nLayout
) );
164 mpStrm
->WriteBytes(rLayout
.nPlaceHolder
, 8); // placeholderIDs (8 parts)
165 mpStrm
->WriteUInt32( nMasterNum
| 0x80000000 ) // master ID (equals 0x80000000 on a master page)
166 .WriteUInt32( nPageNum
+ 0x100 ) // notes ID (equals null if no notes are present)
167 .WriteUInt16( nMode
)
168 .WriteUInt16( 0 ); // padword
171 bool bVisible
= true;
172 css::presentation::FadeEffect eFe
= css::presentation::FadeEffect_NONE
;
174 if ( GetPropertyValue( aAny
, mXPagePropSet
, u
"Visible"_ustr
) )
176 if ( GetPropertyValue( aAny
, mXPagePropSet
, u
"Change"_ustr
) )
178 switch ( *o3tl::doAccess
<sal_Int32
>(aAny
) )
180 case 1 : // automatic
183 case 2 : // semi-automatic
191 if ( GetPropertyValue( aAny
, mXPagePropSet
, u
"Effect"_ustr
) )
194 sal_uInt32 nSoundRef
= 0;
195 bool bIsSound
= false;
196 bool bStopSound
= false;
197 bool bLoopSound
= false;
199 if ( GetPropertyValue( aAny
, mXPagePropSet
, u
"Sound"_ustr
) )
202 if ( aAny
>>= aSoundURL
)
204 nSoundRef
= maSoundCollection
.GetId( aSoundURL
);
210 if ( GetPropertyValue( aAny
, mXPagePropSet
, u
"LoopSound"_ustr
) )
213 bool bNeedsSSSlideInfoAtom
= !bVisible
214 || ( mnDiaMode
== 2 )
217 || ( eFe
!= css::presentation::FadeEffect_NONE
);
218 if ( bNeedsSSSlideInfoAtom
)
220 sal_uInt8 nDirection
= 0;
221 sal_uInt8 nTransitionType
= 0;
222 sal_uInt16 nBuildFlags
= 1; // advance by mouseclick
223 sal_Int32 nSlideTime
= 0; // still has to !!!
224 sal_uInt8 nSpeed
= 1;
226 if ( GetPropertyValue( aAny
, mXPagePropSet
, u
"TransitionDuration"_ustr
) )
228 css::presentation::AnimationSpeed aAs
;
229 double fTransitionDuration
= -1.0;
230 aAny
>>= fTransitionDuration
;
232 if (fTransitionDuration
>= 0)
234 if (fTransitionDuration
<= 0.5)
236 aAs
= css::presentation::AnimationSpeed::AnimationSpeed_FAST
;
238 else if (fTransitionDuration
>= 1.0)
240 aAs
= css::presentation::AnimationSpeed::AnimationSpeed_SLOW
;
244 aAs
= css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM
;
248 aAs
= css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM
;
250 nSpeed
= static_cast<sal_uInt8
>(aAs
);
253 if ( GetPropertyValue( aAny
, mXPagePropSet
, u
"TransitionType"_ustr
)
254 && ( aAny
>>= nTT
) )
257 if ( GetPropertyValue( aAny
, mXPagePropSet
, u
"TransitionSubtype"_ustr
)
258 && ( aAny
>>= nTST
) )
259 nTransitionType
= GetTransition( nTT
, nTST
, eFe
, 0, nDirection
);
262 if ( !nTransitionType
)
263 nTransitionType
= GetTransition( eFe
, nDirection
);
264 if ( mnDiaMode
== 2 ) // automatic ?
265 nBuildFlags
|= 0x400;
275 if ( GetPropertyValue( aAny
, mXPagePropSet
, u
"Duration"_ustr
) )// duration of this slide
276 nSlideTime
= *o3tl::doAccess
<sal_Int32
>(aAny
) << 10; // in ticks
278 mpPptEscherEx
->AddAtom( 16, EPP_SSSlideInfoAtom
);
279 mpStrm
->WriteInt32( nSlideTime
) // standtime in ticks
280 .WriteUInt32( nSoundRef
)
281 .WriteUChar( nDirection
)
282 .WriteUChar( nTransitionType
)
283 .WriteUInt16( nBuildFlags
)
284 .WriteUChar( nSpeed
)
285 .WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
288 ImplCreateHeaderFooters( mXPagePropSet
);
290 EscherSolverContainer aSolverContainer
;
291 mpPptEscherEx
->OpenContainer( EPP_PPDrawing
);
292 mpPptEscherEx
->OpenContainer( ESCHER_DgContainer
);
293 mpPptEscherEx
->EnterGroup(nullptr,nullptr);
294 ImplWritePage( rLayout
, aSolverContainer
, NORMAL
, false, nPageNum
); // the shapes of the pages are created in the PPT document
295 mpPptEscherEx
->LeaveGroup();
297 if ( bHasBackground
)
298 ImplWriteBackground( aXBackgroundPropSet
);
301 mpPptEscherEx
->OpenContainer( ESCHER_SpContainer
);
302 mpPptEscherEx
->AddShape( ESCHER_ShpInst_Rectangle
,
303 ShapeFlag::Background
| ShapeFlag::HaveShapeProperty
);
304 EscherPropertyContainer aPropOpt
;
305 aPropOpt
.AddOpt( ESCHER_Prop_fillRectRight
, PPTtoEMU( maDestPageSize
.Width
) );
306 aPropOpt
.AddOpt( ESCHER_Prop_fillRectBottom
, PPTtoEMU( maDestPageSize
.Width
) );
307 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x120012 );
308 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x80000 );
309 aPropOpt
.AddOpt( ESCHER_Prop_bWMode
, ESCHER_wDontShow
);
310 aPropOpt
.AddOpt( ESCHER_Prop_fBackground
, 0x10001 ); // if true, this is the background shape
311 aPropOpt
.Commit( *mpStrm
);
312 mpPptEscherEx
->CloseContainer(); // ESCHER_SpContainer
315 aSolverContainer
.WriteSolver( *mpStrm
);
317 mpPptEscherEx
->CloseContainer(); // ESCHER_DgContainer
318 mpPptEscherEx
->CloseContainer(); // EPP_Drawing
319 mpPptEscherEx
->AddAtom( 32, EPP_ColorSchemeAtom
, 0, 1 );
320 mpStrm
->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
322 SvMemoryStream aBinaryTagData10Atom
;
323 ImplExportComments( mXDrawPage
, aBinaryTagData10Atom
);
324 SvMemoryStream amsofbtAnimGroup
;
325 ppt::AnimationExporter
aExporter( aSolverContainer
, maSoundCollection
);
326 aExporter
.doexport( mXDrawPage
, amsofbtAnimGroup
);
327 sal_uInt64 nmsofbtAnimGroupSize
= amsofbtAnimGroup
.Tell();
328 if ( nmsofbtAnimGroupSize
)
331 EscherExAtom
aMagic2( aBinaryTagData10Atom
, 0x2eeb );
332 aBinaryTagData10Atom
.WriteUInt32( 0x01c45df9 )
333 .WriteUInt32( 0xe1471b30 );
336 EscherExAtom
aMagic( aBinaryTagData10Atom
, 0x2b00 );
337 aBinaryTagData10Atom
.WriteUInt32( 0 );
339 aBinaryTagData10Atom
.WriteBytes(amsofbtAnimGroup
.GetData(), amsofbtAnimGroup
.Tell());
341 EscherExContainer
aMagic2( aBinaryTagData10Atom
, 0x2b02 );
344 if ( aBinaryTagData10Atom
.Tell() )
346 EscherExContainer
aProgTags ( *mpStrm
, EPP_ProgTags
);
347 EscherExContainer
aProgBinaryTag( *mpStrm
, EPP_ProgBinaryTag
);
349 EscherExAtom
aCString( *mpStrm
, EPP_CString
);
350 mpStrm
->WriteUInt32( 0x5f005f )
351 .WriteUInt32( 0x50005f )
352 .WriteUInt32( 0x540050 )
354 .WriteUInt16( 0x30 );
357 EscherExAtom
aBinaryTagData( *mpStrm
, EPP_BinaryTagData
);
358 mpStrm
->WriteBytes(aBinaryTagData10Atom
.GetData(), aBinaryTagData10Atom
.Tell());
361 mpPptEscherEx
->CloseContainer(); // EPP_Slide
364 void PPTWriter::ImplWriteSlideMaster( sal_uInt32 nPageNum
, Reference
< XPropertySet
> const & aXBackgroundPropSet
)
366 if (!aXBackgroundPropSet
)
368 mpPptEscherEx
->PtReplaceOrInsert( EPP_Persist_MainMaster
| nPageNum
, mpStrm
->Tell() );
369 mpPptEscherEx
->OpenContainer( EPP_MainMaster
);
370 mpPptEscherEx
->AddAtom( 24, EPP_SlideAtom
, 2 );
371 mpStrm
->WriteInt32( static_cast<sal_Int32
>(EppLayout::TITLEANDBODYSLIDE
) ) // slide layout -> title and body slide
372 .WriteUChar( 1 ).WriteUChar( 2 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ) // placeholderID
373 .WriteUInt32( 0 ) // master ID (equals null at a master page)
374 .WriteUInt32( 0 ) // notes ID (equals null if no notes are present)
375 .WriteUInt16( 0 ) // Bit 1: Follow master objects, Bit 2: Follow master scheme, Bit 3: Follow master background
376 .WriteUInt16( 0 ); // padword
378 mpPptEscherEx
->AddAtom( 32, EPP_ColorSchemeAtom
, 0, 6 );
379 mpStrm
->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
380 mpPptEscherEx
->AddAtom( 32, EPP_ColorSchemeAtom
, 0, 6 );
381 mpStrm
->WriteUInt32( 0xff0000 ).WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x00ffff ).WriteUInt32( 0x0099ff ).WriteUInt32( 0xffff00 ).WriteUInt32( 0x0000ff ).WriteUInt32( 0x969696 );
382 mpPptEscherEx
->AddAtom( 32, EPP_ColorSchemeAtom
, 0, 6 );
383 mpStrm
->WriteUInt32( 0xccffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x336666 ).WriteUInt32( 0x008080 ).WriteUInt32( 0x339933 ).WriteUInt32( 0x000080 ).WriteUInt32( 0xcc3300 ).WriteUInt32( 0x66ccff );
384 mpPptEscherEx
->AddAtom( 32, EPP_ColorSchemeAtom
, 0, 6 );
385 mpStrm
->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x333333 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xdddddd ).WriteUInt32( 0x808080 ).WriteUInt32( 0x4d4d4d ).WriteUInt32( 0xeaeaea );
386 mpPptEscherEx
->AddAtom( 32, EPP_ColorSchemeAtom
, 0, 6 );
387 mpStrm
->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x66ccff ).WriteUInt32( 0xff0000 ).WriteUInt32( 0xcc00cc ).WriteUInt32( 0xc0c0c0 );
388 mpPptEscherEx
->AddAtom( 32, EPP_ColorSchemeAtom
, 0, 6 );
389 mpStrm
->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xc0c0c0 ).WriteUInt32( 0xff6600 ).WriteUInt32( 0x0000ff ).WriteUInt32( 0x009900 );
390 mpPptEscherEx
->AddAtom( 32, EPP_ColorSchemeAtom
, 0, 6 );
391 mpStrm
->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xff9933 ).WriteUInt32( 0xccff99 ).WriteUInt32( 0xcc00cc ).WriteUInt32( 0xb2b2b2 );
393 for ( int nInstance
= EPP_TEXTTYPE_Title
; nInstance
<= EPP_TEXTTYPE_QuarterBody
; nInstance
++ )
395 if ( nInstance
== EPP_TEXTTYPE_notUsed
)
398 // the auto color is dependent to the page background,so we have to set a page that is in the right context
399 if ( nInstance
== EPP_TEXTTYPE_Notes
)
400 (void)GetPageByIndex(0, NOTICE
);
402 (void)GetPageByIndex(0, MASTER
);
404 mpPptEscherEx
->BeginAtom();
406 bool bSimpleText
= false;
408 mpStrm
->WriteUInt16( 5 ); // paragraph count
410 for ( sal_uInt16 nLev
= 0; nLev
< 5; nLev
++ )
412 if ( nInstance
>= EPP_TEXTTYPE_CenterBody
)
415 mpStrm
->WriteUInt16( nLev
);
417 mpStyleSheet
->mpParaSheet
[ nInstance
]->Write( *mpStrm
, nLev
, bSimpleText
, mXPagePropSet
);
418 mpStyleSheet
->mpCharSheet
[ nInstance
]->Write( *mpStrm
, nLev
, bSimpleText
, mXPagePropSet
);
420 mpPptEscherEx
->EndAtom( EPP_TxMasterStyleAtom
, 0, nInstance
);
422 GetPageByIndex( nPageNum
, MASTER
);
424 EscherSolverContainer aSolverContainer
;
426 mpPptEscherEx
->OpenContainer( EPP_PPDrawing
);
427 mpPptEscherEx
->OpenContainer( ESCHER_DgContainer
);
429 mpPptEscherEx
->EnterGroup(nullptr,nullptr);
430 ImplWritePage( GetLayout( 0 ), aSolverContainer
, MASTER
, true ); // the shapes of the pages are created in the PPT document
431 mpPptEscherEx
->LeaveGroup();
433 ImplWriteBackground( aXBackgroundPropSet
);
435 aSolverContainer
.WriteSolver( *mpStrm
);
437 mpPptEscherEx
->CloseContainer(); // ESCHER_DgContainer
438 mpPptEscherEx
->CloseContainer(); // EPP_Drawing
439 mpPptEscherEx
->AddAtom( 32, EPP_ColorSchemeAtom
, 0, 1 );
440 mpStrm
->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
442 if ( aBuExMasterStream
.Tell() )
444 ImplProgTagContainer( mpStrm
.get(), &aBuExMasterStream
);
446 mpPptEscherEx
->CloseContainer(); // EPP_MainMaster
449 PPTWriter::~PPTWriter()
452 mpPptEscherEx
.reset();
453 mpCurUserStrm
.clear();
456 maStyleSheetList
.clear();
458 if ( mbStatusIndicator
)
459 mXStatusIndicator
->end();
462 bool PPTWriter::ImplCreateCurrentUserStream()
464 mpCurUserStrm
= mrStg
->OpenSotStream( u
"Current User"_ustr
);
465 if ( !mpCurUserStrm
)
467 char pUserName
[] = "Current User";
468 sal_uInt32 nLenOfUserName
= strlen( pUserName
);
469 sal_uInt32 nSizeOfRecord
= 0x14 + ( ( nLenOfUserName
+ 4 ) & ~ 3 );
471 mpCurUserStrm
->WriteUInt16( 0 ).WriteUInt16( EPP_CurrentUserAtom
).WriteUInt32( nSizeOfRecord
);
472 mpCurUserStrm
->WriteUInt32( 0x14 ) // Len
473 .WriteUInt32( 0xe391c05f ); // Magic
475 sal_uInt64 nEditPos
= mpCurUserStrm
->Tell();
476 mpCurUserStrm
->WriteUInt32( 0x0 ) // OffsetToCurrentEdit;
477 .WriteUInt16( nLenOfUserName
)
478 .WriteUInt16( 0x3f4 ) // DocFileVersion
479 .WriteUChar( 3 ) // MajorVersion
480 .WriteUChar( 0 ) // MinorVersion
481 .WriteUInt16( 0 ); // Pad Word
482 pUserName
[ nLenOfUserName
] = 8;
483 mpCurUserStrm
->WriteBytes(pUserName
, nLenOfUserName
+ 1);
484 for ( sal_uInt32 i
= 0x15 + nLenOfUserName
; i
< nSizeOfRecord
; i
++ )
486 mpCurUserStrm
->WriteUChar( 0 ); // pad bytes
488 mpCurUserStrm
->Seek( nEditPos
);
492 void PPTWriter::ImplCreateDocumentSummaryInformation()
494 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
495 mXModel
, uno::UNO_QUERY_THROW
);
496 uno::Reference
<document::XDocumentProperties
> xDocProps(
497 xDPS
->getDocumentProperties());
502 // no idea what this is...
503 static const sal_Int8 aGuid
[ 0x52 ] =
505 0x4e, 0x00, 0x00, 0x00,
506 '{',0,'D',0,'B',0,'1',0,'A',0,'C',0,'9',0,'6',0,'4',0,'-',0,
507 'E',0,'3',0,'9',0,'C',0,'-',0,'1',0,'1',0,'D',0,'2',0,'-',0,
508 'A',0,'1',0,'E',0,'F',0,'-',0,'0',0,'0',0,'6',0,'0',0,'9',0,
509 '7',0,'D',0,'A',0,'5',0,'6',0,'8',0,'9',0,'}',0
511 // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence
512 uno::Sequence
<sal_Int8
> aGuidSeq(aGuid
, 0x52);
514 SvMemoryStream aHyperBlob
;
515 ImplCreateHyperBlob( aHyperBlob
);
517 sal_uInt64 nHyperLength
= aHyperBlob
.Tell();
518 const sal_Int8
* pBlob(
519 static_cast<const sal_Int8
*>(aHyperBlob
.GetData()));
520 auto aHyperSeq
= comphelper::arrayToSequence
<sal_Int8
>(pBlob
, nHyperLength
);
522 if ( mnCnvrtFlags
& 0x8000 )
524 uno::Sequence
<sal_Int8
> aThumbSeq
;
525 if ( GetPageByIndex( 0, NORMAL
) && ImplGetPropertyValue( mXPagePropSet
, u
"PreviewBitmap"_ustr
) )
527 aThumbSeq
= *o3tl::doAccess
<uno::Sequence
<sal_Int8
>>(mAny
);
529 sfx2::SaveOlePropertySet( xDocProps
, mrStg
.get(),
530 &aThumbSeq
, &aGuidSeq
, &aHyperSeq
);
534 sfx2::SaveOlePropertySet( xDocProps
, mrStg
.get(),
535 nullptr, &aGuidSeq
, &aHyperSeq
);
539 void PPTWriter::ImplWriteExtParaHeader( SvMemoryStream
& rSt
, sal_uInt32 nRef
, sal_uInt32 nInstance
, sal_uInt32 nSlideId
)
543 aBuExOutlineStream
.WriteUInt32( ( EPP_PST_ExtendedParagraphHeaderAtom
<< 16 )
546 .WriteUInt32( nSlideId
)
547 .WriteUInt32( nInstance
);
548 aBuExOutlineStream
.WriteBytes(rSt
.GetData(), rSt
.Tell());
552 void PPTWriter::ImplCreateHeaderFooterStrings( SvStream
& rStrm
, css::uno::Reference
< css::beans::XPropertySet
> const & rXPagePropSet
)
554 if ( !rXPagePropSet
.is() )
559 if ( PropValue::GetPropertyValue( aAny
, rXPagePropSet
, u
"HeaderText"_ustr
, true ) )
561 if ( aAny
>>= aString
)
562 PPTWriter::WriteCString( rStrm
, aString
, 1 );
564 if ( PropValue::GetPropertyValue( aAny
, rXPagePropSet
, u
"FooterText"_ustr
, true ) )
566 if ( aAny
>>= aString
)
567 PPTWriter::WriteCString( rStrm
, aString
, 2 );
569 if ( PropValue::GetPropertyValue( aAny
, rXPagePropSet
, u
"DateTimeText"_ustr
, true ) )
571 if ( aAny
>>= aString
)
572 PPTWriter::WriteCString( rStrm
, aString
);
576 void PPTWriter::ImplCreateHeaderFooters( css::uno::Reference
< css::beans::XPropertySet
> const & rXPagePropSet
)
578 if ( !rXPagePropSet
.is() )
584 if ( PropValue::GetPropertyValue( aAny
, rXPagePropSet
, u
"IsHeaderVisible"_ustr
, true ) )
586 if ( ( aAny
>>= bVal
) && bVal
)
589 if ( PropValue::GetPropertyValue( aAny
, rXPagePropSet
, u
"IsFooterVisible"_ustr
, true ) )
591 if ( ( aAny
>>= bVal
) && bVal
)
594 if ( PropValue::GetPropertyValue( aAny
, rXPagePropSet
, u
"IsDateTimeVisible"_ustr
, true ) )
596 if ( ( aAny
>>= bVal
) && bVal
)
599 if ( PropValue::GetPropertyValue( aAny
, rXPagePropSet
, u
"IsPageNumberVisible"_ustr
, true ) )
601 if ( ( aAny
>>= bVal
) && bVal
)
604 if ( PropValue::GetPropertyValue( aAny
, rXPagePropSet
, u
"IsDateTimeFixed"_ustr
, true ) )
606 if ( ( aAny
>>= bVal
) && !bVal
)
611 if ( PropValue::GetPropertyValue( aAny
, rXPagePropSet
, u
"DateTimeFormat"_ustr
, true ) )
613 sal_Int32 nFormat
= *o3tl::doAccess
<sal_Int32
>(aAny
);
614 SvxDateFormat eDateFormat
= static_cast<SvxDateFormat
>( nFormat
& 0xf );
615 SvxTimeFormat eTimeFormat
= static_cast<SvxTimeFormat
>( ( nFormat
>> 4 ) & 0xf );
616 switch( eDateFormat
)
618 case SvxDateFormat::F
:
621 case SvxDateFormat::D
:
624 case SvxDateFormat::C
:
628 case SvxDateFormat::A
:
631 switch( eTimeFormat
)
633 case SvxTimeFormat::HH24_MM
:
636 case SvxTimeFormat::HH12_MM
:
639 case SvxTimeFormat::HH24_MM_SS
:
642 case SvxTimeFormat::HH12_MM_SS
:
651 mpPptEscherEx
->OpenContainer( EPP_HeadersFooters
);
652 mpPptEscherEx
->AddAtom( 4, EPP_HeadersFootersAtom
);
653 mpStrm
->WriteUInt32( nVal
);
654 ImplCreateHeaderFooterStrings( *mpStrm
, rXPagePropSet
);
655 mpPptEscherEx
->CloseContainer();
658 bool PPTWriter::ImplCreateDocument()
661 sal_uInt16 nSlideType
= EPP_SLIDESIZE_TYPECUSTOM
;
663 sal_uInt32 nWidth
= maDestPageSize
.Width
;
664 sal_uInt32 nHeight
= maDestPageSize
.Height
;
666 if ( ( nWidth
== 0x1680 ) && ( nHeight
== 0x10e0 ) )
667 nSlideType
= EPP_SLIDESIZE_TYPEONSCREEN
;
668 else if ( ( nWidth
== 0x1200 ) && ( nHeight
== 0x240 ) )
669 nSlideType
= EPP_SLIDESIZE_TYPEBANNER
;
670 else if ( ( nWidth
== 0x1950 ) && ( nHeight
== 0x10e0 ) )
671 nSlideType
= EPP_SLIDESIZE_TYPE35MM
;
672 else if ( ( nWidth
== 0x1860 ) && ( nHeight
== 0x10e0 ) )
673 nSlideType
= EPP_SLIDESIZE_TYPEA4PAPER
;
675 mpPptEscherEx
->OpenContainer( EPP_Document
);
676 // CREATE DOCUMENT ATOM
677 mpPptEscherEx
->AddAtom( 40, EPP_DocumentAtom
, 1 );
678 mpStrm
->WriteUInt32( nWidth
) // Slide Size in Master coordinates X
679 .WriteUInt32( nHeight
) // " " " " " Y
680 .WriteInt32( maNotesPageSize
.Width
) // Notes Page Size X
681 .WriteInt32( maNotesPageSize
.Height
) // " " " Y
682 .WriteInt32( 1 ).WriteInt32( 2 ); // the scale used when the Powerpoint document is embedded. the default is 1:2
683 mpPptEscherEx
->InsertPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY
, mpStrm
->Tell() );
684 mpStrm
->WriteUInt32( 0 ) // Reference to NotesMaster ( 0 if none );
685 .WriteUInt32( 0 ) // Reference to HandoutMaster ( 0 if none );
686 .WriteInt16( 1 ) // Number of the first slide;
687 .WriteUInt16( nSlideType
) // Size of the document slides ( default: EPP_SLIDESIZETYPEONSCREEN )
688 .WriteUChar( 0 ) // bool1 indicates if document was saved with embedded true type fonts
689 .WriteUChar( 0 ) // bool1 indicates if the placeholders on the title slide are omitted
690 .WriteUChar( 0 ) // bool1 right to left ( flag for Bidi version )
691 .WriteUChar( 1 ); // bool1 visibility of comments shapes
693 mpPptEscherEx
->PtInsert( EPP_Persist_Document
, mpStrm
->Tell() );
695 mpPptEscherEx
->OpenContainer( EPP_HeadersFooters
, 3 ); //Master footer (default)
696 mpPptEscherEx
->AddAtom( 4, EPP_HeadersFootersAtom
);
697 mpStrm
->WriteUInt32( 0x25000d );
698 if ( GetPageByIndex( 0, MASTER
) )
699 ImplCreateHeaderFooterStrings( *mpStrm
, mXPagePropSet
);
700 mpPptEscherEx
->CloseContainer();
701 mpPptEscherEx
->OpenContainer( EPP_HeadersFooters
, 4 ); //NotesMaster footer (default)
702 mpPptEscherEx
->AddAtom( 4, EPP_HeadersFootersAtom
);
703 mpStrm
->WriteUInt32( 0x3d000d );
704 if ( GetPageByIndex( 0, NOTICE
) )
705 ImplCreateHeaderFooterStrings( *mpStrm
, mXPagePropSet
);
706 mpPptEscherEx
->CloseContainer();
708 mpPptEscherEx
->OpenContainer( EPP_SlideListWithText
); // animation information for the slides
710 for ( i
= 0; i
< mnPages
; i
++ )
712 mpPptEscherEx
->AddAtom( 20, EPP_SlidePersistAtom
);
713 mpPptEscherEx
->InsertPersistOffset( EPP_MAINSLIDE_PERSIST_KEY
| i
, mpStrm
->Tell() );
714 mpStrm
->WriteUInt32( 0 ) // psrReference - logical reference to the slide persist object ( EPP_MAINSLIDE_PERSIST_KEY )
715 .WriteUInt32( 4 ) // flags - only bit 3 used, if set then slide contains shapes other than placeholders
716 .WriteInt32( 0 ) // numberTexts - number of placeholder texts stored with the persist object. Allows to display outline view without loading the slide persist objects
717 .WriteInt32( i
+ 0x100 ) // slideId - Unique slide identifier, used for OLE link monikers for example
718 .WriteUInt32( 0 ); // reserved, usually 0
720 if ( !GetPageByIndex( i
, NORMAL
) ) // very exciting: once again through all pages
722 SetCurrentStyleSheet( GetMasterIndex( NORMAL
) );
724 css::uno::Reference
< css::container::XNamed
>
725 aXName( mXDrawPage
, css::uno::UNO_QUERY
);
728 maSlideNameList
.push_back( aXName
->getName() );
730 maSlideNameList
.emplace_back( );
732 mpPptEscherEx
->CloseContainer(); // EPP_SlideListWithText
734 mpPptEscherEx
->OpenContainer( EPP_SlideListWithText
, 2 ); // animation information for the notes
735 for( i
= 0; i
< mnPages
; i
++ )
737 mpPptEscherEx
->AddAtom( 20, EPP_SlidePersistAtom
);
738 mpPptEscherEx
->InsertPersistOffset( EPP_MAINNOTES_PERSIST_KEY
| i
, mpStrm
->Tell() );
739 mpStrm
->WriteUInt32( 0 )
742 .WriteInt32( i
+ 0x100 )
745 mpPptEscherEx
->CloseContainer(); // EPP_SlideListWithText
747 css::uno::Reference
< css::presentation::XPresentationSupplier
>
748 aXPresSupplier( mXModel
, css::uno::UNO_QUERY
);
749 if ( aXPresSupplier
.is() )
751 css::uno::Reference
< css::presentation::XPresentation
> aXPresentation( aXPresSupplier
->getPresentation() );
752 if ( aXPresentation
.is() )
754 mXPropSet
.set( aXPresentation
, css::uno::UNO_QUERY
);
755 if ( mXPropSet
.is() )
757 OUString aCustomShow
;
758 sal_uInt32
const nPenColor
= 0x1000000;
759 sal_Int32
const nRestartTime
= 0x7fffffff;
760 sal_Int16 nStartSlide
= 0;
761 sal_Int16 nEndSlide
= 0;
762 sal_uInt32 nFlags
= 0; // Bit 0: Auto advance
763 // Bit 1 Skip builds ( do not allow slide effects )
764 // Bit 2 Use slide range
765 // Bit 3 Use named show
766 // Bit 4 Browse mode on
767 // Bit 5 Kiosk mode on
768 // Bit 6 Skip narration
769 // Bit 7 loop continuously
770 // Bit 8 show scrollbar
772 if ( ImplGetPropertyValue( u
"CustomShow"_ustr
) )
774 aCustomShow
= *o3tl::doAccess
<OUString
>(mAny
);
775 if ( !aCustomShow
.isEmpty() )
780 if ( ( nFlags
& 8 ) == 0 )
782 if ( ImplGetPropertyValue( u
"FirstPage"_ustr
) )
784 auto aSlideName
= o3tl::doAccess
<OUString
>(mAny
);
786 std::vector
<OUString
>::const_iterator pIter
= std::find(
787 maSlideNameList
.begin(),maSlideNameList
.end(), *aSlideName
);
789 if (pIter
!= maSlideNameList
.end())
791 nStartSlide
= pIter
- maSlideNameList
.begin() + 1;
793 nEndSlide
= static_cast<sal_uInt16
>(mnPages
);
798 if ( ImplGetPropertyValue( u
"IsAutomatic"_ustr
) )
806 if ( ImplGetPropertyValue( u
"IsEndless"_ustr
) )
813 if ( ImplGetPropertyValue( u
"IsFullScreen"_ustr
) )
821 mpPptEscherEx
->AddAtom( 80, EPP_SSDocInfoAtom
, 1 );
822 mpStrm
->WriteUInt32( nPenColor
).WriteInt32( nRestartTime
).WriteInt16( nStartSlide
).WriteInt16( nEndSlide
);
824 sal_uInt32 nCustomShowNameLen
= aCustomShow
.getLength();
825 if ( nCustomShowNameLen
> 31 )
826 nCustomShowNameLen
= 31;
827 if ( nCustomShowNameLen
) // named show identifier
829 const sal_Unicode
* pCustomShow
= aCustomShow
.getStr();
830 for ( i
= 0; i
< nCustomShowNameLen
; i
++ )
832 mpStrm
->WriteUInt16( pCustomShow
[ i
] );
835 for ( i
= nCustomShowNameLen
; i
< 32; i
++, mpStrm
->WriteUInt16( 0 ) ) ;
837 mpStrm
->WriteUInt32( nFlags
);
838 css::uno::Reference
< css::presentation::XCustomPresentationSupplier
> aXCPSup( mXModel
, css::uno::UNO_QUERY
);
841 css::uno::Reference
< css::container::XNameContainer
> aXCont( aXCPSup
->getCustomPresentations() );
844 const css::uno::Sequence
< OUString
> aNameSeq( aXCont
->getElementNames() );
845 if ( aNameSeq
.hasElements() )
847 mpPptEscherEx
->OpenContainer( EPP_NamedShows
);
848 sal_uInt32 nCustomShowIndex
= 0;
849 for( OUString
const & customShowName
: aNameSeq
)
851 if ( !customShowName
.isEmpty() )
853 mpPptEscherEx
->OpenContainer( EPP_NamedShow
, nCustomShowIndex
++ );
855 sal_uInt32 nNamedShowLen
= customShowName
.getLength();
856 if ( nNamedShowLen
> 31 )
858 mpPptEscherEx
->AddAtom( nNamedShowLen
<< 1, EPP_CString
);
859 const sal_Unicode
* pCustomShowName
= customShowName
.getStr();
860 for ( sal_uInt32 k
= 0; k
< nNamedShowLen
; ++k
)
861 mpStrm
->WriteUInt16( pCustomShowName
[ k
] );
862 mAny
= aXCont
->getByName( customShowName
);
863 css::uno::Reference
< css::container::XIndexContainer
> aXIC
;
866 mpPptEscherEx
->BeginAtom();
868 sal_Int32 nSlideCount
= aXIC
->getCount();
869 for ( sal_Int32 j
= 0; j
< nSlideCount
; j
++ ) // number of slides
871 mAny
= aXIC
->getByIndex( j
);
872 css::uno::Reference
< css::drawing::XDrawPage
> aXDrawPage
;
873 if ( mAny
>>= aXDrawPage
)
875 css::uno::Reference
< css::container::XNamed
> aXName( aXDrawPage
, css::uno::UNO_QUERY
);
878 OUString
aSlideName( aXName
->getName() );
879 std::vector
<OUString
>::const_iterator pIter
= std::find(
880 maSlideNameList
.begin(),maSlideNameList
.end(),aSlideName
);
882 if (pIter
!= maSlideNameList
.end())
884 sal_uInt32 nPageNumber
= pIter
- maSlideNameList
.begin();
885 mpStrm
->WriteUInt32( nPageNumber
+ 0x100 ); // unique slide id
890 mpPptEscherEx
->EndAtom( EPP_NamedShowSlides
);
892 mpPptEscherEx
->CloseContainer(); // EPP_NamedShow
895 mpPptEscherEx
->CloseContainer(); // EPP_NamedShows
902 mpPptEscherEx
->AddAtom( 0, EPP_EndDocument
);
903 mpPptEscherEx
->CloseContainer(); // EPP_Document
907 void PPTWriter::ImplCreateHyperBlob( SvMemoryStream
& rStrm
)
909 sal_uInt32 nCurrentOfs
, nParaOfs
, nParaCount
= 0;
911 nParaOfs
= rStrm
.Tell();
912 rStrm
.WriteUInt32( 0 ); // property size
913 rStrm
.WriteUInt32( 0 ); // property count
915 for ( const auto& rHyperlink
: maHyperlink
)
918 rStrm
.WriteUInt32( 3 ) // Type VT_I4
919 .WriteUInt32( 7 ) // (VTI4 - Private1)
920 .WriteUInt32( 3 ) // Type VT_I4
921 .WriteUInt32( 6 ) // (VTI4 - Private2)
922 .WriteUInt32( 3 ) // Type VT_I4
923 .WriteUInt32( 0 ); // (VTI4 - Private3)
926 // HIWORD: = 0 : do not change anything
927 // = 1 : replace the hyperlink with the target and subaddress in the following two VTLPWSTR
928 // = 2 : delete the hyperlink
929 // LOWORD: = 0 : graphic shown as background (link)
930 // = 1 : graphic shown as shape (link)
931 // = 2 : graphic is used to fill a shape
932 // = 3 : graphic used to fill a shape outline (future use)
933 // = 4 : hyperlink attached to a shape
934 // = 5 : " " " " (Word) field
935 // = 6 : " " " " (Excel) range
936 // = 7 : " " " " (PPT) text range
937 // = 8 : " " " " (Project) task
939 sal_Int32 nUrlLen
= rHyperlink
.aURL
.getLength();
940 const OUString
& rUrl
= rHyperlink
.aURL
;
942 sal_uInt32
const nInfo
= 7;
944 rStrm
.WriteUInt32( 3 ) // Type VT_I4
945 .WriteUInt32( nInfo
); // Info
947 switch( rHyperlink
.nType
& 0xff )
949 case 1 : // click action to slidenumber
951 rStrm
.WriteUInt32( 0x1f ).WriteUInt32( 1 ).WriteUInt32( 0 ); // path
952 rStrm
.WriteUInt32( 0x1f ).WriteUInt32( nUrlLen
+ 1 );
953 for ( sal_Int32 i
= 0; i
< nUrlLen
; i
++ )
955 rStrm
.WriteUInt16( rUrl
[ i
] );
957 rStrm
.WriteUInt16( 0 );
964 rStrm
.WriteUInt32( 0x1f )
965 .WriteUInt32( nUrlLen
+ 1 );
966 for ( i
= 0; i
< nUrlLen
; i
++ )
968 rStrm
.WriteUInt16( rUrl
[ i
] );
971 rStrm
.WriteUInt16( 0 );
972 rStrm
.WriteUInt16( 0 )
980 nCurrentOfs
= rStrm
.Tell();
981 rStrm
.Seek( nParaOfs
);
982 rStrm
.WriteUInt32( nCurrentOfs
- ( nParaOfs
+ 4 ) );
983 rStrm
.WriteUInt32( nParaCount
);
984 rStrm
.Seek( nCurrentOfs
);
987 bool PPTWriter::ImplCreateMainNotes()
989 EscherSolverContainer aSolverContainer
;
991 mpPptEscherEx
->PtReplaceOrInsert( EPP_Persist_MainNotes
, mpStrm
->Tell() );
992 mpPptEscherEx
->OpenContainer( EPP_Notes
);
993 mpPptEscherEx
->AddAtom( 8, EPP_NotesAtom
, 1 );
994 mpStrm
->WriteUInt32( 0x80000001 ) // Number that identifies this slide
995 .WriteUInt32( 0 ); // follow nothing
996 mpPptEscherEx
->OpenContainer( EPP_PPDrawing
);
997 mpPptEscherEx
->OpenContainer( ESCHER_DgContainer
);
998 mpPptEscherEx
->EnterGroup(nullptr,nullptr);
1000 ImplWritePage( GetLayout( 20 ), aSolverContainer
, NOTICE
, true );
1002 mpPptEscherEx
->LeaveGroup();
1003 mpPptEscherEx
->OpenContainer( ESCHER_SpContainer
);
1004 mpPptEscherEx
->AddShape( ESCHER_ShpInst_Rectangle
, ShapeFlag::Background
| ShapeFlag::HaveShapeProperty
);
1005 EscherPropertyContainer aPropOpt
;
1006 aPropOpt
.AddOpt( ESCHER_Prop_fillColor
, 0xffffff ); // stock valued fill color
1007 aPropOpt
.AddOpt( ESCHER_Prop_fillBackColor
, 0 );
1008 aPropOpt
.AddOpt( ESCHER_Prop_fillRectRight
, 0x68bdde );
1009 aPropOpt
.AddOpt( ESCHER_Prop_fillRectBottom
, 0x8b9f8e );
1010 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x120012 );
1011 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0 );
1012 aPropOpt
.AddOpt( ESCHER_Prop_bWMode
, ESCHER_wDontShow
);
1013 aPropOpt
.AddOpt( ESCHER_Prop_fBackground
, 0x10001 ); // if true, this is the background shape
1014 aPropOpt
.Commit( *mpStrm
);
1015 mpPptEscherEx
->CloseContainer(); // ESCHER_SpContainer
1017 aSolverContainer
.WriteSolver( *mpStrm
);
1019 mpPptEscherEx
->CloseContainer(); // ESCHER_DgContainer
1020 mpPptEscherEx
->CloseContainer(); // EPP_Drawing
1021 mpPptEscherEx
->AddAtom( 32, EPP_ColorSchemeAtom
, 0, 1 );
1022 mpStrm
->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
1023 mpPptEscherEx
->CloseContainer(); // EPP_Notes
1027 void PPTWriter::ImplExportComments( const uno::Reference
< drawing::XDrawPage
>& xPage
, SvMemoryStream
& rBinaryTagData10Atom
)
1031 uno::Reference
< office::XAnnotationAccess
> xAnnotationAccess( xPage
, uno::UNO_QUERY_THROW
);
1032 uno::Reference
< office::XAnnotationEnumeration
> xAnnotationEnumeration( xAnnotationAccess
->createAnnotationEnumeration() );
1034 bool bRemoveCommentAuthorDates
1035 = SvtSecurityOptions::IsOptionSet(
1036 SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo
)
1037 && !SvtSecurityOptions::IsOptionSet(
1038 SvtSecurityOptions::EOption::DocWarnKeepNoteAuthorDateInfo
);
1040 sal_Int32 nIndex
= 1;
1042 while( xAnnotationEnumeration
->hasMoreElements() )
1044 EscherExContainer
aComment10( rBinaryTagData10Atom
, EPP_Comment10
);
1046 uno::Reference
< office::XAnnotation
> xAnnotation( xAnnotationEnumeration
->nextElement() );
1048 geometry::RealPoint2D
aRealPoint2D( xAnnotation
->getPosition() );
1049 Point
aPoint(o3tl::convert(aRealPoint2D
.X
, o3tl::Length::mm
, o3tl::Length::master
),
1050 o3tl::convert(aRealPoint2D
.Y
, o3tl::Length::mm
, o3tl::Length::master
));
1052 OUString
sAuthor( bRemoveCommentAuthorDates
1053 ? "Author" + OUString::number(mpAuthorIDs
->GetInfoID(xAnnotation
->getAuthor() ))
1054 : xAnnotation
->getAuthor() );
1055 uno::Reference
< text::XText
> xText( xAnnotation
->getTextRange() );
1056 OUString
sText( xText
->getString() );
1058 bRemoveCommentAuthorDates
1059 ? "A" + OUString::number(mpAuthorIDs
->GetInfoID(xAnnotation
->getAuthor()))
1060 : xAnnotation
->getInitials());
1061 util::DateTime aEmptyDateTime
;
1062 util::DateTime
aDateTime(bRemoveCommentAuthorDates
? aEmptyDateTime
1063 : xAnnotation
->getDateTime());
1064 if ( !sAuthor
.isEmpty() )
1065 PPTWriter::WriteCString( rBinaryTagData10Atom
, sAuthor
);
1066 if ( !sText
.isEmpty() )
1067 PPTWriter::WriteCString( rBinaryTagData10Atom
, sText
, 1 );
1068 if ( !sInitials
.isEmpty() )
1069 PPTWriter::WriteCString( rBinaryTagData10Atom
, sInitials
, 2 );
1071 sal_Int16 nMilliSeconds
= static_cast<sal_Int16
>(::rtl::math::round(static_cast<double>(aDateTime
.NanoSeconds
) / 1000000000.0));
1072 EscherExAtom
aCommentAtom10( rBinaryTagData10Atom
, EPP_CommentAtom10
);
1073 rBinaryTagData10Atom
.WriteInt32( nIndex
++ )
1074 .WriteInt16( aDateTime
.Year
)
1075 .WriteUInt16( aDateTime
.Month
)
1076 .WriteUInt16( aDateTime
.Day
) // todo: day of week
1077 .WriteUInt16( aDateTime
.Day
)
1078 .WriteUInt16( aDateTime
.Hours
)
1079 .WriteUInt16( aDateTime
.Minutes
)
1080 .WriteUInt16( aDateTime
.Seconds
)
1081 .WriteInt16( nMilliSeconds
)
1082 .WriteInt32( aPoint
.X() )
1083 .WriteInt32( aPoint
.Y() );
1087 catch ( uno::Exception
& )
1092 void PPTWriter::ImplWriteNotes( sal_uInt32 nPageNum
)
1094 mpPptEscherEx
->PtReplaceOrInsert( EPP_Persist_Notes
| nPageNum
, mpStrm
->Tell() );
1095 mpPptEscherEx
->OpenContainer( EPP_Notes
);
1096 mpPptEscherEx
->AddAtom( 8, EPP_NotesAtom
, 1 );
1097 mpStrm
->WriteUInt32( nPageNum
+ 0x100 )
1098 .WriteUInt16( 3 ) // follow master...
1101 ImplCreateHeaderFooters( mXPagePropSet
);
1103 EscherSolverContainer aSolverContainer
;
1105 mpPptEscherEx
->OpenContainer( EPP_PPDrawing
);
1106 mpPptEscherEx
->OpenContainer( ESCHER_DgContainer
);
1107 mpPptEscherEx
->EnterGroup(nullptr,nullptr);
1109 ImplWritePage( GetLayout( 20 ), aSolverContainer
, NOTICE
, false ); // the shapes of the pages are created in the PPT document
1111 mpPptEscherEx
->LeaveGroup();
1112 mpPptEscherEx
->OpenContainer( ESCHER_SpContainer
);
1113 mpPptEscherEx
->AddShape( ESCHER_ShpInst_Rectangle
, ShapeFlag::Background
| ShapeFlag::HaveShapeProperty
);
1114 EscherPropertyContainer aPropOpt
;
1115 aPropOpt
.AddOpt( ESCHER_Prop_fillColor
, 0xffffff ); // stock valued fill color
1116 aPropOpt
.AddOpt( ESCHER_Prop_fillBackColor
, 0 );
1117 aPropOpt
.AddOpt( ESCHER_Prop_fillRectRight
, 0x8b9f8e );
1118 aPropOpt
.AddOpt( ESCHER_Prop_fillRectBottom
, 0x68bdde );
1119 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x120012 );
1120 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x80000 );
1121 aPropOpt
.AddOpt( ESCHER_Prop_bWMode
, ESCHER_wDontShow
);
1122 aPropOpt
.AddOpt( ESCHER_Prop_fBackground
, 0x10001 );
1123 aPropOpt
.Commit( *mpStrm
);
1124 mpPptEscherEx
->CloseContainer(); // ESCHER_SpContainer
1126 aSolverContainer
.WriteSolver( *mpStrm
);
1128 mpPptEscherEx
->CloseContainer(); // ESCHER_DgContainer
1129 mpPptEscherEx
->CloseContainer(); // EPP_Drawing
1130 mpPptEscherEx
->AddAtom( 32, EPP_ColorSchemeAtom
, 0, 1 );
1131 mpStrm
->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
1132 mpPptEscherEx
->CloseContainer(); // EPP_Notes
1135 void PPTWriter::ImplWriteBackground( css::uno::Reference
< css::beans::XPropertySet
> const & rXPropSet
)
1137 //************************ ******
1138 //** DEFAULT BACKGROUND SHAPE **
1140 sal_uInt32 nFillColor
= 0xffffff;
1141 sal_uInt32 nFillBackColor
= 0;
1143 mpPptEscherEx
->OpenContainer( ESCHER_SpContainer
);
1144 mpPptEscherEx
->AddShape( ESCHER_ShpInst_Rectangle
, ShapeFlag::Background
| ShapeFlag::HaveShapeProperty
);
1146 // #i121183# Use real PageSize in 100th mm
1147 ::tools::Rectangle
aRect(Point(0, 0), Size(maPageSize
.Width
, maPageSize
.Height
));
1149 EscherPropertyContainer
aPropOpt( mpPptEscherEx
->GetGraphicProvider(), mpPicStrm
.get(), aRect
);
1150 aPropOpt
.AddOpt( ESCHER_Prop_fillType
, ESCHER_FillSolid
);
1151 css::drawing::FillStyle
aFS( css::drawing::FillStyle_NONE
);
1152 if ( ImplGetPropertyValue( rXPropSet
, u
"FillStyle"_ustr
) )
1157 case css::drawing::FillStyle_GRADIENT
:
1159 aPropOpt
.CreateGradientProperties( rXPropSet
);
1160 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x1f001e );
1161 aPropOpt
.GetOpt( ESCHER_Prop_fillColor
, nFillColor
);
1162 aPropOpt
.GetOpt( ESCHER_Prop_fillBackColor
, nFillBackColor
);
1166 case css::drawing::FillStyle_BITMAP
:
1167 aPropOpt
.CreateGraphicProperties( rXPropSet
, u
"FillBitmap"_ustr
, true );
1170 case css::drawing::FillStyle_HATCH
:
1171 aPropOpt
.CreateGraphicProperties( rXPropSet
, u
"FillHatch"_ustr
, true );
1174 case css::drawing::FillStyle_SOLID
:
1176 if ( ImplGetPropertyValue( rXPropSet
, u
"FillColor"_ustr
) )
1178 nFillColor
= EscherEx::GetColor( *o3tl::doAccess
<sal_uInt32
>(mAny
) );
1179 nFillBackColor
= nFillColor
^ 0xffffff;
1183 case css::drawing::FillStyle_NONE
:
1185 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x120012 );
1188 aPropOpt
.AddOpt( ESCHER_Prop_fillColor
, nFillColor
);
1189 aPropOpt
.AddOpt( ESCHER_Prop_fillBackColor
, nFillBackColor
);
1190 aPropOpt
.AddOpt( ESCHER_Prop_fillRectRight
, PPTtoEMU( maDestPageSize
.Width
) );
1191 aPropOpt
.AddOpt( ESCHER_Prop_fillRectBottom
, PPTtoEMU( maDestPageSize
.Height
) );
1192 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x80000 );
1193 aPropOpt
.AddOpt( ESCHER_Prop_bWMode
, ESCHER_bwWhite
);
1194 aPropOpt
.AddOpt( ESCHER_Prop_fBackground
, 0x10001 );
1195 aPropOpt
.Commit( *mpStrm
);
1196 mpPptEscherEx
->CloseContainer(); // ESCHER_SpContainer
1199 void PPTWriter::ImplWriteVBA()
1203 sal_uInt64 nLen
= mpVBA
->TellEnd();
1207 mnVBAOleOfs
= mpStrm
->Tell();
1208 mpPptEscherEx
->BeginAtom();
1209 mpStrm
->WriteBytes(static_cast<sal_Int8
const *>(mpVBA
->GetData()) + 8, nLen
);
1210 mpPptEscherEx
->EndAtom( EPP_ExOleObjStg
, 0, 1 );
1215 void PPTWriter::ImplWriteOLE( )
1218 SvxMSExportOLEObjects
aOleExport( mnCnvrtFlags
);
1220 for ( const auto& rxExOleObjEntry
: maExOleObj
)
1222 PPTExOleObjEntry
* pPtr
= rxExOleObjEntry
.get();
1223 std::unique_ptr
<SvMemoryStream
> pStrm
;
1224 pPtr
->nOfsB
= mpStrm
->Tell();
1225 switch ( pPtr
->eType
)
1227 case NORMAL_OLE_OBJECT
:
1229 SdrObject
* pSdrObj
= SdrObject::getSdrObjectFromXShape(pPtr
->xShape
);
1230 if ( auto pSdrOle2Obj
= dynamic_cast< SdrOle2Obj
* >(pSdrObj
) )
1232 const ::uno::Reference
< embed::XEmbeddedObject
>& xObj( pSdrOle2Obj
->GetObjRef() );
1235 rtl::Reference
<SotStorage
> xTempStorage( new SotStorage( new SvMemoryStream(), true ) );
1236 aOleExport
.ExportOLEObject( xObj
, *xTempStorage
);
1239 SvMemoryStream aStream
;
1240 rtl::Reference
<SotStorage
> xCleanStorage(new SotStorage(false, aStream
));
1241 xTempStorage
->CopyTo( xCleanStorage
.get() );
1242 // create a dummy content stream, the dummy content is necessary for ppt, but not for
1243 // doc files, so we can't share code.
1244 rtl::Reference
<SotStorageStream
> xStm
= xCleanStorage
->OpenSotStream( SVEXT_PERSIST_STREAM
);
1245 xStm
->WriteUInt32( 0 ) // no ClipboardId
1246 .WriteUInt32( 4 ) // no target device
1247 .WriteUInt32( 1 ) // aspect ratio
1248 .WriteInt32( -1 ) // L-Index
1249 .WriteUInt32( 0 ) // Advanced Flags
1250 .WriteUInt32( 0 ) // compression
1251 .WriteUInt32( 0 ) // Size
1252 .WriteUInt32( 0 ) // "
1254 pStrm
= xCleanStorage
->CreateMemoryStream();
1262 if ( pPtr
->xControlModel
.is() )
1265 //Initialize the graphic size which will be used on export
1266 css::awt::Size
aSize( pPtr
->xShape
->getSize() );
1267 rtl::Reference
<SotStorage
> xDest(new SotStorage(new SvMemoryStream(), true));
1268 bool bOk
= oox::ole::MSConvertOCXControls::WriteOCXStream( mXModel
, xDest
, pPtr
->xControlModel
, aSize
, aName
);
1270 pStrm
= xDest
->CreateMemoryStream();
1276 mpPptEscherEx
->BeginAtom();
1277 pStrm
->Seek( STREAM_SEEK_TO_END
);
1278 sal_uInt32 npStrmSize
= pStrm
->Tell();
1279 mpStrm
->WriteUInt32( npStrmSize
); // uncompressed size
1282 ZCodec
aZCodec( 0x8000, 0x8000 );
1283 aZCodec
.BeginCompression();
1284 aZCodec
.Compress( *pStrm
, *mpStrm
);
1285 aZCodec
.EndCompression();
1287 mpPptEscherEx
->EndAtom( EPP_ExOleObjStg
, 0, 1 );
1292 // write PersistantTable and UserEditAtom
1294 void PPTWriter::ImplWriteAtomEnding()
1297 #define EPP_LastViewTypeSlideView 1
1299 sal_uInt32 i
, nPos
, nOfs
, nPersistOfs
= mpStrm
->Tell();
1300 sal_uInt32 nPersistEntrys
= 0;
1301 mpStrm
->WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ); // skip record header and first entry
1303 // write document persist
1305 mpStrm
->WriteUInt32( 0 );
1306 // write MasterPages persists
1307 for ( i
= 0; i
< mnMasterPages
; i
++ )
1309 nOfs
= mpPptEscherEx
->PtGetOffsetByID( EPP_Persist_MainMaster
| i
);
1312 mpStrm
->WriteUInt32( nOfs
);
1313 mpPptEscherEx
->InsertAtPersistOffset( EPP_MAINMASTER_PERSIST_KEY
| i
, ++nPersistEntrys
);
1316 // write MainNotesMaster persist
1317 nOfs
= mpPptEscherEx
->PtGetOffsetByID( EPP_Persist_MainNotes
);
1320 mpStrm
->WriteUInt32( nOfs
);
1321 mpPptEscherEx
->InsertAtPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY
, ++nPersistEntrys
);
1323 // write slide persists -> we have to write a valid value into EPP_SlidePersistAtome too
1324 for ( i
= 0; i
< mnPages
; i
++ )
1326 nOfs
= mpPptEscherEx
->PtGetOffsetByID( EPP_Persist_Slide
| i
);
1329 mpStrm
->WriteUInt32( nOfs
);
1330 mpPptEscherEx
->InsertAtPersistOffset( EPP_MAINSLIDE_PERSIST_KEY
| i
, ++nPersistEntrys
);
1333 // write Notes persists
1334 for ( i
= 0; i
< mnPages
; i
++ )
1336 nOfs
= mpPptEscherEx
->PtGetOffsetByID( EPP_Persist_Notes
| i
);
1339 mpStrm
->WriteUInt32( nOfs
);
1340 mpPptEscherEx
->InsertAtPersistOffset( EPP_MAINNOTES_PERSIST_KEY
| i
, ++nPersistEntrys
);
1344 for ( const auto& rxExOleObjEntry
: maExOleObj
)
1346 PPTExOleObjEntry
* pPtr
= rxExOleObjEntry
.get();
1347 nOfs
= mpPptEscherEx
->PtGetOffsetByID( EPP_Persist_ExObj
);
1351 mpStrm
->WriteUInt32( pPtr
->nOfsB
);
1352 sal_uInt32 nOldPos
, nPersOfs
= nOfs
+ pPtr
->nOfsA
+ 16 + 8; // 8 bytes atom header, +16 to the persist entry
1353 nOldPos
= mpStrm
->Tell();
1354 mpStrm
->Seek( nPersOfs
);
1355 mpStrm
->WriteUInt32( nPersistEntrys
);
1356 mpStrm
->Seek( nOldPos
);
1360 if ( mnVBAOleOfs
&& mpVBA
)
1362 nOfs
= mpPptEscherEx
->PtGetOffsetByID( EPP_Persist_VBAInfoAtom
);
1369 mpVBA
->ReadUInt32( n1
)
1372 mpStrm
->WriteUInt32( mnVBAOleOfs
);
1373 sal_uInt64 nOldPos
= mpStrm
->Tell();
1374 mpStrm
->Seek( nOfs
); // Fill the VBAInfoAtom with the correct index to the persisttable
1375 mpStrm
->WriteUInt32( nPersistEntrys
)
1378 mpStrm
->Seek( nOldPos
);
1382 nPos
= mpStrm
->Tell();
1383 mpStrm
->Seek( nPersistOfs
);
1384 mpPptEscherEx
->AddAtom( ( nPersistEntrys
+ 1 ) << 2, EPP_PersistPtrIncrementalBlock
); // insert Record Header
1385 mpStrm
->WriteUInt32( ( nPersistEntrys
<< 20 ) | 1 );
1386 mpStrm
->Seek( nPos
);
1388 mpCurUserStrm
->WriteUInt32( nPos
); // set offset to current edit
1389 mpPptEscherEx
->AddAtom( 28, EPP_UserEditAtom
);
1390 mpStrm
->WriteInt32( 0x100 ) // last slide ID
1391 .WriteUInt32( 0x03000dbc ) // minor and major app version that did the save
1392 .WriteUInt32( 0 ) // offset last save, 0 after a full save
1393 .WriteUInt32( nPersistOfs
) // File offset to persist pointers for this save operation
1394 .WriteUInt32( 1 ) // Persist reference to the document persist object
1395 .WriteUInt32( nPersistEntrys
) // max persists written, Seed value for persist object id management
1396 .WriteInt16( EPP_LastViewTypeSlideView
) // last view type
1397 .WriteInt16( 0x12 ); // padword
1400 // - exported function -
1402 SAL_DLLPUBLIC_EXPORT
bool ExportPPT( const std::vector
< css::beans::PropertyValue
>& rMediaData
,
1403 rtl::Reference
<SotStorage
> const & rSvStorage
,
1404 css::uno::Reference
< css::frame::XModel
> const & rXModel
,
1405 css::uno::Reference
< css::task::XStatusIndicator
> const & rXStatInd
,
1406 SvMemoryStream
* pVBA
,
1407 sal_uInt32 nCnvrtFlags
)
1409 PPTWriter
aPPTWriter( rSvStorage
, rXModel
, rXStatInd
, pVBA
, nCnvrtFlags
);
1410 aPPTWriter
.exportPPT(rMediaData
);
1411 bool bStatus
= aPPTWriter
.IsValid();
1415 SAL_DLLPUBLIC_EXPORT
bool SaveVBA( SfxObjectShell
& rDocShell
, SvMemoryStream
*& pBas
)
1417 rtl::Reference
<SotStorage
> xDest(new SotStorage(new SvMemoryStream(), true));
1418 SvxImportMSVBasic
aMSVBas( rDocShell
, *xDest
);
1419 aMSVBas
.SaveOrDelMSVBAStorage( true, u
"_MS_VBA_Overhead"_ustr
);
1421 rtl::Reference
<SotStorage
> xOverhead
= xDest
->OpenSotStorage(u
"_MS_VBA_Overhead"_ustr
);
1422 if ( xOverhead
.is() && ( xOverhead
->GetError() == ERRCODE_NONE
) )
1424 rtl::Reference
<SotStorage
> xOverhead2
= xOverhead
->OpenSotStorage(u
"_MS_VBA_Overhead"_ustr
);
1425 if ( xOverhead2
.is() && ( xOverhead2
->GetError() == ERRCODE_NONE
) )
1427 rtl::Reference
<SotStorageStream
> xTemp
= xOverhead2
->OpenSotStream(u
"_MS_VBA_Overhead2"_ustr
);
1428 if ( xTemp
.is() && ( xTemp
->GetError() == ERRCODE_NONE
) )
1430 sal_uInt32 nLen
= xTemp
->GetSize();
1433 char* pTemp
= new char[ nLen
];
1434 xTemp
->Seek( STREAM_SEEK_TO_BEGIN
);
1435 xTemp
->ReadBytes(pTemp
, nLen
);
1436 pBas
= new SvMemoryStream( pTemp
, nLen
, StreamMode::READ
);
1437 pBas
->ObjectOwnsMemory( true );
1447 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */