//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//

//    Make sure all dependent defines exist and have a valid value

#ifndef    NO_COMPILER_NAMES
#define    NO_COMPILER_NAMES        0
#endif

#ifndef VERS_32BIT
#define VERS_32BIT                1
#endif

#ifndef PACK_SIZE
#ifdef _CRTBLD
#define PACK_SIZE                8
#elif !VERS_32BIT
#define PACK_SIZE                2
#elif defined(_X86_)
#define PACK_SIZE                4
#else
#define PACK_SIZE                8
#endif
#endif

//    Check for version inconsistancies, and setup version flags

#ifdef    VERS_BSC
    #undef    NO_COMPILER_NAMES
    #define    NO_COMPILER_NAMES    1

    #pragma    inline_depth ( 3 )
    #pragma    check_stack ( off )
#else
    #pragma    inline_depth ( 3 )
    #pragma    check_stack ( off )
#endif


#define    PURE    = 0

#ifndef CC_COR
#define CC_COR 1
#endif

#include    "undname.hxx"

#if !defined(DASSERT)
#if !defined(_CRTBLD) && defined(_DEBUG)
#include    <assert.h>
#define DASSERT(x) assert(x)
#else
#define DASSERT(x)
#endif
#else
// This is an FE build; DASSERT is defined properly
#endif

#if (defined(_CRTBLD) && defined(_MT))
#include <mtdll.h>
#endif

#include <stdio.h>
#include <windows.h>
//#include "utf8.h"

#pragma warning(disable:4291)    // No matching operator delete

static    unsigned int    und_strlen ( pcchar_t );
static    void            und_memcpy ( _Out_bytecap_(len) pchar_t dst, pcchar_t src, unsigned int len );
static    unsigned int    und_strncmp ( pcchar_t, pcchar_t, unsigned int );

class    DName;
class    DNameNode;
class    Replicator;
class    _HeapManager;
class    UnDecorator;


// A 4K byte block, not including the header.  That matches LIMIT_ID_LENGTH
// in the frontend.
const   unsigned int    memBlockSize = 4096;

// Dev10 bug 662979
// undname will be pullled into libcmt.lib. Prefix with underscore to prevent potential conflict with user code.
class    _HeapManager
{
private:
        Alloc_t            pOpNew;
        Free_t            pOpDelete;

        struct    Block
        {
            Block *        next;
            char        memBlock[ memBlockSize ];

            Block ()    {    next    = 0;    }

        };

        Block *            head;
        Block *            tail;
        size_t            blockLeft;

public:
        void            Constructor ( Alloc_t pAlloc, Free_t pFree )
                        {    pOpNew        = pAlloc;
                            pOpDelete    = pFree;
                            blockLeft    = 0;
                            head        = 0;
                            tail        = 0;
                        }

        void  *            getMemory ( size_t, int );

        void            Destructor ( void )
                        {    if    ( pOpDelete != 0 )
                                while    ( (tail = head) != NULL )
                                {
                                    head    = tail->next;

                                    ( *pOpDelete )( tail );

                                }
                        }

        #define    gnew    new(heap,0)
        #define    rnew    new(heap,1)

};



void   *    operator new ( size_t, _HeapManager &, int = 0 );



static    _HeapManager    heap;


//    The MS Token table

enum    Tokens
{
#if !VERS_32BIT
    TOK_near,
    TOK_nearSp,
    TOK_nearP,
    TOK_far,
    TOK_farSp,
    TOK_farP,
    TOK_huge,
    TOK_hugeSp,
    TOK_hugeP,
#endif
    TOK_basedLp,
    TOK_cdecl,
    TOK_pascal,
    TOK_stdcall,
    TOK_thiscall,
    TOK_fastcall,
    TOK_cocall,
    TOK_eabi,
    TOK_ptr64,
    TOK_restrict,
    TOK_unaligned,
#if !VERS_32BIT
    TOK_interrupt,
    TOK_saveregs,
    TOK_self,
    TOK_segment,
    TOK_segnameLpQ,
#endif
    TOK__last
};


static    const pcchar_t    tokenTable[]    =
{
#if !VERS_32BIT
    "__near",        // TOK_near
    "__near ",        // TOK_nearSp
    "__near*",        // TOK_nearP
    "__far",        // TOK_far
    "__far ",        // TOK_farSp
    "__far*",        // TOK_farP
    "__huge",        // TOK_huge
    "__huge ",        // TOK_hugeSp
    "__huge*",        // TOK_hugeP
#endif
    "__based(",        // TOK_basedLp
    "__cdecl",        // TOK_cdecl
    "__pascal",        // TOK_pascal
    "__stdcall",    // TOK_stdcall
    "__thiscall",    // TOK_thiscall
    "__fastcall",    // TOK_fastcall
    "__clrcall",    // TOK_cocall
    "__eabi",        // TOK_eabi
    "__ptr64",        // TOK_ptr64
    "__restrict",    // TOK_restrict
    "__unaligned",    // TOK_unaligned
#if !VERS_32BIT
    "__interrupt",    // TOK_interrupt
    "__saveregs",    // TOK_saveregs
    "__self",        // TOK_self
    "__segment",    // TOK_segment
    "__segname(\"",    // TOK_segnameLpQ
#endif
    ""
};


//    The operator mapping table

static    const pcchar_t    nameTable[]    =
{
    " new",
    " delete",
    "=",
    ">>",
    "<<",
    "!",
    "==",
    "!=",
    "[]",
    "operator",
    "->",
    "*",
    "++",
    "--",
    "-",
    "+",
    "&",
    "->*",
    "/",
    "%",
    "<",
    "<=",
    ">",
    ">=",
    ",",
    "()",
    "~",
    "^",
    "|",
    "&&",
    "||",
    "*=",
    "+=",
    "-=",
    "/=",
    "%=",
    ">>=",
    "<<=",
    "&=",
    "|=",
    "^=",

#if    ( !NO_COMPILER_NAMES )
    "`vftable'",
    "`vbtable'",
    "`vcall'",
    "`typeof'",
    "`local static guard'",
    "`string'",
    "`vbase destructor'",
    "`vector deleting destructor'",
    "`default constructor closure'",
    "`scalar deleting destructor'",
    "`vector constructor iterator'",
    "`vector destructor iterator'",
    "`vector vbase constructor iterator'",
    "`virtual displacement map'",
    "`eh vector constructor iterator'",
    "`eh vector destructor iterator'",
    "`eh vector vbase constructor iterator'",
    "`copy constructor closure'",
    "`udt returning'",
    "`EH", //eh initialized struct
    "`RTTI", //rtti initialized struct
    "`local vftable'",
    "`local vftable constructor closure'",
#endif    // !NO_COMPILER_NAMES

    " new[]",
    " delete[]",

#if ( !NO_COMPILER_NAMES )
    "`omni callsig'",
    "`placement delete closure'",
    "`placement delete[] closure'",
    "`managed vector constructor iterator'",
    "`managed vector destructor iterator'",
    "`eh vector copy constructor iterator'",
    "`eh vector vbase copy constructor iterator'",
    "`dynamic initializer for '",
    "`dynamic atexit destructor for '",
    "`vector copy constructor iterator'",
    "`vector vbase copy constructor iterator'",
    "`managed vector copy constructor iterator'",
    "`local static thread guard'",
#endif

    ""
};

static const pcchar_t ehTable[] =
{
    " Ptr to Member Data'",
    " Catchable Type'",
    " Catchable Type Array'",
    " ThrowInfo'",
};

static const pcchar_t rttiTable[] =
{
    " Type Descriptor'",
    " Base Class Descriptor at (",
    " Base Class Array'",
    " Class Hierarchy Descriptor'",
    " Complete Object Locator'",
};


//  ------------------------------------------------------------------------
//
//  DName
//
//  A DName is the result of undecorating part of a decorated name.  It has
//  three main parts: a string, a status, and some flags that are used to
//  communicate what kind of thing the string represents.  The bulk of the work
//  of the undecorator is scanning the input and building the output string.
//  DName supports a wide variety of string operations via overloaded operators
//  to make the main algorithm as plain as possible.
//
//  A DName can contain embedded DNames.  This is used to generate a declarator
//  like "void #()" (where # is the embedded DName) and later set # to "__cdecl
//  foo" to build the full string "void __cdecl foo()".
//
//  Once a the DName::length method has been called, you should no longer
//  assign to or append to any of the embedded DNames.  The protocol is:
//
//    1. Build the DName
//    2. Get the length
//    3. Get the text using getString(pchar_t, int);
//


//    The following 'enum' should really be nested inside 'class DName', but to
//    make the code compile better with Glockenspiel, I have extracted it

enum    DNameStatus
{
    DN_valid,        // good result
    DN_truncated,    // ran out of input string or subcomponent
    DN_invalid,        // unusable input, not a valid decorated name
    DN_error        // internal error
};


class    DName
{
public:
                    DName ();
                    DName ( char );

                    DName ( const DName & );        // Shallow copy

                    DName ( pcchar_t );
                    DName ( pcchar_t&, char );
                    DName ( DNameStatus );
                    DName ( DName * );
                    DName ( unsigned __int64 );
                    DName ( __int64 );

        int            isValid () const;
        int            isEmpty () const;
        DNameStatus    status () const;
        void        clearStatus ();

        DName &        setPtrRef ();
        int            isPtrRef () const;
        int            isUDC () const;
        void        setIsUDC ();
        int            isUDTThunk () const;
        void        setIsUDTThunk ();
        int            isArray() const;
        void        setIsArray();
        int            isNoTE () const;
        void        setIsNoTE ();
        int            isPinPtr() const;
        void        setIsPinPtr();
        int            isComArray() const;
        void        setIsComArray();
        int            isVCallThunk() const;
        void        setIsVCallThunk();

        int            length () const;

        // Returns the last character, or '\0' if the DName represents an empty
        // string.
        char        getLastChar () const;

        // Top level getString. Allocates a buffer if none provided.
        // NUL-terminates the buffer.
        pchar_t        getString (  _Inout_z_cap_(max) pchar_t buf, int max ) const;

        // Internal getString fills in characters at 'buf' and returns a
        // pointer to the position of the next character in buf. 'end' points
        // after the last character in the buffer.
        pchar_t        getString ( _In_z_ pchar_t buf, _In_ pchar_t end ) const;

#ifdef _DEBUG
        pchar_t        dbGetString() const;
#endif

        DName        operator + ( pcchar_t ) const;
        DName        operator + ( const DName & ) const;
        DName        operator + ( char ) const;
        DName        operator + ( DName * ) const;
        DName        operator + ( DNameStatus ) const;

        DName &        operator += ( char );
        DName &        operator += ( pcchar_t );
        DName &        operator += ( DName * );
        DName &        operator += ( DNameStatus );
        DName &        operator += ( const DName & );

        DName &        operator |= ( const DName & );

        DName &        operator = ( pcchar_t );
        DName &        operator = ( const DName & );
        DName &        operator = ( char );
        DName &        operator = ( DName * );
        DName &        operator = ( DNameStatus );

//    Friends :

friend    DName        operator + ( char, const DName & );
friend    DName        operator + ( pcchar_t, const DName & );
friend    DName        operator + ( DNameStatus, const DName & );

private:
        DNameNode *        node;

        DNameStatus        stat        : 8;
        unsigned int    isIndir        : 1;
        unsigned int    isAUDC        : 1;
        unsigned int    isAUDTThunk    : 1;
        unsigned int    isArrayType    : 1;
        unsigned int    NoTE        : 1;
        unsigned int    pinPtr        : 1;
        unsigned int    comArray    : 1;
        unsigned int    vcallThunk    : 1;

        void            append ( DNameNode *node );
        void            doPchar ( pcchar_t, int );

};



class    Replicator
{
private:
        //    Declare, in order to suppress automatic generation
        void            operator = ( const Replicator& );

        int                index;
        DName *            dNameBuffer[ 10 ];

public:
                        Replicator ();

        int                isFull () const;

        Replicator &    operator += ( const DName & );
        DName            operator [] ( int ) const;

};



class    UnDecorator
{
private:
        //    Declare, in order to suppress automatic generation
        void            operator = ( const UnDecorator& );

        Replicator        ArgList;
static    Replicator *    pArgList;

        Replicator        ZNameList;
static    Replicator *    pZNameList;

static    Replicator *    pTemplateArgList;

static    pcchar_t        gName;
static    pcchar_t        name;
static    pchar_t            outputString;
static    int                maxStringLength;
static    unsigned long    disableFlags;
static    bool            fExplicitTemplateParams;
static    bool            fGetTemplateArgumentList;

static    DName    getDecoratedName ( void );
static    DName    getSymbolName ( void );
static    DName    getZName ( bool fUpdateCachedNames, bool fAllowEmptyName = false );
static    DName    getOperatorName ( bool fIsTemplate, bool *pfReadTemplateArguments );
static    DName    getScope ( void );
static    DName            getScopedName ( void );
static    DName    getSignedDimension ( void );
static    DName    getDimension ( bool fSigned = false );
static    int        getNumberOfDimensions ( void );
static    DName    getTemplateName ( bool );
static    DName    getTemplateArgumentList( void );
static    DName    getTemplateConstant( void );
static    DName    composeDeclaration ( const DName & );
static    int        getTypeEncoding ( void );
static    DName    getBasedType ( void );
static    DName    getECSUName ( void );
static    DName    getEnumType ( void );
static    DName    getCallingConvention ( void );
static    DName    getReturnType ( DName * = 0 );
static    DName    getDataType ( DName * );
static    DName    getPrimaryDataType ( const DName & );
static    DName    getDataIndirectType ( const DName &, const char*, const DName &, int = FALSE );
static    DName    getExtendedDataIndirectType(const char*& prType, bool& fIsPinPtr, int thisFlag);
static    DName    getDataIndirectType ();
static    DName    getBasicDataType ( const DName & );
static    DName    getECSUDataType ( void );
static    DName    getPtrRefType ( const DName &, const DName &, const char*);
static    DName    getPtrRefDataType ( const DName &, int );
static    DName    getArrayType ( const DName& );
static    DName    getFunctionIndirectType( const DName & superType );
static    DName    getArgumentTypes ( void );
static    DName    getArgumentList ( void );
static    DName    getThrowTypes ( void );
static    DName    getLexicalFrame ( void );
static    DName    getStorageConvention ( void );
static    DName    getThisType ( void );
static    DName    getPointerType ( const DName &, const DName & );
static    DName    getPointerTypeArray ( const DName &, const DName & );
static    DName    getReferenceType ( const DName &, const DName &, const char* );
static    DName    getExternalDataType ( const DName & );
static    DName    getSegmentName ( void );

#if    ( !NO_COMPILER_NAMES )
static    DName    getDisplacement ( void );
static    DName    getCallIndex ( void );
static    DName    getGuardNumber ( void );
static    DName    getVfTableType ( const DName & );
static    DName    getVbTableType ( const DName & );
static    DName    getVdispMapType    ( const DName & );
static    DName    getVCallThunkType ( void );
#endif    // !NO_COMPILER_NAMES

static    DName    getStringEncoding ( _In_z_ char *prefix, int wantBody );

static GetParameter_t m_pGetParameter;

public:
                UnDecorator ( _In_opt_z_ pchar_t, pcchar_t, int, GetParameter_t, unsigned long );

static    int        doUnderScore ();
static    int        doMSKeywords ();
static    int        doPtr64 ();
static    int        doFunctionReturns ();
static    int        doAllocationModel ();
static    int        doAllocationLanguage ();

#if    0
static    int        doMSThisType ();
static    int        doCVThisType ();
#endif

static    int        doThisTypes ();
static    int        doAccessSpecifiers ();
static    int        doThrowTypes ();
static    int        doMemberTypes ();
static    int        doReturnUDTModel ();

static    int        do32BitNear ();

static    int        doNameOnly ();
static    int        doTypeOnly ();
static    int        haveTemplateParameters ();
static    int        doEcsu ();
static    int        doNoIdentCharCheck ();
static    int        doEllipsis();

static    pcchar_t    UScore ( Tokens );

