/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Copyright (c) 1989-1999 Microsoft Corporation

 Module Name:
	
	stcls.hxx

 Abstract:

	Contains definitions for base type related code generation class
	definitions.

 Notes:


 History:

	GregJen		Sep-30-1993		Created.
 ----------------------------------------------------------------------------*/
#ifndef __STCLS_HXX__
#define __STCLS_HXX__

#pragma warning ( disable : 4238 4239 )

#include "nulldefs.h"

extern "C"
	{
	#include <stdio.h>
	
	}

#include "ndrcls.hxx"

class CG_ARRAY;
class ANALYSIS_INFO;
class CG_FIELD;

//
// This class is the base type for compound things like 
// structures, unions, and fields 
//

class CG_COMP	: public CG_NDR
	{
private:

	unsigned short		Zp;

	BOOL				fHasPointer : 1;
	//
	// this flag is set if there are fields with different mem and wire offsets
	//
	BOOL				fHasMovedFields	: 1;

	expr_node		*	pSizeExpression;


public:
	
	//
	// The constructor.
	//

							CG_COMP(
									 node_skl * pBT,	// base type
									 XLAT_SIZE_INFO & Info,	// packing and size info
									 unsigned short HP
									 ) : 
								CG_NDR( pBT, Info )
								{
								SetZp( Info.GetZeePee() );
								SetHasPointer(HP);
								ResetHasMovedFields();
                                SetSizeExpression( 0 );
								}

    virtual
    void                    Visit( CG_VISITOR *pVisitor ) = 0;

	//
	// Get and set methods.
	//

	//	make sure the ZP gets set along the way
	virtual
	void					SetSizesAndAlignments( XLAT_SIZE_INFO & Info )
								{
								CG_NDR::SetSizesAndAlignments( Info );
								SetZp( Info.GetZeePee() );
								}

	expr_node			*	SetSizeExpression( expr_node * pE )
								{
								return (pSizeExpression	= pE);
								}

	expr_node			*	GetSizeExpression()
								{
								return pSizeExpression;
								}

	unsigned short			SetZp( unsigned short ZP )
								{
								return (Zp = ZP);
								}

	unsigned short			GetZp()
								{
								return Zp;
								}

	BOOL					SetHasMovedFields()
								{
								return (fHasMovedFields = TRUE);
								}

	BOOL					ResetHasMovedFields()
								{
								return (fHasMovedFields = FALSE);
								}

	BOOL					HasMovedFields()
								{
								return fHasMovedFields;
								}

	BOOL					SetHasPointer( BOOL HP )
								{
								return (fHasPointer = HP);
								}

	BOOL					HasPointer()
								{
								return fHasPointer;
								}

	virtual
	CG_STATUS				S_GenInitOutLocals( CCB * pCCB );

	virtual
	CG_STATUS				S_OutLocalAnalysis( ANALYSIS_INFO * pAna );

	virtual
	short					GetPointerMembers( ITERATOR&  I );

	virtual
	CG_STATUS				RefCheckAnalysis( ANALYSIS_INFO * )
								{
								return CG_OK;
								}

	virtual
	CG_STATUS				InLocalAnalysis( ANALYSIS_INFO * )
								{
								return CG_OK;
								}

	virtual
	CG_STATUS				S_GenInitInLocals( CCB * )
								{
								return CG_OK;
								}
	virtual
	CG_STATUS				GenRefChecks( CCB * )
								{
								return CG_OK;
								}
	};

/////////////////////////////////////////////////////////////////////////////
// the structure code generation classes.
/////////////////////////////////////////////////////////////////////////////

class CG_COMPLEX_STRUCT;

//
// This class corresponds to a vanilla structure type. 
//

