Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1663 lines
52 KiB

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 1993-2000 Microsoft Corporation
Module Name:
frmtstr.hxx
Abstract:
Notes:
History:
DKays Oct-1993 Created.
----------------------------------------------------------------------------*/
#include "becls.hxx"
#pragma hdrstop
extern CMD_ARG * pCommand;
const char * pExprFormatCharNames[] =
{
""
,"FC_EXPR_CONST32"
,"FC_EXPR_CONST64"
,"FC_EXPR_VAR"
,"FC_EXPR_OPER"
,"FC_EXPR_PAD"
};
const char * pFormatCharNames[] =
{
"", // FC_ZERO
"FC_BYTE",
"FC_CHAR",
"FC_SMALL",
"FC_USMALL",
"FC_WCHAR",
"FC_SHORT",
"FC_USHORT",
"FC_LONG",
"FC_ULONG",
"FC_FLOAT",
"FC_HYPER",
"FC_DOUBLE",
"FC_ENUM16",
"FC_ENUM32",
"FC_IGNORE",
"FC_ERROR_STATUS_T",
"FC_RP", // 11
"FC_UP",
"FC_OP",
"FC_FP",
"FC_STRUCT",
"FC_PSTRUCT",
"FC_CSTRUCT",
"FC_CPSTRUCT",
"FC_CVSTRUCT",
"FC_BOGUS_STRUCT",
"FC_CARRAY",
"FC_CVARRAY",
"FC_SMFARRAY",
"FC_LGFARRAY",
"FC_SMVARRAY",
"FC_LGVARRAY or FC_SPLIT", // 20
"FC_BOGUS_ARRAY",
"FC_C_CSTRING",
"FC_C_BSTRING",
"FC_C_SSTRING",
"FC_C_WSTRING",
"FC_CSTRING",
"FC_BSTRING",
"FC_SSTRING",
"FC_WSTRING",
"FC_ENCAPSULATED_UNION",
"FC_NON_ENCAPSULATED_UNION",
"FC_BYTE_COUNT_POINTER",
"FC_TRANSMIT_AS",
"FC_REPRESENT_AS",
"FC_IP",
"FC_BIND_CONTEXT", // 30
"FC_BIND_GENERIC",
"FC_BIND_PRIMITIVE",
"FC_AUTO_HANDLE",
"FC_CALLBACK_HANDLE",
"FC_UNUSED1",
"FC_POINTER",
"FC_ALIGNM2",
"FC_ALIGNM4",
"FC_ALIGNM8",
"FC_UNUSED2",
"FC_UNUSED3",
"FC_UNUSED4",
"FC_STRUCTPAD1",
"FC_STRUCTPAD2",
"FC_STRUCTPAD3",
"FC_STRUCTPAD4", // 40
"FC_STRUCTPAD5",
"FC_STRUCTPAD6",
"FC_STRUCTPAD7",
"FC_STRING_SIZED",
"FC_UNUSED5",
"FC_NO_REPEAT",
"FC_FIXED_REPEAT",
"FC_VARIABLE_REPEAT",
"FC_FIXED_OFFSET",
"FC_VARIABLE_OFFSET",
"FC_PP",
"FC_EMBEDDED_COMPLEX",
"FC_IN_PARAM",
"FC_IN_PARAM_BASETYPE",
"FC_IN_PARAM_NO_FREE_INST",
"FC_IN_OUT_PARAM", // 50
"FC_OUT_PARAM",
"FC_RETURN_PARAM",
"FC_RETURN_PARAM_BASETYPE",
"FC_DEREFERENCE", // 54
"FC_DIV_2", // 55
"FC_MULT_2", // 56
"FC_ADD_1", // 57
"FC_SUB_1", // 58
"FC_CALLBACK", // 59
"FC_CONSTANT_IID", // 5a
"FC_END", // 5b
"FC_PAD", // 5c
"FC_EXPR", // 5d
"FC_PARTIAL_IGNORE_PARAM", // 5e,
"?", // 5f
"?", "?", "?", "?", "?", "?", "?", "?", // 60-67
"?", "?", "?", "?", "?", "?", "?", "?", // 68-6f
"?", "?", "?", "?", // 70-73
"FC_SPLIT_DEREFERENCE", // 74
"FC_SPLIT_DIV_2", // 75
"FC_SPLIT_MULT_2", // 76
"FC_SPLIT_ADD_1", // 77
"FC_SPLIT_SUB_1", // 78
"FC_SPLIT_CALLBACK", // 79
"?", "?", "?", "?", "?", "?", // 7a-7f
"?", "?", "?", "?", "?", "?", "?", "?", // 80-87
"?", "?", "?", "?", "?", "?", "?", "?", // 88-8f
"?", "?", "?", "?", "?", "?", "?", "?", // 90-97
"?", "?", "?", "?", "?", "?", "?", "?", // 98-9f
"?", "?", "?", "?", "?", "?", "?", "?", // a0-a7
"?", "?", "?", "?", "?", "?", "?", "?", // a8-af
"?", // b0
"FC_HARD_STRUCT",
"FC_TRANSMIT_AS_PTR",
"FC_REPRESENT_AS_PTR",
"FC_USER_MARSHAL",
"FC_PIPE",
"?", // FC_BLKHOLE. obselete
"FC_RANGE", // b7
"FC_INT3264", // b8
"FC_UINT3264", // b9
// Post NT5.0
"FC_CSARRAY", // ba
"FC_CS_TAG", // bb
"FC_STRUCTPADN", // bc
"FC_INT128", // 0xbd
"FC_UINT128", // 0xbe
"FC_FLOAT80", // 0xbf
"FC_FLOAT128", // 0xc0
"FC_BUFFER_ALIGN", // 0xc1
"FC_ENCAP_UNION", // 0xc2
// new 64bit array types
"FC_FIX_ARRAY", // 0xc3
"FC_CONF_ARRAY", // 0xc4
"FC_VAR_ARRAY", // 0xc5
"FC_CONFVAR_ARRAY", // 0xc6
"FC_FIX_FORCED_BOGUS_ARRAY",// 0xc7
"FC_FIX_BOGUS_ARRAY", // 0xc8
"FC_FORCED_BOGUS_ARRAY", // 0xc9
"FC_CHAR_STRING", // 0xca
"FC_WCHAR_STRING", // 0xcb
"FC_STRUCT_STRING", // 0xcc
"FC_CONF_CHAR_STRING", // 0xcd
"FC_CONF_WCHAR_STRING", // 0xce
"FC_CONF_STRUCT_STRING", // 0xcf
// new structure types
"FC_CONF_STRUCT", // 0xd0
"FC_CONF_PSTRUCT", // 0xd1
"FC_CONFVAR_STRUCT", // 0xd2
"FC_CONFVAR_PSTRUCT", // 0xd3
"FC_FORCED_BOGUS_STRUCT", // 0xd4
"FC_CONF_BOGUS_STRUCT", // 0xd5
"FC_FORCED_CONF_BOGUS_STRUCT",// 0xd7
"FC_END_OF_UNIVERSE" // 0xd8
};
const char * pExprOpFormatCharNames[] =
{
"",
"OP_UNARY_PLUS",
"OP_UNARY_MINUS",
"OP_UNARY_NOT",
"OP_UNARY_COMPLEMENT",
"OP_UNARY_INDIRECTION",
"OP_UNARY_CAST",
"OP_UNARY_AND",
"OP_UNARY_SIZEOF",
"OP_UNARY_ALIGNOF",
"OP_PRE_INCR",
"OP_PRE_DECR",
"OP_POST_INCR",
"OP_POST_DECR",
"OP_PLUS",
"OP_MINUS",
"OP_STAR",
"OP_SLASH",
"OP_MOD",
"OP_LEFT_SHIFT",
"OP_RIGHT_SHIFT",
"OP_LESS",
"OP_LESS_EQUAL",
"OP_GREATER_EQUAL",
"OP_GREATER",
"OP_EQUAL",
"OP_NOT_EQUAL",
"OP_AND",
"OP_OR",
"OP_XOR",
"OP_LOGICAL_AND",
"OP_LOGICAL_OR",
"OP_EXPRESSION",
"",
"",
"", // function
"", // param
"", // pointsto
"", // dot
"", // index
"", // comma
"", // stmt
"", // assign
"OP_ASYNCSPLIT", // asyncsplit
"OP_CORR_POINTER", // corr_pointer
"OP_CORR_TOP_LEVEL", // corr_toplevel
};
//
// This table is indexed by FORMAT_CHARACTER (see ndrtypes.h).
// To construct the correct name concatenate the name in this table with
// "Marshall", "Unmarshall", "BufferSize" etc.
//
char * pNdrRoutineNames[] =
{
"", // FC_ZERO
"NdrSimpleType", // FC_BYTE
"NdrSimpleType", // FC_CHAR
"NdrSimpleType", // FC_SMALL
"NdrSimpleType", // FC_USMALL
"NdrSimpleType", // FC_WCHAR
"NdrSimpleType", // FC_SHORT
"NdrSimpleType", // FC_USHORT
"NdrSimpleType", // FC_LONG
"NdrSimpleType", // FC_ULONG
"NdrSimpleType", // FC_FLOAT
"NdrSimpleType", // FC_HYPER
"NdrSimpleType", // FC_DOUBLE
"NdrSimpleType", // FC_ENUM16
"NdrSimpleType", // FC_ENUM32
"NdrSimpleType", // FC_IGNORE
"NdrSimpleType", // FC_ERROR_STATUS_T
"NdrPointer", // FC_RP
"NdrPointer", // FC_UP
"NdrPointer", // FC_OP
"NdrPointer", // FC_FP
"NdrSimpleStruct", // FC_STRUCT
"NdrSimpleStruct", // FC_PSTRUCT
"NdrConformantStruct", // FC_CSTRUCT
"NdrConformantStruct", // FC_CPSTRUCT
"NdrConformantVaryingStruct", // FC_CVSTRUCT
"NdrComplexStruct", // FC_BOGUS_STRUCT
"NdrConformantArray", // FC_CARRAY
"NdrConformantVaryingArray", // FC_CVARRAY
"NdrFixedArray", // FC_SMFARRAY
"NdrFixedArray", // FC_LGFARRAY
"NdrVaryingArray", // FC_SMVARRAY
"NdrVaryingArray", // FC_LGVARRAY
"NdrComplexArray", // FC_BOGUS_ARRAY
"NdrConformantString", // FC_C_CSTRING
"NdrConformantString", // FC_C_BSTRING
"NdrConformantString", // FC_C_SSTRING
"NdrConformantString", // FC_C_WSTRING
"NdrNonConformantString", // FC_CSTRING
"NdrNonConformantString", // FC_BSTRING
"NdrNonConformantString", // FC_SSTRING
"NdrNonConformantString", // FC_WSTRING
"NdrEncapsulatedUnion", // FC_ENCAPSULATED_UNION
"NdrNonEncapsulatedUnion", // FC_NON_ENCAPSULATED_UNION
"NdrByteCountPointer", // FC_BYTE_COUNT_POINTER
"NdrXmitOrRepAs", // FC_TRANSMIT_AS
"NdrXmitOrRepAs", // FC_REPRESENT_AS
"NdrInterfacePointer", // FC_INTERFACE_POINTER
"NdrContextHandle", // FC_BIND_CONTEXT
"?", "?", "?", "?", "?", "?", "?", // 31-37
"?", "?", "?", "?", "?", "?", "?", "?", // 38-3f
"?", "?", "?", "?", "?", "?", "?", "?", // 40-47
"?", "?", "?", "?", "?", "?", "?", "?", // 48-4f
"?", "?", "?", "?", "?", "?", "?", "?", // 50-57
"?", "?", "?", // 58-5a
"?", "?", // FC_END & FC_PAD
"?", "?", "?", // 5d-5f
"?", "?", "?", "?", "?", "?", "?", "?", // 60-67
"?", "?", "?", "?", "?", "?", "?", "?", // 68-6f
"?", "?", "?", "?", "?", "?", "?", "?", // 70-77
"?", "?", "?", "?", "?", "?", "?", "?", // 78-7f
"?", "?", "?", "?", "?", "?", "?", "?", // 80-87
"?", "?", "?", "?", "?", "?", "?", "?", // 88-8f
"?", "?", "?", "?", "?", "?", "?", "?", // 90-97
"?", "?", "?", "?", "?", "?", "?", "?", // 98-9f
"?", "?", "?", "?", "?", "?", "?", "?", // a0-a7
"?", "?", "?", "?", "?", "?", "?", "?", // a8-af
"?", // 0xb0
"NdrHardStruct", // FC_HARD_STRUCT
"NdrXmitOrRepAs", // FC_TRANSMIT_AS_PTR
"NdrXmitOrRepAs", // FC_REPRESENT_AS_PTR
"NdrUserMarshal", // FC_USER_MARSHAL
"NdrPipe", // FC_PIPE
0, // FC_BLKHOLE
0, // FC_RANGE
"NdrSimpleType", // FC_INT3264
"NdrSimpleType", // FC_UINT3264
"NdrCsArray", // FC_CSARRAY
"NdrCsTag", // FC_CS_TAG
0
};
// ============================================================================
//
// FORMAT_STRING class, general comments on fragment optimization.
//
// There are 3 type of offsets that matter a lot when format string fragments
// are optimized. These are absolute type offsets, relative type offsets and
// stack (or field) offsets.
//
// - Absolute type offsets are offsets from the proc format string to type
// format string. For 32b implementation they are limited to ushort32 range.
// An absolute type offset indicates a type of a parameter.
// Note that there is only one absolute type offset for a parameter regardless
// of the platform.
//
// - Relative type offsets are offsets within the type format string.
// For 32b implementation they are limited to short32 range.
// A relative type offset indicates a type of a component for a compund type.
// Note that there is only one relative type offset for a field or element
// regardless of the platform.
//
// - Stack offset is a stack offset to a parameter within a proc stack or
// a field offset to a field within a struct.
// For a 32b implementation stack offsets are limited to a short32 range. This
// is because some of these offsets are relative to a current position within
// a struct or union. They have been clampd together because of correlation
// descriptors may have stack or field offsets.
// Proper stack offsets actually come in a ushort and usmall range variaty.
// Proper field offsets come in as shorts.
// For a given position in the format string, there is a set of stack offsets
// as in general a x86 stack offset is different from other platform offsets
// and a field offset may be different as well.
//
// Proc format string uses only absolute type offsets and stack offsets.
//
// the constructor
FORMAT_STRING::FORMAT_STRING()
{
// Allocate the buffer and align it on a short boundary.
pBuffer = (unsigned char *) new short[ DEFAULT_FORMAT_STRING_SIZE / 2 ];
// Allocate the cousin buffer type array. This does not need to
// be aligned.
pBufferType = new unsigned char[ DEFAULT_FORMAT_STRING_SIZE ];
memset( pBuffer, 0, DEFAULT_FORMAT_STRING_SIZE );
memset( pBufferType, FS_FORMAT_CHARACTER, DEFAULT_FORMAT_STRING_SIZE );
BufferSize = DEFAULT_FORMAT_STRING_SIZE;
CurrentOffset = 0;
LastOffset = 0;
pReuseDict = new FRMTREG_DICT( this );
}
void
FORMAT_STRING::CheckSize()
/*++
Routine Description :
Reallocates a new format string buffer if the current buffer is within
4 bytes of overflowing.
Arguments :
None.
--*/
{
//
// Allocate a new buffer if we're within 4 bytes of
// overflowing the current buffer.
//
if ( CurrentOffset + 3 > BufferSize )
{
unsigned char * pBufferNew;
// double the Buffer size
pBufferNew = (unsigned char *) new short[ BufferSize ];
memcpy( pBufferNew,
pBuffer,
(unsigned int) BufferSize );
memset( pBufferNew + BufferSize, 0, BufferSize );
delete pBuffer;
pBuffer = pBufferNew;
// double the BufferType size
pBufferNew = (unsigned char *) new short[ BufferSize ];
memcpy( pBufferNew,
pBufferType,
(unsigned int) BufferSize );
memset( pBufferNew + BufferSize, FS_FORMAT_CHARACTER, BufferSize );
delete pBufferType;
pBufferType = pBufferNew;
BufferSize *= 2;
}
}
//
// Push a short type-fmt-string offset at the current offset.
// This is used as the offset from a parameter into type format string.
// For 32b code, this needs to be a value within an unsigned short.
// We use a long value internally for better fragment optimization.
//
void
FORMAT_STRING::PushShortTypeOffset( long s )
{
CheckSize();
if ( s < 0 || s > _UI16_MAX )
{
// CG_NDR * pNdr = pCCB->GetLastPlaceholderClass();
CG_NDR * pNdr = 0;
char * pName = pNdr ? pNdr->GetSymName()
: "";
RpcError(NULL, 0, FORMAT_STRING_LIMITS, pName );
exit( FORMAT_STRING_LIMITS );
}
pBufferType[CurrentOffset] = FS_SHORT_TYPE_OFFSET;
pBufferType[CurrentOffset+1] = FS_SMALL;
*((unsigned short UNALIGNED *)(pBuffer + CurrentOffset)) = (unsigned short)s;
TypeOffsetDict.Insert( (long) CurrentOffset, s );
IncrementOffset(2);
}
//
// Push a short offset at the current offset.
// This is the relative type offset within the type string.
// For 32b code, this needs to be a value within a signed short, eventually.
// We use a long value internally for better fragment optimization.
//
void
FORMAT_STRING::PushShortOffset( long TypeOffset )
{
CheckSize();
// We don't check the range for the offset here for better optimization.
pBufferType[ CurrentOffset ] = FS_SHORT_OFFSET;
pBufferType[ CurrentOffset + 1 ] = FS_SMALL;
*((short UNALIGNED *)(pBuffer + CurrentOffset)) = (short)TypeOffset;
TypeOffsetDict.Insert( (long) CurrentOffset, TypeOffset );
IncrementOffset(2);
}
// This an auxilary method to handle relative offsets.
// It is used when we need to write out an offset temporarily and then fix it
// later, for example in pointers, structs etc.
//
void
FORMAT_STRING::PushShortOffset( long TypeOffset, long Position )
{
// We don't check the range for the offset here for better optimization.
pBufferType[ Position ] = FS_SHORT_OFFSET;
pBufferType[ Position + 1 ] = FS_SMALL;
*((short UNALIGNED *)(pBuffer + Position)) = (short)TypeOffset;
TypeOffsetDict.Insert( Position, TypeOffset );
}
//
// Push a stack size or an absolute offset.
//
void
FORMAT_STRING::PushUShortStackOffsetOrSize(
long X86Offset )
{
CheckSize();
if ( X86Offset < 0 || X86Offset > _UI16_MAX )
{
// Make it a warning with a name.
// CG_NDR * pNdr = pCCB->GetLastPlaceholderClass();
CG_NDR * pNdr = 0;
char * pName = pNdr ? pNdr->GetSymName()
: "";
RpcError(NULL, 0, STACK_SIZE_TOO_BIG, pName );
exit( FORMAT_STRING_LIMITS );
}
pBufferType[CurrentOffset] = FS_SHORT_STACK_OFFSET;
pBufferType[CurrentOffset+1] = FS_SMALL;
*((short UNALIGNED *)(pBuffer + CurrentOffset)) = (short) X86Offset;
#if defined(RKK_FRAG_OPT)
{
printf("PushShortStackOffset CurrentOffset %d\n", CurrentOffset );
int offLow = CurrentOffset - 10; if (offLow < 0) offLow = 0;
int offHig = CurrentOffset + 10;
printf(" off=%d ", offLow );
for (int off = offLow; off < offHig; off++)
printf("%02x ", pBuffer[ off ]);
printf( "\n" );
printf(" off=%d ", offLow );
for ( off = offLow; off < offHig; off++)
printf("%02x ", pBufferType[ off ]);
printf( "\n" );
}
#endif
OffsetDict.Insert( (long) CurrentOffset,
X86Offset );
IncrementOffset(2);
}
//
// Push a stack offset.
// Needs to be relative because of offsets in structs etc.
//
void
FORMAT_STRING::PushShortStackOffset(
long X86Offset )
{
CheckSize();
if ( X86Offset < _I16_MIN || X86Offset > _I16_MAX )
{
// Make it a warning with a name.
// CG_NDR * pNdr = pCCB->GetLastPlaceholderClass();
CG_NDR * pNdr = 0;
char * pName = pNdr ? pNdr->GetSymName()
: "";
RpcError(NULL, 0, FORMAT_STRING_LIMITS, pName );
exit( FORMAT_STRING_LIMITS );
}
pBufferType[CurrentOffset] = FS_SHORT_STACK_OFFSET;
pBufferType[CurrentOffset+1] = FS_SMALL;
*((short UNALIGNED *)(pBuffer + CurrentOffset)) = (short) X86Offset;
#if defined(RKK_FRAG_OPT)
{
printf("PushShortStackOffset CurrentOffset %d\n", CurrentOffset );
int offLow = CurrentOffset - 10; if (offLow < 0) offLow = 0;
int offHig = CurrentOffset + 10;
printf(" off=%d ", offLow );
for (int off = offLow; off < offHig; off++)
printf("%02x ", pBuffer[ off ]);
printf( "\n" );
printf(" off=%d ", offLow );
for ( off = offLow; off < offHig; off++)
printf("%02x ", pBufferType[ off ]);
printf( "\n" );
}
#endif
OffsetDict.Insert( (long) CurrentOffset,
X86Offset );
IncrementOffset(2);
}
// =============================================================================
//
// Helper routines writing comments about some tokens.
//
__inline void
Out_PointerFlags(
ISTREAM * pStream,
unsigned char * pFlags
)
{
if ( *pFlags & FC_ALLOCATE_ALL_NODES )
pStream->Write( " [all_nodes]");
if ( *pFlags & FC_DONT_FREE )
pStream->Write( " [dont_free]");
if ( *pFlags & FC_ALLOCED_ON_STACK )
pStream->Write( " [alloced_on_stack]");
if ( *pFlags & FC_SIMPLE_POINTER )
pStream->Write( " [simple_pointer]");
if ( *pFlags & FC_POINTER_DEREF )
pStream->Write( " [pointer_deref]");
}
__inline void
Out_OldProcFlags(
ISTREAM * pStream,
unsigned char * pFlags
)
{
INTERPRETER_FLAGS * pOiFlags = (INTERPRETER_FLAGS *)pFlags;
if ( pOiFlags->FullPtrUsed )
pStream->Write( " full ptr,");
if ( pOiFlags->RpcSsAllocUsed )
pStream->Write( " DCE mem package,");
if ( pOiFlags->ObjectProc )
{
pStream->Write( " object,");
if ( pOiFlags->IgnoreObjectException )
pStream->Write( " ignore obj exc,");
if ( pOiFlags->HasCommOrFault )
pStream->Write( " Oi2");
}
else
{
if ( pOiFlags->IgnoreObjectException )
pStream->Write( " encode,");
if ( pOiFlags->HasCommOrFault )
pStream->Write( " comm or fault/decode");
}
}
__inline void
Out_Oi2ProcFlags(
ISTREAM * pStream,
unsigned char * pFlags
)
{
INTERPRETER_OPT_FLAGS * pOi2Flags = (INTERPRETER_OPT_FLAGS *)pFlags;
if ( pOi2Flags->ServerMustSize )
pStream->Write( " srv must size,");
if ( pOi2Flags->ClientMustSize )
pStream->Write( " clt must size,");
if ( pOi2Flags->HasReturn )
pStream->Write( " has return,");
if ( pOi2Flags->HasPipes )
pStream->Write( " has pipes,");
if ( pOi2Flags->HasAsyncUuid )
pStream->Write( " has async uuid,");
if ( pOi2Flags->HasExtensions )
pStream->Write( " has ext,");
if ( pOi2Flags->HasAsyncHandle )
pStream->Write( " has async handle");
}
__inline void
Out_ExtProcFlags(
ISTREAM * pStream,
unsigned char * pFlags
)
{
INTERPRETER_OPT_FLAGS2 * pExtFlags = (INTERPRETER_OPT_FLAGS2 *)pFlags;
if ( pExtFlags->HasNewCorrDesc )
pStream->Write( " new corr desc,");
if ( pExtFlags->ClientCorrCheck )
pStream->Write( " clt corr check,");
if ( pExtFlags->ServerCorrCheck )
pStream->Write( " srv corr check,");
if ( pExtFlags->HasNotify )
pStream->Write( " has notify");
if ( pExtFlags->HasNotify2 )
pStream->Write( " has notify_flag");
if ( pExtFlags->HasComplexReturn )
pStream->Write( " has complex return");
}
__inline void
Out_ParameterFlags(
ISTREAM * pStream,
PARAM_ATTRIBUTES * pParamAttr
)
{
char Buf[8];
if ( pParamAttr->MustSize )
pStream->Write( " must size,");
if ( pParamAttr->MustFree )
pStream->Write( " must free,");
if ( pParamAttr->IsPipe )
pStream->Write( " pipe,");
if ( pParamAttr->IsIn )
pStream->Write( " in,");
if ( pParamAttr->IsOut )
pStream->Write( " out,");
if ( pParamAttr->IsReturn )
pStream->Write( " return,");
if ( pParamAttr->IsBasetype )
pStream->Write( " base type,");
if ( pParamAttr->IsByValue )
pStream->Write( " by val,");
if ( pParamAttr->IsSimpleRef )
pStream->Write( " simple ref,");
if ( pParamAttr->IsDontCallFreeInst )
pStream->Write( " dont call free inst,");
if ( pParamAttr->IsForceAllocate )
pStream->Write( " force allocate," );
if ( pParamAttr->SaveForAsyncFinish )
pStream->Write( " split async,");
if ( pParamAttr->ServerAllocSize )
{
pStream->Write( " srv alloc size=");
pStream->Write( MIDL_ITOA( 8 * pParamAttr->ServerAllocSize, Buf, 10) );
}
}
__inline void
Out_CorrelationType(
ISTREAM * pStream,
unsigned char * pCorrType
)
{
unsigned char CorrType = *pCorrType;
if ( CorrType & FC_NORMAL_CONFORMANCE )
pStream->Write( " field, ");
if ( CorrType & FC_POINTER_CONFORMANCE )
pStream->Write( " field pointer, ");
if ( CorrType & FC_TOP_LEVEL_CONFORMANCE )
pStream->Write( " parameter, ");
if ( CorrType & FC_TOP_LEVEL_MULTID_CONFORMANCE )
pStream->Write( " multidim parameter, ");
if ( CorrType & FC_CONSTANT_CONFORMANCE )
{
unsigned long ConstVal;
char Buf[12];
pStream->Write( " constant, val=");
// next three bytes: just a weird way of generating it
ConstVal = (ulong) pCorrType[1] << 16;
ConstVal |= *(unsigned short UNALIGNED *)( pCorrType + 2);
pStream->Write( MIDL_ITOA( ConstVal, Buf, 10) );
}
else
{
pStream->Write( pFormatCharNames[ CorrType & 0xf ] );
}
}
__inline void
Out_CorrelationFlags(
ISTREAM * pStream,
unsigned char * pNewCorrFlags
)
{
NDR_CORRELATION_FLAGS * pCorrFlags = (NDR_CORRELATION_FLAGS *)pNewCorrFlags;
if ( pCorrFlags->Early )
pStream->Write( " early," );
if ( pCorrFlags->Split )
pStream->Write( " split," );
if ( pCorrFlags->IsIidIs )
pStream->Write( " iid_is," );
if ( pCorrFlags->DontCheck )
pStream->Write( " dont check" );
}
__inline void
Out_ContextHandleFlags(
ISTREAM * pStream,
unsigned char * pContextFlags
)
{
PNDR_CONTEXT_HANDLE_FLAGS pFlags = (PNDR_CONTEXT_HANDLE_FLAGS)pContextFlags;
if ( pFlags->IsViaPtr )
pStream->Write( " via ptr," );
if ( pFlags->IsIn )
pStream->Write( " in," );
if ( pFlags->IsOut )
pStream->Write( " out," );
if ( pFlags->IsReturn )
pStream->Write( " ret," );
if ( pFlags->IsStrict )
pStream->Write( " strict," );
if ( pFlags->NoSerialize )
pStream->Write( " no serialize," );
if ( pFlags->Serialize )
pStream->Write( " serialize," );
if ( pFlags->CannotBeNull)
pStream->Write( " can't be null" );
}
__inline void
Out_SmallStackSize(
ISTREAM * pStream,
long StackSize,
char * pEnvComment
)
{
char Buf[102];
//
// Non-Alpha stack size.
//
pStream->Write( "0x" );
pStream->Write( MIDL_ITOA(StackSize, Buf, 16) );
pStream->Write( ",\t\t/* ");
pStream->Write( pEnvComment );
pStream->Write( " stack size = ");
pStream->Write( MIDL_ITOA(StackSize, Buf, 10) );
pStream->Write( " */");
}
// The comment table is initialized in FORMAT_STRING::Output as appropriate
// for a given environment { 64b, 32b, others }.
// The comments correspond to the ifdef situation described below.
static char * Env64Comment = "ia64";
static char * Env32Comment = "x86";
static char * OtherEnvComment = "";
__inline void
Out_ShortStackOffset(
ISTREAM * pStream,
OffsetDictElem * pStackOffsets,
char * EnvComment
)
{
char Buf[102];
//
// Emit the main (x86 or ia64) offset.
//
unsigned long OffsetValue = pStackOffsets->X86Offset;
pStream->Write( "NdrFcShort( 0x" );
pStream->Write( MIDL_ITOA( OffsetValue, Buf, 16) );
pStream->Write( " ),\t/* " );
pStream->Write( EnvComment );
pStream->Write( " Stack size/offset = " );
pStream->Write( MIDL_ITOA( OffsetValue, Buf, 10) );
pStream->Write( " */");
}
void
FORMAT_STRING::Output(
ISTREAM * pStream,
char * pTypeName,
char * pName,
RepAsPadExprDict * pPadDict,
RepAsSizeDict * pSizeDict )
/*++
Routine Description :
Outputs the format string structure.
Arguments :
pStream - Stream to output the format string to.
--*/
{
long Offset;
long LastPrinted = 0;
char Buf[102];
BOOL InPP = FALSE;
REP_AS_PAD_EXPR_DESC * pPadExprDesc;
REP_AS_SIZE_DESC * pSizeDesc;
char * pComment;
BOOL fLimitErr = FALSE;
pStream->NewLine();
pStream->Write( "static const " );
pStream->Write( pTypeName );
pStream->Write( ' ' );
pStream->Write( pName );
pStream->Write( " =");
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( "0," );
pStream->NewLine();
pStream->Write( '{' );
pStream->IndentInc();
// Reset the pad and size macro dictionaries
pPadExprDesc = pPadDict->GetFirst();
pSizeDesc = pSizeDict->GetFirst();
pStream->IndentDec();
pStream->IndentDec();
pStream->IndentDec();
BOOL f32 = pCommand->GetEnv() == ENV_WIN32;
BOOL f64 = pCommand->GetEnv() == ENV_WIN64;
char * EnvComment;
if ( f32 )
{
EnvComment = Env32Comment;
}
else if ( f64 )
{
EnvComment = Env64Comment;
}
else
{
EnvComment = OtherEnvComment;
}
for ( Offset = 0; Offset < (long)LastOffset; )
{
pStream->NewLine();
pComment = CommentDict.GetComments( Offset );
if ( pComment )
pStream->Write( pComment );
if ( ! (Offset % 2) && ( Offset != LastPrinted ) )
{
sprintf(Buf,"/* %2d */\t",Offset);
LastPrinted = Offset;
pStream->Write(Buf);
}
else
{
pStream->Write("\t\t\t");
}
switch ( pBufferType[Offset] )
{
case FS_FORMAT_CHARACTER :
// Make the format string readable.
switch ( pBuffer[Offset] )
{
case FC_IN_PARAM :
case FC_IN_OUT_PARAM :
case FC_PARTIAL_IGNORE_PARAM :
case FC_OUT_PARAM :
case FC_RETURN_PARAM :
case FC_STRUCT :
case FC_PSTRUCT :
case FC_CSTRUCT :
case FC_CPSTRUCT :
case FC_CVSTRUCT :
case FC_BOGUS_STRUCT :
case FC_NO_REPEAT :
case FC_FIXED_REPEAT :
case FC_VARIABLE_REPEAT :
case FC_CARRAY :
case FC_CVARRAY :
case FC_SMFARRAY :
case FC_LGFARRAY :
case FC_SMVARRAY :
case FC_LGVARRAY :
case FC_BOGUS_ARRAY :
case FC_C_CSTRING :
case FC_C_SSTRING :
case FC_C_WSTRING :
case FC_CSTRING :
case FC_SSTRING :
case FC_WSTRING :
case FC_ENCAPSULATED_UNION :
case FC_NON_ENCAPSULATED_UNION :
case FC_IP :
pStream->NewLine();
pStream->Write("\t\t\t");
break;
case FC_RP :
case FC_UP :
case FC_OP :
case FC_FP :
//
// If we're not in a pointer layout, and the previous
// format char was not a param/result char then print
// a new line.
//
if ( ! InPP &&
( Offset &&
pBuffer[Offset - 1] != FC_IN_PARAM &&
pBuffer[Offset - 1] != FC_IN_OUT_PARAM &&
pBuffer[Offset - 1] != FC_PARTIAL_IGNORE_PARAM &&
pBuffer[Offset - 1] != FC_OUT_PARAM &&
pBuffer[Offset - 1] != FC_IN_PARAM_NO_FREE_INST &&
pBuffer[Offset - 1] != FC_RETURN_PARAM )
)
{
pStream->NewLine();
pStream->Write("\t\t\t");
}
break;
case FC_PP :
InPP = TRUE;
pStream->NewLine();
pStream->Write("\t\t\t");
break;
case FC_END :
if ( InPP )
{
pStream->NewLine();
pStream->Write("\t\t\t");
}
break;
default:
break;
}
pStream->Write( "0x" );
pStream->Write( MIDL_ITOA( pBuffer[Offset], Buf, 16 ) );
pStream->Write( ",\t\t/* ");
pStream->Write( pFormatCharNames[pBuffer[Offset]] );
pStream->Write( " */");
if ( (pBuffer[Offset] == FC_END) && InPP )
{
pStream->NewLine();
InPP = FALSE;
}
Offset++;
break;
case FS_POINTER_FORMAT_CHARACTER :
//
// If we're not in a pointer layout, and the previous
// format char was not a param/result char then print
// a new line.
//
if ( ! InPP &&
( Offset &&
pBuffer[Offset - 1] != FC_IN_PARAM &&
pBuffer[Offset - 1] != FC_IN_OUT_PARAM &&
pBuffer[Offset - 1] != FC_PARTIAL_IGNORE_PARAM &&
pBuffer[Offset - 1] != FC_OUT_PARAM &&
pBuffer[Offset - 1] != FC_RETURN_PARAM )
)
{
pStream->NewLine();
pStream->Write("\t\t\t");
}
pStream->Write( "0x" );
pStream->Write( MIDL_ITOA( pBuffer[Offset], Buf, 16 ) );
pStream->Write( ", 0x" );
pStream->Write( MIDL_ITOA( pBuffer[Offset + 1] & 0x00ff, Buf, 16 ) );
pStream->Write( ",\t/* ");
pStream->Write( pFormatCharNames[pBuffer[Offset]] );
Out_PointerFlags( pStream, pBuffer + Offset + 1 );
pStream->Write( " */");
Offset += 2;
break;
case FS_SMALL :
pStream->Write( "0x" );
pStream->Write( MIDL_ITOA( pBuffer[Offset] & 0x00ff, Buf, 16 ) );
pStream->Write( ",\t\t/* ");
pStream->Write( MIDL_ITOA( pBuffer[Offset], Buf, 10 ) );
pStream->Write( " */");
Offset++;
break;
case FS_OLD_PROC_FLAG_BYTE :
pStream->Write( "0x" );
pStream->Write( MIDL_ITOA( pBuffer[Offset] & 0x00ff, Buf, 16 ) );
pStream->Write( ",\t\t/* Old Flags: ");
Out_OldProcFlags( pStream, pBuffer + Offset );
pStream->Write( " */");
Offset++;
break;
case FS_Oi2_PROC_FLAG_BYTE :
pStream->Write( "0x" );
pStream->Write( MIDL_ITOA( pBuffer[Offset] & 0x00ff, Buf, 16 ) );
pStream->Write( ",\t\t/* Oi2 Flags: ");
Out_Oi2ProcFlags( pStream, pBuffer + Offset );
pStream->Write( " */");
Offset++;
break;
case FS_EXT_PROC_FLAG_BYTE :
pStream->Write( "0x" );
pStream->Write( MIDL_ITOA( pBuffer[Offset] & 0x00ff, Buf, 16 ) );
pStream->Write( ",\t\t/* Ext Flags: ");
Out_ExtProcFlags( pStream, pBuffer + Offset );
pStream->Write( " */");
Offset++;
break;
case FS_CORR_TYPE_BYTE :
pStream->Write( "0x" );
pStream->Write( MIDL_ITOA( pBuffer[Offset] & 0x00ff, Buf, 16 ) );
pStream->Write( ",\t\t/* Corr desc: ");
Out_CorrelationType( pStream, pBuffer + Offset );
pStream->Write( " */");
Offset++;
break;
case FS_CONTEXT_HANDLE_FLAG_BYTE :
pStream->Write( "0x" );
pStream->Write( MIDL_ITOA( pBuffer[Offset] & 0x00ff, Buf, 16 ) );
pStream->Write( ",\t\t/* Ctxt flags: ");
Out_ContextHandleFlags( pStream, pBuffer + Offset );
pStream->Write( " */");
Offset++;
break;
case FS_SHORT :
pStream->Write( "NdrFcShort( 0x" );
pStream->Write(
MIDL_ITOA( *((unsigned short UNALIGNED *)(pBuffer+Offset)), Buf, 16));
pStream->Write( " ),\t/* ");
pStream->Write(
MIDL_ITOA(*((short UNALIGNED *)(pBuffer+Offset)), Buf, 10));
pStream->Write( " */");
Offset += 2;
break;
case FS_MAGIC_UNION_SHORT :
pStream->Write( "NdrFcShort( 0x" );
pStream->Write(
MIDL_ITOA( *((unsigned short UNALIGNED *)(pBuffer+Offset)), Buf, 16));
pStream->Write( " ),\t/* Simple arm type: ");
pStream->Write( pFormatCharNames[ pBuffer[Offset] ]
? pFormatCharNames[ pBuffer[Offset] ]
: "" );
pStream->Write( " */");
Offset += 2;
break;
case FS_PARAM_FLAG_SHORT :
pStream->Write( "NdrFcShort( 0x" );
pStream->Write(
MIDL_ITOA( *((unsigned short UNALIGNED *)(pBuffer + Offset)), Buf, 16));
pStream->Write( " ),\t/* Flags: ");
Out_ParameterFlags( pStream, (PARAM_ATTRIBUTES *)(pBuffer + Offset) );
pStream->Write( " */");
Offset += 2;
break;
case FS_CORR_FLAG_SHORT :
pStream->Write( "NdrFcShort( 0x" );
pStream->Write(
MIDL_ITOA( *((unsigned short UNALIGNED *)(pBuffer + Offset)), Buf, 16));
pStream->Write( " ),\t/* Corr flags: ");
Out_CorrelationFlags( pStream, pBuffer + Offset );
pStream->Write( " */");
Offset += 2;
break;
case FS_SHORT_OFFSET :
{
// The relative type offset.
TypeOffsetDictElem * pTO;
long ItsOffset;
ItsOffset = *((short UNALIGNED *)(pBuffer + Offset));
pTO = TypeOffsetDict.LookupOffset( Offset );
if ( pTO->TypeOffset != ItsOffset ||
pTO->TypeOffset < UNION_OFFSET16_MIN )
{
pStream->Write( "Relative type offset out of range" );
pStream->NewLine();
RpcError(NULL, 0, FORMAT_STRING_LIMITS, "" );
fLimitErr = TRUE;
}
if ( 0 == ( pTO->TypeOffset + Offset ) ||
-1 == ( pTO->TypeOffset + Offset ) )
{
fprintf( stdout, " MIDL_fixup: Invalid offset at %d\n", Offset );
RpcError( NULL, 0, FORMAT_STRING_OFFSET_IS_ZERO, "" );
}
pStream->Write( "NdrFcShort( 0x" );
pStream->Write( MIDL_ITOA( ItsOffset, Buf, 16 ) );
pStream->Write( " ),\t/* Offset= ");
pStream->Write( MIDL_ITOA( pTO->TypeOffset, Buf, 10 ) );
pStream->Write( " (");
pStream->Write( MIDL_ITOA( pTO->TypeOffset + Offset, Buf, 10 ) );
pStream->Write( ") */");
Offset += 2;
}
break;
case FS_SHORT_TYPE_OFFSET :
{
// The absolute type offset.
TypeOffsetDictElem * pTO;
long ItsOffset;
ItsOffset = *((unsigned short UNALIGNED *)(pBuffer + Offset));
pTO = TypeOffsetDict.LookupOffset( Offset );
if ( pTO->TypeOffset != ItsOffset )
{
pStream->Write( "Type offset out of range" );
pStream->NewLine();
RpcError(NULL, 0, FORMAT_STRING_LIMITS, "" );
fLimitErr = TRUE;
}
if ( 0 == pTO->TypeOffset || -1 == pTO->TypeOffset )
{
fprintf( stdout, " MIDL_fixup: Invalid type offset at %d\n", Offset );
RpcError( NULL, 0, TYPE_OFFSET_IS_ZERO, "" );
}
pStream->Write( "NdrFcShort( 0x" );
pStream->Write( MIDL_ITOA( ItsOffset, Buf, 16 ) );
pStream->Write( " ),\t/* Type Offset=");
pStream->Write( MIDL_ITOA( pTO->TypeOffset, Buf, 10 ) );
pStream->Write( " */");
Offset += 2;
}
break;
case FS_SHORT_STACK_OFFSET :
{
Out_ShortStackOffset( pStream,
OffsetDict.LookupOffset( Offset ),
EnvComment );
Offset += 2;
break;
}
case FS_SMALL_STACK_SIZE :
{
Out_SmallStackSize( pStream,
pBuffer[Offset],
EnvComment );
Offset++;
break;
}
case FS_LONG :
pStream->Write( "NdrFcLong( 0x" );
pStream->Write(
MIDL_LTOA( *((long UNALIGNED *)(pBuffer+Offset)), Buf, 16));
pStream->Write( " ),\t/* ");
pStream->Write(
MIDL_LTOA(*((long UNALIGNED *)(pBuffer+Offset)), Buf, 10));
pStream->Write( " */");
Offset += 4;
break;
case FS_PAD_MACRO :
if ( pPadExprDesc )
{
MIDL_ASSERT( Offset == (long)pPadExprDesc->KeyOffset );
pPadDict->WriteCurrentPadDesc( pStream );
pPadExprDesc = pPadDict->GetNext();
}
else
{
pStream->Write( "0x0,\t\t/* macro */" );
MIDL_ASSERT( 0 && "Pad macro missing" );
}
Offset++;
break;
case FS_SIZE_MACRO :
if ( pSizeDesc )
{
MIDL_ASSERT( Offset == (long)pSizeDesc->KeyOffset );
pSizeDict->WriteCurrentSizeDesc( pStream );
pSizeDesc = pSizeDict->GetNext();
}
else
{
pStream->Write( "0x0, 0x0,\t\t// macro" );
MIDL_ASSERT( 0 && "Size macro missing" );
}
Offset += 2;
break;
case FS_UNKNOWN_STACK_SIZE :
{
char * LongBuf = Buf;
long NameLen = (long) strlen(
UnknownStackSizeDict.LookupTypeName( (long) Offset ));
if ( NameLen > 25 )
LongBuf = new char[ 75 + NameLen ];
sprintf(
LongBuf,
"%s ( (sizeof(%s) + %s) & ~ (%s) ),",
"(unsigned char)",
UnknownStackSizeDict.LookupTypeName( (long) Offset ),
"sizeof(int) - 1",
"sizeof(int) - 1" );
pStream->Write( LongBuf );
}
Offset++;
break;
}
}
pStream->NewLine( 2 );
//
// Spit out a terminating 0 so we don't ever fall off the end
// of the world.
//
pStream->Write( "\t\t\t0x0" );
pStream->IndentInc();
pStream->IndentInc();
pStream->IndentInc();
pStream->IndentDec();
pStream->NewLine();
pStream->Write( '}' );
pStream->IndentDec();
pStream->NewLine();
pStream->Write( "};" );
pStream->IndentDec();
pStream->NewLine();
if ( LastOffset > _UI16_MAX )
{
pStream->Write( "Total Format String size is too big." );
pStream->NewLine();
fprintf(stdout, "Total Format String size = %d\n", LastOffset );
RpcError(NULL, 0, FORMAT_STRING_LIMITS, "" );
fLimitErr = TRUE;
}
if ( fLimitErr )
exit( FORMAT_STRING_LIMITS );
}
long
FORMAT_STRING::OptimizeFragment(
CG_NDR * pNode )
/*++
Routine Description :
Optimize a format string fragment away.
Arguments :
pNode - CG_NDR node, with format string start
and end offsets already set.
--*/
{
long StartOffset = pNode->GetFormatStringOffset();
long EndOffset = pNode->GetFormatStringEndOffset();
FRMTREG_ENTRY NewFragment( StartOffset, EndOffset );
FRMTREG_ENTRY * pOldFragment;
// perform format string optimization
#if defined(RKK_FRAG_OPT)
{
printf("Optimizing: start=%d, end=%d\n", StartOffset, EndOffset);
printf(" off str=%d ", StartOffset );
for (int off = StartOffset; off <= EndOffset; off++)
printf("%02x ", pBuffer[ off ]);
printf( "\n" );
printf(" off typ=%d ", StartOffset );
for ( off = StartOffset; off <= EndOffset; off++)
printf("%02x ", pBufferType[ off ]);
printf( "\n" );
}
#endif
if ( pCommand->IsSwitchDefined( SWITCH_NO_FMT_OPT ) )
return StartOffset;
// We attempt to optimize fragments even if they are apart by more than 32k.
MIDL_ASSERT ( EndOffset <= (long)LastOffset );
// add to dictionary
// if match found, reset format string offset back to our start
if ( GetReuseDict()->GetReUseEntry( pOldFragment, &NewFragment ) )
{
long OldStartOffset = pOldFragment->GetStartOffset();
// if we are not the end, we can't do anything about ourselves
// similarly, if we match ourselves, don't do anything
if ( ( GetCurrentOffset() == EndOffset ) &&
( OldStartOffset != StartOffset ) )
{
// move format string offset back
SetCurrentOffset( StartOffset );
pNode->SetFormatStringOffset( OldStartOffset );
pNode->SetFormatStringEndOffset( pOldFragment->GetEndOffset() );
return OldStartOffset;
}
#if defined(RKK_FRAG_OPT)
else if ( GetCurrentOffset() != EndOffset )
{
printf( "OptimizeFragment fragment not at the end End=%d, frag End=%d\n",
GetCurrentOffset(), EndOffset );
}
#endif
} // duplicate found
return StartOffset;
}
unsigned short
FORMAT_STRING::RegisterFragment(
CG_NDR * pNode )
/*++
Routine Description :
Register, but do not remove, a format string fragment.
Arguments :
pNode - CG_NDR node, with format string start offset already set.
EndOffset - end offset of format string fragment
--*/
{
unsigned short StartOffset = (unsigned short)
pNode->GetFormatStringOffset();
unsigned short EndOffset = (unsigned short)
pNode->GetFormatStringEndOffset();
FRMTREG_ENTRY NewFragment( StartOffset, EndOffset );
FRMTREG_ENTRY * pOldFragment;
// perform format string optimization
if ( pCommand->IsSwitchDefined( SWITCH_NO_FMT_OPT ) )
return StartOffset;
MIDL_ASSERT( ( ((short) StartOffset) != -1 ) &&
( ((short) EndOffset) != -1 ) );
MIDL_ASSERT ( EndOffset <= LastOffset );
// add to dictionary, or return pointer to old entry
GetReuseDict()->GetReUseEntry( pOldFragment, &NewFragment );
return StartOffset;
}
char *
CommentDictionary::GetComments(
long Offset
)
{
CommentDictElem Elem;
CommentDictElem * pHead;
CommentDictElem * pElem;
Dict_Status DictStatus;
char * Comments;
long Length;
Elem.FormatStringOffset = Offset;
DictStatus = Dict_Find( &Elem );
if ( DictStatus != SUCCESS )
return 0;
pHead = (CommentDictElem *) Dict_Item();
Length = 0;
for ( pElem = pHead; pElem; pElem = pElem->Next )
Length += (long) strlen( pElem->Comment );
Comments = new char[Length+1];
Comments[0] = 0;
for ( pElem = pHead; pElem; pElem = pElem->Next )
strcat( Comments, pElem->Comment );
return Comments;
}
void
CommentDictionary::Insert(
long FormatStringOffset,
char * Comment
)
{
CommentDictElem Elem;
CommentDictElem * pHead;
CommentDictElem * pElem;
Dict_Status DictStatus;
Elem.FormatStringOffset = FormatStringOffset;
DictStatus = Dict_Find( &Elem );
if ( DictStatus == SUCCESS )
pHead = (CommentDictElem *) Dict_Item();
else
pHead = 0;
pElem = new CommentDictElem;
pElem->Next = pHead;
pElem->FormatStringOffset = FormatStringOffset;
pElem->Comment = Comment;
//
// We delete any current entry and add a new entry so that comments
// are always prepended to the list.
//
if ( pHead )
Dict_Delete( (pUserType *) &pHead );
Dict_Insert( pElem );
}