/* -*- 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 <config_features.h>
 
#include <cmdid.h>
#include <hintids.hxx>
#include <svl/stritem.hxx>
#include <com/sun/star/text/DefaultNumberingProvider.hpp>
#include <com/sun/star/text/XDefaultNumberingProvider.hpp>
#include <com/sun/star/text/XNumberingTypeInfo.hpp>
#include <com/sun/star/style/NumberingType.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/sdbc/XConnection.hpp>
#include <com/sun/star/sdbc/XDataSource.hpp>
#include <com/sun/star/uri/UriReferenceFactory.hpp>
#include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
#include <editeng/unolingu.hxx>
#include <unotools/localedatawrapper.hxx>
#include <tools/resary.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/linkmgr.hxx>
#include <sfx2/app.hxx>
#include <svx/dialogs.hrc>
#include <svx/strarray.hxx>
#include <basic/basmgr.hxx>
#include <editeng/langitem.hxx>
#include <svl/macitem.hxx>
#include <basic/sbmod.hxx>
#include <fmtrfmrk.hxx>
#include <basic/sbmeth.hxx>
#include <basic/sbx.hxx>
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
#include <vcl/mnemonic.hxx>
#include <view.hxx>
#include <wrtsh.hxx>
#include <doc.hxx>
#include <docsh.hxx>
#include <swmodule.hxx>
#include <charatr.hxx>
#include <fmtinfmt.hxx>
#include <cellatr.hxx>
#include <dbmgr.hxx>
#include <shellres.hxx>
#include <fldbas.hxx>
#include <docufld.hxx>
#include <chpfld.hxx>
#include <ddefld.hxx>
#include <expfld.hxx>
#include <reffld.hxx>
#include <usrfld.hxx>
#include <dbfld.hxx>
#include <authfld.hxx>
#include <flddat.hxx>
#include <fldmgr.hxx>
#include <flddropdown.hxx>
#include <strings.hrc>
#include <tox.hxx>
#include <cnttab.hxx>
#include <unotools/useroptions.hxx>
 
using namespace com::sun::star::uno;
using namespace com::sun::star::container;
using namespace com::sun::star::lang;
using namespace com::sun::star::beans;
using namespace com::sun::star::text;
using namespace com::sun::star::style;
using namespace com::sun::star::sdbc;
using namespace ::com::sun::star;
using namespace nsSwDocInfoSubType;
 
// groups of fields
enum
{
    GRP_DOC_BEGIN   =  0,
    GRP_DOC_END     =  GRP_DOC_BEGIN + 12,
 
    GRP_FKT_BEGIN   =  GRP_DOC_END,
    GRP_FKT_END     =  GRP_FKT_BEGIN + 8,
 
    GRP_REF_BEGIN   =  GRP_FKT_END,
    GRP_REF_END     =  GRP_REF_BEGIN + 2,
 
    GRP_REG_BEGIN   =  GRP_REF_END,
    GRP_REG_END     =  GRP_REG_BEGIN + 1,
 
    GRP_DB_BEGIN    =  GRP_REG_END,
    GRP_DB_END      =  GRP_DB_BEGIN  + 5,
 
    GRP_VAR_BEGIN   =  GRP_DB_END,
    GRP_VAR_END     =  GRP_VAR_BEGIN + 9
};
 
enum
{
    GRP_WEB_DOC_BEGIN   =  0,
    GRP_WEB_DOC_END     =  GRP_WEB_DOC_BEGIN + 9,
 
    GRP_WEB_FKT_BEGIN   =  GRP_WEB_DOC_END + 2,
    GRP_WEB_FKT_END     =  GRP_WEB_FKT_BEGIN + 0,   // the group is empty!
 
    GRP_WEB_REF_BEGIN   =  GRP_WEB_FKT_END + 6,     // the group is empty!
    GRP_WEB_REF_END     =  GRP_WEB_REF_BEGIN + 0,
 
    GRP_WEB_REG_BEGIN   =  GRP_WEB_REF_END + 2,
    GRP_WEB_REG_END     =  GRP_WEB_REG_BEGIN + 1,
 
    GRP_WEB_DB_BEGIN    =  GRP_WEB_REG_END,         // the group is empty!
    GRP_WEB_DB_END      =  GRP_WEB_DB_BEGIN  + 0,
 
    GRP_WEB_VAR_BEGIN   =  GRP_WEB_DB_END + 5,
    GRP_WEB_VAR_END     =  GRP_WEB_VAR_BEGIN + 1
};
 
static const sal_uInt16 VF_COUNT = 1; // { 0 }
static const sal_uInt16 VF_USR_COUNT = 2; // { 0, nsSwExtendedSubType::SUB_CMD }
static const sal_uInt16 VF_DB_COUNT = 1; // { nsSwExtendedSubType::SUB_OWN_FMT }
 
static const char* FLD_EU_ARY[] =
{
    FLD_EU_FIRMA,
    FLD_EU_VORNAME,
    FLD_EU_NAME,
    FLD_EU_ABK,
    FLD_EU_STRASSE,
    FLD_EU_LAND,
    FLD_EU_PLZ,
    FLD_EU_ORT,
    FLD_EU_TITEL,
    FLD_EU_POS,
    FLD_EU_TELPRIV,
    FLD_EU_TELFIRMA,
    FLD_EU_FAX,
    FLD_EU_EMAIL,
    FLD_EU_STATE
};
 
static const char* FMT_AUTHOR_ARY[] =
{
    FMT_AUTHOR_NAME,
    FMT_AUTHOR_SCUT
};
 
static const char* FLD_DATE_ARY[] =
{
    FLD_DATE_FIX,
    FLD_DATE_STD,
};
 
static const char* FLD_TIME_ARY[] =
{
    FLD_TIME_FIX,
    FLD_TIME_STD
};
 
static const char* FMT_NUM_ARY[] =
{
    FMT_NUM_ABC,
    FMT_NUM_SABC,
    FMT_NUM_ABC_N,
    FMT_NUM_SABC_N,
    FMT_NUM_ROMAN,
    FMT_NUM_SROMAN,
    FMT_NUM_ARABIC,
    FMT_NUM_PAGEDESC,
    FMT_NUM_PAGESPECIAL
};
 
static const char* FMT_FF_ARY[] =
{
    FMT_FF_NAME,
    FMT_FF_PATHNAME,
    FMT_FF_PATH,
    FMT_FF_NAME_NOEXT,
    FMT_FF_UI_NAME,
    FMT_FF_UI_RANGE
};
 
static const char* FLD_STAT_ARY[] =
{
    FLD_STAT_PAGE,
    FLD_STAT_PARA,
    FLD_STAT_WORD,
    FLD_STAT_CHAR,
    FLD_STAT_TABLE,
    FLD_STAT_GRF,
    FLD_STAT_OBJ
};
 
static const char* FMT_CHAPTER_ARY[] =
{
    FMT_CHAPTER_NO,
    FMT_CHAPTER_NAME,
    FMT_CHAPTER_NAMENO,
    FMT_CHAPTER_NO_NOSEPARATOR
};
 
static const char* FLD_INPUT_ARY[] =
{
    FLD_INPUT_TEXT
};
 
static const char* FMT_MARK_ARY[] =
{
    FMT_MARK_TEXT,
    FMT_MARK_TABLE,
    FMT_MARK_FRAME,
    FMT_MARK_GRAFIC,
    FMT_MARK_OLE
};
 
static const char* FMT_REF_ARY[] =
{
    FMT_REF_PAGE,
    FMT_REF_CHAPTER,
    FMT_REF_TEXT,
    FMT_REF_UPDOWN,
    FMT_REF_PAGE_PGDSC,
    FMT_REF_ONLYNUMBER,
    FMT_REF_ONLYCAPTION,
    FMT_REF_ONLYSEQNO,
    FMT_REF_NUMBER,
    FMT_REF_NUMBER_NO_CONTEXT,
    FMT_REF_NUMBER_FULL_CONTEXT
};
 
static const char* FMT_REG_ARY[] =
{
    FMT_REG_AUTHOR,
    FMT_REG_TIME,
    FMT_REG_DATE
};
 
static const char* FMT_DBFLD_ARY[] =
{
    FMT_DBFLD_DB,
    FMT_DBFLD_SYS
};
 
static const char* FMT_SETVAR_ARY[] =
{
    FMT_SETVAR_SYS,
    FMT_SETVAR_TEXT
};
 
static const char* FMT_GETVAR_ARY[] =
{
    FMT_GETVAR_TEXT,
    FMT_GETVAR_NAME
};
 
static const char* FMT_DDE_ARY[] =
{
    FMT_DDE_NORMAL,
    FMT_DDE_HOT
};
 
static const char* FLD_PAGEREF_ARY[] =
{
    FLD_PAGEREF_OFF,
    FLD_PAGEREF_ON
};
 
static const char* FMT_USERVAR_ARY[] =
{
    FMT_USERVAR_TEXT,
    FMT_USERVAR_CMD
};
 
// field types and subtypes
struct SwFieldPack
{
    sal_uInt16   nTypeId;
 
    const char** pSubTypeResIds;
    size_t       nSubTypeLength;
 
    const char** pFormatResIds;
    size_t       nFormatLength;
};
 
// strings and formats
static const SwFieldPack aSwFields[] =
{
    // Document
    { TYP_EXTUSERFLD,       FLD_EU_ARY,         SAL_N_ELEMENTS(FLD_EU_ARY),     nullptr,          0 },
    { TYP_AUTHORFLD,        nullptr,            0,                              FMT_AUTHOR_ARY,   SAL_N_ELEMENTS(FMT_AUTHOR_ARY) },
    { TYP_DATEFLD,          FLD_DATE_ARY,       SAL_N_ELEMENTS(FLD_DATE_ARY),   nullptr,          0 },
    { TYP_TIMEFLD,          FLD_TIME_ARY,       SAL_N_ELEMENTS(FLD_TIME_ARY),   nullptr,          0 },
    { TYP_PAGENUMBERFLD,    nullptr,            0,                              FMT_NUM_ARY,      SAL_N_ELEMENTS(FMT_NUM_ARY) -1 },
    { TYP_NEXTPAGEFLD,      nullptr,            0,                              FMT_NUM_ARY,      SAL_N_ELEMENTS(FMT_NUM_ARY) },
    { TYP_PREVPAGEFLD,      nullptr,            0,                              FMT_NUM_ARY,      SAL_N_ELEMENTS(FMT_NUM_ARY) },
    { TYP_FILENAMEFLD,      nullptr,            0,                              FMT_FF_ARY,       SAL_N_ELEMENTS(FMT_FF_ARY) },
    { TYP_DOCSTATFLD,       FLD_STAT_ARY,       SAL_N_ELEMENTS(FLD_STAT_ARY),   FMT_NUM_ARY,      SAL_N_ELEMENTS(FMT_NUM_ARY) -1 },
 
    { TYP_CHAPTERFLD,       nullptr,            0,                              FMT_CHAPTER_ARY,  SAL_N_ELEMENTS(FMT_CHAPTER_ARY) },
    { TYP_TEMPLNAMEFLD,     nullptr,            0,                              FMT_FF_ARY,       SAL_N_ELEMENTS(FMT_FF_ARY) },
    { TYP_PARAGRAPHSIGFLD,  nullptr,            0,                              nullptr,          0 },
 
    // Functions
    { TYP_CONDTXTFLD,       nullptr,            0,                              nullptr,          0 },
    { TYP_DROPDOWN,         nullptr,            0,                              nullptr,          0 },
    { TYP_INPUTFLD,         FLD_INPUT_ARY,      SAL_N_ELEMENTS(FLD_INPUT_ARY),  nullptr,          0 },
    { TYP_MACROFLD,         nullptr,            0,                              nullptr,          0 },
    { TYP_JUMPEDITFLD,      nullptr,            0,                              FMT_MARK_ARY,     SAL_N_ELEMENTS(FMT_MARK_ARY) },
    { TYP_COMBINED_CHARS,   nullptr,            0,                              nullptr,          0 },
    { TYP_HIDDENTXTFLD,     nullptr,            0,                              nullptr,          0 },
    { TYP_HIDDENPARAFLD,    nullptr,            0,                              nullptr,          0 },
 
    // Cross-References
    { TYP_SETREFFLD,        nullptr,            0,                              nullptr,          0 },
    { TYP_GETREFFLD,        nullptr,            0,                              FMT_REF_ARY,      SAL_N_ELEMENTS(FMT_REF_ARY) },
 
    // DocInformation
    { TYP_DOCINFOFLD,       nullptr,            0,                              FMT_REG_ARY,      SAL_N_ELEMENTS(FMT_REG_ARY) },
 
    // Database
    { TYP_DBFLD,            nullptr,            0,                              FMT_DBFLD_ARY,    SAL_N_ELEMENTS(FMT_DBFLD_ARY) },
    { TYP_DBNEXTSETFLD,     nullptr,            0,                              nullptr,          0 },
    { TYP_DBNUMSETFLD,      nullptr,            0,                              nullptr,          0 },
    { TYP_DBSETNUMBERFLD,   nullptr,            0,                              FMT_NUM_ARY,      SAL_N_ELEMENTS(FMT_NUM_ARY) - 2 },
    { TYP_DBNAMEFLD,        nullptr,            0,                              nullptr,          0 },
 
    // Variables
    { TYP_SETFLD,           nullptr,            0,                              FMT_SETVAR_ARY,   SAL_N_ELEMENTS(FMT_SETVAR_ARY) },
 
    { TYP_GETFLD,           nullptr,            0,                              FMT_GETVAR_ARY,   SAL_N_ELEMENTS(FMT_GETVAR_ARY) },
    { TYP_DDEFLD,           nullptr,            0,                              FMT_DDE_ARY,      SAL_N_ELEMENTS(FMT_DDE_ARY) },
    { TYP_FORMELFLD,        nullptr,            0,                              FMT_GETVAR_ARY,   SAL_N_ELEMENTS(FMT_GETVAR_ARY) },
    { TYP_INPUTFLD,         FLD_INPUT_ARY,      SAL_N_ELEMENTS(FLD_INPUT_ARY),  nullptr,          0 },
    { TYP_SEQFLD,           nullptr,            0,                              FMT_NUM_ARY,      SAL_N_ELEMENTS(FMT_NUM_ARY) - 2 },
    { TYP_SETREFPAGEFLD,    FLD_PAGEREF_ARY,    SAL_N_ELEMENTS(FLD_PAGEREF_ARY),nullptr,          0 },
    { TYP_GETREFPAGEFLD,    nullptr,            0,                              FMT_NUM_ARY,      SAL_N_ELEMENTS(FMT_NUM_ARY) - 1 },
    { TYP_USERFLD,          nullptr,            0,                              FMT_USERVAR_ARY,  SAL_N_ELEMENTS(FMT_USERVAR_ARY) }
};
 
// access to the shell
static SwWrtShell* lcl_GetShell()
{
    SwView* pView;
    if ( nullptr != (pView = ::GetActiveView()) )
        return pView->GetWrtShellPtr();
    OSL_FAIL("no current shell found!");
    return nullptr;
}
 
inline sal_uInt16 GetPackCount() {  return SAL_N_ELEMENTS(aSwFields); }
 
// FieldManager controls inserting and updating of fields
SwFieldMgr::SwFieldMgr(SwWrtShell* pSh ) :
    m_pWrtShell(pSh),
    m_bEvalExp(true)
{
    // determine current field if existing
    GetCurField();
}
 
SwFieldMgr::~SwFieldMgr()
{
}
 
// organise RefMark by names
bool  SwFieldMgr::CanInsertRefMark( const OUString& rStr )
{
    bool bRet = false;
    SwWrtShell *pSh = m_pWrtShell ? m_pWrtShell : lcl_GetShell();
    OSL_ENSURE(pSh, "no SwWrtShell found");
    if(pSh)
    {
        sal_uInt16 nCnt = pSh->GetCursorCnt();
 
        // the last Cursor doesn't have to be a spanned selection
        if( 1 < nCnt && !pSh->SwCursorShell::HasSelection() )
            --nCnt;
 
        bRet =  2 > nCnt && nullptr == pSh->GetRefMark( rStr );
    }
    return bRet;
}
 
// access over ResIds
void SwFieldMgr::RemoveFieldType(SwFieldIds nResId, const OUString& rName )
{
    SwWrtShell * pSh = m_pWrtShell ? m_pWrtShell : lcl_GetShell();
    OSL_ENSURE(pSh, "no SwWrtShell found");
    if( pSh )
        pSh->RemoveFieldType(nResId, rName);
}
 
size_t SwFieldMgr::GetFieldTypeCount() const
{
    SwWrtShell * pSh = m_pWrtShell ? m_pWrtShell : lcl_GetShell();
    OSL_ENSURE(pSh, "no SwWrtShell found");
    return pSh ? pSh->GetFieldTypeCount() : 0;
}
 
SwFieldType* SwFieldMgr::GetFieldType(SwFieldIds nResId, size_t nField) const
{
    SwWrtShell * pSh = m_pWrtShell ? m_pWrtShell : lcl_GetShell();
    OSL_ENSURE(pSh, "no SwWrtShell found");
    return pSh ? pSh->GetFieldType(nField, nResId) : nullptr;
}
 
SwFieldType* SwFieldMgr::GetFieldType(SwFieldIds nResId, const OUString& rName) const
{
    SwWrtShell * pSh = m_pWrtShell ? m_pWrtShell : lcl_GetShell();
    OSL_ENSURE(pSh, "no SwWrtShell found");
    return pSh ? pSh->GetFieldType(nResId, rName) : nullptr;
}
 
// determine current field
SwField* SwFieldMgr::GetCurField()
{
    SwWrtShell *pSh = m_pWrtShell ? m_pWrtShell : ::lcl_GetShell();
    if ( pSh )
        m_pCurField = pSh->GetCurField( true );
    else
        m_pCurField = nullptr;
 
    // initialise strings and format
    m_aCurPar1.clear();
    m_aCurPar2.clear();
    m_sCurFrame.clear();
    m_nCurFormat = 0;
 
    if(!m_pCurField)
        return nullptr;
 
    // preprocess current values; determine parameter 1 and parameter 2
    // as well as the format
    const sal_uInt16 nTypeId = m_pCurField->GetTypeId();
 
    m_nCurFormat     = m_pCurField->GetFormat();
    m_aCurPar1    = m_pCurField->GetPar1();
    m_aCurPar2    = m_pCurField->GetPar2();
 
    switch( nTypeId )
    {
        case TYP_PAGENUMBERFLD:
        case TYP_NEXTPAGEFLD:
        case TYP_PREVPAGEFLD:
        case TYP_GETREFPAGEFLD:
            if( m_nCurFormat == SVX_NUM_PAGEDESC )
                m_nCurFormat -= 2;
            break;
    }
    return m_pCurField;
}
 
// provide group range
const SwFieldGroupRgn& SwFieldMgr::GetGroupRange(bool bHtmlMode, sal_uInt16 nGrpId)
{
static SwFieldGroupRgn const aRanges[] =
{
    { /* Document   */  GRP_DOC_BEGIN,  GRP_DOC_END },
    { /* Functions  */  GRP_FKT_BEGIN,  GRP_FKT_END },
    { /* Cross-Refs */  GRP_REF_BEGIN,  GRP_REF_END },
    { /* DocInfos   */  GRP_REG_BEGIN,  GRP_REG_END },
    { /* Database   */  GRP_DB_BEGIN,   GRP_DB_END  },
    { /* User       */  GRP_VAR_BEGIN,  GRP_VAR_END }
};
static SwFieldGroupRgn const aWebRanges[] =
{
    { /* Document    */  GRP_WEB_DOC_BEGIN,  GRP_WEB_DOC_END },
    { /* Functions   */  GRP_WEB_FKT_BEGIN,  GRP_WEB_FKT_END },
    { /* Cross-Refs  */  GRP_WEB_REF_BEGIN,  GRP_WEB_REF_END },
    { /* DocInfos    */  GRP_WEB_REG_BEGIN,  GRP_WEB_REG_END },
    { /* Database    */  GRP_WEB_DB_BEGIN,   GRP_WEB_DB_END  },
    { /* User        */  GRP_WEB_VAR_BEGIN,  GRP_WEB_VAR_END }
};
 
    if (bHtmlMode)
        return aWebRanges[nGrpId];
    else
        return aRanges[nGrpId];
}
 
