Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4211 lines
106 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
undecsym.cxx
Abstract:
This is the engine for the C++ name undecorator.
Syntax for Decorated Names
cv-decorated-name ::=
'?' '@' <decorated-name>
decorated-name ::=
'?' <symbol-name> [ <scope> ] '@' <type-encoding>
symbol-name ::=
<zname>
<operator-name>
zname ::=
<letter> [ { <letter> | <number> } ] '@'
<zname-replicator>
letter ::=
{ 'A'..'Z' | 'a'..'z' | '_' | '$' }
number ::=
{ '0'..'9' }
zname-replicator ::=
'0'..'9' Corresponding to the first through
tenth 'zname' to have appeared
The 'zname-replicator' is a compression facility for decorated names.
Anywhere a 'zname' is expected, a single digit replicator may be used.
The digits are '0' through '9' and correspond to the first through tenth unique
'zname's which occur in the decorated name prior to the use of the replicator.
operator-name ::=
'?' <operator-code>
scope ::=
<zname> [ <scope> ]
'?' <decorated-name> [ < scope > ]
'?' <lexical-frame> [ <scope> ]
'?' '$' <template-name> [ <scope> ]
The 'scope' is ordered sequentially as a function of lexical scope, with successive enclosing
scopes appearing to the right of the enclosed scopes. Thus, the innermost scope is always placed
first, followed by each successive enclosing scope.
operator-code ::=
'0' Constructor
'1' Destructor
'2' 'new'
'3' 'delete'
'4' '=' Assignment
'5' '>>' Right shift
'6' '<<' Left shift
'7' '!' Boolean NOT
'8' '==' Equality
'9' '!=' Inequality
'A' '[]' Indexing
'B' User Defined Conversion
'C' '->' Member selection indirect
'D' '*' Dereference or multiply
'E' '++' Pre/Post-increment
'F' '--' Pre/Post-decrement
'G' '-' Two's complement negate, or subtract
'H' '+' Unary plus, or add
'I' '&' Address of, or bitwise AND
'J' '->*' Pointer to member selection
'K' '/' Divide
'L' '%' Modulo
'M' '<' Less than
'N' '<=' Less than or equal to
'O' '>' Greater than
'P' '>=' Greater than or equal to
'Q' ',' Sequence
'R' '()' Function call
'S' '~' Bitwise NOT
'T' '^' Bitwise XOR
'U' '|' Bitwise OR
'V' '&&' Boolean AND
'W' '||' Boolean OR
'X' '*=' Multiply and assign
'Y' '+=' Add and assign
'Z' '-=' Subtract and assign
'_0' '/=' Divide and assign
'_1' '%=' Modulo and assign
'_2' '>>=' Right shift and assign
'_3' '<<=' Left shift and assign
'_4' '&=' Bitwise AND and assign
'_5' '|=' Bitwise OR and assign
'_6' '^=' Bitwise XOR and assign
'_7' VTable
'_8' VBase
'_9' VCall Thunk
'_A' Metaclass
'_B' Guard variable for local statics
'_C' Ultimate Constructor for Vbases
'_D' Ultimate Destructor for Vbases
'_E' Vector Deleting Destructor
'_F' Default Constructor Closure
'_G' Scalar Deleting Destructor
'_H' Vector Constructor Iterator
'_I' Vector Destructor Iterator
'_J' Vector Allocating Constructor
type-encoding ::=
Member Functions
'A' <member-function-type> private near
'B' <member-function-type> private far
'C' <static-member-function-type> private near
'D' <static-member-function-type> private far
'G' <adjustor-thunk-type> private near
'H' <adjustor-thunk-type> private far
'I' <member-function-type> protected near
'J' <member-function-type> protected far
'K' <static-member-function-type> protected near
'L' <static-member-function-type> protected far
'O' <adjustor-thunk-type> protected near
'P' <adjustor-thunk-type> protected far
'Q' <member-function-type> public near
'R' <member-function-type> public far
'S' <static-member-function-type> public near
'T' <static-member-function-type> public far
'W' <adjustor-thunk-type> public near
'X' <adjustor-thunk-type> public far
'$0' <virtual-adjustor-thunk-type> private near
'$1' <virtual-adjustor-thunk-type> private far
'$2' <virtual-adjustor-thunk-type> protected near
'$3' <virtual-adjustor-thunk-type> protected far
'$4' <virtual-adjustor-thunk-type> public near
'$5' <virtual-adjustor-thunk-type> public far
Virtual Member Functions
'E' <member-function-type> private near
'F' <member-function-type> private far
'M' <member-function-type> protected near
'N' <member-function-type> protected far
'U' <member-function-type> public near
'V' <member-function-type> public far
Non-Member Functions
'Y' <external-function-type> near
'Z' <external-function-type> far
'$A' <local-static-data-destructor-type>
'$B' <vcall-thunk-type>
Non-Functions
'0' <static-member-data-type> private
'1' <static-member-data-type> protected
'2' <static-member-data-type> public
'3' <external-data-type>
'4' <local-static-data-type>
'5' <local-static-data-guard-type>
'6' <vtable-type>
'7' <vbase-type>
'8' <metaclass-type>
Based variants of the above
Member Functions
'_A' <based-member-function-type> private near
'_B' <based-member-function-type> private far
'_C' <based-static-member-function-type> private near
'_D' <based-static-member-function-type> private far
'_G' <based-adjustor-thunk-type> private near
'_H' <based-adjustor-thunk-type> private far
'_I' <based-member-function-type> protected near
'_J' <based-member-function-type> protected far
'_K' <based-static-member-function-type> protected near
'_L' <based-static-member-function-type> protected far
'_O' <based-adjustor-thunk-type> protected near
'_P' <based-adjustor-thunk-type> protected far
'_Q' <based-member-function-type> public near
'_R' <based-member-function-type> public far
'_S' <based-static-member-function-type> public near
'_T' <based-static-member-function-type> public far
'_W' <based-adjustor-thunk-type> public near
'_X' <based-adjustor-thunk-type> public far
'_$0' <based-virtual-adjustor-thunk-type> private near
'_$1' <based-virtual-adjustor-thunk-type> private far
'_$2' <based-virtual-adjustor-thunk-type> protected near
'_$3' <based-virtual-adjustor-thunk-type> protected far
'_$4' <based-virtual-adjustor-thunk-type> public near
'_$5' <based-virtual-adjustor-thunk-type> public far
Virtual Member Functions
'_E' <based-member-function-type> private near
'_F' <based-member-function-type> private far
'_M' <based-member-function-type> protected near
'_N' <based-member-function-type> protected far
'_U' <based-member-function-type> public near
'_V' <based-member-function-type> public far
Non-Member Functions
'_Y' <based-external-function-type> near
'_Z' <based-external-function-type> far
'_$B' <based-vcall-thunk-type>
external-function-type ::=
<function-type>
based-external-function-type ::=
<based-type><external-function-type>
external-data-type ::=
<data-type><storage-convention>
member-function-type ::=
<this-type><static-member-function-type>
based-member-function-type ::=
<based-type><member-function-type>
static-member-function-type ::=
<function-type>
based-static-member-function-type ::=
<based-type><static-member-function-type>
static-member-data-type ::=
<external-data-type>
local-static-data-type ::=
<lexical-frame><external-data-type>
local-static-data-guard-type ::=
<guard-number>
local-static-data-destructor-type ::=
<calling-convention><local-static-data-type>
vtable-type ::=
<storage-convention> [ <vpath-name> ] '@'
vbase-type ::=
<storage-convention> [ <vpath-name> ] '@'
metaclass-type ::=
<storage-convention>
adjustor-thunk-type ::=
<displacement><member-function-type>
based-adjustor-thunk-type ::=
<based-type><adjustor-thunk-type>
virtual-adjustor-thunk-type ::=
<displacement><adjustor-thunk-type>
based-virtual-adjustor-thunk-type ::=
<based-type><virtual-adjustor-thunk-type>
vcall-thunk-type ::=
<call-index><vcall-model-type>
based-vcall-thunk-type ::=
<based-type><vcall-thunk-type>
function-type ::=
<calling-convention><return-type><argument-types>
<throw-types>
segment-name ::=
<zname>
ecsu-name ::=
<zname> [ <scope> ] '@'
'?' <template-name> [ <scope> ] '@'
return-type ::=
'@' No type, for Ctor's and Dtor's
<data-type>
data-type ::=
<primary-data-type>
'X' 'void'
'?' <ecsu-data-indirect-type><ecsu-data-type>
storage-convention ::=
<data-indirect-type>
this-type ::=
<data-indirect-type>
lexical-frame ::=
<dimension>
displacement ::=
<dimension>
call-index ::=
<dimension>
guard-number ::=
<dimension>
vcall-model-type ::=
'A' near this, near call, near vfptr
'B' near this, far call, near vfptr
'C' far this, near call, near vfptr
'D' far this, far call, near vfptr
'E' near this, near call, far vfptr
'F' near this, far call, far vfptr
'G' far this, near call, far vfptr
'H' far this, far call, far vfptr
'I' <based-type> near this, near call, based vfptr
'JK' <based-type> near this, far call, based vfptr
'KJ' <based-type> far this, near call, based vfptr
'L' <based-type> far this, far call, based vfptr
throw-types ::=
<argument-types>
template-name ::=
<zname><argument-list>
calling-convention ::=
'A' cdecl
'B' cdecl saveregs
'C' pascal/fortran/oldcall
'D' pascal/fortran/oldcall saveregs
'E' syscall
'F' syscall saveregs
'G' stdcall
'H' stdcall saveregs
'I' fastcall
'J' fastcall saveregs
'K' interrupt
argument-types ::=
'Z' (...)
'X' (void)
<argument-list> 'Z' (arglist,...)
<argument-list> '@' (arglist)
argument-list ::=
<argument-replicator> [ <argument-list> ]
<primary-data-type> [ <argument-list> ]
argument-replicator ::=
'0'..'9' Corresponding to the first through tenth
argument of more than one character type
encoding.
The 'argument-replicator' like the 'zname-replicator' is used to improve the compression of
information present in decorated names. In this case however, the 'replicator' allows a single
digit to be used where an argument type is expected, and to refer to the first through tenth unique
'argument-type' seen prior to this one. This replicator refers to ANY argument type seen before,
even if it was introduced in the recursively generated name for an argument which itself was a
pointer or reference to a function. An 'argument-replicator' is used only when the argument encoding
exceeds one character, otherwise it would represent no actual compression.
primary-data-type ::=
'A' <reference-type> Reference to
'B' <reference-type> Volatile reference to
<basic-data-type> Other types
reference-type ::=
<data-indirect-type><reference-data-type>
<function-indirect-type><function-type>
pointer-type ::=
<data-indirect-type><pointer-data-type>
<function-indirect-type><function-type>
vpath-name ::=
<scope> '@' [ <vpath-name> ]
ecsu-data-indirect-type ::=
'A' near
'B' near const
'C' near volatile
'D' near const volatile
'E' far
'F' far const
'G' far volatile
'H' far const volatile
'I' huge
'J' huge const
'K' huge volatile
'L' huge const volatile
'M' <based-type> based
'N' <based-type> based const
'O' <based-type> based volatile
'P' <based-type> based const volatile
data-indirect-type ::=
<ecsu-data-indirect-type>
'Q' <scope> '@' member near
'R' <scope> '@' member near const
'S' <scope> '@' member near volatile
'T' <scope> '@' member near const volatile
'U' <scope> '@' member far
'V' <scope> '@' member far const
'W' <scope> '@' member far volatile
'X' <scope> '@' member far const volatile
'Y' <scope> '@' member huge
'Z' <scope> '@' member huge const
'0' <scope> '@' member huge volatile
'1' <scope> '@' member huge const volatile
'2' <scope> '@' <based-type> member based
'3' <scope> '@' <based-type> member based const
'4' <scope> '@' <based-type> member based volatile
'5' <scope> '@' <based-type> member based const volatile
function-indirect-type ::=
'6' near
'7' far
'8' <scope> '@' <this-type> member near
'9' <scope> '@' <this-type> member far
'_A' <based-type> based near
'_B' <based-type> based far
'_C' <scope> '@' <this-type><based-type> based member
near
'_D' <scope> '@' <this-type><based-type> based member
far
based-type ::=
'0' based on void
'1' based on self
'2' based on near pointer
'3' based on far pointer
'4' based on huge pointer
'5' <based-type> based on based pointer (reserved)
'6' based on segment variable
'7' <segment-name> based on named segment
'8' based on segment address of var
'9' reserved
basic-data-type ::=
'C' signed char
'D' char
'E' unsigned char
'F' (signed) short
'G' unsigned short
'H' (signed) int
'I' unsigned int
'J' (signed) long
'K' unsigned long
'L' __segment
'M' float
'N' double
'O' long double
'P' <pointer-type> pointer to
'Q' <pointer-type> const pointer to
'R' <pointer-type> volatile pointer to
'S' <pointer-type> const volatile pointer to
<ecsu-data-type>
'_A' (signed) __int64
'_B' unsigned __int64
ecsu-data-type ::=
'T' <ecsu-name> union
'U' <ecsu-name> struct
'V' <ecsu-name> class
'W' <enum-name> enum
pointer-data-type ::=
'X' void
<reference-data-type>
reference-data-type ::=
'Y' <array-type> array of
<basic-data-type>
enum-name ::=
<enum-type><ecsu-name>
enum-type ::=
'0' signed char enum
'1' unsigned char enum
'2' signed short enum
'3' unsigned short enum
'4' signed int enum
'5' unsigned int enum
'6' signed long enum
'7' unsigned long enum
array-type ::=
<number-of-dimensions> { <dimension> } <basic-data-type>
number-of-dimensions ::=
<dimension>
dimension ::=
'0'..'9' Corresponding to 1 to 10 dimensions
<adjusted-hex-digit> [ { <adjusted-hex-digit> } ] '@'
adjusted-hex-digit ::=
'A'..'P' Corresponding to values 0x0 to 0xF
Author:
Wesley Witt (wesw) 09-June-1993 ( this code came from languages, i just ported it )
Revision History:
--*/
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern "C" {
#define _IMAGEHLP_SOURCE_
#include <imagehlp.h>
#include "private.h"
LONGLONG UndecTime;
}
#pragma inline_depth ( 3 )
#include "undecsym.hxx"
extern "C" VOID FixAlign( DWORD );
#ifdef _ALPHA_
#define THREAD_LS
#else
#define THREAD_LS __declspec(thread)
#endif
static HeapManager *heap;
static pcchar_t tokenTable[] =
{
" ", // TOK_near
" ", // TOK_nearSp
"*", // TOK_nearP
" ", // TOK_far
" ", // TOK_farSp
"*", // TOK_farP
"__huge", // TOK_huge
"__huge ", // TOK_hugeSp
"__huge*", // TOK_hugeP
"__based(", // TOK_basedLp
" ", // TOK_cdecl
" ", // TOK_pascal
"__stdcall", // TOK_stdcall
"__thiscall", // TOK_thiscall
"__fastcall", // TOK_fastcall
"__interrupt", // TOK_interrupt
"__saveregs", // TOK_saveregs
"__self", // TOK_self
"__segment", // TOK_segment
"__segname(\"" // TOK_segnameLpQ
};
// The operator mapping table
static pcchar_t nameTable[] =
{
" new",
" delete",
"=",
">>",
"<<",
"!",
"==",
"!=",
"[]",
"operator",
"->",
"*",
"++",
"--",
"-",
"+",
"&",
"->*",
"/",
"%",
"<",
"<=",
">",
">=",
",",
"()",
"~",
"^",
"|",
"&&",
"||",
"*=",
"+=",
"-=",
"/=",
"%=",
">>=",
"<<=",
"&=",
"|=",
"^=",
"`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'"
};
void *
operator new( unsigned int sz, HeapManager *heap )
{
return heap->getMemory( sz );
}
inline
HeapManager::HeapManager( )
{
blockLeft = 0;
head = 0;
tail = 0;
}
inline
HeapManager::~HeapManager( )
{
while( tail = head ) {
head = tail->next;
MemFree( tail->memory );
MemFree( tail );
}
}
void *
HeapManager::getMemory ( unsigned int sz )
{
// Handler a potential request for no space
if (sz == 0) {
sz = 1;
}
// Allocate a new block
Block * pNewBlock = (Block *) MemAlloc( sizeof(Block) );
// Did the allocation succeed ? If so connect it up
if (pNewBlock) {
// Handle the initial state
if (tail) {
tail = tail->next = pNewBlock;
}
else {
head = tail = pNewBlock;
}
tail->next = NULL;
tail->memory = MemAlloc( sz );
}
else {
// Oh-oh! Memory allocation failure
return NULL;
}
// And return the buffer address
return tail->memory;
}
inline
UnDecorator::UnDecorator( pchar_t output,
pcchar_t dName,
DWORD maxLen,
DWORD disable
)
{
name = dName;
gName = name;
maxStringLength = maxLen;
outputString = output;
disableFlags = disable;
pArgList = &ArgList;
pZNameList = &ZNameList;
pTemplateArgList = &TemplateArgList;
}
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 ] == '@' )) {
gName += 2;
result = "CV: " + getDecoratedName ();
}
else if (( *name == '?' ) && ( name[1] == '$' )) {
result = getTemplateName ();
}
else {
result = getDecoratedName ();
}
}
if ((result.status() == DN_error) ||
(result.status() == DN_invalid) ||
(*gName && !doNameOnly())) {
unDName = name;
if (!outputString) {
maxStringLength = unDName.length () + 1;
outputString = new(heap) char[ maxStringLength ];
}
outputString[0] = '\0';
} else {
unDName = result;
if (!outputString) {
maxStringLength = unDName.length () + 1;
outputString = new(heap) char[ maxStringLength ];
}
unDName.getString( outputString, maxStringLength );
}
return outputString;
}
DName
UnDecorator::getDecoratedName ( void )
{
// Ensure that it is intended to be a decorated name
if ( *gName == '?' ) {
// Extract the basic symbol name
gName++; // Advance the original name pointer
DName symbolName = getSymbolName();
int udcSeen = symbolName.isUDC();
if ((!doSpecial()) && symbolName.isSpecial()) {
return DN_invalid;
}
// Abort if the symbol name is invalid
if (!symbolName.isValid ()) {
return symbolName;
}
// Extract, and prefix the scope qualifiers
if ( *gName && ( *gName != '@' )) {
symbolName = getScope() + "::" + symbolName;
}
if ( udcSeen ) {
symbolName.setIsUDC();
}
// Now compose declaration
if (symbolName.isEmpty () || doNameOnly () ) {
return symbolName;
}
else
if (!*gName || ( *gName == '@' )) {
if ( *gName ) {
gName++;
}
return composeDeclaration( symbolName );
}
else {
return DN_invalid;
}
}
else
if ( *gName ) {
return DN_invalid;
}
else {
return DN_truncated;
}
}
inline DName
UnDecorator::getSymbolName ( void )
{
if ( *gName == '?' ) {
gName++;
return getOperatorName();
}
return getZName();
}
DName
UnDecorator::getZName ( void )
{
int zNameIndex = *gName - '0';
// Handle 'zname-replicators', otherwise an actual name
if (( zNameIndex >= 0 ) && ( zNameIndex <= 9 )) {
gName++; // Skip past the replicator
return ( *pZNameList )[ zNameIndex ];
}
else {
// Extract the 'zname' to the terminator
DName zName ( gName, '@' ); // This constructor updates 'name'
// Add it to the current list of 'zname's
if (!pZNameList->isFull ()) {
*pZNameList += zName;
}
return zName;
}
}
inline DName
UnDecorator::getOperatorName ( void )
{
DName operatorName;
int udcSeen = FALSE;
// 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
{
// Use a temporary. Don't want to advance the name pointer
pcchar_t pName = gName;
operatorName = getZName ();
gName = pName;
if (!operatorName.isEmpty () && ( gName[ -1 ] == OC_dtor )) {
operatorName = '~' + operatorName;
}
return operatorName;
}
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;
// fall thru
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;
case OC_vftable:
case OC_vbtable:
case OC_vcall:
operatorName = nameTable[ gName[ -1 ] - OC_asdiv + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )];
operatorName.setIsSpecial();
return operatorName;
case OC_metatype:
case OC_guard:
case OC_uctor:
case OC_udtor:
case OC_vdeldtor:
case OC_defctor:
case OC_sdeldtor:
case OC_vctor:
case OC_vdtor:
case OC_vallctor:
// Special purpose names
operatorName = nameTable[ gName[ -1 ] - OC_metatype + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )];
operatorName.setIsSpecial();
return operatorName;
default:
return DN_invalid;
}
break;
default:
return DN_invalid;
}
// This really is an operator name, so prefix it with 'operator'
if ( udcSeen ) {
operatorName.setIsUDC();
}
else
if (!operatorName.isEmpty ()) {
operatorName = "operator" + operatorName;
}
return operatorName;
}
DName
UnDecorator::getScope ( void )
{
DName scope;
// Get the list of scopes
while ((scope.status () == DN_valid ) && *gName && ( *gName != '@' )) {
// Insert the scope operator if not the first scope
if ( !scope.isEmpty() ) {
scope = "::" + scope;
}
// Determine what kind of scope it is
if ( *gName == '?' ) {
switch ( *++gName ) {
case '?':
if (!doNameOnly()) {
scope = '`' + getDecoratedName () + '\'' + scope;
} else {
getDecoratedName(); // Skip lexical scope info
}
break;
case '$':
// It's a templace name, which is a kind of zname; back up
// and handle like a zname.
gName--;
scope = getZName () + scope;
break;
default:
if (!doNameOnly()) {
scope = getLexicalFrame () + scope;
} else {
getLexicalFrame(); // Skip lexical scope info
}
break;
}
}
else {
scope = getZName() + scope;
}
}
// 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;
}
return scope;
}
DName
UnDecorator::getSignedDimension ( void )
{
if ( !*gName )
return DN_truncated;
else
if ( *gName == '?' )
return '-' + getDimension();
else
return getDimension();
}
DName
UnDecorator::getDimension ( void )
{
if ( !*gName ) {
return DN_truncated;
}
else
if (( *gName >= '0' ) && ( *gName <= '9' )) {
return DName ((unsigned long)( *gName++ - '0' + 1 ));
}
else {
unsigned long dim = 0L;
// Don't bother detecting overflow, it's not worth it
while ( *gName != '@' ) {
if ( !*gName ) {
return DN_truncated;
}
else
if (( *gName >= 'A' ) && ( *gName <= 'P' )) {
dim = ( dim << 4 ) + ( *gName - 'A' );
}
else {
return DN_invalid;
}
gName++;
}
// Ensure integrity, and return
if ( *gName++ != '@' ) {
return DN_invalid; // Should never get here
}
return dim;
}
}
int
UnDecorator::getNumberOfDimensions ( void )
{
if ( !*gName ) {
return 0;
}
else
if (( *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;
}
else
if (( *gName >= 'A' ) && ( *gName <= 'P' )) {
dim = ( dim << 4 ) + ( *gName - 'A' );
}
else {
return -1;
}
gName++;
}
// Ensure integrity, and return
if ( *gName++ != '@' ) {
return -1; // Should never get here
}
return dim;
}
}
DName
UnDecorator::getTemplateName ( void )
{
// 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 = getZName ();
if ( !templateName.isEmpty ())
templateName += '<' + getTemplateArgumentList () + '>';
// Restore the previous replicators:
pArgList = pSaveArgList;
pZNameList = pSaveZNameList;
pTemplateArgList = pSaveTemplateArgList;
// Return the completed 'template-name'
return templateName;
}
DName
UnDecorator::getTemplateArgumentList ( void )
{
int first = TRUE;
DName aList;
if ( *gName == AT_void ) {
// If first argument is void, there ain't no more
gName++; // Skip this character
aList = "void";
} else {
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 ];
} else {
pcchar_t oldGName = gName;
// Extract the 'argument' type
DName arg = (*gName == '$') ?
gName++, getTemplateConstant()
: 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;
}
}
}
// Return the completed template argument list
return aList;
}
DName
UnDecorator::getTemplateConstant(void)
{
// template-constant ::=
// '0' <template-integral-constant>
// '1' <template-address-constant>
// '2' <template-floating-point-constant>
switch ( *gName++ ) {
// template-integral-constant ::=
// <signed-dimension>
case TC_integral:
return getSignedDimension ();
// template-address-constant ::=
// '@' // Null pointer
// <decorated-name>
case TC_address:
if ( *gName == TC_nullptr )
return "NULL";
else
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;
}
else
return DN_truncated;
}
case '\0':
--gName;
return DN_truncated;
default:
return DN_invalid;
}
}
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;
}
else
if ( TE_istruncated ( typeCode )) {
return ( DN_truncated + 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 ( TE_isfunction ( typeCode ) && !( TE_isthunk ( typeCode ) && TE_islocaldtor ( typeCode ))) {
// If it is based, then compose the 'based' prefix for the name
if ( TE_isbased ( typeCode )) {
if (doMSKeywords () && doAllocationModel ()) {
declaration = ' ' + getBasedType ();
}
else {
// Just lose the 'based-type'
declaration |= getBasedType ();
}
}
// Check for some of the specially composed 'thunk's
if ( TE_isthunk ( typeCode ) && TE_isvcall ( typeCode )) {
declaration += symbol + '{' + getCallIndex () + ',';
declaration += getVCallThunkType () + "}' ";
}
else {
DName vtorDisp;
DName adjustment;
DName thisType;
if ( TE_isthunk ( typeCode )) {
if ( TE_isvtoradj ( typeCode )) {
vtorDisp = getDisplacement ();
}
adjustment = getDisplacement ();
}
// 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 ()) {
// What calling convention ?
declaration = getCallingConvention () + declaration;
}
else {
// Just lose the 'calling-convention'
declaration |= getCallingConvention ();
}
// Any model specifiers ?
if (doAllocationModel ()) {
if ( TE_isnear ( typeCode )) {
declaration = UScore ( TOK_nearSp ) + declaration;
}
else
if ( TE_isfar ( typeCode )) {
declaration = UScore ( TOK_farSp ) + declaration;
}
}
}
else {
// Just lose the 'calling-convention'
declaration |= getCallingConvention ();
}
// Now put them all together
if ( !symbol.isEmpty ()) {
// And the symbol name
if ( !declaration.isEmpty ()) {
declaration += ' ' + symbol;
}
else {
declaration = symbol;
}
}
// Compose the return type, catching the UDC case
DName * pDeclarator = 0;
DName returnType;
// Is the symbol a UDC operator ?
if ( symIsUDC ) {
declaration += "`" + getReturnType () + "' ";
}
else {
pDeclarator = new(heap) DName;
returnType = getReturnType ( pDeclarator );
}
// Add the displacements for virtual function thunks
if ( TE_isthunk ( typeCode )) {
if ( TE_isvtoradj ( typeCode )) {
declaration += "`vtordisp{" + vtorDisp + ',';
}
else {
declaration += "`adjustor{";
}
declaration += adjustment + "}' ";
}
// Add the function argument prototype
if ( doArguments() ) {
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 {
// Just lose the 'throw-types'
declaration |= getThrowTypes ();
}
// If it has a declarator, then insert it into the declaration,
// sensitive to the return type composition
if ( doFunctionReturns () && pDeclarator ) {
*pDeclarator = declaration;
declaration = returnType;
}
}
}
else {
declaration += symbol;
// Catch the special handling cases
if (TE_isvftable ( typeCode )) {
return getVfTableType ( declaration );
}
else
if (TE_isvbtable ( typeCode )) {
return getVbTableType ( declaration );
}
else
if (TE_isguard ( typeCode )) {
return ( declaration + '{' + getGuardNumber () + "}'" );
}
else
if (TE_isthunk ( typeCode ) && TE_islocaldtor ( typeCode )) {
declaration += "`local static destructor helper'";
}
else
if (TE_ismetaclass ( typeCode )) {
// #pragma message ( "NYI: Meta Class" )
return DN_invalid;
}
// All others are decorated as data symbols
declaration = getExternalDataType ( declaration );
}
// 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_isadjustor ( typeCode )))) {
declaration = "virtual " + declaration;
}
}
// Prepend the access specifiers
if (doAccessSpecifiers ()) {
if (TE_isprivate ( typeCode ))
declaration = "private: " + declaration;
else
if ( TE_isprotected ( typeCode ))
declaration = "protected: " + declaration;
else
if ( TE_ispublic ( typeCode ))
declaration = "public: " + declaration;
}
}
// If it is a thunk, mark it appropriately
if ( TE_isthunk ( typeCode ))
declaration = "[thunk]:" + declaration;
return declaration;
}
inline int
UnDecorator::getTypeEncoding ( void )
{
unsigned int typeCode = 0;
// Strip any leading '_' which indicates that it is based
if ( *gName == '_' ) {
TE_setisbased ( typeCode );
gName++;
}
// 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;
}
// 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;
}
}
}
else
// Extended set ? Special handling
if ( *gName == '$' ) {
// What type of symbol is it ?
switch (*(++gName)) {
case 'A': // A destructor helper for a local static ?
TE_setislocaldtor ( typeCode );
break;
case 'B': // A VCall-thunk ?
TE_setisvcall ( typeCode );
break;
case 0:
TE_setistruncated ( typeCode );
break;
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 );
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;
}
}
break;
default:
TE_setisbadtype ( typeCode );
return typeCode;
}
// Advance past the code character
gName++;
}
else
// Non function decorations ?
if (( *gName >= TE_static_d ) && ( *gName <= TE_metatype )) {
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:
// #pragma message ( "NYI: MetaClass Information" )
default:
TE_setisbadtype ( typeCode );
return typeCode;
}
}
else
if ( *gName ) {
TE_setisbadtype ( typeCode );
}
else {
TE_setistruncated ( typeCode );
}
return typeCode;
}
DName
UnDecorator::getBasedType ( void )
{
DName basedDecl ( UScore ( TOK_basedLp ));
// What type of 'based' is it ?
if ( *gName ) {
switch ( *gName++ ) {
case BT_segname:
basedDecl += UScore ( TOK_segnameLpQ ) + getSegmentName () + "\")";
break;
case BT_segment:
basedDecl += DName ( "NYI:" ) + UScore ( TOK_segment );
break;
case BT_void:
basedDecl += "void";
break;
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;
case BT_basedptr:
// #pragma message ( "NOTE: Reserved. Based pointer to based pointer" )
return DN_invalid;
}
}
else {
basedDecl += DN_truncated;
}
// Close the based syntax
basedDecl += ") ";
return basedDecl;
}
DName
UnDecorator::getECSUName ( void )
{
DName ecsuName;
// Get the beginning of the name
ecsuName = getZName ();
// Now the scope (if any)
if (( ecsuName.status () == DN_valid ) && *gName && ( *gName != '@' )) {
ecsuName = getScope () + "::" + ecsuName;
}
// Skip the trailing '@'
if ( *gName == '@' ) {
gName++;
}
else
if ( *gName )
ecsuName = DN_invalid;
else
if (ecsuName.isEmpty ()) {
ecsuName = DN_truncated;
}
else {
ecsuName = DName ( DN_truncated ) + "::" + ecsuName;
}
// And return the complete name
return ecsuName;
}
inline DName
UnDecorator::getEnumName ( 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;
}
// Add the 'unsigned'ness if appropriate
switch ( *gName++ ) {
case ET_uchar:
case ET_ushort:
case ET_uint:
case ET_ulong:
ecsuName = "unsigned " + ecsuName;
break;
}
return ecsuName + getECSUName ();
}
else {
return DN_truncated;
}
}
DName
UnDecorator::getCallingConvention ( void )
{
if ( *gName ) {
unsigned int callCode = ((unsigned int)*gName++ ) - 'A';
// What is the primary calling convention
if (( callCode >= CC_cdecl ) && ( callCode <= CC_interrupt )) {
DName callType;
// Now, what type of 'calling-convention' is it, 'interrupt' is special ?
if (doMSKeywords ()) {
if ( callCode == CC_interrupt ) {
callType = UScore ( TOK_interrupt );
}
else {
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;
}
// Has it also got 'saveregs' marked ?
if ( callCode & CC_saveregs ) {
callType += ' ' + UScore ( TOK_saveregs );
}
}
}
return callType;
}
else {
return DN_invalid;
}
}
else {
return DN_truncated;
}
}
DName
UnDecorator::getReturnType ( DName * pDeclarator )
{
// Return type for constructors and destructors ?
if ( *gName == '@' ) {
gName++;
return DName ( pDeclarator );
}
else {
return getDataType ( pDeclarator );
}
}
DName
UnDecorator::getDataType ( DName * pDeclarator )
{
DName superType ( pDeclarator );
// What type is it ?
switch ( *gName ) {
case 0:
return ( DN_truncated + superType );
case DT_void:
gName++;
if (superType.isEmpty ()) {
return "void";
}
else {
return "void " + superType;
}
case '?':
{
int ecsuMods;
gName++; // Skip the '?'
ecsuMods = getECSUDataIndirectType ();
superType = getECSUDataType ( ecsuMods ) + ' ' + superType;
return superType;
}
default:
return getPrimaryDataType ( superType );
}
}
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 super ( superType );
gName++;
return getReferenceType ( cvType, super.setPtrRef ());
}
default:
return getBasicDataType ( superType );
}
}
DName
UnDecorator::getArgumentTypes ( void )
{
switch ( *gName ) {
case AT_ellipsis:
return ( gName++, "..." );
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 + ",..." );
case AT_endoflist:
return ( gName++, arguments );
default:
return DN_invalid;
}
}
else {
return arguments;
}
}
}
}
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 )) {
// Skip past the replicator
gName++;
// Append to the argument list
aList += ( *pArgList )[ argIndex ];
}
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;
}
}
else {
aList += DN_truncated;
break;
}
}
// Return the completed argument list
return aList;
}
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 + ')' );
}
}
DName
UnDecorator::getBasicDataType ( const DName & superType )
{
if ( *gName ) {
unsigned char bdtCode = *gName++;
unsigned char extended_bdtCode;
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;
case BDT_segment:
basicDataType = UScore ( TOK_segment );
break;
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_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 ):
case BDT_sint64:
case BDT_uint64:
basicDataType = "__int64";
break;
case BDT_int128:
case ( BDT_int128 | BDT_unsigned ):
basicDataType = "__int128";
break;
case BDT_wchar_t:
case ( BDT_wchar_t | BDT_unsigned ):
basicDataType = "wchar_t";
break;
}
break;
default:
// Backup, since 'ecsu-data-type' does it's own decoding
gName--;
basicDataType = getECSUDataType ();
if (basicDataType.isEmpty ()) {
return basicDataType;
}
break;
}
// What type of basic data type composition is involved ?
// Simple ?
if ( pCvCode == -1 ) {
// 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 ):
case BDT_uint64:
basicDataType = "unsigned " + basicDataType;
break;
}
break;
}
// Add the indirection type to the type
if (!superType.isEmpty ()) {
basicDataType += ' ' + superType;
}
return basicDataType;
}
else {
DName cvType;
DName super ( superType );
// Is it 'const/volatile' qualified ?
if ( pCvCode & BDT_const ) {
cvType = "const";
if ( pCvCode & BDT_volatile ) {
cvType += " volatile";
}
}
else
if ( pCvCode & BDT_volatile ) {
cvType = "volatile";
}
// Construct the appropriate pointer type declaration
return getPointerType ( cvType, super.setPtrRef ());
}
}
else {
return (DN_truncated + superType );
}
}
DName
UnDecorator::getECSUDataType ( int ecsuMods )
{
DName ecsuDataType;
// Get the 'model' modifiers if applicable
if ( ecsuMods ) {
if ( ecsuMods == ECSU_invalid ) {
return DN_invalid;
}
else
if ( ecsuMods == ECSU_truncated ) {
ecsuDataType = DN_truncated;
}
else {
switch ( ecsuMods & ECSU_modelmask ) {
case ECSU_near:
if ( doMSKeywords () && doReturnUDTModel ()) {
ecsuDataType = UScore ( TOK_nearSp );
}
break;
case ECSU_far:
if ( doMSKeywords () && doReturnUDTModel ()) {
ecsuDataType = UScore ( TOK_farSp );
}
break;
case ECSU_huge:
if ( doMSKeywords () && doReturnUDTModel ()) {
ecsuDataType = UScore ( TOK_hugeSp );
}
break;
case ECSU_based:
if ( doMSKeywords () && doReturnUDTModel ()) {
ecsuDataType = getBasedType ();
}
else {
// Just lose the 'based-type'
ecsuDataType |= getBasedType ();
}
break;
}
}
}
// Extract the principal type information itself, and validate the codes
switch ( *gName++ ) {
case 0:
// Backup to permit later error recovery to work safely
gName--;
return "`unknown ecsu'" + ecsuDataType + DN_truncated;
case BDT_union:
if ( !doNameOnly() ) {
ecsuDataType = "union " + ecsuDataType;
}
break;
case BDT_struct:
if ( !doNameOnly() ) {
ecsuDataType = "struct " + ecsuDataType;
}
break;
case BDT_class:
if ( !doNameOnly() ) {
ecsuDataType = "class " + ecsuDataType;
}
break;
case BDT_enum:
return "enum " + ecsuDataType + getEnumName ();
default:
return DN_invalid;
}
// Get the UDT 'const/volatile' modifiers if applicable
// Get the 'class/struct/union' name
ecsuDataType += getECSUName ();
// And return the formed 'ecsu-data-type'
return ecsuDataType;
}
DName
UnDecorator::getPtrRefType ( const DName & cvType, const DName & superType, int isPtr )
{
// Doubles up as 'pointer-type' and 'reference-type'
if ( *gName ) {
// Is it a function or data indirection ?
if ( IT_isfunction ( *gName )) {
// Since I haven't coded a discrete 'function-type', both
// 'function-indirect-type' and 'function-type' are implemented
// inline under this condition.
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;
}
}
else {
return ( DN_truncated + superType );
}
}
else
if (( 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 = ( isPtr ? '*' : '&' );
if ( !cvType.isEmpty () && ( superType.isEmpty () || superType.isPtrRef ())) {
fitType += cvType;
}
if ( !superType.isEmpty ()) {
fitType += superType;
}
// Is it a pointer to member function ?
if ( fitCode & FIT_member ) {
fitType = "::" + fitType;
if ( *gName ) {
fitType = ' ' + getScope ();
}
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 ();
}
}
// Is it a based allocated function ?
if ( fitCode & FIT_based ) {
if ( doMSKeywords ()) {
fitType = ' ' + getBasedType () + fitType;
}
else {
// Just lose the 'based-type'
fitType |= getBasedType ();
}
}
// Get the 'calling-convention'
if ( doMSKeywords ()) {
fitType = getCallingConvention () + fitType;
// Is it a near or far function pointer
fitType = UScore ((( fitCode & FIT_far ) ? TOK_farSp : TOK_nearSp )) + fitType;
}
else {
// Just lose the 'calling-convention'
fitType |= getCallingConvention ();
}
// Parenthesise the indirection component, and work on the rest
fitType = '(' + fitType + ')';
// Get the rest of the 'function-type' pieces
DName * pDeclarator = new(heap) DName;
DName returnType ( getReturnType ( pDeclarator ));
fitType += '(' + getArgumentTypes () + ')';
if ( doThisTypes () && ( fitCode & FIT_member )) {
fitType += thisType;
}
if ( doThrowTypes ()) {
fitType += getThrowTypes ();
}
else {
// Just lose the 'throw-types'
fitType |= getThrowTypes ();
}
// 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;
}
else {
// Otherwise, it is either a pointer or a reference to some data type
DName innerType ( getDataIndirectType ( superType, ( isPtr ? '*' : '&' ), cvType ));
return getPtrRefDataType ( innerType, isPtr );
}
}
else {
DName trunk ( DN_truncated );
trunk += ( isPtr ? '*' : '&' );
if ( !cvType.isEmpty ()) {
trunk += cvType;
}
if ( !superType.isEmpty ()) {
if ( !cvType.isEmpty ()) {
trunk += ' ';
}
trunk += superType;
}
return trunk;
}
}
DName
UnDecorator::getDataIndirectType ( const DName & superType, char prType, const DName & cvType, int thisFlag )
{
if ( *gName ) {
unsigned int ditCode = ( *gName - (( *gName >= 'A' ) ? (unsigned int)'A': (unsigned int)( '0' - 26 )));
gName++;
// Is it a valid 'data-indirection-type' ?
if (( ditCode >= DIT_near ) && ( ditCode <= ( DIT_const | DIT_volatile | DIT_modelmask | DIT_member ))) {
DName ditType ( prType );
// 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
ditType = "::" + ditType;
if ( *gName ) {
ditType = ' ' + getScope ();
}
else {
ditType = DN_truncated + ditType;
}
// Now skip the scope terminator
if ( !*gName ) {
ditType += DN_truncated;
}
else
if ( *gName++ != '@' ) {
return DN_invalid;
}
}
// Add the 'model' attributes (prefixed) as appropriate
if (doMSKeywords ()) {
switch ( ditCode & DIT_modelmask ) {
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;
case DIT_based:
// The 'this-type' can never be 'based'
if ( thisFlag ) {
return DN_invalid;
}
ditType = getBasedType () + ditType;
break;
}
}
else
if (( ditCode & DIT_modelmask ) == DIT_based ) {
// Just lose the 'based-type'
ditType |= getBasedType ();
}
// 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 ()) {
ditType += ' ' + superType;
}
else {
ditType += ' ' + cvType + ' ' + superType;
}
}
else
if ( !cvType.isEmpty ()) {
ditType += ' ' + cvType;
}
}
// Finally, return the composed 'data-indirection-type' (with embedded sub-type)
return ditType;
}
else {
return DN_invalid;
}
}
else
if ( !thisFlag && !superType.isEmpty ()) {
// If 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 );
}
}
else
if ( !thisFlag && !cvType.isEmpty ()) {
return ( DN_truncated + cvType );
}
else {
return DN_truncated;
}
}
inline int
UnDecorator::getECSUDataIndirectType ()
{
if ( *gName ) {
unsigned int ecsuCode = *gName++ - 'A';
// Is it a valid 'ecsu-data-indirection-type' ?
if (( ecsuCode >= ECSU_near ) && ( ecsuCode <= ( ECSU_const | ECSU_volatile | ECSU_modelmask ))) {
return ( ecsuCode | ECSU_valid );
}
else {
return ECSU_invalid;
}
}
else {
return ECSU_truncated;
}
}
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++;
if ( superType.isEmpty ()) {
return "void";
}
else {
return "void " + superType;
}
}
// Otherwise it may be a 'reference-data-type'
if ( *gName == RDT_array ) {
DName * pDeclarator = new(heap) DName;
if ( !pDeclarator ) {
return DN_error;
}
gName++;
DName theArray ( getArrayType ( pDeclarator ));
if ( !theArray.isEmpty ()) {
*pDeclarator = superType;
}
return theArray;
}
// Otherwise, it is a 'basic-data-type'
return getBasicDataType ( superType );
}
else {
return ( DN_truncated + superType );
}
}
inline DName
UnDecorator::getArrayType ( DName * pDeclarator )
{
DName superType ( pDeclarator );
if ( *gName ) {
int noDimensions = getNumberOfDimensions ();
if ( !noDimensions ) {
return getBasicDataType ( DName ( '[' ) + DN_truncated + ']' );
}
else {
DName arrayType;
while ( noDimensions-- ) {
arrayType += '[' + getDimension () + ']';
}
// If it is indirect, then parenthesise the 'super-type'
if ( !superType.isEmpty ()) {
arrayType = '(' + superType + ')' + arrayType;
}
// Return the finished array dimension information
return getBasicDataType ( arrayType );
}
}
else
if ( !superType.isEmpty ()) {
return getBasicDataType ( '(' + superType + ")[" + DN_truncated + ']' );
}
else {
return getBasicDataType ( DName ( '[' ) + DN_truncated + ']' );
}
}
inline DName
UnDecorator::getLexicalFrame ( void )
{
return '`' + getDimension () + '\'';
}
inline DName
UnDecorator::getStorageConvention ( void )
{
return getDataIndirectType ();
}
inline DName
UnDecorator::getDataIndirectType ()
{
return getDataIndirectType ( DName (), 0, DName ());
}
inline DName
UnDecorator::getThisType ( void )
{
return getDataIndirectType ( DName (), 0, DName (), TRUE );
}
inline DName
UnDecorator::getPointerType ( const DName & cv, const DName & name )
{
return getPtrRefType ( cv, name, TRUE );
}
inline DName
UnDecorator::getReferenceType ( const DName & cv, const DName & name )
{
return getPtrRefType ( cv, name, FALSE );
}
inline DName
UnDecorator::getSegmentName ( void )
{
return getZName ();
}
inline DName
UnDecorator::getDisplacement ( void )
{
return getDimension ();
}
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 )
{
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;
}
// 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;
}
// Always append 'call'
vcallType += "call, ";
// Get the 'vfptr' model
// Last time, so advance the pointer
switch ( *gName++ ) {
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_nTnCbV:
case VMT_nTfCbV:
case VMT_fTnCbV:
case VMT_fTfCbV:
vcallType += getBasedType ();
break;
}
// Always append 'vfptr'
vcallType += "vfptr}";
// And return the resultant 'vcall-model-type'
return vcallType;
}
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 ";
}
}
if ( vxTableName.isValid ()) {
if ( !*gName ) {
vxTableName += DN_truncated;
}
vxTableName += '}';
}
}
// Skip the 'vpath-name' terminator
if ( *gName == '@' ) {
gName++;
}
}
}
else
if ( vxTableName.isValid ()) {
vxTableName = DN_truncated + vxTableName;
}
return vxTableName;
}
inline DName
UnDecorator::getExternalDataType ( const DName & superType )
{
// Create an indirect declarator for the the rest
DName * pDeclarator = new(heap) DName ();
DName declaration = getDataType ( pDeclarator );
// Now insert the declarator into the declaration along with its 'storage-convention'
*pDeclarator = getStorageConvention () + ' ' + superType;
return declaration;
}
inline int
UnDecorator::doUnderScore ()
{
return !( disableFlags & UNDNAME_NO_LEADING_UNDERSCORES );
}
inline int
UnDecorator::doMSKeywords ()
{
return !( disableFlags & UNDNAME_NO_MS_KEYWORDS );
}
inline int
UnDecorator::doFunctionReturns ()
{
return !( disableFlags & UNDNAME_NO_FUNCTION_RETURNS );
}
inline int
UnDecorator::doArguments ()
{
return !( disableFlags & UNDNAME_NO_ARGUMENTS );
}
inline int
UnDecorator::doSpecial ()
{
return !( disableFlags & UNDNAME_NO_SPECIAL_SYMS );
}
inline int
UnDecorator::doAllocationModel ()
{
return !( disableFlags & UNDNAME_NO_ALLOCATION_MODEL );
}
inline int
UnDecorator::doAllocationLanguage ()
{
return !( disableFlags & UNDNAME_NO_ALLOCATION_LANGUAGE );
}
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 );
}
pcchar_t
UnDecorator::UScore ( Tokens tok )
{
if (((tok == TOK_nearSp ) || ( tok == TOK_nearP )) && !do32BitNear ()) {
return tokenTable[ tok ] + 6; // Skip ''
}
else
if ( doUnderScore ()) {
return tokenTable[ tok ];
}
else {
return tokenTable[ tok ] + 2 ;
}
}
// Friend functions of 'DName'
DName operator + ( char c, const DName & rd )
{
return DName ( c ) + rd;
}
DName operator + ( DNameStatus st, const DName & rd )
{
return DName ( st ) + rd;
}
DName operator + ( pcchar_t s, const DName & rd )
{
return DName ( s ) + rd;
}
// The 'DName' constructors
inline
DName::DName ()
{
node = 0;
stat = DN_valid;
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
}
inline
DName::DName ( DNameNode * pd )
{
node = pd;
stat = DN_valid;
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
}
inline
DName::DName ( char c )
{
stat = DN_valid;
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
node = 0;
if ( c ) {
doPchar ( &c, 1 );
}
}
inline
DName::DName ( const DName & rd )
{
stat = rd.stat;
isIndir = rd.isIndir;
isAUDC = rd.isAUDC;
isSpecialSym = rd.isSpecialSym;
node = rd.node;
}
inline
DName::DName ( DName * pd )
{
if ( pd ) {
node = new(heap) pDNameNode ( pd );
stat = ( node ? DN_valid : DN_error );
}
else {
stat = DN_valid;
node = 0;
}
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
}
inline
DName::DName ( pcchar_t s )
{
stat = DN_valid;
node = 0;
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
if ( s ) {
doPchar ( s, strlen ( s ));
}
}
inline
DName::DName ( pcchar_t & name, char terminator )
{
stat = DN_valid;
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
node = 0;
if ( name ) {
if ( *name ) {
int len = 0;
// How long is the string ?
for ( pcchar_t s = name; *name && ( *name != terminator ); name++ ) {
if ( isValidIdentChar ( *name )) {
len++;
}
else {
stat = DN_invalid;
return;
}
}
// Copy the name string fragment
doPchar( s, len );
// Now gobble the terminator if present, handle error conditions
if ( *name ) {
if ( *name++ != terminator ) {
stat = DN_error;
node = 0;
}
else {
stat = DN_valid;
}
}
else
if ( status () == DN_valid ) {
stat = DN_truncated;
}
}
else {
stat = DN_truncated;
}
}
else {
stat = DN_invalid;
}
}
inline
DName::DName ( unsigned long num )
{
char buf[ 11 ];
char * pBuf = buf + 10;
stat = DN_valid;
node = 0;
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
// Essentially, 'ultoa ( num, buf, 10 )' :-
*pBuf = 0;
do {
*( --pBuf ) = (char)(( num % 10 ) + '0' );
num /= 10UL;
} while( num );
doPchar ( pBuf, ( 10 - ( pBuf - buf )));
}
inline
DName::DName ( DNameStatus st )
{
stat = ((( st == DN_invalid ) || ( st == DN_error )) ? st : DN_valid );
node = new(heap) DNameStatusNode ( st );
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
if ( !node ) {
stat = DN_error;
}
}
// Now the member functions for 'DName'
int
DName::isValid () const
{
return (( status () == DN_valid ) || ( status () == DN_truncated ));
}
int
DName::isEmpty () const
{
return (( node == 0 ) || !isValid ());
}
inline
DNameStatus
DName::status () const
{
return (DNameStatus)stat;
}
inline DName &
DName::setPtrRef ()
{
isIndir = 1;
return *this;
}
inline int
DName::isPtrRef () const
{
return isIndir;
}
inline int
DName::isUDC () const
{
return (!isEmpty () && isAUDC);
}
inline void
DName::setIsUDC ()
{
if (!isEmpty()) {
isAUDC = TRUE;
}
}
inline int
DName::isSpecial () const
{
return isSpecialSym;
}
inline void
DName::setIsSpecial ()
{
isSpecialSym = TRUE;
}
int
DName::length () const
{
int len = 0;
if ( !isEmpty ()) {
for (DNameNode * pNode = node; pNode; pNode = pNode->nextNode ()) {
len += pNode->length ();
}
}
return len;
}
pchar_t
DName::getString( pchar_t buf, int max ) const
{
if (!isEmpty()) {
// Does the caller want a buffer allocated ?
if ( !buf ) {
max = length () + 1;
buf = new(heap) char[ max ]; // Get a buffer big enough
}
// If memory allocation failure, then return no buffer
if ( buf ) {
// Now, go through the process of filling the buffer (until max is reached)
int curLen = max;
DNameNode *curNode = node;
pchar_t curBuf = buf;
while (curNode && ( curLen > 0 )) {
int fragLen = curNode->length ();
pchar_t fragBuf = 0;
// Skip empty nodes
if ( fragLen ) {
// Handle buffer overflow
if (( curLen - fragLen ) < 0 ) {
fragLen = curLen;
}
// Now copy 'len' number of bytes of the piece to the buffer
fragBuf = curNode->getString ( curBuf, fragLen );
// Should never happen, but handle it anyway
if ( fragBuf ) {
// Update string position
curLen -= fragLen;
curBuf += fragLen;
}
}
// Move on to the next name fragment
curNode = curNode->nextNode ();
}
*curBuf = 0; // Always NULL terminate the resulting string
}
}
else
if ( buf ) {
*buf = 0;
}
return buf;
}
DName
DName::operator + ( char ch ) const
{
DName local ( *this );
if ( local.isEmpty ()) {
local = ch;
}
else {
local += ch;
}
return local;
}
DName
DName::operator + ( pcchar_t str ) const
{
DName local ( *this );
if (local.isEmpty ()) {
local = str;
}
else {
local += str;
}
return local;
}
DName
DName::operator + ( const DName & rd ) const
{
DName local ( *this );
if (local.isEmpty ()) {
local = rd;
}
else
if (rd.isEmpty ()) {
local += rd.status ();
}
else {
local += rd;
}
return local;
}
DName
DName::operator + ( DName * pd ) const
{
DName local ( *this );
if (local.isEmpty ()) {
local = pd;
}
else {
local += pd;
}
return local;
}
DName
DName::operator + ( DNameStatus st ) const
{
DName local ( *this );
if ( local.isEmpty ()) {
local = st;
}
else {
local += st;
}
return local;
}
DName &
DName::operator += ( char ch )
{
if ( ch ) {
if (isEmpty ()) {
*this = ch;
}
else {
node = node->clone();
if ( node ) {
*node += new(heap) charNode ( ch );
}
else {
stat = DN_error;
}
}
}
return *this;
}
DName &
DName::operator += ( pcchar_t str )
{
if ( str && *str ) {
if ( isEmpty ()) {
*this = str;
}
else {
node = node->clone();
if ( node ) {
*node += new(heap) pcharNode( str );
}
else {
stat = DN_error;
}
}
}
return *this;
}
DName &
DName::operator += ( const DName & rd )
{
if (rd.isEmpty()) {
*this += rd.status();
}
else {
if (isEmpty()) {
*this = rd;
}
else {
node = node->clone();
if ( node ) {
*node += rd.node;
}
else {
stat = DN_error;
}
}
}
return *this;
}
DName &
DName::operator += ( DName * pd )
{
if ( pd ) {
if ( isEmpty ()) {
*this = pd;
}
else
if ((pd->status() == DN_valid ) || ( pd->status() == DN_truncated)) {
DNameNode * pNew = new(heap) pDNameNode ( pd );
if ( pNew ) {
node = node->clone();
if ( node ) {
*node += pNew;
}
}
else {
node = 0;
}
if ( !node ) {
stat = DN_error;
}
}
else {
*this += pd->status();
}
}
return *this;
}
DName &
DName::operator += ( DNameStatus st )
{
if ( isEmpty () || (( st == DN_invalid ) || ( st == DN_error ))) {
*this = st;
}
else {
DNameNode * pNew = new(heap) DNameStatusNode ( st );
if ( pNew ) {
node = node->clone();
if ( node ) {
*node += pNew;
}
}
else {
node = 0;
}
if ( !node ) {
stat = DN_error;
}
}
return *this;
}
DName &
DName::operator |= ( const DName & rd )
{
// Attenuate the error status. Always becomes worse.
// Don't propogate truncation
if (( status () != DN_error ) && !rd.isValid ()) {
stat = rd.status();
}
return *this;
}
DName &
DName::operator = ( char ch )
{
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
doPchar( &ch, 1 );
return *this;
}
DName &
DName::operator = ( pcchar_t str )
{
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
doPchar( str, strlen ( str ));
return *this;
}
DName &
DName::operator = ( const DName & rd )
{
if (( status () == DN_valid ) || ( status () == DN_truncated )) {
stat = rd.stat;
isIndir = rd.isIndir;
isAUDC = rd.isAUDC;
isSpecialSym = rd.isSpecialSym;
node = rd.node;
}
return *this;
}
DName &
DName::operator = ( DName * pd )
{
if (( status () == DN_valid ) || ( status () == DN_truncated )) {
if ( pd ) {
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
node = new(heap) pDNameNode ( pd );
if ( !node ) {
stat = DN_error;
}
}
else {
*this = DN_error;
}
}
return *this;
}
DName &
DName::operator = ( DNameStatus st )
{
if (( st == DN_invalid ) || ( st == DN_error )) {
node = 0;
if ( status () != DN_error ) {
stat = st;
}
}
else
if (( status () == DN_valid ) || ( status () == DN_truncated )) {
isIndir = 0;
isAUDC = 0;
isSpecialSym = 0;
node = new(heap) DNameStatusNode ( st );
if ( !node ) {
stat = DN_error;
}
}
return *this;
}
// Private implementation functions for 'DName'
void
DName::doPchar ( pcchar_t str, int len )
{
if ( !(( status () == DN_invalid ) || ( status () == DN_error ))) {
if ( node ) {
*this = DN_error;
}
else
if ( str && len ) {
switch ( len ) {
case 0:
stat = DN_error;
break;
case 1:
node = new(heap) charNode ( *str );
if ( !node ) {
stat = DN_error;
}
break;
default:
node = new(heap) pcharNode ( str, len );
if ( !node ) {
stat = DN_error;
}
break;
}
}
else {
stat = DN_invalid;
}
}
}
// The member functions for the 'Replicator'
inline
Replicator::Replicator ()
: ErrorDName ( DN_error ),
InvalidDName ( DN_invalid )
{
index = -1;
}
inline int
Replicator::isFull () const
{
return ( index == 9 );
}
Replicator &
Replicator::operator += ( const DName & rd )
{
if (!isFull () && !rd.isEmpty ()) {
DName * pNew = new(heap) DName ( rd );
if ( pNew ) {
dNameBuffer[ ++index ] = pNew;
}
}
return *this;
}
const DName &
Replicator::operator [] ( int x ) const
{
if (( x < 0 ) || ( x > 9 )) {
return ErrorDName;
}
if (( index == -1 ) || ( x > index )) {
return InvalidDName;
}
return *dNameBuffer[ x ];
}
// The member functions for the 'DNameNode' classes
DNameNode::DNameNode ( NodeType ndTy )
: typeIndex ( ndTy )
{
next = 0;
}
inline
DNameNode::DNameNode ( const DNameNode & rd )
{
next = (( rd.next ) ? rd.next->clone () : 0 );
}
inline DNameNode *
DNameNode::nextNode () const
{
return next;
}
DNameNode *
DNameNode::clone ()
{
return new(heap) pDNameNode( new(heap) DName ( this ));
}
int
DNameNode::length () const
{
switch ( typeIndex ) {
case charNode_t:
return ((charNode*)this )->length ();
case pcharNode_t:
return ((pcharNode*)this )->length ();
case pDNameNode_t:
return ((pDNameNode*)this )->length ();
case DNameStatusNode_t:
return ((DNameStatusNode*)this )->length ();
}
return 0;
}
pchar_t
DNameNode::getString ( pchar_t s, int l ) const
{
switch ( typeIndex ) {
case charNode_t:
return ((charNode*)this )->getString ( s, l );
case pcharNode_t:
return ((pcharNode*)this )->getString ( s, l );
case pDNameNode_t:
return ((pDNameNode*)this )->getString ( s, l );
case DNameStatusNode_t:
return ((DNameStatusNode*)this )->getString ( s, l );
}
return 0;
}
DNameNode &
DNameNode::operator += ( DNameNode * pNode )
{
if ( pNode ) {
if ( next ) {
// Skip to the end of the chain
for (DNameNode* pScan = next; pScan->next; pScan = pScan->next) ;
// And append the new node
pScan->next = pNode;
}
else {
next = pNode;
}
}
return *this;
}
// The 'charNode' virtual functions
charNode::charNode ( char ch )
: DNameNode ( charNode_t )
{
me = ch;
}
inline int
charNode::length () const
{
return 1;
}
pchar_t
charNode::getString ( pchar_t buf, int len ) const
{
if ( buf && len ) {
*buf = me;
}
else {
buf = 0;
}
return buf;
}
// The 'pcharNode' virtual functions
inline int
pcharNode::length () const
{
return myLen;
}
pcharNode::pcharNode ( pcchar_t str, int len )
: DNameNode ( pcharNode_t )
{
// Get length if not supplied
if ( !len && str ) {
len = strlen ( str );
}
// Allocate a new string buffer if valid state
if ( len && str ) {
me = new(heap) char[ len ];
myLen = len;
if ( me ) {
strncpy( me, str, len );
}
}
else {
me = 0;
myLen = 0;
}
}
pchar_t
pcharNode::getString ( pchar_t buf, int len ) const
{
// Use the shorter of the two lengths (may not be NULL terminated)
if (len > pcharNode::length ()) {
len = pcharNode::length();
}
// Do the copy as appropriate
return (( me && buf && len ) ? strncpy ( buf, me, len ) : 0 );
}
// The 'pDNameNode' virtual functions
pDNameNode::pDNameNode ( DName * pName )
: DNameNode ( pDNameNode_t )
{
me = (( pName && (( pName->status () == DN_invalid ) || ( pName->status () == DN_error ))) ? 0 : pName );
}
inline int
pDNameNode::length () const
{
return ( me ? me->length () : 0 );
}
pchar_t
pDNameNode::getString ( pchar_t buf, int len ) const
{
return (( me && buf && len ) ? me->getString ( buf, len ) : 0 );
}
// The 'DNameStatusNode' virtual functions
DNameStatusNode::DNameStatusNode ( DNameStatus stat )
: DNameNode ( DNameStatusNode_t )
{
me = stat;
myLen = (( me == DN_truncated ) ? TruncationMessageLength : 0 );
}
inline int
DNameStatusNode::length () const
{
return myLen;
}
pchar_t
DNameStatusNode::getString ( pchar_t buf, int len ) const
{
// Use the shorter of the two lengths (may not be NULL terminated)
if (len > DNameStatusNode::length ()) {
len = DNameStatusNode::length ();
}
// Do the copy as appropriate
return ((( me == DN_truncated ) && buf && len ) ? strncpy ( buf, TruncationMessage, len ) : 0 );
}
void * _cdecl operator new( unsigned int cb )
{
return MemAlloc( cb );
}
void _cdecl operator delete( void * p )
{
MemFree( p );
}
void * __cdecl AllocIt(unsigned int cb)
{
return (MemAlloc(cb));
}
void __cdecl FreeIt(void * p)
{
MemFree(p);
}
HMODULE hMsvcrt;
PUNDNAME pfUnDname;
BOOL fLoadMsvcrtDLL;
DWORD
IMAGEAPI
WINAPI
UnDecorateSymbolName(
LPCSTR name,
LPSTR outputString,
DWORD maxStringLength,
DWORD flags
)
{
//
// can't undecorate into a zero length buffer
//
if (!maxStringLength) {
return 0;
}
if (!fLoadMsvcrtDLL) {
// The first time we run, see if we can find the system undname. Use
// GetModuleHandle to avoid any additionally overhead.
hMsvcrt = GetModuleHandle("msvcrt.dll");
if (!hMsvcrt) {
hMsvcrt = GetModuleHandle("msvcrt40.dll");
}
if (hMsvcrt) {
pfUnDname = (PUNDNAME) GetProcAddress(hMsvcrt, "__unDName");
}
fLoadMsvcrtDLL = TRUE;
}
if (pfUnDname) {
if (flags & UNDNAME_NO_ARGUMENTS) {
flags |= UNDNAME_NAME_ONLY;
flags &= ~UNDNAME_NO_ARGUMENTS;
}
if (flags & UNDNAME_NO_SPECIAL_SYMS) {
flags &= ~UNDNAME_NO_SPECIAL_SYMS;
}
return(*(pfUnDname)(outputString, name, maxStringLength, AllocIt, FreeIt, (USHORT)flags));
} else {
heap = new HeapManager;
//
// make sure that the buffer is a big as the caller says
//
__try {
UnDecorator unDecorate( outputString, name, maxStringLength, flags );
pchar_t unDecoratedName = unDecorate;
delete heap;
return strlen(outputString);
} __except(EXCEPTION_EXECUTE_HANDLER) {
return 0;
}
}
}