NT4/private/rpc/midl20/codegen/stcls.cxx
2020-09-30 17:12:29 +02:00

681 lines
16 KiB
C++

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 1989 Microsoft Corporation
Module Name:
stcls.cxx
Abstract:
Implementation of offline methods for the structure code generation
classes.
Notes:
History:
Oct-1993 DKays Created.
----------------------------------------------------------------------------*/
#include "becls.hxx"
#pragma hdrstop
CG_ARRAY *
CG_CONFORMANT_STRUCT::GetConformantArray()
/*++
Routine Description :
Gets the conformant (varying/string) class pointer for a conformant
structure.
Arguments :
None.
--*/
{
CG_NDR * pConf;
if ( ! pConfFld )
return 0;
pConf = (CG_NDR *) pConfFld->GetChild();
for (;;)
{
if ( pConf->GetCGID() == ID_CG_CONF_ARRAY ||
pConf->GetCGID() == ID_CG_CONF_VAR_ARRAY ||
pConf->GetCGID() == ID_CG_CONF_STRING_ARRAY )
break;
if ( pConf->IsXmitRepOrUserMarshal() )
{
pConf = (CG_NDR *)pConf->GetChild();
continue;
}
// else
pConf = (CG_NDR *)
((CG_CONFORMANT_STRUCT *)pConf)->GetConformantField();
pConf = (CG_NDR *) pConf->GetChild();
}
return (CG_ARRAY *) pConf;
}
CG_FIELD *
CG_STRUCT::GetFinalField()
{
CG_ITERATOR Iterator;
CG_FIELD * pField;
CG_NDR * pNdr;
GetMembers( Iterator );
//
// Get the last field.
//
while ( ITERATOR_GETNEXT( Iterator, pField ) )
;
pNdr = (CG_NDR *) pField->GetChild();
if ( pNdr->IsStruct() )
pField = ((CG_STRUCT *)pNdr)->GetFinalField();
return pField;
}
CG_FIELD *
CG_STRUCT::GetArrayField( CG_ARRAY * pArray )
{
CG_ITERATOR Iterator;
CG_FIELD * pField;
CG_NDR * pNdr;
GetMembers( Iterator );
while ( ITERATOR_GETNEXT( Iterator, pField ) )
{
pNdr = (CG_NDR *) pField->GetChild();
if ( pNdr == pArray )
return pField;
//
// Search inside of other structs only.
//
if ( pNdr->IsStruct() )
{
if ( (pField = ((CG_STRUCT *)pNdr)->GetArrayField(pArray)) != 0 )
return pField;
}
}
// Didn't find it.
return 0;
}
BOOL
CG_STRUCT::IsHardStruct()
{
// Always return FALSE until after PPC Update.
return FALSE;
}
BOOL
CG_STRUCT::IsHardStructOld()
{
CG_ITERATOR Iterator;
CG_FIELD * pField;
CG_FIELD * pPrevField;
//
// Cannot have a conformant array of any kind.
//
if ( (GetCGID() == ID_CG_CONF_STRUCT) ||
(GetCGID() == ID_CG_CONF_VAR_STRUCT) )
return FALSE;
//
// Cannot have pointers.
//
if ( HasPointer() )
return FALSE;
//
// Can't have more than one enum16.
//
if ( GetNumberOfEnum16s() > 1 )
return FALSE;
//
// Can't have padding in the middle of the struct that differs in
// memory and on the wire.
//
GetMembers( Iterator );
pPrevField = 0;
//
// Get the last field.
//
while ( ITERATOR_GETNEXT( Iterator, pField ) )
{
if ( pField->GetSibling() )
pPrevField = pField;
}
//
// Check if the last field in the struct has a different memory and wire
// offset. However, if there is a single union as the last field then
// we have to check the second to last fields's mem and wire offsets
// instead since a union's field's wire offsets are not accurate.
//
if ( pField->GetChild()->IsUnion() && pPrevField )
pField = pPrevField;
// This is complex.
if ( pField->GetMemOffset() != pField->GetWireOffset() )
return FALSE;
//
// Can have at most one union as the last field only.
//
switch ( GetNumberOfUnions() )
{
case 0 :
break;
case 1 :
//
// The last field must be the union.
//
if ( ! GetFinalField()->GetChild()->IsUnion() )
return FALSE;
else
return TRUE;
break;
default :
return FALSE;
}
//
// Now check again if we have just one enum16.
//
if ( GetNumberOfEnum16s() == 1 )
return TRUE;
//
// Check for end padding, which is ok for a hard struct.
//
if ( GetMemorySize() > GetWireSize() )
return TRUE;
//
// It must be a nice struct.
//
return FALSE;
}
BOOL
CG_STRUCT::HasAFixedBufferSize()
{
CG_ITERATOR Iterator;
CG_FIELD * pField;
GetMembers( Iterator );
while ( ITERATOR_GETNEXT( Iterator, pField ) )
{
if ( !pField->HasAFixedBufferSize() )
return FALSE;
}
return TRUE;
}
BOOL
CG_STRUCT::IsComplexStruct()
{
CG_ITERATOR Iterator;
CG_FIELD * pField;
CG_FIELD * pPrevField;
CG_NDR * pNdr;
BOOL IsConformant;
IsConformant = (GetCGID() == ID_CG_CONF_STRUCT) ||
(GetCGID() == ID_CG_CONF_VAR_STRUCT);
switch ( GetNumberOfEnum16s() )
{
case 0 :
break;
case 1 :
if ( HasPointer() || IsConformant )
return TRUE;
break;
default :
return TRUE;
}
switch ( GetNumberOfUnions() )
{
case 0 :
break;
case 1 :
if ( ! GetFinalField()->GetChild()->IsUnion() ||
HasPointer() ||
IsConformant )
return TRUE;
break;
default :
return TRUE;
}
if ( (GetMemorySize() > GetWireSize()) && (HasPointer() || IsConformant) )
return TRUE;
GetMembers( Iterator );
pPrevField = 0;
//
// Check if there are any embedded structs or arrays which are
// complex.
//
while ( ITERATOR_GETNEXT( Iterator, pField ) )
{
pNdr = (CG_NDR *) pField->GetChild();
if ( pNdr->IsArray() && ((CG_ARRAY *)pNdr)->IsComplex() )
return TRUE;
if ( pNdr->IsStruct() && ((CG_STRUCT *)pNdr)->IsComplexStruct() )
return TRUE;
if ( pField->GetSibling() )
pPrevField = pField;
}
//
// If the last field in the structure has a memory offset not equal
// to the buffer offset then the struct's memory alignment is different
// then the natural buffer alignment and we must make it complex.
//
// However, if there is a single union as the last field then we have to
// check the second to last fields's mem and wire offsets instead since
// a union's field's wire offsets are not accurate.
//
// Otherwise, if that is not true at this point then the structure is
// not complex.
//
if ( pField->GetChild()->IsUnion() && pPrevField )
pField = pPrevField;
return (pField->GetMemOffset() != pField->GetWireOffset()) ||
IsHardStructOld();
}
long
CG_STRUCT::GetNumberOfPointers()
{
CG_ITERATOR Iterator;
CG_FIELD * pField;
CG_NDR * pMember;
long Count;
Count = 0;
GetMembers(Iterator);
while ( ITERATOR_GETNEXT( Iterator, pField ) )
{
pMember = (CG_NDR *) pField->GetChild();
if ( pMember->IsPointer() &&
(pMember->GetCGID() != ID_CG_INTERFACE_PTR) )
Count++;
if ( pMember->IsStruct() )
Count += ((CG_STRUCT *)pMember)->GetNumberOfPointers();
}
return Count;
}
long
CG_STRUCT::GetNumberOfEnum16s()
{
CG_ITERATOR Iterator;
CG_FIELD * pField;
CG_NDR * pNdr;
long Count;
long Weight;
Count = 0;
GetMembers(Iterator);
while ( ITERATOR_GETNEXT( Iterator, pField ) )
{
pNdr = (CG_NDR *) pField->GetChild();
//
// If an array contains a enum16 we count it as 100 enum16s, since
// this routine is only interested in small enum16 counts.
//
if ( pNdr->IsArray() )
{
pNdr = (CG_NDR *) pNdr->GetChild();
while ( pNdr->IsArray() )
pNdr = (CG_NDR *) pNdr->GetChild();
Weight = 100;
}
else
Weight = 1;
if ( pNdr->IsSimpleType() &&
(((CG_BASETYPE *)pNdr)->GetFormatChar() == FC_ENUM16) )
Count += Weight;
if ( pNdr->IsStruct() )
Count += Weight * ((CG_STRUCT *)pNdr)->GetNumberOfEnum16s();
}
return Count;
}
long
CG_STRUCT::GetNumberOfUnions()
{
CG_ITERATOR Iterator;
CG_FIELD * pField;
CG_NDR * pNdr;
long Count;
long Weight;
Count = 0;
GetMembers(Iterator);
while ( ITERATOR_GETNEXT( Iterator, pField ) )
{
pNdr = (CG_NDR *) pField->GetChild();
//
// If an array contains a union we count it as 100 unions, since
// this routine is only interested in small union counts.
//
if ( pNdr->IsArray() )
{
pNdr = (CG_NDR *) pNdr->GetChild();
while ( pNdr->IsArray() )
pNdr = (CG_NDR *) pNdr->GetChild();
Weight = 100;
}
else
Weight = 1;
if ( (pNdr->GetCGID() == ID_CG_UNION) ||
(pNdr->GetCGID() == ID_CG_ENCAP_STRUCT) )
Count += Weight;
if ( pNdr->IsStruct() )
Count += Weight * ((CG_STRUCT *)pNdr)->GetNumberOfUnions();
}
return Count;
}
long
CG_STRUCT::GetEnum16Offset()
{
CG_ITERATOR Iterator;
CG_FIELD * pField;
CG_NDR * pNdr;
assert( GetNumberOfEnum16s() == 1 );
GetMembers( Iterator );
//
// Search for the enum.
//
while ( ITERATOR_GETNEXT( Iterator, pField ) )
{
pNdr = (CG_NDR *) pField->GetChild();
if ( pNdr->IsSimpleType() &&
(((CG_BASETYPE *)pNdr)->GetFormatChar() == FC_ENUM16) )
return pField->GetMemOffset();
if ( pNdr->IsStruct() &&
(((CG_STRUCT *)pNdr)->GetNumberOfEnum16s() == 1) )
return pField->GetMemOffset() +
((CG_STRUCT *)pNdr)->GetEnum16Offset();
}
// Never get here.
return 0;
}
void
CloneForUnrolling(
CG_NDR * pParent,
CG_NDR * pNdr )
/*
This routine will clone pNdr and overwrite the original child at
the parent if needed.
It is assumed the parent has been cloned, too.
*/
{
CG_POINTER * pNewPointer;
pNewPointer = 0;
if ( pNdr->IsPointer() )
{
switch ( pNdr->GetCGID() )
{
case ID_CG_PTR :
pNewPointer = new CG_POINTER(
(CG_POINTER *) pNdr );
break;
case ID_CG_BC_PTR :
pNewPointer = new CG_BYTE_COUNT_POINTER(
(CG_BYTE_COUNT_POINTER *) pNdr );
break;
case ID_CG_STRING_PTR :
case ID_CG_STRUCT_STRING_PTR :
pNewPointer = new CG_STRING_POINTER(
(CG_STRING_POINTER *) pNdr );
break;
case ID_CG_SIZE_PTR :
pNewPointer = new CG_SIZE_POINTER(
(CG_SIZE_POINTER *) pNdr );
break;
case ID_CG_LENGTH_PTR :
pNewPointer = new CG_LENGTH_POINTER(
(CG_LENGTH_POINTER *) pNdr );
break;
case ID_CG_SIZE_LENGTH_PTR :
pNewPointer = new CG_SIZE_LENGTH_POINTER(
(CG_SIZE_LENGTH_POINTER *) pNdr );
break;
case ID_CG_SIZE_STRING_PTR :
pNewPointer = new CG_SIZE_STRING_POINTER(
(CG_SIZE_STRING_POINTER *) pNdr );
break;
case ID_CG_INTERFACE_PTR :
pNewPointer = new CG_INTERFACE_POINTER(
(CG_INTERFACE_POINTER *) pNdr );
break;
default :
break;
}
if ( pNewPointer )
{
//
// We have to re-set the new pointer's format string offset and
// pointee format string offset to -1 so that we get a new
// description!!!
//
if ( pNewPointer )
pNewPointer->SetFormatStringOffset( -1 );
pNewPointer->SetPointeeFormatStringOffset( -1 );
pParent->SetChild( pNewPointer );
if ( pNdr->GetChild() )
CloneForUnrolling( pNewPointer, (CG_NDR*) pNdr->GetChild() );
}
}
}
void
CG_STRUCT::Unroll()
{
ITERATOR Iterator;
CG_FIELD * pPrevField;
CG_FIELD * pField;
CG_NDR * pNdr;
CG_STRUCT * pStruct;
GetMembers( Iterator );
pPrevField = 0;
while ( ITERATOR_GETNEXT(Iterator,pField) )
{
pNdr = (CG_NDR *) pField->GetChild();
if ( pNdr->IsStruct() && ((CG_STRUCT *)pNdr)->HasSizedPointer() )
pStruct = (CG_STRUCT *) pNdr;
else
{
pPrevField = pField;
continue;
}
//
// First force the embeded struct to unroll if needed.
//
pStruct->Unroll();
ITERATOR IteratorEmbeded;
CG_FIELD * pFieldNew;
CG_FIELD * pFieldEmbeded;
CG_FIELD * pFieldList;
long MemOffsetStart;
long WireOffsetStart;
pStruct->GetMembers( IteratorEmbeded );
MemOffsetStart = pField->GetMemOffset();
WireOffsetStart = pField->GetWireOffset();
// Get previous field node.
pFieldList = pPrevField;
// Remove current struct field node from the list.
if ( pFieldList )
pFieldList->SetSibling( pField->GetSibling() );
else
this->SetChild( pField->GetSibling() );
// To be safe.
pField->SetSibling( 0 );
while ( ITERATOR_GETNEXT(IteratorEmbeded,pFieldEmbeded) )
{
pFieldNew = pFieldEmbeded->Clone();
pNdr = (CG_NDR *) pFieldEmbeded->GetChild();
CloneForUnrolling( pFieldNew, pNdr );
//
// Set the new field's memory and wire offset.
//
pFieldNew->SetMemOffset( pFieldEmbeded->GetMemOffset() +
MemOffsetStart );
pFieldNew->SetWireOffset( pFieldEmbeded->GetWireOffset() +
WireOffsetStart );
//
// Now add the imbeded struct's field name to the PrintPrefix of
// the new unrolled field. We ask the imbeded struct's field
// for it's name.
//
pFieldNew->AddPrintPrefix( pField->GetType()->GetSymName() );
if ( pFieldList )
{
pFieldNew->SetSibling( pFieldList->GetSibling() );
pFieldList->SetSibling( pFieldNew );
}
else
{
pFieldNew->SetSibling( this->GetChild() );
this->SetChild( pFieldNew );
}
pFieldList = pFieldNew;
}
//
// Set pPrevField equal to the last field node that we entered into
// the list. The outermost Iterator only knows about fields that
// started in the struct's field list, so the last field node we
// added will have a sibling equal to the next field node we'll get
// from the outer iterator.
//
pPrevField = pFieldNew;
}
}
BOOL
CG_STRUCT::HasSizedPointer()
{
CG_ITERATOR Iterator;
CG_FIELD * pField;
CG_NDR * pNdr;
GetMembers( Iterator );
while ( ITERATOR_GETNEXT(Iterator,pField) )
{
pNdr = (CG_NDR *) pField->GetChild();
if ( pNdr->IsStruct() && ((CG_STRUCT *)pNdr)->HasSizedPointer() )
return TRUE;
if ( (pNdr->GetCGID() == ID_CG_SIZE_PTR) ||
(pNdr->GetCGID() == ID_CG_SIZE_LENGTH_PTR) ||
(pNdr->GetCGID() == ID_CG_SIZE_STRING_PTR) )
return TRUE;
}
return FALSE;
}
BOOL
CG_ENCAPSULATED_STRUCT::ShouldFreeOffline()
{
CG_UNION * pUnion;
pUnion = (CG_UNION *) GetChild()->GetSibling()->GetChild();
return pUnion->HasPointer();
}