/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Copyright (c) 1993  - 1999 Microsoft Corporation

Module Name :

    free.c

Abstract :

    This file contains the routines called by MIDL 2.0 stubs and the 
    interpreter for freeing unmarshalled data on the server. 

Author :

    David Kays  dkays   September 1993.

Revision History :

  ---------------------------------------------------------------------*/

#include "precomp.hxx"
#include "..\..\ndr20\ndrole.h"

__forceinline void
Ndr64FreeTypeMemory( 
    PMIDL_STUB_MESSAGE pStubMsg,
    uchar *            pMemory )
{

    if ( !pStubMsg->pPointerQueueState ||
         !pStubMsg->pPointerQueueState->GetActiveQueue() )
        {
        (*pStubMsg->pfnFree)(pMemory);
        return;
        }
    
    NDR_PFNFREE_POINTER_QUEUE_ELEMENT*pElement = 
        new(pStubMsg->pPointerQueueState) 
            NDR_PFNFREE_POINTER_QUEUE_ELEMENT(pStubMsg->pfnFree,
                                              pMemory );
    pStubMsg->pPointerQueueState->GetActiveQueue()->Enque( pElement );
}

NDR64_FREE_POINTER_QUEUE_ELEMENT::NDR64_FREE_POINTER_QUEUE_ELEMENT( 
    MIDL_STUB_MESSAGE *pStubMsg, 
    uchar * const pMemoryNew,
    const PFORMAT_STRING pFormatNew) :
        pMemory(pMemoryNew),
        pFormat(pFormatNew),
        uFlags(pStubMsg->uFlags),
        pCorrMemory(pStubMsg->pCorrMemory)
{

}

void 
NDR64_FREE_POINTER_QUEUE_ELEMENT::Dispatch(
    MIDL_STUB_MESSAGE *pStubMsg) 
{

    SAVE_CONTEXT<uchar> uFlagsSave( pStubMsg->uFlags, uFlags );
    CORRELATION_CONTEXT CorrContext( pStubMsg, pCorrMemory );
    
    Ndr64ToplevelTypeFree( pStubMsg,
                           pMemory,
                           pFormat );
}

#if defined(DBG)
void 
NDR64_FREE_POINTER_QUEUE_ELEMENT::Print() 
{
    DbgPrint("NDR_FREE_POINTER_QUEUE_ELEMENT\n");
    DbgPrint("pNext:                   %p\n", pNext );
    DbgPrint("pMemory:                 %p\n", pMemory );
    DbgPrint("pFormat:                 %p\n", pFormat );
    DbgPrint("uFlags:                  %x\n", uFlags );
    DbgPrint("pCorrMemory:             %p\n", pCorrMemory );
}
#endif