// determine GroupId
sal_uInt16 SwFieldMgr::GetGroup(sal_uInt16 nTypeId, sal_uInt16 nSubType)
{
    if (nTypeId == TYP_SETINPFLD)
        nTypeId = TYP_SETFLD;
 
    if (nTypeId == TYP_INPUTFLD && (nSubType & INP_USR))
        nTypeId = TYP_USERFLD;
 
    if (nTypeId == TYP_FIXDATEFLD)
        nTypeId = TYP_DATEFLD;
 
    if (nTypeId == TYP_FIXTIMEFLD)
        nTypeId = TYP_TIMEFLD;
 
    for (sal_uInt16 i = GRP_DOC; i <= GRP_VAR; i++)
    {
        const SwFieldGroupRgn& rRange = GetGroupRange(false/*bHtmlMode*/, i);
        for (sal_uInt16 nPos = rRange.nStart; nPos < rRange.nEnd; nPos++)
        {
            if (aSwFields[nPos].nTypeId == nTypeId)
                return i;
        }
    }
    return USHRT_MAX;
}
 
// determine names to TypeId
//  ACCESS over TYP_....
sal_uInt16 SwFieldMgr::GetTypeId(sal_uInt16 nPos)
{
    OSL_ENSURE(nPos < ::GetPackCount(), "forbidden Pos");
    return aSwFields[ nPos ].nTypeId;
}
 