                operator pchar_t ();

};



Replicator *    UnDecorator::pArgList;
Replicator *    UnDecorator::pZNameList            = 0;
Replicator *    UnDecorator::pTemplateArgList    = 0;
pcchar_t        UnDecorator::gName                = 0;
pcchar_t        UnDecorator::name                = 0;
pchar_t            UnDecorator::outputString        = 0;
int                UnDecorator::maxStringLength    = 0;
unsigned long    UnDecorator::disableFlags        = 0;
GetParameter_t    UnDecorator::m_pGetParameter    = 0;
bool            UnDecorator::fExplicitTemplateParams = false;
bool            UnDecorator::fGetTemplateArgumentList = false;


#ifdef _CRTBLD
pchar_t        _CRTIMP             __unDName (    _Out_opt_z_cap_(maxStringLength) pchar_t outputString,
#else
pchar_t        __cdecl             unDName (    _Out_opt_z_cap_(maxStringLength) pchar_t outputString,
#endif
                                            pcchar_t name,
                                            int maxStringLength,    // Note, COMMA is leading following optional arguments
                                            Alloc_t pAlloc,
                                            Free_t pFree,
                                            unsigned short disableFlags

                                        )
/*
 *    This function will undecorate a name, returning the string corresponding to
 *    the C++ declaration needed to produce the name.  Its has a similar interface
 *    to 'strncpy'.
 *
 *    If the target string 'outputString' is specified to be NULL, a string of
 *    suitable length will be allocated and its address returned.  If the returned
 *    string is allocated by 'unDName', then it is the programmers responsibility
 *    to deallocate it.  It will have been allocated on the far heap.
 *
 *    If the target string is not NULL, then the parameter 'maxStringLength' will
 *    specify the maximum number of characters which may be placed in the string.
 *    In this case, the returned value is the same as 'outputString'.
 *
 *    Both the input parameter 'name' and the returned string are NULL terminated
 *    strings of characters.
 *
 *    If the returned value is NULL, it indicates that the undecorator ran out of
 *    memory, or an internal error occurred, and was unable to complete its task.
 */

{
    //    Must have an allocator and a deallocator (and we MUST trust them)
    if    ( !( pAlloc ))
        return    0;
    
    pchar_t        unDecoratedName = NULL;

#if (defined(_CRTBLD) && defined(_MT))
    if (!_mtinitlocknum(_UNDNAME_LOCK))
        return    0;
    _mlock(_UNDNAME_LOCK);
    __try {
#endif

    heap.Constructor ( pAlloc, pFree );

    //    Create the undecorator object, and get the result

    UnDecorator    unDecorate (    outputString,
                                name,
                                maxStringLength,
                                0,
                                disableFlags
                            );
    unDecoratedName    = unDecorate;


    // Destruct the heap (would use a destructor, but that causes DLL problems)

    heap.Destructor ();

#if (defined(_CRTBLD) && defined(_MT))
    } __finally {
        _munlock(_UNDNAME_LOCK);
    }
#endif

    //    And return the composed name

    return unDecoratedName;

}    // End of FUNCTION "unDName"




#ifdef _CRTBLD
pchar_t    _CRTIMP                __unDNameEx (    _Out_opt_z_cap_(maxStringLength) pchar_t outputString,
#else
pchar_t    __cdecl                    unDNameEx (    _Out_opt_z_cap_(maxStringLength) pchar_t outputString,
#endif
                                            pcchar_t name,
                                            int maxStringLength,    // Note, COMMA is leading following optional arguments
                                            Alloc_t pAlloc,
                                            Free_t pFree,
                                            GetParameter_t pGetParameter,
                                            unsigned long disableFlags

                                        )
/*
 *    This function will undecorate a name, returning the string corresponding to
 *    the C++ declaration needed to produce the name.  Its has a similar interface
 *    to 'strncpy'.
 *
 *    If the target string 'outputString' is specified to be NULL, a string of
 *    suitable length will be allocated and its address returned.  If the returned
 *    string is allocated by 'unDName', then it is the programmers responsibility
 *    to deallocate it.  It will have been allocated on the far heap.
 *
 *    If the target string is not NULL, then the parameter 'maxStringLength' will
 *    specify the maximum number of characters which may be placed in the string.
 *    In this case, the returned value is the same as 'outputString'.
 *
 *    Both the input parameter 'name' and the returned string are NULL terminated
 *    strings of characters.
 *
 *    If the returned value is NULL, it indicates that the undecorator ran out of
 *    memory, or an internal error occurred, and was unable to complete its task.
 */

{
    //    Must have an allocator and a deallocator (and we MUST trust them)

    if    ( !( pAlloc ))
        return    0;

    pchar_t        unDecoratedName = NULL;

#if (defined(_CRTBLD) && defined(_MT))
    if (!_mtinitlocknum(_UNDNAME_LOCK))
        return    0;
    _mlock(_UNDNAME_LOCK);
    __try {
#endif

    heap.Constructor ( pAlloc, pFree );

    //    Create the undecorator object, and get the result

    UnDecorator    unDecorate (    outputString,
                                name,
                                maxStringLength,
                                pGetParameter,
                                disableFlags
                            );
    unDecoratedName    = unDecorate;


    // Destruct the heap (would use a destructor, but that causes DLL problems)

    heap.Destructor ();

#if (defined(_CRTBLD) && defined(_MT))
    } __finally {
        _munlock(_UNDNAME_LOCK);
    }
#endif

    //    And return the composed name

    return    unDecoratedName;

}    // End of FUNCTION "unDName"

//    The 'UnDecorator' member functions

inline    UnDecorator::UnDecorator    (    _In_opt_z_ pchar_t output,
                                        pcchar_t dName,
                                        int maxLen,
                                        GetParameter_t pGetParameter,
                                        unsigned long disable
                                    )
{
    name            = dName;
    gName            = name;

    if    ( output ) {
        maxStringLength    = maxLen;
        outputString    = output;    
    }
    else {
        outputString    = 0;
        maxStringLength    = 0;
    }

    pZNameList        = &ZNameList;
    pArgList        = &ArgList;
    disableFlags    = disable;
    m_pGetParameter    = pGetParameter;
    fExplicitTemplateParams = false;

}    // End of "UnDecorator" CONSTRUCTOR '()'


inline    UnDecorator::operator pchar_t ()
{
    DName        result;
    DName        unDName;

    //    Find out if the name is a decorated name or not.  Could be a reserved
    //    CodeView variant of a decorated name

    if    ( name )
    {
        if    (( *name == '?' ) && ( name[ 1 ] == '@' ))
        {
#if    ( !NO_COMPILER_NAMES )
            gName    += 2;
            result    = "CV: " + getDecoratedName ();
#else    // } elif NO_COMPILER_NAMES
            result    = DN_invalid;
#endif    // NO_COMPILER_NAMES

        }    // End of IF then
        else if    (( *name == '?' ) && ( name[1] == '$' )) {
            result = getTemplateName( false );

            if ( result.status () == DN_invalid ) {
                // 
                // What harm could there be to try again ?
                //    Repro:
                //        ?$S1@?1??VTFromRegType@CRegParser@ATL@@KAHPBGAAG@Z@4IA
                //    ---> unsigned int `protected: static int __cdecl ATL::CRegParser::VTFromRegType(unsigned short const *,unsigned short &)'::`2'::$S1
                //
                //    This is a compiler generated symbol for a local static array init.
                //
                gName = name;
                result    = getDecoratedName ();
            }
        } else {
            result    = getDecoratedName ();
        }

    }    // End of IF then

    //    If the name was not a valid name, then make the name the same as the original
    //    It is also invalid if there are any remaining characters in the name (except when
    //    we're giving the name only)

    if        ( result.status () == DN_error )
        return    0;
    elif    ( ( result.status () == DN_invalid ) || (!doNameOnly () && *gName) )
        unDName    = name;    // Return the original name
    else
        unDName    = result;

    //    Construct the return string

    if    ( !outputString )
    {
        maxStringLength    = unDName.length () + 1;
        outputString     = rnew char[ maxStringLength ];

    }    // End of IF

    if    ( outputString ) {
        unDName.getString ( outputString, maxStringLength );

        // strip extra whitespace out of name
        pchar_t pRead = outputString;
        pchar_t pWrite = pRead;
        while (*pRead) {
            if (*pRead == ' ') {
                pRead++;
                *pWrite++ = ' ';
                while ( *pRead == ' ' ) {
                    pRead++;
                }
            }
            else
                *pWrite++ = *pRead++;
        }
        *pWrite = *pRead;
    }

    //    Return the result

    return    outputString;

}    // End of "UnDecorator" OPERATOR 'pchar_t'


#ifdef _DEBUG
pchar_t DName::dbGetString() const
{
    static char buf[80];
    getString(buf, 80);
    return buf;
}
#endif

DName    UnDecorator::getDecoratedName ( void )
{
    //    Ensure that it is intended to be a decorated name

    if        ( doTypeOnly() )
    {
        // Disable the type-only flag, so that if we get here recursively, eg.
        // in a template tag, we do full name undecoration.
        disableFlags &= ~UNDNAME_TYPE_ONLY;

        // If we're decoding just a type, process it as the type for an abstract
        // declarator, by giving an empty symbol name.

        DName    result = getDataType ( NULL );
        disableFlags |= UNDNAME_TYPE_ONLY;

        return result;
    }
    elif    ( *gName == '?' )
    {
        //    Extract the basic symbol name

        gName++;    // Advance the original name pointer

        // What!?!? we have a name that starts with '???' how is this possible?
        // Easy: consider code like the following:
        //
        // int f();
        //
        // int g = f();
        //
        // This will cause the compiler to generate am extern "C" file-scope static
        // initialization function with the name '??__Eg@@YAXXZ'
        //
        // Now: let's say that we compile with file with /clr: as the CLR cannot handle
        // file scope statics the compiler makes them all look like members of an anonymous
        // namespace. So the compiler will try to decorate then name again even though we
        // have already marked it as extern "C". The new name it will generate will be:
        // '???__Eg@@YMXXZ@?A0x2109f7d3@@$$FYMXXZ'
        // 
        // So how should we undecorate this? Well unless you want a really weird looking
        // name the best way is to forget about the encoding added because of the CLR as
        // just undecorate the orginial name.
        if ((gName[0] == '?') && (gName[1] == '?'))
        {
            // Skip the first '?' and restart the undecoration process.
            DName result = getDecoratedName();

            // We have undecorated the original name ... skip whatever else was added
            // to keep the CLR happy
            while (*gName != '\0')
            {
                ++gName;
            }

            return result;
        }

        DName    symbolName = getSymbolName ();
        int        udcSeen            = symbolName.isUDC ();
        int        vcallThunkSeen    = symbolName.isVCallThunk();

        //    Abort if the symbol name is invalid

        if    ( !symbolName.isValid ())
            return    symbolName;

        //    Extract, and prefix the scope qualifiers

        if    ( *gName && ( *gName != '@' )) {
            DName    scope = getScope ();
            
            if    ( !scope.isEmpty() )
                if (fExplicitTemplateParams) {
                    fExplicitTemplateParams = false;
                    symbolName    = symbolName + scope;
                    if (*gName != '@') {
                        scope = getScope();                    
                        symbolName    = scope + "::" + symbolName;
                    }
                } else {
                    symbolName    = scope + "::" + symbolName;
                }
            }

        if    ( udcSeen )
            symbolName.setIsUDC ();

        if (vcallThunkSeen)
        {
            symbolName.setIsVCallThunk();
        }

        //    Now compose declaration

        if    ( symbolName.isEmpty () || symbolName.isNoTE() )
        {
            return    symbolName;
        }
        elif    ( !*gName || ( *gName == '@' ) )
        {
            if    ( *gName )
                gName++;

            if    (doNameOnly () && !udcSeen && !symbolName.isVCallThunk()) {
                // Eat the rest of the dname, in case this is a recursive invocation,
                // such as for a template argument.
                (void)composeDeclaration( DName() );
                return symbolName;
            }
            else {
                return    composeDeclaration ( symbolName );
            }

        }    // End of ELIF then
        else
            return    DN_invalid;

    }    // End of IF then
    elif    ( *gName )
        return    DN_invalid;
    else
        return    DN_truncated;

}    // End of "UnDecorator" FUNCTION "getDecoratedName"



inline DName UnDecorator::getSymbolName()
{
    if (gName[0] == '?') {
        if (gName[1] == '$') {
            return getTemplateName(true);
        }
        else {
            gName += 1;

            return getOperatorName(false, NULL);
        }
    }
    else {
        return getZName(true);
    }
}


DName    UnDecorator::getZName ( bool fUpdateCachedNames, bool fAllowEmptyName )
{
    int        zNameIndex    = *gName - '0';


    //    Handle 'zname-replicators', otherwise an actual name

    if    (( zNameIndex >= 0 ) && ( zNameIndex <= 9 ))
    {
        gName++;    // Skip past the replicator

        //    And return the indexed name

        return    ( *pZNameList )[ zNameIndex ];

    }    // End of IF then
    else
    {
        DName    zName;

        if    ( *gName == '?' )
        {
            zName    = getTemplateName( false );

            if    ( *gName++ != '@' )
                zName    = *--gName ? DN_invalid : DN_truncated;
        }
        else {
            #define TEMPLATE_PARAMETER "template-parameter-"
            #define TEMPLATE_PARAMETER_LEN 19
            #define GENERIC_TYPE "generic-type-"
            #define GENERIC_TYPE_LEN 13

            pchar_t genericType;
            if (und_strncmp(gName, TEMPLATE_PARAMETER, TEMPLATE_PARAMETER_LEN) == 0) {
                genericType = TEMPLATE_PARAMETER;
                gName += TEMPLATE_PARAMETER_LEN;
            } else if (und_strncmp(gName, GENERIC_TYPE, GENERIC_TYPE_LEN) == 0) {
                genericType = GENERIC_TYPE;
                gName += GENERIC_TYPE_LEN;
            } else {
                genericType = NULL;
            }

            if (genericType) {
                DName dimension = getSignedDimension();

                if ( haveTemplateParameters()) {
                    char buffer[16];

                    dimension.getString( buffer, 16 );

                    char *str = (*m_pGetParameter)(atol(buffer));

                    if ( str != NULL ) {
                        zName = str;
                    }
                    else {
                        zName = "`";
                        zName += genericType + dimension + "'";
                    }
                }
                else {
                    zName = "`";
                    zName += genericType + dimension + "'";
                }
            }
            else if (fAllowEmptyName  &&  *gName == '@') {
                // Empty zname is used in old-style template function decorated names
                zName = DName();
                gName += 1;
            }
            else {
                //    Extract the 'zname' to the terminator

                zName    = DName( gName, '@' );    // This constructor updates 'name'
            }
        }


        //    Add it to the current list of 'zname's

        if    ( fUpdateCachedNames && !pZNameList->isFull ())
            *pZNameList    += zName;

        //    And return the symbol name
        return    zName;

    }    // End of IF else
}    // End of "UnDecorator" FUNCTION "getZName"



inline    DName    UnDecorator::getOperatorName ( bool fIsTemplate, bool *pfReadTemplateArguments )
{
    DName    operatorName;
    DName    tmpName;
    int        udcSeen    = FALSE;
    int        index = 0;


    //    So what type of operator is it ?

    switch    ( *gName++ )
    {
    case 0:
        gName--;        // End of string, better back-track

        return    DN_truncated;

    case OC_ctor:
    case OC_dtor:
        //
        // The constructor and destructor are special:
        // Their operator name is the name of their first enclosing scope, which
        // will always be a tag, which may be a template specialization!
        //
        {
            //
            // Is this a specialization of a member function template? If it is
            // then we will actually have the template arguments between the "name"
            // of the operator and the scope: so we need to read the template
            // arguments before we try to read the name of the class
            //
            DName templateArguments;

            if ( fIsTemplate ) {
                templateArguments += '<' + getTemplateArgumentList();

                if ( templateArguments.getLastChar () == '>' ) {
                    templateArguments += ' ';
                }

                templateArguments += '>';

                if ( pfReadTemplateArguments != NULL ) {
                    *pfReadTemplateArguments = true;
                }

                //
                // It is possible that we only want to decode the template
                // arguments -- this happens when want to create a name like
                // mf<int> to use in meta-data
                //
                if ( *gName == '\0' ) {
                    return templateArguments;
                }

                gName += 1;
            }

            //
            // Use a temporary.  Don't want to advance the name pointer
            //
            pcchar_t    pName    = gName;

            operatorName        = getZName ( false );

            gName = pName;        // Undo our lookahead

            if    ( !operatorName.isEmpty () && ( gName[ -1 ] == OC_dtor ))
                operatorName    = '~' + operatorName;

            //
            // Append the template argumentsa (if there are any)
            //
            if ( !templateArguments.isEmpty()) {
                operatorName    += templateArguments;
            }

            return    operatorName;

        }    // End of CASE 'OC_ctor,OC_dtor'
        break;

    case OC_new:
    case OC_delete:
    case OC_assign:
    case OC_rshift:
    case OC_lshift:
    case OC_not:
    case OC_equal:
    case OC_unequal:
            operatorName    = nameTable[ gName[ -1 ] - OC_new ];
        break;

    case OC_udc:
            udcSeen    = TRUE;

        //    No break

    case OC_index:
    case OC_pointer:
    case OC_star:
    case OC_incr:
    case OC_decr:
    case OC_minus:
    case OC_plus:
    case OC_amper:
    case OC_ptrmem:
    case OC_divide:
    case OC_modulo:
    case OC_less:
    case OC_leq:
    case OC_greater:
    case OC_geq:
    case OC_comma:
    case OC_call:
    case OC_compl:
    case OC_xor:
    case OC_or:
    case OC_land:
    case OC_lor:
    case OC_asmul:
    case OC_asadd:
    case OC_assub:            // Regular operators from the first group
            operatorName    = nameTable[ gName[ -1 ] - OC_index + ( OC_unequal - OC_new + 1 )];
        break;

    case '_':
            switch    ( *gName++ )
            {
            case 0:
                gName--;        // End of string, better back-track

                return    DN_truncated;

            case OC_asdiv:
            case OC_asmod:
            case OC_asrshift:
            case OC_aslshift:
            case OC_asand:
            case OC_asor:
            case OC_asxor:    // Regular operators from the extended group
                    operatorName    = nameTable[ gName[ -1 ] - OC_asdiv + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )];
                break;

#if    ( !NO_COMPILER_NAMES )
            case OC_vftable:
            case OC_vbtable:
                return nameTable[ gName[ -1 ] - OC_asdiv + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )];
                break;

            case OC_vcall:
                {
                    DName result = nameTable[ gName[ -1 ] - OC_asdiv + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )];

                    result.setIsVCallThunk();

                    return result;
                }
                break;

            case OC_string:
                {
                DName result = getStringEncoding( "`string'", TRUE );
                result.setIsNoTE();
                return result;
                }

            case OC_metatype:
            case OC_guard:
            case OC_vbdtor:
            case OC_vdeldtor:
            case OC_defctor:
            case OC_sdeldtor:
            case OC_vctor:
            case OC_vdtor:
            case OC_vallctor:
            case OC_vdispmap:
            case OC_ehvctor:
            case OC_ehvdtor:
            case OC_ehvctorvb:
            case OC_copyctorclosure:
            case OC_locvfctorclosure:
            case OC_locvftable:    // Special purpose names
            case OC_placementDeleteClosure:
            case OC_placementArrayDeleteClosure:
                return    nameTable[ gName[ -1 ] - OC_metatype + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )];

            case OC_udtthunk:
                operatorName    = nameTable[ gName[ -1 ] - OC_metatype + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )];
                tmpName         = getOperatorName( false, NULL );
                if ( !tmpName.isEmpty() && tmpName.isUDTThunk() )
                    return    DN_invalid;
                return operatorName + tmpName;
                break;
            case OC_eh_init:
                break;
            case OC_rtti_init:
                operatorName    = nameTable[ gName[ -1 ] - OC_metatype + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )];
                if ( !gName[0] )
                    return  operatorName + DN_truncated;
                index = gName[0] - OC_rtti_TD;
                if ( index < 0  || index >= _countof(rttiTable))
                    return  DN_invalid;

                tmpName = rttiTable[ index ];

                switch    ( *gName++ )
                {
                case OC_rtti_TD:
                    {
                    DName    result = getDataType ( NULL );
                    return result + ' ' + operatorName + tmpName;
                    }
                    break;
                case OC_rtti_BCD:
                    {
                    DName    result = operatorName + tmpName;
                    result += getSignedDimension() + ',';
                    result += getSignedDimension() + ',';
                    result += getSignedDimension() + ',';
                    result += getDimension() + ')';
                    return result + '\'';
                    }
                    break;
                case OC_rtti_BCA:
                case OC_rtti_CHD:
                case OC_rtti_COL:
                    return operatorName + tmpName;
                    break;
                default:
                    gName--;
                    return DN_truncated;
                    break;
                }
                break;