class CG_STRUCT	: public CG_COMP, public CG_CLONEABLE
	{
private:
    void *                  _pCTI;

    // This is needed for recursive embedded complex fixups.

    CG_COMPLEX_STRUCT *     pDuplicatingComplex;

public:
	
	//
	// The constructor.
	//

							CG_STRUCT(
									 node_skl * pBT,	// base type
									 XLAT_SIZE_INFO & Info,	// memory size, etc
									 unsigned short HP	// Has pointer
									 ) : 
								CG_COMP( pBT, Info, HP )
								{
                                _pCTI = NULL;
                                pDuplicatingComplex = NULL;
								}

							CG_STRUCT( CG_STRUCT * pStruct ) :
								CG_COMP( pStruct->GetType(),
										 XLAT_SIZE_INFO(),	// overwritten by copy below
										 ( unsigned short )pStruct->HasPointer() )
								{
								// Make sure we copy everything.
								*this = *pStruct;
								}

    //
    // Generate typeinfo
    //          
    virtual
    CG_STATUS               GenTypeInfo( CCB * pCCB);

	virtual
	ID_CG					GetCGID()
								{
								return ID_CG_STRUCT;
								}

    virtual
    void                    Visit( CG_VISITOR *pVisitor )
                               {
                               pVisitor->Visit( this );
                               }

    virtual
    CG_CLASS*               Clone()
                               {
                               return new CG_STRUCT( *this );
                               }

	// Unroll imbeded structure members.
	void					Unroll();

	BOOL					HasSizedPointer();

	//
	// Get and set methods.
	//

	virtual
	BOOL					IsStruct()
								{
								return TRUE;
								}

	BOOL					IsComplexStruct();

    CG_COMPLEX_STRUCT *     GetDuplicatingComplex()
                                {
                                return( pDuplicatingComplex );
                                }

    void                    SetDuplicatingComplex( CG_COMPLEX_STRUCT * pC )
                                {
                                pDuplicatingComplex = pC;
                                }

    BOOL                    IsHardStruct();

    BOOL                    IsHardStructOld();

    virtual
    bool                    IsHomogeneous(FORMAT_CHARACTER format);

	long					GetNumberOfPointers();

    long                    GetNumberOfEnum16s();

    long                    GetNumberOfUnions();

    CG_FIELD *              GetFinalField();

    CG_FIELD *              GetArrayField( CG_ARRAY * pArray );

    long                    GetEnum16Offset();

	//
	// Generate the Ndr format string for the type.
	//
	virtual
	void					GenNdrFormat( CCB * pCCB );

    //
    // Generate the description for a "hard" structure.
    //
	void					GenNdrFormatHard( CCB * pCCB );

	//
	// Generate the description for a "complex" structure.
	//
	void					GenNdrFormatComplex( CCB * pCCB );

	//
	// Ndr format string generation methods shared by all structure classes
	// except CG_COMPLEX_STRUCT, which redefines both of these methods.
	//

	virtual
	void					GenNdrStructurePointerLayout( CCB * pCCB,
														  BOOL	fNoPP,
														  BOOL 	fNoType );

    void                    GenStructureMemPad( CCB * pCCB, unsigned long MemPad );
	
    virtual
    void		    GenNdrStructureLayout( CCB * pCCB );

    virtual
    BOOL                    ShouldFreeOffline();

    virtual
    void                    GenFreeInline( CCB * pCCB );

	//
	// One more Ndr format string generation method.  This time shared by all 
	// structure classes, so it's not a virtual.
	//

	void					GenNdrStructurePointees( CCB * pCCB );

    virtual
    long                    FixedBufferSize( CCB * pCCB );

    BOOL                    InterpreterMustFree( CCB * ) { return TRUE; }

    CG_FIELD  *             GetPreviousField( CG_FIELD * pField );

	virtual
	CG_STATUS				MarshallAnalysis( ANALYSIS_INFO * pAna );

	virtual
	CG_STATUS				UnMarshallAnalysis( ANALYSIS_INFO * pAna );

    virtual
    BOOL                    HasAFixedBufferSize();

	};