OUString SwFieldMgr::GetTypeStr(sal_uInt16 nPos)
{
    OSL_ENSURE(nPos < ::GetPackCount(), "forbidden TypeId");
 
    sal_uInt16 nFieldWh = aSwFields[ nPos ].nTypeId;
 
    // special treatment for date/time fields (without var/fix)
    if( TYP_DATEFLD == nFieldWh )
    {
        static OUString g_aDate( SwResId( STR_DATEFLD ) );
        return g_aDate;
    }
    if( TYP_TIMEFLD == nFieldWh )
    {
        static OUString g_aTime( SwResId( STR_TIMEFLD ) );
        return g_aTime;
    }
 
    return SwFieldType::GetTypeStr( nFieldWh );
}
 
// determine Pos in the list
sal_uInt16 SwFieldMgr::GetPos(sal_uInt16 nTypeId)
{
    switch( nTypeId )
    {
        case TYP_FIXDATEFLD:        nTypeId = TYP_DATEFLD;      break;
        case TYP_FIXTIMEFLD:        nTypeId = TYP_TIMEFLD;      break;
        case TYP_SETINPFLD:         nTypeId = TYP_SETFLD;       break;
        case TYP_USRINPFLD:         nTypeId = TYP_USERFLD;      break;
    }
 
    for(sal_uInt16 i = 0; i < GetPackCount(); i++)
        if(aSwFields[i].nTypeId == nTypeId)
            return i;
 
    return USHRT_MAX;
}
 
// localise subtypes of a field
void SwFieldMgr::GetSubTypes(sal_uInt16 nTypeId, std::vector<OUString>& rToFill)
{
    SwWrtShell *pSh = m_pWrtShell ? m_pWrtShell : lcl_GetShell();
    OSL_ENSURE(pSh, "no SwWrtShell found");
    if(pSh)
    {
        const sal_uInt16 nPos = GetPos(nTypeId);
 
        switch(nTypeId)
        {
            case TYP_SETREFFLD:
            case TYP_GETREFFLD:
            {
                // references are no fields
                pSh->GetRefMarks( &rToFill );
                break;
            }
            case TYP_MACROFLD:
            {
                break;
            }
            case TYP_INPUTFLD:
            {
                rToFill.push_back(SwResId(aSwFields[nPos].pSubTypeResIds[0]));
                SAL_FALLTHROUGH; // move on at generic types
            }
            case TYP_DDEFLD:
            case TYP_SEQFLD:
            case TYP_FORMELFLD:
            case TYP_GETFLD:
            case TYP_SETFLD:
            case TYP_USERFLD:
            {
 
                const size_t nCount = pSh->GetFieldTypeCount();
                for(size_t i = 0; i < nCount; ++i)
                {
                    SwFieldType* pFieldType = pSh->GetFieldType( i );
                    const SwFieldIds nWhich = pFieldType->Which();
 
                    if((nTypeId == TYP_DDEFLD && pFieldType->Which() == SwFieldIds::Dde) ||
 
                       (nTypeId == TYP_USERFLD && nWhich == SwFieldIds::User) ||
 
                       (nTypeId == TYP_GETFLD && nWhich == SwFieldIds::SetExp &&
                        !(static_cast<SwSetExpFieldType*>(pFieldType)->GetType() & nsSwGetSetExpType::GSE_SEQ)) ||
 
                       (nTypeId == TYP_SETFLD && nWhich == SwFieldIds::SetExp &&
                        !(static_cast<SwSetExpFieldType*>(pFieldType)->GetType() & nsSwGetSetExpType::GSE_SEQ)) ||
 
                       (nTypeId == TYP_SEQFLD && nWhich == SwFieldIds::SetExp  &&
                       (static_cast<SwSetExpFieldType*>(pFieldType)->GetType() & nsSwGetSetExpType::GSE_SEQ)) ||
 
                       ((nTypeId == TYP_INPUTFLD || nTypeId == TYP_FORMELFLD) &&
                         (nWhich == SwFieldIds::User ||
                          (nWhich == SwFieldIds::SetExp &&
                          !(static_cast<SwSetExpFieldType*>(pFieldType)->GetType() & nsSwGetSetExpType::GSE_SEQ))) ) )
                    {
                        rToFill.push_back(pFieldType->GetName());
                    }
                }
                break;
            }
            case TYP_DBNEXTSETFLD:
            case TYP_DBNUMSETFLD:
            case TYP_DBNAMEFLD:
            case TYP_DBSETNUMBERFLD:
                break;
 
            default:
            {
                // static SubTypes
                if(nPos != USHRT_MAX)
                {
                    sal_uInt16 nCount;
                    if (nTypeId == TYP_DOCINFOFLD)
                        nCount = DI_SUBTYPE_END - DI_SUBTYPE_BEGIN;
                    else
                        nCount = aSwFields[nPos].nSubTypeLength;
 
                    for(sal_uInt16 i = 0; i < nCount; ++i)
                    {
                        OUString sNew;
                        if (nTypeId == TYP_DOCINFOFLD)
                        {
                            if ( i == DI_CUSTOM )
                                sNew = SwResId(STR_CUSTOM_FIELD);
                            else
                                sNew = SwViewShell::GetShellRes()->aDocInfoLst[i];
                        }
                        else
                            sNew = SwResId(aSwFields[nPos].pSubTypeResIds[i]);
 
                        rToFill.push_back(sNew);
                    }
                }
            }
        }
    }
}
 