#endif    // !NO_COMPILER_NAMES

            case OC_arrayNew:
            case OC_arrayDelete:
                operatorName    = nameTable[ gName[ -1 ] - OC_metatype + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )
#if NO_COMPILER_NAMES
                                            - ( OC_locvfctorclosure - OC_vftable + 1 )    // discount names not in table
#endif
                                    ];
                break;

            // Yet another level of nested encodings....
            case '?':
                switch( *gName++ ) {

                    case 0:
                        gName--;        // End of string, better back-track

                        return    DN_truncated;

                    case OC_anonymousNamespace:
                        //
                        // Anonymous namespace (new-style) is a string encoding of the
                        // machine name and the translation unit name.  Since the remainder
                        // of the name doesn't really fit the dname grammar, skip it.
                        // There are two '@' markers in the name....
                        //
                        {
                        DName result = getStringEncoding( "`anonymous namespace'", FALSE );
                        result.setIsNoTE();
                        return result;
                        }

                    default:
                        return    DN_invalid;
                }
                break;

            //
            // A double extended operator
            //
            case '_':
                switch (*gName++) {
                    case OC_man_vec_ctor:
                    case OC_man_vec_dtor:
                    case OC_ehvcctor:
                    case OC_ehvcctorvb:
                    case OC_vec_copy_ctor:
                    case OC_vec_copy_ctor_vb:
                    case OC_man_vec_copy_ctor:
                    case OC_thread_guard:
                        return nameTable[ gName[ -1 ] - OC_man_vec_ctor + ( OC_placementArrayDeleteClosure - OC_metatype + 1) + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )];

                    case OC_staticinit:
                    case OC_staticatexit:
                        {
                            DName name = nameTable[ gName[ -1 ] - OC_man_vec_ctor + ( OC_placementArrayDeleteClosure - OC_metatype + 1) + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )];

                            // Is the 'name' after the operator decorated or not? How is this
                            // possible? Well consider the following:
                            //
                            //   int f()
                            //
                            //   int g = f();
                            //
                            //   struct X {
                            //      static int s;
                            //   };
                            //
                            //   int X::s = f();
                            //
                            // The name for the initializer for g is '??__Eg@@YAXXZ' while the
                            // name for the initializer for X::s is '??__E?s@X@@2HA@@YAXXZ'. So
                            // we either have a decorated name or a simple symbol name. Undecorate
                            // the names appropriate.
                            if (*gName == '?')
                            {
                                name += getDecoratedName();

                                // If the decorated name ends withe '@' skip it so that we are ready to process
                                // the next section
                                if (*gName == '@')
                                {
                                    gName += 1;
                                }
                            }
                            else
                            {
                                name += getSymbolName();
                            }

                            name += "''";

                            return name;
                        }
                        break;

                    default:
                        return DN_invalid;
                }
                break;

            default:
                return    DN_invalid;

            }    // End of SWITCH
        break;

    default:
        return    DN_invalid;

    }    // End of SWITCH

    //    This really is an operator name, so prefix it with 'operator'

    if    ( udcSeen )
        operatorName.setIsUDC ();
    elif    ( !operatorName.isEmpty ())
        operatorName    = "operator" + operatorName;

    return    operatorName;

}    // End of "UnDecorator" FUNCTION "getOperatorName"

DName    UnDecorator::getStringEncoding ( _In_z_ char *prefix, int /*unused*/)
{
    DName result = prefix;

    // First @ comes right after operator code
    if    ( *gName++ != '@' || *gName++ != '_' ) {
        return DN_invalid;
    }

    // Skip the string kind
    gName++;

    // Get (& discard) the length
    getDimension();

    // Get (& discart) the checksum
    getDimension();

    while ( *gName && *gName != '@' ) {
        // For now, we'll just skip it
        gName++;
    }

    if    ( !*gName ) {
        gName--;
        return DN_truncated;
    }

    // Eat the terminating '@'
    gName++;

    return result;
}


DName    UnDecorator::getScope ( void )
{
    DName    scope;
    bool    fNeedBracket = false;


    //    Get the list of scopes

    while    (( scope.status () == DN_valid ) && *gName && ( *gName != '@' ))
    {    //    Insert the scope operator if not the first scope

        if (fExplicitTemplateParams && !fGetTemplateArgumentList) {
            return scope;
        }
        if    ( !scope.isEmpty() ) {
            scope    = "::" + scope;

            if (fNeedBracket) {
                scope = '[' + scope;
                fNeedBracket = false;
            }
        }

        //    Determine what kind of scope it is

        if    ( *gName == '?' )
            switch    ( *++gName )
            {
            case '?':
                    if    ( gName[1] == '_' && gName[2] == '?' ) {
                        //
                        // Anonymous namespace name (new style)
                        //
                        gName++;
                        scope = getOperatorName ( false, NULL ) + scope;

                        // There should be a zname termination @...
                        if    ( *gName == '@' ) {
                            gName++;
                        }
                    }
                    else
                        scope    = '`' + getDecoratedName () + '\'' + scope;
                break;

            case '$':
                    // It's a template name, which is a kind of zname; back up
                    // and handle like a zname.
                    gName--;
                    scope    = getZName ( true ) + scope;
                break;

            case 'A':
                    //
                    // This is a new-new encoding for anonymous namespaces
                    //
                    // fall-through

            case '%':
                {
                    //
                    // It an anonymous namespace (old-style);
                    // skip the (unreadable) name and instead insert
                    // an appropriate string
                    //
                    DName namespaceName = DName( gName, '@' );

                    scope = "`anonymous namespace'" + scope;

                    if ( !pZNameList->isFull()) {
                        *pZNameList    += namespaceName;
                    }
                }
                break;
            case 'I':
                //
                // This is the interface whose method the class is
                // implementing
                //
                gName++;
                scope = getZName ( true ) + ']' + scope;
                fNeedBracket = true;
                break;

            default:
                scope    = getLexicalFrame () + scope;
                break;

            }    // End of SWITCH
        else
            scope    = getZName ( true ) + scope;

    }    // End of WHILE

    //    Catch error conditions

    switch    ( *gName )
    {
    case 0:
            if    ( scope.isEmpty() )
                scope    = DN_truncated;
            else
                scope    = DName ( DN_truncated ) + "::" + scope;
        break;

    case '@':        // '@' expected to end the scope list
        break;

    default:
            scope    = DN_invalid;
        break;

    }    // End of SWITCH

    //    Return the composed scope

    return    scope;

}    // End of "UnDecorator" FUNCTION "getScope"