//
// This class corresponds to a encapsulated structure type. 
//

class CG_ENCAPSULATED_STRUCT	: public CG_STRUCT
	{
private:

public:
	
	//
	// The constructor.
	//

							CG_ENCAPSULATED_STRUCT(
									 node_skl * pBT,	// base type
									 XLAT_SIZE_INFO & Info,	// memory size, etc
									 unsigned short HP	// Has pointer
									 ) : 
								CG_STRUCT( pBT, Info, HP )
								{
								}

	virtual
	ID_CG					GetCGID()
								{
								return ID_CG_ENCAP_STRUCT;
								}
    virtual
    void                    Visit( CG_VISITOR *pVisitor )
                               {
                               pVisitor->Visit( this );
                               }

    virtual
    CG_CLASS*               Clone()
                               {
                               return new CG_ENCAPSULATED_STRUCT( *this );
                               }

	BOOL					IsVarying()
								{
								return TRUE;
								}

    //
    // Redefine this method, which CG_STRUCT defines.
    //
	virtual
	BOOL					IsStruct()
								{
								return FALSE;
								}

    //
    // This is, for all intents and purposes, a union.  
    //
	virtual
	BOOL					IsUnion()
								{
								return TRUE;
								}

	//
	// Get and set methods.
	//

	//
	// Generate the Ndr format string for the type.
	//

	virtual
	void					GenNdrFormat( CCB * pCCB );

    virtual
    BOOL                    ShouldFreeOffline();

    virtual
    void                    GenFreeInline( CCB * )
								{
								}

    virtual
    void                    GenNdrPointerFixUp( CCB *       pCCB,
                                                CG_STRUCT * pStruct );

    long                    FixedBufferSize( CCB * )
                                {
                                return -1;
                                }
	virtual
    BOOL                    HasAFixedBufferSize()
                                {
                                return FALSE;
                                }

	};

//
// This class corresponds to a conformant structure type. 
//
// The pConfFld entry points to the CG_FIELD of this structure that describes
// the conformance.  If the conformance is due to an embedded struct, then
// it points to the CG_FIELD above the embedded conformant structure
//
// The actual conformance is described by a CG_xxx_ARRAY somewhere below the
// CG_FIELD.
//

class CG_CONFORMANT_STRUCT	: public CG_STRUCT
	{
private:

	CG_CLASS	*	pConfFld;

public:
	
	//
	// The constructor.
	//

							CG_CONFORMANT_STRUCT(
									 node_skl * pBT,	// base type
									 XLAT_SIZE_INFO & Info,	// memory size
									 unsigned short HP,	// Has pointer
									 CG_CLASS * pCF		// conformant field
									 ) : 
								CG_STRUCT( pBT, Info, HP )
								{
								SetConformantField( pCF );
								}

							CG_CONFORMANT_STRUCT(
									CG_STRUCT *	pStruct,
									CG_CLASS *	pCF 
									) :
								CG_STRUCT( pStruct )
								{
								SetConformantField( pCF );
								}

	virtual
	ID_CG					GetCGID()
								{
								return ID_CG_CONF_STRUCT;
								}

    virtual
    CG_CLASS*               Clone()
                                {
                                return new CG_CONFORMANT_STRUCT( *this );
                                }
    virtual
    void                    Visit( CG_VISITOR *pVisitor )
                                {
                                pVisitor->Visit( this );
                                }
    
	//
	// Get and set methods.
	//

	CG_CLASS	*			SetConformantField( CG_CLASS	* pCF )
								{
								return (pConfFld = pCF);
								}

	CG_CLASS	*			GetConformantField()
								{
								return pConfFld;
								}


	//
	// Dig down into the bowels of the CG class graph and get my
	// conformant array class.
	// Return a CG_ARRAY pointer since both conformant and conformant
	// varying arrays inherit this.
	//
	CG_ARRAY *				GetConformantArray();

	};