// determine format
//  ACCESS over TYP_....
sal_uInt16 SwFieldMgr::GetFormatCount(sal_uInt16 nTypeId, bool bHtmlMode) const
{
    OSL_ENSURE(nTypeId < TYP_END, "forbidden TypeId");
    {
        const sal_uInt16 nPos = GetPos(nTypeId);
 
        if (nPos == USHRT_MAX || (bHtmlMode && nTypeId == TYP_SETFLD))
            return 0;
 
        sal_uInt16 nCount = aSwFields[nPos].nFormatLength;
 
        if (nTypeId == TYP_FILENAMEFLD)
            nCount -= 2;  // no range or template
 
        const char** pStart = aSwFields[nPos].pFormatResIds;
        if (!pStart)
            return nCount;
 
        if (strcmp(*pStart, FMT_GETVAR_ARY[0]) == 0 || strcmp(*pStart, FMT_SETVAR_ARY[0]) == 0)
            return VF_COUNT;
        else if (strcmp(*pStart, FMT_USERVAR_ARY[0]) == 0)
            return VF_USR_COUNT;
        else if (strcmp(*pStart, FMT_DBFLD_ARY[0]) == 0)
            return VF_DB_COUNT;
        else if (strcmp(*pStart, FMT_NUM_ARY[0]) == 0)
        {
            GetNumberingInfo();
            if(m_xNumberingInfo.is())
            {
                Sequence<sal_Int16> aTypes = m_xNumberingInfo->getSupportedNumberingTypes();
                const sal_Int16* pTypes = aTypes.getConstArray();
                for(sal_Int32 nType = 0; nType < aTypes.getLength(); nType++)
                {
                    sal_Int16 nCurrent = pTypes[nType];
                    //skip all values below or equal to CHARS_LOWER_LETTER_N
                    if(nCurrent > NumberingType::CHARS_LOWER_LETTER_N)
                    {
                        // #i28073# it's not necessarily a sorted sequence
                        ++nCount;
                    }
                }
            }
            return nCount;
        }
 
        return nCount;
    }
}
 
// determine FormatString to a type
OUString SwFieldMgr::GetFormatStr(sal_uInt16 nTypeId, sal_uInt32 nFormatId) const
{
    OSL_ENSURE(nTypeId < TYP_END, "forbidden TypeId");
    const sal_uInt16 nPos = GetPos(nTypeId);
 
    if (nPos == USHRT_MAX)
        return OUString();
 
    const char** pStart = aSwFields[nPos].pFormatResIds;
    if (!pStart)
        return OUString();
 
    if (TYP_AUTHORFLD == nTypeId|| TYP_FILENAMEFLD == nTypeId)
        nFormatId &= ~static_cast<sal_uInt32>(FF_FIXED); // mask out Fixed-Flag
 
    if (nFormatId < aSwFields[nPos].nFormatLength)
        return SwResId(pStart[nFormatId]);
 
    OUString aRet;
    if (*pStart == FMT_NUM_ARY[0])
    {
        if (m_xNumberingInfo.is())
        {
            Sequence<sal_Int16> aTypes = m_xNumberingInfo->getSupportedNumberingTypes();
            const sal_Int16* pTypes = aTypes.getConstArray();
            sal_Int32 nOffset = aSwFields[nPos].nFormatLength;
            sal_uInt32 nValidEntry = 0;
            for (sal_Int32 nType = 0; nType < aTypes.getLength(); nType++)
            {
                sal_Int16 nCurrent = pTypes[nType];
                if(nCurrent > NumberingType::CHARS_LOWER_LETTER_N &&
                        (nCurrent != (NumberingType::BITMAP | LINK_TOKEN)))
                {
                    if (nValidEntry == nFormatId - nOffset)
                    {
                        sal_uInt32 n = SvxNumberingTypeTable::FindIndex(pTypes[nType]);
                        if (n != RESARRAY_INDEX_NOTFOUND)
                        {
                            aRet = SvxNumberingTypeTable::GetString(n);
                        }
                        else
                        {
                            aRet = m_xNumberingInfo->getNumberingIdentifier( pTypes[nType] );
                        }
                        break;
                    }
                    ++nValidEntry;
                }
            }
        }
    }
 
    return aRet;
}
 
// determine FormatId from Pseudo-ID
sal_uInt16 SwFieldMgr::GetFormatId(sal_uInt16 nTypeId, sal_uInt32 nFormatId) const
{
    sal_uInt16 nId = static_cast<sal_uInt16>(nFormatId);
    switch( nTypeId )
    {
        case TYP_DOCINFOFLD:
        {
            const OString sId(aSwFields[GetPos(nTypeId)].pFormatResIds[nFormatId]);
            if (sId == FMT_REG_AUTHOR)
                nId = DI_SUB_AUTHOR;
            else if (sId == FMT_REG_TIME)
                nId = DI_SUB_TIME;
            else if (sId == FMT_REG_DATE)
                nId = DI_SUB_DATE;
            break;
        }
        case TYP_PAGENUMBERFLD:
        case TYP_NEXTPAGEFLD:
        case TYP_PREVPAGEFLD:
        case TYP_DOCSTATFLD:
        case TYP_DBSETNUMBERFLD:
        case TYP_SEQFLD:
        case TYP_GETREFPAGEFLD:
        {
            sal_uInt16 nPos = GetPos(nTypeId);
            if (nFormatId < aSwFields[nPos].nFormatLength)
            {
                const OString sId(aSwFields[nPos].pFormatResIds[nFormatId]);
                if (sId == FMT_NUM_ABC)
                    nId = SVX_NUM_CHARS_UPPER_LETTER;
                else if (sId == FMT_NUM_SABC)
                    nId = SVX_NUM_CHARS_LOWER_LETTER;
                else if (sId == FMT_NUM_ROMAN)
                    nId = SVX_NUM_ROMAN_UPPER;
                else if (sId == FMT_NUM_SROMAN)
                    nId = SVX_NUM_ROMAN_LOWER;
                else if (sId == FMT_NUM_ARABIC)
                    nId = SVX_NUM_ARABIC;
                else if (sId == FMT_NUM_PAGEDESC)
                    nId = SVX_NUM_PAGEDESC;
                else if (sId == FMT_NUM_PAGESPECIAL)
                    nId = SVX_NUM_CHAR_SPECIAL;
                else if (sId == FMT_NUM_ABC_N)
                    nId = SVX_NUM_CHARS_UPPER_LETTER_N;
                else if (sId == FMT_NUM_SABC_N)
                    nId = SVX_NUM_CHARS_LOWER_LETTER_N;
            }
            else if (m_xNumberingInfo.is())
            {
                Sequence<sal_Int16> aTypes = m_xNumberingInfo->getSupportedNumberingTypes();
                const sal_Int16* pTypes = aTypes.getConstArray();
                sal_Int32 nOffset = aSwFields[nPos].nFormatLength;
                sal_Int32 nValidEntry = 0;
                for (sal_Int32 nType = 0; nType < aTypes.getLength(); nType++)
                {
                    sal_Int16 nCurrent = pTypes[nType];
                    if (nCurrent > NumberingType::CHARS_LOWER_LETTER_N)
                    {
                        if (nValidEntry == static_cast<sal_Int32>(nFormatId) - nOffset)
                        {
                            nId = pTypes[nType];
                            break;
                        }
                        ++nValidEntry;
                    }
                }
            }
            break;
        }
        case TYP_DDEFLD:
        {
            const OString sId(aSwFields[GetPos(nTypeId)].pFormatResIds[nFormatId]);
            if (sId == FMT_DDE_NORMAL)
                nId = static_cast<sal_uInt16>(SfxLinkUpdateMode::ONCALL);
            else if (sId == FMT_DDE_HOT)
                nId = static_cast<sal_uInt16>(SfxLinkUpdateMode::ALWAYS);
            break;
        }
    }
    return nId;
}
 
// Traveling
bool SwFieldMgr::GoNextPrev( bool bNext, SwFieldType* pTyp )
{
    SwWrtShell* pSh = m_pWrtShell ? m_pWrtShell : ::lcl_GetShell();
    if(!pSh)
        return false;
 
    if( !pTyp && m_pCurField )
    {
        const sal_uInt16 nTypeId = m_pCurField->GetTypeId();
        if( TYP_SETINPFLD == nTypeId || TYP_USRINPFLD == nTypeId )
            pTyp = pSh->GetFieldType( 0, SwFieldIds::Input );
        else
            pTyp = m_pCurField->GetTyp();
    }
 
    if (pTyp && pTyp->Which() == SwFieldIds::Database)
    {
        // for fieldcommand-edit (hop to all DB fields)
        return pSh->MoveFieldType( nullptr, bNext, SwFieldIds::Database );
    }
 
    return pTyp && pSh && pSh->MoveFieldType( pTyp, bNext );
}
 
// insert field types
void SwFieldMgr::InsertFieldType(SwFieldType const & rType)
{
    SwWrtShell* pSh = m_pWrtShell ? m_pWrtShell : ::lcl_GetShell();
    OSL_ENSURE(pSh, "no SwWrtShell found");
    if(pSh)
        pSh->InsertFieldType(rType);
}
 
// determine current TypeId
sal_uInt16 SwFieldMgr::GetCurTypeId() const
{
    return m_pCurField ? m_pCurField->GetTypeId() : USHRT_MAX;
}
 