void
Ndr64EnquePointeeFree(
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
{

    NDR64_POINTER_CONTEXT PointerContext( pStubMsg );

    RpcTryFinally
        {

        NDR64_FREE_POINTER_QUEUE_ELEMENT*pElement = 
            new(PointerContext.GetActiveState()) 
                NDR64_FREE_POINTER_QUEUE_ELEMENT(pStubMsg,
                                                 (uchar*)pMemory,
                                                 (PFORMAT_STRING)pFormat);
        PointerContext.Enque( pElement );
        PointerContext.DispatchIfRequired();
        }
    RpcFinally
        {
        PointerContext.EndContext();
        }
    RpcEndFinally

}

__forceinline void
Ndr64PointeeFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
{
    SAVE_CONTEXT<uchar> uFlagsSave( pStubMsg->uFlags );
    NDR64_RESET_EMBEDDED_FLAGS_TO_STANDALONE(pStubMsg->uFlags);

    if ( !NdrIsLowStack( pStubMsg ) )
        {
        Ndr64ToplevelTypeFree( pStubMsg,
                               pMemory,
                               pFormat );
        return;
        }

    Ndr64EnquePointeeFree( 
        pStubMsg,
        pMemory,
        pFormat );

}

void
Ndr64pNoopFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
{
    return;
}



__forceinline void 
Ndr64PointerFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees a top level or embedded pointer to anything.

    Used for FC64_RP, FC64_UP, FC64_FP, FC64_OP.

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    const NDR64_POINTER_FORMAT *pPointerFormat = (NDR64_POINTER_FORMAT*) pFormat;
    uchar *         pMemoryPointee = pMemory;

    if ( ! pMemory )
        return;

    if ( *(PFORMAT_STRING)pFormat == FC64_IP )
        {
        ((IUnknown *)pMemory)->Release();
        return;
        }

    if ( *(PFORMAT_STRING)pFormat == FC64_FP )
        {
        //
        // Check if we've already freed this full pointer.
        //
        if ( ! NdrFullPointerFree( pStubMsg->FullPtrXlatTables,
                                   pMemory ) )
            return;
        }

    if ( 0 == pPointerFormat->Flags )
        goto FreeEmbeddedPointers;  

    //
    // Check if this pointer and any possible embedded pointers should not
    // be freed.
    //
    if ( NDR64_DONT_FREE( pPointerFormat->Flags) )
        return;

    // 
    // Just go free a pointer to a simple type.
    //
    if ( NDR64_SIMPLE_POINTER( pPointerFormat->Flags ) ) 
        goto FreeTopPointer;

    // 
    // Check if this is an allocate all nodes pointer.  
    // IDL symantics say that we only free the top most allocate all nodes
    // pointer on the server even in the [out] only case.  So jump to the 
    // check for the pointer free at the end of the routine.  
    //  
    if ( NDR64_ALLOCATE_ALL_NODES( pPointerFormat->Flags ) )
        goto FreeTopPointer;

    if ( NDR64_POINTER_DEREF( pPointerFormat->Flags ) )
        pMemoryPointee = *((uchar **)pMemory);

FreeEmbeddedPointers:


    Ndr64PointeeFree( pStubMsg,
                      pMemoryPointee,
                      pPointerFormat->Pointee );

FreeTopPointer:

    //
    // Now free the pointer.  Pointer guaranteed to be non-null here.
    //
    // We only free the pointer if it lies outside of the message buffer
    // that the server stub received from the RPC runtime. Otherwise we
    // used the RPC buffer to hold the pointer's data and should not free it.
    //
    if ( (pMemory < pStubMsg->BufferStart) || (pMemory > pStubMsg->BufferEnd) )
        {
        //
        // Also check to make sure that the pointer was not allocated on the
        // server stub's stack (this may happen for ref pointers).
        //
        // full pointer can't be allocated on stack
        if ( ! NDR64_ALLOCED_ON_STACK( pPointerFormat->Flags ) || 
             *(PFORMAT_STRING)pFormat == FC64_FP )
            {
            Ndr64FreeTypeMemory( pStubMsg, pMemory );
            }
        }
}


__forceinline void
Ndr64TopLevelPointerFree(
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees a top level or embedded pointer to anything.

    Used for FC64_RP, FC64_UP, FC64_FP, FC64_OP.

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    Ndr64PointerFree( pStubMsg,
                      pMemory,
                      pFormat );

}

__forceinline void
Ndr64EmbeddedPointerFree(
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )

{
    Ndr64PointerFree( pStubMsg,
                      *(uchar**)pMemory,
                      pFormat );
}


void 
Ndr64pRangeFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++
--*/
{
    return;
}


void 
Ndr64SimpleStructFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees a simple structure's embedded pointers which were allocated during 
    a remote call.  

    Used for FC64_STRUCT and FC64_PSTRUCT.

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    const NDR64_STRUCTURE_HEADER_FORMAT * const pStructFormat =
        (NDR64_STRUCTURE_HEADER_FORMAT*) pFormat;

    if ( !pMemory || !pStructFormat->Flags.HasPointerInfo ) 
        return;

    CORRELATION_CONTEXT CorrCtxt( pStubMsg, pMemory );

    Ndr64pPointerLayoutFree( pStubMsg,
                             pStructFormat + 1,
                             0,
                             pMemory );
}


void 
Ndr64ConformantStructFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees a conformant structure's embedded pointers which were allocated 
    during a remote call.

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.
    
--*/
{
    const NDR64_CONF_STRUCTURE_HEADER_FORMAT * const pStructFormat =
        (NDR64_CONF_STRUCTURE_HEADER_FORMAT*) pFormat;
    
    const NDR64_CONF_ARRAY_HEADER_FORMAT * const pArrayFormat =  
        (NDR64_CONF_ARRAY_HEADER_FORMAT *) pStructFormat->ArrayDescription;

    if ( !pMemory || !pStructFormat->Flags.HasPointerInfo )
        return;

    CORRELATION_CONTEXT CorrCtxt( pStubMsg, pMemory );

    NDR64_UINT32 MaxCount = (NDR64_UINT32)
    Ndr64EvaluateExpr( pStubMsg,
                       pArrayFormat->ConfDescriptor,
                       EXPR_MAXCOUNT );

    Ndr64pPointerLayoutFree( pStubMsg,
                             pStructFormat + 1,
                             MaxCount,
                             pMemory );
}