DName    UnDecorator::getSignedDimension ( void )
{
    if        ( !*gName )
        return    DN_truncated;
    elif    ( *gName == '?' ) {
        gName++;    // skip the '?'
        return    '-' + getDimension();
    }
    else
        return    getDimension();
}    // End of "Undecorator" FUNCTION "getSignedDimension"


DName    UnDecorator::getDimension ( bool fSigned )
{
    char* prefix = 0;
    if (*gName == TC_nontype_dummy) {
        prefix = "`non-type-template-parameter";
        ++gName;
    }

    if        ( !*gName )
        return    DN_truncated;
    elif    (( *gName >= '0' ) && ( *gName <= '9' ))
        return    prefix ? (prefix + DName ((unsigned __int64)( *gName++ - '0' + 1 ))) : DName ((unsigned __int64)( *gName++ - '0' + 1 ));
    else
    {
        unsigned __int64 dim = 0ui64;


        //    Don't bother detecting overflow, it's not worth it

        while    ( *gName != '@' )
        {
            if        ( !*gName )
                return    DN_truncated;
            elif    (( *gName >= 'A' ) && ( *gName <= 'P' ))
                dim    = ( dim << 4 ) + ( *gName - 'A' );
            else
                return    DN_invalid;

            gName++;

        }    // End of WHILE

        //    Ensure integrity, and return

        if    ( *gName++ != '@' )
            return    DN_invalid;        // Should never get here

        if (fSigned) {
            return prefix ? (prefix + DName((__int64)dim)) : DName((__int64)dim);
        } else {
            return prefix ? (prefix + DName(dim)) : dim;
        }

    }    // End of ELIF else
}    // End of "UnDecorator" FUNCTION "getDimension"


int    UnDecorator::getNumberOfDimensions ( void )
{
    if        ( !*gName )
        return    0;
    elif    (( *gName >= '0' ) && ( *gName <= '9' ))
        return    (( *gName++ - '0' ) + 1 );
    else
    {
        int    dim    = 0;


        //    Don't bother detecting overflow, it's not worth it

        while    ( *gName != '@' )
        {
            if        ( !*gName )
                return    0;
            elif    (( *gName >= 'A' ) && ( *gName <= 'P' ))
                dim    = ( dim << 4 ) + ( *gName - 'A' );
            else
                return    -1;

            gName++;

        }    // End of WHILE

        //    Ensure integrity, and return

        if    ( *gName++ != '@' )
            return    -1;        // Should never get here

        return    dim;

    }    // End of ELIF else
}    // End of "UnDecorator" FUNCTION "getNumberOfDimensions"


DName UnDecorator::getTemplateName( bool fReadTerminator )
{
    //
    // First make sure we're really looking at a template name
    //
    if    ( gName[0] != '?' || gName[1] != '$' )
        return DN_invalid;

    gName += 2;            // Skip the marker characters

    //
    // Stack the replicators, since template names are their own replicator scope:
    //
    Replicator * pSaveArgList             = pArgList;
    Replicator * pSaveZNameList         = pZNameList;
    Replicator * pSaveTemplateArgList     = pTemplateArgList;

    Replicator localArgList, localZNameList, localTemplateArgList;

    pArgList             = &localArgList;
    pZNameList             = &localZNameList;
    pTemplateArgList     = &localTemplateArgList;

    //
    // Crack the template name:
    //
    DName    templateName;
    DName    templateArguments;
    bool    fReadTemplateArguments = false;

    if ( *gName == '?' ) {
        gName += 1;

        templateName = getOperatorName( true, &fReadTemplateArguments );
    }
    else {
        templateName = getZName( true, true );
    }

    if    (templateName.isEmpty ()) {
        fExplicitTemplateParams = true;
    }

    //
    // If we haven't already read the template arguments then
    // now is the time to read them
    //
    if ( !fReadTemplateArguments ) {
        templateName += '<' + getTemplateArgumentList ();

        if ( templateName.getLastChar () == '>' ) {
            templateName += ' ';
        }

        templateName += '>';

        if ( fReadTerminator && *gName ) {
            gName += 1;
        }
    }

    //
    // Restore the previous replicators:
    //
    pArgList            = pSaveArgList;
    pZNameList            = pSaveZNameList;
    pTemplateArgList    = pSaveTemplateArgList;

    //    Return the completed 'template-name'

    return    templateName;

}    // End of "UnDecorator" FUNCTION "getTemplateName"


DName    UnDecorator::getTemplateArgumentList ( void )
{
    int        first    = TRUE;
    DName    aList;
    fGetTemplateArgumentList = true;

    while    (( aList.status () == DN_valid ) && *gName && ( *gName != AT_endoflist ))
    {
        //    Insert the argument list separator if not the first argument

        if    ( first )
            first    = FALSE;
        else
            aList    += ',';


        //    Get the individual argument type

        int        argIndex    = *gName - '0';


        //    Handle 'template-argument-replicators', otherwise a new argument type

        if    (( argIndex >= 0 ) && ( argIndex <= 9 ))
        {
            gName++;    // Skip past the replicator

            //    Append to the argument list

            aList    += ( *pTemplateArgList )[ argIndex ];

        }    // End of IF then
        else
        {
            pcchar_t    oldGName    = gName;
            DName        arg;

            //
            //    Extract the 'argument' type
            //

            if    ( *gName == BDT_void ) {
                gName++;
                arg = "void";
            } 
            elif ( (*gName == '$') && (gName[1] != '$')) {
                gName++;
                arg = getTemplateConstant();
            }
            elif ( *gName == '?' ) {
                //
                // This is a template-parameter, i.e. we have a "specialization" of
                // X<T>. so get the template-parameter-index and use a "generic" name
                // for this parameter
                //
                DName dimension = getSignedDimension();

                if ( haveTemplateParameters()) {
                    char buffer[16];

                    dimension.getString( buffer, 16 );

                    char *str = (*m_pGetParameter)(atol(buffer));

                    if ( str != NULL ) {
                        arg = str;
                    }
                    else {
                        arg = "`template-parameter" + dimension + "'";
                    }
                }
                else {
                    arg = "`template-parameter" + dimension + "'";
                }
            }
            else {
                arg = getPrimaryDataType ( DName() );
            }


            //    Add it to the current list of 'template-argument's, if it is bigger than a one byte encoding

            if    ((( gName - oldGName ) > 1 ) && !pTemplateArgList->isFull ())
                *pTemplateArgList    += arg;

            //    Append to the argument list

            aList    += arg;

        }    // End of IF else
    }    // End of WHILE

    //    Return the completed template argument list

    fGetTemplateArgumentList = false;

    return    aList;

}    // End of "UnDecorator" FUNCTION "getTemplateArgumentList"


DName    UnDecorator::getTemplateConstant(void)
{
    //
    // template-constant ::=
    //        '0'    <template-integral-constant>
    //        '1' <template-address-constant>
    //        '2' <template-floating-point-constant>
    //
    char type_category = *gName++;
    switch ( type_category )
    {
        //
        // template-integral-constant ::=
        //        <signed-dimension>
        //
    case TC_integral:
        return     getSignedDimension ();

        //
        // template-address-constant ::=
        //        '@'            // Null pointer
        //        <decorated-name>
        //
    case TC_address:
        if     ( *gName == TC_nullptr )
        {
            gName++;
            return    "NULL";
        }
        else
            return    DName("&") + getDecoratedName ();

        //
        // template-name ::=
        //        <docorated-name>
        //
    case TC_name:
        return getDecoratedName ();

        //
        // template-floating-point-constant ::=
        //        <normalized-mantissa><exponent>
        //
    case TC_fp:
        {
            DName    mantissa ( getSignedDimension () );
            DName    exponent ( getSignedDimension () );

            if    ( mantissa.isValid() && exponent.isValid() )
            {
                //
                // Get string representation of mantissa
                //
                char    buf[100];        // Way overkill for a compiler generated fp constant

                if    ( !mantissa.getString( &(buf[1]), 100 ) )    
                    return    DN_invalid;

                //
                // Insert decimal point
                //
                buf[0] = buf[1];

                if    ( buf[0] == '-' )
                {
                    buf[1] = buf[2];
                    buf[2] = '.';
                }
                else
                    buf[1] = '.';

                //
                // String it all together
                //
                return DName( buf ) + 'e' + exponent;

            } // End of IF then
            else
                return DN_truncated;

        }    // End of BLOCK case TC_fp

    case TC_dummy:
    case TC_nontype_dummy:
        {
            //
            // This is a template-parameter, i.e. we have a "specialization" of
            // X<n>. so get the template-parameter-index and use a "generic" name
            // for this parameter
            //
            DName dimension = getSignedDimension();

            if ( haveTemplateParameters()) {
                char buffer[16];

                dimension.getString( buffer, 16 );

                char *str = (*m_pGetParameter)(atol(buffer));

                if ( str != NULL ) {
                    return str;
                }
            }

            if (type_category == TC_dummy) {
                return "`template-parameter" + dimension + "'";
            } else {
                return "`non-type-template-parameter" + dimension + "'";
            }
        }
        break;

    case TC_named_dummy:
        {
            DName result = getZName(false);
            getSignedDimension();    // ignore it for the purposes of undecoration
            return result;
        }

    case TC_vptmd:
    case TC_gptmd:
    case TC_mptmf:
    case TC_vptmf:
    case TC_gptmf:
        {
            DName ptm = '{';
        
            switch (type_category) {
            case TC_mptmf:
            case TC_vptmf:
            case TC_gptmf:
                ptm += getDecoratedName();
                ptm += ',';
                break;
            }

            switch (type_category) {
            case TC_gptmf:
            case TC_gptmd:
                ptm += getSignedDimension();
                ptm += ',';
                // fallthrough

            case TC_vptmd:
            case TC_vptmf:
                ptm += getSignedDimension();
                ptm += ',';
                // fallthrough

            case TC_mptmf:
                ptm += getSignedDimension();
            }

            return ptm + '}';
        }
        break;

    case '\0':
        --gName;
        return    DN_truncated;

    default:
        return    DN_invalid;

    }    // End of SWITCH
}    // End of "UnDecorator" FUNCTION "getTemplateConstant"

    
inline    DName    UnDecorator::composeDeclaration ( const DName & symbol )
{
    DName            declaration;
    unsigned int    typeCode    = getTypeEncoding ();
    int                symIsUDC    = symbol.isUDC ();


    //    Handle bad typeCode's, or truncation

    if        ( TE_isbadtype ( typeCode ))
        return    DN_invalid;
    elif    ( TE_istruncated ( typeCode ))
        return    ( DN_truncated + symbol );
    elif    ( TE_isCident ( typeCode ))
        return    symbol;

    //    This is a very complex part.  The type of the declaration must be
    //    determined, and the exact composition must be dictated by this type.

    //    Is it any type of a function ?
    //    However, for ease of decoding, treat the 'localdtor' thunk as data, since
    //    its decoration is a function of the variable to which it belongs and not
    //    a usual function type of decoration.

#if    ( NO_COMPILER_NAMES )
    if    ( TE_isthunk ( typeCode ))
        return    DN_invalid;

    if    ( TE_isfunction ( typeCode ))
#else    // } elif !NO_COMPILER_NAMES {
    if    ( TE_isfunction ( typeCode ) && !(( TE_isthunk ( typeCode ) && TE_islocaldtor ( typeCode )) ||
            ( TE_isthunk ( typeCode ) && ( TE_istemplatector ( typeCode ) || TE_istemplatedtor ( typeCode )))))
#endif    // !NO_COMPILER_NAMES

    {
        //    If it is based, then compose the 'based' prefix for the name

        if    ( TE_isbased ( typeCode ))
            if    ( doMSKeywords () && doAllocationModel ())
                declaration    = ' ' + getBasedType ();
            else
                declaration    |= getBasedType ();    // Just lose the 'based-type'

#if    ( !NO_COMPILER_NAMES )
        //    Check for some of the specially composed 'thunk's

        if    ( TE_isthunk ( typeCode ) && TE_isvcall ( typeCode ))
        {
            declaration    += symbol + '{' + getCallIndex();

            DName thunkType = getVCallThunkType();

            if (!doNameOnly())
            {
                declaration    += ',' + thunkType + "}' ";
            }

            declaration += "}'";

            DName callingConvention = getCallingConvention();

            if (doMSKeywords() && doAllocationLanguage() && !doNameOnly())
            {
                declaration    = ' ' + callingConvention + ' ' + declaration;    // What calling convention ?
            }

        }    // End of IF then
        else
#endif    // !NO_COMPILER_NAMES
        {
            DName    vbptrDisp;
            DName    vbindex;
            DName    vtorDisp;
            DName    adjustment;
            DName    thisType;

#if    ( !NO_COMPILER_NAMES )
            if    ( TE_isthunk ( typeCode ))
            {
                if    ( TE_isvtoradjex ( typeCode ))
                {
                    vbptrDisp    = getDisplacement ();
                    vbindex        = getDisplacement ();
                    vtorDisp    = getDisplacement ();
                }
                else if    ( TE_isvtoradj ( typeCode ))
                {
                    vtorDisp    = getDisplacement ();
                }

                adjustment    = getDisplacement ();

            }    // End of IF else
#endif    // !NO_COMPILER_NAMES

            //    Get the 'this-type' for non-static function members

            if    ( TE_ismember ( typeCode ) && !TE_isstatic ( typeCode ))
                if    ( doThisTypes ())
                    thisType    = getThisType ();
                else
                    thisType    |= getThisType ();

            if    ( doMSKeywords ())
            {
                //    Attach the calling convention

                if    ( doAllocationLanguage ())
                    declaration    = getCallingConvention () + declaration;    // What calling convention ?
                else
                    declaration    |= getCallingConvention ();    // Just lose the 'calling-convention'

                //    Any model specifiers ?

#if !VERS_32BIT
                if    ( doAllocationModel ())
                    if        ( TE_isnear ( typeCode ))
                        declaration    = UScore ( TOK_nearSp ) + declaration;
                    elif    ( TE_isfar ( typeCode ))
                        declaration    = UScore ( TOK_farSp ) + declaration;
#endif

            }    // End of IF
            else
                declaration    |= getCallingConvention ();    // Just lose the 'calling-convention'

            //    Now put them all together

            if    ( !symbol.isEmpty ())
                if    ( !declaration.isEmpty () && !doNameOnly() )            // And the symbol name
                    declaration    += ' ' + symbol;
                else
                    declaration    = symbol;


            //    Compose the return type, catching the UDC case

            DName *    pDeclarator    = 0;
            DName    returnType;


            if    ( symIsUDC )        // Is the symbol a UDC operator ?
            {
                declaration    += " " + getReturnType ();

                if    ( doNameOnly() )
                    return    declaration;
            }
            else
            {
                pDeclarator    = gnew DName;
                returnType    = getReturnType ( pDeclarator );

            }    // End of IF else

#if    ( !NO_COMPILER_NAMES )
            //    Add the displacements for virtual function thunks

            if    ( TE_isthunk ( typeCode ))
            {
                if    ( TE_isvtoradjex ( typeCode ))
                    declaration += "`vtordispex{" + vbptrDisp + ',' + vbindex + ',' + vtorDisp + ',';
                else if    ( TE_isvtoradj ( typeCode ))
                    declaration    += "`vtordisp{" + vtorDisp + ',';
                else
                    declaration    += "`adjustor{";

                declaration    += adjustment + "}' ";

            }    // End of IF
#endif    // !NO_COMPILER_NAMES

            //    Add the function argument prototype

            declaration    += '(' + getArgumentTypes () + ')';

            //    If this is a non-static member function, append the 'this' modifiers

            if    ( TE_ismember ( typeCode ) && !TE_isstatic ( typeCode ))
                declaration    += thisType;

            //    Add the 'throw' signature

            if    ( doThrowTypes ())
                declaration    += getThrowTypes ();
            else
                declaration    |= getThrowTypes ();    // Just lose the 'throw-types'

            //    If it has a declarator, then insert it into the declaration,
            //    sensitive to the return type composition

            if    ( doFunctionReturns () && pDeclarator )
            {
                *pDeclarator    = declaration;
                declaration        = returnType;

            }    // End of IF
        }    // End of IF else
    }    // End of IF then
    else
    {
        declaration    += symbol;

        //    Catch the special handling cases

#if    ( !NO_COMPILER_NAMES )
        if        ( TE_isvftable ( typeCode ))
            return    getVfTableType ( declaration );
        elif    ( TE_isvbtable ( typeCode ))
            return    getVbTableType ( declaration );
        elif    ( TE_isguard ( typeCode ))
            return    ( declaration + '{' + getGuardNumber () + "}'" );
        elif    ( TE_isvdispmap ( typeCode ))
            return    getVdispMapType ( declaration );
        elif    ( TE_isthunk ( typeCode ) && TE_islocaldtor ( typeCode ))
            declaration    += "`local static destructor helper'";
        elif    ( TE_isthunk ( typeCode ) && TE_istemplatector ( typeCode ))
            declaration    += "`template static data member constructor helper'";
        elif    ( TE_isthunk ( typeCode ) && TE_istemplatedtor ( typeCode ))
            declaration    += "`template static data member destructor helper'";
        elif    ( TE_ismetaclass ( typeCode ))
            //
            // Meta-class information has its information in its operator id
            //
            return declaration;
#else    // } elif NO_COMPILER_NAMES {
        if    ( TE_isvftable ( typeCode )
                || TE_isvbtable ( typeCode )
                || TE_isguard ( typeCode )
                || TE_ismetaclass ( typeCode ))
            return    DN_invalid;
#endif    // NO_COMPILER_NAMES

        if ( TE_isthunk( typeCode ) && ( TE_istemplatector( typeCode ) || TE_istemplatedtor( typeCode ))) {
            //
            // Insert a space before the declaration
            //
            declaration = " " + declaration;
        }
        else {
            //    All others are decorated as data symbols
            declaration    = getExternalDataType ( declaration );
        }

    }    // End of IF else

    //    Prepend the 'virtual' and 'static' attributes for members

    if    ( TE_ismember ( typeCode ))
    {
        if    ( doMemberTypes ())
        {
            if    ( TE_isstatic ( typeCode ))
                declaration    = "static " + declaration;

            if    ( TE_isvirtual ( typeCode ) || ( TE_isthunk ( typeCode ) && ( TE_isvtoradj ( typeCode ) || TE_isvtoradjex ( typeCode ) || TE_isadjustor ( typeCode ))))
                declaration    = "virtual " + declaration;

        }    // End of IF

        //    Prepend the access specifiers

        if    ( doAccessSpecifiers ())
            if        ( TE_isprivate ( typeCode ))
                declaration    = "private: " + declaration;
            elif    ( TE_isprotected ( typeCode ))
                declaration    = "protected: " + declaration;
            elif    ( TE_ispublic ( typeCode ))
                declaration    = "public: " + declaration;

    }    // End of IF

#if    ( !NO_COMPILER_NAMES )
    //    If it is a thunk, mark it appropriately

    if    ( TE_isthunk ( typeCode ) && !doNameOnly())
        declaration    = "[thunk]:" + declaration;
#endif    // !NO_COMPILER_NAMES

    //    Return the composed declaration

    if( TE_isexternc( typeCode ) ) {
        declaration = "extern \"C\" " + declaration;
    }

    return    declaration;

}    // End of "UnDecorator" FUNCTION "composeDeclaration"