// Over string  insert field or update
bool SwFieldMgr::InsertField(
    const SwInsertField_Data& rData)
{
    SwField* pField   = nullptr;
    bool bExp = false;
    bool bTable = false;
    bool bPageVar = false;
    sal_uInt32 nFormatId = rData.m_nFormatId;
    sal_uInt16 nSubType = rData.m_nSubType;
    sal_Unicode cSeparator = rData.m_cSeparator;
    SwWrtShell* pCurShell = rData.m_pSh;
    if(!pCurShell)
        pCurShell = m_pWrtShell ? m_pWrtShell : ::lcl_GetShell();
    OSL_ENSURE(pCurShell, "no SwWrtShell found");
    if(!pCurShell)
        return false;
 
    switch (rData.m_nTypeId)
    {   // ATTENTION this field is inserted by a separate dialog
        case TYP_POSTITFLD:
        {
            SvtUserOptions aUserOpt;
            SwPostItFieldType* pType = static_cast<SwPostItFieldType*>(pCurShell->GetFieldType(0, SwFieldIds::Postit));
            SwPostItField* pPostItField =
                new SwPostItField(
                    pType,
                    rData.m_sPar1, // author
                    rData.m_sPar2, // content
                    aUserOpt.GetID(), // author's initials
                    OUString(), // name
                    DateTime(DateTime::SYSTEM) );
            pField = pPostItField;
        }
        break;
        case TYP_SCRIPTFLD:
        {
            SwScriptFieldType* pType =
                static_cast<SwScriptFieldType*>(pCurShell->GetFieldType(0, SwFieldIds::Script));
            pField = new SwScriptField(pType, rData.m_sPar1, rData.m_sPar2, static_cast<bool>(nFormatId));
            break;
        }
 
    case TYP_COMBINED_CHARS:
        {
            SwCombinedCharFieldType* pType = static_cast<SwCombinedCharFieldType*>(
                pCurShell->GetFieldType( 0, SwFieldIds::CombinedChars ));
            pField = new SwCombinedCharField( pType, rData.m_sPar1 );
        }
        break;
 
    case TYP_AUTHORITY:
        {
            SwAuthorityFieldType* pType =
                static_cast<SwAuthorityFieldType*>(pCurShell->GetFieldType(0, SwFieldIds::TableOfAuthorities));
            if (!pType)
            {
                SwAuthorityFieldType const type(pCurShell->GetDoc());
                pType = static_cast<SwAuthorityFieldType*>(
                            pCurShell->InsertFieldType(type));
            }
            pField = new SwAuthorityField(pType, rData.m_sPar1);
        }
        break;
 
    case TYP_DATEFLD:
    case TYP_TIMEFLD:
        {
            sal_uInt16 nSub = static_cast< sal_uInt16 >(rData.m_nTypeId == TYP_DATEFLD ? DATEFLD : TIMEFLD);
            nSub |= nSubType == DATE_VAR ? 0 : FIXEDFLD;
 
            SwDateTimeFieldType* pTyp =
                static_cast<SwDateTimeFieldType*>( pCurShell->GetFieldType(0, SwFieldIds::DateTime) );
            pField = new SwDateTimeField(pTyp, nSub, nFormatId);
            pField->SetPar2(rData.m_sPar2);
            break;
        }
 
    case TYP_FILENAMEFLD:
        {
            SwFileNameFieldType* pTyp =
                static_cast<SwFileNameFieldType*>( pCurShell->GetFieldType(0, SwFieldIds::Filename) );
            pField = new SwFileNameField(pTyp, nFormatId);
            break;
        }
 
    case TYP_TEMPLNAMEFLD:
        {
            SwTemplNameFieldType* pTyp =
                static_cast<SwTemplNameFieldType*>( pCurShell->GetFieldType(0, SwFieldIds::TemplateName) );
            pField = new SwTemplNameField(pTyp, nFormatId);
            break;
        }
 
    case TYP_CHAPTERFLD:
        {
            sal_uInt16 nByte = static_cast<sal_uInt16>(rData.m_sPar2.toInt32());
            SwChapterFieldType* pTyp =
                static_cast<SwChapterFieldType*>( pCurShell->GetFieldType(0, SwFieldIds::Chapter) );
            pField = new SwChapterField(pTyp, nFormatId);
            nByte = std::max(sal_uInt16(1), nByte);
            nByte = std::min(nByte, sal_uInt16(MAXLEVEL));
            nByte -= 1;
            static_cast<SwChapterField*>(pField)->SetLevel(static_cast<sal_uInt8>(nByte));
            break;
        }
 
    case TYP_NEXTPAGEFLD:
    case TYP_PREVPAGEFLD:
    case TYP_PAGENUMBERFLD:
        {
            short nOff = static_cast<short>(rData.m_sPar2.toInt32());
 
            if(rData.m_nTypeId == TYP_NEXTPAGEFLD)
            {
                if( SVX_NUM_CHAR_SPECIAL == nFormatId )
                    nOff = 1;
                else
                    nOff += 1;
                nSubType = PG_NEXT;
            }
            else if(rData.m_nTypeId == TYP_PREVPAGEFLD)
            {
                if( SVX_NUM_CHAR_SPECIAL == nFormatId )
                    nOff = -1;
                else
                    nOff -= 1;
                nSubType =  PG_PREV;
            }
            else
                nSubType = PG_RANDOM;
 
            SwPageNumberFieldType* pTyp =
                static_cast<SwPageNumberFieldType*>( pCurShell->GetFieldType(0, SwFieldIds::PageNumber) );
            pField = new SwPageNumberField(pTyp, nSubType, nFormatId, nOff);
 
            if( SVX_NUM_CHAR_SPECIAL == nFormatId &&
                ( PG_PREV == nSubType || PG_NEXT == nSubType ) )
                static_cast<SwPageNumberField*>(pField)->SetUserString( rData.m_sPar2 );
            break;
        }
 
    case TYP_DOCSTATFLD:
        {
            SwDocStatFieldType* pTyp =
                static_cast<SwDocStatFieldType*>( pCurShell->GetFieldType(0, SwFieldIds::DocStat) );
            pField = new SwDocStatField(pTyp, nSubType, nFormatId);
            break;
        }
 
    case TYP_AUTHORFLD:
        {
            SwAuthorFieldType* pTyp =
                static_cast<SwAuthorFieldType*>( pCurShell->GetFieldType(0, SwFieldIds::Author) );
            pField = new SwAuthorField(pTyp, nFormatId);
            break;
        }
 
    case TYP_CONDTXTFLD:
    case TYP_HIDDENTXTFLD:
        {
            SwHiddenTextFieldType* pTyp =
                static_cast<SwHiddenTextFieldType*>( pCurShell->GetFieldType(0, SwFieldIds::HiddenText) );
            pField = new SwHiddenTextField(pTyp, true, rData.m_sPar1, rData.m_sPar2, false, rData.m_nTypeId);
            bExp = true;
            break;
        }
 
    case TYP_HIDDENPARAFLD:
        {
            SwHiddenParaFieldType* pTyp =
                static_cast<SwHiddenParaFieldType*>( pCurShell->GetFieldType(0, SwFieldIds::HiddenPara) );
            pField = new SwHiddenParaField(pTyp, rData.m_sPar1);
            bExp = true;
            break;
        }
 
    case TYP_SETREFFLD:
        {
            if( !rData.m_sPar1.isEmpty() && CanInsertRefMark( rData.m_sPar1 ) )
            {
                pCurShell->SetAttrItem( SwFormatRefMark( rData.m_sPar1 ) );
                return true;
            }
            return false;
        }
 
    case TYP_GETREFFLD:
        {
            SwGetRefFieldType* pTyp =
                static_cast<SwGetRefFieldType*>( pCurShell->GetFieldType(0, SwFieldIds::GetRef) );
            sal_uInt16 nSeqNo = static_cast<sal_uInt16>(rData.m_sPar2.toInt32());
            OUString sReferenceLanguage;
            // handle language-variant formats
            if (nFormatId >= SAL_N_ELEMENTS(FMT_REF_ARY))
            {
                LanguageType nLang = GetCurrLanguage();
                if (nLang == LANGUAGE_HUNGARIAN)
                {
                    if (nFormatId >= SAL_N_ELEMENTS(FMT_REF_ARY) * 2)
                        sReferenceLanguage = "Hu";
                    else
                        sReferenceLanguage = "hu";
                }
                nFormatId %= SAL_N_ELEMENTS(FMT_REF_ARY);
            }
            pField = new SwGetRefField(pTyp, rData.m_sPar1, sReferenceLanguage, nSubType, nSeqNo, nFormatId);
            bExp = true;
            break;
        }
 
    case TYP_DDEFLD:
        {
            //JP 28.08.95: DDE-Topics/-Items can have blanks in their names!
            //              That's not yet considered here.
            sal_Int32 nIndex = 0;
            OUString sCmd = rData.m_sPar2.replaceFirst(" ", OUStringLiteral1(sfx2::cTokenSeparator), &nIndex);
            if (nIndex>=0 && ++nIndex<sCmd.getLength())
            {
                sCmd = sCmd.replaceFirst(" ", OUStringLiteral1(sfx2::cTokenSeparator), &nIndex);
            }
 
            SwDDEFieldType aType( rData.m_sPar1, sCmd, static_cast<SfxLinkUpdateMode>(nFormatId) );
            SwDDEFieldType* pTyp = static_cast<SwDDEFieldType*>( pCurShell->InsertFieldType( aType ) );
            pField = new SwDDEField( pTyp );
            break;
        }
 
    case TYP_MACROFLD:
        {
            SwMacroFieldType* pTyp =
                static_cast<SwMacroFieldType*>(pCurShell->GetFieldType(0, SwFieldIds::Macro));
 
            pField = new SwMacroField(pTyp, rData.m_sPar1, rData.m_sPar2);
 
            break;
        }
 
    case TYP_INTERNETFLD:
        {
            SwFormatINetFormat aFormat( rData.m_sPar1, m_sCurFrame );
            return pCurShell->InsertURL( aFormat, rData.m_sPar2 );
        }
 
    case TYP_JUMPEDITFLD:
        {
            SwJumpEditFieldType* pTyp =
                static_cast<SwJumpEditFieldType*>(pCurShell->GetFieldType(0, SwFieldIds::JumpEdit));
 
            pField = new SwJumpEditField(pTyp, nFormatId, rData.m_sPar1, rData.m_sPar2);
            break;
        }
 
    case TYP_DOCINFOFLD:
        {
            SwDocInfoFieldType* pTyp = static_cast<SwDocInfoFieldType*>( pCurShell->GetFieldType(
                0, SwFieldIds::DocInfo ) );
            pField = new SwDocInfoField(pTyp, nSubType, rData.m_sPar1, nFormatId);
            break;
        }
 
    case TYP_EXTUSERFLD:
        {
            SwExtUserFieldType* pTyp = static_cast<SwExtUserFieldType*>( pCurShell->GetFieldType(
                0, SwFieldIds::ExtUser) );
            pField = new SwExtUserField(pTyp, nSubType, nFormatId);
            break;
        }
 
    case TYP_DBFLD:
        {
#if HAVE_FEATURE_DBCONNECTIVITY
            SwDBData aDBData;
            OUString sPar1;
 
            if (rData.m_sPar1.indexOf(DB_DELIM)<0)
            {
                aDBData = pCurShell->GetDBData();
                sPar1 = rData.m_sPar1;
            }
            else
            {
                aDBData.sDataSource = rData.m_sPar1.getToken(0, DB_DELIM);
                aDBData.sCommand = rData.m_sPar1.getToken(1, DB_DELIM);
                aDBData.nCommandType = rData.m_sPar1.getToken(2, DB_DELIM).toInt32();
                sPar1 = rData.m_sPar1.getToken(3, DB_DELIM);
            }
 
            if(!aDBData.sDataSource.isEmpty() && pCurShell->GetDBData() != aDBData)
                pCurShell->ChgDBData(aDBData);
 
            SwDBFieldType* pTyp = static_cast<SwDBFieldType*>(pCurShell->InsertFieldType(
                SwDBFieldType(pCurShell->GetDoc(), sPar1, aDBData) ) );
            pField = new SwDBField(pTyp);
            pField->SetSubType(nSubType);
 
            if( !(nSubType & nsSwExtendedSubType::SUB_OWN_FMT) ) // determine database format
            {
                Reference< XDataSource> xSource;
                rData.m_aDBDataSource >>= xSource;
                Reference<XConnection> xConnection;
                rData.m_aDBConnection >>= xConnection;
                Reference<XPropertySet> xColumn;
                rData.m_aDBColumn >>= xColumn;
                if(xColumn.is())
                {
                    nFormatId = SwDBManager::GetColumnFormat(xSource, xConnection, xColumn,
                        pCurShell->GetNumberFormatter(), GetCurrLanguage() );
                }
                else
                    nFormatId = pCurShell->GetDBManager()->GetColumnFormat(
                    aDBData.sDataSource, aDBData.sCommand, sPar1,
                    pCurShell->GetNumberFormatter(), GetCurrLanguage() );
            }
            pField->ChangeFormat( nFormatId );
 
            bExp = true;
#endif
            break;
        }
 
    case TYP_DBSETNUMBERFLD:
    case TYP_DBNUMSETFLD:
    case TYP_DBNEXTSETFLD:
    case TYP_DBNAMEFLD:
        {
#if HAVE_FEATURE_DBCONNECTIVITY
            SwDBData aDBData;
 
            // extract DBName from rData.m_sPar1. Format: DBName.TableName.CommandType.ExpStrg
            sal_Int32 nTablePos = rData.m_sPar1.indexOf(DB_DELIM);
            sal_Int32 nCmdTypePos = -1;
            sal_Int32 nExpPos = -1;
 
            if (nTablePos>=0)
            {
                aDBData.sDataSource = rData.m_sPar1.copy(0, nTablePos++);
                nCmdTypePos = rData.m_sPar1.indexOf(DB_DELIM, nTablePos);
                if (nCmdTypePos>=0)
                {
                    aDBData.sCommand = rData.m_sPar1.copy(nTablePos, nCmdTypePos++ - nTablePos);
                    nExpPos = rData.m_sPar1.indexOf(DB_DELIM, nCmdTypePos);
                    if (nExpPos>=0)
                    {
                        aDBData.nCommandType = rData.m_sPar1.copy(nCmdTypePos, nExpPos++ - nCmdTypePos).toInt32();
                    }
                }
            }
 
            sal_Int32 nPos = 0;
            if (nExpPos>=0)
                nPos = nExpPos;
            else if (nTablePos>=0)
                nPos = nTablePos;
 
            OUString sPar1 = rData.m_sPar1.copy(nPos);
 
            if (!aDBData.sDataSource.isEmpty() && pCurShell->GetDBData() != aDBData)
                pCurShell->ChgDBData(aDBData);
 
            switch(rData.m_nTypeId)
            {
            case TYP_DBNAMEFLD:
                {
                    SwDBNameFieldType* pTyp =
                        static_cast<SwDBNameFieldType*>(pCurShell->GetFieldType(0, SwFieldIds::DatabaseName));
                    pField = new SwDBNameField(pTyp, aDBData);
 
                    break;
                }
            case TYP_DBNEXTSETFLD:
                {
                    SwDBNextSetFieldType* pTyp = static_cast<SwDBNextSetFieldType*>(pCurShell->GetFieldType(
                        0, SwFieldIds::DbNextSet) );
                    pField = new SwDBNextSetField(pTyp, sPar1, aDBData);
                    bExp = true;
                    break;
                }
            case TYP_DBNUMSETFLD:
                {
                    SwDBNumSetFieldType* pTyp = static_cast<SwDBNumSetFieldType*>( pCurShell->GetFieldType(
                        0, SwFieldIds::DbNumSet) );
                    pField = new SwDBNumSetField( pTyp, sPar1, rData.m_sPar2, aDBData);
                    bExp = true;
                    break;
                }
            case TYP_DBSETNUMBERFLD:
                {
                    SwDBSetNumberFieldType* pTyp = static_cast<SwDBSetNumberFieldType*>(
                        pCurShell->GetFieldType(0, SwFieldIds::DbSetNumber) );
                    pField = new SwDBSetNumberField( pTyp, aDBData, nFormatId);
                    bExp = true;
                    break;
                }
            }
#endif
            break;
        }
 
    case TYP_USERFLD:
        {
            SwUserFieldType* pTyp =
                static_cast<SwUserFieldType*>( pCurShell->GetFieldType(SwFieldIds::User, rData.m_sPar1) );
 
            // only if existing
            if(!pTyp)
            {
                pTyp = static_cast<SwUserFieldType*>( pCurShell->InsertFieldType(
                    SwUserFieldType(pCurShell->GetDoc(), rData.m_sPar1)) );
            }
            if (pTyp->GetContent(nFormatId) != rData.m_sPar2)
                pTyp->SetContent(rData.m_sPar2, nFormatId);
            pField = new SwUserField(pTyp, 0, nFormatId);
            if (pField->GetSubType() != nSubType)
                pField->SetSubType(nSubType);
            bTable = true;
            break;
        }
 
    case TYP_INPUTFLD:
        {
            if ((nSubType & 0x00ff) == INP_VAR)
            {
                SwSetExpFieldType* pTyp = static_cast<SwSetExpFieldType*>(
                    pCurShell->GetFieldType(SwFieldIds::SetExp, rData.m_sPar1) );
 
                // no Expression Type with this name existing -> create
                if(pTyp)
                {
                    SwSetExpField* pExpField =
                        new SwSetExpField(pTyp, OUString(), nFormatId);
 
                    // Don't change type of SwSetExpFieldType:
                    sal_uInt16 nOldSubType = pExpField->GetSubType();
                    pExpField->SetSubType(nOldSubType | (nSubType & 0xff00));
 
                    pExpField->SetPromptText(rData.m_sPar2);
                    pExpField->SetInputFlag(true) ;
                    bExp = true;
                    pField = pExpField;
                }
                else
                    return false;
            }
            else
            {
                SwInputFieldType* pTyp =
                    static_cast<SwInputFieldType*>( pCurShell->GetFieldType(0, SwFieldIds::Input) );
 
                SwInputField* pInpField =
                    new SwInputField( pTyp, rData.m_sPar1, rData.m_sPar2, nSubType|nsSwExtendedSubType::SUB_INVISIBLE, nFormatId);
                pField = pInpField;
            }
            break;
        }
 
    case TYP_SETFLD:
        {
            if (rData.m_sPar2.isEmpty())   // empty variables are not allowed
                return false;
 
            SwSetExpFieldType* pTyp = static_cast<SwSetExpFieldType*>( pCurShell->InsertFieldType(
                SwSetExpFieldType(pCurShell->GetDoc(), rData.m_sPar1) ) );
 
            SwSetExpField* pExpField = new SwSetExpField( pTyp, rData.m_sPar2, nFormatId);
            pExpField->SetSubType(nSubType);
            pExpField->SetPar2(rData.m_sPar2);
            bExp = true;
            pField = pExpField;
            break;
        }
 
    case TYP_SEQFLD:
        {
            SwSetExpFieldType* pTyp = static_cast<SwSetExpFieldType*>( pCurShell->InsertFieldType(
                SwSetExpFieldType(pCurShell->GetDoc(), rData.m_sPar1, nsSwGetSetExpType::GSE_SEQ)));
 
            sal_uInt8 nLevel = static_cast< sal_uInt8 >(nSubType & 0xff);
 
            pTyp->SetOutlineLvl(nLevel);
            if (nLevel != 0x7f && cSeparator == 0)
                cSeparator = '.';
 
            pTyp->SetDelimiter(OUString(cSeparator));
            SwSetExpField* pExpField = new SwSetExpField(pTyp, rData.m_sPar2, nFormatId);
            bExp = true;
            pField = pExpField;
            break;
        }
 
    case TYP_GETFLD:
        {
            // is there a corresponding SetField
            SwSetExpFieldType* pSetTyp = static_cast<SwSetExpFieldType*>(
                pCurShell->GetFieldType(SwFieldIds::SetExp, rData.m_sPar1));
 
            if(pSetTyp)
            {
                SwGetExpFieldType* pTyp = static_cast<SwGetExpFieldType*>( pCurShell->GetFieldType(
                    0, SwFieldIds::GetExp) );
                pField = new SwGetExpField(pTyp, rData.m_sPar1, pSetTyp->GetType(), nFormatId);
                pField->SetSubType(nSubType | pSetTyp->GetType());
                bExp = true;
            }
            else
                return false;
            break;
        }
 
    case TYP_FORMELFLD:
        {
            if(pCurShell->GetFrameType(nullptr,false) & FrameTypeFlags::TABLE)
            {
                pCurShell->StartAllAction();
 
                SvNumberFormatter* pFormatter = pCurShell->GetDoc()->GetNumberFormatter();
                const SvNumberformat* pEntry = pFormatter->GetEntry(nFormatId);
 
                if (pEntry)
                {
                    SfxStringItem aFormat(FN_NUMBER_FORMAT, pEntry->GetFormatstring());
                    pCurShell->GetView().GetViewFrame()->GetDispatcher()->
                        ExecuteList(FN_NUMBER_FORMAT, SfxCallMode::SYNCHRON,
                                { &aFormat });
                }
 
                SfxItemSet aBoxSet( pCurShell->GetAttrPool(),
                    svl::Items<RES_BOXATR_FORMULA, RES_BOXATR_FORMULA>{} );
 
                OUString sFormula(comphelper::string::stripStart(rData.m_sPar2, ' '));
                if ( sFormula.startsWith("=") )
                {
                    sFormula = sFormula.copy(1);
                }
 
                aBoxSet.Put( SwTableBoxFormula( sFormula ));
                pCurShell->SetTableBoxFormulaAttrs( aBoxSet );
                pCurShell->UpdateTable();
 
                pCurShell->EndAllAction();
                return true;
 
            }
            else
            {
                SwGetExpFieldType* pTyp = static_cast<SwGetExpFieldType*>(
                    pCurShell->GetFieldType(0, SwFieldIds::GetExp) );
                pField = new SwGetExpField(pTyp, rData.m_sPar2, nsSwGetSetExpType::GSE_FORMULA, nFormatId);
                pField->SetSubType(nSubType);
                bExp = true;
            }
            break;
        }
        case TYP_SETREFPAGEFLD:
            pField = new SwRefPageSetField( static_cast<SwRefPageSetFieldType*>(
                                pCurShell->GetFieldType( 0, SwFieldIds::RefPageSet ) ),
                                static_cast<short>(rData.m_sPar2.toInt32()), 0 != nSubType  );
            bPageVar = true;
            break;
 
        case TYP_GETREFPAGEFLD:
            pField = new SwRefPageGetField( static_cast<SwRefPageGetFieldType*>(
                            pCurShell->GetFieldType( 0, SwFieldIds::RefPageGet ) ), nFormatId );
            bPageVar = true;
            break;
        case TYP_DROPDOWN :
        {
            pField = new SwDropDownField(pCurShell->GetFieldType( 0, SwFieldIds::Dropdown ));
            const sal_Int32 nTokenCount = comphelper::string::getTokenCount(rData.m_sPar2, DB_DELIM);
            Sequence<OUString> aEntries(nTokenCount);
            OUString* pArray = aEntries.getArray();
            for(sal_Int32 nToken = 0; nToken < nTokenCount; nToken++)
                pArray[nToken] = rData.m_sPar2.getToken(nToken, DB_DELIM);
            static_cast<SwDropDownField*>(pField)->SetItems(aEntries);
            static_cast<SwDropDownField*>(pField)->SetName(rData.m_sPar1);
        }
        break;
 
        // Insert Paragraph Signature field by signing the paragraph.
        // The resulting field is really a metadata field, created and added via signing.
        case TYP_PARAGRAPHSIGFLD:
            pCurShell->SignParagraph();
            return true;
        break;
 
        default:
        {   OSL_ENSURE(false, "wrong field type");
            return false;
        }
    }
    OSL_ENSURE(pField, "field not available");
 
    //the auto language flag has to be set prior to the language!
    pField->SetAutomaticLanguage(rData.m_bIsAutomaticLanguage);
    LanguageType nLang = GetCurrLanguage();
    pField->SetLanguage(nLang);
 
    // insert
    pCurShell->StartAllAction();
 
    pCurShell->Insert( *pField );
 
    if (TYP_INPUTFLD == rData.m_nTypeId)
    {
        pCurShell->Push();
 
        // start dialog, not before the field is inserted tdf#99529
        pCurShell->Left(CRSR_SKIP_CHARS,
                false, (INP_VAR == (nSubType & 0xff)) ? 1 : 2, false );
        pCurShell->StartInputFieldDlg(pField, false, true, rData.m_pParent ? rData.m_pParent->GetFrameWeld() : nullptr);
 
        pCurShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
    }
 
    if(bExp && m_bEvalExp)
        pCurShell->UpdateExpFields(true);
 
    if(bTable)
    {
        pCurShell->Left(CRSR_SKIP_CHARS, false, 1, false );
        pCurShell->UpdateFields(*pField);
        pCurShell->Right(CRSR_SKIP_CHARS, false, 1, false );
    }
    else if( bPageVar )
        static_cast<SwRefPageGetFieldType*>(pCurShell->GetFieldType( 0, SwFieldIds::RefPageGet ))->UpdateFields();
    else if( TYP_GETREFFLD == rData.m_nTypeId )
        pField->GetTyp()->ModifyNotification( nullptr, nullptr );
 
    // delete temporary field
    delete pField;
 
    pCurShell->EndAllAction();
    return true;
}
 
