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

 Module Name:

    pipendr.cxx

 Abstract:

    Contains routines for the generation of the new NDR format strings for
    pipe types.

 Notes:

 History:

    SteveBl   Dec-1995        Created.
    
 ----------------------------------------------------------------------------*/

#include "becls.hxx"

extern CMD_ARG * pCommand;

#pragma hdrstop

void
CG_PIPE::GenNdrFormat( CCB * pCCB )
/*++
    The format string is:

        FC_PIPE     
        flags & alignment<1>        // pointer flags on the higher nibble
        index to type desc<2>       // the usual
        memory size<2>              
        buffer size<2>              // wire size, essential

    If either memory size or buffer size > 64k then 
    the FC_BIG_PIPE flag is set and the following format string is used:

        FC_PIPE     
        flags & alignment<1>        
        index to type desc<2>       
        memory size<4>          
        buffer size<4>          
        
--*/
{
    if ( GetFormatStringOffset() != -1 ) 
        return;

    pCommand->GetNdrVersionControl().SetHasRawPipes();

    FORMAT_STRING * pFormatString;
    CG_NDR *        pChild;
    long            ChildOffset;

    // Format offset

    pFormatString = pCCB->GetFormatString();

    pChild = (CG_NDR *) GetChild();

    MIDL_ASSERT( pChild );

    // Do this in case the child is a simple type.
    ChildOffset = pFormatString->GetCurrentOffset();

    pChild->GenNdrFormat( pCCB );

    // Again, do this in case the child is a simple type.
    pFormatString->Align();

    SetFormatStringOffset( pFormatString->GetCurrentOffset() );

    // Real stuff now

    pFormatString->PushFormatChar( FC_PIPE );

    // Compute the memory size and buffer size.
    // Account for alignment

    unsigned long uMemorySize         = pChild->GetMemorySize();
    
    unsigned long uBufferSize = pChild->HasAFixedBufferSize() 
                                           ? pChild->GetWireSize() 
                                           : 0;

    // Now the flag byte.
    
    unsigned char FlagByte = unsigned char(pChild->GetWireAlignment() - 1);

    if (uMemorySize > 0xffff || uBufferSize > 0xffff)
        FlagByte |= FC_BIG_PIPE;

    if ( IsObjectPipe() )
        FlagByte |= FC_OBJECT_PIPE;

    if ( GetRangeAttribute() )
        {
        FlagByte |= FC_PIPE_HAS_RANGE;
        }

    pFormatString->PushByte( FlagByte );

    // Now the index to the type desc

    if ( pChild->IsSimpleType() )
        {
        pFormatString->PushShortOffset(
                           ChildOffset - pFormatString->GetCurrentOffset() );
        }
    else
        {
        pFormatString->PushShortOffset(
                           pChild->GetFormatStringOffset() - 
                             pFormatString->GetCurrentOffset() );
        }

    // Now push the memory size and buffer size.

    if (FlagByte & FC_BIG_PIPE)
    {
        pFormatString->PushLong( uMemorySize);
        pFormatString->PushLong( uBufferSize);
    }
    else
    {
        pFormatString->PushShort( (short) uMemorySize);
        pFormatString->PushShort( (short) uBufferSize);
    }
    if ( GetRangeAttribute() )
        {
        // RKK64: TBD support for a range check on hyper.
        pFormatString->PushLong( (ulong) GetRangeAttribute()->GetMinExpr()->GetValue() );  // min.
        pFormatString->PushLong( (ulong) GetRangeAttribute()->GetMaxExpr()->GetValue() );  // max.
        }

    SetFormatStringEndOffset( pFormatString->GetCurrentOffset() );
    pFormatString->OptimizeFragment( this );
}