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

Copyright (c) 1993 Microsoft Corporation

Module Name :

    unmrshlp.c

Abstract :

    This file contains the routines for unmarshalling an array's or a
    structure's embedded pointers.

Author :

    David Kays  dkays   September 1993.

Revision History :

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

#include "ndrp.h"
#include "attack.h"
#include "pointerq.h"


PFORMAT_STRING
NdrpEmbeddedPointerUnmarshall(
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PFORMAT_STRING      pFormat,
    uchar               fNewMemory )
/*++

Routine Description :

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

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to the structure or array whose embedded pointers
                  are being unmarshalled.
    pFormat     - Pointer layout format string description.
    fNewMemory  - TRUE if the array or structure was allocated during
                  unmarshalling, FALSE otherwise.

Return :

    Format string pointer after the pointer layout.

--*/
{
    uchar **        ppMemPtr;
    uchar **        ppBufPtr;
    uchar *         pBufferMark;
    ULONG_PTR       MaxCountSave;
    long            OffsetSave;

    MaxCountSave =  pStubMsg->MaxCount;
    OffsetSave = pStubMsg->Offset;
    pStubMsg->Memory = pMemory;

    POINTER_BUFFER_SWAP_CONTEXT SwapContext(pStubMsg);
    
    // Save BufferMark in a local.
    pBufferMark = pStubMsg->BufferMark;

    // Increment past FC_PP and FC_PAD.
    pFormat += 2;

    for (;;)
        {
        if ( *pFormat == FC_END )
            {
            return pFormat;
            }

        // Check for FC_FIXED_REPEAT or FC_VARIABLE_REPEAT.
        if ( *pFormat != FC_NO_REPEAT )
            {
            pStubMsg->MaxCount = MaxCountSave;
            pStubMsg->Offset = OffsetSave;

            pStubMsg->BufferMark = pBufferMark;

            pFormat = NdrpEmbeddedRepeatPointerUnmarshall( pStubMsg,
                                                           pMemory,
                                                           pFormat,
                                                           fNewMemory );

            // Continue to the next pointer.
            continue;
            }

        // Compute the pointer to the current memory pointer to the data.
        ppMemPtr = (uchar **)( pMemory + *((signed short *)(pFormat + 2)) );

        // Compute the pointer to the pointer in the buffer.
        ppBufPtr = (uchar **)(pBufferMark + *((signed short *)(pFormat + 4)));

        // Increment to the pointer description.
        pFormat += 6;

        //
        // If the incomming encapsulating memory pointer was just allocated,
        // then explicitly null out the current pointer.
        //
        if ( fNewMemory )
            *ppMemPtr = 0;

        NdrpPointerUnmarshall( 
             pStubMsg,
             (uchar**)ppMemPtr, // Memory rep written here
             *ppMemPtr,
             (long *)ppBufPtr,  // Wire rep written here
             pFormat );

        // Increment to the next pointer description.
        pFormat += 4;
        }
}


PFORMAT_STRING
NdrpEmbeddedRepeatPointerUnmarshall(
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pMemory,
    PFORMAT_STRING      pFormat,
    uchar               fNewMemory )
/*++

Routine Description :

    Unmarshalls an array's embedded pointers.

Arguments :

    pStubMsg    - Pointer to the stub message.
    pMemory     - Pointer to the array whose embedded pointers are being
                  unmarshalled.
    pFormat     - Pointer layout format string description.
    fNewMemory  - TRUE if the array was allocated during unmarshalling,
                  FALSE otherwise.

Return :

    Format string pointer after the pointer layout.

--*/
{
    uchar **        ppMemPtr;
    uchar **        ppBufPtr;
    PFORMAT_STRING  pFormatSave;
    uchar *         pBufferMark;
    uchar *         pArrayElement;
    ulong           RepeatCount, RepeatIncrement, Pointers, PointersSave;

    CORRELATION_RESOURCE_SAVE;

    SAVE_CORRELATION_MEMORY();

    // Get the beginning of the contained structure in the buffer.
    pBufferMark = pStubMsg->BufferMark;

    // Get the repeat count.
    switch ( *pFormat )
        {
        case FC_FIXED_REPEAT :
            pFormat += 2;

            RepeatCount = *((ushort *)pFormat);

            break;

        case FC_VARIABLE_REPEAT :
            RepeatCount = (ulong)pStubMsg->MaxCount;

            //
            // Check if this variable repeat instance also has a variable
            // offset (this would be the case for a conformant varying array
            // of pointers, or structures which contain pointers).  If so then
            // increment the format string to point to the actual first array
            // element which is being marshalled.
            //
            if ( pFormat[1] == FC_VARIABLE_OFFSET )
                pMemory += *((ushort *)(pFormat + 2)) * pStubMsg->Offset;

            // else pFormat[1] == FC_FIXED_OFFSET - do nothing

            break;

        default :
            NDR_ASSERT(0,"NdrpEmbeddedRepeatPointerUnmarshall : bad format");
            RpcRaiseException( RPC_S_INTERNAL_ERROR );
            return 0;
        }

    // Increment format string to increment field.
    pFormat += 2;

    // Get the increment amount between successive pointers.
    RepeatIncrement = *((ushort * &)pFormat)++;

    // Load up pointer to first element of embedded array.
    pArrayElement = pBufferMark + *((ushort * &)pFormat)++;

    // Get number of pointers in each array element.
    PointersSave = Pointers = *((ushort * &)pFormat)++;

    pFormatSave = pFormat;

    //
    // Loop over the number of shipped array elements.
    //
    for ( ; RepeatCount--;
            pBufferMark += RepeatIncrement,
            pMemory += RepeatIncrement,
            pArrayElement += RepeatIncrement )
        {
        pFormat = pFormatSave;
        Pointers = PointersSave;

        // Set the correlation check context to be the beginning of each element
        // in the array. This is necessary since other functions will assume that
        // the context points to the top of the flat part of the containing structure.
        // If the containing structure is embedded in another structure, the offset
        // for correlation checks will be relative to the topmost structure.
        pStubMsg->pCorrMemory = pArrayElement;

        //
        // Loop over the number of pointer per array element (which can
        // be greater than one for an array of structures).
        //
        for ( ; Pointers--; )
            {
            // Pointer to the pointer in memory.
            ppMemPtr = (uchar **)(pMemory + *((signed short * &)pFormat)++);

            // Pointer to the pointer's id in the buffer.
            ppBufPtr = (uchar **)(pBufferMark + *((signed short * &)pFormat)++);

            //
            // If the incomming encapsulating memory pointer was just
            // allocated, then explicitly null out the current pointer.
            //
            if ( fNewMemory )
                *ppMemPtr = 0;

            NdrpPointerUnmarshall( 
                pStubMsg,
                (uchar**)ppMemPtr, // Memory rep written here
                *ppMemPtr,
                (long *)ppBufPtr,  // Wire rep written here
                pFormat );

            // Increment past the pointer description.
            pFormat += 4;
            }
        }

    RESET_CORRELATION_MEMORY();

    // Return the format string pointer past the array's pointer description.
    return pFormatSave + PointersSave * 8;
}