//
// This class corresponds to a vanilla structure type. 
//

class CG_CONFORMANT_VARYING_STRUCT	: public CG_CONFORMANT_STRUCT
	{
private:


public:
	
	//
	// The constructor.
	//

							CG_CONFORMANT_VARYING_STRUCT(
									 node_skl * pBT,	// base type
									 XLAT_SIZE_INFO & Info,	// memory size, etc
									 unsigned short HP,	// Has pointer
									 CG_CLASS * pCF		// conformant field
									 ) : 
								CG_CONFORMANT_STRUCT( pBT, Info, HP, pCF )
								{
								}

	virtual
	ID_CG					GetCGID()
								{
								return ID_CG_CONF_VAR_STRUCT;
								}

    virtual
    CG_CLASS*               Clone() 
                               {
                               return new CG_CONFORMANT_VARYING_STRUCT( *this );
                               }

    virtual
    void                    Visit( CG_VISITOR *pVisitor )
                               {
                               pVisitor->Visit( this );
                               }

    virtual
    BOOL                    HasAFixedBufferSize()
                                {
                                return FALSE;
                                }
	};


//
// This class corresponds to a vanilla structure type. 
//

class CG_COMPLEX_STRUCT	: public CG_CONFORMANT_STRUCT
	{
private:

	//
	// Struct from which we were duplicated, if any.  This is used for 
	// handling packed structures.
	//
	CG_STRUCT *	pDuplicatedStruct;

public:
	
	//
	// The constructor.
	//

							CG_COMPLEX_STRUCT(
									 node_skl * pBT,	// base type
									 XLAT_SIZE_INFO & Info,	// memory size, etc
									 unsigned short HP,	// Has pointer
									 CG_CLASS * pCF		// conformant field
									 ) : 
								CG_CONFORMANT_STRUCT( pBT, Info, HP, pCF )
								{
								pDuplicatedStruct = 0;
								}

							CG_COMPLEX_STRUCT(
									CG_STRUCT *	pStruct,
									CG_CLASS *	pCF 
									) :
								CG_CONFORMANT_STRUCT( pStruct, pCF )
								{
								pDuplicatedStruct = pStruct;
								}

	virtual
	ID_CG					GetCGID()
								{
								return ID_CG_COMPLEX_STRUCT;
								}

    virtual
    CG_CLASS*               Clone()
                                {
                                return new CG_COMPLEX_STRUCT( *this );
                                }

    virtual
    void                    Visit( CG_VISITOR *pVisitor )
                               {
                               pVisitor->Visit( this );
                               }

	BOOL					IsVarying()
								{
								return TRUE;
								}

	//
	// Get and set methods.
	//
 	CG_STRUCT *				GetDuplicatedStruct()
								{
								return pDuplicatedStruct;
								}

	//
	// Generate the Ndr format string for the type.
	//
	virtual
	void					GenNdrFormat( CCB * pCCB );

	virtual
	void					GenNdrStructurePointerLayout( CCB * pCCB );

    BOOL                    WarnAboutEmbeddedComplexStruct();
	};

//
//  New Class for 64bit NDR
//

#define DECLARE_STRUCT_CG_CLASS( NEWTYPE, BASETYPE )                              \
class NEWTYPE : public BASETYPE                                                   \
{                                                                                 \
protected:                                                                        \
    NEWTYPE( const NEWTYPE & Node ) :                                             \
        BASETYPE( Node ) {}                                                       \
public:                                                                           \
    NEWTYPE(node_skl *pType,                                                      \
            XLAT_SIZE_INFO & Info,                                                \
            BOOL HP ) :                                                           \
        BASETYPE( pType,                                                          \
                  Info,                                                           \
                  (unsigned short)HP,                                             \
                  NULL ) {}                                                       \
                                                                                  \
    virtual CG_CLASS* Clone()             { return new NEWTYPE(*this); }          \
    virtual void Visit( CG_VISITOR *pVisitor ) { pVisitor->Visit( this ); }       \
};                                                                                \