void 
Ndr64ComplexStructFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees a complex structure's embedded pointers which were allocated during 
    a remote call.  

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    const NDR64_BOGUS_STRUCTURE_HEADER_FORMAT *  pStructFormat =
        (NDR64_BOGUS_STRUCTURE_HEADER_FORMAT*) pFormat;
    const NDR64_CONF_BOGUS_STRUCTURE_HEADER_FORMAT * pConfStructFormat =
        (NDR64_CONF_BOGUS_STRUCTURE_HEADER_FORMAT*) pFormat;

    PFORMAT_STRING  pFormatPointers = (PFORMAT_STRING)(pStructFormat->PointerLayout );

    PFORMAT_STRING  pFormatArray = NULL;

    PFORMAT_STRING  pMemberLayout = ( *(PFORMAT_STRING)pFormat == FC64_CONF_BOGUS_STRUCT ||
                                      *(PFORMAT_STRING)pFormat == FC64_FORCED_CONF_BOGUS_STRUCT ) ?
                                    (PFORMAT_STRING)( pConfStructFormat + 1) :
                                    (PFORMAT_STRING)( pStructFormat + 1);
    
    if ( !pMemory )
        return;

    CORRELATION_CONTEXT CorrCtxt( pStubMsg, pMemory );
    
    if ( pStructFormat->Flags.HasConfArray )
        {
        pFormatArray = (PFORMAT_STRING)pConfStructFormat->ConfArrayDescription;
        }

    for ( ; ; )
        {
        switch ( *pMemberLayout )
            {

            case FC64_STRUCT:
                {
                const NDR64_SIMPLE_REGION_FORMAT *pRegion = 
                    (NDR64_SIMPLE_REGION_FORMAT*) pMemberLayout;
                
                pMemory          += pRegion->RegionSize;

                pMemberLayout    += sizeof( *pRegion );
                break;
                }
            
            case FC64_STRUCTPADN :
                {
                const NDR64_MEMPAD_FORMAT *pMemPad = (NDR64_MEMPAD_FORMAT*)pMemberLayout;
                pMemory       += pMemPad->MemPad;
                pMemberLayout += sizeof(*pMemPad);
                break;
                }

            case FC64_POINTER :
                Ndr64EmbeddedPointerFree( pStubMsg,
                                          pMemory,
                                          pFormatPointers );

                pMemory += PTR_MEM_SIZE;

                pFormatPointers += sizeof(NDR64_POINTER_FORMAT);                
                pMemberLayout       += sizeof(NDR64_SIMPLE_MEMBER_FORMAT);
                
                break;

            case FC64_EMBEDDED_COMPLEX :
                
                {

                const NDR64_EMBEDDED_COMPLEX_FORMAT * pEmbeddedFormat =
                    (NDR64_EMBEDDED_COMPLEX_FORMAT*) pMemberLayout;

                Ndr64EmbeddedTypeFree( pStubMsg,
                                       pMemory,
                                       pEmbeddedFormat->Type );

                pMemory = Ndr64pMemoryIncrement( pStubMsg,
                                                 pMemory,
                                                 pEmbeddedFormat->Type,
                                                 FALSE );

                pMemberLayout += sizeof( *pEmbeddedFormat );

                break;
                }

            case FC64_BUFFER_ALIGN:
                {
                const NDR64_BUFFER_ALIGN_FORMAT *pBufAlign = 
                    (NDR64_BUFFER_ALIGN_FORMAT*) pMemberLayout;
                pMemberLayout += sizeof( *pBufAlign );
                break;
                }

             case FC64_CHAR :
             case FC64_WCHAR :
             case FC64_INT8:
             case FC64_UINT8:
             case FC64_INT16:
             case FC64_UINT16:
             case FC64_INT32:
             case FC64_UINT32:
             case FC64_INT64:
             case FC64_UINT64:
             case FC64_FLOAT32 :
             case FC64_FLOAT64 :
             case FC64_ERROR_STATUS_T:
                pMemory       += NDR64_SIMPLE_TYPE_MEMSIZE(*pMemberLayout);
                pMemberLayout += sizeof(NDR64_SIMPLE_MEMBER_FORMAT);
                break;
                        
            case FC64_IGNORE :
                pMemory             += PTR_MEM_SIZE;
                pMemberLayout       += sizeof(NDR64_SIMPLE_MEMBER_FORMAT);
                break;
            
            case FC64_END :
                goto ComplexFreeEnd;

            default :
                NDR_ASSERT(0,"Ndr64ComplexStructFree : bad format char");
                RpcRaiseException( RPC_S_INTERNAL_ERROR );
                return;
            } // switch
        } // for