inline    int        UnDecorator::getTypeEncoding ( void )
{
    unsigned int    typeCode    = 0u;


    //    Strip any leading '_' which indicates that it is based

    if    ( *gName == '_' )
    {
        TE_setisbased ( typeCode );

        gName++;

    }    // End of IF

    //    Now handle the code proper :-

    if        (( *gName >= 'A' ) && ( *gName <= 'Z' ))    // Is it some sort of function ?
    {
        int    code    = *gName++ - 'A';


        //    Now determine the function type

        TE_setisfunction ( typeCode );    // All of them are functions ?

        //    Determine the calling model

        if    ( code & TE_far )
            TE_setisfar ( typeCode );
        else
            TE_setisnear ( typeCode );

        //    Is it a member function or not ?

        if    ( code < TE_external )
        {
            //    Record the fact that it is a member

            TE_setismember ( typeCode );

            //    What access permissions does it have

            switch    ( code & TE_access )
            {
            case TE_private:
                    TE_setisprivate ( typeCode );
                break;

            case TE_protect:
                    TE_setisprotected ( typeCode );
                break;

            case TE_public:
                    TE_setispublic ( typeCode );
                break;

            default:
                    TE_setisbadtype ( typeCode );
                    return    typeCode;

            }    // End of SWITCH

            //    What type of a member function is it ?

            switch    ( code & TE_adjustor )
            {
            case TE_adjustor:
                    TE_setisadjustor ( typeCode );
                break;

            case TE_virtual:
                    TE_setisvirtual ( typeCode );
                break;

            case TE_static:
                    TE_setisstatic ( typeCode );
                break;

            case TE_member:
                break;

            default:
                    TE_setisbadtype ( typeCode );
                    return    typeCode;

            }    // End of SWITCH
        }    // End of IF
    }    // End of IF then
    elif    ( *gName == '$' )    // Extended set ?  Special handling
    {
        //    What type of symbol is it ?
        bool isVtorDispThunkEx = false;
        switch    ( *( ++gName ))
        {
        case SHF_localdtor:    // A destructor helper for a local static ?
                TE_setislocaldtor ( typeCode );
            break;

        case SHF_vcall:    // A VCall-thunk ?
                TE_setisvcall ( typeCode );
            break;
        
        case SHF_templateStaticDataMemberCtor:    // A constructor helper for template static data members
                TE_setistemplatector ( typeCode );
            break; 

        case SHF_templateStaticDataMemberDtor:    // A destructor helper for template static data members
                TE_setistemplatedtor ( typeCode );
            break; 
        case SHF_vdispmap:
                TE_setvdispmap ( typeCode );
            break;

        case '$':
            {
                if ( * ( gName + 1 ) == SHF_AnyDLLImportMethod ) {
                    gName += 1;
                }

                switch ( *( ++gName )) {
                    case SHF_CPPManagedILFunction:                // C++ managed-IL function
                    case SHF_CPPManagedILMain:                    // C++ managed-IL main
                    case SHF_CPPManagedILDLLImportData:            // C++ managed-IL DLL-import function
                    case SHF_CPPManagedNativeDLLImportData:        // C++ managed-native DLL-import function
                        //
                        // Skip the encoding
                        //
                        gName += 1;
                        return getTypeEncoding();

                    case SHF_CManagedILFunction:                // C (or extern "C") managed-IL function
                    case SHF_CManagedILDLLImportData:            // C (or extern "C") managed-IL DLL-import function 
                    case SHF_CManagedNativeDLLImportData:        // C (or extern "C") managed-native DLL-import function 
                    {
                        //
                        // Skip the encoding
                        //
                        gName += 1;

                        //
                        // The next character should be the number of characters
                        // in the byte-count
                        //
                        if (( *gName >= '0' ) && ( *gName <= '9' )) {
                            //
                            // Skip the character count and the byte-count
                            // itself
                            //
                            gName += (( *gName - '0' ) + 1 );

                            typeCode = getTypeEncoding();
                            TE_setisisexternc( typeCode );
                            return typeCode;
                        }
                        else {
                            TE_setisbadtype( typeCode );
                        }
                    }
                    break;

                    case MGD_AppDomain:
                        {
                            gName += 1; //  this is __declspec(appdomain), but we won't say it
                            return getTypeEncoding();
                        }

                    case 0:
                        TE_setistruncated ( typeCode );
                        return  typeCode;

                    default:
                        TE_setisbadtype ( typeCode );
                        return  typeCode;
                }
            }
            break;

        case 0:
                TE_setistruncated ( typeCode );
                --gName; // back up, we advance back to the NUL below
            break;

        case SHF_VtorDispThunkEx:
                isVtorDispThunkEx = true;

                ++gName;
                if (*gName < '0' || *gName > '5') // case labels below
                {
                    if (*gName)
                      TE_setistruncated ( typeCode );
                    else
                      TE_setisbadtype ( typeCode );
                    return    typeCode;
                }
                //fallthrough

        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':    // Construction displacement adjustor thunks
            {
                int    code    = *gName - '0';


                //    Set up the principal type information

                TE_setisfunction ( typeCode );
                TE_setismember ( typeCode );
                if (isVtorDispThunkEx)
                    TE_setisvtoradjex ( typeCode );
                else
                    TE_setisvtoradj ( typeCode );

                //    Is it 'near' or 'far' ?

                if    ( code & TE_far )
                    TE_setisfar ( typeCode );
                else
                    TE_setisnear ( typeCode );

                //    What type of access protection ?

                switch    ( code & TE_access_vadj )
                {
                case TE_private_vadj:
                        TE_setisprivate ( typeCode );
                    break;

                case TE_protect_vadj:
                        TE_setisprotected ( typeCode );
                    break;

                case TE_public_vadj:
                        TE_setispublic ( typeCode );
                    break;

                default:
                        TE_setisbadtype ( typeCode );
                        return    typeCode;

                }    // End of SWITCH
            }    // End of CASE '0,1,2,3,4,5'
            break;

        default:
                TE_setisbadtype ( typeCode );
                return    typeCode;

        }    // End of SWITCH

        //    Advance past the code character

        gName++;

    }    // End of ELIF then
    elif    (( *gName >= TE_static_d ) && ( *gName <= TE_metatype ))    // Non function decorations ?
    {
        int    code    = *gName++;


        TE_setisdata ( typeCode );

        //    What type of symbol is it ?

        switch    ( code )
        {
        case ( TE_static_d | TE_private_d ):
                TE_setisstatic ( typeCode );
                TE_setisprivate ( typeCode );
            break;

        case ( TE_static_d | TE_protect_d ):
                TE_setisstatic ( typeCode );
                TE_setisprotected ( typeCode );
            break;

        case ( TE_static_d | TE_public_d ):
                TE_setisstatic ( typeCode );
                TE_setispublic ( typeCode );
            break;

        case TE_global:
                TE_setisglobal ( typeCode );
            break;

        case TE_guard:
                TE_setisguard ( typeCode );
            break;

        case TE_local:
                TE_setislocal ( typeCode );
            break;

        case TE_vftable:
                TE_setisvftable ( typeCode );
            break;

        case TE_vbtable:
                TE_setisvbtable ( typeCode );
            break;

        case TE_metatype:
                TE_setismetaclass ( typeCode );
            break;

        default:
                TE_setisbadtype ( typeCode );

                return    typeCode;

        }    // End of SWITCH
    }    // End of ELIF then
    elif    ( *gName == '9' ) {
        gName++;

        TE_setisCident ( typeCode );
    }
    elif    ( *gName )
        TE_setisbadtype ( typeCode );
    else
        TE_setistruncated ( typeCode );

    //    Return the composed type code

    return    typeCode;

}    // End of "UnDecorator" FUNCTION "getTypeEncoding"



DName    UnDecorator::getBasedType ( void )
{
    DName    basedDecl ( UScore ( TOK_basedLp ));


    //    What type of 'based' is it ?

    if    ( *gName )
    {
        switch    ( *gName++ )
        {
#if !VERS_32BIT
        case BT_segname:
                basedDecl    += UScore ( TOK_segnameLpQ ) + getSegmentName () + "\")";
            break;

        case BT_segment:
                basedDecl    += DName ( "NYI:" ) + UScore ( TOK_segment );
            break;
#endif

        case BT_void:
                basedDecl    += "void";
            break;

#if !VERS_32BIT
        case BT_self:
                basedDecl    += UScore ( TOK_self );
            break;

        case BT_nearptr:
                basedDecl    += DName ( "NYI:" ) + UScore ( TOK_nearP );
            break;

        case BT_farptr:
                basedDecl    += DName ( "NYI:" ) + UScore ( TOK_farP );
            break;

        case BT_hugeptr:
                basedDecl    += DName ( "NYI:" ) + UScore ( TOK_hugeP );
            break;

        case BT_segaddr:
                basedDecl    += "NYI:<segment-address-of-variable>";
            break;
#else
        case BT_nearptr:
                basedDecl    += getScopedName();
            break;
#endif

        case BT_basedptr:
                //
                // Note: based pointer on based pointer is reserved
                //
                return    DN_invalid;

        }    // End of SWITCH
    }    // End of IF else
    else
        basedDecl    += DN_truncated;

    //    Close the based syntax

    basedDecl    += ") ";

    //    Return completed based declaration

    return    basedDecl;

}    // End of "UnDecorator" FUNCTION "getBasedType"