// fields update
void SwFieldMgr::UpdateCurField(sal_uInt32 nFormat,
                            const OUString& rPar1,
                            const OUString& rPar2,
                            std::unique_ptr<SwField> pTmpField)
{
    // change format
    OSL_ENSURE(m_pCurField, "no field at CursorPos");
 
    if (!pTmpField)
        pTmpField = m_pCurField->CopyField();
 
    SwFieldType* pType   = pTmpField->GetTyp();
    const sal_uInt16 nTypeId = pTmpField->GetTypeId();
 
    SwWrtShell* pSh = m_pWrtShell ? m_pWrtShell : ::lcl_GetShell();
    OSL_ENSURE(pSh, "no SwWrtShell found");
    if(!pSh)
        return;
    pSh->StartAllAction();
 
    bool bSetPar2 = true;
    bool bSetPar1 = true;
    OUString sPar2( rPar2 );
 
    // Order to Format
    switch( nTypeId )
    {
        case TYP_DDEFLD:
        {
            // DDE-Topics/-Items can have blanks in their names!
            //  That's not yet considered here!
            sal_Int32 nIndex = 0;
            sPar2 = sPar2.replaceFirst(" ", OUStringLiteral1(sfx2::cTokenSeparator), &nIndex );
            if (nIndex>=0 && ++nIndex<sPar2.getLength())
            {
                sPar2 = sPar2.replaceFirst(" ", OUStringLiteral1(sfx2::cTokenSeparator), &nIndex);
            }
            break;
        }
 
        case TYP_CHAPTERFLD:
        {
            sal_uInt16 nByte = static_cast<sal_uInt16>(rPar2.toInt32());
            nByte = std::max(sal_uInt16(1), nByte);
            nByte = std::min(nByte, sal_uInt16(MAXLEVEL));
            nByte -= 1;
            static_cast<SwChapterField*>(pTmpField.get())->SetLevel(static_cast<sal_uInt8>(nByte));
            bSetPar2 = false;
            break;
        }
 
        case TYP_SCRIPTFLD:
            static_cast<SwScriptField*>(pTmpField.get())->SetCodeURL(static_cast<bool>(nFormat));
            break;
 
        case TYP_NEXTPAGEFLD:
            if( SVX_NUM_CHAR_SPECIAL == nFormat )
            {
                static_cast<SwPageNumberField*>(m_pCurField)->SetUserString( sPar2 );
                sPar2 = "1";
            }
            else
            {
                if( nFormat + 2 == SVX_NUM_PAGEDESC )
                    nFormat = SVX_NUM_PAGEDESC;
                short nOff = static_cast<short>(sPar2.toInt32());
                nOff += 1;
                sPar2 = OUString::number(nOff);
            }
            break;
 
        case TYP_PREVPAGEFLD:
            if( SVX_NUM_CHAR_SPECIAL == nFormat )
            {
                static_cast<SwPageNumberField*>(m_pCurField)->SetUserString( sPar2 );
                sPar2 = "-1";
            }
            else
            {
                if( nFormat + 2 == SVX_NUM_PAGEDESC )
                    nFormat = SVX_NUM_PAGEDESC;
                short nOff = static_cast<short>(sPar2.toInt32());
                nOff -= 1;
                sPar2 = OUString::number(nOff);
            }
            break;
 
        case TYP_PAGENUMBERFLD:
        case TYP_GETREFPAGEFLD:
            if( nFormat + 2 == SVX_NUM_PAGEDESC )
                nFormat = SVX_NUM_PAGEDESC;
            break;
 
        case TYP_GETREFFLD:
            {
                bSetPar2 = false;
                static_cast<SwGetRefField*>(pTmpField.get())->SetSubType( static_cast<sal_uInt16>(rPar2.toInt32()) );
                const sal_Int32 nPos = rPar2.indexOf( '|' );
                if( nPos>=0 )
                    static_cast<SwGetRefField*>(pTmpField.get())->SetSeqNo( static_cast<sal_uInt16>(rPar2.copy( nPos + 1 ).toInt32()));
            }
            break;
        case TYP_DROPDOWN:
        {
            sal_Int32 nTokenCount = comphelper::string::getTokenCount(sPar2, DB_DELIM);
            Sequence<OUString> aEntries(nTokenCount);
            OUString* pArray = aEntries.getArray();
            for(sal_Int32 nToken = 0; nToken < nTokenCount; nToken++)
                pArray[nToken] = sPar2.getToken(nToken, DB_DELIM);
            static_cast<SwDropDownField*>(pTmpField.get())->SetItems(aEntries);
            static_cast<SwDropDownField*>(pTmpField.get())->SetName(rPar1);
            bSetPar1 = bSetPar2 = false;
        }
        break;
        case TYP_AUTHORITY :
        {
            //#i99069# changes to a bibliography field should change the field type
            SwAuthorityField* pAuthorityField = static_cast<SwAuthorityField*>(pTmpField.get());
            SwAuthorityFieldType* pAuthorityType = static_cast<SwAuthorityFieldType*>(pType);
            SwAuthEntry aTempEntry;
            for( sal_uInt16 i = 0; i < AUTH_FIELD_END; ++i )
                aTempEntry.SetAuthorField( static_cast<ToxAuthorityField>(i),
                                rPar1.getToken( i, TOX_STYLE_DELIMITER ));
            if( pAuthorityType->ChangeEntryContent( &aTempEntry ) )
            {
                pType->UpdateFields();
                pSh->SetModified();
            }
 
            if( aTempEntry.GetAuthorField( AUTH_FIELD_IDENTIFIER ) ==
                pAuthorityField->GetFieldText( AUTH_FIELD_IDENTIFIER ) )
                bSetPar1 = false; //otherwise it's a new or changed entry, the field needs to be updated
            bSetPar2 = false;
        }
        break;
    }
 
    // set format
    // setup format before SetPar2 because of NumberFormatter!
    pTmpField->ChangeFormat(nFormat);
 
    if( bSetPar1 )
        pTmpField->SetPar1( rPar1 );
    if( bSetPar2 )
        pTmpField->SetPar2( sPar2 );
 
    // kick off update
    if(nTypeId == TYP_DDEFLD ||
       nTypeId == TYP_USERFLD ||
       nTypeId == TYP_USRINPFLD)
    {
        pType->UpdateFields();
        pSh->SetModified();
    }
    else {
        // mb: #32157
        pSh->SwEditShell::UpdateFields(*pTmpField);
        GetCurField();
    }
 
    pTmpField.reset();
 
    pSh->EndAllAction();
}
 