DECLARE_STRUCT_CG_CLASS( CG_FULL_COMPLEX_STRUCT, CG_COMPLEX_STRUCT )
DECLARE_STRUCT_CG_CLASS( CG_FORCED_COMPLEX_STRUCT, CG_COMPLEX_STRUCT )
DECLARE_STRUCT_CG_CLASS( CG_CONFORMANT_FULL_COMPLEX_STRUCT, CG_COMPLEX_STRUCT )
DECLARE_STRUCT_CG_CLASS( CG_CONFORMANT_FORCED_COMPLEX_STRUCT, CG_COMPLEX_STRUCT )

//
// Block copyable regions for 64bit NDR
//


// Do not instantiate CG_REGION directly since it is a base class.
class CG_REGION : public CG_STRUCT 
{
protected:
    CG_REGION( const CG_REGION & Node ) :
        CG_STRUCT( Node )
    {}
    CG_REGION(CG_COMPLEX_STRUCT *pComplexStruct,
              XLAT_SIZE_INFO & Info,
              BOOL HP) :
        CG_STRUCT(pComplexStruct->GetType(),
                  Info,
                  (unsigned short)HP)
    {
    }
public:
    virtual CG_CLASS* Clone() = 0;
    virtual void Visit( CG_VISITOR *pVisitor ) = 0;
};

// Small region without any pointers
class CG_SIMPLE_REGION : public CG_REGION
{
protected:
    CG_SIMPLE_REGION( const CG_REGION & Node ) :
        CG_REGION( Node )
        {}
public:
    CG_SIMPLE_REGION(  CG_COMPLEX_STRUCT *pComplexStruct, 
                       XLAT_SIZE_INFO & Info ) :
        CG_REGION( pComplexStruct,
                   Info,
                   FALSE )
    {}
    virtual CG_CLASS* Clone()                  { return new CG_SIMPLE_REGION(*this); }
    virtual void Visit( CG_VISITOR *pVisitor ) { pVisitor->Visit( this ); }
};

// Larger region or region with pointers
class CG_COMPLEX_REGION : public CG_REGION
{
protected:
    CG_COMPLEX_REGION( const CG_REGION & Node ) :
        CG_REGION( Node )
        {}
public:
    CG_COMPLEX_REGION( CG_COMPLEX_STRUCT *pComplexStruct,
                       XLAT_SIZE_INFO & Info, 
                       BOOL HP ) :
        CG_REGION( pComplexStruct,
                   Info,
                   HP )
    {}
    virtual CG_CLASS* Clone()                  { return new CG_COMPLEX_REGION(*this); }
    virtual void Visit( CG_VISITOR *pVisitor ) { pVisitor->Visit( this ); }
};

// Represents a buffer pad.
class CG_PAD : public CG_NDR
    {
private:
public:

    //
    // The constructor.
    //

                        CG_PAD( node_skl *pType,
                                XLAT_SIZE_INFO & Info ) :
                            CG_NDR( pType, Info )
                            {
                            }
    virtual
    CG_CLASS *          Clone()
                            {
                            return new CG_PAD( *this );
                            }
    virtual
    ID_CG               GetCGID()
                            {
                            return ID_CG_PAD;
                            }

    virtual
    void                Visit( CG_VISITOR *pVisitor )
                            {
                            pVisitor->Visit( this );
                            }

    //
    // Ndr format string generation method.
    //
    virtual
    void                GenNdrFormat( CCB * pCCB )
                            {
                            FORMAT_STRING   * pFormat = pCCB->GetFormatString();
                            pFormat->PushFormatChar( FC_BUFFER_ALIGN );
                            pFormat->PushByte( GetWireAlignment() - 1 );
                            }

    };

#endif // __STCLS_HXX__