ComplexFreeEnd :

    if ( pFormatArray )
        {

        Ndr64EmbeddedTypeFree( pStubMsg,
                               pMemory,
                               pFormatArray );
        }
}


void 
Ndr64FixedArrayFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees a fixed array's embedded pointers which were allocated during 
    a remote call.  

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    const NDR64_FIX_ARRAY_HEADER_FORMAT * pArrayFormat =
        (NDR64_FIX_ARRAY_HEADER_FORMAT*) pFormat;
    
    if ( ! pMemory || !pArrayFormat->Flags.HasPointerInfo ) 
        return;
    
    Ndr64pPointerLayoutFree( pStubMsg,
                             pArrayFormat + 1,
                             0,
                             pMemory );

}


void 
Ndr64ConformantArrayFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees a one dimensional conformant array's embedded pointers which were 
    allocated during a remote call.  Called for both top level and embedded
    conformant arrays.

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    const NDR64_CONF_ARRAY_HEADER_FORMAT *pArrayFormat =
        (NDR64_CONF_ARRAY_HEADER_FORMAT*) pFormat;
    
    if ( ! pMemory || !pArrayFormat->Flags.HasPointerInfo ) 
        return;

    NDR64_UINT32 MaxCount = (NDR64_UINT32)
    Ndr64EvaluateExpr( pStubMsg,
                       pArrayFormat->ConfDescriptor,
                       EXPR_MAXCOUNT );

    Ndr64pPointerLayoutFree( pStubMsg,
                             pArrayFormat + 1,
                             MaxCount,
                             pMemory );
        
}


void 
Ndr64ConformantVaryingArrayFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees a one dimensional conformant varying array's embedded pointers which 
    were allocated during a remote call.  Called for both top level and 
    embedded conformant varying arrays.

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    const NDR64_CONF_VAR_ARRAY_HEADER_FORMAT * pArrayFormat =
        (NDR64_CONF_VAR_ARRAY_HEADER_FORMAT*) pFormat;

    if ( ! pMemory || !pArrayFormat->Flags.HasPointerInfo) 
        return;
    
    NDR64_UINT32 ActualCount = (NDR64_UINT32)
        Ndr64EvaluateExpr( pStubMsg,
                           pArrayFormat->VarDescriptor,
                           EXPR_ACTUALCOUNT );

    Ndr64pPointerLayoutFree( pStubMsg,
                             pArrayFormat + 1,
                             ActualCount,
                             pMemory );
}


void 
Ndr64VaryingArrayFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees a varying array's embedded pointers which were allocated 
    during a remote call.  Called for both top level and embedded varying
    arrays.

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    const NDR64_VAR_ARRAY_HEADER_FORMAT * pArrayFormat =
        (NDR64_VAR_ARRAY_HEADER_FORMAT*) pFormat;
    
    if ( ! pMemory || !pArrayFormat->Flags.HasPointerInfo) 
        return;

    NDR64_UINT32 ActualCount = (NDR64_UINT32)
    Ndr64EvaluateExpr( pStubMsg,
                       pArrayFormat->VarDescriptor,
                       EXPR_ACTUALCOUNT );

    Ndr64pPointerLayoutFree( pStubMsg,
                             pArrayFormat + 1,
                             ActualCount,
                             pMemory );

}