// explicitly evaluate ExpressionFields
void SwFieldMgr::EvalExpFields(SwWrtShell* pSh)
{
    if (pSh == nullptr)
        pSh = m_pWrtShell ? m_pWrtShell : ::lcl_GetShell();
 
    if(pSh)
    {
        pSh->StartAllAction();
        pSh->UpdateExpFields(true);
        pSh->EndAllAction();
    }
}
LanguageType SwFieldMgr::GetCurrLanguage() const
{
    SwWrtShell* pSh = m_pWrtShell ? m_pWrtShell : ::lcl_GetShell();
    if( pSh )
        return pSh->GetCurLang();
    return SvtSysLocale().GetLanguageTag().getLanguageType();
}
 
void SwFieldType::GetFieldName_()
{
    static const char* coFieldNms[] =
    {
        FLD_DATE_STD,
        FLD_TIME_STD,
        STR_FILENAMEFLD,
        STR_DBNAMEFLD,
        STR_CHAPTERFLD,
        STR_PAGENUMBERFLD,
        STR_DOCSTATFLD,
        STR_AUTHORFLD,
        STR_SETFLD,
        STR_GETFLD,
        STR_FORMELFLD,
        STR_HIDDENTXTFLD,
        STR_SETREFFLD,
        STR_GETREFFLD,
        STR_DDEFLD,
        STR_MACROFLD,
        STR_INPUTFLD,
        STR_HIDDENPARAFLD,
        STR_DOCINFOFLD,
        STR_DBFLD,
        STR_USERFLD,
        STR_POSTITFLD,
        STR_TEMPLNAMEFLD,
        STR_SEQFLD,
        STR_DBNEXTSETFLD,
        STR_DBNUMSETFLD,
        STR_DBSETNUMBERFLD,
        STR_CONDTXTFLD,
        STR_NEXTPAGEFLD,
        STR_PREVPAGEFLD,
        STR_EXTUSERFLD,
        FLD_DATE_FIX,
        FLD_TIME_FIX,
        STR_SETINPUTFLD,
        STR_USRINPUTFLD,
        STR_SETREFPAGEFLD,
        STR_GETREFPAGEFLD,
        STR_INTERNETFLD,
        STR_JUMPEDITFLD,
        STR_SCRIPTFLD,
        STR_AUTHORITY,
        STR_COMBINED_CHARS,
        STR_DROPDOWN,
        STR_CUSTOM_FIELD,
        STR_PARAGRAPH_SIGNATURE
    };
 
    // insert infos for fields
    SwFieldType::s_pFieldNames = new std::vector<OUString>;
    SwFieldType::s_pFieldNames->reserve(SAL_N_ELEMENTS(coFieldNms));
    for (const char* id : coFieldNms)
    {
        const OUString aTmp(SwResId(id));
        SwFieldType::s_pFieldNames->push_back(MnemonicGenerator::EraseAllMnemonicChars( aTmp ));
    }
}
 