DName    UnDecorator::getScopedName ( void )
{
    DName    name;


    //    Get the beginning of the name

    name    = getZName ( true );

    //    Now the scope (if any)

    if    (( name.status () == DN_valid ) && *gName && ( *gName != '@' ))
        name    = getScope () + "::" + name;

    //    Skip the trailing '@'

    if        ( *gName == '@' )
        gName++;
    elif    ( *gName )
        name    = DN_invalid;
    elif    ( name.isEmpty ())
        name    = DN_truncated;
    else
        name    = DName ( DN_truncated ) + "::" + name;

    //    And return the complete name

    return    name;

}    // End of "UnDecorator" FUNCTION "getECSUName"


inline    DName            UnDecorator::getECSUName ( void )        { return getScopedName(); }


inline    DName    UnDecorator::getEnumType ( void )
{
    DName    ecsuName;


    if    ( *gName )
    {
        //    What type of an 'enum' is it ?

        switch    ( *gName )
        {
        case ET_schar:
        case ET_uchar:
                ecsuName    = "char ";
            break;

        case ET_sshort:
        case ET_ushort:
                ecsuName    = "short ";
            break;

        case ET_sint:
            break;

        case ET_uint:
                ecsuName    = "int ";
            break;

        case ET_slong:
        case ET_ulong:
                ecsuName    = "long ";
            break;

        default:
            return    DN_invalid;

        }    // End of SWITCH

        //    Add the 'unsigned'ness if appropriate
        
        switch    ( *gName++ )
        {
        case ET_uchar:
        case ET_ushort:
        case ET_uint:
        case ET_ulong:
                ecsuName    = "unsigned " + ecsuName;
            break;

        }    // End of SWITCH

        //    Now return the composed name

        return    ecsuName;

    }    // End of IF then
    else
        return    DN_truncated;

}    // End of "UnDecorator" FUNCTION "getEnumType"



DName    UnDecorator::getCallingConvention ( void )
{
    if    ( *gName )
    {
        unsigned int    callCode    = ((unsigned int)*gName++ ) - 'A';


        //    What is the primary calling convention

        DASSERT(CC_cdecl == 0);
        
        if    (/*( callCode >= CC_cdecl ) &&*/( callCode <= CC_last ))
        {
            DName    callType;


            //    Now, what type of 'calling-convention' is it, 'interrupt' is special ?

            if    ( doMSKeywords ())
#if !VERS_32BIT
                if    ( callCode == CC_interrupt )
                    callType    = UScore ( TOK_interrupt );
                else
#endif
                {
                    switch    ( callCode & ~CC_saveregs )
                    {
                    case CC_cdecl:
                            callType    = UScore ( TOK_cdecl );
                        break;

                    case CC_pascal:
                            callType    = UScore ( TOK_pascal );
                        break;

                    case CC_thiscall:
                            callType    = UScore ( TOK_thiscall );
                        break;

                    case CC_stdcall:
                            callType    = UScore ( TOK_stdcall );
                        break;

                    case CC_fastcall:
                            callType    = UScore ( TOK_fastcall );
                        break;

                    case CC_cocall:
                            callType    = UScore ( TOK_cocall );
                        break;
                        
                    case CC_eabi:
                            callType    = UScore ( TOK_eabi );
                        break;

                    }    // End of SWITCH

                    //    Has it also got 'saveregs' marked ?

#if !VERS_32BIT
                    if    ( callCode & CC_saveregs )
                        callType    += ' ' + UScore ( TOK_saveregs );
#endif

                }    // End of IF else

            //    And return

            return    callType;

        }    // End of IF then
        else
            return    DN_invalid;

    }    // End of IF then
    else
        return    DN_truncated;

}    // End of "UnDecorator" FUNCTION "getCallingConvention"



DName    UnDecorator::getReturnType ( DName * pDeclarator )
{
    if    ( *gName == '@' )    // Return type for constructors and destructors ?
    {
        gName++;

        return    DName ( pDeclarator );

    }    // End of IF then
    else
        return    getDataType ( pDeclarator );

}    // End of "UnDecorator" FUNCTION "getReturnType"



DName    UnDecorator::getDataType ( DName * pDeclarator )
{
    DName    superType ( pDeclarator );


    //    What type is it ?

    switch    ( *gName )
    {
    case 0:
            return    ( DN_truncated + superType );

    case BDT_void:
            gName++;

            if    ( superType.isEmpty ())
                return    "void";
            else
                return    "void " + superType;

    case '?':
        {

            gName++;    // Skip the '?'

            const char *pStr = "";

            superType = getDataIndirectType(superType, pStr, DName(), 0);
            return    getPrimaryDataType ( superType );
        }    // End of CASE '?'

    default:
            return    getPrimaryDataType ( superType );

    }    // End of SWITCH
}    // End of "UnDecorator" FUNCTION "getDataType"



DName    UnDecorator::getPrimaryDataType ( const DName & superType )
{
    DName    cvType;


    switch    ( *gName )
    {
    case 0:
            return    ( DN_truncated + superType );

    case PDT_volatileReference:
            cvType    = "volatile";

            if    ( !superType.isEmpty ())
                cvType    += ' ';

        // No break

    case PDT_reference:
        {
            DName    superName ( superType );


            gName++;

            const char* pStr = "&";

            return getReferenceType(cvType, superName.setPtrRef (), pStr);

        }    // End of CASE 'PDT_reference'

    case PDT_extend:
        {
            //
            // Extended Primary Data Type (items overlooked in original design):
            // prefixed by '$$'.
            //
            if    ( gName[1] != PDT_extend )
                if    ( gName[1] == '\0' ) 
                    return DN_truncated + superType;
                else
                    return DN_invalid;

            gName += 2;

            switch    ( *gName )
            {
            case PDT_ex_function:
                gName++;
                return    getFunctionIndirectType( superType );

            case PDT_ex_other:
                gName++;
                return    getPtrRefDataType( superType, /* isPtr = */ TRUE );

            case PDT_ex_qualified:
                {
                    gName++;

                    const char *pStr = "";

                    return getBasicDataType(getDataIndirectType(superType, pStr, DName(), 0));
                }
                break;

            case PDT_ex_vol_rvalue_ref:
                cvType = "volatile";

                if (!superType.isEmpty())
                {
                    cvType += ' ';
                }
                // No break

            case PDT_ex_rvalue_ref:
                {
                    DName superName(superType);

                    gName++;

                    const char* pStr = "&&";

                    return getReferenceType(cvType, superName.setPtrRef(), pStr);
                }

            case 0:
                return    ( DN_truncated + superType );

            default:
                return    DN_invalid;
            }
        }

    default:
            return    getBasicDataType ( superType );

    }    // End of SWITCH
}    // End of "UnDecorator" FUNCTION "getPrimaryDataType"



DName    UnDecorator::getArgumentTypes ( void )
{
    switch    ( *gName )
    {
    case AT_ellipsis:
            return    ( gName++, doEllipsis() ? "..." : UNDNAME_ELLIPSIS_ALTERNATE );

    case AT_void:
            return    ( gName++, "void" );

    default:
        {
            DName    arguments ( getArgumentList ());


            //    Now, is it a varargs function or not ?

            if    ( arguments.status () == DN_valid )
                switch    ( *gName )
                {
                case 0:
                        return    arguments;

                case AT_ellipsis:
                        return    ( gName++, arguments + (doEllipsis() ? ",..." : "," UNDNAME_ELLIPSIS_ALTERNATE) );

                case AT_endoflist:
                        return    ( gName++, arguments );

                default:
                        return    DN_invalid;

                }    // End of SWITCH
            else
                return    arguments;

        }    // End of DEFAULT
    }    // End of SWITCH
}    // End of "UnDecorator" FUNCTION "getArgumentTypes"


DName    UnDecorator::getArgumentList ( void )
{
    int        first    = TRUE;
    DName    aList;


    while    (( aList.status () == DN_valid ) && ( *gName != AT_endoflist ) && ( *gName != AT_ellipsis ))
    {
        //    Insert the argument list separator if not the first argument

        if    ( first )
            first    = FALSE;
        else
            aList    += ',';


        //    Get the individual argument type

        if    ( *gName )
        {
            int        argIndex    = *gName - '0';


            //    Handle 'argument-replicators', otherwise a new argument type

            if    (( argIndex >= 0 ) && ( argIndex <= 9 ))
            {
                gName++;    // Skip past the replicator

                //    Append to the argument list

                aList    += ( *pArgList )[ argIndex ];

            }    // End of IF then
            else
            {
                pcchar_t    oldGName    = gName;


                //    Extract the 'argument' type

                DName    arg ( getPrimaryDataType ( DName ()));


                //    Add it to the current list of 'argument's, if it is bigger than a one byte encoding

                if    ((( gName - oldGName ) > 1 ) && !pArgList->isFull ())
                    *pArgList    += arg;

                //    Append to the argument list

                aList    += arg;

#if 1
                if (gName == oldGName)    // prevent endless loop on invalid input
                    aList = DN_invalid;
#endif

            }    // End of IF else
        }    // End of IF then
        else
        {
            aList    += DN_truncated;

            break;

        }    // End of IF else
    }    // End of WHILE

    //    Return the completed argument list

    return    aList;

}    // End of "UnDecorator" FUNCTION "getArgumentList"



DName    UnDecorator::getThrowTypes ( void )
{
    if    ( *gName )
        if    ( *gName == AT_ellipsis )    // Handle ellipsis here to suppress the 'throw' signature
            return    ( gName++, DName ());
        else
            return    ( " throw(" + getArgumentTypes () + ')' );
    else
        return    ( DName ( " throw(" ) + DN_truncated + ')' );

}    // End of "UnDecorator" FUNCTION "getThrowTypes"



DName    UnDecorator::getBasicDataType ( const DName & superType )
{
    if    ( *gName )
    {
        unsigned char    bdtCode    = *gName++;
        unsigned char    extended_bdtCode = 0x0;
        int                pCvCode    = -1;
        DName            basicDataType;


        //    Extract the principal type information itself, and validate the codes

        switch    ( bdtCode )
        {
        case BDT_schar:
        case BDT_char:
        case ( BDT_char   | BDT_unsigned ):
                basicDataType    = "char";
            break;

        case BDT_short:
        case ( BDT_short  | BDT_unsigned ):
                basicDataType    = "short";
            break;

        case BDT_int:
        case ( BDT_int    | BDT_unsigned ):
                basicDataType    = "int";
            break;

        case BDT_long:
        case ( BDT_long   | BDT_unsigned ):
                basicDataType    = "long";
            break;

#if !VERS_32BIT
        case BDT_segment:
                basicDataType    = UScore ( TOK_segment );
            break;
#endif

        case BDT_float:
                basicDataType    = "float";
            break;

        case BDT_longdouble:
                basicDataType    = "long ";

            // No break

        case BDT_double:
                basicDataType    += "double";
            break;

        case BDT_pointer:
        case ( BDT_pointer | BDT_const ):
        case ( BDT_pointer | BDT_volatile ):
        case ( BDT_pointer | BDT_const | BDT_volatile ):
                pCvCode    = ( bdtCode & ( BDT_const | BDT_volatile ));
            break;
        case BDT_extend:
            switch(extended_bdtCode = *gName++) {
                case BDT_array:
                    pCvCode = -2;
                    break;
                case BDT_bool:
                    basicDataType    = "bool";
                    break;
                case BDT_int8:
                case ( BDT_int8   | BDT_unsigned ):
                    basicDataType    = "__int8";
                    break;
                case BDT_int16:
                case ( BDT_int16  | BDT_unsigned ):
                    basicDataType    = "__int16";
                    break;
                case BDT_int32:
                case ( BDT_int32  | BDT_unsigned ):
                    basicDataType    = "__int32";
                    break;
                case BDT_int64:
                case ( BDT_int64  | BDT_unsigned ):
                    basicDataType    = "__int64";
                    break;
                case BDT_int128:
                case ( BDT_int128 | BDT_unsigned ):
                    basicDataType    = "__int128";
                    break;
                case BDT_unknown:
                    basicDataType = "<unknown>";
                    break;
                case BDT_wchar_t:
#if defined(VERSP_PARSEONLY) && VERSP_PARSEONLY
                    // So that we get System::Char as a template argument correct
                    basicDataType    = "__wchar_t";
#else  // VERSP_PARSEONLY
                    // So that we get diagnostics like we want them
                    basicDataType    = "wchar_t";
#endif // VERSP_PARSEONLY
                    break;
#if CC_COR
                case BDT_coclass:
                case BDT_cointerface:
                    {
                        gName--;    // Backup, since 'ecsu-data-type' does it's own decoding

                        basicDataType = getECSUDataType();

                        if ( basicDataType.isEmpty()) {
                            return basicDataType;
                        }
                    }
                    break;
#endif    // CC_COR
                case '$':
                    return "__w64 " + getBasicDataType (superType);

                case '\0':
                    gName--;        // End of string, better back-up
                    basicDataType    = DN_truncated;
                    break;

                default:
                    basicDataType    = "UNKNOWN";
                    break;
                }
            break;

        case BDT_void:
            basicDataType = "void";
            break;

        default:
                gName--;    // Backup, since 'ecsu-data-type' does it's own decoding

                basicDataType    = getECSUDataType ();

                if    ( basicDataType.isEmpty ())
                    return    basicDataType;
            break;

        }    // End of SWITCH

        //    What type of basic data type composition is involved ?

        if    ( pCvCode == -1 )    // Simple ?
        {
            //    Determine the 'signed/unsigned'ness

            switch    ( bdtCode )
            {
            case ( BDT_char   | BDT_unsigned ):
            case ( BDT_short  | BDT_unsigned ):
            case ( BDT_int    | BDT_unsigned ):
            case ( BDT_long   | BDT_unsigned ):
                    basicDataType    = "unsigned " + basicDataType;
                break;

            case BDT_schar:
                    basicDataType    = "signed " + basicDataType;
                break;
            case BDT_extend:
                switch    ( extended_bdtCode )
                {

                    case ( BDT_int8   | BDT_unsigned ):
                    case ( BDT_int16  | BDT_unsigned ):
                    case ( BDT_int32  | BDT_unsigned ):
                    case ( BDT_int64  | BDT_unsigned ):
                    case ( BDT_int128 | BDT_unsigned ):
                        basicDataType    = "unsigned " + basicDataType;
                        break;

                }    // End of SWITCH
                break;
            }    // End of SWITCH

            //     Add the indirection type to the type

            if    ( !superType.isEmpty () )
                    basicDataType    += ' ' + superType;

            //    And return the completed type

            return    basicDataType;

        }    // End of IF then
        else
        {
            DName    cvType;
            DName    superName ( superType );

            if ( pCvCode == -2 )
            {
                superName.setIsArray();
                DName arType =    getPointerTypeArray ( cvType, superName );
                // if we didn't get back an array, append.
                // A multidimensional array sticks the braces in before the
                // other dimensions at sets isArray on it's return type.
                if (!arType.isArray()) {
                    arType += "[]";
                }
                return arType;
            }

            //    Is it 'const/volatile' qualified ?
            
            if        ( superType . isEmpty() ) 
            {
                //
                // const/volatile are redundantly encoded, except at the start
                // of a "type only" context.  In such a context, the super-type
                // is empty.
                //
                if        ( pCvCode & BDT_const )
                {
                    cvType    = "const";

                    if    ( pCvCode & BDT_volatile )
                        cvType    += " volatile";
                }    // End of IF then
                elif    ( pCvCode & BDT_volatile )
                    cvType    = "volatile";
            }    // End of IF then

            //    Construct the appropriate pointer type declaration

            return    getPointerType ( cvType, superName );

        }    // End of IF else
    }    // End of IF then
    else
        return    ( DN_truncated + superType );

}    // End of "UnDecorator" FUNCTION "getBasicDataType"



