/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "eppt.hxx" #include "epptdef.hxx" #include "pptexanimations.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class SfxObjectShell; // complete SfxObjectShell for SaveVBA under -fsanitize=function using namespace com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::presentation; using ::com::sun::star::beans::XPropertySet; //============================ PPTWriter ================================== PPTWriter::PPTWriter( tools::SvRef const & rSvStorage, css::uno::Reference< css::frame::XModel > const & rXModel, css::uno::Reference< css::task::XStatusIndicator > const & rXStatInd, SvMemoryStream* pVBA, sal_uInt32 nCnvrtFlags ) : PPTWriterBase ( rXModel, rXStatInd ), mnCnvrtFlags ( nCnvrtFlags ), mbStatus ( false ), mnStatMaxValue ( 0 ), mnLatestStatValue ( 0 ), mnTextStyle( 0 ), mbFontIndependentLineSpacing( false ), mnTextSize( 0 ), mrStg ( rSvStorage ), mnVBAOleOfs ( 0 ), mpVBA ( pVBA ), mnExEmbed ( 0 ), mpExEmbed ( new SvMemoryStream ), mnPagesWritten ( 0 ), mnTxId ( 0x7a2f64 ), mnDiaMode ( 0 ), mnShapeMasterTitle ( 0 ), mnShapeMasterBody ( 0 ) { } void PPTWriter::exportPPTPre( const std::vector< css::beans::PropertyValue >& rMediaData ) { if ( !mrStg.is() ) return; if ( mXStatusIndicator.is() ) { mbStatusIndicator = true; mnStatMaxValue = ( mnPages + mnMasterPages ) * 5; mXStatusIndicator->start( "PowerPoint Export", mnStatMaxValue + ( mnStatMaxValue >> 3 ) ); } SvGlobalName aGName(MSO_PPT8_CLASSID); mrStg->SetClass( aGName, SotClipboardFormatId::NONE, "MS PowerPoint 97" ); if ( !ImplCreateCurrentUserStream() ) return; mpStrm = mrStg->OpenSotStream( "PowerPoint Document" ); if ( !mpStrm ) return; if ( !mpPicStrm ) mpPicStrm = mrStg->OpenSotStream( "Pictures" ); auto aIter = std::find_if(rMediaData.begin(), rMediaData.end(), [](const css::beans::PropertyValue& rProp) { return rProp.Name == "BaseURI"; }); if (aIter != rMediaData.end()) (*aIter).Value >>= maBaseURI; mpPptEscherEx.reset( new PptEscherEx( *mpStrm, maBaseURI ) ); } void PPTWriter::exportPPTPost( ) { if ( !ImplCloseDocument() ) return; if ( mbStatusIndicator ) { mXStatusIndicator->setText( "PowerPoint Export" ); sal_uInt32 nValue = mnStatMaxValue + ( mnStatMaxValue >> 3 ); if ( nValue > mnLatestStatValue ) { mXStatusIndicator->setValue( nValue ); mnLatestStatValue = nValue; } } ImplWriteOLE(); ImplWriteVBA(); ImplWriteAtomEnding(); ImplCreateDocumentSummaryInformation(); mbStatus = true; }; static void ImplExportComments( const uno::Reference< drawing::XDrawPage >& xPage, SvMemoryStream& rBinaryTagData10Atom ); void PPTWriter::ImplWriteSlide( sal_uInt32 nPageNum, sal_uInt32 nMasterNum, sal_uInt16 nMode, bool bHasBackground, Reference< XPropertySet > const & aXBackgroundPropSet ) { Any aAny; const PHLayout& rLayout = GetLayout( mXPagePropSet ); mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_Slide | nPageNum, mpStrm->Tell() ); mpPptEscherEx->OpenContainer( EPP_Slide ); mpPptEscherEx->AddAtom( 24, EPP_SlideAtom, 2 ); mpStrm->WriteInt32( static_cast(rLayout.nLayout) ); mpStrm->WriteBytes(rLayout.nPlaceHolder, 8); // placeholderIDs (8 parts) mpStrm->WriteUInt32( nMasterNum | 0x80000000 ) // master ID (equals 0x80000000 on a master page) .WriteUInt32( nPageNum + 0x100 ) // notes ID (equals null if no notes are present) .WriteUInt16( nMode ) .WriteUInt16( 0 ); // padword mnDiaMode = 0; bool bVisible = true; css::presentation::FadeEffect eFe = css::presentation::FadeEffect_NONE; if ( GetPropertyValue( aAny, mXPagePropSet, "Visible" ) ) aAny >>= bVisible; if ( GetPropertyValue( aAny, mXPagePropSet, "Change" ) ) { switch ( *o3tl::doAccess(aAny) ) { case 1 : // automatic mnDiaMode++; [[fallthrough]]; case 2 : // semi-automatic mnDiaMode++; break; default : case 0 : // manual break; } } if ( GetPropertyValue( aAny, mXPagePropSet, "Effect" ) ) aAny >>= eFe; sal_uInt32 nSoundRef = 0; bool bIsSound = false; bool bStopSound = false; bool bLoopSound = false; if ( GetPropertyValue( aAny, mXPagePropSet, "Sound" ) ) { OUString aSoundURL; if ( aAny >>= aSoundURL ) { nSoundRef = maSoundCollection.GetId( aSoundURL ); bIsSound = true; } else aAny >>= bStopSound; } if ( GetPropertyValue( aAny, mXPagePropSet, "LoopSound" ) ) aAny >>= bLoopSound; bool bNeedsSSSlideInfoAtom = !bVisible || ( mnDiaMode == 2 ) || bIsSound || bStopSound || ( eFe != css::presentation::FadeEffect_NONE ); if ( bNeedsSSSlideInfoAtom ) { sal_uInt8 nDirection = 0; sal_uInt8 nTransitionType = 0; sal_uInt16 nBuildFlags = 1; // advance by mouseclick sal_Int32 nSlideTime = 0; // still has to !!! sal_uInt8 nSpeed = 1; if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionDuration" ) ) { css::presentation::AnimationSpeed aAs; double fTransitionDuration = -1.0; aAny >>= fTransitionDuration; if (fTransitionDuration >= 0) { if (fTransitionDuration <= 0.5) { aAs = css::presentation::AnimationSpeed::AnimationSpeed_FAST; } else if (fTransitionDuration >= 1.0) { aAs = css::presentation::AnimationSpeed::AnimationSpeed_SLOW; } else { aAs = css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM; } } else aAs = css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM; nSpeed = static_cast(aAs); } sal_Int16 nTT = 0; if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionType" ) && ( aAny >>= nTT ) ) { sal_Int16 nTST = 0; if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionSubtype" ) && ( aAny >>= nTST ) ) nTransitionType = GetTransition( nTT, nTST, eFe, 0, nDirection ); } if ( !nTransitionType ) nTransitionType = GetTransition( eFe, nDirection ); if ( mnDiaMode == 2 ) // automatic ? nBuildFlags |= 0x400; if ( !bVisible ) nBuildFlags |= 4; if ( bIsSound ) nBuildFlags |= 16; if ( bLoopSound ) nBuildFlags |= 64; if ( bStopSound ) nBuildFlags |= 256; if ( GetPropertyValue( aAny, mXPagePropSet, "Duration" ) )// duration of this slide nSlideTime = *o3tl::doAccess(aAny) << 10; // in ticks mpPptEscherEx->AddAtom( 16, EPP_SSSlideInfoAtom ); mpStrm->WriteInt32( nSlideTime ) // standtime in ticks .WriteUInt32( nSoundRef ) .WriteUChar( nDirection ) .WriteUChar( nTransitionType ) .WriteUInt16( nBuildFlags ) .WriteUChar( nSpeed ) .WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ); } ImplCreateHeaderFooters( mXPagePropSet ); EscherSolverContainer aSolverContainer; mpPptEscherEx->OpenContainer( EPP_PPDrawing ); mpPptEscherEx->OpenContainer( ESCHER_DgContainer ); mpPptEscherEx->EnterGroup(nullptr,nullptr); ImplWritePage( rLayout, aSolverContainer, NORMAL, false, nPageNum ); // the shapes of the pages are created in the PPT document mpPptEscherEx->LeaveGroup(); if ( bHasBackground ) ImplWriteBackground( aXBackgroundPropSet ); else { mpPptEscherEx->OpenContainer( ESCHER_SpContainer ); mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty ); EscherPropertyContainer aPropOpt; aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, PPTtoEMU( maDestPageSize.Width ) ); aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, PPTtoEMU( maDestPageSize.Width ) ); aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 ); aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 ); aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow ); aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 ); // if true, this is the background shape aPropOpt.Commit( *mpStrm ); mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer } aSolverContainer.WriteSolver( *mpStrm ); mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer mpPptEscherEx->CloseContainer(); // EPP_Drawing mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 ); mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 ); SvMemoryStream aBinaryTagData10Atom; ImplExportComments( mXDrawPage, aBinaryTagData10Atom ); SvMemoryStream amsofbtAnimGroup; ppt::AnimationExporter aExporter( aSolverContainer, maSoundCollection ); aExporter.doexport( mXDrawPage, amsofbtAnimGroup ); sal_uInt32 nmsofbtAnimGroupSize = amsofbtAnimGroup.Tell(); if ( nmsofbtAnimGroupSize ) { { EscherExAtom aMagic2( aBinaryTagData10Atom, 0x2eeb ); aBinaryTagData10Atom.WriteUInt32( 0x01c45df9 ) .WriteUInt32( 0xe1471b30 ); } { EscherExAtom aMagic( aBinaryTagData10Atom, 0x2b00 ); aBinaryTagData10Atom.WriteUInt32( 0 ); } aBinaryTagData10Atom.WriteBytes(amsofbtAnimGroup.GetData(), amsofbtAnimGroup.Tell()); { EscherExContainer aMagic2( aBinaryTagData10Atom, 0x2b02 ); } } if ( aBinaryTagData10Atom.Tell() ) { EscherExContainer aProgTags ( *mpStrm, EPP_ProgTags ); EscherExContainer aProgBinaryTag( *mpStrm, EPP_ProgBinaryTag ); { EscherExAtom aCString( *mpStrm, EPP_CString ); mpStrm->WriteUInt32( 0x5f005f ) .WriteUInt32( 0x50005f ) .WriteUInt32( 0x540050 ) .WriteUInt16( 0x31 ) .WriteUInt16( 0x30 ); } { EscherExAtom aBinaryTagData( *mpStrm, EPP_BinaryTagData ); mpStrm->WriteBytes(aBinaryTagData10Atom.GetData(), aBinaryTagData10Atom.Tell()); } } mpPptEscherEx->CloseContainer(); // EPP_Slide } void PPTWriter::ImplWriteSlideMaster( sal_uInt32 nPageNum, Reference< XPropertySet > const & aXBackgroundPropSet ) { if (!aXBackgroundPropSet) return; mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_MainMaster | nPageNum, mpStrm->Tell() ); mpPptEscherEx->OpenContainer( EPP_MainMaster ); mpPptEscherEx->AddAtom( 24, EPP_SlideAtom, 2 ); mpStrm->WriteInt32( static_cast(EppLayout::TITLEANDBODYSLIDE) ) // slide layout -> title and body slide .WriteUChar( 1 ).WriteUChar( 2 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ) // placeholderID .WriteUInt32( 0 ) // master ID (equals null at a master page) .WriteUInt32( 0 ) // notes ID (equals null if no notes are present) .WriteUInt16( 0 ) // Bit 1: Follow master objects, Bit 2: Follow master scheme, Bit 3: Follow master background .WriteUInt16( 0 ); // padword mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 ); mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 ); mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 ); mpStrm->WriteUInt32( 0xff0000 ).WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x00ffff ).WriteUInt32( 0x0099ff ).WriteUInt32( 0xffff00 ).WriteUInt32( 0x0000ff ).WriteUInt32( 0x969696 ); mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 ); mpStrm->WriteUInt32( 0xccffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x336666 ).WriteUInt32( 0x008080 ).WriteUInt32( 0x339933 ).WriteUInt32( 0x000080 ).WriteUInt32( 0xcc3300 ).WriteUInt32( 0x66ccff ); mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 ); mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x333333 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xdddddd ).WriteUInt32( 0x808080 ).WriteUInt32( 0x4d4d4d ).WriteUInt32( 0xeaeaea ); mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 ); mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x66ccff ).WriteUInt32( 0xff0000 ).WriteUInt32( 0xcc00cc ).WriteUInt32( 0xc0c0c0 ); mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 ); mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xc0c0c0 ).WriteUInt32( 0xff6600 ).WriteUInt32( 0x0000ff ).WriteUInt32( 0x009900 ); mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 ); mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xff9933 ).WriteUInt32( 0xccff99 ).WriteUInt32( 0xcc00cc ).WriteUInt32( 0xb2b2b2 ); for ( int nInstance = EPP_TEXTTYPE_Title; nInstance <= EPP_TEXTTYPE_QuarterBody; nInstance++ ) { if ( nInstance == EPP_TEXTTYPE_notUsed ) continue; // the auto color is dependent to the page background,so we have to set a page that is in the right context if ( nInstance == EPP_TEXTTYPE_Notes ) (void)GetPageByIndex(0, NOTICE); else (void)GetPageByIndex(0, MASTER); mpPptEscherEx->BeginAtom(); bool bSimpleText = false; mpStrm->WriteUInt16( 5 ); // paragraph count for ( sal_uInt16 nLev = 0; nLev < 5; nLev++ ) { if ( nInstance >= EPP_TEXTTYPE_CenterBody ) { bSimpleText = true; mpStrm->WriteUInt16( nLev ); } mpStyleSheet->mpParaSheet[ nInstance ]->Write( *mpStrm, nLev, bSimpleText, mXPagePropSet ); mpStyleSheet->mpCharSheet[ nInstance ]->Write( *mpStrm, nLev, bSimpleText, mXPagePropSet ); } mpPptEscherEx->EndAtom( EPP_TxMasterStyleAtom, 0, nInstance ); } GetPageByIndex( nPageNum, MASTER ); EscherSolverContainer aSolverContainer; mpPptEscherEx->OpenContainer( EPP_PPDrawing ); mpPptEscherEx->OpenContainer( ESCHER_DgContainer ); mpPptEscherEx->EnterGroup(nullptr,nullptr); ImplWritePage( GetLayout( 0 ), aSolverContainer, MASTER, true ); // the shapes of the pages are created in the PPT document mpPptEscherEx->LeaveGroup(); ImplWriteBackground( aXBackgroundPropSet ); aSolverContainer.WriteSolver( *mpStrm ); mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer mpPptEscherEx->CloseContainer(); // EPP_Drawing mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 ); mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 ); if ( aBuExMasterStream.Tell() ) { ImplProgTagContainer( mpStrm.get(), &aBuExMasterStream ); } mpPptEscherEx->CloseContainer(); // EPP_MainMaster }; PPTWriter::~PPTWriter() { mpExEmbed.reset(); mpPptEscherEx.reset(); mpCurUserStrm.clear(); mpPicStrm.clear(); mpStrm.clear(); maStyleSheetList.clear(); maExOleObj.clear(); if ( mbStatusIndicator ) mXStatusIndicator->end(); } bool PPTWriter::ImplCreateCurrentUserStream() { mpCurUserStrm = mrStg->OpenSotStream( "Current User" ); if ( !mpCurUserStrm ) return false; char pUserName[] = "Current User"; sal_uInt32 nLenOfUserName = strlen( pUserName ); sal_uInt32 nSizeOfRecord = 0x14 + ( ( nLenOfUserName + 4 ) & ~ 3 ); mpCurUserStrm->WriteUInt16( 0 ).WriteUInt16( EPP_CurrentUserAtom ).WriteUInt32( nSizeOfRecord ); mpCurUserStrm->WriteUInt32( 0x14 ) // Len .WriteUInt32( 0xe391c05f ); // Magic sal_uInt32 nEditPos = mpCurUserStrm->Tell(); mpCurUserStrm->WriteUInt32( 0x0 ) // OffsetToCurrentEdit; .WriteUInt16( nLenOfUserName ) .WriteUInt16( 0x3f4 ) // DocFileVersion .WriteUChar( 3 ) // MajorVersion .WriteUChar( 0 ) // MinorVersion .WriteUInt16( 0 ); // Pad Word pUserName[ nLenOfUserName ] = 8; mpCurUserStrm->WriteBytes(pUserName, nLenOfUserName + 1); for ( sal_uInt32 i = 0x15 + nLenOfUserName; i < nSizeOfRecord; i++ ) { mpCurUserStrm->WriteUChar( 0 ); // pad bytes } mpCurUserStrm->Seek( nEditPos ); return true; }; void PPTWriter::ImplCreateDocumentSummaryInformation() { uno::Reference xDPS( mXModel, uno::UNO_QUERY_THROW); uno::Reference xDocProps( xDPS->getDocumentProperties()); if (!xDocProps.is()) return; // no idea what this is... static const sal_Int8 aGuid[ 0x52 ] = { 0x4e, 0x00, 0x00, 0x00, '{',0,'D',0,'B',0,'1',0,'A',0,'C',0,'9',0,'6',0,'4',0,'-',0, 'E',0,'3',0,'9',0,'C',0,'-',0,'1',0,'1',0,'D',0,'2',0,'-',0, 'A',0,'1',0,'E',0,'F',0,'-',0,'0',0,'0',0,'6',0,'0',0,'9',0, '7',0,'D',0,'A',0,'5',0,'6',0,'8',0,'9',0,'}',0 }; // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence uno::Sequence aGuidSeq(aGuid, 0x52); SvMemoryStream aHyperBlob; ImplCreateHyperBlob( aHyperBlob ); auto nHyperLength = static_cast(aHyperBlob.Tell()); const sal_Int8* pBlob( static_cast(aHyperBlob.GetData())); auto aHyperSeq = comphelper::arrayToSequence(pBlob, nHyperLength); if ( mnCnvrtFlags & 0x8000 ) { uno::Sequence aThumbSeq; if ( GetPageByIndex( 0, NORMAL ) && ImplGetPropertyValue( mXPagePropSet, "PreviewBitmap" ) ) { aThumbSeq = *o3tl::doAccess>(mAny); } sfx2::SaveOlePropertySet( xDocProps, mrStg.get(), &aThumbSeq, &aGuidSeq, &aHyperSeq); } else { sfx2::SaveOlePropertySet( xDocProps, mrStg.get(), nullptr, &aGuidSeq, &aHyperSeq ); } } void PPTWriter::ImplWriteExtParaHeader( SvMemoryStream& rSt, sal_uInt32 nRef, sal_uInt32 nInstance, sal_uInt32 nSlideId ) { if ( rSt.Tell() ) { aBuExOutlineStream.WriteUInt32( ( EPP_PST_ExtendedParagraphHeaderAtom << 16 ) | ( nRef << 4 ) ) .WriteUInt32( 8 ) .WriteUInt32( nSlideId ) .WriteUInt32( nInstance ); aBuExOutlineStream.WriteBytes(rSt.GetData(), rSt.Tell()); } } void PPTWriter::ImplCreateHeaderFooterStrings( SvStream& rStrm, css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet ) { if ( !rXPagePropSet.is() ) return; OUString aString; css::uno::Any aAny; if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "HeaderText", true ) ) { if ( aAny >>= aString ) PPTWriter::WriteCString( rStrm, aString, 1 ); } if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "FooterText", true ) ) { if ( aAny >>= aString ) PPTWriter::WriteCString( rStrm, aString, 2 ); } if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "DateTimeText", true ) ) { if ( aAny >>= aString ) PPTWriter::WriteCString( rStrm, aString ); } } void PPTWriter::ImplCreateHeaderFooters( css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet ) { if ( !rXPagePropSet.is() ) return; bool bVal = false; sal_uInt32 nVal = 0; css::uno::Any aAny; if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsHeaderVisible", true ) ) { if ( ( aAny >>= bVal ) && bVal ) nVal |= 0x100000; } if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsFooterVisible", true ) ) { if ( ( aAny >>= bVal ) && bVal ) nVal |= 0x200000; } if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsDateTimeVisible", true ) ) { if ( ( aAny >>= bVal ) && bVal ) nVal |= 0x010000; } if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsPageNumberVisible", true ) ) { if ( ( aAny >>= bVal ) && bVal ) nVal |= 0x080000; } if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsDateTimeFixed", true ) ) { if ( ( aAny >>= bVal ) && !bVal ) nVal |= 0x20000; else nVal |= 0x40000; } if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "DateTimeFormat", true ) ) { sal_Int32 nFormat = *o3tl::doAccess(aAny); SvxDateFormat eDateFormat = static_cast( nFormat & 0xf ); SvxTimeFormat eTimeFormat = static_cast( ( nFormat >> 4 ) & 0xf ); switch( eDateFormat ) { case SvxDateFormat::F : nFormat = 1; break; case SvxDateFormat::D : nFormat = 2; break; case SvxDateFormat::C : nFormat = 4; break; default: case SvxDateFormat::A : nFormat = 0; } switch( eTimeFormat ) { case SvxTimeFormat::HH24_MM : nFormat = 9; break; case SvxTimeFormat::HH12_MM : nFormat = 11; break; case SvxTimeFormat::HH24_MM_SS : nFormat = 10; break; case SvxTimeFormat::HH12_MM_SS : nFormat = 12; break; default: break; } nVal |= nFormat; } mpPptEscherEx->OpenContainer( EPP_HeadersFooters ); mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom ); mpStrm->WriteUInt32( nVal ); ImplCreateHeaderFooterStrings( *mpStrm, rXPagePropSet ); mpPptEscherEx->CloseContainer(); } bool PPTWriter::ImplCreateDocument() { sal_uInt32 i; sal_uInt16 nSlideType = EPP_SLIDESIZE_TYPECUSTOM; sal_uInt32 nWidth = maDestPageSize.Width; sal_uInt32 nHeight = maDestPageSize.Height; if ( ( nWidth == 0x1680 ) && ( nHeight == 0x10e0 ) ) nSlideType = EPP_SLIDESIZE_TYPEONSCREEN; else if ( ( nWidth == 0x1200 ) && ( nHeight == 0x240 ) ) nSlideType = EPP_SLIDESIZE_TYPEBANNER; else if ( ( nWidth == 0x1950 ) && ( nHeight == 0x10e0 ) ) nSlideType = EPP_SLIDESIZE_TYPE35MM; else if ( ( nWidth == 0x1860 ) && ( nHeight == 0x10e0 ) ) nSlideType = EPP_SLIDESIZE_TYPEA4PAPER; mpPptEscherEx->OpenContainer( EPP_Document ); // CREATE DOCUMENT ATOM mpPptEscherEx->AddAtom( 40, EPP_DocumentAtom, 1 ); mpStrm->WriteUInt32( nWidth ) // Slide Size in Master coordinates X .WriteUInt32( nHeight ) // " " " " " Y .WriteInt32( maNotesPageSize.Width ) // Notes Page Size X .WriteInt32( maNotesPageSize.Height ) // " " " Y .WriteInt32( 1 ).WriteInt32( 2 ); // the scale used when the Powerpoint document is embedded. the default is 1:2 mpPptEscherEx->InsertPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY, mpStrm->Tell() ); mpStrm->WriteUInt32( 0 ) // Reference to NotesMaster ( 0 if none ); .WriteUInt32( 0 ) // Reference to HandoutMaster ( 0 if none ); .WriteInt16( 1 ) // Number of the first slide; .WriteUInt16( nSlideType ) // Size of the document slides ( default: EPP_SLIDESIZETYPEONSCREEN ) .WriteUChar( 0 ) // bool1 indicates if document was saved with embedded true type fonts .WriteUChar( 0 ) // bool1 indicates if the placeholders on the title slide are omitted .WriteUChar( 0 ) // bool1 right to left ( flag for Bidi version ) .WriteUChar( 1 ); // bool1 visibility of comments shapes mpPptEscherEx->PtInsert( EPP_Persist_Document, mpStrm->Tell() ); mpPptEscherEx->OpenContainer( EPP_HeadersFooters, 3 ); //Master footer (default) mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom ); mpStrm->WriteUInt32( 0x25000d ); if ( GetPageByIndex( 0, MASTER ) ) ImplCreateHeaderFooterStrings( *mpStrm, mXPagePropSet ); mpPptEscherEx->CloseContainer(); mpPptEscherEx->OpenContainer( EPP_HeadersFooters, 4 ); //NotesMaster footer (default) mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom ); mpStrm->WriteUInt32( 0x3d000d ); if ( GetPageByIndex( 0, NOTICE ) ) ImplCreateHeaderFooterStrings( *mpStrm, mXPagePropSet ); mpPptEscherEx->CloseContainer(); mpPptEscherEx->OpenContainer( EPP_SlideListWithText ); // animation information for the slides for ( i = 0; i < mnPages; i++ ) { mpPptEscherEx->AddAtom( 20, EPP_SlidePersistAtom ); mpPptEscherEx->InsertPersistOffset( EPP_MAINSLIDE_PERSIST_KEY | i, mpStrm->Tell() ); mpStrm->WriteUInt32( 0 ) // psrReference - logical reference to the slide persist object ( EPP_MAINSLIDE_PERSIST_KEY ) .WriteUInt32( 4 ) // flags - only bit 3 used, if set then slide contains shapes other than placeholders .WriteInt32( 0 ) // numberTexts - number of placeholder texts stored with the persist object. Allows to display outline view without loading the slide persist objects .WriteInt32( i + 0x100 ) // slideId - Unique slide identifier, used for OLE link monikers for example .WriteUInt32( 0 ); // reserved, usually 0 if ( !GetPageByIndex( i, NORMAL ) ) // very exciting: once again through all pages return false; SetCurrentStyleSheet( GetMasterIndex( NORMAL ) ); css::uno::Reference< css::container::XNamed > aXName( mXDrawPage, css::uno::UNO_QUERY ); if ( aXName.is() ) maSlideNameList.push_back( aXName->getName() ); else maSlideNameList.emplace_back( ); } mpPptEscherEx->CloseContainer(); // EPP_SlideListWithText mpPptEscherEx->OpenContainer( EPP_SlideListWithText, 2 ); // animation information for the notes for( i = 0; i < mnPages; i++ ) { mpPptEscherEx->AddAtom( 20, EPP_SlidePersistAtom ); mpPptEscherEx->InsertPersistOffset( EPP_MAINNOTES_PERSIST_KEY | i, mpStrm->Tell() ); mpStrm->WriteUInt32( 0 ) .WriteUInt32( 4 ) .WriteInt32( 0 ) .WriteInt32( i + 0x100 ) .WriteUInt32( 0 ); } mpPptEscherEx->CloseContainer(); // EPP_SlideListWithText css::uno::Reference< css::presentation::XPresentationSupplier > aXPresSupplier( mXModel, css::uno::UNO_QUERY ); if ( aXPresSupplier.is() ) { css::uno::Reference< css::presentation::XPresentation > aXPresentation( aXPresSupplier->getPresentation() ); if ( aXPresentation.is() ) { mXPropSet.set( aXPresentation, css::uno::UNO_QUERY ); if ( mXPropSet.is() ) { OUString aCustomShow; sal_uInt32 const nPenColor = 0x1000000; sal_Int32 const nRestartTime = 0x7fffffff; sal_Int16 nStartSlide = 0; sal_Int16 nEndSlide = 0; sal_uInt32 nFlags = 0; // Bit 0: Auto advance // Bit 1 Skip builds ( do not allow slide effects ) // Bit 2 Use slide range // Bit 3 Use named show // Bit 4 Browse mode on // Bit 5 Kiosk mode on // Bit 6 Skip narration // Bit 7 loop continuously // Bit 8 show scrollbar if ( ImplGetPropertyValue( "CustomShow" ) ) { aCustomShow = *o3tl::doAccess(mAny); if ( !aCustomShow.isEmpty() ) { nFlags |= 8; } } if ( ( nFlags & 8 ) == 0 ) { if ( ImplGetPropertyValue( "FirstPage" ) ) { auto aSlideName = o3tl::doAccess(mAny); std::vector::const_iterator pIter = std::find( maSlideNameList.begin(),maSlideNameList.end(), *aSlideName); if (pIter != maSlideNameList.end()) { nStartSlide = pIter - maSlideNameList.begin() + 1; nFlags |= 4; nEndSlide = static_cast(mnPages); } } } if ( ImplGetPropertyValue( "IsAutomatic" ) ) { bool bBool = false; mAny >>= bBool; if ( !bBool ) nFlags |= 1; } if ( ImplGetPropertyValue( "IsEndless" ) ) { bool bBool = false; mAny >>= bBool; if ( bBool ) nFlags |= 0x80; } if ( ImplGetPropertyValue( "IsFullScreen" ) ) { bool bBool = false; mAny >>= bBool; if ( !bBool ) nFlags |= 0x11; } mpPptEscherEx->AddAtom( 80, EPP_SSDocInfoAtom, 1 ); mpStrm->WriteUInt32( nPenColor ).WriteInt32( nRestartTime ).WriteInt16( nStartSlide ).WriteInt16( nEndSlide ); sal_uInt32 nCustomShowNameLen = aCustomShow.getLength(); if ( nCustomShowNameLen > 31 ) nCustomShowNameLen = 31; if ( nCustomShowNameLen ) // named show identifier { const sal_Unicode* pCustomShow = aCustomShow.getStr(); for ( i = 0; i < nCustomShowNameLen; i++ ) { mpStrm->WriteUInt16( pCustomShow[ i ] ); } } for ( i = nCustomShowNameLen; i < 32; i++, mpStrm->WriteUInt16( 0 ) ) ; mpStrm->WriteUInt32( nFlags ); css::uno::Reference< css::presentation::XCustomPresentationSupplier > aXCPSup( mXModel, css::uno::UNO_QUERY ); if ( aXCPSup.is() ) { css::uno::Reference< css::container::XNameContainer > aXCont( aXCPSup->getCustomPresentations() ); if ( aXCont.is() ) { const css::uno::Sequence< OUString> aNameSeq( aXCont->getElementNames() ); if ( aNameSeq.hasElements() ) { mpPptEscherEx->OpenContainer( EPP_NamedShows ); sal_uInt32 nCustomShowIndex = 0; for( OUString const & customShowName : aNameSeq ) { if ( !customShowName.isEmpty() ) { mpPptEscherEx->OpenContainer( EPP_NamedShow, nCustomShowIndex++ ); sal_uInt32 nNamedShowLen = customShowName.getLength(); if ( nNamedShowLen > 31 ) nNamedShowLen = 31; mpPptEscherEx->AddAtom( nNamedShowLen << 1, EPP_CString ); const sal_Unicode* pCustomShowName = customShowName.getStr(); for ( sal_uInt32 k = 0; k < nNamedShowLen; ++k ) mpStrm->WriteUInt16( pCustomShowName[ k ] ); mAny = aXCont->getByName( customShowName ); css::uno::Reference< css::container::XIndexContainer > aXIC; if ( mAny >>= aXIC ) { mpPptEscherEx->BeginAtom(); sal_Int32 nSlideCount = aXIC->getCount(); for ( sal_Int32 j = 0; j < nSlideCount; j++ ) // number of slides { mAny = aXIC->getByIndex( j ); css::uno::Reference< css::drawing::XDrawPage > aXDrawPage; if ( mAny >>= aXDrawPage ) { css::uno::Reference< css::container::XNamed > aXName( aXDrawPage, css::uno::UNO_QUERY ); if ( aXName.is() ) { OUString aSlideName( aXName->getName() ); std::vector::const_iterator pIter = std::find( maSlideNameList.begin(),maSlideNameList.end(),aSlideName); if (pIter != maSlideNameList.end()) { sal_uInt32 nPageNumber = pIter - maSlideNameList.begin(); mpStrm->WriteUInt32( nPageNumber + 0x100 ); // unique slide id } } } } mpPptEscherEx->EndAtom( EPP_NamedShowSlides ); } mpPptEscherEx->CloseContainer(); // EPP_NamedShow } } mpPptEscherEx->CloseContainer(); // EPP_NamedShows } } } } } } mpPptEscherEx->AddAtom( 0, EPP_EndDocument ); mpPptEscherEx->CloseContainer(); // EPP_Document return true; }; void PPTWriter::ImplCreateHyperBlob( SvMemoryStream& rStrm ) { sal_uInt32 nCurrentOfs, nParaOfs, nParaCount = 0; nParaOfs = rStrm.Tell(); rStrm.WriteUInt32( 0 ); // property size rStrm.WriteUInt32( 0 ); // property count for ( const auto& rHyperlink : maHyperlink ) { nParaCount += 6; rStrm .WriteUInt32( 3 ) // Type VT_I4 .WriteUInt32( 7 ) // (VTI4 - Private1) .WriteUInt32( 3 ) // Type VT_I4 .WriteUInt32( 6 ) // (VTI4 - Private2) .WriteUInt32( 3 ) // Type VT_I4 .WriteUInt32( 0 ); // (VTI4 - Private3) // INFO // HIWORD: = 0 : do not change anything // = 1 : replace the hyperlink with the target and subaddress in the following two VTLPWSTR // = 2 : delete the hyperlink // LOWORD: = 0 : graphic shown as background (link) // = 1 : graphic shown as shape (link) // = 2 : graphic is used to fill a shape // = 3 : graphic used to fill a shape outline (future use) // = 4 : hyperlink attached to a shape // = 5 : " " " " (Word) field // = 6 : " " " " (Excel) range // = 7 : " " " " (PPT) text range // = 8 : " " " " (Project) task sal_Int32 nUrlLen = rHyperlink.aURL.getLength(); const OUString& rUrl = rHyperlink.aURL; sal_uInt32 const nInfo = 7; rStrm .WriteUInt32( 3 ) // Type VT_I4 .WriteUInt32( nInfo ); // Info switch( rHyperlink.nType & 0xff ) { case 1 : // click action to slidenumber { rStrm.WriteUInt32( 0x1f ).WriteUInt32( 1 ).WriteUInt32( 0 ); // path rStrm.WriteUInt32( 0x1f ).WriteUInt32( nUrlLen + 1 ); for ( sal_Int32 i = 0; i < nUrlLen; i++ ) { rStrm.WriteUInt16( rUrl[ i ] ); } rStrm.WriteUInt16( 0 ); } break; case 2 : { sal_Int32 i; rStrm .WriteUInt32( 0x1f ) .WriteUInt32( nUrlLen + 1 ); for ( i = 0; i < nUrlLen; i++ ) { rStrm.WriteUInt16( rUrl[ i ] ); } if ( ! ( i & 1 ) ) rStrm.WriteUInt16( 0 ); rStrm .WriteUInt16( 0 ) .WriteUInt32( 0x1f ) .WriteUInt32( 1 ) .WriteUInt32( 0 ); } break; } } nCurrentOfs = rStrm.Tell(); rStrm.Seek( nParaOfs ); rStrm.WriteUInt32( nCurrentOfs - ( nParaOfs + 4 ) ); rStrm.WriteUInt32( nParaCount ); rStrm.Seek( nCurrentOfs ); } bool PPTWriter::ImplCreateMainNotes() { EscherSolverContainer aSolverContainer; mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_MainNotes, mpStrm->Tell() ); mpPptEscherEx->OpenContainer( EPP_Notes ); mpPptEscherEx->AddAtom( 8, EPP_NotesAtom, 1 ); mpStrm->WriteUInt32( 0x80000001 ) // Number that identifies this slide .WriteUInt32( 0 ); // follow nothing mpPptEscherEx->OpenContainer( EPP_PPDrawing ); mpPptEscherEx->OpenContainer( ESCHER_DgContainer ); mpPptEscherEx->EnterGroup(nullptr,nullptr); ImplWritePage( GetLayout( 20 ), aSolverContainer, NOTICE, true ); mpPptEscherEx->LeaveGroup(); mpPptEscherEx->OpenContainer( ESCHER_SpContainer ); mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty ); EscherPropertyContainer aPropOpt; aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0xffffff ); // stock valued fill color aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0 ); aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, 0x68bdde ); aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, 0x8b9f8e ); aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 ); aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0 ); aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow ); aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 ); // if true, this is the background shape aPropOpt.Commit( *mpStrm ); mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer aSolverContainer.WriteSolver( *mpStrm ); mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer mpPptEscherEx->CloseContainer(); // EPP_Drawing mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 ); mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 ); mpPptEscherEx->CloseContainer(); // EPP_Notes return true; } static OUString getInitials( const OUString& rName ) { OUStringBuffer sInitials; const sal_Unicode * pStr = rName.getStr(); sal_Int32 nLength = rName.getLength(); while( nLength ) { // skip whitespace while( nLength && (*pStr <= ' ') ) { nLength--; pStr++; } // take letter if( nLength ) { sInitials.append( *pStr ); nLength--; pStr++; } // skip letters until whitespace while( nLength && (*pStr > ' ') ) { nLength--; pStr++; } } return sInitials.makeStringAndClear(); } void ImplExportComments( const uno::Reference< drawing::XDrawPage >& xPage, SvMemoryStream& rBinaryTagData10Atom ) { try { uno::Reference< office::XAnnotationAccess > xAnnotationAccess( xPage, uno::UNO_QUERY_THROW ); uno::Reference< office::XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() ); sal_Int32 nIndex = 1; while( xAnnotationEnumeration->hasMoreElements() ) { EscherExContainer aComment10( rBinaryTagData10Atom, EPP_Comment10 ); { uno::Reference< office::XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement() ); geometry::RealPoint2D aRealPoint2D( xAnnotation->getPosition() ); Point aPoint(o3tl::convert(aRealPoint2D.X, o3tl::Length::mm, o3tl::Length::master), o3tl::convert(aRealPoint2D.Y, o3tl::Length::mm, o3tl::Length::master)); OUString sAuthor( xAnnotation->getAuthor() ); uno::Reference< text::XText > xText( xAnnotation->getTextRange() ); OUString sText( xText->getString() ); OUString sInitials( getInitials( sAuthor ) ); util::DateTime aDateTime( xAnnotation->getDateTime() ); if ( !sAuthor.isEmpty() ) PPTWriter::WriteCString( rBinaryTagData10Atom, sAuthor ); if ( !sText.isEmpty() ) PPTWriter::WriteCString( rBinaryTagData10Atom, sText, 1 ); if ( !sInitials.isEmpty() ) PPTWriter::WriteCString( rBinaryTagData10Atom, sInitials, 2 ); sal_Int16 nMilliSeconds = static_cast(::rtl::math::round(static_cast(aDateTime.NanoSeconds) / 1000000000.0)); EscherExAtom aCommentAtom10( rBinaryTagData10Atom, EPP_CommentAtom10 ); rBinaryTagData10Atom.WriteInt32( nIndex++ ) .WriteInt16( aDateTime.Year ) .WriteUInt16( aDateTime.Month ) .WriteUInt16( aDateTime.Day ) // todo: day of week .WriteUInt16( aDateTime.Day ) .WriteUInt16( aDateTime.Hours ) .WriteUInt16( aDateTime.Minutes ) .WriteUInt16( aDateTime.Seconds ) .WriteInt16( nMilliSeconds ) .WriteInt32( aPoint.X() ) .WriteInt32( aPoint.Y() ); } } } catch ( uno::Exception& ) { } } void PPTWriter::ImplWriteNotes( sal_uInt32 nPageNum ) { mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_Notes | nPageNum, mpStrm->Tell() ); mpPptEscherEx->OpenContainer( EPP_Notes ); mpPptEscherEx->AddAtom( 8, EPP_NotesAtom, 1 ); mpStrm->WriteUInt32( nPageNum + 0x100 ) .WriteUInt16( 3 ) // follow master... .WriteUInt16( 0 ); ImplCreateHeaderFooters( mXPagePropSet ); EscherSolverContainer aSolverContainer; mpPptEscherEx->OpenContainer( EPP_PPDrawing ); mpPptEscherEx->OpenContainer( ESCHER_DgContainer ); mpPptEscherEx->EnterGroup(nullptr,nullptr); ImplWritePage( GetLayout( 20 ), aSolverContainer, NOTICE, false ); // the shapes of the pages are created in the PPT document mpPptEscherEx->LeaveGroup(); mpPptEscherEx->OpenContainer( ESCHER_SpContainer ); mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty ); EscherPropertyContainer aPropOpt; aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0xffffff ); // stock valued fill color aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0 ); aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, 0x8b9f8e ); aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, 0x68bdde ); aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 ); aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 ); aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow ); aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 ); aPropOpt.Commit( *mpStrm ); mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer aSolverContainer.WriteSolver( *mpStrm ); mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer mpPptEscherEx->CloseContainer(); // EPP_Drawing mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 ); mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 ); mpPptEscherEx->CloseContainer(); // EPP_Notes }; void PPTWriter::ImplWriteBackground( css::uno::Reference< css::beans::XPropertySet > const & rXPropSet ) { //************************ ****** //** DEFAULT BACKGROUND SHAPE ** sal_uInt32 nFillColor = 0xffffff; sal_uInt32 nFillBackColor = 0; mpPptEscherEx->OpenContainer( ESCHER_SpContainer ); mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty ); // #i121183# Use real PageSize in 100th mm ::tools::Rectangle aRect(Point(0, 0), Size(maPageSize.Width, maPageSize.Height)); EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect ); aPropOpt.AddOpt( ESCHER_Prop_fillType, ESCHER_FillSolid ); css::drawing::FillStyle aFS( css::drawing::FillStyle_NONE ); if ( ImplGetPropertyValue( rXPropSet, "FillStyle" ) ) mAny >>= aFS; switch( aFS ) { case css::drawing::FillStyle_GRADIENT : { aPropOpt.CreateGradientProperties( rXPropSet ); aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x1f001e ); aPropOpt.GetOpt( ESCHER_Prop_fillColor, nFillColor ); aPropOpt.GetOpt( ESCHER_Prop_fillBackColor, nFillBackColor ); } break; case css::drawing::FillStyle_BITMAP : aPropOpt.CreateGraphicProperties( rXPropSet, "FillBitmap", true ); break; case css::drawing::FillStyle_HATCH : aPropOpt.CreateGraphicProperties( rXPropSet, "FillHatch", true ); break; case css::drawing::FillStyle_SOLID : { if ( ImplGetPropertyValue( rXPropSet, "FillColor" ) ) { nFillColor = EscherEx::GetColor( *o3tl::doAccess(mAny) ); nFillBackColor = nFillColor ^ 0xffffff; } [[fallthrough]]; } case css::drawing::FillStyle_NONE : default: aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 ); break; } aPropOpt.AddOpt( ESCHER_Prop_fillColor, nFillColor ); aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, nFillBackColor ); aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, PPTtoEMU( maDestPageSize.Width ) ); aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, PPTtoEMU( maDestPageSize.Height ) ); aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 ); aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_bwWhite ); aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 ); aPropOpt.Commit( *mpStrm ); mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer } void PPTWriter::ImplWriteVBA() { if ( mpVBA ) { sal_uInt32 nLen = mpVBA->TellEnd(); if ( nLen > 8 ) { nLen -= 8; mnVBAOleOfs = mpStrm->Tell(); mpPptEscherEx->BeginAtom(); mpStrm->WriteBytes(static_cast(mpVBA->GetData()) + 8, nLen); mpPptEscherEx->EndAtom( EPP_ExOleObjStg, 0, 1 ); } } } void PPTWriter::ImplWriteOLE( ) { SvxMSExportOLEObjects aOleExport( mnCnvrtFlags ); for ( const auto& rxExOleObjEntry : maExOleObj ) { PPTExOleObjEntry* pPtr = rxExOleObjEntry.get(); std::unique_ptr pStrm; pPtr->nOfsB = mpStrm->Tell(); switch ( pPtr->eType ) { case NORMAL_OLE_OBJECT : { SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(pPtr->xShape); if ( auto pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >(pSdrObj) ) { const ::uno::Reference < embed::XEmbeddedObject >& xObj( pSdrOle2Obj->GetObjRef() ); if( xObj.is() ) { tools::SvRef xTempStorage( new SotStorage( new SvMemoryStream(), true ) ); aOleExport.ExportOLEObject( xObj, *xTempStorage ); //TODO/MBA: testing SvMemoryStream aStream; tools::SvRef xCleanStorage( new SotStorage( false, aStream ) ); xTempStorage->CopyTo( xCleanStorage.get() ); // create a dummy content stream, the dummy content is necessary for ppt, but not for // doc files, so we can't share code. tools::SvRef xStm = xCleanStorage->OpenSotStream( SVEXT_PERSIST_STREAM ); xStm->WriteUInt32( 0 ) // no ClipboardId .WriteUInt32( 4 ) // no target device .WriteUInt32( 1 ) // aspect ratio .WriteInt32( -1 ) // L-Index .WriteUInt32( 0 ) // Advanced Flags .WriteUInt32( 0 ) // compression .WriteUInt32( 0 ) // Size .WriteUInt32( 0 ) // " .WriteUInt32( 0 ); pStrm = xCleanStorage->CreateMemoryStream(); } } } break; case OCX_CONTROL : { if ( pPtr->xControlModel.is() ) { OUString aName; //Initialize the graphic size which will be used on export css::awt::Size aSize( pPtr->xShape->getSize() ); tools::SvRef xDest( new SotStorage( new SvMemoryStream(), true ) ); bool bOk = oox::ole::MSConvertOCXControls::WriteOCXStream( mXModel, xDest, pPtr->xControlModel, aSize, aName ); if ( bOk ) pStrm = xDest->CreateMemoryStream(); } } } if ( pStrm ) { mpPptEscherEx->BeginAtom(); pStrm->Seek( STREAM_SEEK_TO_END ); sal_uInt32 npStrmSize = pStrm->Tell(); mpStrm->WriteUInt32( npStrmSize ); // uncompressed size pStrm->Seek( 0 ); ZCodec aZCodec( 0x8000, 0x8000 ); aZCodec.BeginCompression(); aZCodec.Compress( *pStrm, *mpStrm ); aZCodec.EndCompression(); pStrm.reset(); mpPptEscherEx->EndAtom( EPP_ExOleObjStg, 0, 1 ); } } } // write PersistantTable and UserEditAtom void PPTWriter::ImplWriteAtomEnding() { #define EPP_LastViewTypeSlideView 1 sal_uInt32 i, nPos, nOfs, nPersistOfs = mpStrm->Tell(); sal_uInt32 nPersistEntrys = 0; mpStrm->WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ); // skip record header and first entry // write document persist nPersistEntrys++; mpStrm->WriteUInt32( 0 ); // write MasterPages persists for ( i = 0; i < mnMasterPages; i++ ) { nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_MainMaster | i ); if ( nOfs ) { mpStrm->WriteUInt32( nOfs ); mpPptEscherEx->InsertAtPersistOffset( EPP_MAINMASTER_PERSIST_KEY | i, ++nPersistEntrys ); } } // write MainNotesMaster persist nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_MainNotes ); if ( nOfs ) { mpStrm->WriteUInt32( nOfs ); mpPptEscherEx->InsertAtPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY, ++nPersistEntrys ); } // write slide persists -> we have to write a valid value into EPP_SlidePersistAtome too for ( i = 0; i < mnPages; i++ ) { nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Slide | i ); if ( nOfs ) { mpStrm->WriteUInt32( nOfs ); mpPptEscherEx->InsertAtPersistOffset( EPP_MAINSLIDE_PERSIST_KEY | i, ++nPersistEntrys ); } } // write Notes persists for ( i = 0; i < mnPages; i++ ) { nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Notes | i ); if ( nOfs ) { mpStrm->WriteUInt32( nOfs ); mpPptEscherEx->InsertAtPersistOffset( EPP_MAINNOTES_PERSIST_KEY | i, ++nPersistEntrys ); } } // Ole persists for ( const auto& rxExOleObjEntry : maExOleObj ) { PPTExOleObjEntry* pPtr = rxExOleObjEntry.get(); nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_ExObj ); if ( nOfs ) { nPersistEntrys++; mpStrm->WriteUInt32( pPtr->nOfsB ); sal_uInt32 nOldPos, nPersOfs = nOfs + pPtr->nOfsA + 16 + 8; // 8 bytes atom header, +16 to the persist entry nOldPos = mpStrm->Tell(); mpStrm->Seek( nPersOfs ); mpStrm->WriteUInt32( nPersistEntrys ); mpStrm->Seek( nOldPos ); } } // VB persist if ( mnVBAOleOfs && mpVBA ) { nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_VBAInfoAtom ); if ( nOfs ) { nPersistEntrys++; sal_uInt32 n1, n2; mpVBA->Seek( 0 ); mpVBA->ReadUInt32( n1 ) .ReadUInt32( n2 ); mpStrm->WriteUInt32( mnVBAOleOfs ); sal_uInt32 nOldPos = mpStrm->Tell(); mpStrm->Seek( nOfs ); // Fill the VBAInfoAtom with the correct index to the persisttable mpStrm->WriteUInt32( nPersistEntrys ) .WriteUInt32( n1 ) .WriteInt32( 2 ); mpStrm->Seek( nOldPos ); } } nPos = mpStrm->Tell(); mpStrm->Seek( nPersistOfs ); mpPptEscherEx->AddAtom( ( nPersistEntrys + 1 ) << 2, EPP_PersistPtrIncrementalBlock ); // insert Record Header mpStrm->WriteUInt32( ( nPersistEntrys << 20 ) | 1 ); mpStrm->Seek( nPos ); mpCurUserStrm->WriteUInt32( nPos ); // set offset to current edit mpPptEscherEx->AddAtom( 28, EPP_UserEditAtom ); mpStrm->WriteInt32( 0x100 ) // last slide ID .WriteUInt32( 0x03000dbc ) // minor and major app version that did the save .WriteUInt32( 0 ) // offset last save, 0 after a full save .WriteUInt32( nPersistOfs ) // File offset to persist pointers for this save operation .WriteUInt32( 1 ) // Persist reference to the document persist object .WriteUInt32( nPersistEntrys ) // max persists written, Seed value for persist object id management .WriteInt16( EPP_LastViewTypeSlideView ) // last view type .WriteInt16( 0x12 ); // padword } // - exported function - extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool ExportPPT( const std::vector< css::beans::PropertyValue >& rMediaData, tools::SvRef const & rSvStorage, css::uno::Reference< css::frame::XModel > const & rXModel, css::uno::Reference< css::task::XStatusIndicator > const & rXStatInd, SvMemoryStream* pVBA, sal_uInt32 nCnvrtFlags ) { PPTWriter aPPTWriter( rSvStorage, rXModel, rXStatInd, pVBA, nCnvrtFlags ); aPPTWriter.exportPPT(rMediaData); bool bStatus = aPPTWriter.IsValid(); return bStatus; } extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool SaveVBA( SfxObjectShell& rDocShell, SvMemoryStream*& pBas ) { tools::SvRef xDest( new SotStorage( new SvMemoryStream(), true ) ); SvxImportMSVBasic aMSVBas( rDocShell, *xDest ); aMSVBas.SaveOrDelMSVBAStorage( true, "_MS_VBA_Overhead" ); tools::SvRef xOverhead = xDest->OpenSotStorage( "_MS_VBA_Overhead" ); if ( xOverhead.is() && ( xOverhead->GetError() == ERRCODE_NONE ) ) { tools::SvRef xOverhead2 = xOverhead->OpenSotStorage( "_MS_VBA_Overhead" ); if ( xOverhead2.is() && ( xOverhead2->GetError() == ERRCODE_NONE ) ) { tools::SvRef xTemp = xOverhead2->OpenSotStream( "_MS_VBA_Overhead2" ); if ( xTemp.is() && ( xTemp->GetError() == ERRCODE_NONE ) ) { sal_uInt32 nLen = xTemp->GetSize(); if ( nLen ) { char* pTemp = new char[ nLen ]; xTemp->Seek( STREAM_SEEK_TO_BEGIN ); xTemp->ReadBytes(pTemp, nLen); pBas = new SvMemoryStream( pTemp, nLen, StreamMode::READ ); pBas->ObjectOwnsMemory( true ); return true; } } } } return false; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */