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

Copyright (c) 2000 Microsoft Corporation

Module Name :

    pointer.cxx

Abstract :

    This file contains the routines for handling pointers and pointer
    layouts.
    
Author :

    Mike Zoran  mzoran   January 2000.

Revision History :

  ---------------------------------------------------------------------*/
#include "precomp.hxx"

#if !defined(DBG)
// Optimize for time to force inlining.
#pragma optimize("gt", on)

#endif

typedef enum 
{
    NDR64_CORRELATION_NONE=0,
    NDR64_CORRELATION_MEMORY=1,
    NDR64_CORRELATION_BUFFER=2
} NDR64_CORRELATION_TYPE;

template<class Function>
static __forceinline void
Ndr64pProcessPointerLayout( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    PNDR64_FORMAT       pLayoutFormat,
    NDR64_UINT32        ArrayIterations,
    uchar *             pMemory,
    uchar *             pBuffer,
    const NDR64_CORRELATION_TYPE CorrType,
    Function            func )
/*++

Routine Description :

    Marshalls an array's or a structure's embedded pointers.

Arguments :

    pStubMsg        - Pointer to the stub message.
    pFormat         - The format string pointer layout.
    ArrayIterations - Numbers of iterations for variable sized arrays.
    pMemory         - Pointer to the structure or array whose embedded pointers 
                      are being marshalled.
    pBuffer         - Pointer to the buffer for the structure or arrays
    CorrType        - Determines how to set pCorrMemory.
    func            - Function to call to do the processing 
 

Return :

    Format string pointer after the pointer layout.

 --*/
{

    PFORMAT_STRING pFormat = (PFORMAT_STRING)pLayoutFormat;

    for (;;) 
        {

        const NDR64_REPEAT_FORMAT *pRepeatFormat;
        NDR64_UINT32 Iterations;

        switch( *pFormat )
            {

            case FC64_NO_REPEAT:
                {
                const NDR64_NO_REPEAT_FORMAT                *pNoRepeatHeader  = 
                    (NDR64_NO_REPEAT_FORMAT*)pFormat;
                
                const NDR64_POINTER_INSTANCE_HEADER_FORMAT  *pPointerInstance =
                    (NDR64_POINTER_INSTANCE_HEADER_FORMAT   *)(pNoRepeatHeader + 1);
                
                const NDR64_POINTER_FORMAT           *pPointerFormat = 
                    (NDR64_POINTER_FORMAT*)(pPointerInstance + 1);

                uchar *pMemPtr = pMemory + pPointerInstance->Offset;
                uchar *pBufPtr = pBuffer + pPointerInstance->Offset;
                
                func( pStubMsg,
                      pMemPtr,
                      pBufPtr ,
                      pPointerFormat );

                pFormat += sizeof(NDR64_NO_REPEAT_FORMAT) + 
                           sizeof(NDR64_POINTER_INSTANCE_HEADER_FORMAT) +
                           sizeof(NDR64_POINTER_FORMAT);

                break;
                }
            
            case FC64_FIXED_REPEAT:
                Iterations = ((NDR64_FIXED_REPEAT_FORMAT*)pFormat)->Iterations;
                pRepeatFormat = (NDR64_REPEAT_FORMAT*)pFormat;
                pFormat += sizeof(NDR64_FIXED_REPEAT_FORMAT);
                goto RepeatCommon;

            case FC64_VARIABLE_REPEAT:
                Iterations = ArrayIterations;
                pRepeatFormat = (NDR64_REPEAT_FORMAT*)pFormat;
                pFormat += sizeof(NDR64_REPEAT_FORMAT);
                // Fall through to Repeat Common
RepeatCommon:
                {

                uchar *pArrayMemory = pMemory + pRepeatFormat->OffsetToArray;
                uchar *pArrayBuffer = pBuffer + pRepeatFormat->OffsetToArray;
                PFORMAT_STRING pFormatSave = pFormat;

                uchar *pCorrMemorySave;
                if ( CorrType ) 
                    pCorrMemorySave = pStubMsg->pCorrMemory;

                    {
                    // Loop over the array elements
                    for( ; Iterations; 
                         Iterations--,
                         pArrayMemory += pRepeatFormat->Increment,
                         pArrayBuffer += pRepeatFormat->Increment)
                        {

                        pFormat = pFormatSave;

                        if ( CorrType ) 
                            {
                            if ( CorrType == NDR64_CORRELATION_MEMORY ) 
                                {
                                if (pRepeatFormat->Flags.SetCorrMark)
                                    pStubMsg->pCorrMemory = pArrayMemory;                      
                                }
                            else 
                                {
                                if (pRepeatFormat->Flags.SetCorrMark)
                                    pStubMsg->pCorrMemory = pArrayBuffer;                      
                                }
                            }

                        // Loop over the pointers per element
                        for ( NDR64_UINT32 Pointers = pRepeatFormat->NumberOfPointers;
                              Pointers; Pointers-- ) 
                            {

                            const NDR64_POINTER_INSTANCE_HEADER_FORMAT  *pPointerInstance =
                                  (NDR64_POINTER_INSTANCE_HEADER_FORMAT   *)pFormat;
                            const NDR64_POINTER_FORMAT           *pPointerFormat = 
                                  (NDR64_POINTER_FORMAT*)(pPointerInstance + 1);

                            uchar *pMemPtr = pArrayMemory + pPointerInstance->Offset;
                            uchar *pBufPtr = pArrayBuffer + pPointerInstance->Offset;

                            func( pStubMsg,
                                  pMemPtr,
                                  pBufPtr,
                                  pPointerFormat );

                            pFormat += sizeof(NDR64_POINTER_INSTANCE_HEADER_FORMAT) +
                                       sizeof(NDR64_POINTER_FORMAT);
                            }
                        }
                    
                    }

                if ( CorrType ) 
                    pStubMsg->pCorrMemory = pCorrMemorySave;
                
                }
            
            case FC64_END:

                return;

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

static __forceinline void 
Ndr64pPointerLayoutMarshallCallback(
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar*              pMemPtr,
    uchar*              pBufPtr,
    PNDR64_FORMAT       pFormat )
{

    Ndr64pPointerMarshall
        ( pStubMsg,
          (NDR64_PTR_WIRE_TYPE*)pBufPtr,
          *(uchar**)pMemPtr,
          (PFORMAT_STRING)pFormat );        
}


void
Ndr64pPointerLayoutMarshall( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    PNDR64_FORMAT       pFormat,
    NDR64_UINT32        ArrayIterations,
    uchar *             pMemory,
    uchar *             pBuffer )
{

    POINTER_BUFFER_SWAP_CONTEXT SwapContext( pStubMsg );

    Ndr64pProcessPointerLayout(
        pStubMsg,
        pFormat,
        ArrayIterations,
        pMemory,
        pBuffer,
        NDR64_CORRELATION_MEMORY,
        Ndr64pPointerLayoutMarshallCallback);

}

static __forceinline void 
Ndr64pPointerLayoutUnmarshallCallback(
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar*              pMemPtr,
    uchar*              pBufPtr,
    PNDR64_FORMAT       pFormat )
{

   Ndr64pPointerUnmarshall( 
       pStubMsg,
       *(NDR64_PTR_WIRE_TYPE*)pBufPtr,
       (uchar **)pMemPtr,
       *(uchar**)pMemPtr,
       pFormat );

    // Need to copy the value written to the memory pointer back to 
    // the buffer pointer since the buffer will be block copied to the memory. 
    *(uchar **)pBufPtr = *(uchar **)pMemPtr; 
}

void
Ndr64pPointerLayoutUnmarshall(
    PMIDL_STUB_MESSAGE  pStubMsg,
    PNDR64_FORMAT       pFormat,
    NDR64_UINT32        ArrayIterations,
    uchar *             pMemory,
    uchar *             pBuffer ) 
{

    POINTER_BUFFER_SWAP_CONTEXT SwapContext( pStubMsg );

    uchar *pBufferSave = 0;

    // Insert full pointer to ref id translation if needed.
    if ( pStubMsg->FullPtrRefId )
        FULL_POINTER_INSERT( pStubMsg, pMemory );

    Ndr64pProcessPointerLayout(
        pStubMsg,
        pFormat,
        ArrayIterations,
        pMemory,
        pBuffer,
        NDR64_CORRELATION_BUFFER,
        Ndr64pPointerLayoutUnmarshallCallback);

}

static __forceinline void 
Ndr64pPointerLayoutMemorySizeCallback(
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar*              pMemPtr,
    uchar*              pBufPtr,
    PNDR64_FORMAT       pFormat )
{

    // Discard the pMemPtr
    Ndr64pPointerMemorySize( 
        pStubMsg,
        (NDR64_PTR_WIRE_TYPE*)pBufPtr,
        pFormat );

}

void
Ndr64pPointerLayoutMemorySize (
    PMIDL_STUB_MESSAGE  pStubMsg,
    PNDR64_FORMAT       pFormat,
    NDR64_UINT32        ArrayIterations,
    uchar *             pBuffer )
{

    if ( pStubMsg->IgnoreEmbeddedPointers )
        return;

    POINTER_MEMSIZE_SWAP_CONTEXT SwapContext( pStubMsg );

    Ndr64pProcessPointerLayout(
        pStubMsg,
        pFormat,
        ArrayIterations,
        pBuffer,
        pBuffer,
        NDR64_CORRELATION_NONE,
        Ndr64pPointerLayoutMemorySizeCallback );

}

static __forceinline void 
Ndr64pPointerLayoutBufferSizeCallback(
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar*              pMemPtr,
    uchar*              pBufPtr,
    PNDR64_FORMAT       pFormat )
{

    // Discard the BufferPointer
    Ndr64pPointerBufferSize( 
        pStubMsg,
        *(uchar**)pMemPtr,
        pFormat );

}


void 
Ndr64pPointerLayoutBufferSize ( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    PNDR64_FORMAT       pFormat,
    NDR64_UINT32        ArrayIterations,
    uchar *             pMemory )
{

    if ( pStubMsg->IgnoreEmbeddedPointers )
        return;

    POINTER_BUFFERLENGTH_SWAP_CONTEXT SwapContext( pStubMsg );

    Ndr64pProcessPointerLayout(
        pStubMsg,
        pFormat,
        ArrayIterations,
        pMemory,
        pMemory,
        NDR64_CORRELATION_MEMORY,
        Ndr64pPointerLayoutBufferSizeCallback );

}

static __forceinline void 
Ndr64pPointerLayoutFreeCallback(
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar*              pMemPtr,
    uchar*              pBufPtr,
    PNDR64_FORMAT       pFormat )
{

    Ndr64PointerFree( 
        pStubMsg,
        *(uchar**)pMemPtr,
        pFormat );

}


void 
Ndr64pPointerLayoutFree( 
    PMIDL_STUB_MESSAGE  pStubMsg,
    PNDR64_FORMAT       pFormat,
    NDR64_UINT32        ArrayIterations,
    uchar *             pMemory )

{
    Ndr64pProcessPointerLayout(
        pStubMsg,
        pFormat,
        ArrayIterations,
        pMemory,
        pMemory,
        NDR64_CORRELATION_MEMORY,
        Ndr64pPointerLayoutFreeCallback );
 
}