/* -*- 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 <sal/config.h>
 
#include <osl/endian.h>
#include <utility>
#include <vcl/svapp.hxx>
#include <unotools/tempfile.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <tools/UnitConversion.hxx>
#include <editeng/eeitem.hxx>
#include <editeng/editdata.hxx>
#include <sot/storage.hxx>
#include <sot/storinfo.hxx>
#include <sot/stg.hxx>
#include <com/sun/star/embed/Aspects.hpp>
#include <com/sun/star/embed/XEmbeddedObject.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/office/XAnnotation.hpp>
#include <com/sun/star/office/XAnnotationAccess.hpp>
#include <com/sun/star/text/XText.hpp>
#include <com/sun/star/geometry/RealPoint2D.hpp>
#include <com/sun/star/util/DateTime.hpp>
#include <com/sun/star/drawing/BitmapMode.hpp>
#include <filter/msfilter/svdfppt.hxx>
#include <svx/xflgrit.hxx>
#include <svx/xbtmpit.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdobj.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdorect.hxx>
#include <svx/svdopage.hxx>
#include <svx/svdograf.hxx>
#include <svx/svdopath.hxx>
#include <svx/svdotable.hxx>
#include <svx/xfillit0.hxx>
#include <svx/xfilluseslidebackgrounditem.hxx>
#include <svx/xflbstit.hxx>
#include <svx/xflbmtit.hxx>
#include <svx/xflclit.hxx>
#include <svx/xfltrit.hxx>
#include <editeng/outlobj.hxx>
#include <editeng/numdef.hxx>
#include <svx/sdasitm.hxx>
#include <svx/sdmetitm.hxx>
#include <svx/sdtagitm.hxx>
#include <svx/sdtditm.hxx>
#include <svx/sdtfsitm.hxx>
#include <svx/sdtmfitm.hxx>
#include <svx/xlineit0.hxx>
#include <svx/xlnclit.hxx>
#include <svx/xlnwtit.hxx>
#include <editeng/hngpnctitem.hxx>
#include <editeng/forbiddenruleitem.hxx>
#include <svx/svdoashp.hxx>
#include <editeng/tstpitem.hxx>
#include <editeng/editids.hrc>
 
#include <editeng/adjustitem.hxx>
#include <editeng/escapementitem.hxx>
#include <editeng/colritem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/wghtitem.hxx>
#include <editeng/postitem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/crossedoutitem.hxx>
#include <editeng/shdditem.hxx>
#include <editeng/charreliefitem.hxx>
#include <editeng/fontitem.hxx>
#include <svx/svdoutl.hxx>
#include <editeng/lspcitem.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/numitem.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/BitmapReadAccess.hxx>
#include <svx/svditer.hxx>
#include <editeng/flditem.hxx>
#include <tools/zcodec.hxx>
#include <filter/msfilter/svxmsbas.hxx>
#include <sfx2/objsh.hxx>
#include <editeng/brushitem.hxx>
#include <editeng/langitem.hxx>
#include <svx/svdoole2.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <com/sun/star/container/XIndexContainer.hpp>
#include <com/sun/star/drawing/XControlShape.hpp>
#include <com/sun/star/form/XFormComponent.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
#include <com/sun/star/awt/Size.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
#include <editeng/frmdiritem.hxx>
#include <svx/sdtfchim.hxx>
#include <com/sun/star/awt/Gradient.hpp>
#include <com/sun/star/table/XMergeableCellRange.hpp>
#include <com/sun/star/table/BorderLine2.hpp>
#include <com/sun/star/table/BorderLineStyle.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <svtools/embedhlp.hxx>
#include <o3tl/enumrange.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/sorted_vector.hxx>
#include <sal/log.hxx>
 
#include <algorithm>
#include <cassert>
#include <rtl/strbuf.hxx>
#include <tools/time.hxx>
#include <memory>
 
// PPT ColorScheme Slots
#define PPT_COLSCHEME                       (0x08000000)
#define PPT_COLSCHEME_HINTERGRUND           (0x08000000)
#define PPT_COLSCHEME_TEXT_UND_ZEILEN       (0x08000001)
#define PPT_COLSCHEME_TITELTEXT             (0x08000003)
#define PPT_COLSCHEME_A_UND_HYPERLINK       (0x08000006)
 
#define ANSI_CHARSET            0
#define SYMBOL_CHARSET          2
 
/* Font Families */
#define FF_ROMAN                0x10
#define FF_SWISS                0x20
#define FF_MODERN               0x30
#define FF_SCRIPT               0x40
#define FF_DECORATIVE           0x50
 
#define DEFAULT_PITCH           0x00
#define FIXED_PITCH             0x01
#define VARIABLE_PITCH          0x02
 
using namespace ::com::sun::star    ;
using namespace uno                 ;
using namespace beans               ;
using namespace drawing             ;
using namespace container           ;
using namespace table               ;
 
PowerPointImportParam::PowerPointImportParam( SvStream& rDocStrm ) :
    rDocStream      ( rDocStrm ),
    nImportFlags    ( 0 )
{
}
 
SvStream& ReadPptCurrentUserAtom( SvStream& rIn, PptCurrentUserAtom& rAtom )
{
    DffRecordHeader aHd;
    ReadDffRecordHeader( rIn, aHd );
    if ( aHd.nRecType == PPT_PST_CurrentUserAtom )
    {
        sal_uInt32 nLen;
        sal_uInt16 nUserNameLen(0), nPad;
        rIn.ReadUInt32( nLen )
           .ReadUInt32( rAtom.nMagic )
           .ReadUInt32( rAtom.nCurrentUserEdit )
           .ReadUInt16( nUserNameLen )
           .ReadUInt16( rAtom.nDocFileVersion )
           .ReadUChar( rAtom.nMajorVersion )
           .ReadUChar( rAtom.nMinorVersion )
           .ReadUInt16( nPad );
        rAtom.aCurrentUser = SvxMSDffManager::MSDFFReadZString( rIn, nUserNameLen, true );
    }
    aHd.SeekToEndOfRecord( rIn );
    return rIn;
}
 
void PptSlidePersistAtom::Clear()
{
    nReserved = nPsrReference = nFlags = nNumberTexts = nSlideId = 0;
}
 
SvStream& ReadPptSlidePersistAtom( SvStream& rIn, PptSlidePersistAtom& rAtom )
{
    DffRecordHeader aHd;
    ReadDffRecordHeader( rIn, aHd );
    rIn
       .ReadUInt32( rAtom.nPsrReference )
       .ReadUInt32( rAtom.nFlags )
       .ReadUInt32( rAtom.nNumberTexts )
       .ReadUInt32( rAtom.nSlideId );
    aHd.SeekToEndOfRecord( rIn );
    return rIn;
}
 
PptSlidePersistList::PptSlidePersistList() {}
 
PptSlidePersistList::~PptSlidePersistList() {}
 
sal_uInt16 PptSlidePersistList::FindPage(sal_uInt32 nId) const
{
    for ( size_t i=0; i < mvEntries.size(); i++ )
    {
        if (mvEntries[ i ]->GetSlideId() == nId) return i;
    }
    return PPTSLIDEPERSIST_ENTRY_NOTFOUND;
}
 
bool ReadPptInteractiveInfoAtom( SvStream& rIn, PptInteractiveInfoAtom& rAtom )
{
    rIn.ReadUInt32( rAtom.nSoundRef )
       .ReadUInt32( rAtom.nExHyperlinkId )
       .ReadUChar( rAtom.nAction )
       .ReadUChar( rAtom.nOleVerb )
       .ReadUChar( rAtom.nJump )
       .ReadUChar( rAtom.nFlags )
       .ReadUChar( rAtom.nHyperlinkType )
       .ReadUChar( rAtom.nUnknown1 )
       .ReadUChar( rAtom.nUnknown2 )
       .ReadUChar( rAtom.nUnknown3 );
    return rIn.good();
}
 
SvStream& ReadPptExOleObjAtom( SvStream& rIn, PptExOleObjAtom& rAtom )
{
    sal_uInt32 nDummy1;
    sal_uInt32 nDummy2;
    sal_uInt32 nDummy4;
 
    rIn.ReadUInt32( rAtom.nAspect )
       .ReadUInt32( nDummy1 )
       .ReadUInt32( rAtom.nId )
       .ReadUInt32( nDummy2 )
       .ReadUInt32( rAtom.nPersistPtr )
       .ReadUInt32( nDummy4 );
    return rIn;
}
 
SvStream& ReadPptDocumentAtom(SvStream& rIn, PptDocumentAtom& rAtom)
{
// Actual format:
//  00 aSlidePageSizeXY  8
//  08 aNotesPageSizeXY  8
//  16 aZoomRatio (OLE)  8
//  24 nNotesMasterPersist   4
//  28 nHandoutMasterPersist 4
//  32 n1stPageNumber    2
//  34 ePageFormat       2
//  36 bEmbeddedTrueType 1
//  37 bOmitTitlePlace   1
//  38 bRightToLeft      1
//  39 bShowComments     1
 
    DffRecordHeader aHd;
    sal_Int32 nSlideX(0), nSlideY(0), nNoticeX(0), nNoticeY(0), nDummy;
    sal_uInt16 nSlidePageFormat(0);
    sal_Int8 nEmbeddedTrueType(0), nTitlePlaceHoldersOmitted(0), nRightToLeft(0), nShowComments(0);
 
    ReadDffRecordHeader( rIn, aHd );
    rIn
       .ReadInt32( nSlideX ).ReadInt32( nSlideY )
       .ReadInt32( nNoticeX ).ReadInt32( nNoticeY )
       .ReadInt32( nDummy ).ReadInt32( nDummy )             // skip ZoomRatio
       .ReadUInt32( rAtom.nNotesMasterPersist )
       .ReadUInt32( rAtom.nHandoutMasterPersist )
       .ReadUInt16( rAtom.n1stPageNumber )
       .ReadUInt16( nSlidePageFormat )
       .ReadSChar( nEmbeddedTrueType )
       .ReadSChar( nTitlePlaceHoldersOmitted )
       .ReadSChar( nRightToLeft )
       .ReadSChar( nShowComments );
    // clamp dodgy data to avoid overflow in later calculations
    const sal_Int32 nPageClamp = SAL_MAX_INT32/5;
    rAtom.aSlidesPageSize.setWidth( std::clamp<sal_Int32>(nSlideX, -nPageClamp, nPageClamp) );
    rAtom.aSlidesPageSize.setHeight( std::clamp<sal_Int32>(nSlideY, -nPageClamp, nPageClamp) );
    const sal_Int32 nNoteClamp = 65536;
    rAtom.aNotesPageSize.setWidth( std::clamp<sal_Int32>(nNoticeX, -nNoteClamp, nNoteClamp) );
    rAtom.aNotesPageSize.setHeight( std::clamp<sal_Int32>(nNoticeY, -nNoteClamp, nNoteClamp) );
    rAtom.eSlidesPageFormat = static_cast<PptPageFormat>(nSlidePageFormat);
    rAtom.bEmbeddedTrueType = nEmbeddedTrueType;
    rAtom.bTitlePlaceholdersOmitted = nTitlePlaceHoldersOmitted;
    rAtom.bRightToLeft = nRightToLeft;
    rAtom.bShowComments = nShowComments;
    aHd.SeekToEndOfRecord( rIn );
    return rIn;
}
 
void PptSlideLayoutAtom::Clear()
{
    eLayout = PptSlideLayout::TITLESLIDE;
    for (PptPlaceholder & i : aPlaceholderId)
        i = PptPlaceholder::NONE;
}
 
SvStream& ReadPptSlideLayoutAtom( SvStream& rIn, PptSlideLayoutAtom& rAtom )
{
    sal_Int32 nTmp;
    rIn.ReadInt32(nTmp);
    rAtom.eLayout = static_cast<PptSlideLayout>(nTmp);
    static_assert(sizeof(rAtom.aPlaceholderId) == 8, "wrong size of serialized array");
    rIn.ReadBytes(rAtom.aPlaceholderId, 8);
    return rIn;
}
 
SvStream& ReadPptSlideAtom( SvStream& rIn, PptSlideAtom& rAtom )
{
    DffRecordHeader aHd;
    ReadDffRecordHeader( rIn, aHd );
    ReadPptSlideLayoutAtom( rIn, rAtom.aLayout );
    rIn.ReadUInt32( rAtom.nMasterId )
       .ReadUInt32( rAtom.nNotesId )
       .ReadUInt16( rAtom.nFlags );
    aHd.SeekToEndOfRecord( rIn );
    return rIn;
}
 
void PptSlideAtom::Clear()
{
    nMasterId = nNotesId = 0;
    nFlags = 0;
}
 
SvStream& ReadPptNotesAtom( SvStream& rIn, PptNotesAtom& rAtom )
{
    DffRecordHeader aHd;
    ReadDffRecordHeader( rIn, aHd );
    rIn
       .ReadUInt32( rAtom.nSlideId )
       .ReadUInt16( rAtom.nFlags );
    aHd.SeekToEndOfRecord( rIn );
    return rIn;
}
 
void PptNotesAtom::Clear()
{
    nSlideId = 0;
    nFlags = 0;
}
 
PptColorSchemeAtom::PptColorSchemeAtom()
{
}
 
Color PptColorSchemeAtom::GetColor( sal_uInt16 nNum ) const
{
    Color aRetval;
    if ( nNum < 8 )
    {
        nNum <<= 2;
        aRetval.SetRed( aData[ nNum++ ] );
        aRetval.SetGreen( aData[ nNum++ ] );
        aRetval.SetBlue( aData[ nNum++ ] );
    }
    return aRetval;
}
 
SvStream& ReadPptColorSchemeAtom( SvStream& rIn, PptColorSchemeAtom& rAtom )
{
    DffRecordHeader aHd;
    ReadDffRecordHeader( rIn, aHd );
    rIn.ReadBytes(rAtom.aData, 32);
    aHd.SeekToEndOfRecord( rIn );
    return rIn;
}
 
SvStream& ReadPptFontEntityAtom( SvStream& rIn, PptFontEntityAtom& rAtom )
{
    DffRecordHeader aHd;
    ReadDffRecordHeader( rIn, aHd );
    sal_Unicode nTemp, cData[ 32 ];
    rIn.ReadBytes(cData, 64);
 
    sal_uInt8   lfCharset, lfPitchAndFamily;
 
    rIn.ReadUChar( lfCharset )
       .ReadUChar( rAtom.lfClipPrecision )
       .ReadUChar( rAtom.lfQuality )
       .ReadUChar( lfPitchAndFamily );
 
    switch( lfCharset )
    {
        case SYMBOL_CHARSET :
            rAtom.eCharSet = RTL_TEXTENCODING_SYMBOL;
        break;
        case ANSI_CHARSET :
            rAtom.eCharSet = RTL_TEXTENCODING_MS_1252;
        break;
 
        default :
            rAtom.eCharSet = osl_getThreadTextEncoding();
    }
    switch ( lfPitchAndFamily & 0xf0 )
    {
        case FF_ROMAN:
            rAtom.eFamily = FAMILY_ROMAN;
        break;
 
        case FF_SWISS:
            rAtom.eFamily = FAMILY_SWISS;
        break;
 
        case FF_MODERN:
            rAtom.eFamily = FAMILY_MODERN;
        break;
 
        case FF_SCRIPT:
            rAtom.eFamily = FAMILY_SCRIPT;
        break;
 
        case FF_DECORATIVE:
             rAtom.eFamily = FAMILY_DECORATIVE;
        break;
 
        default:
            rAtom.eFamily = FAMILY_DONTKNOW;
        break;
    }
 
    switch ( lfPitchAndFamily & 0x0f )
    {
        case FIXED_PITCH:
            rAtom.ePitch = PITCH_FIXED;
        break;
 
        case DEFAULT_PITCH:
        case VARIABLE_PITCH:
        default:
            rAtom.ePitch = PITCH_VARIABLE;
        break;
    }
    sal_uInt16 i;
    for ( i = 0; i < 32; i++ )
    {
        nTemp = cData[ i ];
        if ( !nTemp )
            break;
#ifdef OSL_BIGENDIAN
        cData[ i ] = ( nTemp >> 8 ) | ( nTemp << 8 );
#endif
    }
    rAtom.aName = OUString(cData, i);
    OutputDevice* pDev = Application::GetDefaultDevice();
    rAtom.bAvailable = pDev->IsFontAvailable( rAtom.aName );
    aHd.SeekToEndOfRecord( rIn );
    return rIn;
}
 
SvStream& ReadPptUserEditAtom( SvStream& rIn, PptUserEditAtom& rAtom )
{
    sal_Int16 lastViewType = 0;
    ReadDffRecordHeader( rIn, rAtom.aHd );
    rIn
       .ReadInt32( rAtom.nLastSlideID )
       .ReadUInt32( rAtom.nVersion )
       .ReadUInt32( rAtom.nOffsetLastEdit )
       .ReadUInt32( rAtom.nOffsetPersistDirectory )
       .ReadUInt32( rAtom.nDocumentRef )
       .ReadUInt32( rAtom.nMaxPersistWritten )
       .ReadInt16( lastViewType );
    rAtom.eLastViewType = static_cast<PptViewTypeEnum>(lastViewType);
    rAtom.aHd.SeekToEndOfRecord(rIn);
    return rIn;
}
 
void PptOEPlaceholderAtom::Clear()
{
    nPlacementId = 0;
    nPlaceholderSize = 0;
    nPlaceholderId = PptPlaceholder::NONE;
}
 
SvStream& ReadPptOEPlaceholderAtom( SvStream& rIn, PptOEPlaceholderAtom& rAtom )
{
    rIn.ReadUInt32( rAtom.nPlacementId );
    sal_uInt8 nTmp(0);
    rIn.ReadUChar(nTmp);
    rAtom.nPlaceholderId = static_cast<PptPlaceholder>(nTmp);
    rIn.ReadUChar( rAtom.nPlaceholderSize );
    return rIn;
}
 
PptSlidePersistEntry::PptSlidePersistEntry() :
    nSlidePersistStartOffset( 0 ),
    nSlidePersistEndOffset  ( 0 ),
    nBackgroundOffset       ( 0 ),
    nDrawingDgId            ( 0xffffffff ),
    ePageKind               ( PPT_MASTERPAGE ),
    bNotesMaster            ( false ),
    bHandoutMaster          ( false ),
    bStarDrawFiller         ( false )
{
    HeaderFooterOfs[ 0 ] =  HeaderFooterOfs[ 1 ] = HeaderFooterOfs[ 2 ] = HeaderFooterOfs[ 3 ] = 0;
}
 
PptSlidePersistEntry::~PptSlidePersistEntry()
{
}
 
SdrEscherImport::SdrEscherImport( PowerPointImportParam& rParam, const OUString& rBaseURL ) :
    SvxMSDffManager         ( rParam.rDocStream, rBaseURL ),
    nStreamLen              ( 0 ),
    rImportParam            ( rParam )
{
}
 
SdrEscherImport::~SdrEscherImport()
{
}
 
const PptSlideLayoutAtom* SdrEscherImport::GetSlideLayoutAtom() const
{
    return nullptr;
}
 
bool SdrEscherImport::ReadString( OUString& rStr ) const
{
    bool bRet = false;
    DffRecordHeader aStrHd;
    ReadDffRecordHeader( rStCtrl, aStrHd );
    if (aStrHd.nRecType == PPT_PST_TextBytesAtom
        || aStrHd.nRecType == PPT_PST_TextCharsAtom
        || aStrHd.nRecType == PPT_PST_CString)
    {
        bool bUniCode =
            (aStrHd.nRecType == PPT_PST_TextCharsAtom
            || aStrHd.nRecType == PPT_PST_CString);
        sal_uLong nBytes = aStrHd.nRecLen;
        rStr = MSDFFReadZString( rStCtrl, nBytes, bUniCode );
        bRet = aStrHd.SeekToEndOfRecord( rStCtrl );
    }
    else
        aStrHd.SeekToBegOfRecord( rStCtrl );
    return bRet;
}
 
bool SdrEscherImport::GetColorFromPalette(sal_uInt16 /*nNum*/, Color& /*rColor*/) const
{
    return false;
}
 
bool SdrEscherImport::SeekToShape( SvStream& /*rSt*/, SvxMSDffClientData* /*pClientData*/, sal_uInt32 /*nId*/) const
{
    return false;
}
 
const PptFontEntityAtom* SdrEscherImport::GetFontEnityAtom( sal_uInt32 nNum ) const
{
    if (m_xFonts && nNum < m_xFonts->size())
        return &(*m_xFonts)[ nNum ];
    return nullptr;
}
 
SdrObject* SdrEscherImport::ReadObjText( PPTTextObj* /*pTextObj*/, SdrObject* pObj, SdPageCapsule /*pPage*/) const
{
    return pObj;
}
 
void SdrEscherImport::ProcessClientAnchor2( SvStream& rSt, DffRecordHeader& rHd, DffObjData& rObj )
{
    sal_Int32 l, t, r, b;
    if ( rHd.nRecLen == 16 )
    {
        rSt.ReadInt32( l ).ReadInt32( t ).ReadInt32( r ).ReadInt32( b );
    }
    else
    {
        sal_Int16 ls, ts, rs, bs;
        rSt.ReadInt16( ts ).ReadInt16( ls ).ReadInt16( rs ).ReadInt16( bs ); // the order of coordinates is a bit strange...
        l = ls;
        t = ts;
        r = rs;
        b = bs;
    }
    if (!rSt.good())
    {
        SAL_WARN("filter.ms", "ProcessClientAnchor2: short read");
        return;
    }
    Scale( l );
    Scale( t );
    Scale( r );
    Scale( b );
    rObj.aChildAnchor = tools::Rectangle( l, t, r, b );
    rObj.bChildAnchor = true;
};
 
void SdrEscherImport::RecolorGraphic( SvStream& rSt, sal_uInt32 nRecLen, Graphic& rGraphic )
{
    if ( rGraphic.GetType() != GraphicType::GdiMetafile )
        return;
 
    sal_uInt16 nX, nGlobalColorsCount, nFillColorsCount;
 
    rSt.ReadUInt16( nX )
       .ReadUInt16( nGlobalColorsCount )
       .ReadUInt16( nFillColorsCount )
       .ReadUInt16( nX )
       .ReadUInt16( nX )
       .ReadUInt16( nX );
 
    if ( ( nGlobalColorsCount > 64 ) || ( nFillColorsCount > 64 ) )
        return;
 
    if ( static_cast<sal_uInt32>( ( nGlobalColorsCount + nFillColorsCount ) * 44 + 12 ) != nRecLen )
        return;
 
    sal_uInt32 OriginalGlobalColors[ 64 ];
    sal_uInt32 NewGlobalColors[ 64 ];
 
    sal_uInt32 i, j, nGlobalColorsChanged, nFillColorsChanged;
    nGlobalColorsChanged = nFillColorsChanged = 0;
 
    sal_uInt32* pCurrentOriginal = OriginalGlobalColors;
    sal_uInt32* pCurrentNew = NewGlobalColors;
    sal_uInt32* pCount = &nGlobalColorsChanged;
    i = nGlobalColorsCount;
 
    for ( j = 0; j < 2; j++ )
    {
        for ( ; i > 0; i-- )
        {
            sal_uInt64 nPos = rSt.Tell();
            sal_uInt16 nChanged;
            rSt.ReadUInt16( nChanged );
            if ( nChanged & 1 )
            {
                sal_uInt8  nDummy, nRed, nGreen, nBlue;
                sal_uInt32 nColor = 0;
                sal_uInt32 nIndex;
                rSt.ReadUChar( nDummy )
                   .ReadUChar( nRed )
                   .ReadUChar( nDummy )
                   .ReadUChar( nGreen )
                   .ReadUChar( nDummy )
                   .ReadUChar( nBlue )
                   .ReadUInt32( nIndex );
 
                if ( nIndex < 8 )
                {
                    Color aColor = MSO_CLR_ToColor( nIndex << 24 );
                    nRed = aColor.GetRed();
                    nGreen = aColor.GetGreen();
                    nBlue = aColor.GetBlue();
                }
                nColor = nRed | ( nGreen << 8 ) | ( nBlue << 16 );
                *pCurrentNew++ = nColor;
                rSt.ReadUChar( nDummy )
                   .ReadUChar( nRed )
                   .ReadUChar( nDummy )
                   .ReadUChar( nGreen )
                   .ReadUChar( nDummy )
                   .ReadUChar( nBlue );
                nColor = nRed | ( nGreen << 8 ) | ( nBlue << 16 );
                *pCurrentOriginal++ = nColor;
                (*pCount)++;
            }
            rSt.Seek( nPos + 44 );
        }
        pCount = &nFillColorsChanged;
        i = nFillColorsCount;
    }
    if ( !(nGlobalColorsChanged || nFillColorsChanged) )
        return;
 
    std::unique_ptr<Color[]> pSearchColors(new Color[ nGlobalColorsChanged ]);
    std::unique_ptr<Color[]> pReplaceColors(new Color[ nGlobalColorsChanged ]);
 
    for ( j = 0; j < nGlobalColorsChanged; j++ )
    {
        sal_uInt32 nSearch = OriginalGlobalColors[ j ];
        sal_uInt32 nReplace = NewGlobalColors[ j ];
 
        pSearchColors[ j ].SetRed( static_cast<sal_uInt8>(nSearch) );
        pSearchColors[ j ].SetGreen( static_cast<sal_uInt8>( nSearch >> 8 ) );
        pSearchColors[ j ].SetBlue( static_cast<sal_uInt8>( nSearch >> 16 ) );
 
        pReplaceColors[ j ].SetRed( static_cast<sal_uInt8>(nReplace) );
        pReplaceColors[ j ].SetGreen( static_cast<sal_uInt8>( nReplace >> 8 ) );
        pReplaceColors[ j ].SetBlue( static_cast<sal_uInt8>( nReplace >> 16 ) );
    }
    GDIMetaFile aGdiMetaFile( rGraphic.GetGDIMetaFile() );
    aGdiMetaFile.ReplaceColors( pSearchColors.get(), pReplaceColors.get(),
        nGlobalColorsChanged );
    rGraphic = aGdiMetaFile;
}
 
sal_uLong DffPropSet::SanitizeEndPos(SvStream &rIn, sal_uLong nEndRecPos)
{
    auto nStreamLen = rIn.Tell() + rIn.remainingSize();
    if (nEndRecPos > nStreamLen)
    {
        SAL_WARN("filter.ms", "Parsing error: " << nStreamLen <<
                 " max end pos, but " << nEndRecPos << " claimed, truncating");
        nEndRecPos = nStreamLen;
    }
    return nEndRecPos;
}
 
void ProcessData::NotifyFreeObj(SdrObject* pObj)
{
    if (rPersistEntry.xSolverContainer)
    {
        for (auto & pPtr : rPersistEntry.xSolverContainer->aCList)
        {
            if (pPtr->pAObj == pObj)
                pPtr->pAObj = nullptr;
            if (pPtr->pBObj == pObj)
                pPtr->pBObj = nullptr;
            if (pPtr->pCObj == pObj)
                pPtr->pCObj = nullptr;
        }
    }
}
 
/* ProcessObject is called from ImplSdPPTImport::ProcessObj to handle all application specific things,
   such as the import of text, animation effects, header footer and placeholder.
 
   The parameter pOriginalObj is the object as it was imported by our general escher import, it must either
   be deleted or it can be returned to be inserted into the sdr page.
*/
rtl::Reference<SdrObject> SdrEscherImport::ProcessObj( SvStream& rSt, DffObjData& rObjData, SvxMSDffClientData& rClientData, tools::Rectangle& rTextRect, SdrObject* pOriginalObj )
{
    if ( dynamic_cast<const SdrObjCustomShape* >(pOriginalObj) !=  nullptr )
        pOriginalObj->SetMergedItem( SdrTextFixedCellHeightItem( true ) );
 
    // we are initializing our return value with the object that was imported by our escher import
    rtl::Reference<SdrObject> pRet = pOriginalObj;
 
    ProcessData& rData = static_cast<ProcessData&>(rClientData);
    PptSlidePersistEntry& rPersistEntry = rData.rPersistEntry;
 
    if ( ! (rObjData.nSpFlags & ShapeFlag::Group) )     // sj: #114758# ...
    {
        PptOEPlaceholderAtom aPlaceholderAtom;
 
        if ( maShapeRecords.SeekToContent( rSt, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) )
        {
            sal_Int16 nHeaderFooterInstance = -1;
            DffRecordHeader aClientDataHd;
            auto nEndRecPos = SanitizeEndPos(rSt, maShapeRecords.Current()->GetRecEndFilePos());
            while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nEndRecPos ) )
            {
                ReadDffRecordHeader( rSt, aClientDataHd );
                switch ( aClientDataHd.nRecType )
                {
                    // importing header/footer object from master page
                    case PPT_PST_OEPlaceholderAtom :
                    {
                        ReadPptOEPlaceholderAtom( rSt, aPlaceholderAtom );
                        if ( nHeaderFooterInstance == -1 )
                        {
                            switch ( aPlaceholderAtom.nPlaceholderId )
                            {
                                case PptPlaceholder::MASTERSLIDENUMBER :    nHeaderFooterInstance++;
                                    [[fallthrough]];
                                case PptPlaceholder::MASTERFOOTER :         nHeaderFooterInstance++;
                                    [[fallthrough]];
                                case PptPlaceholder::MASTERHEADER :         nHeaderFooterInstance++;
                                    [[fallthrough]];
                                case PptPlaceholder::MASTERDATE :           nHeaderFooterInstance++; break;
                                default: break;
 
                            }
                            if ( ! ( nHeaderFooterInstance & 0xfffc ) )     // is this a valid instance ( 0->3 )
                                rPersistEntry.HeaderFooterOfs[ nHeaderFooterInstance ] = rObjData.rSpHd.GetRecBegFilePos();
                        }
                    }
                    break;
 
                    case PPT_PST_RecolorInfoAtom :
                    {
                        if ( auto pSdrGrafObj = dynamic_cast<SdrGrafObj* >(pRet.get()) )
                            if ( pSdrGrafObj->HasGDIMetaFile() )
                            {
                                Graphic aGraphic( pSdrGrafObj->GetGraphic() );
                                RecolorGraphic( rSt, aClientDataHd.nRecLen, aGraphic );
                                pSdrGrafObj->SetGraphic( aGraphic );
                            }
                    }
                    break;
                }
                if (!aClientDataHd.SeekToEndOfRecord(rSt))
                    break;
            }
        }
        if ( ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::NOTESSLIDEIMAGE ) && !rPersistEntry.bNotesMaster )
        {
            sal_uInt16 nPageNum = pSdrModel->GetPageCount();
            if ( nPageNum > 0 )
                nPageNum--;
 
            // replacing the object which we will return with a SdrPageObj
            pRet = new SdrPageObj(
                *pSdrModel,
                rObjData.aBoundRect,
                pSdrModel->GetPage(nPageNum - 1));
        }
        else
        {
            // try to load some ppt text
            PPTTextObj aTextObj( rSt, static_cast<SdrPowerPointImport&>(*this), rPersistEntry, &rObjData );
            if ( aTextObj.Count() || aTextObj.GetOEPlaceHolderAtom() )
            {
                bool bVerticalText = false;
                // and if the text object is not empty, it must be applied to pRet, the object we
                // initially got from our escher import
                Degree100 nTextRotationAngle(0);
                if ( IsProperty( DFF_Prop_txflTextFlow ) )
                {
                    auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
                    switch( eTextFlow )
                    {
                        case mso_txflBtoT :                     // Bottom to Top non-@
                            nTextRotationAngle += 9000_deg100;
                        break;
                        case mso_txflTtoBA :    /* #68110# */   // Top to Bottom @-font
                        case mso_txflTtoBN :                    // Top to Bottom non-@
                        case mso_txflVertN :                    // Vertical, non-@, top to bottom
                            bVerticalText = !bVerticalText;     // nTextRotationAngle += 27000;
                        break;
    //                  case mso_txflHorzN :                    // Horizontal non-@, normal
    //                  case mso_txflHorzA :                    // Horizontal @-font, normal
                        default: break;
                    }
                }
                sal_Int32 nFontDirection = GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 );
                if ( ( nFontDirection == 1 ) || ( nFontDirection == 3 ) )
                {
                    bVerticalText = !bVerticalText;
                }
                const bool bFail = o3tl::checked_multiply<sal_Int32>(nFontDirection, 9000, nFontDirection);
                if (!bFail)
                    nTextRotationAngle -= Degree100(nFontDirection);
                else
                    SAL_WARN("filter.ms", "Parsing error: bad fontdirection: " << nFontDirection);
                aTextObj.SetVertical( bVerticalText );
                if ( pRet )
                {
                    bool bDeleteSource = aTextObj.GetOEPlaceHolderAtom().has_value();
                    if ( bDeleteSource  && dynamic_cast<const SdrGrafObj* >(pRet.get()) ==  nullptr     // we are not allowed to get
                            && dynamic_cast<const SdrObjGroup* >(pRet.get()) ==  nullptr                // grouped placeholder objects
                                && dynamic_cast<const SdrOle2Obj* >(pRet.get()) ==  nullptr )
                    {
                        pRet = nullptr;
                    }
                }
                sal_uInt32 nTextFlags = aTextObj.GetTextFlags();
                sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 25 * 3600 );   // 0.25 cm (emu)
                sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 25 * 3600 ); // 0.25 cm (emu)
                sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 13 * 3600 );     // 0.13 cm (emu)
                sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 13 * 3600 );
                ScaleEmu( nTextLeft );
                ScaleEmu( nTextRight );
                ScaleEmu( nTextTop );
                ScaleEmu( nTextBottom );
 
                sal_Int32   nMinFrameWidth = 0;
                sal_Int32   nMinFrameHeight = 0;
                bool    bAutoGrowWidth, bAutoGrowHeight;
 
                SdrTextVertAdjust eTVA;
                SdrTextHorzAdjust eTHA;
 
                nTextFlags &= PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT   | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT
                            | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK;
 
                if ( bVerticalText )
                {
                    eTVA = SDRTEXTVERTADJUST_BLOCK;
                    eTHA = SDRTEXTHORZADJUST_CENTER;
 
                    // read text anchor
                    auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop);
 
                    switch( eTextAnchor )
                    {
                        case mso_anchorTop:
                        case mso_anchorTopCentered:
                        case mso_anchorTopBaseline:
                        case mso_anchorTopCenteredBaseline:
                            eTHA = SDRTEXTHORZADJUST_RIGHT;
                        break;
 
                        case mso_anchorMiddle :
                        case mso_anchorMiddleCentered:
                            eTHA = SDRTEXTHORZADJUST_CENTER;
                        break;
 
                        case mso_anchorBottom:
                        case mso_anchorBottomCentered:
                        case mso_anchorBottomBaseline:
                        case mso_anchorBottomCenteredBaseline:
                            eTHA = SDRTEXTHORZADJUST_LEFT;
                        break;
                    }
                    switch ( eTextAnchor )
                    {
                        case mso_anchorTopCentered :
                        case mso_anchorMiddleCentered :
                        case mso_anchorBottomCentered :
                        case mso_anchorTopCenteredBaseline:
                        case mso_anchorBottomCenteredBaseline:
                        {
                            // check if it is sensible to use the centered alignment
                            const sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK;
                            switch (nTextFlags & nMask)
                            {
                            case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT:
                            case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER:
                            case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT:
                            case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK:
                                eTVA = SDRTEXTVERTADJUST_CENTER;    // If the textobject has only one type of alignment, then the text has not to be displayed using the full width;
                                break;
                            }
                            break;
                        }
                        default:
                            break;
                    }
                    nMinFrameWidth = rTextRect.GetWidth() - ( nTextLeft + nTextRight );
                }
                else
                {
                    eTVA = SDRTEXTVERTADJUST_CENTER;
                    eTHA = SDRTEXTHORZADJUST_BLOCK;
 
                    // read text anchor
                    auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop);
 
                    switch( eTextAnchor )
                    {
                        case mso_anchorTop:
                        case mso_anchorTopCentered:
                        case mso_anchorTopBaseline:
                        case mso_anchorTopCenteredBaseline:
                            eTVA = SDRTEXTVERTADJUST_TOP;
                        break;
 
                        case mso_anchorMiddle :
                        case mso_anchorMiddleCentered:
                            eTVA = SDRTEXTVERTADJUST_CENTER;
                        break;
 
                        case mso_anchorBottom:
                        case mso_anchorBottomCentered:
                        case mso_anchorBottomBaseline:
                        case mso_anchorBottomCenteredBaseline:
                            eTVA = SDRTEXTVERTADJUST_BOTTOM;
                        break;
                    }
                    switch ( eTextAnchor )
                    {
                        case mso_anchorTopCentered :
                        case mso_anchorMiddleCentered :
                        case mso_anchorBottomCentered :
                        case mso_anchorTopCenteredBaseline:
                        case mso_anchorBottomCenteredBaseline:
                        {
                            // check if it is sensible to use the centered alignment
                            const sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK;
                            switch (nTextFlags & nMask)
                            {
                            case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT:
                            case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER:
                            case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT:
                            case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK:
                                eTHA = SDRTEXTHORZADJUST_CENTER;    // If the textobject has only one type of alignment, then the text has not to be displayed using the full width;
                                break;
                            }
                            break;
                        }
                        default:
                            break;
                    }
                    nMinFrameHeight = rTextRect.GetHeight() - ( nTextTop + nTextBottom );
                }
 
                SdrObjKind eTextKind = SdrObjKind::Rectangle;
                if ( ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::NOTESSLIDEIMAGE )
                    || ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::MASTERNOTESSLIDEIMAGE ) )
                {
                    aTextObj.SetInstance( TSS_Type::Notes );
                    eTextKind = SdrObjKind::TitleText;
                }
                else if ( ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::MASTERNOTESBODYIMAGE )
                    || ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::NOTESBODY ) )
                {
                    aTextObj.SetInstance( TSS_Type::Notes );
                    eTextKind = SdrObjKind::Text;
                }
 
                TSS_Type nDestinationInstance = aTextObj.GetInstance();
                if ( rPersistEntry.ePageKind == PPT_MASTERPAGE )
                {
                    if ( !rPersistEntry.pPresentationObjects )
                    {
                        rPersistEntry.pPresentationObjects.reset( new sal_uInt32[ PPT_STYLESHEETENTRIES ] );
                        memset( rPersistEntry.pPresentationObjects.get(), 0, PPT_STYLESHEETENTRIES * 4 );
                    }
                    if ( !rPersistEntry.pPresentationObjects[ static_cast<int>(nDestinationInstance) ] )
                        rPersistEntry.pPresentationObjects[ static_cast<int>(nDestinationInstance) ] = rObjData.rSpHd.GetRecBegFilePos();
                }
                switch ( nDestinationInstance )
                {
                    case TSS_Type::PageTitle :
                    case TSS_Type::Title :
                    {
                        if ( GetSlideLayoutAtom()->eLayout == PptSlideLayout::TITLEMASTERSLIDE )
                            nDestinationInstance = TSS_Type::Title;
                        else
                            nDestinationInstance = TSS_Type::PageTitle;
                    }
                    break;
                    case TSS_Type::Body :
                    case TSS_Type::HalfBody :
                    case TSS_Type::QuarterBody :
                        nDestinationInstance = TSS_Type::Body;
                    break;
                    default: break;
                }
                aTextObj.SetDestinationInstance( nDestinationInstance );
 
                bool bAutoFit = false; // auto-scale text into shape box
                switch ( aTextObj.GetInstance() )
                {
                    case TSS_Type::PageTitle :
                    case TSS_Type::Title : eTextKind = SdrObjKind::TitleText; break;
                    case TSS_Type::Subtitle : eTextKind = SdrObjKind::Text; break;
                    case TSS_Type::Body :
                    case TSS_Type::HalfBody :
                    case TSS_Type::QuarterBody : eTextKind = SdrObjKind::OutlineText; bAutoFit = true; break;
                    default: break;
                }
                if ( aTextObj.GetDestinationInstance() != TSS_Type::TextInShape )
                {
                    if ( !aTextObj.GetOEPlaceHolderAtom() || aTextObj.GetOEPlaceHolderAtom()->nPlaceholderId == PptPlaceholder::NONE )
                    {
                        aTextObj.SetDestinationInstance( TSS_Type::TextInShape );
                        eTextKind = SdrObjKind::Rectangle;
                    }
                }
                rtl::Reference<SdrObject> pTObj;
                bool bWordWrap = GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare) != mso_wrapNone;
                bool bFitShapeToText = ( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 2 ) != 0;
 
                if ( dynamic_cast<const SdrObjCustomShape* >(pRet.get()) !=  nullptr && ( eTextKind == SdrObjKind::Rectangle ) )
                {
                    bAutoGrowHeight = bFitShapeToText;
                    bAutoGrowWidth = !bWordWrap;
                    pTObj = pRet;
                    pRet = nullptr;
                }
                else
                {
                    if ( dynamic_cast<const SdrObjCustomShape* >(pRet.get()) !=  nullptr )
                    {
                        pRet = nullptr;
                    }
                    pTObj = new SdrRectObj(
                        *pSdrModel,
                        eTextKind != SdrObjKind::Rectangle ? eTextKind : SdrObjKind::Text);
                    SfxItemSet aSet( pSdrModel->GetItemPool() );
                    if ( !pRet )
                        ApplyAttributes( rSt, aSet, rObjData );
                    pTObj->SetMergedItemSet( aSet );
                    if ( pRet )
                    {
                        pTObj->SetMergedItem( XLineStyleItem( drawing::LineStyle_NONE ) );
                        pTObj->SetMergedItem( XFillStyleItem( drawing::FillStyle_NONE ) );
                    }
                    if ( bVerticalText )
                    {
                        bAutoGrowWidth = bFitShapeToText;
                        bAutoGrowHeight = false;
                    }
                    else
                    {
                        bAutoGrowWidth = false;
 
                        // #119885# re-activating bFitShapeToText here, could not find deeper explanations
                        // for it (it was from 2005). Keeping the old comment here for reference
                        // old comment: // bFitShapeToText; can't be used, because we cut the text if it is too height,
                        bAutoGrowHeight = bFitShapeToText;
                    }
                }
                pTObj->SetMergedItem( SvxFrameDirectionItem( bVerticalText ? SvxFrameDirection::Vertical_RL_TB : SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) );
 
                //Autofit text only if there is no auto grow height and width
                //See fdo#41245
                if (bAutoFit && !bAutoGrowHeight && !bAutoGrowWidth)
                {
                    pTObj->SetMergedItem( SdrTextFitToSizeTypeItem(drawing::TextFitToSizeType_AUTOFIT) );
                }
 
                if ( dynamic_cast<const SdrObjCustomShape* >(pTObj.get()) ==  nullptr )
                {
                    pTObj->SetMergedItem( makeSdrTextAutoGrowWidthItem( bAutoGrowWidth ) );
                    pTObj->SetMergedItem( makeSdrTextAutoGrowHeightItem( bAutoGrowHeight ) );
                }
                else
                {
                    pTObj->SetMergedItem( makeSdrTextWordWrapItem( bWordWrap ) );
                    pTObj->SetMergedItem( makeSdrTextAutoGrowHeightItem( bFitShapeToText ) );
                }
 
                pTObj->SetMergedItem( SdrTextVertAdjustItem( eTVA ) );
                pTObj->SetMergedItem( SdrTextHorzAdjustItem( eTHA ) );
 
                if ( nMinFrameHeight < 0 )
                    nMinFrameHeight = 0;
                if ( dynamic_cast<const SdrObjCustomShape* >(pTObj.get()) ==  nullptr )
                    pTObj->SetMergedItem( makeSdrTextMinFrameHeightItem( nMinFrameHeight ) );
 
                if ( nMinFrameWidth < 0 )
                    nMinFrameWidth = 0;
                if ( dynamic_cast<const SdrObjCustomShape* >(pTObj.get()) ==  nullptr )
                    pTObj->SetMergedItem( makeSdrTextMinFrameWidthItem( nMinFrameWidth ) );
 
                // set margins at the borders of the textbox
                pTObj->SetMergedItem( makeSdrTextLeftDistItem( nTextLeft ) );
                pTObj->SetMergedItem( makeSdrTextRightDistItem( nTextRight ) );
                pTObj->SetMergedItem( makeSdrTextUpperDistItem( nTextTop ) );
                pTObj->SetMergedItem( makeSdrTextLowerDistItem( nTextBottom ) );
                pTObj->SetMergedItem( SdrTextFixedCellHeightItem( true ) );
 
                if ( dynamic_cast<const SdrObjCustomShape* >(pTObj.get()) ==  nullptr )
                    pTObj->SetSnapRect( rTextRect );
                pTObj = ReadObjText( &aTextObj, pTObj.get(), rData.pPage );
 
                if ( pTObj )
                {
                    /* check if our new snaprect makes trouble,
                    because we do not display the ADJUST_BLOCK
                    properly if the textsize is bigger than the
                    snaprect of the object. Then we will use
                    ADJUST_CENTER instead of ADJUST_BLOCK.
                    */
                    if ( dynamic_cast<const SdrObjCustomShape* >(pTObj.get()) ==  nullptr && !bFitShapeToText && !bWordWrap )
                    {
                        SdrTextObj* pText = DynCastSdrTextObj( pTObj.get()  );
                        if ( pText )
                        {
                            if ( bVerticalText )
                            {
                                if ( eTVA == SDRTEXTVERTADJUST_BLOCK )
                                {
                                    Size aTextSize( pText->GetTextSize() );
                                    aTextSize.AdjustWidth(nTextLeft + nTextRight );
                                    aTextSize.AdjustHeight(nTextTop + nTextBottom );
                                    if ( rTextRect.GetHeight() < aTextSize.Height() )
                                        pTObj->SetMergedItem( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) );
                                }
                            }
                            else
                            {
                                if ( eTHA == SDRTEXTHORZADJUST_BLOCK )
                                {
                                    Size aTextSize( pText->GetTextSize() );
                                    aTextSize.AdjustWidth(nTextLeft + nTextRight );
                                    aTextSize.AdjustHeight(nTextTop + nTextBottom );
                                    if ( rTextRect.GetWidth() < aTextSize.Width() )
                                        pTObj->SetMergedItem( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_CENTER ) );
                                }
                            }
                        }
                    }
                    // rotate text with shape?
                    Degree100 nAngle = ( rObjData.nSpFlags & ShapeFlag::FlipV ) ? -mnFix16Angle : mnFix16Angle; // #72116# vertical flip -> rotate by using the other way
                    nAngle += nTextRotationAngle;
 
                    if ( dynamic_cast< const SdrObjCustomShape* >(pTObj.get()) ==  nullptr )
                    {
                        if ( rObjData.nSpFlags & ShapeFlag::FlipV )
                        {
                            pTObj->Rotate( rTextRect.Center(), 18000_deg100, 0.0, -1.0 );
                        }
                        if ( rObjData.nSpFlags & ShapeFlag::FlipH )
                            nAngle = 36000_deg100 - nAngle;
                        if ( nAngle )
                            pTObj->NbcRotate( rObjData.aBoundRect.Center(), nAngle );
                    }
                    if ( pRet )
                    {
                        rtl::Reference<SdrObject> pGroup = new SdrObjGroup(*pSdrModel);
                        pGroup->GetSubList()->NbcInsertObject( pRet.get() );
                        pGroup->GetSubList()->NbcInsertObject( pTObj.get() );
                        pRet = std::move(pGroup);
                    }
                    else
                        pRet = pTObj.get();
                }
            }
        }
    }
    else
    {
        if ( maShapeRecords.SeekToContent( rSt, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART ) )
        {
            maShapeRecords.Current()->SeekToBegOfRecord( rSt );
            DffPropertyReader aSecPropSet( *this );
            aSecPropSet.ReadPropSet( rSt, &rClientData );
            sal_Int32 nTableProperties = aSecPropSet.GetPropertyValue( DFF_Prop_tableProperties, 0 );
            if ( nTableProperties & 3 )
            {
                if ( aSecPropSet.SeekToContent( DFF_Prop_tableRowProperties, rSt ) )
                {
                    sal_Int16 i, nReadRowCount = 0;
                    rSt.ReadInt16( nReadRowCount ).ReadInt16( i ).ReadInt16( i );
                    if (nReadRowCount > 0)
                    {
                        const size_t nMinRecordSize = 4;
                        const size_t nMaxRecords = rSt.remainingSize() / nMinRecordSize;
 
                        auto nRowCount = o3tl::make_unsigned(nReadRowCount);
                        if (nRowCount > nMaxRecords)
                        {
                            SAL_WARN("filter.ms", "Parsing error: " << nMaxRecords <<
                                     " max possible entries, but " << nRowCount << " claimed, truncating");
                            nRowCount = nMaxRecords;
                        }
                        if (nRowCount > 0)
                        {
                            std::unique_ptr<sal_uInt32[]> pTableArry(new sal_uInt32[ nRowCount + 2 ]);
                            pTableArry[ 0 ] = nTableProperties;
                            pTableArry[ 1 ] = nRowCount;
                            for (decltype(nRowCount) nRow = 0; nRow < nRowCount; ++nRow)
                                rSt.ReadUInt32(pTableArry[nRow + 2]);
                            rData.pTableRowProperties = std::move(pTableArry);
                        }
                    }
                }
            }
        }
    }
    if ( pRet ) // sj: #i38501#, and taking care of connections to group objects
    {
        if ( rObjData.nSpFlags & ShapeFlag::Background )
        {
            pRet->NbcSetSnapRect( tools::Rectangle( Point(), rData.pPage.page->GetSize() ) );   // set size
        }
        if (rPersistEntry.xSolverContainer)
        {
            for (auto & pPtr : rPersistEntry.xSolverContainer->aCList)
            {
                if ( rObjData.nShapeId == pPtr->nShapeC )
                    pPtr->pCObj = pRet.get();
                else
                {
                    SdrObject* pConnectObj = pRet.get();
                    if ( pOriginalObj && dynamic_cast< const SdrObjGroup* >(pRet.get()) !=  nullptr )
                    {   /* check if the original object from the escherimport is part of the group object,
                        if this is the case, we will use the original object to connect to */
                        SdrObjListIter aIter( *pRet, SdrIterMode::DeepWithGroups );
                        while( aIter.IsMore() )
                        {
                            SdrObject* pPartObj = aIter.Next();
                            if ( pPartObj == pOriginalObj )
                            {
                                pConnectObj = pPartObj;
                                break;
                            }
                        }
                    }
                    if ( rObjData.nShapeId == pPtr->nShapeA )
                    {
                        pPtr->pAObj = pConnectObj;
                        pPtr->nSpFlagsA = rObjData.nSpFlags;
                    }
                    if ( rObjData.nShapeId == pPtr->nShapeB )
                    {
                        pPtr->pBObj = pConnectObj;
                        pPtr->nSpFlagsB = rObjData.nSpFlags;
                    }
                }
            }
        }
        if ( rPersistEntry.ePageKind == PPT_MASTERPAGE )
        {   // maybe the escher clusterlist is not correct, but we have to got the right page by using the
            // spMaster property, so we are patching the table
            if ( rPersistEntry.nDrawingDgId != 0xffffffff )
            {
                sal_uInt32 nSec = ( rObjData.nShapeId >> 10 ) - 1;
                if ( !maFidcls.empty() && ( nSec < mnIdClusters ) )
                    maFidcls[ nSec ].dgid = rPersistEntry.nDrawingDgId; // insert the correct drawing id;
            }
        }
    }
    return pRet;
}
 
SdrPowerPointImport::SdrPowerPointImport( PowerPointImportParam& rParam, const OUString& rBaseURL ) :
    SdrEscherImport     ( rParam, rBaseURL ),
    m_bOk                 ( rStCtrl.GetErrorCode() == ERRCODE_NONE ),
    m_nPersistPtrCnt      ( 0 ),
    m_pDefaultSheet       ( nullptr ),
    m_nCurrentPageNum     ( 0 ),
    m_nDocStreamPos       ( 0 ),
    m_nPageColorsNum      ( 0xFFFF ),
    m_ePageColorsKind     ( PPT_MASTERPAGE ),
    m_eCurrentPageKind    ( PPT_MASTERPAGE )
{
    if ( m_bOk )
    {
        nStreamLen = rStCtrl.TellEnd();
 
        // try to allocate the UserEditAtom via CurrentUserAtom
        sal_uInt32 nCurrentUserEdit = rParam.aCurrentUserAtom.nCurrentUserEdit;
        if (nCurrentUserEdit && checkSeek(rStCtrl, nCurrentUserEdit))
        {
            ReadPptUserEditAtom( rStCtrl, m_aUserEditAtom );
        }
        if ( !m_aUserEditAtom.nOffsetPersistDirectory )
        {   // if there is no UserEditAtom try to search the last one
 
            rStCtrl.Seek( 0 );
            DffRecordManager aPptRecManager;                            // contains all first level container and atoms
            aPptRecManager.Consume( rStCtrl, nStreamLen );
            DffRecordHeader* pHd;
            for ( pHd = aPptRecManager.Last(); pHd; pHd = aPptRecManager.Prev() )
            {
                if ( pHd->nRecType == PPT_PST_UserEditAtom )
                {
                    pHd->SeekToBegOfRecord( rStCtrl );
                    ReadPptUserEditAtom( rStCtrl, m_aUserEditAtom );
                    break;
                }
            }
            if ( !pHd )
                m_bOk = false;
        }
    }
    if ( rStCtrl.GetError() != ERRCODE_NONE )
        m_bOk = false;
 
    if ( m_bOk )
    {
        m_nPersistPtrCnt = m_aUserEditAtom.nMaxPersistWritten + 1;
        if ( ( m_nPersistPtrCnt >> 2 ) > nStreamLen )     // sj: at least m_nPersistPtrCnt is not allowed to be greater than filesize
            m_bOk = false;                                // (it should not be greater than the PPT_PST_PersistPtrIncrementalBlock, but
                                                        // we are reading this block later, so we do not have access yet)
 
        if ( m_bOk && ( m_nPersistPtrCnt < ( SAL_MAX_UINT32 / sizeof( sal_uInt32 ) ) -1 ) )
            m_pPersistPtr.reset( new (std::nothrow) sal_uInt32[ m_nPersistPtrCnt + 1 ] );
        if ( !m_pPersistPtr )
            m_bOk = false;
        if ( m_bOk )
        {
            memset( m_pPersistPtr.get(), 0x00, (m_nPersistPtrCnt+1) * sizeof(sal_uInt32) );
 
            // SJ: new search mechanism from bottom to top (Issue 21122)
            PptUserEditAtom aCurrentEditAtom( m_aUserEditAtom );
            sal_uInt32 nCurrentEditAtomStrmPos = aCurrentEditAtom.aHd.GetRecEndFilePos();
            while( nCurrentEditAtomStrmPos )
            {
                sal_uInt32 nPersistIncPos = aCurrentEditAtom.nOffsetPersistDirectory;
                if (nPersistIncPos && checkSeek(rStCtrl, nPersistIncPos))
                {
                    DffRecordHeader aPersistHd;
                    ReadDffRecordHeader( rStCtrl, aPersistHd );
                    if ( aPersistHd.nRecType == PPT_PST_PersistPtrIncrementalBlock )
                    {
                        sal_uLong nPibLen = aPersistHd.GetRecEndFilePos();
                        while (m_bOk && rStCtrl.good() && (rStCtrl.Tell() < nPibLen))
                        {
                            sal_uInt32 nOfs(0);
                            rStCtrl.ReadUInt32( nOfs );
                            sal_uInt32 nCnt = nOfs;
                            nOfs &= 0x000FFFFF;
                            nCnt >>= 20;
                            while (m_bOk && rStCtrl.good() && (nCnt > 0) && (nOfs <= m_nPersistPtrCnt))
                            {
                                sal_uInt32 nPt(0);
                                rStCtrl.ReadUInt32( nPt );
                                if ( !m_pPersistPtr[ nOfs ] )
                                {
                                    m_pPersistPtr[ nOfs ] = nPt;
                                    if ( m_pPersistPtr[ nOfs ] > nStreamLen )
                                    {
                                        m_bOk = false;
                                        OSL_FAIL("SdrPowerPointImport::Ctor(): Invalid Entry in Persist-Directory!");
                                    }
                                }
                                nCnt--;
                                nOfs++;
                            }
                            if ( m_bOk && nCnt > 0 )
                            {
                                OSL_FAIL("SdrPowerPointImport::Ctor(): Not all entries of Persist-Directory read!");
                                m_bOk = false;
                            }
                        }
                    }
                }
                nCurrentEditAtomStrmPos = aCurrentEditAtom.nOffsetLastEdit < nCurrentEditAtomStrmPos ? aCurrentEditAtom.nOffsetLastEdit : 0;
                if (nCurrentEditAtomStrmPos && checkSeek(rStCtrl, nCurrentEditAtomStrmPos))
                {
                    ReadPptUserEditAtom( rStCtrl, aCurrentEditAtom );
                }
            }
        }
    }
    if ( rStCtrl.GetError() != ERRCODE_NONE )
        m_bOk = false;
    if ( m_bOk )
    {   // check Document PersistEntry
        m_nDocStreamPos = m_aUserEditAtom.nDocumentRef;
        if ( m_nDocStreamPos > m_nPersistPtrCnt )
        {
            OSL_FAIL("SdrPowerPointImport::Ctor(): m_aUserEditAtom.nDocumentRef invalid!");
            m_bOk = false;
        }
    }
    if ( m_bOk )
    {   // check Document FilePos
        m_nDocStreamPos = m_pPersistPtr[ m_nDocStreamPos ];
        if ( m_nDocStreamPos >= nStreamLen )
        {
            OSL_FAIL("SdrPowerPointImport::Ctor(): m_nDocStreamPos >= nStreamLen!");
            m_bOk = false;
        }
    }
    if ( m_bOk )
    {
        rStCtrl.Seek( m_nDocStreamPos );
        aDocRecManager.Consume( rStCtrl );
 
        DffRecordHeader aDocHd;
        ReadDffRecordHeader( rStCtrl, aDocHd );
        // read DocumentAtom
        DffRecordHeader aDocAtomHd;
        ReadDffRecordHeader( rStCtrl, aDocAtomHd );
        if ( aDocHd.nRecType == PPT_PST_Document && aDocAtomHd.nRecType == PPT_PST_DocumentAtom )
        {
            aDocAtomHd.SeekToBegOfRecord( rStCtrl );
            ReadPptDocumentAtom( rStCtrl, aDocAtom );
        }
        else
            m_bOk = false;
 
        if ( m_bOk )
        {
            if (!m_xFonts)
                ReadFontCollection();
 
            // reading TxPF, TxSI
            PPTTextParagraphStyleAtomInterpreter    aTxPFStyle;
            PPTTextSpecInfoAtomInterpreter          aTxSIStyle; // styles (default language setting ... )
 
            DffRecordHeader* pEnvHd = aDocRecManager.GetRecordHeader( PPT_PST_Environment );
            if ( pEnvHd )
            {
                pEnvHd->SeekToContent( rStCtrl );
                DffRecordHeader aTxPFStyleRecHd;
                if ( SeekToRec( rStCtrl, PPT_PST_TxPFStyleAtom, pEnvHd->GetRecEndFilePos(), &aTxPFStyleRecHd ) )
                    aTxPFStyle.Read( rStCtrl, aTxPFStyleRecHd );
 
                pEnvHd->SeekToContent( rStCtrl );
                DffRecordHeader aTxSIStyleRecHd;
                if ( SeekToRec( rStCtrl, PPT_PST_TxSIStyleAtom, pEnvHd->GetRecEndFilePos(), &aTxSIStyleRecHd ) )
                {
                    aTxSIStyle.Read( rStCtrl, aTxSIStyleRecHd, PPT_PST_TxSIStyleAtom );
#ifdef DBG_UTIL
                    if ( !aTxSIStyle.bValid )
                    {
                        if (!(rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT ))
                        {
                            OSL_FAIL( "SdrTextSpecInfoAtomInterpreter::Ctor(): parsing error, this document needs to be analysed (SJ)" );
                        }
                    }
#endif
                }
            }
 
            // TODO:: PPT_PST_TxPFStyleAtom
 
            // read SlidePersists
            m_pMasterPages.reset( new PptSlidePersistList );
            m_pSlidePages.reset( new PptSlidePersistList );
            m_pNotePages.reset( new PptSlidePersistList );
 
            // now always creating the handout page, it will be the first in our masterpage list
            std::unique_ptr<PptSlidePersistEntry> pE(new PptSlidePersistEntry);
            pE->aPersistAtom.nPsrReference = aDocAtom.nHandoutMasterPersist;
            pE->bHandoutMaster = true;
            if ( !aDocAtom.nHandoutMasterPersist )
                pE->bStarDrawFiller = true;     // this is a dummy master page
            m_pMasterPages->insert(m_pMasterPages->begin(), std::move(pE));
 
            DffRecordHeader* pSlideListWithTextHd = aDocRecManager.GetRecordHeader( PPT_PST_SlideListWithText );
            PptSlidePersistEntry* pPreviousPersist = nullptr;
            DffRecordHeader* pSlideListHd = aDocRecManager.GetRecordHeader(PPT_PST_List);
            sal_uLong nPSTList = 0;
            if (pSlideListHd) nPSTList = pSlideListHd->GetRecBegFilePos();
            sal_uInt16 nRealPageNum = 0;
            // Normal PPT document has order of Master slides - Presentation slides - Note slides
            // for document with the order of Master slides - Note slides - Presentation slides
            // we need to swap the later two sections
            bool notePresentationSwap = false;
            for (sal_uInt16 nPageListNum = 0;
                 pSlideListWithTextHd && nPageListNum < 3; ++nPageListNum)
            {
                pSlideListWithTextHd->SeekToContent( rStCtrl );
                PptSlidePersistList* pPageList = nullptr;
                sal_uInt32 nSlideListWithTextHdEndOffset = pSlideListWithTextHd->GetRecEndFilePos();
                nRealPageNum = nPageListNum;
                while ( SeekToRec( rStCtrl, PPT_PST_SlidePersistAtom, nSlideListWithTextHdEndOffset ) )
                {
                    if ( pPreviousPersist )
                        pPreviousPersist->nSlidePersistEndOffset = rStCtrl.Tell();
                    std::unique_ptr<PptSlidePersistEntry> pE2(new PptSlidePersistEntry);
                    ReadPptSlidePersistAtom( rStCtrl, pE2->aPersistAtom );
                    pE2->nSlidePersistStartOffset = rStCtrl.Tell();
                    // Note/Presentation section swap
                    if (nPageListNum == 1 && pE2->nSlidePersistStartOffset < nPSTList)
                    {
                        notePresentationSwap = true;
                    }
                    if (notePresentationSwap)
                    {
                        if (nPageListNum == 1) nRealPageNum = 2;
                        else if (nPageListNum == 2) nRealPageNum = 1;
                    }
 
                    pE2->ePageKind = PptPageKind(nRealPageNum);
                    pPreviousPersist = pE2.get();
                    if (!pPageList)
                    {
                        pPageList = GetPageList(PptPageKind(nRealPageNum));
                    }
                    pPageList->push_back(std::move(pE2));
                }
                if ( pPreviousPersist )
                    pPreviousPersist->nSlidePersistEndOffset = nSlideListWithTextHdEndOffset;
                pSlideListWithTextHd = aDocRecManager.GetRecordHeader( PPT_PST_SlideListWithText, SEEK_FROM_CURRENT );
            }
 
            // we will ensure that there is at least one master page
            if (m_pMasterPages->size() == 1) // -> there is only a handout page available
            {
                std::unique_ptr<PptSlidePersistEntry> pE2(new PptSlidePersistEntry);
                pE2->bStarDrawFiller = true;            // this is a dummy master page
                m_pMasterPages->insert(m_pMasterPages->begin() + 1, std::move(pE2));
            }
 
            // now we will insert at least one notes master for each master page
            sal_uInt16 nMasterPage;
            sal_uInt16 nMasterPages = m_pMasterPages->size() - 1;
            for ( nMasterPage = 0; nMasterPage < nMasterPages; nMasterPage++ )
            {
                std::unique_ptr<PptSlidePersistEntry> pE2(new PptSlidePersistEntry);
                pE2->bNotesMaster = true;
                pE2->bStarDrawFiller = true;            // this is a dummy master page
                if ( !nMasterPage && aDocAtom.nNotesMasterPersist )
                {   // special treatment for the first notes master
                    pE2->aPersistAtom.nPsrReference = aDocAtom.nNotesMasterPersist;
                    pE2->bStarDrawFiller = false;   // this is a dummy master page
                }
                m_pMasterPages->insert(m_pMasterPages->begin() + ((nMasterPage + 1) << 1), std::move(pE2));
            }
 
            // read for each page the SlideAtom respectively the NotesAtom if it exists
            for (sal_uInt16 nPageListNum = 0; nPageListNum < 3; ++nPageListNum)
            {
                PptSlidePersistList* pPageList = GetPageList( PptPageKind( nPageListNum ) );
                for ( size_t nPageNum = 0; nPageNum < pPageList->size(); nPageNum++ )
                {
                    PptSlidePersistEntry& rE2 = (*pPageList)[ nPageNum ];
                    sal_uLong nPersist = rE2.aPersistAtom.nPsrReference;
                    if ( ( nPersist > 0 ) && ( nPersist < m_nPersistPtrCnt ) )
                    {
                        sal_uLong nFPos = m_pPersistPtr[ nPersist ];
                        if ( nFPos < nStreamLen )
                        {
                            rStCtrl.Seek( nFPos );
                            DffRecordHeader aSlideHd;
                            ReadDffRecordHeader( rStCtrl, aSlideHd );
                            if ( SeekToRec( rStCtrl, PPT_PST_SlideAtom, aSlideHd.GetRecEndFilePos() ) )
                                ReadPptSlideAtom( rStCtrl, rE2.aSlideAtom );
                            else if ( SeekToRec( rStCtrl, PPT_PST_NotesAtom, aSlideHd.GetRecEndFilePos() ) )
                                ReadPptNotesAtom( rStCtrl, rE2.aNotesAtom );
                            aSlideHd.SeekToContent( rStCtrl );
 
                            DffRecordHeader aPPTDrawingHd;
                            if ( SeekToRec( rStCtrl, PPT_PST_PPDrawing, aSlideHd.GetRecEndFilePos(), &aPPTDrawingHd ) )
                            {
                                DffRecordHeader aPPTDgContainer;
                                if ( SeekToRec( rStCtrl, DFF_msofbtDgContainer, aPPTDrawingHd.GetRecEndFilePos(), &aPPTDgContainer ) )
                                {
                                    if ( SeekToRec( rStCtrl, DFF_msofbtDg, aPPTDrawingHd.GetRecEndFilePos() ) )
                                    {
                                        DffRecordHeader aDgRecordHeader;
                                        ReadDffRecordHeader( rStCtrl, aDgRecordHeader );
                                        rE2.nDrawingDgId = aDgRecordHeader.nRecInstance;
                                        aDgRecordHeader.SeekToEndOfRecord( rStCtrl );
                                    }
                                    if ( SeekToRec( rStCtrl, DFF_msofbtSolverContainer, aPPTDgContainer.GetRecEndFilePos() ) )
                                    {
                                        rE2.xSolverContainer.reset(new SvxMSDffSolverContainer);
                                        ReadSvxMSDffSolverContainer(rStCtrl, *rE2.xSolverContainer);
                                    }
                                    aPPTDgContainer.SeekToBegOfRecord( rStCtrl );
                                    SetDgContainer( rStCtrl );  // set this, so that the escherimport is knowing of our drawings
                                }
                            }
                            // office xp is supporting more than one stylesheet
                            if ( ( rE2.ePageKind == PPT_MASTERPAGE ) && ( rE2.aSlideAtom.nMasterId == 0 ) && !rE2.bNotesMaster )
                            {
                                PPTTextSpecInfo aTxSI( 0 );
                                if ( aTxSIStyle.bValid && !aTxSIStyle.aList.empty() )
                                    aTxSI = aTxSIStyle.aList[ 0 ];
 
                                rE2.xStyleSheet = std::make_unique<PPTStyleSheet>(aSlideHd, rStCtrl, *this, aTxPFStyle, aTxSI);
                                m_pDefaultSheet = rE2.xStyleSheet.get();
                            }
                            if ( SeekToRec( rStCtrl, PPT_PST_ColorSchemeAtom, aSlideHd.GetRecEndFilePos() ) )
                                ReadPptColorSchemeAtom( rStCtrl, rE2.aColorScheme );
                            else
                            {
                                OSL_FAIL( "SdrPowerPointImport::Ctor(): could not get SlideColorScheme! (SJ)" );
                            }
                        }
                        else
                        {
                            OSL_FAIL("SdrPowerPointImport::Ctor(): Persist entry is flawed! (SJ)");
                        }
                    }
                }
            }
            DffRecordHeader* pHeadersFootersHd = aDocRecManager.GetRecordHeader( PPT_PST_HeadersFooters );
            if ( pHeadersFootersHd )
            {
                HeaderFooterEntry aNormalMaster, aNotesMaster;
                for ( ; pHeadersFootersHd; pHeadersFootersHd = aDocRecManager.GetRecordHeader( PPT_PST_HeadersFooters, SEEK_FROM_CURRENT ) )
                {
                    if ( pHeadersFootersHd->nRecInstance == 3 )         // normal master
                        ImportHeaderFooterContainer( *pHeadersFootersHd, aNormalMaster );
                    else if ( pHeadersFootersHd->nRecInstance == 4 )    // notes master
                        ImportHeaderFooterContainer( *pHeadersFootersHd, aNotesMaster );
                }
                for (size_t i = 0; i < m_pMasterPages->size(); i++)
                {
                    if ((*m_pMasterPages)[ i ].bNotesMaster)
                        (*m_pMasterPages)[ i ].xHeaderFooterEntry.reset(new HeaderFooterEntry(aNotesMaster));
                    else
                        (*m_pMasterPages)[ i ].xHeaderFooterEntry.reset(new HeaderFooterEntry(aNormalMaster));
                }
            }
        }
    }
    if ( ( rStCtrl.GetError() != ERRCODE_NONE ) || ( m_pDefaultSheet == nullptr ) )
        m_bOk = false;
    m_pPPTStyleSheet = m_pDefaultSheet;
    rStCtrl.Seek( 0 );
}
 
SdrPowerPointImport::~SdrPowerPointImport()
{
    m_pMasterPages.reset();
    m_pSlidePages.reset();
    m_pNotePages.reset();
}
 
bool PPTConvertOCXControls::ReadOCXStream( rtl::Reference<SotStorage>& rSrc,
        css::uno::Reference< css::drawing::XShape > *pShapeRef )
{
    bool bRes = false;
    uno::Reference< form::XFormComponent > xFComp;
    if ( mpPPTImporter && mpPPTImporter->ReadFormControl( rSrc, xFComp ) )
    {
        if ( xFComp.is() )
        {
            css::awt::Size aSz;  // not used in import
            bRes = InsertControl( xFComp, aSz,pShapeRef, false/*bFloatingCtrl*/);
        }
    }
    return bRes;
}
 
bool PPTConvertOCXControls::InsertControl(
        const css::uno::Reference< css::form::XFormComponent > &rFComp,
        const css::awt::Size& rSize,
        css::uno::Reference< css::drawing::XShape > *pShape,
        bool /*bFloatingCtrl*/)
{
    bool bRetValue = false;
    try
    {
        css::uno::Reference< css::drawing::XShape >  xShape;
 
        const css::uno::Reference< css::container::XIndexContainer > & rFormComps =
            GetFormComps();
 
        css::uno::Any aTmp( &rFComp, cppu::UnoType<css::form::XFormComponent>::get() );
 
        rFormComps->insertByIndex( rFormComps->getCount(), aTmp );
 
        const css::uno::Reference< css::lang::XMultiServiceFactory > & rServiceFactory =
            GetServiceFactory();
        if( rServiceFactory.is() )
        {
            css::uno::Reference< css::uno::XInterface >  xCreate = rServiceFactory
                ->createInstance( u"com.sun.star.drawing.ControlShape"_ustr );
            if( xCreate.is() )
            {
                xShape.set(xCreate, css::uno::UNO_QUERY);
                if ( xShape.is() )
                {
                    xShape->setSize(rSize);
                    // set the Control-Model at the Control-Shape
                    css::uno::Reference< css::drawing::XControlShape >  xControlShape( xShape,
                        css::uno::UNO_QUERY );
                    css::uno::Reference< css::awt::XControlModel >  xControlModel( rFComp,
                        css::uno::UNO_QUERY );
                    if ( xControlShape.is() && xControlModel.is() )
                    {
                        xControlShape->setControl( xControlModel );
                        if (pShape)
                            *pShape = std::move(xShape);
                        bRetValue = true;
                    }
                }
            }
        }
    }
    catch( ... )
    {
        bRetValue = false;
    }
    return bRetValue;
};
void PPTConvertOCXControls::GetDrawPage()
{
    if( xDrawPage.is() || !mxModel.is() )
        return;
 
    css::uno::Reference< css::drawing::XDrawPages > xDrawPages;
    switch( ePageKind )
    {
        case PPT_SLIDEPAGE :
        case PPT_NOTEPAGE :
        {
            css::uno::Reference< css::drawing::XDrawPagesSupplier >
                    xDrawPagesSupplier( mxModel, css::uno::UNO_QUERY);
            if ( xDrawPagesSupplier.is() )
                xDrawPages = xDrawPagesSupplier->getDrawPages();
        }
        break;
 
        case PPT_MASTERPAGE :
        {
            css::uno::Reference< css::drawing::XMasterPagesSupplier >
                    xMasterPagesSupplier( mxModel, css::uno::UNO_QUERY);
            if ( xMasterPagesSupplier.is() )
                xDrawPages = xMasterPagesSupplier->getMasterPages();
        }
        break;
    }
    if ( xDrawPages.is() && xDrawPages->getCount() )
    {
        xDrawPages->getCount();
        css::uno::Any aAny( xDrawPages->getByIndex( xDrawPages->getCount() - 1 ) );
        aAny >>= xDrawPage;
    }
}
 
static bool SdrPowerPointOLEDecompress( SvStream& rOutput, SvStream& rInput, sal_uInt32 nInputSize )
{
    sal_uInt64 nOldPos = rInput.Tell();
    std::unique_ptr<char[]> pBuf(new char[ nInputSize ]);
    rInput.ReadBytes(pBuf.get(), nInputSize);
    ZCodec aZCodec( 0x8000, 0x8000 );
    aZCodec.BeginCompression();
    SvMemoryStream aSource( pBuf.get(), nInputSize, StreamMode::READ );
    aZCodec.Decompress( aSource, rOutput );
    const bool bSuccess(0 != aZCodec.EndCompression());
    rInput.Seek( nOldPos );
    return bSuccess;
}
 
// #i32596# - add new parameter <_nCalledByGroup>
rtl::Reference<SdrObject> SdrPowerPointImport::ImportOLE( sal_uInt32 nOLEId,
                                           const Graphic& rGraf,
                                           const tools::Rectangle& rBoundRect,
                                           const tools::Rectangle& rVisArea,
                                           const int /*_nCalledByGroup*/ ) const
{
    rtl::Reference<SdrObject> pRet;
 
    sal_uInt64 nOldPos = rStCtrl.Tell();
 
    Graphic aGraphic( rGraf );
 
    if ( const_cast<SdrPowerPointImport*>(this)->maShapeRecords.SeekToContent( rStCtrl, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) )
    {
        DffRecordHeader aPlaceHd;
 
        auto nEndRecPos = SanitizeEndPos(rStCtrl, const_cast<SdrPowerPointImport*>(this)->maShapeRecords.Current()->GetRecEndFilePos());
        while ( ( rStCtrl.GetError() == ERRCODE_NONE )
            && ( rStCtrl.Tell() < nEndRecPos ) )
        {
            ReadDffRecordHeader( rStCtrl, aPlaceHd );
            if ( aPlaceHd.nRecType == PPT_PST_RecolorInfoAtom )
            {
                const_cast<SdrPowerPointImport*>(this)->RecolorGraphic( rStCtrl, aPlaceHd.nRecLen, aGraphic );
                break;
            }
            else
            {
                if (!aPlaceHd.SeekToEndOfRecord(rStCtrl))
                    break;
            }
        }
    }
 
    for (PPTOleEntry& rOe : const_cast<SdrPowerPointImport*>(this)->aOleObjectList)
    {
        if ( rOe.nId != nOLEId )
            continue;
 
        rStCtrl.Seek( rOe.nRecHdOfs );
 
        DffRecordHeader aHd;
        ReadDffRecordHeader( rStCtrl, aHd );
 
        sal_uInt32 nLen = aHd.nRecLen - 4;
        if ( static_cast<sal_Int32>(nLen) > 0 )
        {
            bool bSuccess = false;
 
            rStCtrl.SeekRel( 4 );
 
            ::utl::TempFileFast aTmpFile;
            SvStream* pDest = aTmpFile.GetStream(StreamMode::READWRITE);
            if (pDest)
            {
                bSuccess = SdrPowerPointOLEDecompress( *pDest, rStCtrl, nLen );
            }
            if ( bSuccess )
            {
                pDest->Seek(0);
                Storage* pObjStor = new Storage(*pDest, false);
                rtl::Reference<SotStorage> xObjStor(new SotStorage(pObjStor));
                if ( xObjStor.is() && !xObjStor->GetError() )
                {
                    if ( xObjStor->GetClassName() == SvGlobalName() )
                    {
                        xObjStor->SetClass( SvGlobalName( pObjStor->GetClassId() ), pObjStor->GetFormat(), pObjStor->GetUserName() );
                    }
                    rtl::Reference<SotStorageStream> xSrcTst = xObjStor->OpenSotStream(u"\1Ole"_ustr);
                    if ( xSrcTst.is() )
                    {
                        sal_uInt8 aTestA[ 10 ];
                        bool bGetItAsOle = (sizeof(aTestA) == xSrcTst->ReadBytes(aTestA, sizeof(aTestA)));
                        if ( !bGetItAsOle )
                        {   // maybe there is a contents stream in here
                            xSrcTst = xObjStor->OpenSotStream( u"Contents"_ustr, StreamMode::READWRITE | StreamMode::NOCREATE );
                            bGetItAsOle = (xSrcTst.is() &&
                                sizeof(aTestA) == xSrcTst->ReadBytes(aTestA, sizeof(aTestA)));
                        }
                        if ( bGetItAsOle )
                        {
                            OUString aNm;
                            // if ( nSvxMSDffOLEConvFlags )
                            {
                                uno::Reference < embed::XStorage > xDestStorage( rOe.pShell->GetStorage() );
                                uno::Reference < embed::XEmbeddedObject > xObj =
                                    CheckForConvertToSOObj(nSvxMSDffOLEConvFlags, *xObjStor, xDestStorage, rGraf, rVisArea, maBaseURL);
                                if( xObj.is() )
                                {
                                    rOe.pShell->getEmbeddedObjectContainer().InsertEmbeddedObject( xObj, aNm );
 
                                    svt::EmbeddedObjectRef aObj( xObj, rOe.nAspect );
 
                                    // TODO/LATER: need MediaType for Graphic
                                    aObj.SetGraphic( rGraf, OUString() );
                                    pRet = new SdrOle2Obj(
                                        *pSdrModel,
                                        aObj,
                                        aNm,
                                        rBoundRect);
                                }
                            }
                            if ( !pRet && ( rOe.nType == PPT_PST_ExControl ) )
                            {
                                uno::Reference< frame::XModel > xModel( rOe.pShell->GetModel() );
                                PPTConvertOCXControls aPPTConvertOCXControls( this, xModel, m_eCurrentPageKind );
                                css::uno::Reference< css::drawing::XShape > xShape;
                                if ( aPPTConvertOCXControls.ReadOCXStream( xObjStor, &xShape ) )
                                    pRet = SdrObject::getSdrObjectFromXShape(xShape);
 
                            }
                            if ( !pRet )
                            {
                                aNm = rOe.pShell->getEmbeddedObjectContainer().CreateUniqueObjectName();
 
                                // object is not an own object
                                const css::uno::Reference < css::embed::XStorage >& rStorage = rOe.pShell->GetStorage();
                                if (rStorage.is())
                                {
                                    rtl::Reference<SotStorage> xTarget = SotStorage::OpenOLEStorage(rStorage, aNm, StreamMode::READWRITE);
                                    if (xObjStor.is() && xTarget.is())
                                    {
                                        xObjStor->CopyTo(xTarget.get());
                                        if (!xTarget->GetError())
                                            xTarget->Commit();
                                    }
                                    xTarget.clear();
                                }
 
                                uno::Reference < embed::XEmbeddedObject > xObj =
                                    rOe.pShell->getEmbeddedObjectContainer().GetEmbeddedObject( aNm );
                                if ( xObj.is() )
                                {
                                    if ( rOe.nAspect != embed::Aspects::MSOLE_ICON )
                                    {
                                        //TODO/LATER: keep on hacking?!
                                        // we don't want to be modified
                                        //xInplaceObj->EnableSetModified( sal_False );
                                        if ( rVisArea.IsEmpty() )
                                        {
                                            MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( rOe.nAspect ) );
                                            Size aSize( OutputDevice::LogicToLogic( aGraphic.GetPrefSize(),
                                                aGraphic.GetPrefMapMode(), MapMode( aMapUnit ) ) );
 
                                            awt::Size aSz;
                                            aSz.Width = aSize.Width();
                                            aSz.Height = aSize.Height();
                                            xObj->setVisualAreaSize( rOe.nAspect, aSz );
                                        }
                                        else
                                        {
                                            awt::Size aSize( rVisArea.GetSize().Width(), rVisArea.GetSize().Height() );
                                            xObj->setVisualAreaSize( rOe.nAspect, aSize );
                                        }
                                        //xInplaceObj->EnableSetModified( sal_True );
                                    }
 
                                    svt::EmbeddedObjectRef aObj( xObj, rOe.nAspect );
 
                                    // TODO/LATER: need MediaType for Graphic
                                    aObj.SetGraphic( aGraphic, OUString() );
 
                                    pRet = new SdrOle2Obj(
                                        *pSdrModel,
                                        aObj,
                                        aNm,
                                        rBoundRect);
                                }
                            }
                        }
                    }
                }
            }
            aTmpFile.CloseStream();
        }
    }
    rStCtrl.Seek( nOldPos );
 
    return pRet;
}
 
std::unique_ptr<SvMemoryStream> SdrPowerPointImport::ImportExOleObjStg( sal_uInt32 nPersistPtr, sal_uInt32& nOleId ) const
{
    std::unique_ptr<SvMemoryStream> pRet;
    if ( nPersistPtr && ( nPersistPtr < m_nPersistPtrCnt ) )
    {
        sal_uInt32 nOldPos, nOfs = m_pPersistPtr[ nPersistPtr ];
        nOldPos = rStCtrl.Tell();
        rStCtrl.Seek( nOfs );
        DffRecordHeader aHd;
        ReadDffRecordHeader( rStCtrl, aHd );
        if ( aHd.nRecType == DFF_PST_ExOleObjStg )
        {
            sal_uInt32 nLen = aHd.nRecLen - 4;
            if ( static_cast<sal_Int32>(nLen) > 0 )
            {
                rStCtrl.ReadUInt32( nOleId );
                pRet.reset(new SvMemoryStream);
                ZCodec aZCodec( 0x8000, 0x8000 );
                aZCodec.BeginCompression();
                aZCodec.Decompress( rStCtrl, *pRet );
                if ( !aZCodec.EndCompression() )
                {
                    pRet.reset();
                }
            }
        }
        rStCtrl.Seek( nOldPos );
    }
    return pRet;
}
 
void SdrPowerPointImport::SeekOle( SfxObjectShell* pShell, sal_uInt32 nFilterOptions )
{
    if ( !pShell )
        return;
 
    DffRecordHeader*    pHd;
 
    sal_uInt64 nOldPos = rStCtrl.Tell();
    if ( nFilterOptions & 1 )
    {
        pHd = aDocRecManager.GetRecordHeader( PPT_PST_List );
        if ( pHd )
        {
            // we try to locate the basic atom
            pHd->SeekToContent( rStCtrl );
            if ( SeekToRec( rStCtrl, PPT_PST_VBAInfo, pHd->GetRecEndFilePos(), pHd ) )
            {
                if ( SeekToRec( rStCtrl, PPT_PST_VBAInfoAtom, pHd->GetRecEndFilePos(), pHd ) )
                {
                    sal_uInt32 nPersistPtr, nIDoNotKnow1, nIDoNotKnow2;
                    rStCtrl.ReadUInt32( nPersistPtr )
                           .ReadUInt32( nIDoNotKnow1 )
                           .ReadUInt32( nIDoNotKnow2 );
 
                    sal_uInt32 nOleId;
                    std::unique_ptr<SvMemoryStream> pBas = ImportExOleObjStg( nPersistPtr, nOleId );
                    if ( pBas )
                    {
                        rtl::Reference<SotStorage> xSource(new SotStorage(pBas.release(), true));
                        rtl::Reference<SotStorage> xDest( new SotStorage( new SvMemoryStream(), true ) );
                        if ( xSource.is() && xDest.is() )
                        {
                            // is this a visual basic storage ?
                            rtl::Reference<SotStorage> xSubStorage = xSource->OpenSotStorage( u"VBA"_ustr,
                                StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL );
                            if( xSubStorage.is() && ( ERRCODE_NONE == xSubStorage->GetError() ) )
                            {
                                rtl::Reference<SotStorage> xMacros = xDest->OpenSotStorage( u"MACROS"_ustr );
                                if ( xMacros.is() )
                                {
                                    SvStorageInfoList aList;
                                    xSource->FillInfoList( &aList );
                                    SvStorageInfoList::size_type i;
 
                                    bool bCopied = true;
                                    for ( i = 0; i < aList.size(); i++ )    // copy all entries
                                    {
                                        const SvStorageInfo& rInfo = aList[ i ];
                                        if ( !xSource->CopyTo( rInfo.GetName(), xMacros.get(), rInfo.GetName() ) )
                                            bCopied = false;
                                    }
                                    if ( i && bCopied )
                                    {
                                        uno::Reference < embed::XStorage > xDoc( pShell->GetStorage() );
                                        if ( xDoc.is() )
                                        {
                                            rtl::Reference<SotStorage> xVBA = SotStorage::OpenOLEStorage( xDoc, SvxImportMSVBasic::GetMSBasicStorageName() );
                                            if ( xVBA.is() && ( xVBA->GetError() == ERRCODE_NONE ) )
                                            {
                                                rtl::Reference<SotStorage> xSubVBA = xVBA->OpenSotStorage( u"_MS_VBA_Overhead"_ustr );
                                                if ( xSubVBA.is() && ( xSubVBA->GetError() == ERRCODE_NONE ) )
                                                {
                                                    rtl::Reference<SotStorageStream> xOriginal = xSubVBA->OpenSotStream( u"_MS_VBA_Overhead2"_ustr );
                                                    if ( xOriginal.is() && ( xOriginal->GetError() == ERRCODE_NONE ) )
                                                    {
                                                        if ( nPersistPtr && ( nPersistPtr < m_nPersistPtrCnt ) )
                                                        {
                                                            rStCtrl.Seek( m_pPersistPtr[ nPersistPtr ] );
                                                            ReadDffRecordHeader( rStCtrl, *pHd );
 
                                                            xOriginal->WriteUInt32( nIDoNotKnow1 )
                                                                      .WriteUInt32( nIDoNotKnow2 );
 
                                                            sal_uInt32 nToCopy, nBufSize;
                                                            nToCopy = pHd->nRecLen;
                                                            std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[ 0x40000 ]); // 256KB Buffer
                                                            while ( nToCopy )
                                                            {
                                                                nBufSize = ( nToCopy >= 0x40000 ) ? 0x40000 : nToCopy;
                                                                rStCtrl.ReadBytes(pBuf.get(), nBufSize);
                                                                xOriginal->WriteBytes(pBuf.get(), nBufSize);
                                                                nToCopy -= nBufSize;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            xVBA->Commit();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    pHd = aDocRecManager.GetRecordHeader( PPT_PST_ExObjList );
    if ( pHd )
    {
        DffRecordHeader*    pExEmbed = nullptr;
 
        pHd->SeekToBegOfRecord( rStCtrl );
        DffRecordManager aExObjListManager( rStCtrl );
        sal_uInt16 i, nRecType(PPT_PST_ExEmbed);
 
        for ( i = 0; i < 2; i++ )
        {
            switch ( i )
            {
                case 0 : nRecType = PPT_PST_ExEmbed; break;
                case 1 : nRecType = PPT_PST_ExControl; break;
            }
            for ( pExEmbed = aExObjListManager.GetRecordHeader( nRecType );
                    pExEmbed; pExEmbed = aExObjListManager.GetRecordHeader( nRecType, SEEK_FROM_CURRENT ) )
            {
                pExEmbed->SeekToContent( rStCtrl );
 
                DffRecordHeader aExOleAtHd;
                if ( SeekToRec( rStCtrl, PPT_PST_ExOleObjAtom, pExEmbed->GetRecEndFilePos(), &aExOleAtHd ) )
                {
                    PptExOleObjAtom aAt;
                    ReadPptExOleObjAtom( rStCtrl, aAt );
 
                    if ( aAt.nPersistPtr && ( aAt.nPersistPtr < m_nPersistPtrCnt ) )
                    {
                        rStCtrl.Seek( m_pPersistPtr[ aAt.nPersistPtr ] );
                        DffRecordHeader aHd;
                        ReadDffRecordHeader( rStCtrl, aHd );
                        if ( aHd.nRecType == DFF_PST_ExOleObjStg )
                        {
                            sal_uInt32 nId;
                            rStCtrl.ReadUInt32( nId );
                            aOleObjectList.emplace_back(
                                aAt.nId, aHd.nFilePos, pShell, nRecType, aAt.nAspect );
                        }
                    }
                }
            }
        }
    }
    rStCtrl.Seek( nOldPos );
}
 
bool SdrPowerPointImport::ReadFontCollection()
{
    bool bRet = false;
    DffRecordHeader* pEnvHd = aDocRecManager.GetRecordHeader( PPT_PST_Environment );
    if ( pEnvHd )
    {
        sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for restoring it later
        pEnvHd->SeekToContent( rStCtrl );
        DffRecordHeader aListHd;
        if ( SeekToRec( rStCtrl, PPT_PST_FontCollection, pEnvHd->GetRecEndFilePos(), &aListHd ) )
        {
            sal_uInt16 nCount2 = 0;
            while ( SeekToRec( rStCtrl, PPT_PST_FontEntityAtom, aListHd.GetRecEndFilePos() ) )
            {
                bRet = true;
                if (!m_xFonts)
                    m_xFonts.emplace();
                PptFontEntityAtom aFontAtom;
                ReadPptFontEntityAtom( rStCtrl, aFontAtom );
 
                vcl::Font aFont;
                aFont.SetCharSet( aFontAtom.eCharSet );
                aFont.SetFamilyName( aFontAtom.aName );
                aFont.SetFamily( aFontAtom.eFamily );
                aFont.SetPitch( aFontAtom.ePitch );
                aFont.SetFontHeight( 100 );
 
                // following block is necessary, because our old PowerPoint export did not set the
                // correct charset
                if ( aFontAtom.aName.equalsIgnoreAsciiCase( "Wingdings" ) ||
                     aFontAtom.aName.equalsIgnoreAsciiCase( "Wingdings 2" ) ||
                     aFontAtom.aName.equalsIgnoreAsciiCase( "Wingdings 3" ) ||
                     aFontAtom.aName.equalsIgnoreAsciiCase( "Monotype Sorts" ) ||
                     aFontAtom.aName.equalsIgnoreAsciiCase( "Monotype Sorts 2" ) ||
                     aFontAtom.aName.equalsIgnoreAsciiCase( "Webdings" ) ||
                     aFontAtom.aName.equalsIgnoreAsciiCase( "StarBats" ) ||
                     aFontAtom.aName.equalsIgnoreAsciiCase( "StarMath" ) ||
                     aFontAtom.aName.equalsIgnoreAsciiCase( "ZapfDingbats" ) )
                {
                    aFontAtom.eCharSet = RTL_TEXTENCODING_SYMBOL;
                };
                m_xFonts->insert(m_xFonts->begin() + nCount2++, std::move(aFontAtom));
            }
        }
        rStCtrl.Seek( nOldFPos ); // restore FilePos
    }
    return bRet;
}
 
PptSlidePersistList* SdrPowerPointImport::GetPageList(PptPageKind ePageKind) const
{
    switch (ePageKind)
    {
        case PPT_MASTERPAGE:
            return m_pMasterPages.get();
        case PPT_SLIDEPAGE:
            return m_pSlidePages.get();
        case PPT_NOTEPAGE:
            return m_pNotePages.get();
    }
    return nullptr;
}
 
SdrOutliner* SdrPowerPointImport::GetDrawOutliner( SdrTextObj const * pSdrText )
{
    if ( !pSdrText )
        return nullptr;
    else
        return &pSdrText->ImpGetDrawOutliner();
}
 
 
SdrObject* SdrPowerPointImport::ReadObjText( PPTTextObj* pTextObj, SdrObject* pSdrObj, SdPageCapsule pPage ) const
{
    SdrTextObj* pText = DynCastSdrTextObj( pSdrObj  );
    if ( pText )
    {
        if ( !ApplyTextObj( pTextObj, pText, pPage, nullptr, nullptr ) )
            pSdrObj = nullptr;
    }
    return pSdrObj;
}
 
SdrObject* SdrPowerPointImport::ApplyTextObj( PPTTextObj* pTextObj, SdrTextObj* pSdrText, SdPageCapsule /*pPage*/,
                                                SfxStyleSheet* pSheet, SfxStyleSheet** ppStyleSheetAry ) const
{
    SdrTextObj* pText = pSdrText;
    if ( pTextObj->Count() )
    {
        TSS_Type nDestinationInstance = pTextObj->GetDestinationInstance() ;
        SdrOutliner& rOutliner = pText->ImpGetDrawOutliner();
        bool bUndoEnabled = rOutliner.IsUndoEnabled();
        rOutliner.EnableUndo(false);
 
        if ( ( pText->GetObjInventor() == SdrInventor::Default ) && ( pText->GetObjIdentifier() == SdrObjKind::TitleText ) ) // Outliner-Style for Title-Text object?!? (->of DL)
            rOutliner.Init( OutlinerMode::TitleObject );             // Outliner reset
 
        bool bOldUpdateMode = rOutliner.SetUpdateLayout( false );
        if ( pSheet )
        {
            if ( rOutliner.GetStyleSheet( 0 ) != pSheet )
                rOutliner.SetStyleSheet( 0, pSheet );
        }
        rOutliner.SetVertical( pTextObj->GetVertical() );
        for ( PPTParagraphObj* pPara = pTextObj->First(); pPara; pPara = pTextObj->Next() )
        {
            sal_uInt32 nTextSize = pPara->GetTextSize();
            if ( ! ( nTextSize & 0xffff0000 ) )
            {
                PPTPortionObj* pPortion;
                std::unique_ptr<sal_Unicode[]> pParaText(new sal_Unicode[ nTextSize ]);
                sal_Int32 nCurrentIndex = 0;
                for ( pPortion = pPara->First(); pPortion; pPortion = pPara->Next() )
                {
                    if ( pPortion->mpFieldItem )
                        pParaText[ nCurrentIndex++ ] = ' ';
                    else
                    {
                        sal_Int32 nCharacters = pPortion->Count();
                        const sal_Unicode* pSource = pPortion->maString.getStr();
                        sal_Unicode* pDest = pParaText.get() + nCurrentIndex;
 
                        sal_uInt32 nFont;
                        pPortion->GetAttrib( PPT_CharAttr_Font, nFont, pTextObj->GetInstance() );
                        const PptFontEntityAtom* pFontEnityAtom = GetFontEnityAtom( nFont );
                        if ( pFontEnityAtom && ( pFontEnityAtom->eCharSet == RTL_TEXTENCODING_SYMBOL ) )
                        {
                            sal_Unicode nUnicode;
                            for (sal_Int32 i = 0; i < nCharacters; i++ )
                            {
                                nUnicode = pSource[ i ];
                                if ( ! ( nUnicode & 0xff00 ) )
                                    nUnicode |= 0xf000;
                                pDest[ i ] = nUnicode;
                            }
                        }
                        else
                            memcpy( pDest, pSource, nCharacters << 1 );
                        nCurrentIndex += nCharacters;
                    }
                }
                sal_Int32  nParaIndex = pTextObj->GetCurrentIndex();
                SfxStyleSheet* pS = ppStyleSheetAry ? ppStyleSheetAry[ pPara->mxParaSet->mnDepth ] : pSheet;
 
                ESelection aSelection( nParaIndex, 0, nParaIndex, 0 );
                rOutliner.Insert( OUString(), nParaIndex, pPara->mxParaSet->mnDepth );
                rOutliner.QuickInsertText( OUString(pParaText.get(), nCurrentIndex), aSelection );
                rOutliner.SetParaAttribs( nParaIndex, rOutliner.GetEmptyItemSet() );
                if ( pS )
                    rOutliner.SetStyleSheet( nParaIndex, pS );
 
                for ( pPortion = pPara->First(); pPortion; pPortion = pPara->Next() )
                {
                    SfxItemSet aPortionAttribs( rOutliner.GetEmptyItemSet() );
                    std::unique_ptr<SvxFieldItem> pFieldItem(pPortion->GetTextField());
                    if ( pFieldItem )
                    {
                        rOutliner.QuickInsertField( *pFieldItem, ESelection( nParaIndex, aSelection.nEndPos, nParaIndex, aSelection.nEndPos + 1 ) );
                        aSelection.nEndPos++;
                    }
                    else
                    {
                        const sal_Unicode *pF, *pPtr = pPortion->maString.getStr();
                        const sal_Unicode *pMax = pPtr + pPortion->maString.getLength();
                        sal_Int32 nLen;
                        for ( pF = pPtr; pPtr < pMax; pPtr++ )
                        {
                            if ( *pPtr == 0xb )
                            {
                                nLen = pPtr - pF;
                                if ( nLen )
                                    aSelection.nEndPos =
                                        sal::static_int_cast< sal_uInt16 >(
                                            aSelection.nEndPos + nLen );
                                pF = pPtr + 1;
                                rOutliner.QuickInsertLineBreak( ESelection( nParaIndex, aSelection.nEndPos, nParaIndex, aSelection.nEndPos + 1 ) );
                                aSelection.nEndPos++;
                            }
                        }
                        nLen = pPtr - pF;
                        if ( nLen )
                            aSelection.nEndPos = sal::static_int_cast< sal_uInt16 >(
                                aSelection.nEndPos + nLen );
                    }
                    pPortion->ApplyTo( aPortionAttribs, const_cast<SdrPowerPointImport&>(*this), nDestinationInstance, pTextObj );
                    rOutliner.QuickSetAttribs( aPortionAttribs, aSelection );
                    aSelection.nStartPos = aSelection.nEndPos;
                }
                std::optional< sal_Int16 > oStartNumbering;
                SfxItemSet aParagraphAttribs( rOutliner.GetEmptyItemSet() );
                pPara->ApplyTo( aParagraphAttribs, oStartNumbering, *this, nDestinationInstance );
 
                sal_uInt32  nIsBullet2 = 0; //, nInstance = nDestinationInstance != 0xffffffff ? nDestinationInstance : pTextObj->GetInstance();
                pPara->GetAttrib( PPT_ParaAttr_BulletOn, nIsBullet2, nDestinationInstance );
                if ( !nIsBullet2 )
                    aParagraphAttribs.Put( SfxBoolItem( EE_PARA_BULLETSTATE, false ) );
                else
                    aParagraphAttribs.Put( SfxInt16Item(EE_PARA_OUTLLEVEL, pPara->mxParaSet->mnDepth));
 
                if ( !aSelection.nStartPos )    // in PPT empty paragraphs never gets a bullet
                {
                    aParagraphAttribs.Put( SfxBoolItem( EE_PARA_BULLETSTATE, false ) );
                }
                aSelection.nStartPos = 0;
                rOutliner.QuickSetAttribs( aParagraphAttribs, aSelection );
            }
        }
        std::optional<OutlinerParaObject> pNewText = rOutliner.CreateParaObject();
        rOutliner.Clear();
        rOutliner.SetUpdateLayout( bOldUpdateMode );
        rOutliner.EnableUndo(bUndoEnabled);
        pText->SetOutlinerParaObject( std::move(pNewText) );
    }
    return pText;
}
 
bool SdrPowerPointImport::SeekToDocument( DffRecordHeader* pRecHd ) const
{
    bool bRet;
    sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for restoring it, if the situation should happen
    rStCtrl.Seek( m_nDocStreamPos );
    DffRecordHeader aDocHd;
    ReadDffRecordHeader( rStCtrl, aDocHd );
    bRet = aDocHd.nRecType == PPT_PST_Document;
    if ( bRet )
    {
        if ( pRecHd )
            *pRecHd = aDocHd;
        else
            aDocHd.SeekToBegOfRecord( rStCtrl );
    }
    if ( !bRet )
        rStCtrl.Seek( nOldFPos ); // restore FilePos
    return bRet;
}
 
bool SdrPowerPointImport::SeekToContentOfProgTag( sal_Int32 nVersion, SvStream& rSt,
                                const DffRecordHeader& rSourceHd, DffRecordHeader& rContentHd )
{
    bool    bRetValue = false;
    sal_uInt64  nOldPos = rSt.Tell();
 
    DffRecordHeader aProgTagsHd, aProgTagBinaryDataHd;
    rSourceHd.SeekToContent( rSt );
    bool bFound = rSourceHd.nRecType == PPT_PST_ProgTags;
    if ( !bFound )
        bFound = SeekToRec( rSt, PPT_PST_ProgTags, rSourceHd.GetRecEndFilePos(), &aProgTagsHd );
    if ( bFound )
    {
        while( SeekToRec( rSt, PPT_PST_ProgBinaryTag, aProgTagsHd.GetRecEndFilePos(), &aProgTagBinaryDataHd ) )
        {
            ReadDffRecordHeader( rSt, rContentHd );
            if ( rContentHd.nRecType == PPT_PST_CString )
            {
                sal_uInt16  n = 6;
                sal_uInt32  i = rContentHd.nRecLen >> 1;
                if ( i > n )
                {
                    OUString aPre = read_uInt16s_ToOUString(rSt, n);
                    n = static_cast<sal_uInt16>( i - 6 );
                    OUString aSuf = read_uInt16s_ToOUString(rSt, n);
                    sal_Int32 nV = aSuf.toInt32();
                    if ( ( nV == nVersion ) && ( aPre == "___PPT" ) )
                    {
                        if (!rContentHd.SeekToEndOfRecord(rSt))
                        {
                            break;
                        }
                        ReadDffRecordHeader( rSt, rContentHd );
                        if ( rContentHd.nRecType == PPT_PST_BinaryTagData )
                        {
                            bRetValue = true;
                            break;
                        }
                    }
                }
            }
            if (!aProgTagBinaryDataHd.SeekToEndOfRecord(rSt))
                break;
        }
    }
    if ( !bRetValue )
        rSt.Seek( nOldPos );
    return bRetValue;
}
 
sal_uInt32 SdrPowerPointImport::GetCurrentPageId()
{
    PptSlidePersistList* pList = GetPageList( m_eCurrentPageKind );
    if ( pList && m_nCurrentPageNum < pList->size() )
        return (*pList)[ m_nCurrentPageNum ].aPersistAtom.nSlideId;
    return 0;
}
 
bool SdrPowerPointImport::SeekToCurrentPage( DffRecordHeader* pRecHd ) const
{
    bool bRet = false;
    PptSlidePersistList* pList = GetPageList( m_eCurrentPageKind );
    if ( pList && ( m_nCurrentPageNum < pList->size() ) )
    {
        sal_uLong nPersist = (*pList)[ m_nCurrentPageNum ].aPersistAtom.nPsrReference;
        if ( nPersist > 0 && nPersist < m_nPersistPtrCnt )
        {
            sal_uLong nFPos = m_pPersistPtr[ nPersist ];
            if ( nFPos < nStreamLen )
            {
                rStCtrl.Seek( nFPos );
                if ( pRecHd )
                    ReadDffRecordHeader( rStCtrl, *pRecHd );
                bRet = true;
            }
        }
    }
    return bRet;
}
 
sal_uInt16 SdrPowerPointImport::GetPageCount( PptPageKind ePageKind ) const
{
    PptSlidePersistList* pList = GetPageList( ePageKind );
    if ( pList )
        return pList->size();
    return 0;
}
 
void SdrPowerPointImport::SetPageNum( sal_uInt16 nPageNum, PptPageKind eKind )
{
    m_eCurrentPageKind = eKind;
    m_nCurrentPageNum = nPageNum;
 
    m_pPPTStyleSheet = nullptr;
 
    bool bHasMasterPage = true;
    sal_uInt16 nMasterIndex = 0;
 
    if ( eKind == PPT_MASTERPAGE )
        nMasterIndex = nPageNum;
    else
    {
        if ( HasMasterPage( nPageNum, eKind ) )
            nMasterIndex = GetMasterPageIndex( nPageNum, eKind );
        else
            bHasMasterPage = false;
    }
    if ( bHasMasterPage )
    {
        PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE );
        if ( pPageList && nMasterIndex < pPageList->size() )
        {
            PptSlidePersistEntry* pMasterPersist = &(*pPageList)[ nMasterIndex ];
            if (!pMasterPersist->xStyleSheet && pMasterPersist->aSlideAtom.nMasterId)
            {
                nMasterIndex = m_pMasterPages->FindPage( pMasterPersist->aSlideAtom.nMasterId );
                if ( nMasterIndex != PPTSLIDEPERSIST_ENTRY_NOTFOUND )
                    pMasterPersist = &(*pPageList)[ nMasterIndex ];
            }
            m_pPPTStyleSheet = pMasterPersist->xStyleSheet.get();
        }
    }
    if ( !m_pPPTStyleSheet )
        m_pPPTStyleSheet = m_pDefaultSheet;
}
 
Size SdrPowerPointImport::GetPageSize() const
{
    Size aRet( IsNoteOrHandout( m_nCurrentPageNum ) ? aDocAtom.GetNotesPageSize() : aDocAtom.GetSlidesPageSize() );
    Scale( aRet );
    // PPT works with units of 576 dpi in any case. To avoid inaccuracies
    // I do round the last decimal digit away.
    if ( nMapMul > 2 * nMapDiv )
    {
        MapUnit eMap = pSdrModel->GetScaleUnit();
        bool bInch = IsInch( eMap );
        tools::Long nInchMul = 1, nInchDiv = 1;
        if ( bInch )
        {   // temporarily convert size (for rounding it) from inch to metric units
            Fraction aFact(GetMapFactor(eMap,MapUnit::Map100thMM).X());
            nInchMul = aFact.GetNumerator();
            nInchDiv = aFact.GetDenominator();
            aRet.setWidth( BigMulDiv( aRet.Width(), nInchMul, nInchDiv ) );
            aRet.setHeight( BigMulDiv( aRet.Height(), nInchMul, nInchDiv ) );
        }
        aRet.AdjustWidth(5 ); aRet.setWidth( aRet.Width() / 10 ); aRet.setWidth( aRet.Width() * 10 );
        aRet.AdjustHeight(5 ); aRet.setHeight( aRet.Height() / 10 ); aRet.setHeight( aRet.Height() * 10 );
        if ( bInch )
        {
            aRet.setWidth( BigMulDiv( aRet.Width(), nInchDiv, nInchMul ) );
            aRet.setHeight( BigMulDiv( aRet.Height(), nInchDiv, nInchMul ) );
        }
    }
    return aRet;
}
 
bool SdrPowerPointImport::GetColorFromPalette( sal_uInt16 nNum, Color& rColor ) const
{
    if ( m_nPageColorsNum != m_nCurrentPageNum || m_ePageColorsKind != m_eCurrentPageKind )
    {
        sal_uInt16 nSlideFlags = 0;
        PptSlidePersistList* pPageList = GetPageList( m_eCurrentPageKind );
        if ( pPageList && ( m_nCurrentPageNum < pPageList->size() ) )
        {
            assert( !pPageList->is_null( m_nCurrentPageNum ) );
            const PptSlidePersistEntry& rE = (*pPageList)[ m_nCurrentPageNum ];
            nSlideFlags = rE.aSlideAtom.nFlags;
            if ( ! ( nSlideFlags & 2 ) )
                const_cast<SdrPowerPointImport*>(this)->m_aPageColors = rE.aColorScheme;
        }
        if ( nSlideFlags & 2 )      // follow master colorscheme?
        {
            PptSlidePersistList* pPageList2 = GetPageList( PPT_MASTERPAGE );
            if ( pPageList2 )
            {
                PptSlidePersistEntry* pMasterPersist = nullptr;
                if ( m_eCurrentPageKind == PPT_MASTERPAGE )
                    pMasterPersist = &(*pPageList2)[ m_nCurrentPageNum ];
                else
                {
                    if ( HasMasterPage( m_nCurrentPageNum, m_eCurrentPageKind ) )
                    {
                        sal_uInt16 nMasterNum = GetMasterPageIndex( m_nCurrentPageNum, m_eCurrentPageKind );
                        if ( nMasterNum < pPageList2->size() )
                            pMasterPersist = &(*pPageList2)[ nMasterNum ];
                    }
                }
                if ( pMasterPersist )
                {
                    while( (pMasterPersist->aSlideAtom.nFlags & 2) // it is possible that a masterpage
                        && pMasterPersist->aSlideAtom.nMasterId )  // itself is following a master colorscheme
                    {
                        auto nOrigMasterId = pMasterPersist->aSlideAtom.nMasterId;
                        sal_uInt16 nNextMaster = m_pMasterPages->FindPage(nOrigMasterId);
                        if (nNextMaster == PPTSLIDEPERSIST_ENTRY_NOTFOUND)
                            break;
                        pMasterPersist = &(*pPageList2)[ nNextMaster ];
                        if (pMasterPersist->aSlideAtom.nMasterId == nOrigMasterId)
                        {
                            SAL_WARN("filter.ms", "loop in atom chain");
                            break;
                        }
                    }
                    const_cast<SdrPowerPointImport*>(this)->m_aPageColors = pMasterPersist->aColorScheme;
                }
            }
        }
        // register current color scheme
        const_cast<SdrPowerPointImport*>(this)->m_nPageColorsNum = m_nCurrentPageNum;
        const_cast<SdrPowerPointImport*>(this)->m_ePageColorsKind = m_eCurrentPageKind;
    }
    rColor = m_aPageColors.GetColor( nNum );
    return true;
}
 
bool SdrPowerPointImport::SeekToShape( SvStream& rSt, SvxMSDffClientData* pClientData, sal_uInt32 nId ) const
{
    bool bRet = SvxMSDffManager::SeekToShape( rSt, pClientData, nId );
    if (!bRet && pClientData)
    {
        ProcessData& rData = *static_cast<ProcessData*>(pClientData);
        PptSlidePersistEntry& rPersistEntry = rData.rPersistEntry;
        if ( rPersistEntry.ePageKind == PPT_SLIDEPAGE )
        {
            if ( HasMasterPage( m_nCurrentPageNum, m_eCurrentPageKind ) )
            {
                sal_uInt16 nMasterNum = GetMasterPageIndex( m_nCurrentPageNum, m_eCurrentPageKind );
                PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE );
                if ( pPageList && ( nMasterNum < pPageList->size() ) )
                {
                    assert( !pPageList->is_null( nMasterNum ) );
                    const PptSlidePersistEntry& rPersist = (*pPageList)[ nMasterNum ];    // get the masterpage's persistentry
                    if ( rPersist.pPresentationObjects )
                    {
                        sal_uInt32 nCurrent(0);
                        DffRecordList* pCList = maShapeRecords.pCList;              // we got a backup of the current position
                        if ( pCList )
                            nCurrent = pCList->nCurrent;
                        if ( const_cast<SdrPowerPointImport*>(this)->maShapeRecords.SeekToContent( rSt, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) )
                        {
                            sal_uInt64 nStreamPos = rSt.Tell();
                            PPTTextObj aTextObj( rSt, const_cast<SdrPowerPointImport&>(*this), rPersistEntry, nullptr );
                            if ( aTextObj.Count() || aTextObj.GetOEPlaceHolderAtom() )
                            {
                                sal_uInt32 nShapePos = 0;
                                switch ( aTextObj.GetInstance() )
                                {
                                    case TSS_Type::Title :
                                        nShapePos = rPersist.pPresentationObjects[ int(TSS_Type::PageTitle) ];
                                    break;
                                    case TSS_Type::PageTitle :
                                        nShapePos = rPersist.pPresentationObjects[ int(TSS_Type::PageTitle) ];
                                    break;
                                    case TSS_Type::Subtitle :
                                    case TSS_Type::HalfBody :
                                    case TSS_Type::QuarterBody :
                                    case TSS_Type::Body :
                                        nShapePos = rPersist.pPresentationObjects[ int(TSS_Type::Body) ];
                                    break;
                                    default: break;
                                }
                                if ( nShapePos )
                                {
                                    rSt.Seek( nShapePos );
                                    bRet = true;
                                }
                            }
                            if ( !bRet )
                                rSt.Seek( nStreamPos );
                        }
                        if ( pCList )                                               // restoring
                            pCList->nCurrent = nCurrent;
                        const_cast<SdrPowerPointImport*>(this)->maShapeRecords.pCList = pCList;
                    }
                }
            }
        }
    }
    return bRet;
}
 
rtl::Reference<SdrPage> SdrPowerPointImport::MakeBlankPage( bool bMaster ) const
{
    rtl::Reference<SdrPage> pRet = pSdrModel->AllocPage( bMaster );
    pRet->SetSize( GetPageSize() );
 
    return pRet;
}
 
static void ImportComment10( SvxMSDffManager const & rMan, SvStream& rStCtrl, SdrPage* pPage, DffRecordHeader const & rComment10Hd )
{
    OUString        sAuthor;
    OUString        sText;
    OUString        sInitials;
 
    sal_Int32       nIndex = 0;
    util::DateTime  aDateTime;
    sal_Int32       nPosX = 0;
    sal_Int32       nPosY = 0;
 
 
    auto nEndRecPos = DffPropSet::SanitizeEndPos(rStCtrl, rComment10Hd.GetRecEndFilePos());
    while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nEndRecPos ) )
    {
        DffRecordHeader aCommentHd;
        ReadDffRecordHeader( rStCtrl, aCommentHd );
        switch( aCommentHd.nRecType )
        {
            case PPT_PST_CString :
            {
                OUString aString = SvxMSDffManager::MSDFFReadZString( rStCtrl,
                    aCommentHd.nRecLen, true );
                switch ( aCommentHd.nRecInstance )
                {
                    case 0 : sAuthor = aString;     break;
                    case 1 : sText = aString;       break;
                    case 2 : sInitials = aString;   break;
                }
            }
            break;
 
            case PPT_PST_CommentAtom10 :
            {
                sal_uInt16 millisec = 0;
                rStCtrl.ReadInt32( nIndex )
                       .ReadInt16( aDateTime.Year )
                       .ReadUInt16( aDateTime.Month )
                       .ReadUInt16( aDateTime.Day )    // DayOfWeek
                       .ReadUInt16( aDateTime.Day )
                       .ReadUInt16( aDateTime.Hours )
                       .ReadUInt16( aDateTime.Minutes )
                       .ReadUInt16( aDateTime.Seconds )
                       .ReadUInt16( millisec )
                       .ReadInt32( nPosX )
                       .ReadInt32( nPosY );
 
                aDateTime.NanoSeconds = millisec * ::tools::Time::nanoPerMilli;
            }
            break;
        }
        if (!aCommentHd.SeekToEndOfRecord(rStCtrl))
            break;
    }
    Point aPosition( nPosX, nPosY );
    rMan.Scale( aPosition );
 
    try
    {
        uno::Reference< office::XAnnotationAccess > xAnnotationAccess( pPage->getUnoPage(), UNO_QUERY_THROW );
        uno::Reference< office::XAnnotation > xAnnotation( xAnnotationAccess->createAndInsertAnnotation() );
        xAnnotation->setPosition( geometry::RealPoint2D( aPosition.X() / 100.0, aPosition.Y() / 100.0 ) );
        xAnnotation->setAuthor( sAuthor );
        xAnnotation->setDateTime( aDateTime );
        xAnnotation->setInitials( sInitials );
        uno::Reference< text::XText > xText( xAnnotation->getTextRange() );
        xText->setString( sText );
    }
    catch( const uno::Exception& )
    {
 
    }
}
 
 
// be sure not to import masterpages with this method
void SdrPowerPointImport::ImportPage( SdrPage* pRet, const PptSlidePersistEntry* pMasterPersist )
{
    sal_uInt64 nOldPos = rStCtrl.Tell();
    PptSlidePersistList* pList = GetPageList( m_eCurrentPageKind );
    if ( ( !pList ) || ( pList->size() <= m_nCurrentPageNum ) )
        return;
    PptSlidePersistEntry& rSlidePersist = (*pList)[ m_nCurrentPageNum ];
    if ( rSlidePersist.bStarDrawFiller )
        return;
 
    DffRecordHeader aPageHd;
    if ( SeekToCurrentPage( &aPageHd ) )
    {
        rSlidePersist.xHeaderFooterEntry.reset(new HeaderFooterEntry(pMasterPersist));
        ProcessData aProcessData( rSlidePersist, SdPageCapsule(pRet) );
        auto nEndRecPos = SanitizeEndPos(rStCtrl, aPageHd.GetRecEndFilePos());
        while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nEndRecPos ) )
        {
            DffRecordHeader aHd;
            ReadDffRecordHeader( rStCtrl, aHd );
            switch ( aHd.nRecType )
            {
                case PPT_PST_HeadersFooters :
                {
                    ImportHeaderFooterContainer(aHd, *rSlidePersist.xHeaderFooterEntry);
                }
                break;
 
                case PPT_PST_ProgTags :
                {
                    DffRecordHeader aContentDataHd;
                    if ( SeekToContentOfProgTag( 10, rStCtrl, aHd, aContentDataHd ) )
                    {
                        DffRecordHeader aComment10Hd;
                        while( ( rStCtrl.GetError() == ERRCODE_NONE ) && SeekToRec( rStCtrl, PPT_PST_Comment10, aContentDataHd.GetRecEndFilePos(), &aComment10Hd ) )
                        {
                            ImportComment10( *this, rStCtrl, pRet, aComment10Hd );
                            if (!aComment10Hd.SeekToEndOfRecord(rStCtrl))
                                break;
                        }
                    }
                }
                break;
 
                case PPT_PST_PPDrawing :
                {
                    DffRecordHeader aPPDrawHd;
                    if ( SeekToRec( rStCtrl, DFF_msofbtDgContainer, aHd.GetRecEndFilePos(), &aPPDrawHd ) )
                    {
                        sal_uInt64 nPPDrawOfs = rStCtrl.Tell();
 
                        // importing the background object before importing the page
                        auto nPPEndRecPos = SanitizeEndPos(rStCtrl, aPPDrawHd.GetRecEndFilePos());
                        while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nPPEndRecPos ) )
                        {
                            DffRecordHeader aEscherObjListHd;
                            ReadDffRecordHeader( rStCtrl, aEscherObjListHd );
                            switch ( aEscherObjListHd.nRecType )
                            {
                                case DFF_msofbtSpContainer :
                                {
                                    tools::Rectangle aPageSize( Point(), pRet->GetSize() );
                                    if ( rSlidePersist.aSlideAtom.nFlags & 4 )          // follow master background?
                                    {
                                        if ( HasMasterPage( m_nCurrentPageNum, m_eCurrentPageKind ) )
                                        {
                                            sal_uInt16 nMasterNum = GetMasterPageIndex( m_nCurrentPageNum, m_eCurrentPageKind );
                                            PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE );
                                            PptSlidePersistEntry* pE = &(*pPageList)[ nMasterNum ];
                                            while( ( pE->aSlideAtom.nFlags & 4 ) && pE->aSlideAtom.nMasterId )
                                            {
                                                auto nOrigMasterId = pE->aSlideAtom.nMasterId;
                                                sal_uInt16 nNextMaster = m_pMasterPages->FindPage(nOrigMasterId);
                                                if ( nNextMaster == PPTSLIDEPERSIST_ENTRY_NOTFOUND )
                                                    break;
                                                else
                                                    pE = &(*pPageList)[ nNextMaster ];
                                                if (pE->aSlideAtom.nMasterId == nOrigMasterId)
                                                {
                                                    SAL_WARN("filter.ms", "loop in atom chain");
                                                    break;
                                                }
                                            }
                                            if ( pE->nBackgroundOffset )
                                            {
                                                // do not follow master colorscheme?
                                                sal_uInt64 nPos = rStCtrl.Tell();
                                                rStCtrl.Seek( pE->nBackgroundOffset );
                                                rSlidePersist.pBObj = ImportObj( rStCtrl, aProcessData, aPageSize, aPageSize, /*nCalledByGroup*/0, /*pShapeId*/nullptr );
                                                rStCtrl.Seek( nPos );
                                            }
                                        }
                                    }
                                    else
                                    {
                                        DffRecordHeader aShapeHd;
                                        ReadDffRecordHeader( rStCtrl, aShapeHd );
                                        if ( aShapeHd.nRecType == DFF_msofbtSp )
                                        {
                                            sal_uInt32 nSpFlags;
                                            rStCtrl.ReadUInt32( nSpFlags ).ReadUInt32( nSpFlags );
                                            if (rStCtrl.good() && ShapeFlag(nSpFlags) & ShapeFlag::Background)
                                            {
                                                aEscherObjListHd.SeekToBegOfRecord( rStCtrl );
                                                rSlidePersist.pBObj = ImportObj( rStCtrl, aProcessData, aPageSize, aPageSize, /*nCalledByGroup*/0, /*pShapeId*/nullptr );
                                            }
                                        }
                                    }
                                }
                                break;
                            }
                            if ( aEscherObjListHd.nRecType == DFF_msofbtSpContainer )
                                break;
                            if (!aEscherObjListHd.SeekToEndOfRecord(rStCtrl))
                                break;
                        }
 
                        // now importing page
                        rStCtrl.Seek( nPPDrawOfs );
                        auto nHdEndRecPos = SanitizeEndPos(rStCtrl, aPPDrawHd.GetRecEndFilePos());
                        while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nHdEndRecPos ) )
                        {
                            DffRecordHeader aEscherObjListHd;
                            ReadDffRecordHeader( rStCtrl, aEscherObjListHd );
                            switch ( aEscherObjListHd.nRecType )
                            {
                                case DFF_msofbtSpgrContainer :
                                {
                                    DffRecordHeader aShapeHd;
                                    if ( SeekToRec( rStCtrl, DFF_msofbtSpContainer, aEscherObjListHd.GetRecEndFilePos(), &aShapeHd ) )
                                    {
                                        if (!aShapeHd.SeekToEndOfRecord(rStCtrl))
                                        {
                                            break;
                                        }
                                        auto nListEndRecPos = SanitizeEndPos(rStCtrl, aEscherObjListHd.GetRecEndFilePos());
                                        while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nListEndRecPos ) )
                                        {
                                            ReadDffRecordHeader( rStCtrl, aShapeHd );
                                            if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) || ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) )
                                            {
                                                tools::Rectangle aEmpty;
                                                aShapeHd.SeekToBegOfRecord( rStCtrl );
                                                sal_Int32 nShapeId;
                                                aProcessData.pTableRowProperties.reset();
                                                rtl::Reference<SdrObject> pObj = ImportObj( rStCtrl, aProcessData, aEmpty, aEmpty, 0, &nShapeId );
                                                if ( pObj )
                                                {
                                                    if ( aProcessData.pTableRowProperties )
                                                        pObj = CreateTable(pObj.get(), aProcessData.pTableRowProperties.get(), aProcessData.rPersistEntry.xSolverContainer.get());
 
                                                    pRet->NbcInsertObject( pObj.get() );
 
                                                    if( nShapeId )
                                                        insertShapeId( nShapeId, pObj.get() );
                                                }
                                            }
                                            bool bSuccess = aShapeHd.SeekToEndOfRecord(rStCtrl);
                                            if (!bSuccess)
                                                break;
                                        }
                                    }
                                }
                                break;
                            }
                            if ( aEscherObjListHd.nRecType == DFF_msofbtSpgrContainer )
                                break;
                            if (!aEscherObjListHd.SeekToEndOfRecord(rStCtrl))
                                break;
                        }
 
                        if ( rSlidePersist.pBObj )
                        {
                            // #i99386# transfer the attributes from the temporary BackgroundObject
                            // to the Page and delete it.
                            pRet->getSdrPageProperties().ClearItem();
                            pRet->getSdrPageProperties().PutItemSet(rSlidePersist.pBObj->GetMergedItemSet());
                            if (rSlidePersist.xSolverContainer)
                            {
                                for (auto & pPtr : rSlidePersist.xSolverContainer->aCList)
                                {
                                    // check connections to the group object
                                    if (pPtr->pAObj == rSlidePersist.pBObj.get())
                                        pPtr->pAObj = nullptr;
                                    if (pPtr->pBObj == rSlidePersist.pBObj.get())
                                        pPtr->pBObj = nullptr;
                                    if (pPtr->pCObj == rSlidePersist.pBObj.get())
                                        pPtr->pCObj = nullptr;
                                }
                            }
                            rSlidePersist.pBObj.clear();
                        }
                    }
                }
                break;
            }
            if (!aHd.SeekToEndOfRecord(rStCtrl))
                break;
        }
        if (rSlidePersist.xSolverContainer)
            SolveSolver(*rSlidePersist.xSolverContainer);
    }
    rStCtrl.Seek( nOldPos );
}
 
const PptSlideLayoutAtom* SdrPowerPointImport::GetSlideLayoutAtom() const
{
    PptSlidePersistList* pPageList = GetPageList( m_eCurrentPageKind );
    if ( pPageList && m_nCurrentPageNum < pPageList->size() )
    {
        assert( !pPageList->is_null( m_nCurrentPageNum ) );
        return &(*pPageList)[ m_nCurrentPageNum ].aSlideAtom.aLayout;
    }
    return nullptr;
}
 
bool SdrPowerPointImport::IsNoteOrHandout( sal_uInt16 nPageNum ) const
{
    bool bNote = m_eCurrentPageKind == PPT_NOTEPAGE;
    if ( m_eCurrentPageKind == PPT_MASTERPAGE )
        bNote = ( nPageNum & 1 ) == 0;
    return bNote;
}
 
sal_uInt32 SdrPowerPointImport::GetMasterPageId( sal_uInt16 nPageNum, PptPageKind ePageKind ) const
{
    PptSlidePersistList* pPageList = GetPageList( ePageKind );
    if ( pPageList && nPageNum < pPageList->size() )
        return (*pPageList)[ nPageNum ].aSlideAtom.nMasterId;
    return 0;
}
 
sal_uInt32 SdrPowerPointImport::GetNotesPageId( sal_uInt16 nPageNum ) const
{
    PptSlidePersistList* pPageList=GetPageList( PPT_SLIDEPAGE );
    if ( pPageList && nPageNum < pPageList->size() )
        return (*pPageList)[ nPageNum ].aSlideAtom.nNotesId;
    return 0;
}
 
bool SdrPowerPointImport::HasMasterPage( sal_uInt16 nPageNum, PptPageKind ePageKind ) const
{
    if ( ePageKind == PPT_NOTEPAGE )
        return aDocAtom.nNotesMasterPersist != 0;
    if ( ePageKind == PPT_MASTERPAGE )
        return false;
    return GetMasterPageId( nPageNum, ePageKind ) != 0;
}
 
sal_uInt16 SdrPowerPointImport::GetMasterPageIndex( sal_uInt16 nPageNum, PptPageKind ePageKind ) const
{
    sal_uInt16 nIdx = 0;
    if ( ePageKind == PPT_NOTEPAGE )
        return 2;
    sal_uInt32 nId = GetMasterPageId( nPageNum, ePageKind );
    if (nId && m_pMasterPages)
    {
        nIdx = m_pMasterPages->FindPage( nId );
        if ( nIdx == PPTSLIDEPERSIST_ENTRY_NOTFOUND )
            nIdx = 0;
    }
    return nIdx;
}
 
rtl::Reference<SdrObject> SdrPowerPointImport::ImportPageBackgroundObject( const SdrPage& rPage, sal_uInt32& nBgFileOffset )
{
    rtl::Reference<SdrObject> pRet;
    std::optional<SfxItemSet> pSet;
    sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for restoring it later
    DffRecordHeader aPageHd;
    if ( SeekToCurrentPage( &aPageHd ) )
    {   // and now search for the background attributes of the Page
        sal_uLong nPageRecEnd = aPageHd.GetRecEndFilePos();
        DffRecordHeader aPPDrawHd;
        if ( SeekToRec( rStCtrl, PPT_PST_PPDrawing, nPageRecEnd, &aPPDrawHd ) )
        {
            sal_uLong nPPDrawEnd = aPPDrawHd.GetRecEndFilePos();
            DffRecordHeader aEscherF002Hd;
            if ( SeekToRec( rStCtrl, DFF_msofbtDgContainer, nPPDrawEnd, &aEscherF002Hd ) )
            {
                sal_uLong nEscherF002End = aEscherF002Hd.GetRecEndFilePos();
                DffRecordHeader aEscherObjectHd;
                if ( SeekToRec( rStCtrl, DFF_msofbtSpContainer, nEscherF002End, &aEscherObjectHd ) )
                {
                    nBgFileOffset = aEscherObjectHd.GetRecBegFilePos();
                    //sal_uLong nEscherObjectEnd = aEscherObjectHd.GetRecEndFilePos();
                    //DffRecordHeader aEscherPropertiesHd;
                    if ( SeekToRec( rStCtrl, DFF_msofbtOPT,nEscherF002End ) )
                    {
                        ReadDffPropSet( rStCtrl, static_cast<DffPropertyReader&>(*this) );
                        mnFix16Angle = Fix16ToAngle( GetPropertyValue( DFF_Prop_Rotation, 0 ) );
                        sal_uInt32 nColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );
                        pSet.emplace( pSdrModel->GetItemPool() );
                        DffObjData aObjData( aEscherObjectHd, tools::Rectangle( 0, 0, 28000, 21000 ), 0 );
                        ApplyAttributes( rStCtrl, *pSet, aObjData );
                        Color aColor( MSO_CLR_ToColor( nColor ) );
                        pSet->Put( XFillColorItem( OUString(), aColor ) );
                    }
                }
            }
        }
    }
    rStCtrl.Seek( nOldFPos ); // restore FilePos
    if ( !pSet )
    {
        pSet.emplace( pSdrModel->GetItemPool() );
        pSet->Put( XFillStyleItem( drawing::FillStyle_NONE ) );
    }
    pSet->Put( XLineStyleItem( drawing::LineStyle_NONE ) );
    tools::Rectangle aRect(
        rPage.GetLeftBorder(),
        rPage.GetUpperBorder(),
        rPage.GetWidth() - rPage.GetRightBorder(),
        rPage.GetHeight() - rPage.GetLowerBorder());
 
    pRet = new SdrRectObj(
        *pSdrModel,
        aRect);
 
    pRet->SetMergedItemSet(*pSet);
    pRet->SetMarkProtect( true );
    pRet->SetMoveProtect( true );
    pRet->SetResizeProtect( true );
    return pRet;
}
 
HeaderFooterEntry::HeaderFooterEntry( const PptSlidePersistEntry* pMPE ) :
    pMasterPersist  ( pMPE ),
    nAtom           ( 0 )
{
    if ( pMPE )
    {
        HeaderFooterEntry* pMHFE = pMPE->xHeaderFooterEntry.get();
        if ( pMHFE )
        {
            nAtom = pMPE->xHeaderFooterEntry->nAtom;
            pPlaceholder[ 0 ] = pMHFE->pPlaceholder[ 0 ];
            pPlaceholder[ 1 ] = pMHFE->pPlaceholder[ 1 ];
            pPlaceholder[ 2 ] = pMHFE->pPlaceholder[ 2 ];
            pPlaceholder[ 3 ] = pMHFE->pPlaceholder[ 3 ];
        }
    }
}
 
sal_uInt32 HeaderFooterEntry::IsToDisplay( sal_uInt32 nInstance )
{
    sal_uInt32 nMask = 0;
    switch ( nInstance )
    {
        case 0 : nMask = 0x010000; break;
        case 1 : nMask = 0x100000; break;
        case 2 : nMask = 0x200000; break;
        case 3 : nMask = 0x080000; break;
    }
    return ( nAtom & nMask );
}
 
// The following method checks if the slide is using a different colorscheme than
// its master, if this is the fact, then the HeaderFooter must probably be
// imported as real sdrobject. In this case, the return value is the offset to the
// master header footer object, so it can be re-loaded with a different color set
sal_uInt32 HeaderFooterEntry::NeedToImportInstance( const sal_uInt32 nInstance, const PptSlidePersistEntry& rSlidePersist )
{
    sal_uInt32 nRet = 0;
    if ( pMasterPersist )
    {
        if ( !( rSlidePersist.aSlideAtom.nFlags & 2 ) )
        {   // not following the master persist, so we have to check if the colors are changed
            if ( memcmp( &rSlidePersist.aColorScheme, &pMasterPersist->aColorScheme, 32 ) )
            {
                nRet = pMasterPersist->HeaderFooterOfs[ nInstance ];
            }
        }
    }
    return nRet;
}
 
void SdrEscherImport::ImportHeaderFooterContainer( DffRecordHeader const & rHd, HeaderFooterEntry& rE )
{
    rHd.SeekToContent( rStCtrl );
    auto nEndRecPos = SanitizeEndPos(rStCtrl, rHd.GetRecEndFilePos());
    while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nEndRecPos ) )
    {
        DffRecordHeader aHd;
        ReadDffRecordHeader( rStCtrl, aHd );
        switch ( aHd.nRecType )
        {
            case PPT_PST_HeadersFootersAtom :
                rStCtrl.ReadUInt32( rE.nAtom );
            break;
 
            case PPT_PST_CString :
            {
                if ( aHd.nRecInstance < 4 )
                {
                    rE.pPlaceholder[ aHd.nRecInstance ] = MSDFFReadZString( rStCtrl,
                        aHd.nRecLen, true );
                }
            }
            break;
        }
        if (!aHd.SeekToEndOfRecord(rStCtrl))
            break;
    }
}
 
PPTBuGraEntry::PPTBuGraEntry( Graphic aGraphic, sal_uInt32 nInst ) :
    nInstance       ( nInst ),
    aBuGra          (std::move( aGraphic ))  {}
 
PPTExtParaLevel::PPTExtParaLevel()
: mnExtParagraphMask( 0 )
, mnBuBlip( 0xffff )
, mnHasAnm( 0 )
, mnAnmScheme( 0 )
, mpfPP10Ext( 0 )
, mnExtCharacterMask( 0 )
, mcfPP10Ext( 0 )
, mbSet( false )
{}
 
SvStream& ReadPPTExtParaLevel( SvStream& rIn, PPTExtParaLevel& rLevel )
{
    rLevel.mbSet = true;
    rIn.ReadUInt32( rLevel.mnExtParagraphMask );
    if ( rLevel.mnExtParagraphMask & 0x00800000 )
        rIn.ReadUInt16( rLevel.mnBuBlip );
    if ( rLevel.mnExtParagraphMask & 0x02000000 )
        rIn.ReadUInt16( rLevel.mnHasAnm );
    if ( rLevel.mnExtParagraphMask & 0x01000000 )
        rIn.ReadUInt32( rLevel.mnAnmScheme );
    if ( rLevel.mnExtParagraphMask & 0x04000000 )
        rIn.ReadUInt32( rLevel.mpfPP10Ext );
    rIn.ReadUInt32( rLevel.mnExtCharacterMask );
    if ( rLevel.mnExtCharacterMask & 0x100000 )
        rIn.ReadUInt32( rLevel.mcfPP10Ext );
    return rIn;
}
 
bool PPTExtParaProv::GetGraphic( sal_uInt32 nInstance, Graphic& rGraph ) const
{
    bool bRetValue = false;
    PPTBuGraEntry* pPtr = nullptr;
    if ( nInstance < aBuGraList.size() )
    {
        pPtr = aBuGraList[ nInstance ].get();
        if ( pPtr->nInstance == nInstance )
            bRetValue = true;
    }
    if ( !bRetValue )
    {
        for (std::unique_ptr<PPTBuGraEntry> const & i : aBuGraList)
        {
            pPtr = i.get();
            if ( pPtr->nInstance == nInstance )
            {
                bRetValue = true;
                break;
            }
        }
    }
    if ( bRetValue )
        rGraph = pPtr->aBuGra;
    return bRetValue;
}
 
PPTExtParaProv::PPTExtParaProv( SdrPowerPointImport& rMan, SvStream& rSt, const DffRecordHeader* pHd ) :
    bStyles         ( false )
{
    sal_uInt64 nOldPos = rSt.Tell();
 
    // here we have to get the graphical bullets...
 
    DffRecordHeader aHd;
    DffRecordHeader aContentDataHd;
 
    const DffRecordHeader* pListHd = rMan.aDocRecManager.GetRecordHeader( PPT_PST_List );
    if( pListHd )
        pListHd->SeekToContent( rSt );
    if ( pListHd && SdrPowerPointImport::SeekToContentOfProgTag( 9, rSt, *pListHd, aContentDataHd ) )
    {
        auto nEndRecPos = DffPropSet::SanitizeEndPos(rSt, aContentDataHd.GetRecEndFilePos());
        while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nEndRecPos ) )
        {
            ReadDffRecordHeader( rSt, aHd );
            switch ( aHd.nRecType )
            {
                case PPT_PST_ExtendedBuGraContainer :
                {
                    auto nHdEndRecPos = DffPropSet::SanitizeEndPos(rSt, aHd.GetRecEndFilePos());
                    while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nHdEndRecPos ) )
                    {
                        DffRecordHeader aBuGraAtomHd;
                        ReadDffRecordHeader( rSt, aBuGraAtomHd );
                        if ( aBuGraAtomHd.nRecType == PPT_PST_ExtendedBuGraAtom )
                        {
                            sal_uInt16 nType;
                            rSt.ReadUInt16( nType );
                            Graphic aGraphic;
                            if ( SvxMSDffManager::GetBLIPDirect( rSt, aGraphic ) )
                            {
                                sal_uInt32 nInstance = aBuGraAtomHd.nRecInstance;
                                PPTBuGraEntry* pBuGra = new PPTBuGraEntry( std::move(aGraphic), nInstance );
                                size_t n = 0;
                                size_t nBuGraCount = aBuGraList.size();
                                if ( nBuGraCount )
                                {
                                    if ( aBuGraList[ nBuGraCount - 1 ]->nInstance < nInstance )
                                        n = nBuGraCount;
                                    else
                                    {   // maybe the instances are not sorted, we sort it
                                        for ( n = 0; n < nBuGraCount; n++ )
                                        {   // sorting fields ( hi >> lo )
                                            if ( aBuGraList[ n ]->nInstance < nInstance )
                                                break;
                                        }
                                    }
                                }
                                if ( n < nBuGraCount ) {
                                    aBuGraList.emplace( aBuGraList.begin() + n, pBuGra );
                                } else {
                                    aBuGraList.emplace_back( pBuGra );
                                }
                            }
#ifdef DBG_UTIL
                            else OSL_FAIL( "PPTExParaProv::PPTExParaProv - bullet graphic is not valid (SJ)" );
#endif
                        }
#ifdef DBG_UTIL
                        else OSL_FAIL( "PPTExParaProv::PPTExParaProv - unknown atom interpreting the PPT_PST_ExtendedBuGraContainer (SJ)" );
#endif
                        if (!aBuGraAtomHd.SeekToEndOfRecord(rSt))
                            break;
                    }
                }
                break;
 
                case PPT_PST_ExtendedPresRuleContainer :
                    aExtendedPresRules.Consume( rSt, aHd.GetRecEndFilePos() );
                break;
#ifdef DBG_UTIL
                default :
                    OSL_FAIL( "PPTExParaProv::PPTExParaProv - unknown atom reading ppt2000 num rules (SJ)" );
                break;
                case PPT_PST_MasterText :   // first seen in: ms-tt02.ppt
                case PPT_PST_SrKinsoku :
                case PPT_PST_TextDefaults9Atom :
                case PPT_PST_PresentationAdvisorFlags9Atom :
                case PPT_PST_HtmlDocInfo9Atom :
                case PPT_PST_GridSpacing10Atom :
                case PPT_PST_CommentIndex10 :
                case PPT_PST_DocToolbarStates10Atom :
                break;
#endif
            }
            if (!aHd.SeekToEndOfRecord(rSt))
                break;
        }
    }
 
    if ( pHd && SdrPowerPointImport::SeekToContentOfProgTag( 9, rSt, *pHd, aContentDataHd ) )
    {   // get the extended paragraph styles on mainmaster ( graphical bullets, num ruling ... )
        auto nEndRecPos = DffPropSet::SanitizeEndPos(rSt, aContentDataHd.GetRecEndFilePos());
        while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nEndRecPos ) )
        {
            ReadDffRecordHeader( rSt, aHd );
            switch ( aHd.nRecType )
            {
                case PPT_PST_ExtendedParagraphMasterAtom :
                {
                    if ( aHd.nRecInstance < PPT_STYLESHEETENTRIES )
                    {
                        sal_uInt16 nDepth = 0, i = 0;
                        rSt.ReadUInt16(nDepth);
                        nDepth = std::min<sal_uInt16>(nDepth, nMaxPPTLevels);
                        auto nHdEndRecPos = DffPropSet::SanitizeEndPos(rSt, aHd.GetRecEndFilePos());
                        while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nHdEndRecPos ) && ( i < nDepth ) )
                        {
                            bStyles = true;
                            ReadPPTExtParaLevel( rSt, aExtParaSheet[ static_cast<TSS_Type>(aHd.nRecInstance) ].aExtParaLevel[ i++ ] );
                        }
#ifdef DBG_UTIL
                        if ( rSt.Tell() != aHd.GetRecEndFilePos() )
                            OSL_FAIL( "PPTExParaProv::PPTExParaProv - error reading PPT_PST_ExtendedParagraphMasterAtom (SJ)" );
#endif
                    }
#ifdef DBG_UTIL
                    else OSL_FAIL( "PPTExParaProv::PPTExParaProv - instance out of range (SJ)" );
#endif
                }
                break;
                default :
                    OSL_FAIL( "PPTExParaProv::PPTExParaProv - unknown atom, assuming PPT_PST_ExtendedParagraphMasterAtom (SJ)" );
                break;
                case PPT_PST_HashCodeAtom :
                case PPT_PST_BuildList :
                case PPT_PST_SlideFlags10Atom :
                case PPT_PST_SlideTime10Atom :
                case 0xf144 :
                break;
            }
            if (!aHd.SeekToEndOfRecord(rSt))
                break;
        }
    }
    rSt.Seek( nOldPos );
}
 
PPTExtParaProv::~PPTExtParaProv()
{
}
 
PPTNumberFormatCreator::PPTNumberFormatCreator( std::unique_ptr<PPTExtParaProv> pParaProv )
    : nIsBullet(0)
    , nBulletChar(0)
    , nBulletFont(0)
    , nBulletHeight(0)
    , nBulletColor(0)
    , nTextOfs(0)
    , nBulletOfs(0)
    , pExtParaProv(std::move(pParaProv))
{
}
 
PPTNumberFormatCreator::~PPTNumberFormatCreator()
{
}
 
bool PPTNumberFormatCreator::ImplGetExtNumberFormat( SdrPowerPointImport const & rManager,
    SvxNumberFormat& rNumberFormat, sal_uInt32 nLevel, TSS_Type nInstance, TSS_Type nDestinationInstance,
        std::optional< sal_Int16 >& rStartNumbering, sal_uInt32 nFontHeight,  PPTParagraphObj const * pPara )
{
    bool bHardAttribute = ( nDestinationInstance == TSS_Type::Unknown );
 
    sal_uInt32  nBuFlags = 0;
    sal_uInt16  nHasAnm = 0;
    sal_uInt32  nAnmScheme = 0xFFFF0003;
    sal_uInt16  nBuBlip = 0xffff;
 
    const PPTExtParaProv* pParaProv = pExtParaProv.get();
    if ( !pExtParaProv )
        pParaProv = pPara ? pPara->mrStyleSheet.pExtParaProv.get()
                          : rManager.m_pPPTStyleSheet->pExtParaProv.get();
    if ( pPara )
    {
        nBuFlags = pPara->mxParaSet->mnExtParagraphMask;
        if ( nBuFlags )
        {
            if ( nBuFlags & 0x00800000 )
                nBuBlip = pPara->mxParaSet->mnBuBlip;
            if ( nBuFlags & 0x01000000 )
                nAnmScheme = pPara->mxParaSet->mnAnmScheme;
            if ( nBuFlags & 0x02000000 )
                nHasAnm = pPara->mxParaSet->mnHasAnm;
            bHardAttribute = true;
        }
    }
 
    if ( ( nBuFlags & 0x03800000 ) != 0x03800000 )  // merge style sheet
    {
        // we have to read the master attributes
        if (pParaProv && nLevel < nMaxPPTLevels)
        {
            if ( pParaProv->bStyles )
            {
                const PPTExtParaLevel& rLev = pParaProv->aExtParaSheet[ nInstance ].aExtParaLevel[ nLevel ];
                if ( rLev.mbSet )
                {
                    sal_uInt32 nMaBuFlags = rLev.mnExtParagraphMask;
 
                    if ( (!( nBuFlags & 0x00800000)) && ( nMaBuFlags & 0x00800000 ) )
                    {
                        if (!( nBuFlags & 0x02000000))          // if there is a BuStart without BuInstance,
                            nBuBlip = rLev.mnBuBlip;            // then there is no graphical Bullet possible
                    }
                    if ( (!( nBuFlags & 0x01000000)) && ( nMaBuFlags & 0x01000000 ) )
                        nAnmScheme = rLev.mnAnmScheme;
                    if ( (!( nBuFlags & 0x02000000)) && ( nMaBuFlags & 0x02000000 ) )
                        nHasAnm = rLev.mnHasAnm;
                    nBuFlags |= nMaBuFlags;
                }
            }
        }
    }
    if ( nBuBlip != 0xffff )        // set graphical bullet
    {
        Graphic aGraphic;
        if ( pParaProv && pParaProv->GetGraphic( nBuBlip, aGraphic ) )
        {
            SvxBrushItem aBrush( aGraphic, GPOS_MM, SID_ATTR_BRUSH );
            rNumberFormat.SetGraphicBrush( &aBrush );
            sal_uInt32 nHeight = static_cast<sal_uInt32>( static_cast<double>(nFontHeight) * 0.2540 * nBulletHeight + 0.5 );
            Size aPrefSize( aGraphic.GetPrefSize() );
            sal_uInt32 nWidth;
            if (aPrefSize.Height())
                nWidth = ( nHeight * aPrefSize.Width() ) / aPrefSize.Height();
            else
                nWidth = 0;
            rNumberFormat.SetGraphicSize( Size( nWidth, nHeight ) );
            rNumberFormat.SetNumberingType ( SVX_NUM_BITMAP );
        }
    }
    else if ( nHasAnm )
    {
        switch( static_cast< sal_uInt16 >( nAnmScheme ) )
        {
            default :
            case 0 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_CHARS_LOWER_LETTER );
                rNumberFormat.SetListFormat(u""_ustr, u"."_ustr, nLevel);
            }
            break;
            case 1 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_CHARS_UPPER_LETTER );
                rNumberFormat.SetListFormat(u""_ustr, u"."_ustr, nLevel);
            }
            break;
            case 2 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_ARABIC );
                rNumberFormat.SetListFormat(u""_ustr,  u")"_ustr, nLevel);
            }
            break;
            case 3 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_ARABIC );
                rNumberFormat.SetListFormat(u""_ustr, u"."_ustr, nLevel);
            }
            break;
            case 4 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_LOWER );
                rNumberFormat.SetListFormat(u"("_ustr, u")"_ustr, nLevel);
            }
            break;
            case 5 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_LOWER );
                rNumberFormat.SetListFormat(u""_ustr, u")"_ustr, nLevel);
            }
            break;
            case 6 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_LOWER );
                rNumberFormat.SetListFormat(u""_ustr, u"."_ustr, nLevel);
            }
            break;
            case 7 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_UPPER );
                rNumberFormat.SetListFormat(u""_ustr, u"."_ustr, nLevel);
            }
            break;
            case 8 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_CHARS_LOWER_LETTER );
                rNumberFormat.SetListFormat(u"("_ustr, u")"_ustr, nLevel);
            }
            break;
            case 9 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_CHARS_LOWER_LETTER );
                rNumberFormat.SetListFormat(u""_ustr, u")"_ustr, nLevel);
            }
            break;
            case 10 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_CHARS_UPPER_LETTER );
                rNumberFormat.SetListFormat(u"("_ustr, u")"_ustr, nLevel);
            }
            break;
            case 11 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_CHARS_UPPER_LETTER );
                rNumberFormat.SetListFormat(u""_ustr, u")"_ustr, nLevel);
            }
            break;
            case 12 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_ARABIC );
                rNumberFormat.SetListFormat(u"("_ustr, u")"_ustr, nLevel);
            }
            break;
            case 13 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_ARABIC );
            }
            break;
            case 14 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_UPPER );
                rNumberFormat.SetListFormat(u"("_ustr, u")"_ustr, nLevel);
            }
            break;
            case 15 :
            {
                rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_UPPER );
                rNumberFormat.SetListFormat(u""_ustr, u")"_ustr, nLevel);
            }
            break;
            case 16: // Simplified Chinese.
            {
                rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH );
            }
            break;
            case 17: // Simplified Chinese with single-byte period.
            {
                rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH );
                rNumberFormat.SetListFormat(u""_ustr, u"."_ustr, nLevel);
            }
            break;
            case 18: // Double byte circle numbers.
            case 19: // Wingdings white circle numbers.
            case 20: // Wingdings black circle numbers.
            {
                rNumberFormat.SetNumberingType( SVX_NUM_CIRCLE_NUMBER );
            }
            break;
            case 21: // Traditional Chinese.
            {
                rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH_TW );
            }
            break;
            case 22: // Traditional Chinese with single-byte period.
            {
                rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH_TW );
                rNumberFormat.SetListFormat(u""_ustr, u"."_ustr, nLevel);
            }
            break;
            case 25: // Bidi Hebrew 2 with ANSI minus symbol.
            {
                rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_HEBREW );
                rNumberFormat.SetListFormat(u""_ustr, u"-"_ustr, nLevel);
            }
            break;
            case 26: // Japanese/Korean.
            {
                rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_LOWER_ZH );
            }
            break;
            case 27: // Japanese/Korean with single-byte period.
            {
                rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_LOWER_ZH );
                rNumberFormat.SetListFormat(u""_ustr, u"."_ustr, nLevel);
            }
            break;
            case 28: // Double-byte Arabic numbers.
            {
                rNumberFormat.SetNumberingType( SVX_NUM_FULL_WIDTH_ARABIC );
            }
            break;
            case 29: // Double-byte Arabic numbers with double-byte period.
            {
                rNumberFormat.SetNumberingType( SVX_NUM_FULL_WIDTH_ARABIC );
                rNumberFormat.SetListFormat(u""_ustr, OUString(u'\xff0e'), nLevel);
            }
            break;
            case 38: // Japanese with double-byte period.
            {
                rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_LOWER_ZH ); // No such type. Instead with Lower Chinese Number
                rNumberFormat.SetListFormat(u""_ustr, OUString(u'\xff0e'), nLevel);
            }
            break;
        }
        rStartNumbering = std::optional< sal_Int16 >( nAnmScheme >> 16 );
        sal_Int16 nBuStart = *rStartNumbering;
        //The Seventh bit of nBuFlags that specifies whether fBulletHasAutoNumber exists,
        //and fBulletHasAutoNumber that specifies whether this paragraph has an automatic numbering scheme.
        if ( ( nBuFlags & 0x02000000 ) && ( nBuStart != -1 ))
        {
            rNumberFormat.SetStart( static_cast<sal_uInt16>(nBuStart) );
        }
    }
    return bHardAttribute;
}
 
void PPTNumberFormatCreator::GetNumberFormat( SdrPowerPointImport const & rManager, SvxNumberFormat& rNumberFormat, sal_uInt32 nLevel, const PPTParaLevel& rParaLevel, const PPTCharLevel& rCharLevel, TSS_Type nInstance )
{
    nIsBullet = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BulletOn ) ) != 0 ? 1 : 0;
    nBulletChar = rParaLevel.mnBulletChar;
 
    bool bBuHardFont;
    bBuHardFont = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardFont ) ) != 0;
    if ( bBuHardFont )
        nBulletFont = rParaLevel.mnBulletFont;
    else
        nBulletFont = rCharLevel.mnFont;
    nBulletHeight = rParaLevel.mnBulletHeight;
    nBulletColor = rParaLevel.mnBulletColor;
    nTextOfs = rParaLevel.mnTextOfs;
    nBulletOfs = rParaLevel.mnBulletOfs;
 
    std::optional< sal_Int16 > oStartNumbering;
    ImplGetExtNumberFormat( rManager, rNumberFormat, nLevel, nInstance, TSS_Type::Unknown, oStartNumbering, rCharLevel.mnFontHeight, nullptr );
    if ( ( rNumberFormat.GetNumberingType() != SVX_NUM_BITMAP ) && ( nBulletHeight > 0x7fff ) )
        nBulletHeight = rCharLevel.mnFontHeight ? ((- static_cast<sal_Int16>(nBulletHeight)) * 100 ) / rCharLevel.mnFontHeight : 100;
    ImplGetNumberFormat( rManager, rNumberFormat );
    switch ( rNumberFormat.GetNumberingType() )
    {
        case SVX_NUM_CHARS_UPPER_LETTER :
        case SVX_NUM_CHARS_LOWER_LETTER :
        case SVX_NUM_ROMAN_UPPER :
        case SVX_NUM_ROMAN_LOWER :
        case SVX_NUM_ARABIC :
        case SVX_NUM_CHARS_UPPER_LETTER_N :
        case SVX_NUM_CHARS_LOWER_LETTER_N :
        {
            sal_uInt32 nFont = rCharLevel.mnFont;
            const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nFont );
            if ( pFontEnityAtom )
            {
                vcl::Font aFont;
                aFont.SetCharSet( pFontEnityAtom->eCharSet );
                aFont.SetFamilyName( pFontEnityAtom->aName );
                aFont.SetFamily( pFontEnityAtom->eFamily );
                aFont.SetPitch( pFontEnityAtom->ePitch );
                rNumberFormat.SetBulletFont( &aFont );
            }
        }
        break;
        default: break;
    }
}
 
bool PPTNumberFormatCreator::GetNumberFormat( SdrPowerPointImport const & rManager, SvxNumberFormat& rNumberFormat, PPTParagraphObj* pParaObj,
                                                TSS_Type nDestinationInstance, std::optional< sal_Int16 >& rStartNumbering )
{
    sal_uInt32 nHardCount = 0;
    nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletOn, nIsBullet, nDestinationInstance ) ? 1 : 0;
    nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletChar, nBulletChar, nDestinationInstance ) ? 1 : 0;
    nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletFont, nBulletFont, nDestinationInstance ) ? 1 : 0;
    nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletHeight, nBulletHeight, nDestinationInstance ) ? 1 : 0;
    nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletColor, nBulletColor, nDestinationInstance ) ? 1 : 0;
    nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_TextOfs, nTextOfs, nDestinationInstance ) ? 1 : 0;
    nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletOfs, nBulletOfs, nDestinationInstance ) ? 1 : 0;
 
    if ( nIsBullet )
        rNumberFormat.SetNumberingType( SVX_NUM_CHAR_SPECIAL );
 
    sal_uInt32 nFontHeight = 24;
    PPTPortionObj* pPtr = pParaObj->First();
    if ( pPtr )
        pPtr->GetAttrib( PPT_CharAttr_FontHeight, nFontHeight, nDestinationInstance );
    if ( nIsBullet )
        nHardCount += ImplGetExtNumberFormat( rManager, rNumberFormat, pParaObj->mxParaSet->mnDepth,
                                                    pParaObj->mnInstance, nDestinationInstance, rStartNumbering, nFontHeight, pParaObj ) ? 1 : 0;
 
    if ( rNumberFormat.GetNumberingType() != SVX_NUM_BITMAP )
        pParaObj->UpdateBulletRelSize( nBulletHeight );
    if ( nHardCount )
    {
        ImplGetNumberFormat( rManager, rNumberFormat );
        switch ( rNumberFormat.GetNumberingType() )
        {
            case SVX_NUM_CHARS_UPPER_LETTER :
            case SVX_NUM_CHARS_LOWER_LETTER :
            case SVX_NUM_ROMAN_UPPER :
            case SVX_NUM_ROMAN_LOWER :
            case SVX_NUM_ARABIC :
            case SVX_NUM_CHARS_UPPER_LETTER_N :
            case SVX_NUM_CHARS_LOWER_LETTER_N :
            {
                if ( pPtr )
                {
                    sal_uInt32 nFont;
                    pPtr->GetAttrib( PPT_CharAttr_Font, nFont, nDestinationInstance );
                    const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nFont );
                    if ( pFontEnityAtom )
                    {
                        vcl::Font aFont;
                        aFont.SetCharSet( pFontEnityAtom->eCharSet );
                        aFont.SetFamilyName( pFontEnityAtom->aName );
                        aFont.SetFamily( pFontEnityAtom->eFamily );
                        aFont.SetPitch( pFontEnityAtom->ePitch );
                        rNumberFormat.SetBulletFont( &aFont );
                    }
                }
            }
            break;
            default: break;
        }
    }
    return nHardCount != 0;
}
 
void PPTNumberFormatCreator::ImplGetNumberFormat( SdrPowerPointImport const & rManager, SvxNumberFormat& rNumberFormat )
{
    vcl::Font aFont;
    const PptFontEntityAtom* pAtom = rManager.GetFontEnityAtom( nBulletFont );
    if ( pAtom )
    {
        rtl_TextEncoding eCharSet( pAtom->eCharSet );
        aFont.SetFamilyName( pAtom->aName );
        aFont.SetCharSet( eCharSet );
        aFont.SetFamily( pAtom->eFamily );
        aFont.SetPitch( pAtom->ePitch );
    }
    Color aCol( rManager.MSO_TEXT_CLR_ToColor( nBulletColor ) );
    aFont.SetColor( aCol );
 
    sal_uInt16 nBuChar = static_cast<sal_uInt16>(nBulletChar);
    if ( aFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL )
    {
        nBuChar &= 0x00ff;
        nBuChar |= 0xf000;
    }
    rNumberFormat.SetBulletFont( &aFont );
    rNumberFormat.SetBulletChar( nBuChar );
    rNumberFormat.SetBulletRelSize( static_cast<sal_uInt16>(nBulletHeight) );
    rNumberFormat.SetBulletColor( aCol );
    sal_uInt32 nAbsLSpace = convertMasterUnitToMm100(nTextOfs);
    sal_uInt32 nFirstLineOffset = nAbsLSpace - convertMasterUnitToMm100(nBulletOfs);
    rNumberFormat.SetAbsLSpace( nAbsLSpace );
    rNumberFormat.SetFirstLineOffset( -static_cast<sal_Int32>(nFirstLineOffset) );
}
 
PPTCharSheet::PPTCharSheet( TSS_Type nInstance )
{
    sal_uInt32 nColor = PPT_COLSCHEME_TEXT_UND_ZEILEN;
    sal_uInt16 nFontHeight(0);
    switch ( nInstance )
    {
        case TSS_Type::PageTitle :
        case TSS_Type::Title :
        {
            nColor = PPT_COLSCHEME_TITELTEXT;
            nFontHeight = 44;
        }
        break;
        case TSS_Type::Body :
        case TSS_Type::Subtitle :
        case TSS_Type::HalfBody :
        case TSS_Type::QuarterBody :
            nFontHeight = 32;
        break;
        case TSS_Type::Notes :
            nFontHeight = 12;
        break;
        case TSS_Type::Unused :
        case TSS_Type::TextInShape :
            nFontHeight = 24;
        break;
        default: break;
    }
    for (PPTCharLevel & nDepth : maCharLevel)
    {
        nDepth.mnFlags = 0;
        nDepth.mnFont = 0;
        nDepth.mnAsianOrComplexFont = 0xffff;
        nDepth.mnFontHeight = nFontHeight;
        nDepth.mnFontColor = nColor;
        nDepth.mnFontColorInStyleSheet = Color( static_cast<sal_uInt8>(nColor), static_cast<sal_uInt8>( nColor >> 8 ), static_cast<sal_uInt8>( nColor >> 16 ) );
        nDepth.mnEscapement = 0;
    }
}
 
void PPTCharSheet::Read( SvStream& rIn, sal_uInt32 nLevel)
{
    // character attributes
    sal_uInt32 nCMask(0);
    sal_uInt16 nVal16;
    rIn.ReadUInt32(nCMask);
 
    if ( nCMask & 0x0000FFFF )
    {
        sal_uInt16 nBitAttr(0);
        maCharLevel[ nLevel ].mnFlags &= ~static_cast<sal_uInt16>(nCMask);
        rIn.ReadUInt16( nBitAttr ); // Bit attributes (bold, underlined, ...)
        maCharLevel[ nLevel ].mnFlags |= nBitAttr;
    }
    if ( nCMask & ( 1 << PPT_CharAttr_Font ) )                  // 0x00010000
        rIn.ReadUInt16( maCharLevel[ nLevel ].mnFont );
    if ( nCMask & ( 1 << PPT_CharAttr_AsianOrComplexFont ) )    // 0x00200000
        rIn.ReadUInt16( maCharLevel[ nLevel ].mnAsianOrComplexFont );
    if ( nCMask & ( 1 << PPT_CharAttr_ANSITypeface ) )          // 0x00400000
        rIn.ReadUInt16( nVal16 );
    if ( nCMask & ( 1 << PPT_CharAttr_Symbol ) )                // 0x00800000
        rIn.ReadUInt16( nVal16 );
    if ( nCMask & ( 1 << PPT_CharAttr_FontHeight ) )            // 0x00020000
        rIn.ReadUInt16( maCharLevel[ nLevel ].mnFontHeight );
    if ( nCMask & ( 1 << PPT_CharAttr_FontColor ) )             // 0x00040000
    {
        rIn.ReadUInt32( maCharLevel[ nLevel ].mnFontColor );
        if( ! (maCharLevel[ nLevel ].mnFontColor & 0xff000000 ) )
            maCharLevel[ nLevel ].mnFontColor = PPT_COLSCHEME_HINTERGRUND;
    }
    if ( nCMask & ( 1 << PPT_CharAttr_Escapement ) )            // 0x00080000
        rIn.ReadUInt16( maCharLevel[ nLevel ].mnEscapement );
    if ( nCMask & 0x00100000 )                                  // 0x00100000
        rIn.ReadUInt16( nVal16 );
 
    nCMask >>= 24;
    while( nCMask )
    {
        if ( nCMask & 1 )
        {
            OSL_FAIL( "PPTCharSheet::Read - unknown attribute, send me this document (SJ)" );
            rIn.ReadUInt16( nVal16 );
        }
        nCMask >>= 1;
    }
}
 
PPTParaSheet::PPTParaSheet( TSS_Type nInstance )
{
    sal_uInt16 nBuFlags = 0;
    sal_uInt32 nBulletColor = 0x8000000;
    sal_uInt16 nUpperDist = 0;
 
    switch ( nInstance )
    {
        case TSS_Type::PageTitle :
        case TSS_Type::Title :
            nBulletColor = PPT_COLSCHEME_TITELTEXT;
        break;
        case TSS_Type::Body :
        case TSS_Type::Subtitle :
        case TSS_Type::HalfBody :
        case TSS_Type::QuarterBody :
        {
            nBuFlags = 1;
            nUpperDist = 0x14;
        }
        break;
        case TSS_Type::Notes :
            nUpperDist = 0x1e;
        break;
        default: break;
    }
    for (PPTParaLevel & i : maParaLevel)
    {
        i.mnBuFlags = nBuFlags;
        i.mnBulletChar = 0x2022;
        i.mnBulletFont = 0;
        i.mnBulletHeight = 100;
        i.mnBulletColor = nBulletColor;
        i.mnAdjust = 0;
        i.mnLineFeed = 100;
        i.mnLowerDist = 0;
        i.mnUpperDist = nUpperDist;
        i.mnTextOfs = 0;
        i.mnBulletOfs = 0;
        i.mnDefaultTab = 0x240;
        i.mnAsianLineBreak = 0;
        i.mnBiDi = 0;
    }
}
 
void PPTParaSheet::Read( SdrPowerPointImport const &
#ifdef DBG_UTIL
                    rManager
#endif
                    , SvStream& rIn
                    , sal_uInt32 nLevel, bool bFirst )
{
    // paragraph attributes
    sal_uInt32 nPMask(0);
    rIn.ReadUInt32(nPMask);
 
    sal_uInt16 nMask16 = static_cast<sal_uInt16>(nPMask) & 0xf;
    if ( nMask16 )
    {
        sal_uInt16 nVal16(0);
        rIn.ReadUInt16( nVal16 );
        maParaLevel[ nLevel ].mnBuFlags &=~ nMask16;
        nVal16 &= nMask16;
        maParaLevel[ nLevel ].mnBuFlags |= nVal16;
    }
    if ( nPMask & 0x0080 )
        rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletChar );
    if ( nPMask & 0x0010 )
        rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletFont );
    if ( nPMask & 0x0040 )
    {
        sal_uInt16 nVal16(0);
        rIn.ReadUInt16( nVal16 );
        maParaLevel[ nLevel ].mnBulletHeight = nVal16;
    }
    if ( nPMask & 0x0020 )
    {
        sal_uInt32 nVal32(0);
        rIn.ReadUInt32(nVal32);
        maParaLevel[ nLevel ].mnBulletColor = nVal32;
    }
    if ( bFirst )
    {
        if ( nPMask & 0xF00 )
        {
            // AbsJust!
            sal_uInt16 nVal16(0);
            rIn.ReadUInt16( nVal16 );
            maParaLevel[ nLevel ].mnAdjust = nVal16 & 3;
        }
        if ( nPMask & 0x1000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnLineFeed );
        if ( nPMask & 0x2000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnUpperDist );
        if ( nPMask & 0x4000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnLowerDist );
        if ( nPMask & 0x8000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnTextOfs );
        if ( nPMask & 0x10000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletOfs );
        if ( nPMask & 0x20000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnDefaultTab );
        if ( nPMask & 0x200000 )
        {
            sal_uInt16 nVal16;
            sal_uInt32 nVal32;
            // number of tabulators
            rIn.ReadUInt16( nVal16 );
            if (!rIn.good() || rIn.remainingSize() / sizeof(nVal32) < nVal16)
                return;
            for (sal_uInt16 i = 0; i < nVal16; ++i)
                rIn.ReadUInt32( nVal32 );      // reading the tabulators
        }
        if ( nPMask & 0x40000 )
        {
            sal_uInt16 nVal16;
            rIn.ReadUInt16( nVal16 );
        }
        if ( nPMask & 0x80000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnAsianLineBreak );
        if ( nPMask & 0x100000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnBiDi );
    }
    else
    {
        if ( nPMask & 0x800 )
        {
            sal_uInt16 nVal16(0);
            rIn.ReadUInt16( nVal16 );
            maParaLevel[ nLevel ].mnAdjust = nVal16 & 3;
        }
        if ( nPMask & 0x1000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnLineFeed );
        if ( nPMask & 0x2000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnUpperDist );
        if ( nPMask & 0x4000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnLowerDist );
        if ( nPMask & 0x8000 )
        {
            sal_uInt16 nVal16;
            rIn.ReadUInt16( nVal16 );
        }
        if ( nPMask & 0x100 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnTextOfs );
        if ( nPMask & 0x200 )
        {
            sal_uInt16 nVal16;
            rIn.ReadUInt16( nVal16 );
        }
        if ( nPMask & 0x400 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletOfs );
        if ( nPMask & 0x10000 )
        {
            sal_uInt16 nVal16;
            rIn.ReadUInt16( nVal16 );
        }
        if ( nPMask & 0xe0000 )
        {
            sal_uInt16 nFlagsToModifyMask = static_cast<sal_uInt16>( ( nPMask >> 17 ) & 7 );
            sal_uInt16 nVal16(0);
            rIn.ReadUInt16( nVal16 );
            // bits that are not involved to zero
            nVal16 &= nFlagsToModifyMask;
            // bits that are to change to zero
            maParaLevel[ nLevel ].mnAsianLineBreak &=~nFlagsToModifyMask;
            // now set the corresponding bits
            maParaLevel[ nLevel ].mnAsianLineBreak |= nVal16;
        }
        if ( nPMask & 0x100000 )
        {
            sal_uInt16 nVal16;
            sal_uInt32 nVal32;
            // number of tabulators
            rIn.ReadUInt16( nVal16 );
            if (!rIn.good() || rIn.remainingSize() / sizeof(nVal32) < nVal16)
                return;
            for (sal_uInt16 i = 0; i < nVal16; ++i)
                rIn.ReadUInt32( nVal32 );      // reading the tabulators
        }
        if ( nPMask & 0x200000 )
            rIn.ReadUInt16( maParaLevel[ nLevel ].mnBiDi );
    }
 
    nPMask >>= 22;
    while( nPMask )
    {
        if ( nPMask & 1 )
        {
#ifdef DBG_UTIL
            if (!(rManager.rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT))
            {
                OSL_FAIL( "PPTParaSheet::Read - unknown attribute, send me this document (SJ)" );
            }
#endif
            sal_uInt16 nVal16;
            rIn.ReadUInt16( nVal16 );
        }
        nPMask >>= 1;
    }
}
 
void PPTParaSheet::UpdateBulletRelSize(  sal_uInt32 nLevel, sal_uInt16 nFontHeight )
{
    if ( maParaLevel[ nLevel ].mnBulletHeight > 0x7fff ) // a negative value is the absolute bullet height
    {
        sal_Int16  nBulletRelSize = static_cast<sal_Int16>(maParaLevel[ nLevel ].mnBulletHeight);
        nBulletRelSize = nFontHeight ? ((-nBulletRelSize) * 100 ) / nFontHeight : 100;
        if ( nBulletRelSize < 0 ) //bullet size over flow
            nBulletRelSize = 100;
        maParaLevel[ nLevel ].mnBulletHeight = nBulletRelSize;
    }
}
 
PPTStyleSheet::PPTStyleSheet( const DffRecordHeader& rSlideHd, SvStream& rIn, SdrPowerPointImport& rManager,
                              const PPTTextParagraphStyleAtomInterpreter& rTxPFStyle,
                              const PPTTextSpecInfo& rTextSpecInfo ) :
 
    PPTNumberFormatCreator  ( std::make_unique<PPTExtParaProv>( rManager, rIn, &rSlideHd ) ),
    maTxSI                  ( rTextSpecInfo )
{
    sal_uInt64 nOldFilePos = rIn.Tell();
 
    // default stylesheets
    mpCharSheet[ TSS_Type::PageTitle ] = std::make_unique<PPTCharSheet>( TSS_Type::PageTitle );
    mpCharSheet[ TSS_Type::Body ] = std::make_unique<PPTCharSheet>( TSS_Type::Body );
    mpCharSheet[ TSS_Type::Notes ] = std::make_unique<PPTCharSheet>(  TSS_Type::Notes );
    mpCharSheet[ TSS_Type::Unused ] = std::make_unique<PPTCharSheet>( TSS_Type::Unused );   // this entry is not used by ppt
    mpCharSheet[ TSS_Type::TextInShape ] = std::make_unique<PPTCharSheet>( TSS_Type::TextInShape );
    mpParaSheet[ TSS_Type::PageTitle ] = std::make_unique<PPTParaSheet>( TSS_Type::PageTitle );
    mpParaSheet[ TSS_Type::Body ] = std::make_unique<PPTParaSheet>( TSS_Type::Body );
    mpParaSheet[ TSS_Type::Notes ] = std::make_unique<PPTParaSheet>( TSS_Type::Notes );
    mpParaSheet[ TSS_Type::Unused ] = std::make_unique<PPTParaSheet>( TSS_Type::Unused );
    mpParaSheet[ TSS_Type::TextInShape ] = std::make_unique<PPTParaSheet>( TSS_Type::TextInShape );
    // mpCharSheet[ TSS_Type::QuarterBody ], mpCharSheet[ TSS_Type::HalfBody ], mpCharSheet[ TSS_Type::Title ], mpCharSheet[ TSS_Type::Subtitle ] intentionally null
    // mpParaSheet[ TSS_Type::QuarterBody ], mpParaSheet[ TSS_Type::HalfBody ], mpParaSheet[ TSS_Type::Title ], mpParaSheet[ TSS_Type::Subtitle ] intentionally null
 
    /* SJ: try to locate the txMasterStyleAtom in the Environment
 
       it seems that the environment TextStyle is having a higher priority
       than the TextStyle that can be found within the master page
    */
    bool bFoundTxMasterStyleAtom04 = false;
    DffRecordHeader* pEnvHeader = rManager.aDocRecManager.GetRecordHeader( PPT_PST_Environment );
    if ( pEnvHeader )
    {
        pEnvHeader->SeekToContent( rIn );
        DffRecordHeader aTxMasterStyleHd;
        auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, pEnvHeader->GetRecEndFilePos());
        while (rIn.Tell() < nEndRecPos)
        {
            ReadDffRecordHeader( rIn, aTxMasterStyleHd );
            if ( aTxMasterStyleHd.nRecType == PPT_PST_TxMasterStyleAtom )
            {
                sal_uInt16 nLevelCnt(0);
                rIn.ReadUInt16(nLevelCnt);
 
                sal_uInt16 nLev = 0;
                bool bFirst = true;
                bFoundTxMasterStyleAtom04 = true;
                auto nTxEndRecPos = DffPropSet::SanitizeEndPos(rIn, aTxMasterStyleHd.GetRecEndFilePos());
                while (rIn.GetError() == ERRCODE_NONE && rIn.Tell() < nTxEndRecPos && nLev < nLevelCnt && nLev < nMaxPPTLevels)
                {
                    if ( nLev )
                    {
                        mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev ] = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev - 1 ];
                        mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ] = mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev - 1 ];
                    }
                    mpParaSheet[ TSS_Type::TextInShape ]->Read( rManager, rIn, nLev, bFirst );
                    if ( !nLev )
                    {
                        // set paragraph defaults for instance 4 (TSS_Type::TextInShape)
                        if ( rTxPFStyle.bValid )
                        {
                            PPTParaLevel& rParaLevel = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ 0 ];
                            rParaLevel.mnAsianLineBreak = 0;
                            if ( rTxPFStyle.bForbiddenRules )
                                rParaLevel.mnAsianLineBreak |= 1;
                            if ( !rTxPFStyle.bLatinTextWrap )
                                rParaLevel.mnAsianLineBreak |= 2;
                            if ( rTxPFStyle.bHangingPunctuation )
                                rParaLevel.mnAsianLineBreak |= 4;
                        }
                    }
                    mpCharSheet[ TSS_Type::TextInShape ]->Read( rIn, nLev );
                    mpParaSheet[ TSS_Type::TextInShape ]->UpdateBulletRelSize(  nLev, mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ].mnFontHeight );
                    bFirst = false;
                    nLev++;
                }
                break;
            }
            else
            {
                if (!aTxMasterStyleHd.SeekToEndOfRecord(rIn))
                    break;
            }
        }
    }
 
    rSlideHd.SeekToContent( rIn );
 
    DffRecordHeader aTxMasterStyleHd;
    auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, rSlideHd.GetRecEndFilePos());
    while (rIn.Tell() < nEndRecPos)
    {
        ReadDffRecordHeader( rIn, aTxMasterStyleHd );
        if ( aTxMasterStyleHd.nRecType == PPT_PST_TxMasterStyleAtom )
            break;
        else
        {
            if (!aTxMasterStyleHd.SeekToEndOfRecord(rIn))
                break;
        }
    }
    while ( ( aTxMasterStyleHd.nRecType == PPT_PST_TxMasterStyleAtom ) && ( rIn.Tell() < nEndRecPos ) ) //TODO: aTxMasterStyleHd may be used without having been properly initialized
    {
        TSS_Type nInstance = static_cast<TSS_Type>(aTxMasterStyleHd.nRecInstance);
        if ( ( nInstance <= TSS_Type::LAST ) &&
            ( ( nInstance != TSS_Type::TextInShape ) || !bFoundTxMasterStyleAtom04 ) )
        {
            if ( nInstance > TSS_Type::TextInShape )
            {
                mpCharSheet[ nInstance ].reset();    // be sure to delete the old one if this instance comes twice
                mpParaSheet[ nInstance ].reset();
 
                switch ( nInstance )
                {
                    case TSS_Type::Subtitle :
                    {
                        mpCharSheet[ TSS_Type::Subtitle ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
                        mpParaSheet[ TSS_Type::Subtitle ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
                    }
                    break;
                    case TSS_Type::Title :
                    {
                        mpCharSheet[ TSS_Type::Title ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::PageTitle ] ) );
                        mpParaSheet[ TSS_Type::Title ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::PageTitle ] ) );
                    }
                    break;
                    case TSS_Type::HalfBody :
                    {
                        mpCharSheet[ TSS_Type::HalfBody ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
                        mpParaSheet[ TSS_Type::HalfBody ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
                    }
                    break;
 
                    case TSS_Type::QuarterBody :
                    {
                        mpCharSheet[ TSS_Type::QuarterBody ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
                        mpParaSheet[ TSS_Type::QuarterBody ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
                    }
                    break;
                    default: break;
                }
            }
            sal_uInt16 nLevelCnt(0);
            rIn.ReadUInt16(nLevelCnt);
            if (nLevelCnt > nMaxPPTLevels)
            {
                OSL_FAIL( "PPTStyleSheet::Ppt-TextStylesheet has more than 5 levels! (SJ)" );
                nLevelCnt = nMaxPPTLevels;
            }
            sal_uInt16  nLev = 0;
            bool    bFirst = true;
 
            auto nTxEndRecPos = DffPropSet::SanitizeEndPos(rIn, aTxMasterStyleHd.GetRecEndFilePos());
            while ( rIn.GetError() == ERRCODE_NONE && rIn.Tell() < nTxEndRecPos && nLev < nLevelCnt )
            {
                if ( nLev && ( nInstance < TSS_Type::Subtitle ) )
                {
                    mpParaSheet[ nInstance ]->maParaLevel[ nLev ] = mpParaSheet[ nInstance ]->maParaLevel[ nLev - 1 ];
                    mpCharSheet[ nInstance ]->maCharLevel[ nLev ] = mpCharSheet[ nInstance ]->maCharLevel[ nLev - 1 ];
                }
 
                // Exception: Template 5, 6 (MasterTitle Title and SubTitle)
                if ( nInstance >= TSS_Type::Subtitle )
                {
                    bFirst = false;
 
                    sal_uInt16 nDontKnow;
                    rIn.ReadUInt16( nDontKnow );
                }
                mpParaSheet[ nInstance ]->Read( rManager, rIn, nLev, bFirst );
                mpCharSheet[ nInstance ]->Read( rIn, nLev );
                mpParaSheet[ nInstance ]->UpdateBulletRelSize(  nLev, mpCharSheet[ nInstance ]->maCharLevel[ nLev ].mnFontHeight );
                bFirst = false;
                nLev++;
            }
#ifdef DBG_UTIL
            if (!(rManager.rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT))
            {
                if ( rIn.GetError() == ERRCODE_NONE )
                {
                    OStringBuffer aMsg;
                    if ( rIn.Tell() > aTxMasterStyleHd.GetRecEndFilePos() )
                    {
                        aMsg.append("\n  reading too many bytes:" +
                                    OString::number(rIn.Tell() - aTxMasterStyleHd.GetRecEndFilePos()));
                    }
                    if ( rIn.Tell() < aTxMasterStyleHd.GetRecEndFilePos() )
                    {
                        aMsg.append("\n  reading too few bytes:" +
                                    OString::number(aTxMasterStyleHd.GetRecEndFilePos() - rIn.Tell()));
                    }
                    if (aMsg.getLength())
                    {
                        aMsg.insert(0, "PptStyleSheet::operator>>[]");
                        OSL_FAIL(aMsg.getStr());
                    }
                }
                if ( rIn.Tell() != aTxMasterStyleHd.GetRecEndFilePos() )
                    SAL_WARN( "filter.ms", "SJ: Wrong number of bytes read during import of PPT style");
            }
#endif
        }
        if (!aTxMasterStyleHd.SeekToEndOfRecord(rIn))
            break;
        ReadDffRecordHeader( rIn, aTxMasterStyleHd );
    }
    if ( !mpCharSheet[ TSS_Type::Subtitle ] )
    {
        mpCharSheet[ TSS_Type::Subtitle ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
        mpParaSheet[ TSS_Type::Subtitle ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
    }
    if ( !mpCharSheet[ TSS_Type::Title ] )
    {
        mpCharSheet[ TSS_Type::Title ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::PageTitle ] ) );
        mpParaSheet[ TSS_Type::Title ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::PageTitle ] ) );
    }
    if ( !mpCharSheet[ TSS_Type::HalfBody ] )
    {
        mpCharSheet[ TSS_Type::HalfBody ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
        mpParaSheet[ TSS_Type::HalfBody ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
    }
    if ( !mpCharSheet[ TSS_Type::QuarterBody ] )
    {
        mpCharSheet[ TSS_Type::QuarterBody ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
        mpParaSheet[ TSS_Type::QuarterBody ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
    }
    if ( !bFoundTxMasterStyleAtom04 )
    {   // try to locate the txMasterStyleAtom in the Environment
        DffRecordHeader* pEnvHeader2 = rManager.aDocRecManager.GetRecordHeader( PPT_PST_Environment );
        if ( pEnvHeader2 )
        {
            pEnvHeader2->SeekToContent( rIn );
            DffRecordHeader aTxMasterStyleHd2;
            auto nEnvEndRecPos = DffPropSet::SanitizeEndPos(rIn, pEnvHeader2->GetRecEndFilePos());
            while (rIn.Tell() < nEnvEndRecPos)
            {
                ReadDffRecordHeader( rIn, aTxMasterStyleHd2 );
                if ( aTxMasterStyleHd2.nRecType == PPT_PST_TxMasterStyleAtom )
                {
                    sal_uInt16 nLevelCnt;
                    rIn.ReadUInt16( nLevelCnt );
 
                    sal_uInt16 nLev = 0;
                    bool bFirst = true;
                    auto nTxEndRecPos = DffPropSet::SanitizeEndPos(rIn, aTxMasterStyleHd2.GetRecEndFilePos());
                    while ( rIn.GetError() == ERRCODE_NONE && rIn.Tell() < nTxEndRecPos && nLev < nLevelCnt )
                    {
                        if ( nLev )
                        {
                            mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev ] = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev - 1 ];
                            mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ] = mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev - 1 ];
                        }
                        mpParaSheet[ TSS_Type::TextInShape ]->Read( rManager, rIn, nLev, bFirst );
                        if ( !nLev )
                        {
                            // set paragraph defaults for instance 4 (TSS_Type::TextInShape)
                            if ( rTxPFStyle.bValid )
                            {
                                PPTParaLevel& rParaLevel = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ 0 ];
                                rParaLevel.mnAsianLineBreak = 0;
                                if ( rTxPFStyle.bForbiddenRules )
                                    rParaLevel.mnAsianLineBreak |= 1;
                                if ( !rTxPFStyle.bLatinTextWrap )
                                    rParaLevel.mnAsianLineBreak |= 2;
                                if ( rTxPFStyle.bHangingPunctuation )
                                    rParaLevel.mnAsianLineBreak |= 4;
                            }
                        }
                        mpCharSheet[ TSS_Type::TextInShape ]->Read( rIn, nLev );
                        mpParaSheet[ TSS_Type::TextInShape ]->UpdateBulletRelSize(  nLev, mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ].mnFontHeight );
                        bFirst = false;
                        nLev++;
                    }
                    break;
                }
                else
                {
                    if (!aTxMasterStyleHd2.SeekToEndOfRecord(rIn))
                        break;
                }
            }
        }
    }
    rIn.Seek( nOldFilePos );
 
    // will create the default numbulletitem for each instance
    for ( auto i : o3tl::enumrange<TSS_Type>() )
    {
        sal_uInt16          nLevels, nDepth = 0;
        SvxNumRuleType  eNumRuleType;
 
        switch ( i )
        {
            case TSS_Type::PageTitle :
            case TSS_Type::Title :
                nLevels = 1;
                eNumRuleType = SvxNumRuleType::NUMBERING;
            break;
            case TSS_Type::Subtitle :
                nLevels = SVX_MAX_NUM;
                eNumRuleType = SvxNumRuleType::NUMBERING;
            break;
            case TSS_Type::Body :
            case TSS_Type::HalfBody :
            case TSS_Type::QuarterBody :
                nLevels = SVX_MAX_NUM;
                eNumRuleType = SvxNumRuleType::PRESENTATION_NUMBERING;
            break;
            default :
            case TSS_Type::Notes :
            case TSS_Type::Unused :
            case TSS_Type::TextInShape :
                nLevels = SVX_MAX_NUM;
                eNumRuleType = SvxNumRuleType::NUMBERING;
            break;
        }
        SvxNumRule aRule( SvxNumRuleFlags::BULLET_REL_SIZE | SvxNumRuleFlags::BULLET_COLOR,
                        nLevels, false, eNumRuleType );
        for ( sal_uInt16 nCount = 0; nDepth < nLevels; nCount++ )
        {
            const PPTParaLevel& rParaLevel = mpParaSheet[ i ]->maParaLevel[ nCount ];
            const PPTCharLevel& rCharLevel = mpCharSheet[ i ]->maCharLevel[ nCount ];
            SvxNumberFormat aNumberFormat( SVX_NUM_CHAR_SPECIAL );
            aNumberFormat.SetBulletChar( ' ' );
            GetNumberFormat( rManager, aNumberFormat, nCount, rParaLevel, rCharLevel, i );
            aRule.SetLevel( nDepth++, aNumberFormat );
            if ( nCount >= 4 )
            {
                for ( ;nDepth < nLevels; nDepth++ )
                    aRule.SetLevel( nDepth, aNumberFormat );
            }
        }
        mpNumBulletItem[ i ] = std::make_unique<SvxNumBulletItem>( std::move(aRule), EE_PARA_NUMBULLET );
    }
}
 
PPTStyleSheet::~PPTStyleSheet()
{
    for ( auto i : o3tl::enumrange<TSS_Type>() )
    {
        mpCharSheet[i].reset();
        mpParaSheet[i].reset();
        mpNumBulletItem[i].reset();
    }
}
 
PPTParaPropSet::PPTParaPropSet()
    : mnOriginalTextPos(0)
    , mxParaSet( new ImplPPTParaPropSet )
{
    mxParaSet->mnHasAnm = 1;
}
 
PPTParaPropSet::PPTParaPropSet( PPTParaPropSet const & rParaPropSet )
{
    mxParaSet = rParaPropSet.mxParaSet;
    mnOriginalTextPos = rParaPropSet.mnOriginalTextPos;
}
 
PPTParaPropSet::~PPTParaPropSet()
{
}
 
PPTParaPropSet& PPTParaPropSet::operator=( const PPTParaPropSet& rParaPropSet )
{
    if ( this != &rParaPropSet )
    {
        mxParaSet = rParaPropSet.mxParaSet;
        mnOriginalTextPos = rParaPropSet.mnOriginalTextPos;
    }
    return *this;
}
 
PPTCharPropSet::PPTCharPropSet(sal_uInt32 nParagraph)
    : mnOriginalTextPos(0)
    , mnParagraph(nParagraph)
{
    mnHylinkOrigColor = 0;
    mbIsHyperlink = false;
    mbHardHylinkOrigColor = false;
    mnLanguage[ 0 ] = mnLanguage[ 1 ] = mnLanguage[ 2 ] = LANGUAGE_SYSTEM;
}
 
PPTCharPropSet::PPTCharPropSet( const PPTCharPropSet& rCharPropSet )
    : mpImplPPTCharPropSet( rCharPropSet.mpImplPPTCharPropSet )
{
    mnHylinkOrigColor = rCharPropSet.mnHylinkOrigColor;
    mbIsHyperlink = rCharPropSet.mbIsHyperlink;
    mbHardHylinkOrigColor = rCharPropSet.mbHardHylinkOrigColor;
 
    mnParagraph = rCharPropSet.mnParagraph;
    mnOriginalTextPos = rCharPropSet.mnOriginalTextPos;
    maString = rCharPropSet.maString;
    mpFieldItem.reset( rCharPropSet.mpFieldItem ? new SvxFieldItem( *rCharPropSet.mpFieldItem ) : nullptr );
    mnLanguage[ 0 ] = rCharPropSet.mnLanguage[ 0 ];
    mnLanguage[ 1 ] = rCharPropSet.mnLanguage[ 1 ];
    mnLanguage[ 2 ] = rCharPropSet.mnLanguage[ 2 ];
}
 
PPTCharPropSet::PPTCharPropSet( const PPTCharPropSet& rCharPropSet, sal_uInt32 nParagraph )
    : mpImplPPTCharPropSet(rCharPropSet.mpImplPPTCharPropSet)
{
    mnHylinkOrigColor = rCharPropSet.mnHylinkOrigColor;
    mbIsHyperlink = rCharPropSet.mbIsHyperlink;
    mbHardHylinkOrigColor = rCharPropSet.mbHardHylinkOrigColor;
 
    mnParagraph = nParagraph;
    mnOriginalTextPos = rCharPropSet.mnOriginalTextPos;
    maString = rCharPropSet.maString;
    mpFieldItem.reset( rCharPropSet.mpFieldItem ? new SvxFieldItem( *rCharPropSet.mpFieldItem ) : nullptr );
    mnLanguage[ 0 ] = mnLanguage[ 1 ] = mnLanguage[ 2 ] = LANGUAGE_SYSTEM;
}
 
PPTCharPropSet::~PPTCharPropSet()
{
}
 
PPTCharPropSet& PPTCharPropSet::operator=( const PPTCharPropSet& rCharPropSet )
{
    if ( this != &rCharPropSet )
    {
        mpImplPPTCharPropSet = rCharPropSet.mpImplPPTCharPropSet;
        mnOriginalTextPos = rCharPropSet.mnOriginalTextPos;
        mnParagraph = rCharPropSet.mnParagraph;
        maString = rCharPropSet.maString;
        mpFieldItem.reset( rCharPropSet.mpFieldItem ? new SvxFieldItem( *rCharPropSet.mpFieldItem ) : nullptr );
    }
    return *this;
}
 
void PPTCharPropSet::SetFont( sal_uInt16 nFont )
{
    sal_uInt32  nMask = 1 << PPT_CharAttr_Font;
    bool bDoNotMake = (mpImplPPTCharPropSet->mnAttrSet & nMask) != 0;
 
    if ( bDoNotMake )
        bDoNotMake = nFont == mpImplPPTCharPropSet->mnFont;
 
    if ( !bDoNotMake )
    {
        mpImplPPTCharPropSet->mnFont = nFont;
        mpImplPPTCharPropSet->mnAttrSet |= nMask;
    }
}
 
void PPTCharPropSet::SetColor( sal_uInt32 nColor )
{
    mpImplPPTCharPropSet->mnColor = nColor;
    mpImplPPTCharPropSet->mnAttrSet |= 1 << PPT_CharAttr_FontColor;
}
 
PPTRuler::PPTRuler()
    : nFlags(0)
    , nDefaultTab(0x240)
    , nTabCount(0)
{
}
 
PPTRuler::~PPTRuler()
{
};
 
 
PPTTextRulerInterpreter::PPTTextRulerInterpreter() :
    mxImplRuler ( new PPTRuler() )
{
}
 
PPTTextRulerInterpreter::PPTTextRulerInterpreter( PPTTextRulerInterpreter const & rRuler )
{
    mxImplRuler = rRuler.mxImplRuler;
}
 
PPTTextRulerInterpreter::PPTTextRulerInterpreter( sal_uInt32 nFileOfs, DffRecordHeader const & rHeader, SvStream& rIn ) :
    mxImplRuler ( new PPTRuler() )
{
    if ( nFileOfs == 0xffffffff )
        return;
 
    sal_uInt64 nOldPos = rIn.Tell();
    DffRecordHeader rHd;
    if ( nFileOfs )
    {
        rIn.Seek( nFileOfs );
        ReadDffRecordHeader( rIn, rHd );
    }
    else
    {
        rHeader.SeekToContent( rIn );
        if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextRulerAtom, rHeader.GetRecEndFilePos(), &rHd ) )
            nFileOfs++;
    }
    if ( nFileOfs )
    {
        bool bRecordOk = true;
 
        sal_Int16   nTCount(0);
        sal_Int32   i;
        rIn.ReadInt32( mxImplRuler->nFlags );
 
        // number of indent levels, unused now
        if ( mxImplRuler->nFlags & 2 )
            rIn.ReadInt16( nTCount );
        if ( mxImplRuler->nFlags & 1 )
            rIn.ReadUInt16( mxImplRuler->nDefaultTab );
        if ( mxImplRuler->nFlags & 4 )
        {
            rIn.ReadInt16(nTCount);
 
            const size_t nMaxPossibleRecords = rIn.remainingSize() / (2*sizeof(sal_uInt16));
            const sal_uInt16 nTabCount(nTCount);
 
            bRecordOk = nTabCount <= nMaxPossibleRecords;
 
            if (nTCount && bRecordOk)
            {
                mxImplRuler->nTabCount = nTabCount;
                mxImplRuler->pTab.reset( new PPTTabEntry[ mxImplRuler->nTabCount ] );
                for ( i = 0; i < nTCount; i++ )
                {
                    rIn.ReadUInt16( mxImplRuler->pTab[ i ].nOffset )
                       .ReadUInt16( mxImplRuler->pTab[ i ].nStyle );
                }
            }
        }
 
        if (bRecordOk)
        {
            for ( i = 0; i < 5; i++ )
            {
                if ( mxImplRuler->nFlags & ( 8 << i ) )
                    rIn.ReadUInt16( mxImplRuler->nTextOfs[ i ] );
                if ( mxImplRuler->nFlags & ( 256 << i ) )
                    rIn.ReadUInt16( mxImplRuler->nBulletOfs[ i ] );
                if( mxImplRuler->nBulletOfs[ i ] > 0x7fff)
                {
                    // workaround
                    // when bullet offset is > 0x7fff, the paragraph should look like
                    // *    first line text
                    // second line text
 
                    // we add to bullet para indent 0xffff - bullet offset. It looks like
                    // best we can do for now
                    mxImplRuler->nTextOfs[ i ] += 0xffff - mxImplRuler->nBulletOfs[ i ];
                    mxImplRuler->nBulletOfs[ i ] = 0;
                }
            }
        }
    }
    rIn.Seek( nOldPos );
}
 
bool PPTTextRulerInterpreter::GetDefaultTab( sal_uInt16& nValue ) const
{
    if ( ! ( mxImplRuler->nFlags & 1 ) )
        return false;
    nValue = mxImplRuler->nDefaultTab;
    return true;
}
 
bool PPTTextRulerInterpreter::GetTextOfs( sal_uInt32 nLevel, sal_uInt16& nValue ) const
{
    if ( ! ( ( nLevel < 5 ) && ( mxImplRuler->nFlags & ( 8 << nLevel ) ) ) )
        return false;
    nValue = mxImplRuler->nTextOfs[ nLevel ];
    return true;
}
 
bool PPTTextRulerInterpreter::GetBulletOfs( sal_uInt32 nLevel, sal_uInt16& nValue ) const
{
    if ( ! ( ( nLevel < 5 ) && ( mxImplRuler->nFlags & ( 256 << nLevel ) ) ) )
        return false;
    nValue = mxImplRuler->nBulletOfs[ nLevel ];
    return true;
}
 
PPTTextRulerInterpreter& PPTTextRulerInterpreter::operator=( const PPTTextRulerInterpreter& rRuler )
{
    if ( this != &rRuler )
    {
        mxImplRuler = rRuler.mxImplRuler;
    }
    return *this;
}
 
PPTTextRulerInterpreter::~PPTTextRulerInterpreter()
{
}
 
PPTTextParagraphStyleAtomInterpreter::PPTTextParagraphStyleAtomInterpreter() :
    bValid              ( false ),
    bForbiddenRules     ( false ),
    bHangingPunctuation ( false ),
    bLatinTextWrap      ( false )
{
}
 
bool PPTTextParagraphStyleAtomInterpreter::Read( SvStream& rIn, const DffRecordHeader& rRecHd )
{
    bValid = false;
    rRecHd.SeekToContent( rIn );
    sal_uInt32 nDummy32, nFlags, nRecEndPos = rRecHd.GetRecEndFilePos();
    sal_uInt16 nDummy16;
 
    rIn.ReadUInt16( nDummy16 )
       .ReadUInt32( nFlags );
 
    if ( nFlags & 0xf && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );    // BuFlags
    if ( nFlags & 0x80 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );    // BuChar
    if ( nFlags & 0x10 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );    // nBuFont;
    if ( nFlags & 0x40 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );    // nBuHeight;
    if ( nFlags & 0x0020 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt32( nDummy32 );    // nBuColor;
    if ( nFlags & 0x800 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );    // AbsJust!
    if ( nFlags & 0x400 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );
    if ( nFlags & 0x200 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );
    if ( nFlags & 0x100 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );
    if ( nFlags & 0x1000 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );    // LineFeed
    if ( nFlags & 0x2000 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );    // nUpperDist
    if ( nFlags & 0x4000 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );    // nLowerDist
    if ( nFlags & 0x8000 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );
    if ( nFlags & 0x10000 && ( rIn.Tell() < nRecEndPos ) )
        rIn.ReadUInt16( nDummy16 );
    if ( nFlags & 0xe0000 && ( rIn.Tell() < nRecEndPos ) )
    {
        rIn.ReadUInt16( nDummy16 );
        if ( nFlags & 0x20000 )
            bForbiddenRules = ( nDummy16 & 1 ) == 1;
        if ( nFlags & 0x40000 )
            bLatinTextWrap = ( nDummy16 & 2 ) == 0;
        if ( nFlags & 0x80000 )
            bHangingPunctuation = ( nDummy16 & 4 ) == 4;
    }
    nFlags &=~ 0xfffff;
    sal_uInt32 nMask = 0x100000;
    while ( nFlags && nMask && ( rIn.Tell() < nRecEndPos ) )
    {
        if ( nFlags & nMask )
        {
            rIn.ReadUInt16( nDummy16 );
            nFlags ^= nMask;
        }
        nMask <<= 1;
    }
    bValid = rIn.Tell() == nRecEndPos;
    return bValid;
}
 
PPTTextSpecInfo::PPTTextSpecInfo( sal_uInt32 _nCharIdx ) :
    nCharIdx        ( _nCharIdx ),
    nDontKnow       ( 1 )
{
    nLanguage[ 0 ] = LANGUAGE_PROCESS_OR_USER_DEFAULT;
    nLanguage[ 1 ] = LANGUAGE_SYSTEM;
    nLanguage[ 2 ] = LANGUAGE_SYSTEM;
}
 
PPTTextSpecInfoAtomInterpreter::PPTTextSpecInfoAtomInterpreter() :
    bValid  ( false )
{
}
 
bool PPTTextSpecInfoAtomInterpreter::Read( SvStream& rIn, const DffRecordHeader& rRecHd,
    sal_uInt16 nRecordType, const PPTTextSpecInfo* pTextSpecDefault )
{
    bValid = false;
    sal_uInt32  nCharIdx = 0;
    rRecHd.SeekToContent( rIn );
 
    auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, rRecHd.GetRecEndFilePos());
    while (rIn.Tell() < nEndRecPos && rIn.good())
    {
        if ( nRecordType == PPT_PST_TextSpecInfoAtom )
        {
            sal_uInt32 nCharCount(0);
            rIn.ReadUInt32( nCharCount );
            nCharIdx += nCharCount;
        }
 
        sal_uInt32 nFlags(0);
        rIn.ReadUInt32(nFlags);
 
        PPTTextSpecInfo aEntry( nCharIdx );
        if ( pTextSpecDefault )
        {
            aEntry.nDontKnow = pTextSpecDefault->nDontKnow;
            aEntry.nLanguage[ 0 ] = pTextSpecDefault->nLanguage[ 0 ];
            aEntry.nLanguage[ 1 ] = pTextSpecDefault->nLanguage[ 1 ];
            aEntry.nLanguage[ 2 ] = pTextSpecDefault->nLanguage[ 2 ];
        }
        for (sal_uInt32 i = 1; nFlags && i ; i <<= 1)
        {
            sal_uInt16 nLang = 0;
            switch( nFlags & i )
            {
                case 0 : break;
                case 1 : rIn.ReadUInt16( aEntry.nDontKnow ); break;
                case 2 : rIn.ReadUInt16( nLang ); break;
                case 4 : rIn.ReadUInt16( nLang ); break;
                default :
                {
                    rIn.SeekRel( 2 );
                }
            }
            if ( nLang )
            {
                // #i119985#, we could probably handle this better if we have a
                // place to override the final language for weak
                // characters/fields to fallback to, rather than the current
                // application locale. Assuming that we can determine what the
                // default fallback language for a given .ppt, etc is during
                // load time.
                if (i == 2)
                {
                    aEntry.nLanguage[ 0 ] = aEntry.nLanguage[ 1 ] = aEntry.nLanguage[ 2 ] = LanguageType(nLang);
                }
            }
            nFlags &= ~i;
        }
        aList.push_back( aEntry );
    }
    bValid = rIn.Tell() == rRecHd.GetRecEndFilePos();
    return bValid;
}
 
PPTTextSpecInfoAtomInterpreter::~PPTTextSpecInfoAtomInterpreter()
{
}
 
void StyleTextProp9::Read( SvStream& rIn )
{
    rIn.ReadUInt32( mnExtParagraphMask );
    if ( mnExtParagraphMask & 0x800000 )
        rIn.ReadUInt16( mnBuBlip );
    if ( mnExtParagraphMask & 0x2000000 )
        rIn.ReadUInt16( mnHasAnm );
    if ( mnExtParagraphMask & 0x1000000 )
        rIn.ReadUInt32( mnAnmScheme );
    if ( mnExtParagraphMask & 0x4000000 )
        rIn.ReadUInt32( mpfPP10Ext );
    rIn.ReadUInt32( mnExtCharacterMask );
    if ( mnExtCharacterMask & 0x100000 )
        rIn.ReadUInt32( mncfPP10Ext );
    rIn.ReadUInt32( mnSpecialInfoMask );
    if ( mnSpecialInfoMask & 0x20 )
        rIn.ReadUInt32( mnPP10Ext );
    if ( mnSpecialInfoMask & 0x40 )
        rIn.ReadUInt16( mfBidi );
}
 
PPTStyleTextPropReader::PPTStyleTextPropReader( SvStream& rIn, const DffRecordHeader& rTextHeader,
                                                        PPTTextRulerInterpreter const & rRuler, const DffRecordHeader& rExtParaHd, TSS_Type nInstance )
{
    Init(rIn, rTextHeader, rRuler, rExtParaHd, nInstance);
}
 
void PPTStyleTextPropReader::ReadParaProps( SvStream& rIn, const DffRecordHeader& rTextHeader,
                                            const OUString& aString, PPTTextRulerInterpreter const & rRuler,
                                            sal_uInt32& nCharCount, bool& bTextPropAtom )
{
    sal_uInt32  nMask = 0; //TODO: nMask initialized here to suppress warning for now, see corresponding TODO below
    sal_uInt32  nCharReadCnt = 0;
    sal_uInt16  nDummy16;
 
    sal_uInt16 nStringLen = aString.getLength();
 
    DffRecordHeader aTextHd2;
    rTextHeader.SeekToContent( rIn );
    if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_StyleTextPropAtom, rTextHeader.GetRecEndFilePos(), &aTextHd2 ) )
        bTextPropAtom = true;
    while ( nCharReadCnt <= nStringLen )
    {
        PPTParaPropSet aParaPropSet;
        ImplPPTParaPropSet& aSet = *aParaPropSet.mxParaSet;
        if ( bTextPropAtom )
        {
            rIn.ReadUInt32( nCharCount )
               .ReadUInt16( aParaPropSet.mxParaSet->mnDepth );  // indent depth
 
            aParaPropSet.mxParaSet->mnDepth =        // taking care of about using not more than 9 outliner levels
                std::min(sal_uInt16(8),
                    aParaPropSet.mxParaSet->mnDepth);
 
            nCharCount--;
 
            rIn.ReadUInt32( nMask );
            aSet.mnAttrSet = nMask & 0x207df7;
            sal_uInt16 nBulFlg = 0;
            if ( nMask & 0xF )
                rIn.ReadUInt16( nBulFlg ); // Bullet-HardAttr-Flags
            aSet.mpArry[ PPT_ParaAttr_BulletOn    ] = ( nBulFlg & 1 ) ? 1 : 0;
            aSet.mpArry[ PPT_ParaAttr_BuHardFont  ] = ( nBulFlg & 2 ) ? 1 : 0;
            aSet.mpArry[ PPT_ParaAttr_BuHardColor ] = ( nBulFlg & 4 ) ? 1 : 0;
 
            // NOTE: one might think that the hard-coded numbers here are the
            // same as the PPT_ParaAttr_* constants, but it's NOT always true!
            if ( nMask & 0x0080 )   // buChar
            {
                rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletChar ] );
                if (!rIn.good())
                {
                    aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletChar);
                }
            }
            if ( nMask & 0x0010 )   // buTypeface
            {
                rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletFont ] );
                if (!rIn.good())
                {
                    aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletFont);
                }
            }
            if ( nMask & 0x0040 )   // buSize
            {
                rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletHeight ] );
                if (!rIn.good()
                    || !((nMask & (1 << PPT_ParaAttr_BuHardHeight))
                         && (nBulFlg & (1 << PPT_ParaAttr_BuHardHeight))))
                {
                    aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletHeight);
                }
            }
            if ( nMask & 0x0020 )   // buColor
            {
                sal_uInt32 nVal32;
                rIn.ReadUInt32( nVal32 );
                if (!rIn.good())
                {
                    aSet.mnBulletColor = 0; // no flag for this? default it
                }
                else
                {
                    sal_uInt32 nHiByte;
                    nHiByte = nVal32 >> 24;
                    if ( nHiByte <= 8 )
                        nVal32 = nHiByte | PPT_COLSCHEME;
                    aSet.mnBulletColor = nVal32;
                }
            }
            if ( nMask & 0x0800 )   // pfAlignment
            {
                rIn.ReadUInt16( nDummy16 );
                if (!rIn.good())
                {
                    aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_Adjust);
                }
                else
                {
                    aSet.mpArry[ PPT_ParaAttr_Adjust ] = nDummy16 & 3;
                }
            }
            if ( nMask & 0x1000 )   // pfLineSpacing
            {
                rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_LineFeed ] );
                if (!rIn.good())
                {
                    aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_LineFeed);
                }
            }
            if ( nMask & 0x2000 )   // pfSpaceBefore
            {
                rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_UpperDist ] );
                if (!rIn.good())
                {
                    aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_UpperDist);
                }
            }
            if ( nMask & 0x4000 )   // pfSpaceAfter
            {
                rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_LowerDist ] );
                if (!rIn.good())
                {
                    aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_LowerDist);
                }
            }
            if ( nMask & 0x100 )    // pfLeftMargin
            {
                rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_TextOfs ] );
                if (!rIn.good())
                {
                    aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_TextOfs);
                }
                else
                {
                    aSet.mnAttrSet |= 1 << PPT_ParaAttr_TextOfs;
                }
            }
            if ( nMask & 0x400 )    // pfIndent
            {
                rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletOfs ] );
                if (!rIn.good())
                {
                    aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletOfs);
                }
                else
                {
                    aSet.mnAttrSet |= 1 << PPT_ParaAttr_BulletOfs;
                }
            }
            if ( nMask & 0x8000 )   // pfDefaultTabSize
            {
                rIn.ReadUInt16( nDummy16 );
                if (!rIn.good())
                {
                    // TODO?
                }
            }
            if ( nMask & 0x100000 ) // pfTabStops
            {
                sal_uInt16 i, nDistance, nAlignment, nNumberOfTabStops = 0;
                rIn.ReadUInt16( nNumberOfTabStops );
                if (!rIn.good())
                {
                    // TODO?
                }
                else
                {
                    const size_t nMinRecordSize = 4;
                    const size_t nMaxRecords = rIn.remainingSize() / nMinRecordSize;
                    if (nNumberOfTabStops > nMaxRecords)
                    {
                        SAL_WARN("filter.ms", "Parsing error: " << nMaxRecords <<
                                 " max possible entries, but " << nNumberOfTabStops << " claimed, truncating");
                        nNumberOfTabStops = nMaxRecords;
                    }
                    for (i = 0; i < nNumberOfTabStops; ++i)
                    {
                        rIn.ReadUInt16( nDistance )
                           .ReadUInt16( nAlignment );
                    }
                }
            }
            if ( nMask & 0x10000 )  // pfBaseLine
            {
                rIn.ReadUInt16( nDummy16 );
                if (!rIn.good())
                {
                    // TODO?
                }
            }
            if ( nMask & 0xe0000 )  // pfCharWrap, pfWordWrap, pfOverflow
            {
                rIn.ReadUInt16( nDummy16 );
                if (!rIn.good())
                {   // clear flag to avoid invalid access
                    aSet.mnAttrSet &= ~((1 << PPT_ParaAttr_AsianLB_1)
                                      | (1 << PPT_ParaAttr_AsianLB_2)
                                      | (1 << PPT_ParaAttr_AsianLB_3));
                }
                else
                {
                    if (nMask & 0x20000)
                        aSet.mpArry[PPT_ParaAttr_AsianLB_1] = nDummy16 & 1;
                    if (nMask & 0x40000)
                        aSet.mpArry[PPT_ParaAttr_AsianLB_2] = (nDummy16 >> 1) & 1;
                    if (nMask & 0x80000)
                        aSet.mpArry[PPT_ParaAttr_AsianLB_3] = (nDummy16 >> 2) & 1;
                    aSet.mnAttrSet |= ((nMask >> 17) & 7) << PPT_ParaAttr_AsianLB_1;
                }
            }
            if ( nMask & 0x200000 ) // pfTextDirection
            {
                rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BiDi ] );
                if (!rIn.good())
                {   // clear flag to avoid invalid access
                    aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BiDi);
                }
            }
        }
        else
            nCharCount = nStringLen;
 
        //if the textofs attr has been read at above, need not to reset.
        if ( ( !( aSet.mnAttrSet & 1 << PPT_ParaAttr_TextOfs ) ) && rRuler.GetTextOfs( aParaPropSet.mxParaSet->mnDepth, aSet.mpArry[ PPT_ParaAttr_TextOfs ] ) )
            aSet.mnAttrSet |= 1 << PPT_ParaAttr_TextOfs;
        if ( ( !( aSet.mnAttrSet & 1 << PPT_ParaAttr_BulletOfs ) ) && rRuler.GetBulletOfs( aParaPropSet.mxParaSet->mnDepth, aSet.mpArry[ PPT_ParaAttr_BulletOfs ] ) )
            aSet.mnAttrSet |= 1 << PPT_ParaAttr_BulletOfs;
        if ( rRuler.GetDefaultTab( aSet.mpArry[ PPT_ParaAttr_DefaultTab ] ) )
            aSet.mnAttrSet |= 1 << PPT_ParaAttr_DefaultTab;
 
        if ( ( nCharCount > nStringLen ) || ( nStringLen < nCharReadCnt + nCharCount ) )
        {
            bTextPropAtom = false;
            nCharCount = nStringLen - nCharReadCnt;
            // please fix the right hand side of
            // PPTParaPropSet& PPTParaPropSet::operator=(PPTParaPropSet&),
            // it should be a const reference
            PPTParaPropSet aTmpPPTParaPropSet;
            aParaPropSet = aTmpPPTParaPropSet;
            OSL_FAIL( "SJ:PPTStyleTextPropReader::could not get this PPT_PST_StyleTextPropAtom by reading the paragraph attributes" );
        }
        PPTParaPropSet* pPara = new PPTParaPropSet( aParaPropSet );
        pPara->mnOriginalTextPos = nCharReadCnt;
        aParaPropList.emplace_back( pPara );
        if ( nCharCount )
        {
            sal_uInt32   nCount;
            const sal_Unicode* pDat = aString.getStr() + nCharReadCnt;
            for ( nCount = 0; nCount < nCharCount; nCount++ )
            {
                if ( pDat[ nCount ] == 0xd )
                {
                    pPara = new PPTParaPropSet( aParaPropSet );
                    pPara->mnOriginalTextPos = nCharReadCnt + nCount + 1;
                    aParaPropList.emplace_back( pPara );
                }
            }
        }
        nCharReadCnt += nCharCount + 1;
    }
}
 
void PPTStyleTextPropReader::ReadCharProps( SvStream& rIn, PPTCharPropSet& aCharPropSet, std::u16string_view aString,
                                            sal_uInt32& nCharCount, sal_uInt32 nCharReadCnt,
                                            bool& bTextPropAtom, sal_uInt32 nExtParaPos,
                                            const std::vector< StyleTextProp9 >& aStyleTextProp9,
                                            sal_uInt32& nExtParaFlags, sal_uInt16& nBuBlip,
                                            sal_uInt16& nHasAnm, sal_uInt32& nAnmScheme )
{
    sal_uInt16 nStringLen = aString.size();
 
    sal_uInt16 nDummy16;
    rIn.ReadUInt16( nDummy16 );
    nCharCount = (rIn.good()) ? nDummy16 : 0;
    rIn.ReadUInt16( nDummy16 );
 
    sal_Int32 nCharsToRead = nStringLen - ( nCharReadCnt + nCharCount );
    if ( nCharsToRead < 0 )
    {
        nCharCount = nStringLen - nCharReadCnt;
        if ( nCharsToRead < -1 )
        {
            bTextPropAtom = false;
            OSL_FAIL( "SJ:PPTStyleTextPropReader::could not get this PPT_PST_StyleTextPropAtom by reading the character attributes" );
        }
    }
    ImplPPTCharPropSet& aSet = *aCharPropSet.mpImplPPTCharPropSet;
 
    // character attributes
    sal_uInt32 nMask(0);
    rIn.ReadUInt32( nMask );
    if ( static_cast<sal_uInt16>(nMask) )
    {
        aSet.mnAttrSet |= static_cast<sal_uInt16>(nMask);
        rIn.ReadUInt16( aSet.mnFlags );
    }
    if ( nMask & 0x10000 )  // cfTypeface
    {
        rIn.ReadUInt16( aSet.mnFont );
        aSet.mnAttrSet |= 1 << PPT_CharAttr_Font;
    }
    if ( nMask & 0x200000 ) // cfFEOldTypeface
    {
        rIn.ReadUInt16( aSet.mnAsianOrComplexFont );
        aSet.mnAttrSet |= 1 << PPT_CharAttr_AsianOrComplexFont;
    }
    if ( nMask & 0x400000 ) // cfANSITypeface
    {
        rIn.ReadUInt16( aSet.mnANSITypeface );
        aSet.mnAttrSet |= 1 << PPT_CharAttr_ANSITypeface;
    }
    if ( nMask & 0x800000 ) // cfSymbolTypeface
    {
        rIn.ReadUInt16( aSet.mnSymbolFont );
        aSet.mnAttrSet |= 1 << PPT_CharAttr_Symbol;
    }
    if ( nMask & 0x20000 )  // cfSize
    {
        rIn.ReadUInt16( aSet.mnFontHeight );
        aSet.mnAttrSet |= 1 << PPT_CharAttr_FontHeight;
    }
    if ( nMask & 0x40000 )  // cfColor
    {
        sal_uInt32 nVal(0);
        rIn.ReadUInt32( nVal );
        if ( !( nVal & 0xff000000 ) )
            nVal = PPT_COLSCHEME_HINTERGRUND;
        aSet.mnColor = nVal;
        aSet.mnAttrSet |= 1 << PPT_CharAttr_FontColor;
    }
    if ( nMask & 0x80000 )  // cfPosition
    {
        rIn.ReadUInt16( aSet.mnEscapement );
        aSet.mnAttrSet |= 1 << PPT_CharAttr_Escapement;
    }
    if ( !nExtParaPos )
        return;
 
    sal_uInt32 nExtBuInd = nMask & 0x3c00;
    if ( nExtBuInd )
        nExtBuInd = ( aSet.mnFlags & 0x3c00 ) >> 10;
    if ( nExtBuInd < aStyleTextProp9.size() )
    {
        nExtParaFlags = aStyleTextProp9[ nExtBuInd ].mnExtParagraphMask;
        nBuBlip = aStyleTextProp9[ nExtBuInd ].mnBuBlip;
        nHasAnm = aStyleTextProp9[ nExtBuInd ].mnHasAnm;
        nAnmScheme = aStyleTextProp9[ nExtBuInd ].mnAnmScheme;
    }
}
 
void PPTStyleTextPropReader::Init( SvStream& rIn, const DffRecordHeader& rTextHeader,
                                   PPTTextRulerInterpreter const & rRuler, const DffRecordHeader& rExtParaHd, TSS_Type nInstance )
{
    sal_uInt64 nOldPos = rIn.Tell();
    sal_uInt32 nExtParaPos = ( rExtParaHd.nRecType == PPT_PST_ExtendedParagraphAtom ) ? rExtParaHd.nFilePos + 8 : 0;
 
    std::vector< StyleTextProp9 > aStyleTextProp9;
    if ( rExtParaHd.nRecType == PPT_PST_ExtendedParagraphAtom  )
    {
        rIn.Seek( rExtParaHd.nFilePos + 8 );
 
        auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, rExtParaHd.GetRecEndFilePos());
        while( ( rIn.GetError() == ERRCODE_NONE ) && ( rIn.Tell() < nEndRecPos ) )
        {
            aStyleTextProp9.emplace_back();
            aStyleTextProp9.back().Read( rIn );
        }
        rIn.Seek( nOldPos );
    }
 
    OUString aString;
    DffRecordHeader aTextHd;
    ReadDffRecordHeader( rIn, aTextHd );
    sal_uInt32 nMaxLen = aTextHd.nRecLen;
    if ( nMaxLen >= 0xFFFF )
        nMaxLen = 0xFFFE;
 
    if( aTextHd.nRecType == PPT_PST_TextCharsAtom )
    {
        std::vector<sal_Unicode> aBuf(( nMaxLen >> 1 ) + 1);
        void* pDest = aBuf.data();
        auto nRead = rIn.ReadBytes(pDest, nMaxLen);
        if (nRead != nMaxLen)
            memset(static_cast<char*>(pDest) + nRead, 0, nMaxLen - nRead);
        nMaxLen >>= 1;
        aBuf[nMaxLen] = 0;
 
        sal_uInt32 i;
        sal_Unicode* pPtr = aBuf.data();
 
#ifdef OSL_BIGENDIAN
        sal_Unicode nTemp;
        for ( i = 0; i < nMaxLen; i++ )
        {
            nTemp = *pPtr;
            *pPtr++ = ( nTemp << 8 ) | ( nTemp >> 8 );
        }
        pPtr = aBuf.data();
#endif
 
        for ( i = 0; i < nMaxLen; pPtr++, i++ )
        {
            sal_Unicode nChar = *pPtr;
            if ( !nChar )
                break;
            if ( ( nChar & 0xff00 ) == 0xf000 )         // in this special case we got a symbol
                aSpecMarkerList.push_back( static_cast<sal_uInt32>( i | PPT_SPEC_SYMBOL ) );
            else if ( nChar == 0xd )
            {
                if ( nInstance == TSS_Type::PageTitle )
                    *pPtr = 0xb;
                else
                    aSpecMarkerList.push_back( static_cast<sal_uInt32>( i | PPT_SPEC_NEWLINE ) );
            }
        }
        if ( i )
            aString = OUString(aBuf.data(), i);
    }
    else if( aTextHd.nRecType == PPT_PST_TextBytesAtom )
    {
        std::unique_ptr<char[]> pBuf(new char[ nMaxLen + 1 ]);
        nMaxLen = rIn.ReadBytes(pBuf.get(), nMaxLen);
        pBuf[ nMaxLen ] = 0;
        char* pPtr = pBuf.get();
        for (;;)
        {
            char cLo = *pPtr;
            if ( cLo == 0 )
                break;
            if ( cLo == 0xd )
            {
                if ( nInstance == TSS_Type::PageTitle )
                    *pPtr = 0xb;
                else
                    aSpecMarkerList.push_back( static_cast<sal_uInt32>( (pPtr - pBuf.get()) | PPT_SPEC_NEWLINE ) );
            }
            pPtr++;
        }
        sal_Int32 nLen = pPtr - pBuf.get();
        if ( nLen )
            aString = OUString( pBuf.get(), nLen, RTL_TEXTENCODING_MS_1252 );
    }
    else
    {
        // no chars, but potentially char/para props?
        sal_uInt32  nCharCount;
        bool        bTextPropAtom = false;
        ReadParaProps( rIn, rTextHeader, aString, rRuler, nCharCount, bTextPropAtom );
 
        if ( bTextPropAtom )
        {
            // yeah, StyleTextProp is there, read it all & push to
            // aParaPropList
            PPTCharPropSet aCharPropSet(0);
            aCharPropSet.mnOriginalTextPos = 0;
 
            sal_uInt32 nExtParaFlags = 0, nAnmScheme = 0;
            sal_uInt16 nBuBlip = 0xffff, nHasAnm = 0;
            ReadCharProps( rIn, aCharPropSet, aString, nCharCount, 0/*nCharReadCnt*/,
                           bTextPropAtom, nExtParaPos, aStyleTextProp9, nExtParaFlags,
                           nBuBlip, nHasAnm, nAnmScheme );
 
            aCharPropList.push_back(std::make_unique<PPTCharPropSet>(aCharPropSet, 0));
        }
    }
 
    const sal_uInt32 nStringLen = aString.getLength();
    if (nStringLen)
    {
        sal_uInt32  nCharCount;
        bool        bTextPropAtom = false;
 
        ReadParaProps( rIn, rTextHeader, aString, rRuler, nCharCount, bTextPropAtom );
 
        bool bEmptyParaPossible = true;
        sal_uInt32 nCharReadCnt = 0;
        sal_uInt32 nCurrentPara = 0;
        size_t i = 1;                   // points to the next element to process
        sal_uInt32 nCurrentSpecMarker = aSpecMarkerList.empty() ? 0 : aSpecMarkerList[0];
 
        while ( nCharReadCnt < nStringLen )
        {
            sal_uInt32 nExtParaFlags = 0, nLatestParaUpdate = 0xffffffff, nAnmScheme = 0;
            sal_uInt16 nBuBlip = 0xffff, nHasAnm = 0;
 
            PPTCharPropSet aCharPropSet( nCurrentPara );
            if ( bTextPropAtom )
            {
                ReadCharProps( rIn, aCharPropSet, aString, nCharCount, nCharReadCnt,
                               bTextPropAtom, nExtParaPos, aStyleTextProp9, nExtParaFlags,
                               nBuBlip, nHasAnm, nAnmScheme );
                if (!rIn.good())
                    break;
            }
            else
                nCharCount = nStringLen;
 
            sal_uInt32 nLen;
            while( nCharCount )
            {
                if ( nExtParaPos && ( nLatestParaUpdate != nCurrentPara ) && ( nCurrentPara < aParaPropList.size() ) )
                {
                    PPTParaPropSet* pPropSet = aParaPropList[ nCurrentPara ].get();
                    pPropSet->mxParaSet->mnExtParagraphMask = nExtParaFlags;
                    if ( nExtParaFlags & 0x800000 )
                        pPropSet->mxParaSet->mnBuBlip = nBuBlip;
                    if ( nExtParaFlags & 0x01000000 )
                        pPropSet->mxParaSet->mnAnmScheme = nAnmScheme;
                    if ( nExtParaFlags & 0x02000000 )
                        pPropSet->mxParaSet->mnHasAnm = nHasAnm;
                    nLatestParaUpdate = nCurrentPara;
                }
                aCharPropSet.mnOriginalTextPos = nCharReadCnt;
                if ( nCurrentSpecMarker &&  ( ( nCurrentSpecMarker & 0xffff ) < ( nCharReadCnt + nCharCount ) ) )
                {
                    if ( nCurrentSpecMarker & PPT_SPEC_NEWLINE )
                    {
                        nLen = ( nCurrentSpecMarker & 0xffff ) - nCharReadCnt;
                        if ( nLen )
                            aCharPropSet.maString = aString.copy( nCharReadCnt, nLen );
                        else if ( bEmptyParaPossible )
                            aCharPropSet.maString.clear();
                        if ( nLen || bEmptyParaPossible )
                            aCharPropList.push_back(
                                std::make_unique<PPTCharPropSet>(aCharPropSet, nCurrentPara));
                        nCurrentPara++;
                        nLen++;
                        nCharReadCnt += nLen;
                        nCharCount -= nLen;
                        bEmptyParaPossible = true;
                    }
                    else if ( nCurrentSpecMarker & PPT_SPEC_SYMBOL )
                    {
                        if ( ( nCurrentSpecMarker & 0xffff ) != nCharReadCnt )
                        {
                            nLen = ( nCurrentSpecMarker & 0xffff ) - nCharReadCnt;
                            aCharPropSet.maString = aString.copy(nCharReadCnt, nLen);
                            aCharPropList.push_back(
                                std::make_unique<PPTCharPropSet>(aCharPropSet, nCurrentPara));
                            nCharCount -= nLen;
                            nCharReadCnt += nLen;
                        }
                        PPTCharPropSet* pCPropSet = new PPTCharPropSet( aCharPropSet, nCurrentPara );
                        pCPropSet->maString = aString.copy(nCharReadCnt, 1);
                        if ( aCharPropSet.mpImplPPTCharPropSet->mnAttrSet & ( 1 << PPT_CharAttr_Symbol ) )
                            pCPropSet->SetFont( aCharPropSet.mpImplPPTCharPropSet->mnSymbolFont );
                        aCharPropList.emplace_back( pCPropSet );
                        nCharCount--;
                        nCharReadCnt++;
                        bEmptyParaPossible = false;
                    }
                    nCurrentSpecMarker = ( i < aSpecMarkerList.size() ) ? aSpecMarkerList[ i++ ] : 0;
                }
                else
                {
                    if (nCharReadCnt > o3tl::make_unsigned(aString.getLength()))
                        aCharPropSet.maString = OUString();
                    else
                    {
                        sal_Int32 nStrLen = nCharCount;
                        sal_Int32 nMaxStrLen = aString.getLength() - nCharReadCnt;
                        if (nStrLen > nMaxStrLen)
                            nStrLen = nMaxStrLen;
                        aCharPropSet.maString = aString.copy(nCharReadCnt, nStrLen);
                    }
                    aCharPropList.push_back(
                        std::make_unique<PPTCharPropSet>(aCharPropSet, nCurrentPara));
                    nCharReadCnt += nCharCount;
                    bEmptyParaPossible = false;
                    break;
                }
            }
        }
        if ( !aCharPropList.empty() && ( aCharPropList.back()->mnParagraph != nCurrentPara ) )
        {
            PPTCharPropSet* pCharPropSet = new PPTCharPropSet( *aCharPropList.back(), nCurrentPara );
            pCharPropSet->maString.clear();
            pCharPropSet->mnOriginalTextPos = nStringLen - 1;
            aCharPropList.emplace_back( pCharPropSet );
        }
    }
    rIn.Seek( nOldPos );
}
 
PPTStyleTextPropReader::~PPTStyleTextPropReader()
{
}
 
PPTPortionObj::PPTPortionObj( const PPTStyleSheet& rStyleSheet, TSS_Type nInstance, sal_uInt32 nDepth ) :
    PPTCharPropSet  ( 0 ),
    mrStyleSheet    ( rStyleSheet ),
    mnInstance      ( nInstance ),
    mnDepth         ( std::min<sal_uInt32>( nDepth, 4 ) )
{
}
 
PPTPortionObj::PPTPortionObj( const PPTCharPropSet& rCharPropSet, const PPTStyleSheet& rStyleSheet, TSS_Type nInstance, sal_uInt32 nDepth ) :
    PPTCharPropSet  ( rCharPropSet ),
    mrStyleSheet    ( rStyleSheet ),
    mnInstance      ( nInstance ),
    mnDepth         ( std::min<sal_uInt32>( nDepth, 4 ) )
{
}
 
PPTPortionObj::PPTPortionObj( const PPTPortionObj& rPortionObj ) :
    PPTCharPropSet      ( rPortionObj ),
    mrStyleSheet        ( rPortionObj.mrStyleSheet ),
    mnInstance          ( rPortionObj.mnInstance ),
    mnDepth             ( rPortionObj.mnDepth )
{
}
 
PPTPortionObj::~PPTPortionObj()
{
}
 
bool PPTPortionObj::GetAttrib( sal_uInt32 nAttr, sal_uInt32& rRetValue, TSS_Type nDestinationInstance ) const
{
    sal_uInt32  nMask = 1 << nAttr;
    rRetValue = 0;
 
    bool bIsHardAttribute = ( ( mpImplPPTCharPropSet->mnAttrSet & nMask ) != 0 );
 
    if ( bIsHardAttribute )
    {
        switch ( nAttr )
        {
            case PPT_CharAttr_Bold :
            case PPT_CharAttr_Italic :
            case PPT_CharAttr_Underline :
            case PPT_CharAttr_Shadow :
            case PPT_CharAttr_Strikeout :
            case PPT_CharAttr_Embossed :
                rRetValue = ( mpImplPPTCharPropSet->mnFlags & nMask ) ? 1 : 0;
            break;
            case PPT_CharAttr_Font :
                rRetValue = mpImplPPTCharPropSet->mnFont;
            break;
            case PPT_CharAttr_AsianOrComplexFont :
                rRetValue = mpImplPPTCharPropSet->mnAsianOrComplexFont;
            break;
            case PPT_CharAttr_FontHeight :
                rRetValue = mpImplPPTCharPropSet->mnFontHeight;
            break;
            case PPT_CharAttr_FontColor :
                rRetValue = mpImplPPTCharPropSet->mnColor;
            break;
            case PPT_CharAttr_Escapement :
                rRetValue = mpImplPPTCharPropSet->mnEscapement;
            break;
            default :
                OSL_FAIL( "SJ:PPTPortionObj::GetAttrib ( hard attribute does not exist )" );
        }
    }
    else
    {
        const PPTCharLevel& rCharLevel = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[ mnDepth ];
        PPTCharLevel* pCharLevel = nullptr;
        if ( ( nDestinationInstance == TSS_Type::Unknown )
                || ( mnDepth && ( ( mnInstance == TSS_Type::Subtitle ) || ( mnInstance == TSS_Type::TextInShape ) ) ) )
            bIsHardAttribute = true;
        else if ( nDestinationInstance != mnInstance )
            pCharLevel = &mrStyleSheet.mpCharSheet[ nDestinationInstance ]->maCharLevel[ mnDepth ];
        switch( nAttr )
        {
            case PPT_CharAttr_Bold :
            case PPT_CharAttr_Italic :
            case PPT_CharAttr_Underline :
            case PPT_CharAttr_Shadow :
            case PPT_CharAttr_Strikeout :
            case PPT_CharAttr_Embossed :
            {
                rRetValue = ( rCharLevel.mnFlags & nMask ) ? 1 : 0;
                if ( pCharLevel )
                {
                    sal_uInt32 nTmp = ( pCharLevel->mnFlags & nMask ) ? 1 : 0;
                    if ( rRetValue != nTmp )
                        bIsHardAttribute = true;
                }
            }
            break;
            case PPT_CharAttr_Font :
            {
                rRetValue = rCharLevel.mnFont;
                if ( pCharLevel && ( rRetValue != pCharLevel->mnFont ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_CharAttr_AsianOrComplexFont :
            {
                rRetValue = rCharLevel.mnAsianOrComplexFont;
                if ( pCharLevel && ( rRetValue != pCharLevel->mnAsianOrComplexFont ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_CharAttr_FontHeight :
            {
                rRetValue = rCharLevel.mnFontHeight;
                if ( pCharLevel && ( rRetValue != pCharLevel->mnFontHeight ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_CharAttr_FontColor :
            {
                rRetValue = rCharLevel.mnFontColor;
                if ( pCharLevel && ( rRetValue != pCharLevel->mnFontColor ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_CharAttr_Escapement :
            {
                rRetValue = rCharLevel.mnEscapement;
                if ( pCharLevel && ( rRetValue != pCharLevel->mnEscapement ) )
                    bIsHardAttribute = true;
            }
            break;
            default :
                OSL_FAIL( "SJ:PPTPortionObj::GetAttrib ( attribute does not exist )" );
        }
    }
    return bIsHardAttribute;
}
 
void PPTPortionObj::ApplyTo(  SfxItemSet& rSet, SdrPowerPointImport& rManager, TSS_Type nDestinationInstance )
{
    ApplyTo( rSet, rManager, nDestinationInstance, nullptr );
}
 
void PPTPortionObj::ApplyTo(  SfxItemSet& rSet, SdrPowerPointImport& rManager, TSS_Type nDestinationInstance, const PPTTextObj* pTextObj )
{
    sal_uInt32  nVal;
    if ( GetAttrib( PPT_CharAttr_Bold, nVal, nDestinationInstance ) )
    {
        rSet.Put( SvxWeightItem( nVal != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
        rSet.Put( SvxWeightItem( nVal != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT_CJK ) );
        rSet.Put( SvxWeightItem( nVal != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT_CTL ) );
    }
    if ( GetAttrib( PPT_CharAttr_Italic, nVal, nDestinationInstance ) )
    {
        rSet.Put( SvxPostureItem( nVal != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) );
        rSet.Put( SvxPostureItem( nVal != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC_CJK ) );
        rSet.Put( SvxPostureItem( nVal != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC_CTL ) );
    }
    if ( GetAttrib( PPT_CharAttr_Underline, nVal, nDestinationInstance ) )
        rSet.Put( SvxUnderlineItem( nVal != 0 ? LINESTYLE_SINGLE : LINESTYLE_NONE, EE_CHAR_UNDERLINE ) );
 
    if ( GetAttrib( PPT_CharAttr_Shadow, nVal, nDestinationInstance ) )
        rSet.Put( SvxShadowedItem( nVal != 0, EE_CHAR_SHADOW ) );
 
    if ( GetAttrib( PPT_CharAttr_Strikeout, nVal, nDestinationInstance ) )
        rSet.Put( SvxCrossedOutItem( nVal != 0 ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ) );
 
    sal_uInt32  nAsianFontId = 0xffff;
    if ( GetAttrib( PPT_CharAttr_AsianOrComplexFont, nAsianFontId, nDestinationInstance ) )
    {
        if ( nAsianFontId != 0xffff )
        {
            const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nAsianFontId );
            if ( pFontEnityAtom )
            {
                rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName,
                            OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CJK ) );
                rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName,
                            OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CTL ) );
            }
        }
    }
    if ( GetAttrib( PPT_CharAttr_Font, nVal, nDestinationInstance ) )
    {
        const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nVal );
        if ( pFontEnityAtom )
        {
            rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName, OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO ) );
 
            // #i119475# bullet font info for CJK and CTL
            if ( RTL_TEXTENCODING_SYMBOL ==  pFontEnityAtom->eCharSet )
            {
                rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName, OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CJK ) );
                rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName, OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CTL ) );
            }
        }
    }
    if ( GetAttrib( PPT_CharAttr_FontHeight, nVal, nDestinationInstance ) ) // Schriftgrad in Point
    {
        sal_uInt32 nHeight = rManager.ScalePoint( nVal );
        rSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
        rSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
        rSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );
    }
 
    if ( GetAttrib( PPT_CharAttr_Embossed, nVal, nDestinationInstance ) )
        rSet.Put( SvxCharReliefItem( nVal != 0 ? FontRelief::Embossed : FontRelief::NONE, EE_CHAR_RELIEF ) );
    if ( nVal ) /* if Embossed is set, the font color depends to the fillstyle/color of the object,
                   if the object has no fillstyle, the font color depends to fillstyle of the background */
    {
        Color aDefColor( COL_BLACK );
        sal_uInt32 eFillType = mso_fillSolid;
        if ( rManager.GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ) & 0x10 )
            eFillType = rManager.GetPropertyValue(DFF_Prop_fillType, mso_fillSolid);
        else
            eFillType = mso_fillBackground;
        switch( eFillType )
        {
            case mso_fillShade :
            case mso_fillShadeCenter :
            case mso_fillShadeShape :
            case mso_fillShadeScale :
            case mso_fillShadeTitle :
            case mso_fillSolid :
                aDefColor = rManager.MSO_CLR_ToColor( rManager.GetPropertyValue( DFF_Prop_fillColor, 0 ) );
            break;
            case mso_fillPattern :
                aDefColor = rManager.MSO_CLR_ToColor( rManager.GetPropertyValue( DFF_Prop_fillBackColor, 0 ) );
            break;
            case mso_fillTexture :
            {
                Graphic aGraf;
                if ( rManager.GetBLIP( rManager.GetPropertyValue( DFF_Prop_fillBlip, 0 ), aGraf ) )
                {
                    Bitmap aBmp( aGraf.GetBitmapEx().GetBitmap() );
                    Size aSize( aBmp.GetSizePixel() );
                    if ( aSize.Width() && aSize.Height() )
                    {
                        if ( aSize.Width () > 64 )
                            aSize.setWidth( 64 );
                        if ( aSize.Height() > 64 )
                            aSize.setHeight( 64 );
 
                        BitmapScopedReadAccess pAcc(aBmp);
                        if( pAcc )
                        {
                            sal_uLong nRt = 0, nGn = 0, nBl = 0;
                            const tools::Long nWidth = aSize.Width();
                            const tools::Long nHeight = aSize.Height();
 
                            if( pAcc->HasPalette() )
                            {
                                for( tools::Long nY = 0; nY < nHeight; nY++ )
                                {
                                    Scanline pScanline = pAcc->GetScanline( nY );
                                    for( tools::Long nX = 0; nX < nWidth; nX++ )
                                    {
                                        const BitmapColor& rCol = pAcc->GetPaletteColor( pAcc->GetIndexFromData( pScanline, nX ) );
                                        nRt+=rCol.GetRed(); nGn+=rCol.GetGreen(); nBl+=rCol.GetBlue();
                                    }
                                }
                            }
                            else
                            {
                                for( tools::Long nY = 0; nY < nHeight; nY++ )
                                {
                                    Scanline pScanline = pAcc->GetScanline( nY );
                                    for( tools::Long nX = 0; nX < nWidth; nX++ )
                                    {
                                        const BitmapColor aCol( pAcc->GetPixelFromData( pScanline, nX ) );
                                        nRt+=aCol.GetRed(); nGn+=aCol.GetGreen(); nBl+=aCol.GetBlue();
                                    }
                                }
                            }
                            pAcc.reset();
                            sal_uInt32 nC = aSize.Width() * aSize.Height();
                            nRt /= nC;
                            nGn /= nC;
                            nBl /= nC;
                            aDefColor = Color(sal_uInt8( nRt ), sal_uInt8( nGn ),sal_uInt8( nBl ) );
                        }
                    }
                }
            }
            break;
            case mso_fillBackground :
            {
                if ( pTextObj ) // the textobject is needed
                {
                    const SfxItemSet* pItemSet = pTextObj->GetBackground();
                    if ( pItemSet )
                    {
                        const XFillStyleItem* pFillStyleItem = pItemSet->GetItemIfSet( XATTR_FILLSTYLE, false );
                        if ( pFillStyleItem )
                        {
                            drawing::FillStyle eFillStyle = pFillStyleItem->GetValue();
                            switch( eFillStyle )
                            {
                                case drawing::FillStyle_SOLID :
                                {
                                    const XColorItem* pFillColorItem = pItemSet->GetItemIfSet( XATTR_FILLCOLOR, false );
                                    if ( pFillColorItem )
                                        aDefColor = pFillColorItem->GetColorValue();
                                }
                                break;
                                case drawing::FillStyle_GRADIENT :
                                {
                                    const XFillGradientItem* pGradientItem = pItemSet->GetItemIfSet( XATTR_FILLGRADIENT, false );
                                    if ( pGradientItem )
                                        aDefColor = Color(pGradientItem->GetGradientValue().GetColorStops().front().getStopColor());
                                }
                                break;
                                case drawing::FillStyle_HATCH :
                                case drawing::FillStyle_BITMAP :
                                    aDefColor = COL_WHITE;
                                break;
                                default: break;
                            }
                        }
                    }
                }
            }
            break;
            default: break;
        }
        rSet.Put( SvxColorItem( aDefColor, EE_CHAR_COLOR ) );
    }
    else
    {
        if ( GetAttrib( PPT_CharAttr_FontColor, nVal, nDestinationInstance ) )  // text color (4Byte-Arg)
        {
            Color aCol( rManager.MSO_TEXT_CLR_ToColor( nVal ) );
            rSet.Put( SvxColorItem( aCol, EE_CHAR_COLOR ) );
            if ( nDestinationInstance == TSS_Type::Unknown )
                mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[ mnDepth ].mnFontColorInStyleSheet = aCol;
        }
        else if ( nVal & 0x0f000000 )   // this is not a hard attribute, but maybe the page has a different colorscheme,
        {                               // so that in this case we must use a hard color attribute
            Color   aCol( rManager.MSO_TEXT_CLR_ToColor( nVal ) );
            Color&  aColorInSheet = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[ mnDepth ].mnFontColorInStyleSheet;
            if ( aColorInSheet != aCol )
                rSet.Put( SvxColorItem( aCol, EE_CHAR_COLOR ) );
        }
    }
 
    if ( GetAttrib( PPT_CharAttr_Escapement, nVal, nDestinationInstance ) ) // super-/subscript in %
    {
        sal_uInt16  nEsc = 0;
        sal_uInt8   nProp = 100;
 
        if ( nVal )
        {
            nEsc = static_cast<sal_Int16>(nVal);
            nProp = DFLT_ESC_PROP;
        }
        SvxEscapementItem aItem( nEsc, nProp, EE_CHAR_ESCAPEMENT );
        rSet.Put( aItem );
    }
    if ( mnLanguage[ 0 ] )
        rSet.Put( SvxLanguageItem( mnLanguage[ 0 ], EE_CHAR_LANGUAGE ) );
    if ( mnLanguage[ 1 ] )
        rSet.Put( SvxLanguageItem( mnLanguage[ 1 ], EE_CHAR_LANGUAGE_CJK ) );
    if ( mnLanguage[ 2 ] )
        rSet.Put( SvxLanguageItem( mnLanguage[ 2 ], EE_CHAR_LANGUAGE_CTL ) );
}
 
SvxFieldItem* PPTPortionObj::GetTextField()
{
    if ( mpFieldItem )
        return new SvxFieldItem( *mpFieldItem );
    return nullptr;
}
 
namespace
{
    sal_uInt16 sanitizeForMaxPPTLevels(sal_uInt16 nDepth)
    {
        if (nDepth >= nMaxPPTLevels)
        {
            SAL_WARN("filter.ms", "Para Style Sheet depth " << nDepth << " but " << nMaxPPTLevels - 1 << " is max possible");
            nDepth = nMaxPPTLevels - 1;
        }
        return nDepth;
    }
}
 
PPTParagraphObj::PPTParagraphObj( const PPTStyleSheet& rStyleSheet, TSS_Type nInstance, sal_uInt16 nDepth ) :
    PPTNumberFormatCreator  ( nullptr ),
    mrStyleSheet            ( rStyleSheet ),
    mnInstance              ( nInstance ),
    mnCurrentObject         ( 0 )
{
    mxParaSet->mnDepth = sanitizeForMaxPPTLevels(nDepth);
}
 
PPTParagraphObj::PPTParagraphObj( PPTStyleTextPropReader& rPropReader,
        size_t const nCurParaPos, size_t& rnCurCharPos,
        const PPTStyleSheet& rStyleSheet,
        TSS_Type nInstance, PPTTextRulerInterpreter const & rRuler ) :
    PPTParaPropSet          ( *rPropReader.aParaPropList[nCurParaPos] ),
    PPTNumberFormatCreator  ( nullptr ),
    PPTTextRulerInterpreter ( rRuler ),
    mrStyleSheet            ( rStyleSheet ),
    mnInstance              ( nInstance ),
    mnCurrentObject         ( 0 )
{
    if (rnCurCharPos >= rPropReader.aCharPropList.size())
        return;
 
    sal_uInt32 const nCurrentParagraph =
        rPropReader.aCharPropList[rnCurCharPos]->mnParagraph;
    for (; rnCurCharPos < rPropReader.aCharPropList.size() &&
         rPropReader.aCharPropList[rnCurCharPos]->mnParagraph == nCurrentParagraph;
         ++rnCurCharPos)
    {
        PPTCharPropSet *const pCharPropSet =
            rPropReader.aCharPropList[rnCurCharPos].get();
        std::unique_ptr<PPTPortionObj> pPPTPortion(new PPTPortionObj(
                *pCharPropSet, rStyleSheet, nInstance, mxParaSet->mnDepth));
        m_PortionList.push_back(std::move(pPPTPortion));
    }
}
 
PPTParagraphObj::~PPTParagraphObj()
{
}
 
void PPTParagraphObj::AppendPortion( PPTPortionObj& rPPTPortion )
{
    m_PortionList.push_back(
            std::make_unique<PPTPortionObj>(rPPTPortion));
}
 
void PPTParagraphObj::UpdateBulletRelSize( sal_uInt32& nBulletRelSize ) const
{
    if ( nBulletRelSize <= 0x7fff )      // a negative value is the absolute bullet height
        return;
 
    sal_uInt16 nFontHeight = 0;
    if (!m_PortionList.empty())
    {
        PPTPortionObj const& rPortion = *m_PortionList.front();
        if (rPortion.mpImplPPTCharPropSet->mnAttrSet & (1 << PPT_CharAttr_FontHeight))
        {
            nFontHeight = rPortion.mpImplPPTCharPropSet->mnFontHeight;
        }
    }
    // if we do not have a hard attributed fontheight, the fontheight is taken from the style
    if ( !nFontHeight )
    {
        nFontHeight = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[sanitizeForMaxPPTLevels(mxParaSet->mnDepth)].mnFontHeight;
    }
    nBulletRelSize = nFontHeight ? ((- static_cast<sal_Int16>(nBulletRelSize)) * 100 ) / nFontHeight : 100;
}
 
bool PPTParagraphObj::GetAttrib( sal_uInt32 nAttr, sal_uInt32& rRetValue, TSS_Type nDestinationInstance )
{
    sal_uInt32  nMask = 1 << nAttr;
    rRetValue = 0;
 
    if ( nAttr > 21 )
    {
        OSL_FAIL( "SJ:PPTParagraphObj::GetAttrib - attribute does not exist" );
        return false;
    }
 
    bool bIsHardAttribute = ( ( mxParaSet->mnAttrSet & nMask ) != 0 );
 
    sal_uInt16 nDepth = sanitizeForMaxPPTLevels(mxParaSet->mnDepth);
 
    if ( bIsHardAttribute )
    {
        if ( nAttr == PPT_ParaAttr_BulletColor )
        {
            bool bHardBulletColor;
            if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardColor ) )
                bHardBulletColor = mxParaSet->mpArry[ PPT_ParaAttr_BuHardColor ] != 0;
            else
                bHardBulletColor = ( mrStyleSheet.mpParaSheet[ mnInstance ]->maParaLevel[nDepth].mnBuFlags
                                        & ( 1 << PPT_ParaAttr_BuHardColor ) ) != 0;
            if ( bHardBulletColor )
                rRetValue = mxParaSet->mnBulletColor;
            else
            {
                rRetValue = PPT_COLSCHEME_TEXT_UND_ZEILEN;
                if ((nDestinationInstance != TSS_Type::Unknown) && !m_PortionList.empty())
                {
                    PPTPortionObj const& rPortion = *m_PortionList.front();
                    if (rPortion.mpImplPPTCharPropSet->mnAttrSet & (1 << PPT_CharAttr_FontColor))
                    {
                        rRetValue = rPortion.mpImplPPTCharPropSet->mnColor;
                    }
                    else
                    {
                        rRetValue = mrStyleSheet.mpCharSheet[ nDestinationInstance ]->maCharLevel[nDepth].mnFontColor;
                    }
                }
            }
        }
        else if ( nAttr == PPT_ParaAttr_BulletFont )
        {
            bool bHardBuFont;
            if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardFont ) )
                bHardBuFont = mxParaSet->mpArry[ PPT_ParaAttr_BuHardFont ] != 0;
            else
                bHardBuFont = ( mrStyleSheet.mpParaSheet[ mnInstance ]->maParaLevel[nDepth].mnBuFlags
                                        & ( 1 << PPT_ParaAttr_BuHardFont ) ) != 0;
            if ( bHardBuFont )
                rRetValue = mxParaSet->mpArry[ PPT_ParaAttr_BulletFont ];
            else
            {
                // it is the font used which assigned to the first character of the following text
                rRetValue = 0;
                if ((nDestinationInstance != TSS_Type::Unknown) && !m_PortionList.empty())
                {
                    PPTPortionObj const& rPortion = *m_PortionList.front();
                    if (rPortion.mpImplPPTCharPropSet->mnAttrSet & ( 1 << PPT_CharAttr_Font ) )
                    {
                        rRetValue = rPortion.mpImplPPTCharPropSet->mnFont;
                    }
                    else
                    {
                        rRetValue = mrStyleSheet.mpCharSheet[ nDestinationInstance ]->maCharLevel[nDepth].mnFont;
                    }
                }
            }
        }
        else
            rRetValue = mxParaSet->mpArry[ nAttr ];
    }
    else
    {
        const PPTParaLevel& rParaLevel = mrStyleSheet.mpParaSheet[ mnInstance ]->maParaLevel[nDepth];
 
        PPTParaLevel* pParaLevel = nullptr;
        if ( ( nDestinationInstance == TSS_Type::Unknown )
            || ( nDepth && ( ( mnInstance == TSS_Type::Subtitle ) || ( mnInstance == TSS_Type::TextInShape ) ) ) )
            bIsHardAttribute = true;
        else if ( nDestinationInstance != mnInstance )
            pParaLevel = &mrStyleSheet.mpParaSheet[ nDestinationInstance ]->maParaLevel[nDepth];
        switch ( nAttr )
        {
            case PPT_ParaAttr_BulletOn :
            {
                rRetValue = rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BulletOn );
                if ( pParaLevel )
                {
                    if ( rRetValue != ( static_cast<sal_uInt32>(pParaLevel->mnBuFlags) & ( 1 << PPT_ParaAttr_BulletOn ) ) )
                        bIsHardAttribute = true;
                }
            }
            break;
            case PPT_ParaAttr_BuHardFont :
            case PPT_ParaAttr_BuHardColor :
            case PPT_ParaAttr_BuHardHeight :
                OSL_FAIL( "SJ:PPTParagraphObj::GetAttrib - this attribute does not make sense" );
            break;
            case PPT_ParaAttr_BulletChar :
            {
                rRetValue = rParaLevel.mnBulletChar;
                if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletChar ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_BulletFont :
            {
                bool bHardBuFont;
                if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardFont ) )
                    bHardBuFont = mxParaSet->mpArry[ PPT_ParaAttr_BuHardFont ] != 0;
                else
                    bHardBuFont = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardFont ) ) != 0;
                if ( bHardBuFont )
                {
                    rRetValue = rParaLevel.mnBulletFont;
                    if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletFont ) )
                        bIsHardAttribute = true;
                }
                else
                {
                    if (!m_PortionList.empty())
                    {
                        PPTPortionObj const& rPortion = *m_PortionList.front();
                        bIsHardAttribute = rPortion.GetAttrib(
                            PPT_CharAttr_Font, rRetValue, nDestinationInstance);
                    }
                    else
                    {
                        rRetValue = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[nDepth].mnFont;
                        bIsHardAttribute = true;
                    }
                }
            }
            break;
            case PPT_ParaAttr_BulletHeight :
            {
                rRetValue = rParaLevel.mnBulletHeight;
                if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletHeight ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_BulletColor :
            {
                bool bHardBulletColor;
                if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardColor ) )
                    bHardBulletColor = mxParaSet->mpArry[ PPT_ParaAttr_BuHardColor ] != 0;
                else
                    bHardBulletColor = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardColor ) ) != 0;
                if ( bHardBulletColor )
                {
                    rRetValue = rParaLevel.mnBulletColor;
                    if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletColor ) )
                        bIsHardAttribute = true;
                }
                else
                {
                    if (!m_PortionList.empty())
                    {
                        PPTPortionObj const& rPortion = *m_PortionList.front();
                        if (rPortion.mbIsHyperlink )
                        {
                            if( rPortion.mbHardHylinkOrigColor )
                                rRetValue = rPortion.mnHylinkOrigColor;
                            else
                                rRetValue = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[nDepth].mnFontColor;
                            bIsHardAttribute = true;
                        }
                        else
                        {
                            bIsHardAttribute = rPortion.GetAttrib( PPT_CharAttr_FontColor, rRetValue, nDestinationInstance );
                        }
                    }
                    else
                    {
                        rRetValue = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[nDepth].mnFontColor;
                        bIsHardAttribute = true;
                    }
                }
            }
            break;
            case PPT_ParaAttr_Adjust :
            {
                rRetValue = rParaLevel.mnAdjust;
                if ( pParaLevel && ( rRetValue != pParaLevel->mnAdjust ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_LineFeed :
            {
                rRetValue = rParaLevel.mnLineFeed;
                if ( pParaLevel && ( rRetValue != pParaLevel->mnLineFeed ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_UpperDist :
            {
                rRetValue = rParaLevel.mnUpperDist;
                if ( pParaLevel && ( rRetValue != pParaLevel->mnUpperDist ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_LowerDist :
            {
                rRetValue = rParaLevel.mnLowerDist;
                if ( pParaLevel && ( rRetValue != pParaLevel->mnLowerDist ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_TextOfs :
            {
                rRetValue = rParaLevel.mnTextOfs;
                if ( pParaLevel && ( rRetValue != pParaLevel->mnTextOfs ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_BulletOfs :
            {
                rRetValue = rParaLevel.mnBulletOfs;
                if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletOfs ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_DefaultTab :
            {
                rRetValue = rParaLevel.mnDefaultTab;
                if ( pParaLevel && ( rRetValue != pParaLevel->mnDefaultTab ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_AsianLB_1 :
            {
                rRetValue = rParaLevel.mnAsianLineBreak & 1;
                if ( pParaLevel && ( rRetValue != ( static_cast<sal_uInt32>(pParaLevel->mnAsianLineBreak) & 1 ) ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_AsianLB_2 :
            {
                rRetValue = ( rParaLevel.mnAsianLineBreak >> 1 ) & 1;
                if ( pParaLevel && ( rRetValue != ( ( static_cast<sal_uInt32>(pParaLevel->mnAsianLineBreak) >> 1 ) & 1 ) ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_AsianLB_3 :
            {
                rRetValue = ( rParaLevel.mnAsianLineBreak >> 2 ) & 1;
                if ( pParaLevel && ( rRetValue != ( ( static_cast<sal_uInt32>(pParaLevel->mnAsianLineBreak) >> 2 ) & 1 ) ) )
                    bIsHardAttribute = true;
            }
            break;
            case PPT_ParaAttr_BiDi :
            {
                rRetValue = rParaLevel.mnBiDi;
                if ( pParaLevel && ( rRetValue != pParaLevel->mnBiDi ) )
                    bIsHardAttribute = true;
            }
            break;
        }
    }
    return bIsHardAttribute;
}
 
void PPTParagraphObj::ApplyTo( SfxItemSet& rSet,  std::optional< sal_Int16 >& rStartNumbering, SdrPowerPointImport const & rManager, TSS_Type nDestinationInstance )
{
    sal_Int16   nVal2;
    sal_uInt32  nVal, nUpperDist, nLowerDist;
    TSS_Type    nInstance = nDestinationInstance != TSS_Type::Unknown ? nDestinationInstance : mnInstance;
 
    if ( ( nDestinationInstance != TSS_Type::Unknown ) || ( mxParaSet->mnDepth <= 1 ) )
    {
        SvxNumBulletItem* pNumBulletItem = mrStyleSheet.mpNumBulletItem[ nInstance ].get();
        if ( pNumBulletItem )
        {
            SvxNumberFormat aNumberFormat( SVX_NUM_NUMBER_NONE );
            if ( GetNumberFormat( rManager, aNumberFormat, this, nDestinationInstance, rStartNumbering ) )
            {
                if ( aNumberFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE )
                {
                    aNumberFormat.SetAbsLSpace( 0 );
                    aNumberFormat.SetFirstLineOffset( 0 );
                    aNumberFormat.SetCharTextDistance( 0 );
                    aNumberFormat.SetFirstLineIndent( 0 );
                    aNumberFormat.SetIndentAt( 0 );
                }
                SvxNumBulletItem aNewNumBulletItem( *pNumBulletItem );
                SvxNumRule& rRule = aNewNumBulletItem.GetNumRule();
                rRule.SetLevel( mxParaSet->mnDepth, aNumberFormat );
                for (sal_uInt16 i = 0; i < rRule.GetLevelCount(); ++i)
                {
                    if ( i != mxParaSet->mnDepth )
                    {
                        sal_uInt16 n = sanitizeForMaxPPTLevels(i);
 
                        SvxNumberFormat aNumberFormat2( rRule.GetLevel( i ) );
                        const PPTParaLevel& rParaLevel = mrStyleSheet.mpParaSheet[ nInstance ]->maParaLevel[ n ];
                        const PPTCharLevel& rCharLevel = mrStyleSheet.mpCharSheet[ nInstance ]->maCharLevel[ n ];
                        sal_uInt32 nColor;
                        if ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardColor ) )
                            nColor = rParaLevel.mnBulletColor;
                        else
                            nColor = rCharLevel.mnFontColor;
                        aNumberFormat2.SetBulletColor( rManager.MSO_TEXT_CLR_ToColor( nColor ) );
                        rRule.SetLevel( i, aNumberFormat2 );
                    }
                }
                rSet.Put( aNewNumBulletItem );
            }
        }
    }
 
    sal_uInt32 nIsBullet2, _nTextOfs, _nBulletOfs;
    GetAttrib(PPT_ParaAttr_BulletOn, nIsBullet2, nDestinationInstance);
    GetAttrib(PPT_ParaAttr_TextOfs, _nTextOfs, nDestinationInstance);
    GetAttrib(PPT_ParaAttr_BulletOfs, _nBulletOfs, nDestinationInstance);
    SvxLRSpaceItem aLRSpaceItem( EE_PARA_LRSPACE );
    if ( !nIsBullet2 )
    {
        auto const nAbsLSpace = convertMasterUnitToMm100(_nTextOfs);
        auto const nFirstLineOffset = nAbsLSpace - convertMasterUnitToMm100(_nBulletOfs);
        aLRSpaceItem.SetTextFirstLineOffsetValue( -nFirstLineOffset );
        aLRSpaceItem.SetTextLeft( nAbsLSpace );
    }
    rSet.Put( aLRSpaceItem );
 
    if ( GetAttrib( PPT_ParaAttr_Adjust, nVal, nDestinationInstance ) )
    {
        if ( nVal <= 3 )
        {   // paragraph adjustment
            static SvxAdjust const aAdj[ 4 ] = { SvxAdjust::Left, SvxAdjust::Center, SvxAdjust::Right, SvxAdjust::Block };
            rSet.Put( SvxAdjustItem( aAdj[ nVal ], EE_PARA_JUST ) );
        }
    }
 
    if ( GetAttrib( PPT_ParaAttr_AsianLB_1, nVal, nDestinationInstance ) )
        rSet.Put(SvxForbiddenRuleItem(nVal != 0, EE_PARA_FORBIDDENRULES));
    if ( GetAttrib( PPT_ParaAttr_AsianLB_3, nVal, nDestinationInstance ) )
        rSet.Put(SvxHangingPunctuationItem(nVal != 0, EE_PARA_HANGINGPUNCTUATION));
 
    if ( GetAttrib( PPT_ParaAttr_BiDi, nVal, nDestinationInstance ) )
        rSet.Put( SvxFrameDirectionItem( nVal == 1 ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) );
 
    // LineSpacing
    PPTPortionObj* pPortion = First();
    bool bIsHardAttribute = GetAttrib( PPT_ParaAttr_LineFeed, nVal, nDestinationInstance );
    nVal2 = static_cast<sal_Int16>(nVal);
    sal_uInt32 nFont = sal_uInt32();
    if ( pPortion && pPortion->GetAttrib( PPT_CharAttr_Font, nFont, nDestinationInstance ) )
        bIsHardAttribute = true;
 
    if ( bIsHardAttribute )
    {
        SdrTextFixedCellHeightItem aHeightItem(true);
        aHeightItem.SetWhich(SDRATTR_TEXT_USEFIXEDCELLHEIGHT);
        rSet.Put( aHeightItem );
        SvxLineSpacingItem aItem( 200, EE_PARA_SBL );
        if ( nVal2 <= 0 ) {
            aItem.SetLineHeight( static_cast<sal_uInt16>( rManager.ScalePoint( -nVal2 ) / 8 ) );
            aItem.SetLineSpaceRule( SvxLineSpaceRule::Fix );
            aItem.SetInterLineSpaceRule(SvxInterLineSpaceRule::Off);
        } else
        {
            sal_uInt16 nPropLineSpace = static_cast<sal_uInt16>(nVal2);
            aItem.SetPropLineSpace( nPropLineSpace );
            aItem.SetLineSpaceRule( SvxLineSpaceRule::Auto );
        }
        rSet.Put( aItem );
    }
 
    // Paragraph Spacing
    bIsHardAttribute = ( static_cast<sal_uInt32>(GetAttrib( PPT_ParaAttr_UpperDist, nUpperDist, nDestinationInstance )) +
        static_cast<sal_uInt32>(GetAttrib( PPT_ParaAttr_LowerDist, nLowerDist, nDestinationInstance )) ) != 0;
    if ( ( nUpperDist > 0 ) || ( nLowerDist > 0 ) )
    {
        if (!m_PortionList.empty())
        {
            sal_uInt32 nFontHeight = 0;
            m_PortionList.back()->GetAttrib(
                    PPT_CharAttr_FontHeight, nFontHeight, nDestinationInstance);
            if ( static_cast<sal_Int16>(nUpperDist) > 0 )
                nUpperDist = - static_cast<sal_Int16>( ( nFontHeight * nUpperDist * 100 ) / 1000 );
            if ( static_cast<sal_Int16>(nLowerDist) > 0 )
                nLowerDist = - static_cast<sal_Int16>( ( nFontHeight * nLowerDist * 100 ) / 1000 );
        }
        bIsHardAttribute = true;
    }
    if ( bIsHardAttribute )
    {
        SvxULSpaceItem aULSpaceItem( EE_PARA_ULSPACE );
        nVal2 = static_cast<sal_Int16>(nUpperDist);
        if ( nVal2 <= 0 )
            aULSpaceItem.SetUpper(static_cast<sal_uInt16>(convertMasterUnitToMm100(-nVal2)));
        else
        {
            aULSpaceItem.SetUpperValue( 0 );
            aULSpaceItem.SetPropUpper( static_cast<sal_uInt16>(nUpperDist) == 100 ? 101 : static_cast<sal_uInt16>(nUpperDist) );
        }
        nVal2 = static_cast<sal_Int16>(nLowerDist);
        if ( nVal2 <= 0 )
            aULSpaceItem.SetLower(static_cast<sal_uInt16>(convertMasterUnitToMm100(-nVal2)));
        else
        {
            aULSpaceItem.SetLowerValue( 0 );
            aULSpaceItem.SetPropLower( static_cast<sal_uInt16>(nLowerDist) == 100 ? 101 : static_cast<sal_uInt16>(nLowerDist) );
        }
        rSet.Put( aULSpaceItem );
    }
 
    sal_uInt32 i, nDefaultTab, nTab, nTextOfs2 = 0;
    sal_uInt32 nLatestManTab = 0;
    GetAttrib( PPT_ParaAttr_TextOfs, nTextOfs2, nDestinationInstance );
    GetAttrib( PPT_ParaAttr_BulletOfs, nTab, nDestinationInstance );
    GetAttrib( PPT_ParaAttr_DefaultTab, nDefaultTab, nDestinationInstance );
 
    SvxTabStopItem aTabItem( 0, 0, SvxTabAdjust::Default, EE_PARA_TABS );
    if ( GetTabCount() )
    {
        for ( i = 0; i < GetTabCount(); i++ )
        {
            SvxTabAdjust eTabAdjust;
            nTab = GetTabOffsetByIndex( static_cast<sal_uInt16>(i) );
            switch( GetTabStyleByIndex( static_cast<sal_uInt16>(i) ) )
            {
                case 1 :    eTabAdjust = SvxTabAdjust::Center; break;
                case 2 :    eTabAdjust = SvxTabAdjust::Right; break;
                case 3 :    eTabAdjust = SvxTabAdjust::Decimal; break;
                default :   eTabAdjust = SvxTabAdjust::Left;
            }
            aTabItem.Insert(SvxTabStop(convertMasterUnitToMm100(nTab), eTabAdjust));
        }
        nLatestManTab = nTab;
    }
    if ( nIsBullet2 == 0 )
        aTabItem.Insert( SvxTabStop( sal_uInt16(0) ) );
    if ( nDefaultTab )
    {
        nTab = std::max( nTextOfs2, nLatestManTab );
        nTab /= nDefaultTab;
        nTab = nDefaultTab * ( 1 + nTab );
        for ( i = 0; ( i < 20 ) && ( nTab < 0x1b00 ); i++ )
        {
            aTabItem.Insert( SvxTabStop( convertMasterUnitToMm100(nTab)));
            nTab += nDefaultTab;
        }
    }
    rSet.Put( aTabItem );
}
 
sal_uInt32 PPTParagraphObj::GetTextSize()
{
    sal_uInt32 nCount, nRetValue = 0;
    for (const std::unique_ptr<PPTPortionObj> & i : m_PortionList)
    {
        PPTPortionObj const& rPortionObj = *i;
        nCount = rPortionObj.Count();
        if ((!nCount) && rPortionObj.mpFieldItem)
            nCount++;
        nRetValue += nCount;
    }
    return nRetValue;
}
 
PPTPortionObj* PPTParagraphObj::First()
{
    mnCurrentObject = 0;
    if (m_PortionList.empty())
        return nullptr;
    return m_PortionList.front().get();
}
 
PPTPortionObj* PPTParagraphObj::Next()
{
    sal_uInt32 i = mnCurrentObject + 1;
    if (i >= m_PortionList.size())
        return nullptr;
    mnCurrentObject++;
    return m_PortionList[i].get();
}
 
PPTFieldEntry::~PPTFieldEntry()
{
}
 
void PPTFieldEntry::GetDateTime( const sal_uInt32 nVal, SvxDateFormat& eDateFormat, SvxTimeFormat& eTimeFormat )
{
    eDateFormat = SvxDateFormat::AppDefault;
    eTimeFormat = SvxTimeFormat::AppDefault;
    // evaluate ID
    switch( nVal )
    {
        case 0:
        case 6:
            eDateFormat = SvxDateFormat::A;
        break;
        case 1:
            eDateFormat = SvxDateFormat::F;
        break;
        case 2:
        case 3:
            eDateFormat = SvxDateFormat::D;
        break;
        case 4:
        case 5:
            eDateFormat = SvxDateFormat::C;
        break;
        case 7:
            eDateFormat = SvxDateFormat::A;
            [[fallthrough]];
        case 9:
            eTimeFormat = SvxTimeFormat::HH24_MM;
        break;
        case 8:
            eDateFormat = SvxDateFormat::A;
            [[fallthrough]];
        case 11:
            eTimeFormat = SvxTimeFormat::HH12_MM;
        break;
        case 10:
            eTimeFormat = SvxTimeFormat::HH24_MM_SS;
        break;
        case 12:
            eTimeFormat = SvxTimeFormat::HH12_MM_SS;
        break;
    }
}
 
void PPTFieldEntry::SetDateTime( sal_uInt32 nVal )
{
    SvxDateFormat eDateFormat;
    SvxTimeFormat eTimeFormat;
    GetDateTime( nVal, eDateFormat, eTimeFormat );
    if ( eDateFormat != SvxDateFormat::AppDefault )
        xField1.reset(new SvxFieldItem(SvxDateField( Date( Date::SYSTEM ), SvxDateType::Var, eDateFormat ), EE_FEATURE_FIELD));
    if ( eTimeFormat != SvxTimeFormat::AppDefault )
    {
        std::unique_ptr<SvxFieldItem> xFieldItem(new SvxFieldItem(SvxExtTimeField( tools::Time( tools::Time::SYSTEM ), SvxTimeType::Var, eTimeFormat ), EE_FEATURE_FIELD));
        if (xField1)
            xField2 = std::move(xFieldItem);
        else
            xField1 = std::move(xFieldItem);
    }
}
 
PPTTextObj::PPTTextObj( SvStream& rIn, SdrPowerPointImport& rSdrPowerPointImport, PptSlidePersistEntry& rPersistEntry, DffObjData const * pObjData ) :
    mxImplTextObj   ( new ImplPPTTextObj( rPersistEntry ) )
{
    mxImplTextObj->mnShapeId = 0;
    mxImplTextObj->mnShapeMaster = 0;
    mxImplTextObj->mnDestinationInstance = mxImplTextObj->mnInstance = TSS_Type::TextInShape;
    mxImplTextObj->mnCurrentObject = 0;
    mxImplTextObj->mnParagraphCount = 0;
    mxImplTextObj->mnTextFlags = 0;
    mxImplTextObj->meShapeType = ( pObjData && pObjData->bShapeType ) ? pObjData->eShapeType : mso_sptMin;
 
    DffRecordHeader aExtParaHd;
    aExtParaHd.nRecType = 0;    // set empty
 
 
    DffRecordHeader aShapeContainerHd;
    ReadDffRecordHeader( rIn, aShapeContainerHd );
 
    if ( !(( pObjData == nullptr ) || ( pObjData->bShapeType )) )
        return;
 
    PPTExtParaProv* pExtParaProv = rSdrPowerPointImport.m_pPPTStyleSheet->pExtParaProv.get();
    if ( pObjData )
    {
        mxImplTextObj->mnShapeId = pObjData->nShapeId;
        if ( pObjData->nSpFlags & ShapeFlag::HaveMaster )
            mxImplTextObj->mnShapeMaster = rSdrPowerPointImport.GetPropertyValue( DFF_Prop_hspMaster, 0 );
    }
    // ClientData
    if ( rSdrPowerPointImport.maShapeRecords.SeekToContent( rIn, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) )
    {
        sal_uInt64 nOldPos = rIn.Tell();
        DffRecordHeader& aClientDataContainerHd = *rSdrPowerPointImport.maShapeRecords.Current();
        DffRecordHeader aPlaceHolderAtomHd;
        if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_OEPlaceholderAtom, aClientDataContainerHd.GetRecEndFilePos(), &aPlaceHolderAtomHd ) )
        {
            mxImplTextObj->moPlaceHolderAtom.emplace();
            ReadPptOEPlaceholderAtom( rIn, *( mxImplTextObj->moPlaceHolderAtom ) );
        }
        rIn.Seek( nOldPos );
        DffRecordHeader aProgTagHd;
        if ( SdrPowerPointImport::SeekToContentOfProgTag( 9, rIn, aClientDataContainerHd, aProgTagHd ) )
        {
            ReadDffRecordHeader( rIn, aExtParaHd );
        }
    }
 
    // ClientTextBox
    if ( !rSdrPowerPointImport.maShapeRecords.SeekToContent( rIn, DFF_msofbtClientTextbox, SEEK_FROM_CURRENT_AND_RESTART ) )
        return;
 
    bool bStatus = true;
 
 
    DffRecordHeader aClientTextBoxHd( *rSdrPowerPointImport.maShapeRecords.Current() );
    sal_uInt32  nTextRulerAtomOfs = 0;  // case of zero -> this atom may be found in aClientDataContainerHd;
                                    // case of -1 -> there is no atom of this kind
                                    // else -> this is the fileofs where we can get it
 
    // checkout if this is a referenced
    // textobj, if so the we will patch
    // the ClientTextBoxHd for a
    // equivalent one
    DffRecordHeader aTextHd;
    if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_OutlineTextRefAtom, aClientTextBoxHd.GetRecEndFilePos(), &aTextHd ) )
    {
        sal_uInt32 nRefNum;
        rIn.ReadUInt32( nRefNum );
 
        if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextRulerAtom, aClientTextBoxHd.GetRecEndFilePos() ) )
            nTextRulerAtomOfs = rIn.Tell();
        else
            nTextRulerAtomOfs = 0xffffffff;
 
        switch( rSdrPowerPointImport.m_eCurrentPageKind )
        {
            case PPT_NOTEPAGE :
            case PPT_MASTERPAGE :
            case PPT_SLIDEPAGE :
            break;
            default :
                bStatus = false;
        }
        if ( bStatus )
        {
            sal_uInt32 nSlideId = rSdrPowerPointImport.GetCurrentPageId();
            if ( !nSlideId )
                bStatus = false;
            else
            {
                if ( !aExtParaHd.nRecType )
                {
                    sal_uInt64 nOldPos = rIn.Tell();
                    // try to locate the referenced ExtendedParaHd
                    DffRecordHeader* pHd = pExtParaProv->
                                                aExtendedPresRules.GetRecordHeader( PPT_PST_ExtendedParagraphHeaderAtom,
                                                                                    SEEK_FROM_CURRENT_AND_RESTART );
                    DffRecordHeader     aPresRuleHd;
                    DffRecordHeader*    pFirst = pHd;
 
                    while ( pHd )
                    {
                        pHd->SeekToContent( rIn );
                        sal_uInt32 nTmpSlideId(0), nTmpRef;
                        rIn.ReadUInt32( nTmpSlideId )
                           .ReadUInt32( nTmpRef );         // this seems to be the instance
 
                        if ( ( nTmpSlideId == nSlideId ) && ( pHd->nRecInstance == nRefNum ) )
                        {
                            if (!pHd->SeekToEndOfRecord(rIn))
                                break;
                            ReadDffRecordHeader( rIn, aPresRuleHd );
                            if ( aPresRuleHd.nRecType == PPT_PST_ExtendedParagraphAtom )
                            {
                                aExtParaHd = aPresRuleHd;
                                break;
                            }
                        }
                        pHd = pExtParaProv->
                                aExtendedPresRules.GetRecordHeader( PPT_PST_ExtendedParagraphHeaderAtom,
                                                                    SEEK_FROM_CURRENT_AND_RESTART );
                        if ( pHd == pFirst )
                            break;
                    }
                    rIn.Seek( nOldPos );
                }
                // now pHd points to the right SlideListWithText Container
                PptSlidePersistList* pPageList = rSdrPowerPointImport.GetPageList( rSdrPowerPointImport.m_eCurrentPageKind );
                PptSlidePersistEntry* pE = nullptr;
                if ( pPageList && ( rSdrPowerPointImport.m_nCurrentPageNum < pPageList->size() ) )
                    pE = &(*pPageList)[ rSdrPowerPointImport.m_nCurrentPageNum ];
                if ( (!pE) || (!pE->nSlidePersistStartOffset) || ( pE->aPersistAtom.nSlideId != nSlideId ) )
                    bStatus = false;
                else
                {
                    auto nOffset(pE->nSlidePersistStartOffset);
                    bStatus = (nOffset == rIn.Seek(nOffset));
                    // now we got the right page and are searching for the right
                    // TextHeaderAtom
                    auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, pE->nSlidePersistEndOffset);
                    while (bStatus && rIn.Tell() < nEndRecPos)
                    {
                        ReadDffRecordHeader( rIn, aClientTextBoxHd );
                        if ( aClientTextBoxHd.nRecType == PPT_PST_TextHeaderAtom )
                        {
                            if ( aClientTextBoxHd.nRecInstance == nRefNum )
                            {
                                aClientTextBoxHd.SeekToEndOfRecord( rIn );
                                break;
                            }
                        }
                        if (!aClientTextBoxHd.SeekToEndOfRecord(rIn))
                            break;
                    }
                    if ( rIn.Tell() > pE->nSlidePersistEndOffset )
                        bStatus = false;
                    else
                    {   // patching the RecordHeader
                        aClientTextBoxHd.nFilePos -= DFF_COMMON_RECORD_HEADER_SIZE;
                        aClientTextBoxHd.nRecLen += DFF_COMMON_RECORD_HEADER_SIZE;
                        aClientTextBoxHd.nRecType = DFF_msofbtClientTextbox;
                        aClientTextBoxHd.nRecVer = DFF_PSFLAG_CONTAINER;
 
                        // we have to calculate the correct record len
                        DffRecordHeader aTmpHd;
                        nEndRecPos = DffPropSet::SanitizeEndPos(rIn, pE->nSlidePersistEndOffset);
                        while (rIn.Tell() < nEndRecPos)
                        {
                            ReadDffRecordHeader( rIn, aTmpHd );
                            if ( ( aTmpHd.nRecType == PPT_PST_SlidePersistAtom ) || ( aTmpHd.nRecType == PPT_PST_TextHeaderAtom ) )
                                break;
                            if (!aTmpHd.SeekToEndOfRecord(rIn))
                                break;
                            aClientTextBoxHd.nRecLen += aTmpHd.nRecLen + DFF_COMMON_RECORD_HEADER_SIZE;
                        }
                        aClientTextBoxHd.SeekToContent( rIn );
                    }
                }
            }
        }
    }
 
    if ( !bStatus )
        return;
 
    if ( !SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextHeaderAtom, aClientTextBoxHd.GetRecEndFilePos(), &aTextHd ) )
        return;
 
    // TextHeaderAtom is always the first Atom
    sal_uInt16 nTmp(0);
    rIn.ReadUInt16(nTmp);   // this number tells us the TxMasterStyleAtom Instance
    if (nTmp > 8)
        nTmp = 4;
    TSS_Type nInstance = static_cast<TSS_Type>(nTmp);
    aTextHd.SeekToEndOfRecord( rIn );
    mxImplTextObj->mnInstance = nInstance;
 
    sal_uInt64 nFilePos = rIn.Tell();
    if ( !(rSdrPowerPointImport.SeekToRec2( PPT_PST_TextBytesAtom,
                                          PPT_PST_TextCharsAtom,
                                          aClientTextBoxHd.GetRecEndFilePos() )
         || SvxMSDffManager::SeekToRec( rIn,
                                            PPT_PST_StyleTextPropAtom,
                                            aClientTextBoxHd.GetRecEndFilePos() )) )
        return;
 
    PPTTextRulerInterpreter aTextRulerInterpreter( nTextRulerAtomOfs, aClientTextBoxHd, rIn );
 
    PPTStyleTextPropReader aStyleTextPropReader( rIn, aClientTextBoxHd,
                                                    aTextRulerInterpreter, aExtParaHd, nInstance );
    sal_uInt32 nParagraphs = mxImplTextObj->mnParagraphCount = aStyleTextPropReader.aParaPropList.size();
    if ( !nParagraphs )
        return;
 
    // the languages and locales will be merged into the list of PPTCharPropSet
    DffRecordHeader aTextSpecInfoHd;
    PPTTextSpecInfoAtomInterpreter aTextSpecInfoAtomInterpreter;
    if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextSpecInfoAtom,
                                aClientTextBoxHd.GetRecEndFilePos(), &aTextSpecInfoHd ) )
    {
        if ( aTextSpecInfoAtomInterpreter.Read( rIn, aTextSpecInfoHd, PPT_PST_TextSpecInfoAtom,
                &(rSdrPowerPointImport.m_pPPTStyleSheet->maTxSI) ) )
        {
            size_t nI = 0;
            for (const PPTTextSpecInfo& rSpecInfo : aTextSpecInfoAtomInterpreter.aList)
            {
                sal_uInt32 nCharIdx = rSpecInfo.nCharIdx;
 
                // portions and text have to been split in some cases
                for ( ; nI < aStyleTextPropReader.aCharPropList.size(); ++nI)
                {
                    PPTCharPropSet* pSet = aStyleTextPropReader.aCharPropList[nI].get();
                    if (pSet->mnOriginalTextPos >= nCharIdx)
                        break;
                    pSet->mnLanguage[0] = rSpecInfo.nLanguage[0];
                    pSet->mnLanguage[1] = rSpecInfo.nLanguage[1];
                    pSet->mnLanguage[2] = rSpecInfo.nLanguage[2];
                    // test if the current portion needs to be split
                    if (pSet->maString.getLength() <= 1)
                        continue;
                    sal_Int32 nIndexOfNextPortion = pSet->maString.getLength() + pSet->mnOriginalTextPos;
                    sal_Int32 nNewLen = nIndexOfNextPortion - nCharIdx;
                    if (nNewLen <= 0)
                        continue;
                    sal_Int32 nOldLen = pSet->maString.getLength() - nNewLen;
                    if (nOldLen <= 0)
                        continue;
                    OUString aString(pSet->maString);
                    PPTCharPropSet* pNew = new PPTCharPropSet(*pSet);
                    pSet->maString = aString.copy(0, nOldLen);
                    pNew->maString = aString.copy(nOldLen, nNewLen);
                    pNew->mnOriginalTextPos += nOldLen;
                    aStyleTextPropReader.aCharPropList.emplace(aStyleTextPropReader.aCharPropList.begin() + nI + 1, pNew);
                }
            }
        }
#ifdef DBG_UTIL
        else
        {
            if (!(rSdrPowerPointImport.rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT))
            {
                OSL_FAIL( "SdrTextSpecInfoAtomInterpreter::Ctor(): parsing error, this document needs to be analysed (SJ)" );
            }
        }
#endif
    }
    // now will search for possible textextensions such as date/time fields
    // or ParaTabStops and append them on this textobj
    rIn.Seek( nFilePos );
    ::std::vector< std::unique_ptr<PPTFieldEntry> > FieldList;
    auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, aClientTextBoxHd.GetRecEndFilePos());
    while (rIn.Tell() < nEndRecPos)
    {
        ReadDffRecordHeader( rIn, aTextHd );
        sal_uInt16 nVal = 0;
        std::unique_ptr<PPTFieldEntry> xEntry;
        switch ( aTextHd.nRecType )
        {
            case PPT_PST_DateTimeMCAtom :
            {
                xEntry.reset(new PPTFieldEntry);
                rIn.ReadUInt16(xEntry->nPos)
                   .ReadUInt16( nVal )
                   .ReadUInt16( nVal );
                xEntry->SetDateTime( nVal & 0xff );
            }
            break;
 
            case PPT_PST_FooterMCAtom :
            {
                xEntry.reset(new PPTFieldEntry);
                rIn.ReadUInt16(xEntry->nPos);
                xEntry->xField1.reset(new SvxFieldItem(SvxFooterField(), EE_FEATURE_FIELD));
            }
            break;
 
            case PPT_PST_HeaderMCAtom :
            {
                xEntry.reset(new PPTFieldEntry);
                rIn.ReadUInt16(xEntry->nPos);
                xEntry->xField1.reset(new SvxFieldItem(SvxHeaderField(), EE_FEATURE_FIELD));
            }
            break;
 
            case PPT_PST_GenericDateMCAtom :
            {
                xEntry.reset(new PPTFieldEntry);
                rIn.ReadUInt16(xEntry->nPos);
                xEntry->xField1.reset(new SvxFieldItem(SvxDateTimeField(), EE_FEATURE_FIELD));
                if (rPersistEntry.xHeaderFooterEntry) // sj: #i34111# on master pages it is possible
                {                                     // that there is no HeaderFooterEntry available
                    if (rPersistEntry.xHeaderFooterEntry->nAtom & 0x20000)    // auto date time
                        xEntry->SetDateTime(rPersistEntry.xHeaderFooterEntry->nAtom & 0xff);
                    else
                        xEntry->xString = rPersistEntry.xHeaderFooterEntry->pPlaceholder[nVal];
                }
            }
            break;
 
            case PPT_PST_SlideNumberMCAtom :
            case PPT_PST_RTFDateTimeMCAtom :
            {
                xEntry.reset(new PPTFieldEntry);
                if ( aTextHd.nRecLen >= 4 )
                {
                    rIn.ReadUInt16(xEntry->nPos)
                       .ReadUInt16( nVal );
 
                    // evaluate ID
                    //SvxFieldItem* pFieldItem = NULL;
                    switch( aTextHd.nRecType )
                    {
                        case PPT_PST_SlideNumberMCAtom:
                            xEntry->xField1.reset(new SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD));
                        break;
 
                        case PPT_PST_RTFDateTimeMCAtom:
                        {
                            // Rude workaround for one special case reported
                            // by a customer. (#i75203#)
 
                            // Don't even attempt to handle the general use
                            // case for PPT_PST_RTFDateTimeMCAtom (a generic
                            // MS style date/time format string). Just handle
                            // the special case where the format string
                            // contains only one or several possibly empty
                            // quoted strings. I.e. something that doesn't
                            // expand to any date or time at all, but to a
                            // fixed string. How on earth somebody manages to
                            // produce such things in PPT slides I have no
                            // idea.
                            if (nVal == 0)
                            {
                                OUStringBuffer aStr;
                                bool inquote = false;
                                for (int nLen = 0; nLen < 64; ++nLen)
                                {
                                    sal_Unicode n(0);
                                    rIn.ReadUtf16( n );
 
                                    // Collect quoted characters into aStr
                                    if ( n == '\'')
                                        inquote = !inquote;
                                    else if (!n)
                                    {
                                        // End of format string
                                        xEntry->xString = aStr.makeStringAndClear();
                                        break;
                                    }
                                    else if (!inquote)
                                    {
                                        // Non-quoted character, i.e. a real
                                        // format specifier. We don't handle
                                        // those. Sorry.
                                        break;
                                    }
                                    else
                                    {
                                        aStr.append(OUStringChar(n));
                                    }
                                }
                            }
                            if (!xEntry->xString)
                            {
                                // Handle as previously
                                xEntry->xField1.reset(new SvxFieldItem( SvxDateField( Date( Date::SYSTEM ), SvxDateType::Fix ), EE_FEATURE_FIELD ));
                            }
                        }
                    }
                }
            }
            break;
 
            case PPT_PST_InteractiveInfo :
            {
                DffRecordHeader aHdInteractiveInfoAtom;
                if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_InteractiveInfoAtom, aTextHd.GetRecEndFilePos(), &aHdInteractiveInfoAtom ) )
                {
                    PptInteractiveInfoAtom aInteractiveInfoAtom;
                    ReadPptInteractiveInfoAtom( rIn, aInteractiveInfoAtom );
                    for (const SdHyperlinkEntry& rHyperlink : rSdrPowerPointImport.m_aHyperList)
                    {
                        if ( rHyperlink.nIndex == aInteractiveInfoAtom.nExHyperlinkId )
                        {
                            if (!aTextHd.SeekToEndOfRecord(rIn))
                            {
                                break;
                            }
                            ReadDffRecordHeader( rIn, aTextHd );
                            if ( aTextHd.nRecType != PPT_PST_TxInteractiveInfoAtom )
                            {
                                aTextHd.SeekToBegOfRecord( rIn );
                                continue;
                            }
                            else
                            {
                                sal_uInt32 nStartPos, nEndPos;
                                rIn.ReadUInt32( nStartPos )
                                   .ReadUInt32( nEndPos );
                                if ( nEndPos )
                                {
                                    xEntry.reset(new PPTFieldEntry);
                                    xEntry->nPos = static_cast<sal_uInt16>(nStartPos);
                                    xEntry->nTextRangeEnd = static_cast<sal_uInt16>(nEndPos);
                                    OUString aTarget( rHyperlink.aTarget );
                                    if ( !rHyperlink.aConvSubString.isEmpty() )
                                    {
                                        aTarget += "#" + rHyperlink.aConvSubString;
                                    }
                                    xEntry->xField1.reset(new SvxFieldItem( SvxURLField( aTarget, OUString(), SvxURLFormat::Repr ), EE_FEATURE_FIELD ));
                                }
                            }
                            break;
                        }
                    }
                }
            }
            break;
        }
        if (!aTextHd.SeekToEndOfRecord(rIn))
            break;
        if (xEntry)
        {
            // sorting fields ( hi >> lo )
            auto it = std::find_if(FieldList.begin(), FieldList.end(),
                [&xEntry](const std::unique_ptr<PPTFieldEntry>& rxField) {
                    return rxField->nPos < xEntry->nPos; });
            if ( it != FieldList.end() ) {
                FieldList.insert(it, std::move(xEntry));
            } else {
                FieldList.push_back( std::move(xEntry));
            }
        }
    }
    if ( !FieldList.empty() )
    {
        auto FE = FieldList.begin();
        auto& aCharPropList = aStyleTextPropReader.aCharPropList;
 
        sal_Int32   i = nParagraphs - 1;
        sal_Int32   n = aCharPropList.size() - 1;
 
        // at this point we just have a list of textportions(aCharPropList)
        // the next while loop tries to resolve the list of fields(pFieldList)
        while( ( FE < FieldList.end() ) && ( n >= 0 ) && ( i >= 0 ) )
        {
            PPTCharPropSet* pSet  = aCharPropList[n].get();
            OUString aString( pSet->maString );
            sal_uInt32 nCount = aString.getLength();
            sal_uInt32 nPos = pSet->mnOriginalTextPos + nCount;
            while ( ( FE < FieldList.end() ) && nCount-- )
            {
                nPos--;
                FE = std::find_if(FE, FieldList.end(),
                    [&nPos](const std::unique_ptr<PPTFieldEntry>& rxField) {return rxField->nPos <= nPos;});
                if (FE == FieldList.end())
                    break;
 
                if ( (*FE)->nPos == nPos )
                {
                    if ( aString[nCount] == 0x2a )
                    {
                        sal_uInt32 nBehind = aString.getLength() - ( nCount + 1 );
                        pSet->maString.clear();
                        if ( nBehind )
                        {
                            PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pSet );
                            pNewCPS->maString = aString.copy( nCount + 1, nBehind );
                            aCharPropList.emplace( aCharPropList.begin() + n + 1, pNewCPS );
                        }
                        if ( (*FE)->xField2 )
                        {
                            PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pSet );
                            pNewCPS->mpFieldItem = std::move((*FE)->xField2);
                            aCharPropList.emplace( aCharPropList.begin() + n + 1, pNewCPS );
 
                            pNewCPS = new PPTCharPropSet( *pSet );
                            pNewCPS->maString = " ";
                            aCharPropList.emplace( aCharPropList.begin() + n + 1, pNewCPS );
                        }
                        if ( nCount )
                        {
                            PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pSet );
                            pNewCPS->maString = aString.copy( 0, nCount );
                            aCharPropList.emplace( aCharPropList.begin() + n++, pNewCPS );
                        }
                        if ( (*FE)->xField1 )
                        {
                            pSet->mpFieldItem = std::move((*FE)->xField1);
                        }
                        else if ( (*FE)->xString )
                            pSet->maString = *(*FE)->xString;
                    }
                    else
                    {
                        if ( (*FE)->nTextRangeEnd )   // text range hyperlink
                        {
                            sal_uInt32 nHyperLen = (*FE)->nTextRangeEnd - nPos;
                            if ( nHyperLen )
                            {
                                PPTCharPropSet* pBefCPS = nullptr;
                                if ( nCount )
                                {
                                    pBefCPS = new PPTCharPropSet( *pSet );
                                    pSet->maString = pSet->maString.copy(nCount);
                                }
                                sal_uInt32  nIdx = n;
                                sal_Int32   nHyperLenLeft = nHyperLen;
 
                                while ( ( aCharPropList.size() > nIdx ) && nHyperLenLeft )
                                {
                                    // the textrange hyperlink can take more than 1 paragraph
                                    // the solution here is to clone the hyperlink...
 
                                    PPTCharPropSet* pCurrent = aCharPropList[ nIdx ].get();
                                    sal_Int32       nNextStringLen = pCurrent->maString.getLength();
 
                                    DBG_ASSERT( (*FE)->xField1, "missing field!" );
                                    if (!(*FE)->xField1)
                                        break;
 
                                    const SvxURLField* pField = static_cast<const SvxURLField*>((*FE)->xField1->GetField());
 
                                    pCurrent->mbIsHyperlink = true;
                                    pCurrent->mnHylinkOrigColor = pCurrent->mpImplPPTCharPropSet->mnColor;
                                    pCurrent->mbHardHylinkOrigColor = ( ( pCurrent->mpImplPPTCharPropSet->mnAttrSet >>PPT_CharAttr_FontColor ) & 1)>0;
 
                                    // add missing attribute to show underline property
                                    pCurrent->mpImplPPTCharPropSet->mnAttrSet |= 1 << PPT_CharAttr_Underline;
                                    pCurrent->mpImplPPTCharPropSet->mnFlags = 1 << PPT_CharAttr_Underline;
 
                                    if ( pCurrent->mpFieldItem )
                                    {
                                        pCurrent->SetColor( PPT_COLSCHEME_A_UND_HYPERLINK );
                                        if ( dynamic_cast< const SvxURLField* >(pCurrent->mpFieldItem->GetField()) != nullptr)
                                            break;
                                        nHyperLenLeft--;
                                    }
                                    else if ( nNextStringLen )
                                    {
                                        if ( nNextStringLen <= nHyperLenLeft )
                                        {
                                            pCurrent->mpFieldItem.reset( new SvxFieldItem( SvxURLField( pField->GetURL(), pCurrent->maString, SvxURLFormat::Repr ), EE_FEATURE_FIELD ) );
                                            nHyperLenLeft -= nNextStringLen;
 
                                            if ( nHyperLenLeft )
                                            {
                                                // if the next portion is in a higher paragraph,
                                                // the textrange is to decrease (because of the LineBreak character)
                                                if ( aCharPropList.size() > ( nIdx + 1 ) )
                                                {
                                                    PPTCharPropSet* pNext = aCharPropList[ nIdx + 1 ].get();
                                                    if ( pNext->mnParagraph > pCurrent->mnParagraph )
                                                        nHyperLenLeft--;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pCurrent );
                                            pNewCPS->maString = pCurrent->maString.copy( nHyperLenLeft,( nNextStringLen - nHyperLenLeft ) );
                                            aCharPropList.emplace( aCharPropList.begin() + nIdx + 1, pNewCPS );
                                            OUString aRepresentation = pCurrent->maString.copy( 0, nHyperLenLeft );
                                            pCurrent->mpFieldItem.reset( new SvxFieldItem( SvxURLField( pField->GetURL(), aRepresentation, SvxURLFormat::Repr ), EE_FEATURE_FIELD ) );
                                            nHyperLenLeft = 0;
                                        }
                                        pCurrent->maString.clear();
                                        pCurrent->SetColor( PPT_COLSCHEME_A_UND_HYPERLINK );
                                    }
                                    nIdx++;
                                }
                                (*FE)->xField1.reset();
 
                                if ( pBefCPS )
                                {
                                    pBefCPS->maString = aString.copy( 0, nCount );
                                    aCharPropList.emplace( aCharPropList.begin() + n, pBefCPS );
                                    n++;
                                }
                            }
                        }
                    }
                    break;
                }
            }
            n--;
        }
    }
    mxImplTextObj->maParagraphList.resize( nParagraphs );
    for (size_t nCurCharPos = 0, nCurPos = 0;
        nCurPos < aStyleTextPropReader.aParaPropList.size();
        ++nCurPos)
    {
        mxImplTextObj->maParagraphList[ nCurPos ].reset(
            new PPTParagraphObj(
                aStyleTextPropReader, nCurPos, nCurCharPos,
                *rSdrPowerPointImport.m_pPPTStyleSheet,
                nInstance, aTextRulerInterpreter ) );
 
        sal_uInt32 nParaAdjust, nFlags = 0;
        mxImplTextObj->maParagraphList[ nCurPos ]->GetAttrib( PPT_ParaAttr_Adjust, nParaAdjust, GetInstance() );
 
        switch ( nParaAdjust )
        {
            case 0 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT;   break;
            case 1 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER; break;
            case 2 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT;  break;
            case 3 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK;  break;
        }
        mxImplTextObj->mnTextFlags |= nFlags;
    }
}
 
PPTTextObj::PPTTextObj( PPTTextObj const & rTextObj )
{
    mxImplTextObj = rTextObj.mxImplTextObj;
}
 
PPTTextObj::~PPTTextObj()
{
}
 
PPTParagraphObj* PPTTextObj::First()
{
    mxImplTextObj->mnCurrentObject = 0;
    if ( !mxImplTextObj->mnParagraphCount )
        return nullptr;
    return mxImplTextObj->maParagraphList[ 0 ].get();
}
 
PPTParagraphObj* PPTTextObj::Next()
{
    sal_uInt32 i = mxImplTextObj->mnCurrentObject + 1;
    if ( i >= mxImplTextObj->mnParagraphCount )
        return nullptr;
    mxImplTextObj->mnCurrentObject++;
    return mxImplTextObj->maParagraphList[ i ].get();
}
 
const SfxItemSet* PPTTextObj::GetBackground() const
{
    if ( mxImplTextObj->mrPersistEntry.pBObj )
        return &mxImplTextObj->mrPersistEntry.pBObj->GetMergedItemSet();
    else
        return nullptr;
}
 
PPTTextObj& PPTTextObj::operator=( const PPTTextObj& rTextObj )
{
    if ( this != &rTextObj )
    {
        mxImplTextObj = rTextObj.mxImplTextObj;
    }
    return *this;
}
 
static bool IsLine( const SdrObject* pObj )
{
    auto pSdrPathObj = dynamic_cast< const SdrPathObj* >(pObj);
    return pSdrPathObj && pSdrPathObj->IsLine() && pSdrPathObj->GetPointCount() == 2;
}
 
static bool GetCellPosition( const SdrObject* pObj, const o3tl::sorted_vector< sal_Int32 >& rRows, const o3tl::sorted_vector< sal_Int32 >& rColumns,
                            sal_Int32& nTableIndex, sal_Int32& nRow, sal_Int32& nRowCount, sal_Int32& nColumn, sal_Int32& nColumnCount )
{
    tools::Rectangle aSnapRect( pObj->GetSnapRect() );
    bool bCellObject = ( aSnapRect.GetWidth() > 1 ) && ( aSnapRect.GetHeight() > 1 );
    if ( bCellObject )
    {
        auto aRowIter = rRows.find( aSnapRect.Top() );
        auto aColumnIter = rColumns.find( aSnapRect.Left() );
        if ( ( aRowIter == rRows.end() ) || ( aColumnIter == rColumns.end() ) )
            bCellObject = false;
        else
        {
            nRowCount = 1;
            nRow = std::distance( rRows.begin(), aRowIter );
            while( ++aRowIter != rRows.end() )
            {
                if ( *aRowIter >= aSnapRect.Bottom() )
                    break;
                nRowCount++;
            }
            nColumnCount = 1;
            nColumn = std::distance( rColumns.begin(), aColumnIter );
            while( ++aColumnIter != rColumns.end() )
            {
                if ( *aColumnIter >= aSnapRect.Right() )
                    break;
                nColumnCount++;
            }
            nTableIndex = nRow * rColumns.size() + nColumn;
        }
    }
    return bCellObject;
}
 
#define LinePositionLeft    0x01000000
#define LinePositionTop     0x02000000
#define LinePositionRight   0x04000000
#define LinePositionBottom  0x08000000
#define LinePositionTLBR    0x10000000
#define LinePositionBLTR    0x20000000
 
 
static void GetRowPositions( const tools::Rectangle& rSnapRect, const o3tl::sorted_vector< sal_Int32 >& rRows,
                        const o3tl::sorted_vector< sal_Int32 >& rColumns, std::vector< sal_Int32 >& rPositions, sal_Int32 nColumn, sal_Int32 nFlags )
{
    auto aRow = rRows.find( rSnapRect.Top() );
    if ( aRow == rRows.end() )
        return;
 
    sal_Int32 nRow = std::distance( rRows.begin(), aRow );
    while( ( aRow != rRows.end() ) && ((*aRow) < rSnapRect.Bottom() ) )
    {
        if ( nFlags & LinePositionLeft )
            rPositions.push_back( ( ( nRow * rColumns.size() ) + nColumn ) | LinePositionLeft );
        if ( nFlags & LinePositionRight )
            rPositions.push_back( ( ( nRow * rColumns.size() ) + ( nColumn - 1 ) ) | LinePositionRight );
 
        ++nRow;
        ++aRow;
    }
}
 
 
static void GetColumnPositions( const tools::Rectangle& rSnapRect,
                        const o3tl::sorted_vector< sal_Int32 >& rColumns, std::vector< sal_Int32 >& rPositions, sal_Int32 nRow, sal_Int32 nFlags )
{
    auto aColumn = rColumns.find( rSnapRect.Left() );
    if ( aColumn == rColumns.end() )
        return;
 
    sal_Int32 nColumn = std::distance( rColumns.begin(), aColumn );
    while( ( aColumn != rColumns.end() ) && ((*aColumn) < rSnapRect.Right() ) )
    {
        if ( nFlags & LinePositionTop )
            rPositions.push_back( ( ( nRow * rColumns.size() ) + nColumn ) | LinePositionTop );
        if ( nFlags & LinePositionBottom )
            rPositions.push_back( ( ( ( nRow - 1 ) * rColumns.size() ) + nColumn ) | LinePositionBottom );
 
        ++nColumn;
        ++aColumn;
    }
}
 
static void GetLinePositions( const SdrObject* pObj, const o3tl::sorted_vector< sal_Int32 >& rRows, const o3tl::sorted_vector< sal_Int32 >& rColumns,
                        std::vector< sal_Int32 >& rPositions, const tools::Rectangle& rGroupSnap )
{
    tools::Rectangle aSnapRect( pObj->GetSnapRect() );
    if ( aSnapRect.Left() == aSnapRect.Right() )
    {
        auto aColumn = rColumns.find( aSnapRect.Left() );
        if ( ( aColumn != rColumns.end() ) || ( aSnapRect.Left() == rGroupSnap.Right() ) )
        {
            sal_Int32 nColumn, nFlags;
            if ( aColumn != rColumns.end() )
            {
                nColumn = std::distance( rColumns.begin(), aColumn );
                nFlags = LinePositionLeft;
                if ( aColumn != rColumns.begin() )
                    nFlags |= LinePositionRight;
            }
            else
            {
                nColumn = rColumns.size();
                nFlags = LinePositionRight;
            }
            GetRowPositions( aSnapRect, rRows, rColumns, rPositions, nColumn, nFlags );
        }
    }
    else if ( aSnapRect.Top() == aSnapRect.Bottom() )
    {
        auto aRow = rRows.find( aSnapRect.Top() );
        if ( ( aRow != rRows.end() ) || ( aSnapRect.Top() == rGroupSnap.Bottom() ) )
        {
            sal_Int32 nRow, nFlags;
            if ( aRow != rRows.end() )
            {
                nRow = std::distance( rRows.begin(), aRow );
                nFlags = LinePositionTop;
                if ( aRow != rRows.begin() )
                    nFlags |= LinePositionBottom;
            }
            else
            {
                nRow = rRows.size();
                nFlags = LinePositionBottom;
            }
            GetColumnPositions( aSnapRect, rColumns, rPositions, nRow, nFlags );
        }
    }
    else
    {
        sal_uInt32 nPosition = 0;
        Point aPt1( static_cast<const SdrPathObj*>(pObj)->GetPoint( 0 ) );
        Point aPt2( static_cast<const SdrPathObj*>(pObj)->GetPoint( 1 ) );
        if ( aPt1.X() < aPt2.X() )
            nPosition |= aPt1.Y() < aPt2.Y() ? LinePositionTLBR : LinePositionBLTR;
        else
            nPosition |= aPt1.Y() < aPt2.Y() ? LinePositionBLTR : LinePositionTLBR;
 
        auto aRow = rRows.find( std::min(aPt1.Y(), aPt2.Y() ) );
        auto aColumn = rColumns.find( std::min(aPt1.X(), aPt2.X() ) );
        if ( ( aRow != rRows.end() ) && ( aColumn != rColumns.end() ) )
        {
            nPosition |= ( std::distance( rRows.begin(), aRow ) * rColumns.size() ) + std::distance( rColumns.begin(), aColumn );
            rPositions.push_back( nPosition );
        }
    }
}
 
static void CreateTableRows( const Reference< XTableRows >& xTableRows, const o3tl::sorted_vector< sal_Int32 >& rRows, sal_Int32 nTableBottom )
{
    if ( rRows.size() > 1 )
        xTableRows->insertByIndex( 0, rRows.size() - 1 );
 
    auto aIter = rRows.begin();
    sal_Int32 nLastPosition( *aIter );
    for ( sal_Int32 n = 0; n < xTableRows->getCount(); n++ )
    {
        sal_Int32 nHeight;
        if ( ++aIter != rRows.end() )
        {
            if (o3tl::checked_sub<sal_Int32>(*aIter, nLastPosition, nHeight))
                throw lang::IllegalArgumentException();
            nLastPosition = *aIter;
        }
        else
        {
            if (o3tl::checked_sub<sal_Int32>(nTableBottom, nLastPosition, nHeight))
                throw lang::IllegalArgumentException();
        }
 
        Reference< XPropertySet > xPropSet( xTableRows->getByIndex( n ), UNO_QUERY_THROW );
        xPropSet->setPropertyValue( u"Height"_ustr, Any( nHeight ) );
    }
}
 
static void CreateTableColumns( const Reference< XTableColumns >& xTableColumns, const o3tl::sorted_vector< sal_Int32 >& rColumns, sal_Int32 nTableRight )
{
    if ( rColumns.size() > 1 )
        xTableColumns->insertByIndex( 0, rColumns.size() - 1 );
 
    auto aIter = rColumns.begin();
    sal_Int32 nLastPosition( *aIter );
    for ( sal_Int32 n = 0; n < xTableColumns->getCount(); n++ )
    {
        sal_Int32 nWidth;
        if ( ++aIter != rColumns.end() )
        {
            if (o3tl::checked_sub<sal_Int32>(*aIter, nLastPosition, nWidth))
                throw lang::IllegalArgumentException();
            nLastPosition = *aIter;
        }
        else
        {
            if (o3tl::checked_sub<sal_Int32>(nTableRight, nLastPosition, nWidth))
                throw lang::IllegalArgumentException();
        }
 
        Reference< XPropertySet > xPropSet( xTableColumns->getByIndex( n ), UNO_QUERY_THROW );
        xPropSet->setPropertyValue( u"Width"_ustr, Any( nWidth ) );
    }
}
 
static void MergeCells( const Reference< XTable >& xTable, sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan )
{
   DBG_ASSERT( (nColSpan > 1) || (nRowSpan > 1), "nonsense parameter!!" );
   DBG_ASSERT( (nCol >= 0) && (nCol < xTable->getColumnCount()) && (nRow >= 0) && (nRow < xTable->getRowCount()), "the cell does not exists!!" );
   DBG_ASSERT( (nColSpan >= 1) && ((nCol  + nColSpan - 1) < xTable->getColumnCount()), "nColSpan botch!" );
   DBG_ASSERT(  (nRowSpan >= 1) && ((nRow  + nRowSpan - 1) < xTable->getRowCount()), "nRowSpan botch!" );
 
   if( xTable.is() ) try
   {
       Reference< XMergeableCellRange > xRange( xTable->createCursorByRange( xTable->getCellRangeByPosition( nCol, nRow,nCol + nColSpan - 1, nRow + nRowSpan - 1 ) ), UNO_QUERY_THROW );
       if( xRange->isMergeable() )
               xRange->merge();
   }
   catch( const Exception& )
   {
       DBG_UNHANDLED_EXCEPTION("filter.ms");
   }
}
 
static void ApplyCellAttributes( const SdrObject* pObj, Reference< XCell > const & xCell )
{
    try
    {
        Reference< XPropertySet > xPropSet( xCell, UNO_QUERY_THROW );
 
        const sal_Int32 nLeftDist(pObj->GetMergedItem(SDRATTR_TEXT_LEFTDIST).GetValue());
        const sal_Int32 nRightDist(pObj->GetMergedItem(SDRATTR_TEXT_RIGHTDIST).GetValue());
        const sal_Int32 nUpperDist(pObj->GetMergedItem(SDRATTR_TEXT_UPPERDIST).GetValue());
        const sal_Int32 nLowerDist(pObj->GetMergedItem(SDRATTR_TEXT_LOWERDIST).GetValue());
        xPropSet->setPropertyValue( u"TextUpperDistance"_ustr, Any( nUpperDist ) );
        xPropSet->setPropertyValue( u"TextRightDistance"_ustr, Any( nRightDist ) );
        xPropSet->setPropertyValue( u"TextLeftDistance"_ustr, Any( nLeftDist ) );
        xPropSet->setPropertyValue( u"TextLowerDistance"_ustr, Any( nLowerDist ) );
 
        const SdrTextVertAdjust eTextVertAdjust(pObj->GetMergedItem(SDRATTR_TEXT_VERTADJUST).GetValue());
        drawing::TextVerticalAdjust eVA( drawing::TextVerticalAdjust_TOP );
        if ( eTextVertAdjust == SDRTEXTVERTADJUST_CENTER )
            eVA = drawing::TextVerticalAdjust_CENTER;
        else if ( eTextVertAdjust == SDRTEXTVERTADJUST_BOTTOM )
            eVA = drawing::TextVerticalAdjust_BOTTOM;
        xPropSet->setPropertyValue( u"TextVerticalAdjust"_ustr, Any( eVA ) );
 
        //set textHorizontalAdjust and TextWritingMode attr
        const sal_Int32 eHA(pObj->GetMergedItem(SDRATTR_TEXT_HORZADJUST).GetValue());
        const SvxFrameDirection eDirection = pObj->GetMergedItem(EE_PARA_WRITINGDIR).GetValue();
        xPropSet->setPropertyValue(  u"TextHorizontalAdjust"_ustr , Any( eHA ) );
        if ( eDirection == SvxFrameDirection::Vertical_RL_TB )
        {//vertical writing
            xPropSet->setPropertyValue(  u"TextWritingMode"_ustr , Any( css::text::WritingMode_TB_RL ) );
        }
        drawing::FillStyle eFillStyle(pObj->GetMergedItem( XATTR_FILLSTYLE ).GetValue());
        css::drawing::FillStyle eFS( css::drawing::FillStyle_NONE );
        switch( eFillStyle )
        {
            case drawing::FillStyle_SOLID :
                {
                    eFS = css::drawing::FillStyle_SOLID;
                    Color aFillColor( pObj->GetMergedItem( XATTR_FILLCOLOR ).GetColorValue() );
                    xPropSet->setPropertyValue( u"FillColor"_ustr, Any( aFillColor ) );
                }
                break;
            case drawing::FillStyle_GRADIENT :
                {
                    eFS = css::drawing::FillStyle_GRADIENT;
                    basegfx::BGradient aBGradient(pObj->GetMergedItem(XATTR_FILLGRADIENT).GetGradientValue());
 
                    css::awt::Gradient aGradient;
                    aGradient.Style = aBGradient.GetGradientStyle();
                    aGradient.StartColor = static_cast<sal_Int32>(Color(aBGradient.GetColorStops().front().getStopColor()));
                    aGradient.EndColor = static_cast<sal_Int32>(Color(aBGradient.GetColorStops().back().getStopColor()));
                    aGradient.Angle = static_cast<short>(aBGradient.GetAngle());
                    aGradient.Border = aBGradient.GetBorder();
                    aGradient.XOffset = aBGradient.GetXOffset();
                    aGradient.YOffset = aBGradient.GetYOffset();
                    aGradient.StartIntensity = aBGradient.GetStartIntens();
                    aGradient.EndIntensity = aBGradient.GetEndIntens();
                    aGradient.StepCount = aBGradient.GetSteps();
 
                    xPropSet->setPropertyValue( u"FillGradient"_ustr, Any( aGradient ) );
                }
                break;
            case drawing::FillStyle_HATCH :
                eFS = css::drawing::FillStyle_HATCH;
            break;
            case drawing::FillStyle_BITMAP :
                {
                    eFS = css::drawing::FillStyle_BITMAP;
 
                    const XFillBitmapItem & rXFillBitmapItem(pObj->GetMergedItem( XATTR_FILLBITMAP ));
                    uno::Reference<graphic::XGraphic> xGraphic = rXFillBitmapItem.GetGraphicObject().GetGraphic().GetXGraphic();
                    uno::Reference<awt::XBitmap> xBitmap(xGraphic, uno::UNO_QUERY);
                    xPropSet->setPropertyValue(u"FillBitmap"_ustr, uno::Any(xBitmap));
 
                    const XFillBmpStretchItem & rStretchItem(pObj->GetMergedItem( XATTR_FILLBMP_STRETCH ));
                    const XFillBmpTileItem & rTileItem(pObj->GetMergedItem( XATTR_FILLBMP_TILE ));
                    if( rTileItem.GetValue() )
                        xPropSet->setPropertyValue(u"FillBitmapMode"_ustr, uno::Any(drawing::BitmapMode_REPEAT));
                    else if( rStretchItem.GetValue() )
                        xPropSet->setPropertyValue(u"FillBitmapMode"_ustr, uno::Any(drawing::BitmapMode_STRETCH));
                    else
                        xPropSet->setPropertyValue(u"FillBitmapMode"_ustr, uno::Any(drawing::BitmapMode_NO_REPEAT));
                }
            break;
            default:
            case drawing::FillStyle_NONE :
                eFS = css::drawing::FillStyle_NONE;
            break;
 
        }
        xPropSet->setPropertyValue( u"FillStyle"_ustr, Any( eFS ) );
        if ( eFillStyle != drawing::FillStyle_NONE )
        {
            sal_Int16 nFillTransparence( pObj->GetMergedItem( XATTR_FILLTRANSPARENCE ).GetValue() );
            xPropSet->setPropertyValue( u"FillTransparence"_ustr, Any( nFillTransparence ) );
        }
    }
    catch( const Exception& )
    {
    }
}
 
static void ApplyCellLineAttributes( const SdrObject* pLine, Reference< XTable > const & xTable, const std::vector< sal_Int32 >& vPositions, sal_Int32 nColumns )
{
    try
    {
        drawing::LineStyle eLineStyle(pLine->GetMergedItem( XATTR_LINESTYLE ).GetValue());
        css::table::BorderLine2 aBorderLine;
        switch( eLineStyle )
        {
            case drawing::LineStyle_DASH :
            case drawing::LineStyle_SOLID :
                {
                    Color aLineColor( pLine->GetMergedItem( XATTR_LINECOLOR ).GetColorValue() );
                    aBorderLine.Color = sal_Int32(aLineColor);
                    // Avoid width = 0, the min value should be 1.
                    sal_Int32 nLineWidth = std::max(sal_Int32(1), pLine->GetMergedItem(XATTR_LINEWIDTH) .GetValue() / 4);
                    aBorderLine.LineWidth = static_cast< sal_Int16 >( nLineWidth );
                    aBorderLine.LineStyle = eLineStyle == drawing::LineStyle_SOLID ? table::BorderLineStyle::SOLID : table::BorderLineStyle::DASHED;
                }
                break;
            default:
            case drawing::LineStyle_NONE :
                {
                    aBorderLine.LineWidth = 0;
                    aBorderLine.LineStyle = table::BorderLineStyle::NONE;
                }
            break;
        }
        for (auto const& vPos : vPositions)
        {
            sal_Int32 nPosition = vPos & 0xffffff;
            sal_Int32 nFlags = vPos &~0xffffff;
            sal_Int32 nRow = nPosition / nColumns;
            sal_Int32 nColumn = nPosition - ( nRow * nColumns );
            Reference< XCell > xCell( xTable->getCellByPosition( nColumn, nRow ) );
            Reference< XPropertySet > xPropSet( xCell, UNO_QUERY_THROW );
 
            if ( nFlags & LinePositionLeft )
                xPropSet->setPropertyValue( u"LeftBorder"_ustr, Any( aBorderLine ) );
            if ( nFlags & LinePositionTop )
                xPropSet->setPropertyValue( u"TopBorder"_ustr, Any( aBorderLine ) );
            if ( nFlags & LinePositionRight )
                xPropSet->setPropertyValue( u"RightBorder"_ustr, Any( aBorderLine ) );
            if ( nFlags & LinePositionBottom )
                xPropSet->setPropertyValue( u"BottomBorder"_ustr, Any( aBorderLine ) );
            if ( nFlags & LinePositionTLBR )
                xPropSet->setPropertyValue( u"DiagonalTLBR"_ustr, Any( true ) );
            if ( nFlags & LinePositionBLTR )
                xPropSet->setPropertyValue( u"DiagonalBLTR"_ustr, Any( true ) );
        }
    }
    catch( const Exception& )
    {
    }
}
 
rtl::Reference<SdrObject> SdrPowerPointImport::CreateTable(
        SdrObject* pGroup, const sal_uInt32* pTableArry,
        SvxMSDffSolverContainer* pSolverContainer)
{
    rtl::Reference<SdrObject> pRet = pGroup;
 
    sal_uInt32 nRows = pTableArry[ 1 ];
    if (!nRows)
        return pRet;
 
    const SdrObjGroup* pObjGroup = dynamic_cast<const SdrObjGroup*>(pGroup);
    if (!pObjGroup)
        return pRet;
 
    SdrObjList* pSubList(pObjGroup->GetSubList());
    if (!pSubList)
        return pRet;
 
    o3tl::sorted_vector< sal_Int32 > aRows;
    o3tl::sorted_vector< sal_Int32 > aColumns;
 
    SdrObjListIter aGroupIter( pSubList, SdrIterMode::DeepNoGroups, false );
    while( aGroupIter.IsMore() )
    {
        const SdrObject* pObj( aGroupIter.Next() );
        if ( !IsLine( pObj ) )
        {
            tools::Rectangle aSnapRect( pObj->GetSnapRect() );
            aRows.insert( aSnapRect.Top() );
            aColumns.insert( aSnapRect.Left() );
        }
    }
 
    if (aRows.empty())
        return pRet;
 
    rtl::Reference<sdr::table::SdrTableObj> pTable = new sdr::table::SdrTableObj(*pSdrModel);
    pTable->uno_lock();
    Reference< XTable > xTable( pTable->getTable() );
 
    try
    {
        CreateTableRows( xTable->getRows(), aRows, pGroup->GetSnapRect().Bottom() );
        CreateTableColumns( xTable->getColumns(), aColumns, pGroup->GetSnapRect().Right() );
 
        sal_Int32 nCellCount = aRows.size() * aColumns.size();
        std::unique_ptr<sal_Int32[]> pMergedCellIndexTable(new sal_Int32[ nCellCount ]);
        for ( sal_Int32 i = 0; i < nCellCount; i++ )
            pMergedCellIndexTable[ i ] = i;
 
        aGroupIter.Reset();
        while( aGroupIter.IsMore() )
        {
            SdrObject* pObj( aGroupIter.Next() );
            if ( !IsLine( pObj ) )
            {
                sal_Int32 nTableIndex = 0;
                sal_Int32 nRow = 0;
                sal_Int32 nRowCount = 0;
                sal_Int32 nColumn = 0;
                sal_Int32 nColumnCount = 0;
                if ( GetCellPosition( pObj, aRows, aColumns, nTableIndex, nRow, nRowCount, nColumn, nColumnCount ) )
                {
                    Reference< XCell > xCell( xTable->getCellByPosition( nColumn, nRow ) );
 
                    ApplyCellAttributes( pObj, xCell );
 
                    if ( ( nRowCount > 1 ) || ( nColumnCount > 1 ) )    // cell merging
                    {
                        MergeCells( xTable, nColumn, nRow, nColumnCount, nRowCount );
                        for ( sal_Int32 nRowIter = 0; nRowIter < nRowCount; nRowIter++ )
                        {
                            for ( sal_Int32 nColumnIter = 0; nColumnIter < nColumnCount; nColumnIter++ )
                            {   // now set the correct index for the merged cell
                                pMergedCellIndexTable[ ( ( nRow + nRowIter ) * aColumns.size() ) + nColumn + nColumnIter ] = nTableIndex;
                            }
                        }
                    }
 
                    // applying text
                    OutlinerParaObject* pParaObject = pObj->GetOutlinerParaObject();
                    if ( pParaObject )
                    {
                        SdrText* pSdrText = pTable->getText( nTableIndex );
                        if ( pSdrText )
                            pSdrText->SetOutlinerParaObject(*pParaObject);
                    }
                }
            }
        }
        aGroupIter.Reset();
        while( aGroupIter.IsMore() )
        {
            SdrObject* pObj( aGroupIter.Next() );
            if ( IsLine( pObj ) )
            {
                std::vector< sal_Int32 > vPositions;    // containing cell indexes + cell position
                GetLinePositions( pObj, aRows, aColumns, vPositions, pGroup->GetSnapRect() );
 
                // correcting merged cell position
                for (auto & vPos : vPositions)
                {
                    sal_Int32 nOldPosition = vPos & 0xffff;
                    sal_Int32 nOldFlags = vPos & 0xffff0000;
                    sal_Int32 nNewPosition = pMergedCellIndexTable[ nOldPosition ] | nOldFlags;
                    vPos = nNewPosition;
                }
                ApplyCellLineAttributes( pObj, xTable, vPositions, aColumns.size() );
            }
        }
        pMergedCellIndexTable.reset();
 
        // we are replacing the whole group object by a single table object, so
        // possibly connections to the group object have to be removed.
        if ( pSolverContainer )
        {
            for (auto & pPtr : pSolverContainer->aCList)
            {
                // check connections to the group object
                if ( pPtr->pAObj == pGroup )
                    pPtr->pAObj = nullptr;
                if ( pPtr->pBObj == pGroup )
                    pPtr->pBObj = nullptr;
 
                // check connections to all its subobjects
                SdrObjListIter aIter( *pGroup, SdrIterMode::DeepWithGroups );
                while( aIter.IsMore() )
                {
                    SdrObject* pPartObj = aIter.Next();
                    if ( pPtr->pAObj == pPartObj )
                        pPtr->pAObj = nullptr;
                    if ( pPtr->pBObj == pPartObj )
                        pPtr->pBObj = nullptr;
                }
                //In MS, the one_row_one_col table is made up of five
                //shape,the connector is connected to some part of a
                //table.  But for us, the connector is connected to the
                //whole group table,so the connector obj is a group
                //table when export by us. We should process this
                //situation when importing.
                if ( pPtr->pAObj == pGroup )
                    pPtr->pAObj = pTable.get();
                if ( pPtr->pBObj == pGroup )
                    pPtr->pBObj = pTable.get();
            }
        }
        pTable->uno_unlock();
        pTable->SetSnapRect( pGroup->GetSnapRect() );
        pRet = pTable;
 
        //Remove Objects from shape map
        SdrObjListIter aIter( *pGroup, SdrIterMode::DeepWithGroups );
        while( aIter.IsMore() )
        {
            SdrObject* pPartObj = aIter.Next();
            removeShapeId(pPartObj);
        }
    }
    catch( const Exception& )
    {
        pTable->uno_unlock();
        pTable = nullptr;
    }
 
    return pRet;
}
 
bool SdrPowerPointImport::IsVerticalText() const
{
    bool bVerticalText = false;
    if ( IsProperty( DFF_Prop_txflTextFlow ) )
    {
        auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
        switch( eTextFlow )
        {
        case mso_txflTtoBA :                    // Top to Bottom @-font, above -> below
        case mso_txflTtoBN :                    // Top to Bottom non-@, above -> below
        case mso_txflVertN :                    // Vertical, non-@, above -> below
            bVerticalText = !bVerticalText;
            break;
        default: break;
        }
    }
 
    return bVerticalText;
}
 
void    SdrPowerPointImport::ApplyTextAnchorAttributes( PPTTextObj const & rTextObj, SfxItemSet& rSet ) const
{
    SdrTextVertAdjust eTVA;
    SdrTextHorzAdjust eTHA;
 
    sal_uInt32 nTextFlags = rTextObj.GetTextFlags();
 
    nTextFlags &= PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT   | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT
        | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK;
 
    if ( IsVerticalText() )
    {
        eTVA = SDRTEXTVERTADJUST_BLOCK;
        eTHA = SDRTEXTHORZADJUST_CENTER;
 
        // read text anchor
        auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop);
 
        switch( eTextAnchor )
        {
        case mso_anchorTop:
        case mso_anchorTopCentered:
            eTHA = SDRTEXTHORZADJUST_RIGHT;
            break;
 
        case mso_anchorMiddle :
        case mso_anchorMiddleCentered:
            eTHA = SDRTEXTHORZADJUST_CENTER;
            break;
 
        case mso_anchorBottom:
        case mso_anchorBottomCentered:
            eTHA = SDRTEXTHORZADJUST_LEFT;
            break;
 
        default:
            break;
        }
        // if there is a 100% use of following attributes, the textbox can been aligned also in vertical direction
        switch ( eTextAnchor )
        {
        case mso_anchorTopCentered :
        case mso_anchorMiddleCentered :
        case mso_anchorBottomCentered :
            {
                // check if it is sensible to use the centered alignment
                sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT;
                if ( ( nTextFlags & nMask ) != nMask )  // if the textobject has left or also right aligned paragraphs
                    eTVA = SDRTEXTVERTADJUST_CENTER;    // the text has to be displayed using the full width;
            }
            break;
 
        default :
            {
                if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT )
                    eTVA = SDRTEXTVERTADJUST_TOP;
                else if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT )
                    eTVA = SDRTEXTVERTADJUST_BOTTOM;
            }
            break;
        }
    }
    else
    {
        eTVA = SDRTEXTVERTADJUST_CENTER;
        eTHA = SDRTEXTHORZADJUST_BLOCK;
 
        // read text anchor
        auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop);
 
        switch( eTextAnchor )
        {
        case mso_anchorTop:
        case mso_anchorTopCentered:
            eTVA = SDRTEXTVERTADJUST_TOP;
            break;
 
        case mso_anchorMiddle :
        case mso_anchorMiddleCentered:
            eTVA = SDRTEXTVERTADJUST_CENTER;
            break;
 
        case mso_anchorBottom:
        case mso_anchorBottomCentered:
            eTVA = SDRTEXTVERTADJUST_BOTTOM;
            break;
 
        default:
            break;
        }
 
        // if there is a 100% usage of following attributes, the textbox can be aligned also in horizontal direction
        switch ( eTextAnchor )
        {
        case mso_anchorTopCentered :
        case mso_anchorMiddleCentered :
        case mso_anchorBottomCentered :
            {
                // check if it is sensible to use the centered alignment
                sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT;
                if ( ( nTextFlags & nMask ) != nMask )  // if the textobject has left or also right aligned paragraphs
                    eTHA = SDRTEXTHORZADJUST_CENTER;    // the text has to be displayed using the full width;
            }
            break;
 
        default :
            {
                if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT )
                    eTHA = SDRTEXTHORZADJUST_LEFT;
                else if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT )
                    eTHA = SDRTEXTHORZADJUST_RIGHT;
            }
            break;
        }
    }
    rSet.Put( SdrTextVertAdjustItem( eTVA ) );
    rSet.Put( SdrTextHorzAdjustItem( eTHA ) );
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V1004 The 'rPersistEntry.pPresentationObjects' pointer was used unsafely after it was verified against nullptr. Check lines: 1006, 1011.

V1029 Numeric Truncation Error. Return value of the 'size' function is written to the 16-bit variable.

V1037 Two or more case-branches perform the same actions. Check lines: 2633, 2636

V1037 Two or more case-branches perform the same actions. Check lines: 4366, 4379

V1048 The 'eTHA' variable was assigned the same value.

V1048 The 'eTVA' variable was assigned the same value.

V1048 The 'eTHA' variable was assigned the same value.

V1048 The 'eTVA' variable was assigned the same value.

V1051 Consider checking for misprints. It's possible that the 'pConnectObj' should be checked here.