void 
Ndr64ComplexArrayFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees a complex array's embedded pointers which were allocated 
    during a remote call.  Called for both top level and embedded complex
    arrays.

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    const NDR64_BOGUS_ARRAY_HEADER_FORMAT *pArrayFormat =
        (NDR64_BOGUS_ARRAY_HEADER_FORMAT *) pFormat;
        
    BOOL                IsFixed = ( pArrayFormat->FormatCode == FC64_FIX_BOGUS_ARRAY ) ||
                                  ( pArrayFormat->FormatCode == FC64_FIX_FORCED_BOGUS_ARRAY );
    
    PFORMAT_STRING      pElementFormat  = (PFORMAT_STRING)pArrayFormat->Element;

    //
    // We have to check this in case we get an exception before actually 
    // unmarshalling the array.
    // 
    if ( ! pMemory ) 
        return;
    
    NDR64_WIRE_COUNT_TYPE    Elements = pArrayFormat->NumberElements; 
    NDR64_WIRE_COUNT_TYPE    Count    = Elements;
    NDR64_WIRE_COUNT_TYPE    Offset   = 0;

    if ( !IsFixed )
        {
        const NDR64_CONF_VAR_BOGUS_ARRAY_HEADER_FORMAT* pConfVarFormat=
             (NDR64_CONF_VAR_BOGUS_ARRAY_HEADER_FORMAT*)pFormat;

        //
        // Check for conformance description.
        //
        if ( pConfVarFormat->ConfDescription )
            {
            Elements = (NDR64_UINT32)Ndr64EvaluateExpr( pStubMsg,
                                                        pConfVarFormat->ConfDescription,
                                                        EXPR_MAXCOUNT );
            Offset = 0;
            Count = Elements;

            }

        //
        // Check for variance description.
        //
        if ( pConfVarFormat->VarDescription )
            {
            Count = (NDR64_UINT32)
                Ndr64EvaluateExpr( pStubMsg,
                                   pConfVarFormat->VarDescription,
                                   EXPR_ACTUALCOUNT );

            Offset = (NDR64_UINT32)
                Ndr64EvaluateExpr( pStubMsg,
                                   pConfVarFormat->OffsetDescription,
                                   EXPR_OFFSET );

            }
        
        }

    NDR64_UINT32    ElementMemorySize = 
        Ndr64pMemorySize( pStubMsg,
                          pElementFormat,
                          FALSE );

    pMemory += Ndr64pConvertTo2GB((NDR64_UINT64)Offset * 
                                  (NDR64_UINT64)ElementMemorySize);

    Ndr64pConvertTo2GB( (NDR64_UINT64)Elements *
                        (NDR64_UINT64)ElementMemorySize );
    Ndr64pConvertTo2GB( (NDR64_UINT64)Count *
                        (NDR64_UINT64)ElementMemorySize );

    for ( ; Count--; )
        {

        Ndr64EmbeddedTypeFree( pStubMsg,
                               pMemory,
                               pElementFormat );

        pMemory += ElementMemorySize;
        }

}


void 
Ndr64UnionFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees an encapsulated union's embedded pointers which were allocated 
    during a remote call.  

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    const NDR64_UNION_ARM_SELECTOR* pArmSelector;

    EXPR_VALUE          SwitchIs;
    NDR64_FORMAT_CHAR   SwitchType;
    uchar *pArmMemory;
    
    if ( !pMemory )
        return;
    
    switch(*(PFORMAT_STRING)pFormat)
        {
        case FC64_NON_ENCAPSULATED_UNION:
            {
            const NDR64_NON_ENCAPSULATED_UNION* pNonEncapUnionFormat =
                (const NDR64_NON_ENCAPSULATED_UNION*) pFormat;

            SwitchType      = pNonEncapUnionFormat->SwitchType;
            pArmSelector    = (NDR64_UNION_ARM_SELECTOR*)(pNonEncapUnionFormat + 1);

            SwitchIs   = Ndr64EvaluateExpr( pStubMsg,
                                            pNonEncapUnionFormat->Switch,
                                            EXPR_SWITCHIS );
            
            pArmMemory = pMemory;
            break;
            }
        case FC64_ENCAPSULATED_UNION:
            {
            const NDR64_ENCAPSULATED_UNION* pEncapUnionFormat =
                (const NDR64_ENCAPSULATED_UNION*)pFormat;

            SwitchType      = pEncapUnionFormat->SwitchType;
            pArmSelector    = (NDR64_UNION_ARM_SELECTOR*)(pEncapUnionFormat + 1);
                
            SwitchIs        = Ndr64pSimpleTypeToExprValue( SwitchType,
                                                           pMemory );
            pArmMemory      = pMemory + pEncapUnionFormat->MemoryOffset;
            break;
            }
        default:
            NDR_ASSERT("Bad union format\n", 0);
            return;
        }

    PNDR64_FORMAT pArmFormat = 
        Ndr64pFindUnionArm( pStubMsg,
                            pArmSelector, 
                            SwitchIs );
    
    if ( !pArmFormat )
        return;

    Ndr64EmbeddedTypeFree( pStubMsg,
                           pArmMemory,
                           pArmFormat );
}