DName    UnDecorator::getECSUDataType ( void )
{
    //    Extract the principal type information itself, and validate the codes

    int fPrefix = doEcsu() && !doNameOnly();

    DName Prefix;

    switch    ( *gName++ )
    {
    case 0:
            gName--;    // Backup to permit later error recovery to work safely

            return    "`unknown ecsu'" + DN_truncated;

    case BDT_union:
            Prefix = "union ";
        break;

    case BDT_struct:
            Prefix = "struct ";
        break;

    case BDT_class:
            Prefix = "class ";
        break;

#if CC_COR
    case BDT_coclass:
            Prefix = "coclass ";
        break;

    case BDT_cointerface:
            Prefix = "cointerface ";
        break;
#endif    // CC_COR

    case BDT_enum:
            fPrefix = doEcsu();

            Prefix = "enum " + getEnumType ();
        break;

//    default:
//            return    DN_invalid;

    }    // End of SWITCH

    DName            ecsuDataType;

    if    ( fPrefix )
        ecsuDataType    = Prefix;

    //    Get the 'class/struct/union' name

    ecsuDataType    += getECSUName ();

    //    And return the formed 'ecsu-data-type'

    return    ecsuDataType;

}    // End of "UnDecorator" FUNCTION "getECSUDataType"


//
// Undecorator::getFunctionIndirectType
//
//    Note: this function gets both the function-indirect-type and the function-type.
//
DName        UnDecorator::getFunctionIndirectType( const DName & superType )
{
    if    ( ! *gName )
        return DN_truncated + superType;

    if    ( ! IT_isfunction( *gName ))
        return DN_invalid;


    int        fitCode    = *gName++ - '6';

    if        ( fitCode == ( '_' - '6' ))
    {
        if    ( *gName )
        {
            fitCode    = *gName++ - 'A' + FIT_based;

            if    (( fitCode < FIT_based ) || ( fitCode > ( FIT_based | FIT_far | FIT_member )))
                fitCode    = -1;

        }    // End of IF then
        else
            return    ( DN_truncated + superType );

    }    // End of IF then
    elif    (( fitCode < FIT_near ) || ( fitCode > ( FIT_far | FIT_member )))
        fitCode    = -1;

    //    Return if invalid name

    if    ( fitCode == -1 )
        return    DN_invalid;


    //    Otherwise, what are the function indirect attributes

    DName    thisType;
    DName    fitType = superType;

    //    Is it a pointer to member function ?

    if    ( fitCode & FIT_member )
    {
        fitType    = "::" + fitType;

        if    ( *gName )
            fitType    = ' ' + getScope () + fitType;
        else
            fitType    = DN_truncated + fitType;

        if    ( *gName )
            if    ( *gName == '@' )
                gName++;
            else
                return    DN_invalid;
        else
            return    ( DN_truncated + fitType );

        if    ( doThisTypes ())
            thisType    = getThisType ();
        else
            thisType    |= getThisType ();

    }    // End of IF

    //    Is it a based allocated function ?

    if    ( fitCode & FIT_based )
        if    ( doMSKeywords ())
            fitType    = ' ' + getBasedType () + fitType;
        else
            fitType    |= getBasedType ();    // Just lose the 'based-type'

    //    Get the 'calling-convention'

    if    ( doMSKeywords ())
    {
        fitType    = getCallingConvention () + fitType;

        //    Is it a near or far function pointer

#if !VERS_32BIT
        fitType    = UScore ((( fitCode & FIT_far ) ? TOK_farSp : TOK_nearSp )) + fitType;
#endif

    }    // End of IF then
    else
        fitType    |= getCallingConvention ();    // Just lose the 'calling-convention'

    //    Parenthesise the indirection component, and work on the rest

    if    ( ! superType . isEmpty() ) {
        fitType    = '(' + fitType + ')';
    }

    //    Get the rest of the 'function-type' pieces

    DName *    pDeclarator    = gnew DName;
    DName    returnType ( getReturnType ( pDeclarator ));


    fitType    += '(' + getArgumentTypes () + ')';

    if    ( doThisTypes () && ( fitCode & FIT_member ))
        fitType    += thisType;

    if    ( doThrowTypes ())
        fitType    += getThrowTypes ();
    else
        fitType    |= getThrowTypes ();    // Just lose the 'throw-types'

    //    Now insert the indirected declarator, catch the allocation failure here

    if    ( pDeclarator )
        *pDeclarator    = fitType;
    else
        return    DN_error;

    //    And return the composed function type (now in 'returnType' )

    return    returnType;
}


DName    UnDecorator::getPtrRefType ( const DName & cvType, const DName & superType, const char* ptrChar )
{
    DASSERT((ptrChar != NULL) && ((*ptrChar == '*') || (*ptrChar == '&') || (*ptrChar == '^') || (*ptrChar == '%') || (*ptrChar == '\0')));

    //    Doubles up as 'pointer-type' and 'reference-type'

    if    ( *gName )
        if    ( IT_isfunction ( *gName ))    // Is it a function or data indirection ?
        {
            DName    fitType    = ptrChar;


            if    ( !cvType.isEmpty () && ( superType.isEmpty () || !superType.isPtrRef ()))
                fitType    += cvType;

            if    ( !superType.isEmpty ())
                fitType    += superType;

            return getFunctionIndirectType( fitType );
        }    // End of IF then
        else
        {
            //    Otherwise, it is either a pointer or a reference to some data type

            DName    innerType ( getDataIndirectType ( superType, ptrChar, cvType ));

            return    getPtrRefDataType ( innerType, *ptrChar == '*' );
        }    // End of IF else
    else
    {
        DName    trunk ( DN_truncated );


        trunk    += ptrChar;

        if    ( !cvType.isEmpty ())
            trunk    += cvType;

        if    ( !superType.isEmpty ())
        {
            if    ( !cvType.isEmpty ())
                trunk    += ' ';

            trunk    += superType;

        }    // End of IF

        return    trunk;

    }    // End of IF else
}    // End of "UnDecorator" FUNCTION "getPtrRefType"


DName UnDecorator::getExtendedDataIndirectType(const char*& prType, bool& fIsPinPtr, int thisFlag)
{
    DASSERT((prType != NULL) && ((*prType == '*') || (*prType == '&') || (*prType == '^') || (*prType == '%') || (*prType == '\0')));

    DName szComPlusIndirSpecifier;

    DASSERT(*gName == '$');

    gName++;    // swallow up the dollar

    switch( *gName )
    {
    case DIT_GCPointer:
        // Don't print ^ if we're undecorating the 'this' pointer
        if (!thisFlag) {
            // if (oldSyntax()) szComPlusIndirSpecifier = "__gc "; else
            prType = (*prType == '&') ? "%" : "^";
        }
        gName++;
        break;

    case DIT_PinPointer:
        // DASSERT(!thisFlag);    // validate, don't assert
        if (thisFlag)
            return    DN_invalid;

        fIsPinPtr = true;
        szComPlusIndirSpecifier = '>';
        gName++;
        break;

    case DIT_InteriorPointer:
        // this pointer of value class is interior_ptr 
        prType = "%";
        gName++;
        break;

    default:
        if ( !gName[0]    ||    !gName[1] )
            return    DN_truncated;
        // DASSERT(!thisFlag);    // validate, don't assert
        if (thisFlag)
            return    DN_invalid;

        unsigned int nRank = ((gName[0]-'0') << 4) + (gName[1]-'0');
        gName += 2;

        if (nRank > 1)
        {
            szComPlusIndirSpecifier = ',';
            szComPlusIndirSpecifier = szComPlusIndirSpecifier + DName((unsigned __int64)nRank);
        }

        szComPlusIndirSpecifier = szComPlusIndirSpecifier + '>';

        if (*gName == '$')
        {
            // Skip the "incomplete" com array marker.  There is no
            // way to express this construct in the old syntax.  In
            // the new syntax, this tells us the difference between:
            //
            //      array<int>^
            // and: array<int>

            gName++;
        }
        else
        {
            szComPlusIndirSpecifier = szComPlusIndirSpecifier + '^';
        }

        if (*gName)
            gName++;
        else
            szComPlusIndirSpecifier += DN_truncated;

        szComPlusIndirSpecifier.setIsComArray();

        return szComPlusIndirSpecifier;
    }

    return DName();
}

DName    UnDecorator::getDataIndirectType ( const DName & superType, const char* prType, const DName & cvType, int thisFlag )
{
    DASSERT((prType != NULL) && ((*prType == '*') || (*prType == '&') || (*prType == '^') || (*prType == '%') || (*prType == '\0')));

    DName szComPlusIndirSpecifier;
    bool bIsPinPtr = false;

    if        ( *gName )
    {
        if( gName[0] == '$' ) 
        {
            DName name = getExtendedDataIndirectType(prType, bIsPinPtr, thisFlag);

            if (!name.isEmpty())
            {
                return name;
            }
        }

        unsigned int    ditCode    = ( *gName - (( *gName >= 'A' ) ? (unsigned int)'A': (unsigned int)( '0' - 26 )));

        DName msExtension;
        DName msExtensionPre;

        int fContinue = TRUE;

        do
        {
            switch    ( ditCode )
            {
            case DIT_ptr64:
                    if    ( doMSKeywords () && doPtr64() ) {
                        if ( !msExtension.isEmpty())
                            msExtension = msExtension + ' ' + UScore( TOK_ptr64 );
                        else
                            msExtension = UScore( TOK_ptr64 );
                    }
                break;
            case DIT_unaligned:
                    if    ( doMSKeywords ()) {
                        if ( !msExtensionPre.isEmpty())
                            msExtensionPre = msExtensionPre + ' ' + UScore( TOK_unaligned );
                        else
                            msExtensionPre = UScore( TOK_unaligned );
                    }
                break;
            case DIT_restrict:
                    if    ( doMSKeywords ()) {
                        if ( !msExtension.isEmpty())
                            msExtension = msExtension + ' ' + UScore( TOK_restrict );
                        else
                            msExtension = UScore( TOK_restrict );
                    }
                break;

            default:
                fContinue = FALSE;
                break;
            }
            
            if (fContinue)
            {
                gName++;

                if( gName[0] == '$' ) 
                {
                    DName name = getExtendedDataIndirectType(prType, bIsPinPtr, thisFlag);

                    if (!name.isEmpty())
                    {
                        return name;
                    }
                }

                ditCode    = ( *gName - (( *gName >= 'A' ) ? (unsigned int)'A': (unsigned int)( '0' - 26 )));
            }
        } while (fContinue);

        if (*gName)
            gName++;        // Skip to next character in name

        //    Is it a valid 'data-indirection-type' ?

        DASSERT(DIT_near == 0);
        if    (( ditCode <= ( DIT_const | DIT_volatile | DIT_modelmask | DIT_member )))
        {
            DName    ditType ( prType );

            ditType = szComPlusIndirSpecifier + ditType;

            if ( !msExtension.isEmpty()) 
                ditType = ditType + ' ' + msExtension;

            if ( !msExtensionPre.isEmpty())
                ditType = msExtensionPre + ' ' + ditType;

            //    If it is a member, then these attributes immediately precede the indirection token

            if    ( ditCode & DIT_member )
            {
                //    If it is really 'this-type', then it cannot be any form of pointer to member

                if    ( thisFlag )
                    return    DN_invalid;

                //    Otherwise, extract the scope for the PM

                if        ( *prType != '\0' )
                {
                    ditType        = "::" + ditType;

                    if    ( *gName )
                        ditType    = getScope () + ditType;
                    else
                        ditType    = DN_truncated + ditType;
                }
                elif    ( *gName )
                {
                    //
                    // The scope is ignored for special uses of data-indirect-type, such
                    // as storage-convention.  I think it's a bug that we ever mark things
                    // with Member storage convention, as that is already covered in the
                    // scope of the name.  However, we don't want to change the dname scheme,
                    // so we're stuck with it.
                    //
                    ditType |= getScope ();
                }

                //    Now skip the scope terminator

                if        ( !*gName )
                    ditType    += DN_truncated;
                elif    ( *gName++ != '@' )
                    return    DN_invalid;

            }    // End of IF

            //    Add the 'model' attributes (prefixed) as appropriate

            if    ( doMSKeywords ()) {
                switch    ( ditCode & DIT_modelmask )
                {
#if !VERS_32BIT
                case DIT_near:
                        if    ( do32BitNear ())
                            ditType    = UScore ( TOK_near ) + ditType;
                    break;

                case DIT_far:
                        ditType    = UScore ( TOK_far ) + ditType;
                    break;

                case DIT_huge:
                        ditType    = UScore ( TOK_huge ) + ditType;
                    break;
#endif

                case DIT_based:
                        //    The 'this-type' can never be 'based'

                        if    ( thisFlag )
                            return    DN_invalid;

                        ditType    = getBasedType () + ditType;
                    break;

                }    // End of SWITCH
            }    // End of IF
            elif    (( ditCode & DIT_modelmask ) == DIT_based )
                ditType    |= getBasedType ();    // Just lose the 'based-type'

            //    Handle the 'const' and 'volatile' attributes

            if    ( ditCode & DIT_volatile )
                ditType    = "volatile " + ditType;

            if    ( ditCode & DIT_const )
                ditType    = "const " + ditType;

            //    Append the supertype, if not 'this-type'

            if    ( !thisFlag )
                if        ( !superType.isEmpty ())
                {
                    //    Is the super context included 'cv' information, ensure that it is added appropriately

                    if    ( superType.isPtrRef () || cvType.isEmpty ())
                        if (superType.isArray())
                            ditType    = superType;    // array type, skip space
                        else
                            ditType    += ' ' + superType;
                    else
                        ditType    += ' ' + cvType + ' ' + superType;

                }    // End of IF then
                elif    ( !cvType.isEmpty ())
                    ditType    += ' ' + cvType;

            //    Make sure qualifiers aren't re-applied
            ditType.setPtrRef ();

            if (bIsPinPtr)
            {
                ditType.setIsPinPtr();
            }

            //    Finally, return the composed 'data-indirection-type' (with embedded sub-type)

            return    ditType;

        }    // End of IF then
        else
            return    DN_invalid;

    }    // End of IF then
    elif    ( !thisFlag && !superType.isEmpty ())
    {
        //    Is the super context included 'cv' information, ensure that it is added appropriately

        if    ( superType.isPtrRef () || cvType.isEmpty ())
            return    ( DN_truncated + superType );
        else
            return    ( DN_truncated + cvType + ' ' + superType );

    }    // End of ELIF then
    elif    ( !thisFlag && !cvType.isEmpty ())
        return    ( DN_truncated + cvType );
    else
        return    DN_truncated;

}    // End of "UnDecorator" FUNCTION "getDataIndirectType"


