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.
 
 
 
 
 
 

1774 lines
44 KiB

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 1993 Microsoft Corporation
Module Name:
arrayndr.cxx
Abstract:
Contains routines for the generation of the new NDR format strings for
array types, and the new NDR marshalling and unmarshalling calls.
Notes:
History:
DKays Oct-1993 Created.
----------------------------------------------------------------------------*/
#include "becls.hxx"
#pragma hdrstop
//*************************************************************************
// CG_ARRAY
//*************************************************************************
BOOL
CG_ARRAY::GenNdrFormatArrayProlog( CCB * pCCB )
/*++
Routine Description :
Handles some common tasks for array Ndr format string generation.
Arguments :
pCCB - pointer to code control block
Return :
TRUE if format string generation should continue, FALSE if the format
string for the array has already been generated.
--*/
{
FORMAT_STRING * pFormatString;
CG_NDR * pChild;
if ( GetFormatStringOffset() != -1 )
return FALSE;
pFormatString = pCCB->GetFormatString();
pChild = (CG_NDR *) GetChild();
if ( pChild->IsArray() )
{
SetIsInMultiDim( TRUE );
((CG_ARRAY *)pChild)->SetIsInMultiDim( TRUE );
}
//
// If the array's element type is a structure, pointer, or another array
// then generate either it's description (structure/array) or it's
// pointee's description (pointer).
//
if ( pChild->IsStruct() ||
pChild->IsArray() ||
pChild->IsUnion() ||
(pChild->GetCGID() == ID_CG_INTERFACE_PTR) ||
pChild->IsXmitRepOrUserMarshal() )
{
pChild->GenNdrFormat( pCCB );
}
if ( pChild->IsPointer() && (pChild->GetCGID() != ID_CG_INTERFACE_PTR) )
{
// Only generate the pointee format string if the pointee is not a
// base type or non-sized string pointer.
if ( ! pChild->IsPointerToBaseType() &&
(pChild->GetCGID() != ID_CG_STRING_PTR) )
((CG_POINTER *)pChild)->GenNdrFormatPointee( pCCB );
}
SetFormatStringOffset( pFormatString->GetCurrentOffset() );
//
// For an array which has [unique] or [ptr] applied to it, we generate
// a format string description of a pointer to the array.
//
if ( GetPtrType() != PTR_REF )
{
pFormatString->PushFormatChar( GetPtrType() == PTR_UNIQUE ?
FC_UP : FC_FP );
pFormatString->PushByte( 0 );
pFormatString->PushShortOffset( (short) 2 );
}
//
// Check if this is a complex array.
//
if ( IsComplex() )
{
GenNdrFormatComplex( pCCB );
return FALSE;
}
// Push the type.
switch ( GetCGID() )
{
case ID_CG_ARRAY :
case ID_CG_VAR_ARRAY :
//
// Fixed and varying array's fill this in later when they know
// their size.
//
pFormatString->PushByte( 0 );
break;
case ID_CG_CONF_ARRAY :
pFormatString->PushFormatChar( FC_CARRAY );
break;
case ID_CG_CONF_VAR_ARRAY :
pFormatString->PushFormatChar( FC_CVARRAY );
break;
}
//
// Push the correct alignment value.
//
pFormatString->PushByte(
CvtAlignPropertyToAlign( pChild->IsUnion()
? AL_1
: pChild->GetWireAlignment() ) - 1 );
return TRUE;
}
void
CG_ARRAY::GenNdrFormatArrayLayout( CCB * pCCB )
{
FORMAT_STRING * pFormatString;
CG_NDR * pChild;
pFormatString = pCCB->GetFormatString();
pChild = (CG_NDR *) GetChild();
//
// See if we need to generate a pointer layout.
//
if ( (pChild->IsPointer() && (pChild->GetCGID() != ID_CG_INTERFACE_PTR)) ||
(pChild->IsStruct() && ((CG_STRUCT *)pChild)->HasPointer()) )
{
//
// Not home free yet. Even if the array has pointers, we only
// output a pointer layout if one of the following is true :
// 1. The array is a top level parameter.
// 2. The array is really a fabrication of a size or size length
// pointer (of structures which contain pointers).
// 3. The array is embedded in a complex or hard struct.
// Otherwise the array's pointer description will be in its structure's
// pointer layout.
//
// We also never generate a pointer layout for complex arrays.
//
// We know if it was fabricated from a size or size-length pointer
// if IsDupedSizePtr() is TRUE.
//
CG_NDR * pParent;
pParent = pCCB->GetCGNodeContext();
if ( pParent->IsProc() ||
(pParent->GetCGID() == ID_CG_COMPLEX_STRUCT) ||
(pParent->IsStruct() &&
((CG_STRUCT *)pParent)->IsHardStruct()) ||
IsDupedSizePtr()
)
{
if ( ! IsComplex() )
GenNdrFormatArrayPointerLayout( pCCB,
FALSE );
}
}
SetElementDescriptionOffset( pFormatString->GetCurrentOffset() );
//
// Now generate the element description.
//
if ( pChild->IsStruct() ||
pChild->IsArray() ||
pChild->IsUnion() ||
(pChild->GetCGID() == ID_CG_INTERFACE_PTR) ||
pChild->IsXmitRepOrUserMarshal() )
{
pFormatString->PushFormatChar( FC_EMBEDDED_COMPLEX );
// Not used.
pFormatString->PushByte( 0 );
// if embedded complex member has an offset zero, it
// almost certainly means that it is in a recursion
// that is not resolved yet. See structs for a solution.
//
// BUGBUG: this should work like for structs but
// I have no time to setup arrays correctly for the
// method fixing all such places.
// So, it needs to wait for better times.
//
// if ( pMember->GetFormatStringOffset() == 0 )
// {
// RegisterComplexEmbeddedForFixup(
// pMember,
// pFormatString->GetCurrentOffset() - GetInitialOffset() );
// }
//
pFormatString->PushShortOffset( pChild->GetFormatStringOffset() -
pFormatString->GetCurrentOffset() );
}
if ( pChild->IsPointer() && (pChild->GetCGID() != ID_CG_INTERFACE_PTR) )
{
//
// For complex arrays of pointers we put the actual pointer description
// in the layout, otherwise we put a long.
//
if ( IsComplex() )
{
((CG_POINTER *)pChild)->GenNdrFormatAlways( pCCB );
}
else
{
pFormatString->PushFormatChar( FC_LONG );
}
}
if ( pChild->IsSimpleType() )
{
pChild->GenNdrFormat( pCCB );
}
// Possibly align the format string and spit out the FC_END.
if ( ! (pFormatString->GetCurrentOffset() % 2) )
pFormatString->PushFormatChar( FC_PAD );
pFormatString->PushFormatChar( FC_END );
SetFormatStringEndOffset( pFormatString->GetCurrentOffset() );
}
void
CG_ARRAY::GenNdrFormatArrayPointerLayout( CCB * pCCB,
BOOL fNoPP )
/*++
Routine Description :
Generates the Ndr format string pointer layout for a conformant array.
Arguments :
pCCB - pointer to the code control block
fNoPP - TRUE if no FC_PP or FC_END should be generated
--*/
{
ITERATOR Iterator;
FORMAT_STRING * pFormatString;
CG_STRUCT * pStruct;
CG_NDR * pImbedingNode;
unsigned long MemOffsetToArray;
unsigned long BufOffsetToArray;
long ImbedingMemSize;
long ImbedingBufSize;
// Get the current imbeding sizes.
ImbedingMemSize = pCCB->GetImbedingMemSize();
ImbedingBufSize = pCCB->GetImbedingBufSize();
pFormatString = pCCB->GetFormatString();
pImbedingNode = pCCB->GetCGNodeContext();
MemOffsetToArray = ImbedingMemSize;
BufOffsetToArray = ImbedingBufSize;
if ( pImbedingNode->IsStruct() )
{
pStruct = (CG_STRUCT *) pImbedingNode;
if ( GetCGID() == ID_CG_CONF_ARRAY ||
GetCGID() == ID_CG_CONF_VAR_ARRAY )
{
; // Do nothing, imbeding sizes set offset right.
}
else // GetCGID() == ID_CG_ARRAY || ID_CG_VAR_ARRAY
{
CG_FIELD * pField;
//
// If we're embedded in a complex struct then we do nothing - our
// offset will end up being 0.
//
if ( pStruct->GetCGID() != ID_CG_COMPLEX_STRUCT )
{
pField = pStruct->GetArrayField( this );
//
// If we don't find the array's field, that's because the
// array must have been contained within a union which was
// part of a Hard Structure.
//
if ( pField )
{
//
// What has to be done here is to actually subract the
// difference between the struct's sizes and the field's
// offsets, since the array appears somewhere inside the
// struct whose size has already been added to the
// imbeding sizes.
//
MemOffsetToArray -= pStruct->GetMemorySize() -
pField->GetMemOffset();
BufOffsetToArray -= pStruct->GetWireSize() -
pField->GetWireOffset();
}
}
}
}
if ( ! fNoPP )
{
pFormatString->PushFormatChar( FC_PP );
pFormatString->PushFormatChar( FC_PAD );
}
//
// Stuff for fixed arrays.
//
if ( GetCGID() == ID_CG_ARRAY )
{
pFormatString->PushFormatChar( FC_FIXED_REPEAT );
pFormatString->PushFormatChar( FC_PAD );
pFormatString->PushShort( (short)
((CG_FIXED_ARRAY *)this)->GetNumOfElements() );
}
//
// Stuff for conformant arrays.
//
if ( GetCGID() == ID_CG_CONF_ARRAY )
{
pFormatString->PushFormatChar( FC_VARIABLE_REPEAT );
pFormatString->PushFormatChar( FC_FIXED_OFFSET );
}
//
// Stuff for conformant varying and varying arrays.
//
if ( GetCGID() == ID_CG_CONF_VAR_ARRAY ||
GetCGID() == ID_CG_VAR_ARRAY )
{
pFormatString->PushFormatChar( FC_VARIABLE_REPEAT );
pFormatString->PushFormatChar( FC_VARIABLE_OFFSET );
}
if ( GetChild()->IsPointer() &&
(GetChild()->GetCGID() != ID_CG_INTERFACE_PTR) )
{
CG_POINTER * pPointer;
pPointer = (CG_POINTER *) GetChild();
//
// Push the increment amount between successive pointers. In this
// case it's always 4.
//
pFormatString->PushShort( (short) sizeof(void *) );
// offset_to_array<2>
pFormatString->PushShort( (short) MemOffsetToArray );
// number_of_pointers<2>
pFormatString->PushShort( (short) 1 );
// offset_to_pointer_in_memory<2>
pFormatString->PushShort( (short) MemOffsetToArray );
// offset_to_pointer_in_buffer<2>
pFormatString->PushShort( (short) BufOffsetToArray );
// Push the pointer description.
pPointer->GenNdrFormatEmbedded( pCCB );
}
if ( GetChild()->IsStruct() )
{
ITERATOR Iterator;
CG_STRUCT * pStruct;
pStruct = (CG_STRUCT *) GetChild();
//
// Increment between successive pointers is the memory size of
// the structure.
//
pFormatString->PushShort( (short) pStruct->GetMemorySize() );
// offset_to_array<2>
pFormatString->PushShort( (short) MemOffsetToArray );
// number_of_pointers<2>
pFormatString->PushShort( (short) pStruct->GetNumberOfPointers() );
pStruct->GenNdrStructurePointerLayout( pCCB, TRUE, TRUE );
}
if ( GetChild()->IsUnion() )
assert(0);
if ( GetChild()->IsArray() )
assert(0);
if ( ! fNoPP )
pFormatString->PushFormatChar( FC_END );
SetFormatStringEndOffset( pFormatString->GetCurrentOffset() );
}
void
CG_ARRAY::GenNdrFormatComplex( CCB * pCCB )
{
FORMAT_STRING * pFormatString;
CG_NDR * pChild;
pFormatString = pCCB->GetFormatString();
pChild = (CG_NDR *) GetChild();
pFormatString->PushFormatChar( FC_BOGUS_ARRAY );
// Alignment.
pFormatString->PushByte(
CvtAlignPropertyToAlign( pChild->IsUnion()
? AL_1
: pChild->GetWireAlignment() ) - 1 );
//
// Number of elements - 0 if conformant.
//
switch ( GetCGID() )
{
case ID_CG_ARRAY :
pFormatString->PushShort( (short)
((CG_FIXED_ARRAY *)this)->GetNumOfElements() );
break;
case ID_CG_VAR_ARRAY :
pFormatString->PushShort( (short)
((CG_VARYING_ARRAY *)this)->GetNumOfElements() );
break;
default :
pFormatString->PushShort( (short) 0 );
break;
}
//
// Conformance description.
//
switch ( GetCGID() )
{
case ID_CG_CONF_ARRAY :
((CG_CONFORMANT_ARRAY *)this)->
GenFormatStringConformanceDescription( pCCB,
IsDupedSizePtr(),
IsInMultiDim() );
break;
case ID_CG_CONF_VAR_ARRAY :
((CG_CONFORMANT_VARYING_ARRAY *)this)->
GenFormatStringConformanceDescription( pCCB,
IsDupedSizePtr(),
IsInMultiDim() );
break;
default :
pFormatString->PushLong( 0xffffffff );
break;
}
//
// Variance description.
//
switch ( GetCGID() )
{
case ID_CG_CONF_VAR_ARRAY :
((CG_CONFORMANT_VARYING_ARRAY *)this)->
GenFormatStringVarianceDescription( pCCB,
IsDupedSizePtr(),
FALSE,
IsInMultiDim() );
break;
case ID_CG_VAR_ARRAY :
((CG_VARYING_ARRAY *)this)->
GenFormatStringVarianceDescription( pCCB,
FALSE,
TRUE,
IsInMultiDim() );
break;
default :
pFormatString->PushLong( 0xffffffff );
break;
}
GenNdrFormatArrayLayout( pCCB );
// optimize away duplicates
pFormatString->OptimizeFragment( this );
// This call needs some preparation that I have no time for.
// FixupEmbeddedComplex( pCCB );
}
long
CG_ARRAY::GetElementSize()
{
CG_NDR * pChild;
pChild = (CG_NDR *) GetChild();
if ( pChild->IsSimpleType() )
{
// Cheat a little. Size is equal to wire alignment value.
return CvtAlignPropertyToAlign( pChild->GetWireAlignment() );
}
if ( pChild->IsPointer() )
return sizeof( void * );
if ( pChild->IsStruct() )
return ((CG_STRUCT *)pChild)->GetMemorySize();
if ( pChild->IsArray() )
{
assert ( pChild->GetCGID() == ID_CG_ARRAY );
CG_FIXED_ARRAY * pArray = (CG_FIXED_ARRAY *) pChild;
return pArray->GetElementSize() * pArray->GetNumOfElements();
}
if ( pChild->GetCGID() == ID_CG_INTERFACE_PTR )
return sizeof( void * );
assert(0);
return 0; // for the compiler
}
BOOL
CG_ARRAY::IsComplex()
{
//
// If this is a conformant and/or varying array, then it becomes
// complex if it is part of a multidimensional array (but not a multi
// level sized pointer).
//
if ( (GetCGID() == ID_CG_CONF_ARRAY) ||
(GetCGID() == ID_CG_CONF_VAR_ARRAY) ||
(GetCGID() == ID_CG_VAR_ARRAY) )
{
if ( IsInMultiDim() && ! IsDupedSizePtr() )
return TRUE;
}
//
// Is the array complex by Ndr Engine standards. Any array of complex
// or hard structs, encapsulated unions, transmit_as or represent_as,
// enums, ref pointers, or another complex array, is complex.
//
// Any multidimensional array with at least one dimension with conformance
// or variance is complex as well.
//
switch ( ((CG_NDR *)GetChild())->GetCGID() )
{
case ID_CG_STRUCT :
return( ((CG_STRUCT *)GetChild())->IsComplexStruct() ||
((CG_STRUCT *)GetChild())->IsHardStruct() ||
GetWireSize() != GetMemorySize() );
case ID_CG_ARRAY :
switch ( GetCGID() )
{
case ID_CG_CONF_ARRAY :
case ID_CG_CONF_VAR_ARRAY :
case ID_CG_VAR_ARRAY :
return TRUE;
default :
//
// The array is complex if the next lower fixed array
// dimension is complex.
//
return ((CG_ARRAY *) GetChild())->IsComplex();
}
case ID_CG_COMPLEX_STRUCT :
case ID_CG_ENCAP_STRUCT :
case ID_CG_CONF_ARRAY :
case ID_CG_CONF_VAR_ARRAY :
case ID_CG_VAR_ARRAY :
case ID_CG_STRING_ARRAY :
case ID_CG_CONF_STRING_ARRAY :
case ID_CG_TRANSMIT_AS :
case ID_CG_REPRESENT_AS :
case ID_CG_USER_MARSHAL :
case ID_CG_INTERFACE_PTR :
return TRUE;
case ID_CG_ENUM :
//
// The array is complex only if this
// is an array of enum16.
//
return ! ((CG_ENUM *)GetChild())->IsEnumLong();
case ID_CG_CONF_STRUCT :
case ID_CG_CONF_VAR_STRUCT :
//
// These two are not possible and
// should be caught by the front end.
//
assert(0);
default :
//
// Make a final check for an array of ref pointers.
//
return GetChild()->IsPointer() &&
(((CG_POINTER *)GetChild())->GetPtrType() == PTR_REF);
}
}
BOOL
CG_ARRAY::IsMultiConfOrVar()
{
CG_NDR * pNdr;
switch ( GetCGID() )
{
case ID_CG_CONF_ARRAY :
case ID_CG_CONF_VAR_ARRAY :
case ID_CG_VAR_ARRAY :
break;
default :
return FALSE;
}
//
// Search for an inner dimension array other than fixed.
//
pNdr = (CG_NDR *) GetChild();
for ( ; pNdr && pNdr->IsArray(); pNdr = (CG_NDR *) pNdr->GetChild() )
{
if ( pNdr->GetCGID() == ID_CG_ARRAY )
continue;
else
return TRUE;
}
return FALSE;
}
BOOL
CG_ARRAY::ShouldFreeOffline()
{
CG_NDR * pChild;
pChild = (CG_NDR *) GetChild();
switch ( GetCGID() )
{
case ID_CG_STRING_ARRAY :
case ID_CG_CONF_STRING_ARRAY :
return FALSE;
default :
if ( pChild->IsSimpleType() )
return FALSE;
if ( pChild->IsStruct() )
return ((CG_STRUCT *)pChild)->ShouldFreeOffline();
if ( pChild->IsArray() )
return ((CG_ARRAY *)pChild)->ShouldFreeOffline();
return TRUE;
}
}
void
CG_ARRAY::GenFreeInline( CCB * pCCB )
{
CG_PARAM * pParam;
BOOL fFree;
fFree = FALSE;
pParam = (CG_PARAM *) pCCB->GetLastPlaceholderClass();
//
// Don't free a [unique] or [ptr] array inline.
//
if ( GetPtrType() != PTR_REF )
return;
if ( IsComplex() )
{
//
// If the array is complex then we must free it unless it is a
// fixed or varying array of ref pointers or an [out] fixed or varying
// array.
//
if ( ! pParam->IsParamIn() || GetBasicCGClass()->IsPointer() )
fFree = (GetCGID() == ID_CG_CONF_ARRAY) ||
(GetCGID() == ID_CG_CONF_VAR_ARRAY);
else
fFree = TRUE;
}
else
{
//
// For non complex arrays the rules are :
// Fixed - never free, we use the buffer.
// Conformant - free if [out] only.
// Conformant Varying - always free.
// Varying - free if [in] or [in,out].
//
// String array - free always.
// Conformant string array - free if sized.
//
switch ( GetCGID() )
{
case ID_CG_ARRAY :
break;
case ID_CG_CONF_ARRAY :
fFree = ! pParam->IsParamIn();
break;
case ID_CG_CONF_VAR_ARRAY :
fFree = TRUE;
break;
case ID_CG_VAR_ARRAY :
fFree = pParam->IsParamIn();
break;
case ID_CG_STRING_ARRAY :
fFree = TRUE;
break;
case ID_CG_CONF_STRING_ARRAY :
fFree = GetSizeIsExpr() != 0;
break;
}
}
if ( fFree )
Out_FreeParamInline( pCCB );
}
//*************************************************************************
// CG_FIXED_ARRAY
//*************************************************************************
void
CG_FIXED_ARRAY::GenNdrFormat( CCB * pCCB )
/*++
Routine Description :
Generates the Ndr format string for a fixed array.
Arguments :
pCCB - pointer to the code control block
--*/
{
FORMAT_STRING * pFormatString = pCCB->GetFormatString();
unsigned long ArraySize;
if ( ! GenNdrFormatArrayProlog( pCCB ) )
return;
assert( GetSizeIsExpr()->IsConstant() );
ArraySize = GetNumOfElements() * GetElementSize();
//
// If the array size is >= 64K then the format is different.
//
if ( ArraySize >= (64 * 1024) )
{
pFormatString->PushFormatChar( FC_LGFARRAY,
pFormatString->GetCurrentOffset() - 2 );
pFormatString->PushLong( ArraySize );
}
else
{
pFormatString->PushFormatChar( FC_SMFARRAY,
pFormatString->GetCurrentOffset() - 2 );
pFormatString->PushShort( (short) ArraySize );
}
GenNdrFormatArrayLayout( pCCB );
// optimize away duplicates
pFormatString->OptimizeFragment( this );
}
long
CG_FIXED_ARRAY::FixedBufferSize( CCB * pCCB )
{
CG_NDR * pNdr;
long BufSize;
long TotalSize;
pNdr = (CG_NDR *)GetChild();
// skip these nodes to get to the transmitted element type.
if ( pNdr->IsXmitRepOrUserMarshal() )
pNdr = (CG_NDR *)pNdr->GetChild();
if ( pNdr->IsPointer() && ((CG_POINTER *)pNdr)->IsPointerToBaseType() )
{
CG_POINTER * pPointer;
//
// Special case arrays of pointers to base types so that we
// don't grossly overestimate the buffer size.
//
pPointer = (CG_POINTER *) pNdr;
pNdr = (CG_NDR *) pNdr->GetChild();
BufSize = (pPointer->GetPtrType() == PTR_REF) ? 0 : 4;
BufSize += pNdr->GetWireSize();
return 8 + (GetNumOfElements() * BufSize);
}
if ( pNdr->IsStruct() || pNdr->IsArray() || pNdr->IsPointer() )
{
BufSize = pNdr->FixedBufferSize( pCCB );
if ( BufSize == -1 )
return -1;
// Success!
TotalSize = GetNumOfElements() * BufSize;
}
else
{
// Fixed array of basetypes.
TotalSize = 8 + GetWireSize();
}
return TotalSize;
}
//*************************************************************************
// CG_CONFORMANT_ARRAY
//*************************************************************************
void
CG_CONFORMANT_ARRAY::GenNdrFormat( CCB * pCCB )
/*++
Routine Description :
Generates the Ndr format string for a conformant or array.
Arguments :
pCCB - pointer to the code control block
--*/
{
FORMAT_STRING * pFormatString = pCCB->GetFormatString();
long ElementSize;
if ( ! GenNdrFormatArrayProlog( pCCB ) )
return;
ElementSize = GetElementSize();
if ( ElementSize >= (64 * 1024) )
{
fprintf(stderr,
"ERROR : Conformant array element too large for NDR engine.\n");
assert(0);
}
pFormatString->PushShort( ElementSize );
GenFormatStringConformanceDescription( pCCB,
IsDupedSizePtr(),
IsInMultiDim() );
GenNdrFormatArrayLayout( pCCB );
// optimize away duplicates
pFormatString->OptimizeFragment( this );
}
//*************************************************************************
// CG_CONFORMANT_VARYING_ARRAY
//*************************************************************************
void CG_CONFORMANT_VARYING_ARRAY::GenNdrFormat( CCB * pCCB )
/*++
Routine Description :
Generates the Ndr format string for a conformant varying array.
Arguments :
pCCB - pointer to the code control block
--*/
{
FORMAT_STRING * pFormatString = pCCB->GetFormatString();
long ElementSize;
if ( ! GenNdrFormatArrayProlog( pCCB ) )
return;
ElementSize = GetElementSize();
if ( ElementSize >= (64 * 1024) )
{
fprintf(stderr, "ERROR : Conformant varying array "
"element too large for NDR engine.\n");
assert(0);
}
pFormatString->PushShort( ElementSize );
GenFormatStringConformanceDescription( pCCB,
IsDupedSizePtr(),
IsInMultiDim() );
GenFormatStringVarianceDescription( pCCB,
IsDupedSizePtr(),
FALSE,
IsInMultiDim() );
GenNdrFormatArrayLayout( pCCB );
// optimize away duplicates
pFormatString->OptimizeFragment( this );
}
void CG_VARYING_ARRAY::GenNdrFormat( CCB * pCCB )
/*++
Routine Description :
Generates the Ndr format string for a varying array.
Arguments :
pCCB - pointer to the code control block
--*/
{
FORMAT_STRING * pFormatString = pCCB->GetFormatString();
long Elements;
long ElementSize;
long ArraySize;
if ( ! GenNdrFormatArrayProlog( pCCB ) )
return;
//
// Size must be constant.
//
if ( ! GetSizeIsExpr()->IsConstant() )
assert(0);
Elements = GetNumOfElements();
ElementSize = GetElementSize();
ArraySize = Elements * ElementSize;
//
// Check if this is a large varying array.
//
if ( ArraySize >= (64 * 1024) )
{
pFormatString->PushFormatChar( FC_LGVARRAY,
pFormatString->GetCurrentOffset() - 2 );
pFormatString->PushLong( ArraySize );
pFormatString->PushLong( Elements );
}
else
{
pFormatString->PushFormatChar( FC_SMVARRAY,
pFormatString->GetCurrentOffset() - 2 );
pFormatString->PushShort( ArraySize );
pFormatString->PushShort( Elements );
}
pFormatString->PushShort( ElementSize );
GenFormatStringVarianceDescription( pCCB,
FALSE,
TRUE,
FALSE );
GenNdrFormatArrayLayout( pCCB );
// optimize away duplicates
pFormatString->OptimizeFragment( this );
}
//*************************************************************************
// CG_STRING_ARRAY
//*************************************************************************
void CG_STRING_ARRAY::GenNdrFormat( CCB * pCCB )
/*++
Routine Description :
Generates the Ndr format string for a string array.
Arguments :
pCCB - pointer to the code control block
--*/
{
FORMAT_STRING * pFormatString;
if ( GetFormatStringOffset() != -1 )
return;
pFormatString = pCCB->GetFormatString();
SetFormatStringOffset( pFormatString->GetCurrentOffset() );
if ( IsStringableStruct() )
{
pFormatString->PushFormatChar( FC_SSTRING );
pFormatString->PushByte( ((CG_NDR *)GetChild())->GetWireSize() );
}
else
{
switch ( ((CG_BASETYPE *)GetChild())->GetFormatChar() )
{
case FC_CHAR :
case FC_BYTE :
pFormatString->PushFormatChar( FC_CSTRING );
break;
case FC_WCHAR :
pFormatString->PushFormatChar( FC_WSTRING );
break;
default :
assert(0);
}
pFormatString->PushFormatChar( FC_PAD );
}
assert( GetSizeIsExpr()->IsConstant() );
pFormatString->PushShort( GetSizeIsExpr()->GetValue() );
// optimize away duplicates
SetFormatStringEndOffset( pFormatString->GetCurrentOffset() );
pFormatString->OptimizeFragment( this );
}
void CG_CONFORMANT_STRING_ARRAY::GenNdrFormat( CCB * pCCB )
/*++
Routine Description :
Generates the Ndr format string for a conformant string array.
Arguments :
pCCB - pointer to the code control block
--*/
{
FORMAT_STRING * pFormatString;
if ( GetFormatStringOffset() != -1 )
return;
pFormatString = pCCB->GetFormatString();
SetFormatStringOffset( pFormatString->GetCurrentOffset() );
if ( IsStringableStruct() )
{
pFormatString->PushFormatChar( FC_C_SSTRING );
pFormatString->PushByte( ((CG_NDR *)GetChild())->GetWireSize() );
}
else
{
switch ( ((CG_BASETYPE *)GetChild())->GetFormatChar() )
{
case FC_CHAR :
case FC_BYTE :
pFormatString->PushFormatChar( FC_C_CSTRING );
break;
case FC_WCHAR :
pFormatString->PushFormatChar( FC_C_WSTRING );
break;
default :
assert(0);
}
}
if ( GetSizeIsExpr() )
{
pFormatString->PushFormatChar( FC_STRING_SIZED );
if ( IsStringableStruct() )
pFormatString->PushFormatChar( FC_PAD );
//
// Set the IsPointer parameter to FALSE.
//
GenFormatStringConformanceDescription( pCCB, FALSE, IsInMultiDim() );
}
else
{
if ( ! IsStringableStruct() )
pFormatString->PushFormatChar( FC_PAD );
}
// optimize away duplicates
SetFormatStringEndOffset( pFormatString->GetCurrentOffset() );
pFormatString->OptimizeFragment( this );
}
//*************************************************************************
// Alignment methods.
//*************************************************************************
void
CG_ARRAY::SetNextNdrAlignment( CCB * pCCB )
{
CG_NDR * pChild;
if ( IsComplex() )
{
pCCB->SetNdrAlignment( NDR_ALWC1 );
return;
}
if ( GetCGID() == ID_CG_ARRAY )
{
if ( HasPointer() )
pCCB->SetNdrAlignment( NDR_ALWC1 );
else
pCCB->SetNextNdrAlignment( GetWireSize() );
return;
}
pChild = (CG_NDR *) GetChild();
pCCB->SetNdrAlignment( NDR_ALWC4 );
pCCB->NdrAlignmentAction( GetWireAlignment() );
pChild->SetNextNdrAlignment( pCCB );
}
void
CG_STRING_ARRAY::SetNextNdrAlignment( CCB * pCCB )
{
CG_BASETYPE * pChild = (CG_BASETYPE *) GetChild();
pCCB->SetNdrAlignment( pChild->GetFormatChar() == FC_WCHAR ?
NDR_ALWC2 : NDR_ALWC1 );
}
void
CG_CONFORMANT_STRING_ARRAY::SetNextNdrAlignment( CCB * pCCB )
{
CG_BASETYPE * pChild = (CG_BASETYPE *) GetChild();
pCCB->SetNdrAlignment( pChild->GetFormatChar() == FC_WCHAR ?
NDR_ALWC2 : NDR_ALWC1 );
}
//*************************************************************************
// CG_CONF_ATTRIBUTE
//*************************************************************************
void
CG_CONF_ATTRIBUTE::GenFormatStringConformanceDescription(
CCB * pCCB,
BOOL IsPointer,
BOOL IsMultiDArray )
/*++
Routine Description :
Generates the conformace description field for a conformant (varying)
array.
Arguments :
pCCB - pointer to the code control block
--*/
{
GenNdrFormatAttributeDescription( pCCB,
GetMinIsExpr(),
GetSizeIsExpr(),
IsPointer,
FALSE,
FALSE,
IsMultiDArray );
}
//*************************************************************************
// CG_VARY_ATTRIBUTE
//*************************************************************************
void
CG_VARY_ATTRIBUTE::GenFormatStringVarianceDescription(
CCB * pCCB,
BOOL IsPointer,
BOOL IsVaryingArray,
BOOL IsMultiDArray )
/*++
Routine Description :
Generates the variance description for a (conformant) varying array.
Arguments :
pCCB - pointer to the code control block
IsPointer - TRUE if the array is actually a length_is pointer
IsVaryingArray - TRUE if the array is varying only
--*/
{
GenNdrFormatAttributeDescription( pCCB,
GetFirstIsExpr(),
GetLengthIsExpr(),
IsPointer,
FALSE,
IsVaryingArray,
IsMultiDArray );
}
void
GenNdrFormatAttributeDescription( CCB * pCCB,
expr_node * pMinExpr,
expr_node * pSizeExpr,
BOOL IsPointer,
BOOL IsUnion,
BOOL IsVaryingArray,
BOOL IsMultiDArray )
/*++
Routine Description :
Generates the conformance, variance, switch_is, or iid_is description for
an array, pointer, union, or interface pointer.
Arguments :
pCCB - Pointer to code control block.
pMinExpr - Either the min_is expression (conformance), first_is
expression (variance), or 0 for a switch_is (union)
or iid_is (interface pointer).
pSizeExpr - Either the size_is (conformance), length_is (variance),
switch_is (union), or iid_is (interface pointer) expression.
IsPointer - Is the conformance or variance a pointer attribute.
IsUnion - Are we generating a switch_is description.
--*/
{
FORMAT_STRING * pFormatString;
node_skl * pAttributeNodeType;
long Offset;
FORMAT_CHARACTER Op;
unsigned char Type;
pFormatString = pCCB->GetFormatString();
//
// Make sure the min_is() or first_is() is constant 0.
// The pMinExpr is NULL if we're handling a union's switch_is.
//
if ( pMinExpr )
{
if ( ! pMinExpr->IsConstant() )
goto ComplexAttribute;
else
if ( ((expr_constant *)pMinExpr)->GetValue() != 0 )
goto ComplexAttribute;
}
if ( pSizeExpr->IsConstant() )
{
long Size;
pFormatString->PushByte( FC_CONSTANT_CONFORMANCE );
Size = ((expr_constant *)pSizeExpr)->GetValue();
//
// We push the lower 24 bits of the constant size.
//
pFormatString->PushByte( (char) ((Size & 0x00ff0000) >> 16) );
pFormatString->PushShort( (short) (Size & 0x0000ffff) );
return;
}
if ( pSizeExpr->IsAVariable() )
{
Op = FC_ZERO;
pAttributeNodeType = pSizeExpr->GetType();
}
else
{
expr_node * pLeftExpr;
expr_node * pRightExpr;
OPERATOR Operator;
if ( pSizeExpr->IsBinaryOperator() )
{
pLeftExpr = ((expr_op_binary *)pSizeExpr)->GetLeft();
pRightExpr = ((expr_op_binary *)pSizeExpr)->GetRight();
}
else
if ( pSizeExpr->IsUnaryOperator() )
pLeftExpr = ((expr_op_unary *)pSizeExpr)->GetLeft();
else
goto ComplexAttribute;
switch ( Operator = ((expr_operator *)pSizeExpr)->GetOperator() )
{
case OP_SLASH :
case OP_STAR :
if ( pLeftExpr->IsAVariable() &&
pRightExpr->IsConstant() &&
((expr_constant *)pRightExpr)->GetValue() == 2 )
{
Op = ((Operator == OP_SLASH) ? FC_DIV_2 : FC_MULT_2);
pAttributeNodeType = pLeftExpr->GetType();
}
else
{
goto ComplexAttribute;
}
break;
case OP_PLUS :
case OP_MINUS :
if ( ( pLeftExpr->IsAVariable() &&
pRightExpr->IsConstant() &&
((expr_constant *)pRightExpr)->GetValue() == 1 ) ||
( pRightExpr->IsAVariable() &&
pLeftExpr->IsConstant() &&
((expr_constant *)pLeftExpr)->GetValue() == 1 ) )
{
Op = ((Operator == OP_PLUS) ? FC_ADD_1 : FC_SUB_1);
pAttributeNodeType = pLeftExpr->GetType();
}
else
{
goto ComplexAttribute;
}
break;
case OP_UNARY_INDIRECTION :
if ( ! pLeftExpr->IsAVariable() )
goto ComplexAttribute;
pAttributeNodeType = pLeftExpr->GetType();
Op = FC_DEREFERENCE;
break;
default :
goto ComplexAttribute;
}
}
// Will hold the switch_is node.
CG_NDR * pSwitchNode;
//
// Check if this is top level conformance.
//
if ( pCCB->GetCGNodeContext()->IsProc() )
{
CG_PROC * pProc;
CG_PARAM * pParam;
CG_ITERATOR Iterator;
pProc = (CG_PROC *) pCCB->GetCGNodeContext();
if ( (pProc->GetOptimizationFlags() & OPTIMIZE_SIZE) &&
IsMultiDArray )
Type = FC_TOP_LEVEL_MULTID_CONFORMANCE;
else
Type = FC_TOP_LEVEL_CONFORMANCE;
pProc->GetMembers( Iterator );
//
// Find out the type of the attribute descriptor.
//
while ( ITERATOR_GETNEXT( Iterator, pParam ) )
{
pSwitchNode = (CG_NDR *) pParam->GetChild();
if ( pParam->GetType() == pAttributeNodeType )
{
//
// Get the actual base type if the attribute is a dereference.
//
if ( Op == FC_DEREFERENCE )
pSwitchNode = (CG_NDR *) pSwitchNode->GetChild();
//
// Iid_is check.
//
if ( pSwitchNode->IsPointer() )
{
Type |= FC_LONG;
break;
}
Type |= ((CG_BASETYPE *)pSwitchNode)->GetSignedFormatChar();
break;
}
}
if ( IsPointer && IsMultiDArray &&
(pProc->GetOptimizationFlags() & OPTIMIZE_SIZE) )
{
CG_QUALIFIED_POINTER * pSizePointer;
pSizePointer = pCCB->GetCurrentSizePointer();
pFormatString->PushByte( Type );
pFormatString->PushFormatChar( Op );
pFormatString->PushShort( pSizePointer->GetDimension() );
}
else
{
pFormatString->PushByte( Type );
pFormatString->PushFormatChar( Op );
pFormatString->PushShortStackOffset(
(short) pParam->GetStackOffset( pCCB, I386_STACK_SIZING ),
(short) pParam->GetStackOffset( pCCB, ALPHA_STACK_SIZING ),
(short) pParam->GetStackOffset( pCCB, MIPS_STACK_SIZING ),
(short) pParam->GetStackOffset( pCCB, PPC_STACK_SIZING ),
(short) pParam->GetStackOffset( pCCB, MAC_STACK_SIZING )
);
}
}
else // structure cg class
{
CG_STRUCT * pStruct;
CG_FIELD * pField;
CG_ITERATOR Iterator;
if ( IsPointer )
Type = FC_POINTER_CONFORMANCE;
else
Type = FC_NORMAL_CONFORMANCE;
pStruct = (CG_STRUCT *) pCCB->GetCGNodeContext();
pStruct->GetMembers( Iterator );
while ( ITERATOR_GETNEXT( Iterator, pField ) )
{
pSwitchNode = (CG_NDR *) pField->GetChild();
if ( (pField->GetType() == pAttributeNodeType) &&
! pField->GetSizeIsDone() )
{
pField->SetSizeIsDone( TRUE );
//
// Get the actual base type if the attribute is a dereference.
//
if ( Op == FC_DEREFERENCE )
pSwitchNode = (CG_NDR *) pSwitchNode->GetChild();
//
// Iid_is check.
//
if ( pSwitchNode->IsPointer() )
{
Type |= FC_LONG;
break;
}
Type |= ((CG_BASETYPE *)pSwitchNode)->GetSignedFormatChar();
break;
}
}
//
// Offset to the attribute field in the structure. Below are
// the three possible ways to compute the offset, with the order
// of precedence.
//
// For pointers (either sized pointers, or a pointer to a union)
// this is a positive offset from the beginning of the structure.
// For imbeded unions this is the offset from the union's position
// in the structure to the attribute's position.
// For conformant (varying) arrays it's a negative offset from the
// end of the structure.
//
if ( IsPointer )
Offset = pField->GetMemOffset();
else
{
if ( IsUnion || IsVaryingArray )
{
CG_FIELD * pUnionField;
pUnionField = (CG_FIELD *) pCCB->GetLastPlaceholderClass();
Offset = pField->GetMemOffset() -
pUnionField->GetMemOffset();
}
else
{
Offset = pField->GetMemOffset() -
pStruct->GetMemorySize();
}
}
pFormatString->PushByte( Type );
pFormatString->PushFormatChar( Op );
pFormatString->PushShort( Offset );
}
return;
ComplexAttribute:
char * PrintPrefix = "";
CG_NDR * pNdr;
pNdr = pCCB->GetCGNodeContext();
//
// If this is a top level attribute and we're compiling /Os then we
// don't need the callback since the expression is computed inline in
// the stub.
//
if ( pNdr->IsProc() &&
(((CG_PROC *)pNdr)->GetOptimizationFlags() & OPTIMIZE_SIZE) )
{
pFormatString->PushByte(
IsMultiDArray ?
FC_TOP_LEVEL_MULTID_CONFORMANCE : FC_TOP_LEVEL_CONFORMANCE );
pFormatString->PushByte( 0 );
pFormatString->PushShort( (short) 0 );
}
else
{
long Displacement;
if ( pCCB->GetCGNodeContext()->IsProc() )
Displacement = 0;
else
{
CG_STRUCT * pStruct;
CG_FIELD * pField;
CG_NDR * pNdr;
// Get the imbeding struct.
pStruct = (CG_STRUCT *) pCCB->GetCGNodeContext();
// Get the field whose attribute we're handling.
pField = (CG_FIELD *) pCCB->GetLastPlaceholderClass();
//
// Set the PrintPrefix string correctly.
//
PrintPrefix = pField->GetPrintPrefix();
pNdr = (CG_NDR *) pField->GetChild();
switch ( pNdr->GetCGID() )
{
case ID_CG_CONF_ARRAY :
case ID_CG_CONF_VAR_ARRAY :
case ID_CG_CONF_STRING_ARRAY :
// Displacement is imbeding struct's size.
Displacement = pStruct->GetMemorySize();
break;
case ID_CG_VAR_ARRAY :
case ID_CG_STRING_ARRAY :
case ID_CG_ENCAP_STRUCT :
case ID_CG_UNION :
// Displacement is imbeded node's offset in the struct.
Displacement = pField->GetMemOffset();
break;
default :
Displacement = 0;
break;
}
}
GenNdrFormatComplexAttributeDescription( pCCB,
pMinExpr,
pSizeExpr,
Displacement,
PrintPrefix,
IsPointer );
}
}
void
GenNdrFormatComplexAttributeDescription( CCB * pCCB,
expr_node * pMinExpr,
expr_node * pSizeExpr,
long StackTopDisplacement,
char * PrintPrefix,
BOOL IsPointer )
/*++
Routine description:
This routine generates
- an auxuliary routine that evaluates a complicated expression.
- a description of the callback call into the current code stream.
The routine has the following signature:
void <name>( PMIDL_STUB_MESSAGE pStubMsg );
The description is as follows (takes 4 bytes):
0, FC_CALLBACK, <<routine_index>>
The naming convention for the routine is currently as follows
<name> is <proc_or_struct_name>exprEval_<routine_index>
Routine generation is postponed by using a Registry object.
Arguments:
pCCB - ptr to the code control block
pMinExpr - pointer to an expression tree, relates to min_is, first_is
pSizeExpr - pointer to an expression tree, relates to size_is, max_is etc.
StackTopDisplacement - For an attribute expression on a field in a
a structure, this is the number of bytes to
subtract from StackTop to get the proper
structure pointer.
PrinfPrefix - The prefix to print after "pS->" when accessing a field.
IsPointer - Is this a description for an attribute on a pointer
The interpretation of the two input expressions (pMinExpr and pSizeExpr)
is such that when both of them are present, it is enough to take
the difference to come up with the proper sizing.
The algorithm used here is thus as follows:
pMin pSize
NULL NULL impossible (assert)
!=NULL NULL impossible (assert)
NULL !=NULL Generate a routine that evaluates the following:
pStubMsg->Offset = 0
pStubMsg->MaxCount = eval(pSize)
!=NULL !=NULL Generate a routine that evaluates the following:
pStubMsg->Offset = eval(pMin)
pStubMsg->MaxCount = eval(pSize) - pStubMsg->Offset
Returns:
--*/
{
assert( pSizeExpr != NULL );
// Make the name of the routine and put it into the table.
// Each call to the routine we are in right now will create a new entry
// in the ExprEval routine table.
CG_NDR * pContainer = pCCB->GetCGNodeContext();
unsigned short Index = (unsigned short)
(pCCB->GetExprEvalIndexMgr()->GetIndex() - 1);
char * pContainerName = pContainer->GetType()->GetSymName();
char * pName = new char[ strlen(pCCB->GetInterfaceName()) +
1 + // "_"
strlen(pContainerName) +
sizeof("ExprEval_0000") + 1 ];
strcpy( pName, pCCB->GetInterfaceName() );
strcat( pName, "_" );
strcat( pName, pContainerName );
strcat( pName, "ExprEval_" );
char * pBuf = pName + strlen(pName);
sprintf( pBuf, "%04x", Index );
pCCB->GetExprEvalIndexMgr()->Lookup( pName );
// generate the description of the callback
// If this is a top level attribute we note that in the description.
if ( pCCB->GetCGNodeContext()->IsProc() )
pCCB->GetFormatString()->PushByte(FC_TOP_LEVEL_CONFORMANCE);
else
if ( IsPointer )
pCCB->GetFormatString()->PushByte(FC_POINTER_CONFORMANCE);
else
pCCB->GetFormatString()->PushByte(0);
pCCB->GetFormatString()->PushFormatChar( FC_CALLBACK );
pCCB->GetFormatString()->PushShort( (short) Index );
// Register the routine to be generated for future use.
EXPR_EVAL_CONTEXT * pExprEvalContext = new EXPR_EVAL_CONTEXT;
pExprEvalContext->pContainer = pContainer;
pExprEvalContext->pMinExpr = pMinExpr;
pExprEvalContext->pSizeExpr = pSizeExpr;
pExprEvalContext->pRoutineName = pName;
pExprEvalContext->pPrintPrefix = PrintPrefix;
pExprEvalContext->Displacement = StackTopDisplacement;
pCCB->RegisterExprEvalRoutine( (node_skl *) pExprEvalContext );
}