void 
Ndr64XmitOrRepAsFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees the transmit-as object (actually the presented type instance)
    and steps over the object.

    There is an exceptional situation where the spec forbids stub to free
    the instance. This happens when there is an [in] only parameter with
    a [transmit_as()] on a component of the parameter, and the presented
    typedef is composed of one or more pointers.
    We have a flag in the stub msg that is set when this happens.

    See mrshl.c for the description of the FC layout.

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    const NDR64_TRANSMIT_AS_FORMAT *pTransFormat =
        ( const NDR64_TRANSMIT_AS_FORMAT *) pFormat;
    
    if ( !pMemory )
        return;

    NDR_ASSERT( pTransFormat->FormatCode == FC64_TRANSMIT_AS || pTransFormat->FormatCode , "invalid format string for user marshal" );

    unsigned short QIndex = pTransFormat->RoutineIndex;
    const XMIT_ROUTINE_QUINTUPLE * pQuintuple = pStubMsg->StubDesc->aXmitQuintuple;

    // Free the presented type instance unless forbidden explicitely.

    if ( ! pStubMsg->fDontCallFreeInst )
        {
        pStubMsg->pPresentedType = pMemory;
        pQuintuple[ QIndex ].pfnFreeInst( pStubMsg );
        }
}


void 
Ndr64UserMarshalFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PNDR64_FORMAT       pFormat )
/*++

Routine Description :

    Frees the usr_marshal object and steps over the object.
    See mrshl.c for the description of the layouts.

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to be freed.
    pFormat     - Pointer's format string description.

Return :

    None.

--*/
{
    NDR64_USER_MARSHAL_FORMAT  *      pUserFormat = 
        ( NDR64_USER_MARSHAL_FORMAT *) pFormat;

    NDR_ASSERT( pUserFormat->FormatCode == FC64_USER_MARSHAL, "invalid format string for user marshal" );

    unsigned short QIndex = pUserFormat->RoutineIndex;
    const USER_MARSHAL_ROUTINE_QUADRUPLE * pQuadruple = 
        (const USER_MARSHAL_ROUTINE_QUADRUPLE *)( (  NDR_PROC_CONTEXT *)pStubMsg->pContext )->pSyntaxInfo->aUserMarshalQuadruple;

    // Call the user to free his stuff.
    USER_MARSHAL_CB        UserMarshalCB;
    Ndr64pInitUserMarshalCB( pStubMsg,
                           pUserFormat,
                           USER_MARSHAL_CB_FREE,
                           & UserMarshalCB);

    // The user shouldn't ever free the top level object as we free it.
    // He should free only pointees of his top level object.

    pQuadruple[ QIndex ].pfnFree( (ulong*) &UserMarshalCB, pMemory );

    // Ndr64pMemoryIncrement steps over the memory object.
}

// define the jump table
#define NDR64_BEGIN_TABLE  \
PNDR64_FREE_ROUTINE extern const Ndr64FreeRoutinesTable[] = \
{                                                          

#define NDR64_TABLE_END    \
};                         

#define NDR64_ZERO_ENTRY   NULL
#define NDR64_UNUSED_TABLE_ENTRY( number, tokenname ) ,NULL
#define NDR64_UNUSED_TABLE_ENTRY_NOSYM( number ) ,NULL

#define NDR64_TABLE_ENTRY( number, tokenname, marshall, embeddedmarshall, unmarshall, embeddedunmarshall, buffersize, embeddedbuffersize, memsize, embeddedmemsize, free, embeddedfree, typeflags ) \
   ,free                     

#define NDR64_SIMPLE_TYPE_TABLE_ENTRY( number, tokenname, buffersize, memorysize) \
   ,Ndr64pNoopFree         
   

#include "tokntbl.h"

C_ASSERT( sizeof(Ndr64FreeRoutinesTable)/sizeof(PNDR64_FREE_ROUTINE) == 256 );

#undef NDR64_BEGIN_TABLE
#undef NDR64_TABLE_ENTRY

#define NDR64_BEGIN_TABLE \
PNDR64_FREE_ROUTINE extern const Ndr64EmbeddedFreeRoutinesTable[] = \
{

#define NDR64_TABLE_ENTRY( number, tokenname, marshall, embeddedmarshall, unmarshall, embeddedunmarshall, buffersize, embeddedbuffersize, memsize, embeddedmemsize, free, embeddedfree, typeflags ) \
   ,embeddedfree
   
#include "tokntbl.h"

C_ASSERT( sizeof(Ndr64EmbeddedFreeRoutinesTable) / sizeof(PNDR64_FREE_ROUTINE) == 256 );