bool SwFieldMgr::ChooseMacro()
{
    bool bRet = false;
 
    // choose script dialog
    OUString aScriptURL = SfxApplication::ChooseScript();
 
    // the script selector dialog returns a valid script URL
    if ( !aScriptURL.isEmpty() )
    {
        SetMacroPath( aScriptURL );
        bRet = true;
    }
 
    return bRet;
}
 
void SwFieldMgr::SetMacroPath(const OUString& rPath)
{
    m_sMacroPath = rPath;
    m_sMacroName = rPath;
 
    // try to set sMacroName member variable by parsing the macro path
    // using the new URI parsing services
 
    Reference< XComponentContext > xContext =
        ::comphelper::getProcessComponentContext();
 
    Reference< uri::XUriReferenceFactory >
        xFactory = uri::UriReferenceFactory::create( xContext );
 
    Reference< uri::XVndSunStarScriptUrl >
        xUrl( xFactory->parse( m_sMacroPath ), UNO_QUERY );
 
    if ( xUrl.is() )
    {
        m_sMacroName = xUrl->getName();
    }
}
 
sal_uInt32 SwFieldMgr::GetDefaultFormat(sal_uInt16 nTypeId, bool bIsText, SvNumberFormatter* pFormatter)
{
    SvNumFormatType  nDefFormat;
 
    switch (nTypeId)
    {
        case TYP_TIMEFLD:
        case TYP_DATEFLD:
        {
            nDefFormat = (nTypeId == TYP_DATEFLD) ? SvNumFormatType::DATE : SvNumFormatType::TIME;
        }
        break;
 
        default:
            if (bIsText)
            {
                nDefFormat = SvNumFormatType::TEXT;
            }
            else
            {
                nDefFormat = SvNumFormatType::ALL;
            }
            break;
    }
 
    return pFormatter->GetStandardFormat(nDefFormat, GetCurrLanguage());
}
 
Reference<XNumberingTypeInfo> const & SwFieldMgr::GetNumberingInfo() const
{
    if(!m_xNumberingInfo.is())
    {
        Reference<XComponentContext>         xContext( ::comphelper::getProcessComponentContext() );
        Reference<XDefaultNumberingProvider> xDefNum = text::DefaultNumberingProvider::create(xContext);
        const_cast<SwFieldMgr*>(this)->m_xNumberingInfo.set(xDefNum, UNO_QUERY);
    }
    return m_xNumberingInfo;
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V557 Array overrun is possible. The value of 'nPos' index could reach 65535.

V557 Array overrun is possible. The value of 'GetPos(nTypeId)' index could reach 65535.

V560 A part of conditional expression is always true: pSh.

V557 Array overrun is possible. The value of 'nPos' index could reach 65535.

V557 Array overrun is possible. The value of 'GetPos(nTypeId)' index could reach 65535.

V557 Array overrun is possible. The value of 'nPos' index could reach 65535.

V557 Array overrun is possible. The value of 'nPos' index could reach 65535.