inline    DName    UnDecorator::getPtrRefDataType ( const DName & superType, int isPtr )
{
    //    Doubles up as 'pointer-data-type' and 'reference-data-type'

    if    ( *gName )
    {
        //    Is this a 'pointer-data-type' ?

        if    ( isPtr && ( *gName == PoDT_void ))
        {
            gName++;    // Skip this character

            if    ( superType.isEmpty ())
                return    "void";
            else
                return    "void " + superType;

        }    // End of IF

        //    Otherwise it may be a 'reference-data-type'

        if    ( *gName == RDT_array )    // An array ?
        {
            gName++;

            return    getArrayType( superType );

        }    // End of IF

        //    Otherwise, it is a 'basic-data-type'

        DName bdt = getBasicDataType ( superType );
        if (superType.isComArray())
        {
            bdt = "cli::array<" + bdt;
        }
        else if (superType.isPinPtr())
        {
            bdt = "cli::pin_ptr<" + bdt;
        }
        return bdt;

    }    // End of IF then
    else
        return    ( DN_truncated + superType );

}    // End of "UnDecorator" FUNCTION "getPtrRefDataType"


inline    DName    UnDecorator::getArrayType ( const DName & superType )
{
    if    ( *gName )
    {
        int    noDimensions    = getNumberOfDimensions ();

        if ( noDimensions < 0 )
            noDimensions = 0;

        if    ( !noDimensions )
            return    getBasicDataType ( DName ( '[' ) + DN_truncated + ']' );
        else
        {
            DName    arrayType;

            if ( superType.isArray() ) {
                arrayType    += "[]";
            }

            while    ( arrayType.isValid() && noDimensions-- && *gName )
                arrayType    += '[' + getDimension () + ']';

            //    If it is indirect, then parenthesise the 'super-type'

            if    ( !superType.isEmpty () )
                if ( superType.isArray() )
                    arrayType    = superType + arrayType;
                else
                    arrayType    = '(' + superType + ')' + arrayType;

            //    Return the finished array dimension information

            DName newType =    getPrimaryDataType ( arrayType );
            newType.setIsArray();
            return newType;

        }    // End of IF else
    }    // End of IF
    elif    ( !superType.isEmpty ())
        return    getBasicDataType ( '(' + superType + ")[" + DN_truncated + ']' );
    else
        return    getBasicDataType ( DName ( '[' ) + DN_truncated + ']' );

}    // End of "UnDecorator" FUNCTION "getArrayType"


inline        DName        UnDecorator::getLexicalFrame ( void )        {    return    '`' + getDimension () + '\'';    }
inline        DName        UnDecorator::getStorageConvention ( void )    {    return    getDataIndirectType ();    }


inline DName UnDecorator::getDataIndirectType()
{
    const char *pStr = "";
    
    return getDataIndirectType(DName(), pStr, DName());
}

inline DName UnDecorator::getThisType()
{
    const char *pStr = "";
    
    return getDataIndirectType(DName(), pStr, DName(), TRUE);
}

inline DName UnDecorator::getPointerType(const DName& cv, const DName& name)
{
    const char* pStr = "*";
    
    return getPtrRefType(cv, name, pStr);
}

inline DName UnDecorator::getPointerTypeArray(const DName& cv, const DName& name)
{
    const char* pStr = "";
    
    return getPtrRefType(cv, name, pStr);
}

inline DName UnDecorator::getReferenceType(const DName& cv, const DName& name, const char* ptrChar)
{
    return getPtrRefType(cv, name, ptrChar);
}

inline    DName        UnDecorator::getSegmentName ( void )        {    return    getZName ( true );    }

#if    ( !NO_COMPILER_NAMES )
inline    DName        UnDecorator::getDisplacement ( void )        {    return    getDimension ( true );    }
inline    DName        UnDecorator::getCallIndex ( void )            {    return    getDimension ();    }
inline    DName        UnDecorator::getGuardNumber ( void )        {    return    getDimension ();    }

inline    DName    UnDecorator::getVbTableType ( const DName & superType )
{    return    getVfTableType ( superType );    }


inline    DName    UnDecorator::getVCallThunkType ( void )
{
#if VERS_32BIT
    switch (*gName) {
    case VMT_nTnCnV:
        ++gName;
        return DName("{flat}");
    case 0:
        return DN_truncated;
    default:
        return DN_invalid;
    }
#else
    DName    vcallType    = '{';


    //    Get the 'this' model, and validate all values

    switch    ( *gName )
    {
    case VMT_nTnCnV:
    case VMT_nTfCnV:
    case VMT_nTnCfV:
    case VMT_nTfCfV:
    case VMT_nTnCbV:
    case VMT_nTfCbV:
            vcallType    += UScore ( TOK_nearSp );
        break;

    case VMT_fTnCnV:
    case VMT_fTfCnV:
    case VMT_fTnCfV:
    case VMT_fTfCfV:
    case VMT_fTnCbV:
    case VMT_fTfCbV:
            vcallType    += UScore ( TOK_farSp );
        break;

    case 0:
            return    DN_truncated;

    default:
            return    DN_invalid;

    }    // End of SWITCH

    //    Always append 'this'

    vcallType    += "this, ";

    //    Get the 'call' model

    switch    ( *gName )
    {
    case VMT_nTnCnV:
    case VMT_fTnCnV:
    case VMT_nTnCfV:
    case VMT_fTnCfV:
    case VMT_nTnCbV:
    case VMT_fTnCbV:
            vcallType    += UScore ( TOK_nearSp );
        break;

    case VMT_nTfCnV:
    case VMT_fTfCnV:
    case VMT_nTfCfV:
    case VMT_fTfCfV:
    case VMT_nTfCbV:
    case VMT_fTfCbV:
            vcallType    += UScore ( TOK_farSp );
        break;

    }    // End of SWITCH

    //    Always append 'call'

    vcallType    += "call, ";

    //    Get the 'vfptr' model

    switch    ( *gName++ )    // Last time, so advance the pointer
    {
    case VMT_nTnCnV:
    case VMT_nTfCnV:
    case VMT_fTnCnV:
    case VMT_fTfCnV:
            vcallType    += UScore ( TOK_nearSp );
        break;

    case VMT_nTnCfV:
    case VMT_nTfCfV:
    case VMT_fTnCfV:
    case VMT_fTfCfV:
            vcallType    += UScore ( TOK_farSp );
        break;

    case VMT_nTfCbV:
    case VMT_fTnCbV:
    case VMT_fTfCbV:
    case VMT_nTnCbV:
            vcallType    += getBasedType ();
        break;

    }    // End of SWITCH    

    //    Always append 'vfptr'

    vcallType    += "vfptr}";

    //    And return the resultant 'vcall-model-type'

    return    vcallType;
#endif

}    // End of "UnDecorator" FUNCTION "getVCallThunk"


inline    DName    UnDecorator::getVfTableType ( const DName & superType )
{
    DName    vxTableName    = superType;


    if    ( vxTableName.isValid () && *gName )
    {
        vxTableName    = getStorageConvention () + ' ' + vxTableName;

        if    ( vxTableName.isValid ())
        {
            if    ( *gName != '@' )
            {
                vxTableName    += "{for ";

                while    ( vxTableName.isValid () && *gName && ( *gName != '@' ))
                {
                    vxTableName    += '`' + getScope () + '\'';

                    //    Skip the scope delimiter

                    if    ( *gName == '@' )
                        gName++;

                    //    Close the current scope, and add a conjunction for the next (if any)

                    if    ( vxTableName.isValid () && ( *gName != '@' ))
                        vxTableName    += "s ";

                }    // End of WHILE

                if    ( vxTableName.isValid ())
                {
                    if    ( !*gName )
                        vxTableName    += DN_truncated;

                    vxTableName    += '}';

                }    // End of IF
            }    // End of IF

            //    Skip the 'vpath-name' terminator

            if    ( *gName == '@' )
                gName++;

        }    // End of IF
    }    // End of IF then
    elif    ( vxTableName.isValid ())
        vxTableName    = DN_truncated + vxTableName;

    return    vxTableName;

}    //    End of "UnDecorator" FUNCTION "getVfTableType"


inline    DName    UnDecorator::getVdispMapType ( const DName & superType )
{
    DName    vdispMapName    = superType;
    vdispMapName += "{for ";
    vdispMapName += getScope();
    vdispMapName += '}';

    if    ( *gName == '@' )
        gName++;
    return vdispMapName;
}
#endif    // !NO_COMPILER_NAMES


inline    DName    UnDecorator::getExternalDataType ( const DName & superType )
{
    //    Create an indirect declarator for the the rest

    DName *    pDeclarator    = gnew DName ();
    DName    declaration    = getDataType ( pDeclarator );


    //    Now insert the declarator into the declaration along with its 'storage-convention'

    *pDeclarator    = getStorageConvention () + ' ' + superType;

    return    declaration;

}    //    End of "UnDecorator" FUNCTION "getExternalDataType"

inline    int            UnDecorator::doUnderScore ()                {    return    !( disableFlags & UNDNAME_NO_LEADING_UNDERSCORES );    }
inline    int            UnDecorator::doMSKeywords ()                {    return    !( disableFlags & UNDNAME_NO_MS_KEYWORDS );            }
inline    int            UnDecorator::doPtr64 ()                        {    return    !( disableFlags & UNDNAME_NO_PTR64 );                }
inline    int            UnDecorator::doFunctionReturns ()            {    return    !( disableFlags & UNDNAME_NO_FUNCTION_RETURNS );    }
inline    int            UnDecorator::doAllocationModel ()            {    return    !( disableFlags & UNDNAME_NO_ALLOCATION_MODEL );    }
inline    int            UnDecorator::doAllocationLanguage ()        {    return    !( disableFlags & UNDNAME_NO_ALLOCATION_LANGUAGE );    }

#if    0
inline    int            UnDecorator::doMSThisType ()                {    return    !( disableFlags & UNDNAME_NO_MS_THISTYPE );            }
inline    int            UnDecorator::doCVThisType ()                {    return    !( disableFlags & UNDNAME_NO_CV_THISTYPE );            }
#endif

inline    int            UnDecorator::doThisTypes ()                    {    return    (( disableFlags & UNDNAME_NO_THISTYPE ) != UNDNAME_NO_THISTYPE );    }
inline    int            UnDecorator::doAccessSpecifiers ()            {    return    !( disableFlags & UNDNAME_NO_ACCESS_SPECIFIERS );    }
inline    int            UnDecorator::doThrowTypes ()                {    return    !( disableFlags & UNDNAME_NO_THROW_SIGNATURES );    }
inline    int            UnDecorator::doMemberTypes ()                {    return    !( disableFlags & UNDNAME_NO_MEMBER_TYPE );            }
inline    int            UnDecorator::doReturnUDTModel ()            {    return    !( disableFlags & UNDNAME_NO_RETURN_UDT_MODEL );    }

inline    int            UnDecorator::do32BitNear ()                    {    return    !( disableFlags & UNDNAME_32_BIT_DECODE );            }

inline    int            UnDecorator::doNameOnly ()                    {    return    ( disableFlags & UNDNAME_NAME_ONLY );                }
inline    int            UnDecorator::doTypeOnly ()                    {    return    ( disableFlags & UNDNAME_TYPE_ONLY );                }
inline    int            UnDecorator::haveTemplateParameters ()        {    return    ( disableFlags & UNDNAME_HAVE_PARAMETERS);            }
inline    int         UnDecorator::doEcsu ()                        {    return    !( disableFlags & UNDNAME_NO_ECSU );                }
inline    int         UnDecorator::doNoIdentCharCheck ()            {    return    ( disableFlags & UNDNAME_NO_IDENT_CHAR_CHECK );        }
inline    int            UnDecorator::doEllipsis ()                    {    return    !(disableFlags & UNDNAME_NO_ELLIPSIS);                }


pcchar_t    UnDecorator::UScore ( Tokens tok  )
{
#if !VERS_32BIT
    if        ((( tok == TOK_nearSp ) || ( tok == TOK_nearP )) && !do32BitNear ())
        return    tokenTable[ tok ] + 6;    // Skip '__near'
#endif
    if        ( doUnderScore ())
        return    tokenTable[ tok ];
    else
        return    tokenTable[ tok ] + 2 ;

}    // End of "UnDecorator" FUNCTION "UScore"


//    Include the string composition support classes.  Mostly inline stuff, and
//    not important to the algorithm.

#include    "undname.inl"
