windows-nt/Source/XPSP1/NT/com/rpc/ndr20/pickle.cxx
2020-09-26 16:20:57 +08:00

2377 lines
70 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 1993-2000 Microsoft Corporation
Module Name:
pickle.cxx
Abstract:
This module contains pickling related ndr library routines.
Notes:
Author:
Ryszard K. Kott (ryszardk) Oct 10, 1993
Revision History:
ryszardk Mar 17, 1994 Reworked for midl20
------------------------------------------------------------------------*/
#include <ndrp.h>
#include <rpcdcep.h>
#include "ndrtypes.h"
#include <midles.h>
#include <stdarg.h>
#include <malloc.h>
#include "interp2.h"
#include "mulsyntx.h"
#include "picklep.hxx"
#include "util.hxx" // PerformRpcInitialization
extern const MIDL_FORMAT_STRING __MIDLFormatString;
// DCE puts endianness on the low nibble in the pickling header.
#define NDR_LOCAL_ENDIAN_LOW (NDR_LOCAL_ENDIAN >> 4)
RPC_STATUS
NdrpPerformRpcInitialization (
void
)
{
return PerformRpcInitialization();
}
// =======================================================================
// Handle validation
// =======================================================================
void
NdrpValidateMesHandle(
PMIDL_ES_MESSAGE_EX pMesMsgEx )
{
RpcTryExcept
{
if ( pMesMsgEx == 0 || pMesMsgEx->Signature != MIDL_ES_SIGNATURE ||
pMesMsgEx->MesMsg.MesVersion != MIDL_ES_VERSION )
RpcRaiseException( RPC_S_INVALID_ARG );
}
RpcExcept( 1 )
{
RpcRaiseException( RPC_S_INVALID_ARG );
}
RpcEndExcept
}
RPC_STATUS
NdrpValidateMesHandleReturnStatus(
PMIDL_ES_MESSAGE_EX pMesMsgEx )
{
RPC_STATUS Status = RPC_S_OK;
RpcTryExcept
{
if ( pMesMsgEx == 0 || pMesMsgEx->Signature != MIDL_ES_SIGNATURE ||
( pMesMsgEx->MesMsg.MesVersion != MIDL_ES_VERSION &&
pMesMsgEx->MesMsg.MesVersion != MIDL_NDR64_ES_VERSION ) )
Status = RPC_S_INVALID_ARG;
}
RpcExcept( 1 )
{
Status = RPC_S_INVALID_ARG;
}
RpcEndExcept
return Status;
}
// =======================================================================
// Handle allocation and freeing.
// =======================================================================
RPC_STATUS
NdrpHandleAllocate(
handle_t * pHandle )
/*++
The reason for having this function here is that
handle_t is a near pointer on win16 (but not on Dos),
and we still compile the whole rpcndr20 large for that platform.
So we need near malloc to be within the default segment.
--*/
{
RPC_STATUS RpcStatus;
if ( pHandle == NULL )
return( RPC_S_INVALID_ARG );
// Rpc mtrt heap allocation initialization (any platform).
// This is a macro that returns from NdrpHandleAllocate with
// out of memory error when it fails.
// It's under an if only to facilitate testing.
RpcStatus = NdrpPerformRpcInitialization();
if ( RpcStatus != RPC_S_OK )
return(RpcStatus);
// Now allocate.
// Mes handle includes stubmsg but we need to add rpcmsg to it.
*pHandle = new char[ sizeof(MIDL_ES_MESSAGE_EX) ];
if ( *pHandle == NULL )
return( RPC_S_OUT_OF_MEMORY );
return( RPC_S_OK );
}
RPC_STATUS RPC_ENTRY
MesHandleFree( handle_t Handle )
/*++
This routine frees a pickling handle.
--*/
{
if ( Handle)
{
delete Handle;
}
return( RPC_S_OK );
}
void RPC_ENTRY
I_NdrMesMessageInit(
PMIDL_ES_MESSAGE_EX pMesMsgEx )
{
PMIDL_STUB_MESSAGE pStubMsg = & pMesMsgEx->MesMsg.StubMsg;
PRPC_MESSAGE pRpcMsg = & pMesMsgEx->RpcMsg;
MIDL_memset( pStubMsg, 0, sizeof(MIDL_STUB_MESSAGE) );
MIDL_memset( pRpcMsg, 0, sizeof(RPC_MESSAGE) );
pRpcMsg->DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
pStubMsg->RpcMsg = pRpcMsg;
pStubMsg->IsClient = 1;
NdrSetupLowStackMark( pStubMsg );
}
// =======================================================================
RPC_STATUS RPC_ENTRY
MesEncodeIncrementalHandleCreate(
void * UserState,
MIDL_ES_ALLOC Alloc,
MIDL_ES_WRITE Write,
handle_t * pHandle )
/*++
This routine creates an encoding incremental pickling handle.
--*/
{
RPC_STATUS Status;
if ( (Status = NdrpHandleAllocate( pHandle )) == RPC_S_OK )
{
((PMIDL_ES_MESSAGE) *pHandle)->HandleStyle = MES_INCREMENTAL_HANDLE;
((PMIDL_ES_MESSAGE) *pHandle)->MesVersion = MIDL_ES_VERSION;
((PMIDL_ES_MESSAGE_EX)*pHandle)->Signature = MIDL_ES_SIGNATURE;
if ( (Status = MesIncrementalHandleReset( *pHandle,
UserState,
Alloc,
Write,
0,
MES_ENCODE )) != RPC_S_OK )
{
MesHandleFree( *pHandle );
*pHandle = NULL;
}
}
return( Status );
}
RPC_STATUS RPC_ENTRY
MesDecodeIncrementalHandleCreate(
void * UserState,
MIDL_ES_READ Read,
handle_t * pHandle )
/*++
This routine creates a descoding incrementsl pickling handle.
--*/
{
RPC_STATUS Status;
if ( (Status = NdrpHandleAllocate( pHandle )) == RPC_S_OK )
{
((PMIDL_ES_MESSAGE) *pHandle)->HandleStyle = MES_INCREMENTAL_HANDLE;
((PMIDL_ES_MESSAGE) *pHandle)->MesVersion = MIDL_ES_VERSION;
((PMIDL_ES_MESSAGE_EX)*pHandle)->Signature = MIDL_ES_SIGNATURE;
if ( (Status = MesIncrementalHandleReset( *pHandle,
UserState,
0,
0,
Read,
MES_DECODE )) != RPC_S_OK )
{
MesHandleFree( *pHandle );
*pHandle = NULL;
}
}
return( Status );
}
RPC_STATUS RPC_ENTRY
MesIncrementalHandleReset(
handle_t Handle,
void * UserState,
MIDL_ES_ALLOC Alloc,
MIDL_ES_WRITE Write,
MIDL_ES_READ Read,
MIDL_ES_CODE Operation )
/*++
This routine initializes a pickling handle with supplied arguments.
--*/
{
RPC_STATUS Status;
Status = NdrpValidateMesHandleReturnStatus( (PMIDL_ES_MESSAGE_EX)Handle );
if ( Status != RPC_S_OK )
return Status;
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
// we support ndr64 pickling now.
if ( Handle == NULL ||
pMesMsg->HandleStyle != MES_INCREMENTAL_HANDLE ||
( Operation != MES_ENCODE &&
Operation != MES_DECODE &&
Operation != MES_ENCODE_NDR64 &&
Operation != MES_DECODE_NDR64 ) )
return( RPC_S_INVALID_ARG );
I_NdrMesMessageInit( (PMIDL_ES_MESSAGE_EX) Handle );
pMesMsg->Operation = Operation;
pMesMsg->HandleFlags = 0;
pMesMsg->ByteCount = 0;
if ( Operation == MES_ENCODE_NDR64 ||
Operation == MES_DECODE_NDR64 )
{
pMesMsg->MesVersion = MIDL_NDR64_ES_VERSION;
}
else
{
pMesMsg->MesVersion = MIDL_ES_VERSION;
}
if ( UserState )
pMesMsg->UserState = UserState;
if ( Alloc )
pMesMsg->Alloc = Alloc;
if ( Write )
pMesMsg->Write = Write;
if ( Read )
pMesMsg->Read = Read;
if ( ( (Operation == MES_ENCODE || Operation == MES_ENCODE_NDR64 ) &&
(pMesMsg->Alloc == NULL || pMesMsg->Write == NULL) ) ||
( (Operation == MES_DECODE || Operation == MES_DECODE_NDR64 ) &&
(pMesMsg->Read == NULL)) )
return( RPC_S_INVALID_ARG );
return( RPC_S_OK );
}
RPC_STATUS RPC_ENTRY
MesEncodeFixedBufferHandleCreate(
char * Buffer,
unsigned long BufferSize,
unsigned long * pEncodedSize,
handle_t * pHandle )
{
RPC_STATUS Status;
if( (LONG_PTR)Buffer & 0x7 )
return( RPC_X_INVALID_BUFFER );
if ( (Status = NdrpHandleAllocate( pHandle )) == RPC_S_OK )
{
((PMIDL_ES_MESSAGE) *pHandle)->HandleStyle = MES_FIXED_BUFFER_HANDLE;
((PMIDL_ES_MESSAGE) *pHandle)->MesVersion = MIDL_ES_VERSION;
((PMIDL_ES_MESSAGE_EX)*pHandle)->Signature = MIDL_ES_SIGNATURE;
if ( (Status = MesBufferHandleReset( *pHandle,
MES_FIXED_BUFFER_HANDLE,
MES_ENCODE,
& Buffer,
BufferSize,
pEncodedSize )) != RPC_S_OK )
{
MesHandleFree( *pHandle );
*pHandle = NULL;
}
}
return( Status );
}
RPC_STATUS RPC_ENTRY
MesEncodeDynBufferHandleCreate(
char ** pBuffer,
unsigned long * pEncodedSize,
handle_t * pHandle )
{
RPC_STATUS Status;
if ( (Status = NdrpHandleAllocate( pHandle )) == RPC_S_OK )
{
((PMIDL_ES_MESSAGE) *pHandle)->HandleStyle = MES_DYNAMIC_BUFFER_HANDLE;
((PMIDL_ES_MESSAGE) *pHandle)->MesVersion = MIDL_ES_VERSION;
((PMIDL_ES_MESSAGE_EX)*pHandle)->Signature = MIDL_ES_SIGNATURE;
if ( (Status = MesBufferHandleReset( *pHandle,
MES_DYNAMIC_BUFFER_HANDLE,
MES_ENCODE,
pBuffer,
0,
pEncodedSize )) != RPC_S_OK )
{
MesHandleFree( *pHandle );
*pHandle = NULL;
}
}
return( Status );
}
RPC_STATUS RPC_ENTRY
MesDecodeBufferHandleCreate(
char * Buffer,
unsigned long BufferSize,
handle_t * pHandle )
{
if ( Buffer == NULL ||
BufferSize < MES_CTYPE_HEADER_SIZE + 8 )
return( RPC_S_INVALID_ARG );
if( (LONG_PTR)Buffer & 0x7 )
return( RPC_X_INVALID_BUFFER );
RPC_STATUS Status;
if ( (Status = NdrpHandleAllocate( pHandle )) == RPC_S_OK )
{
((PMIDL_ES_MESSAGE) *pHandle)->HandleStyle = MES_FIXED_BUFFER_HANDLE;
((PMIDL_ES_MESSAGE) *pHandle)->MesVersion = MIDL_ES_VERSION;
((PMIDL_ES_MESSAGE_EX)*pHandle)->Signature = MIDL_ES_SIGNATURE;
if ( (Status = MesBufferHandleReset( *pHandle,
MES_FIXED_BUFFER_HANDLE,
MES_DECODE,
& Buffer,
BufferSize,
0 )) != RPC_S_OK )
{
MesHandleFree( *pHandle );
*pHandle = NULL;
}
}
return( Status );
}
// reset a pickling handle.
RPC_STATUS RPC_ENTRY
MesBufferHandleReset(
handle_t Handle,
unsigned long HandleStyle,
MIDL_ES_CODE Operation,
char * * pBuffer,
unsigned long BufferSize,
unsigned long * pEncodedSize )
{
RPC_STATUS Status;
Status = NdrpValidateMesHandleReturnStatus( (PMIDL_ES_MESSAGE_EX)Handle );
if ( Status != RPC_S_OK )
return Status;
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
if ( Handle == NULL || pBuffer == NULL ||
( HandleStyle != MES_FIXED_BUFFER_HANDLE &&
HandleStyle != MES_DYNAMIC_BUFFER_HANDLE ) ||
(HandleStyle == MES_FIXED_BUFFER_HANDLE &&
(*pBuffer == NULL || BufferSize < MES_MINIMAL_BUFFER_SIZE)) ||
(Operation == MES_ENCODE && pEncodedSize == NULL) ||
(Operation == MES_DECODE &&
(*pBuffer == NULL || BufferSize < MES_MINIMAL_BUFFER_SIZE))
)
return( RPC_S_INVALID_ARG );
if ( (Operation == MES_ENCODE_NDR64 && pEncodedSize == NULL) ||
(Operation == MES_DECODE_NDR64 &&
(*pBuffer == NULL || BufferSize < MES_MINIMAL_NDR64_BUFFER_SIZE ) ) )
return( RPC_S_INVALID_ARG );
I_NdrMesMessageInit( (PMIDL_ES_MESSAGE_EX) Handle );
pMesMsg->Operation = Operation;
pMesMsg->HandleFlags = 0;
pMesMsg->HandleStyle = HandleStyle;
pMesMsg->ByteCount = 0;
if ( Operation == MES_ENCODE_NDR64 ||
Operation == MES_DECODE_NDR64 )
{
pMesMsg->MesVersion = MIDL_NDR64_ES_VERSION;
}
else
{
pMesMsg->MesVersion = MIDL_ES_VERSION;
}
PMIDL_STUB_MESSAGE pStubMsg = & pMesMsg->StubMsg;
PRPC_MESSAGE pRpcMsg = pMesMsg->StubMsg.RpcMsg;
if ( HandleStyle == MES_FIXED_BUFFER_HANDLE)
{
pMesMsg->Buffer = (uchar *)*pBuffer;
pRpcMsg->BufferLength = BufferSize;
pRpcMsg->Buffer = *pBuffer;
pStubMsg->Buffer = (uchar *)*pBuffer;
pStubMsg->BufferStart = (uchar *)*pBuffer;
pStubMsg->BufferEnd = (uchar *)*pBuffer + BufferSize;
}
if ( HandleStyle == MES_DYNAMIC_BUFFER_HANDLE)
{
pMesMsg->pDynBuffer = (uchar **)pBuffer;
if (Operation == MES_DECODE || Operation == MES_DECODE_NDR64 )
{
pMesMsg->Buffer = (uchar *)*pBuffer;
pRpcMsg->BufferLength = BufferSize;
pRpcMsg->Buffer = *pBuffer;
pStubMsg->Buffer = (uchar *)*pBuffer;
pStubMsg->BufferStart = (uchar *)*pBuffer;
pStubMsg->BufferEnd = (uchar *)*pBuffer + BufferSize;
}
else
{
*pBuffer = NULL;
pRpcMsg->BufferLength = 0;
pRpcMsg->Buffer = 0;
pStubMsg->Buffer = 0;
pStubMsg->BufferStart = 0;
pStubMsg->BufferEnd = 0;
}
}
pMesMsg->BufferSize = BufferSize;
pMesMsg->pEncodedSize = pEncodedSize;
return( RPC_S_OK );
}
RPC_STATUS RPC_ENTRY
MesInqProcEncodingId(
handle_t Handle,
PRPC_SYNTAX_IDENTIFIER pInterfaceId,
unsigned long * pProcNumber )
/*++
The routine returns an informantion about the last proc encoding.
Called before an encode, it should return RPC_X_INVALID_ES_ACTION.
Called after an encode, it should return the last encoding info.
Called before a decode, it should return the same encoding info.
Called after a decode, it should return the just decoded encode info.
--*/
{
RPC_STATUS Status;
Status = NdrpValidateMesHandleReturnStatus( (PMIDL_ES_MESSAGE_EX)Handle );
if ( Status != RPC_S_OK )
return Status;
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
Status = RPC_X_INVALID_ES_ACTION;
if ( Handle == NULL || pInterfaceId == NULL || pProcNumber == NULL )
return( RPC_S_INVALID_ARG );
RpcTryExcept
{
// Note: because we allow to pickle several procs into the same buffer
// (using the same handle without resetting), the PEEKED bit may be
// cleared and the info may still be available.
// On the other hand, the info bit is always set if we unmarshaled
// a header. So check the info bit first.
if ( pMesMsg->Operation == MES_DECODE &&
! GET_MES_INFO_AVAILABLE( pMesMsg ) &&
! GET_MES_HEADER_PEEKED( pMesMsg ) )
{
NdrpProcHeaderUnmarshallAll( pMesMsg );
SET_MES_HEADER_PEEKED( pMesMsg );
}
if ( GET_MES_INFO_AVAILABLE( pMesMsg ) )
{
RpcpMemoryCopy( pInterfaceId,
& pMesMsg->InterfaceId,
sizeof( RPC_SYNTAX_IDENTIFIER ) );
*pProcNumber = pMesMsg->ProcNumber;
Status = RPC_S_OK;
}
// else Status = RPC_X_INVALID_ES_ACTION;
}
RpcExcept(1)
{
Status = RpcExceptionCode();
}
RpcEndExcept
return( Status );
}
// =======================================================================
//
// Private Alloc, Read, Write helper routines
//
// =======================================================================
void
NdrpAllocPicklingBuffer(
PMIDL_ES_MESSAGE pMesMsg,
unsigned int RequiredLen
)
{
unsigned int ActualLen;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
// Get the marshalling buffer.
// alert: assuming the return buffer is aligned at 16 in 64bit platform.
// ndr64 buffer needs to be aligned at 16.
switch ( pMesMsg->HandleStyle )
{
case MES_INCREMENTAL_HANDLE:
// Allocating the pickling buffer.
ActualLen = RequiredLen;
(pMesMsg->Alloc)( pMesMsg->UserState,
(char * *) & pStubMsg->Buffer,
& ActualLen );
if ( ActualLen < RequiredLen )
RpcRaiseException( RPC_S_OUT_OF_MEMORY );
pStubMsg->RpcMsg->BufferLength = ActualLen;
pStubMsg->RpcMsg->Buffer = pStubMsg->Buffer;
pStubMsg->BufferStart = pStubMsg->Buffer;
pStubMsg->BufferEnd = pStubMsg->Buffer + ActualLen;
break;
case MES_FIXED_BUFFER_HANDLE:
break;
case MES_DYNAMIC_BUFFER_HANDLE:
{
// We have to return one buffer for multiple encodings,
// and a cumulative size along with it.
// So, we check if we have to copy data to a new buffer.
uchar * pOldBufferToCopy = NULL;
if ( pMesMsg->ByteCount )
{
RequiredLen += pMesMsg->ByteCount;
pOldBufferToCopy = *pMesMsg->pDynBuffer;
}
pStubMsg->Buffer = (uchar *) pStubMsg->pfnAllocate( RequiredLen );
if ( pStubMsg->Buffer == NULL )
RpcRaiseException( RPC_S_OUT_OF_MEMORY );
if ( pOldBufferToCopy )
{
RpcpMemoryCopy( pStubMsg->Buffer,
pOldBufferToCopy,
pMesMsg->ByteCount );
pStubMsg->pfnFree( pOldBufferToCopy );
}
pStubMsg->RpcMsg->BufferLength = RequiredLen;
pStubMsg->RpcMsg->Buffer = pStubMsg->Buffer;
pStubMsg->BufferStart = pStubMsg->Buffer;
pStubMsg->BufferEnd = pStubMsg->Buffer + RequiredLen;
* pMesMsg->pDynBuffer = pStubMsg->Buffer;
pMesMsg->BufferSize = RequiredLen;
// We write after the previously written buffer.
pStubMsg->Buffer += pMesMsg->ByteCount;
break;
}
}
if( (LONG_PTR)pStubMsg->Buffer & 0x7 )
RpcRaiseException( RPC_X_INVALID_BUFFER );
}
void
NdrpReadPicklingBuffer(
PMIDL_ES_MESSAGE pMesMsg,
unsigned int RequiredLen
)
{
unsigned int ActualLen;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
// Read the marshalling buffer.
if ( pMesMsg->HandleStyle == MES_INCREMENTAL_HANDLE )
{
// Allocating the pickling buffer.
ActualLen = RequiredLen;
(pMesMsg->Read)( pMesMsg->UserState,
(char **) & pStubMsg->Buffer,
& ActualLen );
if ( ActualLen < RequiredLen )
RpcRaiseException( RPC_S_OUT_OF_MEMORY );
pStubMsg->RpcMsg->BufferLength = ActualLen;
pStubMsg->RpcMsg->Buffer = pStubMsg->Buffer;
pStubMsg->BufferStart = pStubMsg->Buffer;
pStubMsg->BufferEnd = pStubMsg->Buffer + ActualLen;
}
if( (LONG_PTR)pStubMsg->Buffer & 0x7 )
RpcRaiseException( RPC_X_INVALID_BUFFER );
}
void
NdrpWritePicklingBuffer(
PMIDL_ES_MESSAGE pMesMsg,
uchar * pBuffer,
size_t WriteLength
)
{
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
NDR_ASSERT( ! ((LONG_PTR)pStubMsg->Buffer & 0x7), "Misaligned buffer" );
NDR_ASSERT( ! (WriteLength & 0x7 ), "Length should be multiple of 8" );
// Write the marshalling buffer.
if ( pMesMsg->HandleStyle == MES_INCREMENTAL_HANDLE )
{
(pMesMsg->Write)( pMesMsg->UserState,
(char * ) pBuffer,
WriteLength );
}
else
{
// We return the cumulative length both for the fixed buffer
// and for the dynamic buffer style.
pMesMsg->ByteCount += WriteLength;
* pMesMsg->pEncodedSize = pMesMsg->ByteCount;
}
}
// =======================================================================
//
// One call generic routine pickling.
//
// =======================================================================
void
NdrpProcHeaderMarshall(
PMIDL_ES_MESSAGE pMesMsg
)
{
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
// Marshall DCE pickle header.
if( (LONG_PTR)pStubMsg->Buffer & 0x7 )
RpcRaiseException( RPC_X_INVALID_BUFFER );
* pStubMsg->Buffer++ = MIDL_ES_VERSION;
* pStubMsg->Buffer++ = NDR_LOCAL_ENDIAN_LOW;
*( PSHORT_LV_CAST pStubMsg->Buffer)++ = (short)0xcccc; // filler
// Marshall transfer syntax from the stub.
RpcpMemoryCopy( pStubMsg->Buffer,
& ((PRPC_CLIENT_INTERFACE)(pStubMsg->
StubDesc->RpcInterfaceInformation))->TransferSyntax,
sizeof(RPC_SYNTAX_IDENTIFIER) );
// We need to remember InterfaceId for inquiries.
RpcpMemoryCopy( & pMesMsg->InterfaceId,
& ((PRPC_CLIENT_INTERFACE)(pStubMsg->
StubDesc->RpcInterfaceInformation))->InterfaceId,
sizeof(RPC_SYNTAX_IDENTIFIER) );
// Marshall InterfaceId and ProcNumber from the handle.
RpcpMemoryCopy( pStubMsg->Buffer + sizeof(RPC_SYNTAX_IDENTIFIER),
& pMesMsg->InterfaceId,
sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(long) );
SET_MES_INFO_AVAILABLE( pMesMsg );
pStubMsg->Buffer += 2 * sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(long);
* pStubMsg->Buffer++ = NDR_LOCAL_ENDIAN_LOW;
* pStubMsg->Buffer++ = NDR_ASCII_CHAR;
* pStubMsg->Buffer++ = (char) (NDR_IEEE_FLOAT >> 8);
* pStubMsg->Buffer++ = 0; // filler
// This is non-DCE element as they have just 4 more bytes of filler here.
// This field is used only when unmarshalling in our incremental style.
*( PLONG_LV_CAST pStubMsg->Buffer)++ = pStubMsg->BufferLength -
MES_PROC_HEADER_SIZE;
}
void
NdrpProcHeaderUnmarshall(
PMIDL_ES_MESSAGE pMesMsg
)
{
unsigned char * BufferToRestore;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
if ( GET_MES_HEADER_PEEKED( pMesMsg ) )
return;
NdrpReadPicklingBuffer( pMesMsg, MES_PROC_HEADER_SIZE );
// Unmarshalling the header
if ( *pStubMsg->Buffer != MIDL_ES_VERSION )
RpcRaiseException( RPC_X_WRONG_ES_VERSION );
BufferToRestore = pStubMsg->Buffer + 4;
if ( pStubMsg->Buffer[1] != NDR_LOCAL_ENDIAN_LOW )
{
// The DCE header has the endianness on the low nibble, while
// our DataRep has it on the high nibble.
// We need only endianess to convert the proc header.
byte Endianness = (pStubMsg->Buffer[1] << 4 );
pStubMsg->RpcMsg->DataRepresentation = Endianness;
pStubMsg->Buffer += 4;
NdrSimpleStructConvert( pStubMsg,
&__MIDLFormatString.Format[32],
FALSE );
}
pStubMsg->Buffer = BufferToRestore;
// Verify the transfer syntax
if ( NULL != pStubMsg->StubDesc )
{
if (0 != RpcpMemoryCompare(
pStubMsg->Buffer,
& ((PRPC_CLIENT_INTERFACE)(pStubMsg->
StubDesc->RpcInterfaceInformation))->
TransferSyntax,
sizeof(RPC_SYNTAX_IDENTIFIER) ) )
{
RpcRaiseException( RPC_S_UNSUPPORTED_TRANS_SYN );
}
}
RpcpMemoryCopy( &((PMIDL_ES_MESSAGE_EX)pMesMsg)->TransferSyntax,
pStubMsg->Buffer,
sizeof( RPC_SYNTAX_IDENTIFIER ) );
pStubMsg->Buffer += sizeof(RPC_SYNTAX_IDENTIFIER);
// We need to remember the last InterfaceId and ProcNumber for inquiries.
RpcpMemoryCopy( & pMesMsg->InterfaceId,
pStubMsg->Buffer,
sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(long) );
pStubMsg->Buffer += sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(long);
SET_MES_INFO_AVAILABLE( pMesMsg );
unsigned long AlienDataRepresentation =
( (pStubMsg->Buffer[0] << 4) | // endianness
pStubMsg->Buffer[1] | // chars
((unsigned long)(pStubMsg->Buffer[2]) << 8) ); // float
pMesMsg->AlienDataRep = AlienDataRepresentation;
pMesMsg->IncrDataSize = (size_t) *(unsigned long *)
(pStubMsg->Buffer + 4);
pStubMsg->Buffer += 8;
}
void
NdrpDataBufferInit(
PMIDL_ES_MESSAGE pMesMsg,
PFORMAT_STRING pProcFormat
)
{
size_t RequiredLen;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
if ( pMesMsg->AlienDataRep != NDR_LOCAL_DATA_REPRESENTATION )
{
pStubMsg->RpcMsg->DataRepresentation = pMesMsg->AlienDataRep;
NdrConvert( pStubMsg, pProcFormat );
}
// When incremental, this is the non-DCE buffer size.
// For non incremental RequiredLen will be ignored.
RequiredLen = pMesMsg->IncrDataSize;
NdrpReadPicklingBuffer( pMesMsg, RequiredLen );
pStubMsg->pfnAllocate = pStubMsg->StubDesc->pfnAllocate;
pStubMsg->pfnFree = pStubMsg->StubDesc->pfnFree;
}
void RPC_VAR_ENTRY
NdrMesProcEncodeDecode(
handle_t Handle,
const MIDL_STUB_DESC * pStubDesc,
PFORMAT_STRING pFormat,
...
)
/*++
Routine description:
Sizes and marshalls [in] arguments, unmarshalls [out] arguments.
Includes a routine header.
Arguments:
Handle - a pickling handle
pStubDesc - a pointer to the stub descriptor,
pFormat - a pointer to the format code describing the object type.
Note:
Please note that all the ... arguments here are pointers.
We will handle them appropriately to access the original arguments.
The pickling header for the routine is included in the sizing.
--*/
{
BOOL fMoreParams;
PFORMAT_STRING pProcFormat;
void * pArg;
va_list ArgList;
unsigned char * BufferSaved;
size_t WriteLength;
NdrpValidateMesHandle( (PMIDL_ES_MESSAGE_EX)Handle );
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
PMIDL_STUB_MESSAGE pStubMsg = & pMesMsg->StubMsg;
NDR_ASSERT( *pFormat == FC_BIND_PRIMITIVE || *pFormat == 0,
"Pickling handle expected" );
pStubMsg->StubDesc = pStubDesc;
pStubMsg->pfnAllocate = pStubDesc->pfnAllocate;
pStubMsg->pfnFree = pStubDesc->pfnFree;
BOOL fEncodeUsed = (pFormat[1] & ENCODE_IS_USED) &&
pMesMsg->Operation == MES_ENCODE;
BOOL fDecodeUsed = (pFormat[1] & DECODE_IS_USED) &&
pMesMsg->Operation == MES_DECODE;
NDR_ASSERT( !( fEncodeUsed && fDecodeUsed ),
"Both encode & decode at the same time" );
if ( !fEncodeUsed && !fDecodeUsed )
RpcRaiseException( RPC_X_INVALID_ES_ACTION );
pStubMsg->FullPtrXlatTables = ( (pFormat[1] & Oi_FULL_PTR_USED)
? NdrFullPointerXlatInit( 0, XLAT_CLIENT )
: 0 );
pFormat += HAS_RPCFLAGS(pFormat[1]) ? 6
: 2;
// We use the proc number only to support MesInqEncodingId. So, set it for
// encoding only. When decoding it will get picked up from the header.
//
if ( fEncodeUsed )
pMesMsg->ProcNumber = * (unsigned short *) pFormat;
pFormat +=4;
if ( *pFormat == FC_BIND_PRIMITIVE )
pFormat += 4;
if ( fEncodeUsed )
{
//
// The sizing walk.
//
pStubMsg->BufferLength = MES_PROC_HEADER_SIZE;
// We will be walking this routine's stack.
// However, for the engine to be able to calculate conformant arrays
// and such, top of the original routine's stack has to be available
// via the stub message.
INIT_ARG( ArgList, pFormat );
GET_FIRST_ARG( pArg, ArgList );
pStubMsg->StackTop = *(uchar * *)pArg;
pProcFormat = pFormat;
fMoreParams = TRUE;
for ( ; fMoreParams ; pProcFormat += 2 )
{
switch ( *pProcFormat )
{
case FC_OUT_PARAM:
break;
case FC_RETURN_PARAM:
fMoreParams = FALSE;
break;
default:
fMoreParams = FALSE;
break;
case FC_IN_PARAM_BASETYPE :
LENGTH_ALIGN( pStubMsg->BufferLength,
SIMPLE_TYPE_ALIGNMENT( pProcFormat[1] ));
pStubMsg->BufferLength +=
SIMPLE_TYPE_BUFSIZE( pProcFormat[1] );
break;
case FC_IN_PARAM:
case FC_IN_PARAM_NO_FREE_INST:
// Other [in] types than simple or ignore
// fall through to [in,out].
case FC_IN_OUT_PARAM:
{
uchar * pOrigArg = *(uchar * *)pArg;
PFORMAT_STRING pTypeFormat;
unsigned char FcType;
pProcFormat += 2;
pTypeFormat = pStubDesc->pFormatTypes +
*(signed short *) pProcFormat;
FcType = *pTypeFormat;
if ( ! IS_BY_VALUE( FcType ) )
pOrigArg = *(uchar * *)pOrigArg;
(*pfnSizeRoutines[ ROUTINE_INDEX( FcType ) ])( pStubMsg,
pOrigArg,
pTypeFormat );
}
break;
}
GET_NEXT_ARG( pArg, ArgList );
} // for
LENGTH_ALIGN( pStubMsg->BufferLength, 7 );
size_t LengthSaved;
NdrpAllocPicklingBuffer( pMesMsg, pStubMsg->BufferLength );
BufferSaved = pStubMsg->Buffer;
LengthSaved = pStubMsg->BufferLength;
//
// Marshalling.
//
NdrpProcHeaderMarshall( pMesMsg );
INIT_ARG( ArgList, pFormat );
GET_FIRST_ARG( pArg, ArgList );
pProcFormat = pFormat;
fMoreParams = TRUE;
for ( ; fMoreParams ; pProcFormat += 2 )
{
switch ( *pProcFormat )
{
case FC_OUT_PARAM:
break;
case FC_RETURN_PARAM:
default:
fMoreParams = FALSE;
break;
case FC_IN_PARAM_BASETYPE :
NdrSimpleTypeMarshall( pStubMsg,
*(uchar * *)pArg,
pProcFormat[1] );
break;
case FC_IN_PARAM:
case FC_IN_PARAM_NO_FREE_INST:
case FC_IN_OUT_PARAM:
{
uchar * pOrigArg = *(uchar * *)pArg;
PFORMAT_STRING pTypeFormat;
unsigned char FcType;
pProcFormat += 2;
pTypeFormat = pStubDesc->pFormatTypes +
*(signed short *) pProcFormat;
FcType = *pTypeFormat;
if ( ! IS_BY_VALUE( FcType ) )
pOrigArg = *(uchar * *)pOrigArg;
(*pfnMarshallRoutines[ ROUTINE_INDEX( FcType )])( pStubMsg,
pOrigArg,
pTypeFormat );
}
break;
}
GET_NEXT_ARG( pArg, ArgList );
}
// Next encoding (if any) starts at aligned to 8.
ALIGN( pStubMsg->Buffer, 7 );
// Now manage the actual size of encoded data.
WriteLength = (size_t)(pStubMsg->Buffer - BufferSaved);
* (unsigned long *)
( BufferSaved + MES_PROC_HEADER_SIZE - 4) =
WriteLength - MES_PROC_HEADER_SIZE;
if ( LengthSaved < WriteLength )
{
NDR_ASSERT( 0, "NdrMesProcEncodeDecode: encode buffer overflow" );
RpcRaiseException( RPC_S_INTERNAL_ERROR );
}
NdrpWritePicklingBuffer( pMesMsg, BufferSaved, WriteLength );
}
if ( fDecodeUsed )
{
//
// Unmarshalling.
//
if ( GET_MES_HEADER_PEEKED( pMesMsg ) )
{
// This makes it possible to encode/decode several procs one after
// another with the same pickling handle (using the same buffer).
CLEAR_MES_HEADER_PEEKED( pMesMsg );
}
else
NdrpProcHeaderUnmarshall( pMesMsg );
NdrpDataBufferInit( pMesMsg, pFormat );
INIT_ARG( ArgList, pFormat );
GET_FIRST_ARG( pArg, ArgList );
pStubMsg->StackTop = *(uchar * *)pArg;
pProcFormat = pFormat;
fMoreParams = TRUE;
for ( ; fMoreParams ; pProcFormat += 2 )
{
switch ( *pProcFormat )
{
case FC_IN_PARAM_BASETYPE :
case FC_IN_PARAM:
case FC_IN_PARAM_NO_FREE_INST:
break;
default:
fMoreParams = FALSE;
break;
case FC_RETURN_PARAM_BASETYPE :
NdrSimpleTypeUnmarshall( pStubMsg,
*(uchar * *)pArg,
pProcFormat[1] );
fMoreParams = FALSE;
break;
case FC_RETURN_PARAM:
fMoreParams = FALSE;
// fall through to out params.
case FC_IN_OUT_PARAM:
case FC_OUT_PARAM:
{
uchar * pOrigArg = *(uchar * *)pArg;
PFORMAT_STRING pTypeFormat;
unsigned char FcType;
pProcFormat += 2;
pTypeFormat = pStubDesc->pFormatTypes +
*(signed short *) pProcFormat;
FcType = *pTypeFormat;
if ( IS_STRUCT( FcType ) || IS_UNION( FcType) ||
IS_XMIT_AS( FcType ) )
{
// All these are possible only as a return value.
pOrigArg = (uchar *) &pOrigArg;
}
else
pOrigArg = (uchar *)pOrigArg;
(*pfnUnmarshallRoutines[ ROUTINE_INDEX( FcType )])(
pStubMsg,
(uchar * *)pOrigArg,
pTypeFormat,
FALSE );
}
break;
}
GET_NEXT_ARG( pArg, ArgList );
} // for
// Next decoding (if any) starts at aligned to 8.
ALIGN( pStubMsg->Buffer, 7 );
} // if decode
NdrFullPointerXlatFree( pStubMsg->FullPtrXlatTables );
}
CLIENT_CALL_RETURN RPC_VAR_ENTRY
NdrMesProcEncodeDecode2(
handle_t Handle,
const MIDL_STUB_DESC * pStubDescriptor,
PFORMAT_STRING pFormat,
...
)
{
va_list ArgList;
uchar * StartofStack;
PFORMAT_STRING pFormatParam;
CLIENT_CALL_RETURN ReturnValue;
ulong ProcNum;
uchar * pArg;
void * pThis;
PFORMAT_STRING pProcFormat = pFormat;
unsigned char * BufferSaved;
size_t WriteLength;
NDR_PROC_CONTEXT ProcContext;
PNDR_PROC_HEADER_EXTS pHeaderExts = 0;
ReturnValue.Pointer = 0;
//
// Get address of argument to this function following pFormat. This
// is the address of the address of the first argument of the function
// calling this function.
//
INIT_ARG( ArgList, pFormat);
//
// Get the address of the stack where the parameters are.
//
GET_FIRST_IN_ARG(ArgList);
StartofStack = (uchar *) GET_STACK_START(ArgList);
// StartofStack points to the virtual stack at this point.
NdrpValidateMesHandle( (PMIDL_ES_MESSAGE_EX)Handle );
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
PMIDL_STUB_MESSAGE pStubMsg = & pMesMsg->StubMsg;
NDR_ASSERT( *pFormat == FC_BIND_PRIMITIVE || *pFormat == 0,
"Pickling handle expected" );
pStubMsg->StubDesc = pStubDescriptor;
pStubMsg->pfnAllocate = pStubDescriptor->pfnAllocate;
pStubMsg->pfnFree = pStubDescriptor->pfnFree;
ProcNum = MulNdrpInitializeContextFromProc( XFER_SYNTAX_DCE, pFormat, &ProcContext, StartofStack );
BOOL fEncodeUsed = ( * ( ( uchar *)&ProcContext.NdrInfo.InterpreterFlags ) & ENCODE_IS_USED ) &&
pMesMsg->Operation == MES_ENCODE;
BOOL fDecodeUsed = ( * ( ( uchar *)&ProcContext.NdrInfo.InterpreterFlags ) & DECODE_IS_USED ) &&
pMesMsg->Operation == MES_DECODE;
NDR_ASSERT( !( fEncodeUsed && fDecodeUsed ),
"Both encode & decode at the same time" );
if ( !fEncodeUsed && !fDecodeUsed )
RpcRaiseException( RPC_X_INVALID_ES_ACTION );
if ( fEncodeUsed )
pMesMsg->ProcNumber = ProcNum;
// Must do this before the sizing pass!
pStubMsg->StackTop = StartofStack;
pStubMsg->pContext = &ProcContext;
RpcTryFinally
{
// We don't really need to zeroout here, but code is much more cleaner this way,
// and ObjectProc is the first check anyhow.
NdrpClientInit( pStubMsg, &ReturnValue );
if (fEncodeUsed)
{
//
// ----------------------------------------------------------------
// Sizing Pass.
// ----------------------------------------------------------------
//
pStubMsg->BufferLength += MES_PROC_HEADER_SIZE;
//
// Skip buffer size pass if possible.
//
if ( ProcContext.NdrInfo.pProcDesc->Oi2Flags.ClientMustSize )
{
NdrpSizing( pStubMsg,
TRUE ); // IsClient
}
LENGTH_ALIGN( pStubMsg->BufferLength, 7 );
size_t LengthSaved;
NdrpAllocPicklingBuffer( pMesMsg, pStubMsg->BufferLength );
BufferSaved = pStubMsg->Buffer;
LengthSaved = pStubMsg->BufferLength;
NdrpProcHeaderMarshall( pMesMsg );
//
// ----------------------------------------------------------
// Marshall Pass.
// ----------------------------------------------------------
//
NdrpClientMarshal( pStubMsg,
FALSE ); // IsObject
// Next encoding (if any) starts at aligned to 8.
ALIGN( pStubMsg->Buffer, 7 );
// Now manage the actual size of encoded data.
WriteLength = (size_t)(pStubMsg->Buffer - BufferSaved);
* (unsigned long *) ( BufferSaved + MES_PROC_HEADER_SIZE - 4) =
WriteLength - MES_PROC_HEADER_SIZE;
if ( LengthSaved < WriteLength )
{
NDR_ASSERT( 0, "NdrMesProcEncodeDecode: encode buffer overflow" );
RpcRaiseException( RPC_S_INTERNAL_ERROR );
}
NdrpWritePicklingBuffer( pMesMsg, BufferSaved, WriteLength );
}
if (fDecodeUsed)
{
//
// ----------------------------------------------------------
// Unmarshall Pass.
// ----------------------------------------------------------
//
if ( GET_MES_HEADER_PEEKED( pMesMsg ) )
{
// This makes it possible to encode/decode several procs one after
// another with the same pickling handle (using the same buffer).
CLEAR_MES_HEADER_PEEKED( pMesMsg );
}
else
NdrpProcHeaderUnmarshall( pMesMsg );
NdrpDataBufferInit( pMesMsg, pFormat );
NdrpClientUnMarshal( pStubMsg,
&ReturnValue );
// Next decoding (if any) starts at aligned to 8.
ALIGN( pStubMsg->Buffer, 7 );
} // if decode
}
RpcFinally
{
NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables);
NdrCorrelationFree( pStubMsg );
}
RpcEndFinally
return ReturnValue;
}
// =======================================================================
//
// Generic type pickling routines (for non-simple types).
//
// =======================================================================
void
NdrpCommonTypeHeaderSize(
PMIDL_ES_MESSAGE pMesMsg
)
{
// This check is to prevent a decoding handle from being used
// for both encoding and sizing of types.
if ( pMesMsg->Operation != MES_ENCODE )
RpcRaiseException( RPC_X_INVALID_ES_ACTION );
if ( ! GET_COMMON_TYPE_HEADER_SIZED( pMesMsg ) )
{
pMesMsg->StubMsg.BufferLength += MES_CTYPE_HEADER_SIZE;
SET_COMMON_TYPE_HEADER_SIZED( pMesMsg );
}
}
size_t RPC_ENTRY
NdrMesTypeAlignSize2(
handle_t Handle,
const MIDL_TYPE_PICKLING_INFO * pxPicklingInfo,
const MIDL_STUB_DESC * pStubDesc,
PFORMAT_STRING pFormat,
const void * pObject
)
{
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
PMIDL_TYPE_PICKLING_INFOp pPicklingInfo;
pPicklingInfo = (PMIDL_TYPE_PICKLING_INFOp) pxPicklingInfo;
NDR_ASSERT( pPicklingInfo->Flags.Oicf, "Oicf should always be on" )
pStubMsg->fHasExtensions = 1;
if ( pPicklingInfo->Flags.HasNewCorrDesc )
{
void * pCorrInfo = alloca( NDR_DEFAULT_CORR_CACHE_SIZE );
NdrCorrelationInitialize( pStubMsg,
(unsigned long *) pCorrInfo,
NDR_DEFAULT_CORR_CACHE_SIZE,
0 /* flags */ );
}
return NdrMesTypeAlignSize(Handle, pStubDesc, pFormat, pObject);
}
size_t RPC_ENTRY
NdrMesTypeAlignSize(
handle_t Handle,
const MIDL_STUB_DESC * pStubDesc,
PFORMAT_STRING pFormat,
const void * pObject
)
/*++
Routine description:
Calculates the buffer size of the object relative to the current state
of the pickling handle.
Arguments:
Handle - a pickling handle,
pStubDesc - a pointer to the stub descriptor,
pFormat - a pointer to the format code describing the object type
pObject - a pointer to the object being sized.
Returns:
The size.
Note:
The pickling header is included in the sizing.
--*/
{
NdrpValidateMesHandle( (PMIDL_ES_MESSAGE_EX)Handle );
PMIDL_STUB_MESSAGE pStubMsg = &((PMIDL_ES_MESSAGE)Handle)->StubMsg;
size_t OldLength = pStubMsg->BufferLength;
if ( ! pObject )
RpcRaiseException( RPC_X_NULL_REF_POINTER );
if( (long)pStubMsg->BufferLength & 0x7 )
RpcRaiseException( RPC_X_INVALID_BUFFER );
pStubMsg->StubDesc = pStubDesc;
pStubMsg->pfnAllocate = pStubDesc->pfnAllocate;
pStubMsg->pfnFree = pStubDesc->pfnFree;
// See if we need to size the common type header.
NdrpCommonTypeHeaderSize( (PMIDL_ES_MESSAGE)Handle );
// Now the individual type object.
pStubMsg->BufferLength += MES_HEADER_SIZE;
if ( IS_POINTER_TYPE(*pFormat) )
{
// We have to dereference the pointer once.
pObject = *(void * *)pObject;
}
(*pfnSizeRoutines[ ROUTINE_INDEX(*pFormat) ])
( pStubMsg,
(uchar *)pObject,
pFormat );
LENGTH_ALIGN( pStubMsg->BufferLength, 7 );
return( pStubMsg->BufferLength - OldLength );
}
size_t
NdrpCommonTypeHeaderMarshall(
PMIDL_ES_MESSAGE pMesMsg
)
/*++
Returns the space used by the common header.
--*/
{
if ( ! GET_COMMON_TYPE_HEADER_IN( pMesMsg ) )
{
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
MIDL_memset( pStubMsg->Buffer, 0xcc, MES_CTYPE_HEADER_SIZE );
*pStubMsg->Buffer++ = MIDL_ES_VERSION;
*pStubMsg->Buffer++ = NDR_LOCAL_ENDIAN;
* PSHORT_CAST pStubMsg->Buffer = MES_CTYPE_HEADER_SIZE;
pStubMsg->Buffer += MES_CTYPE_HEADER_SIZE - 2;
SET_COMMON_TYPE_HEADER_IN( pMesMsg );
return( MES_CTYPE_HEADER_SIZE );
}
return( 0 );
}
void RPC_ENTRY
NdrMesTypeEncode2(
handle_t Handle,
const MIDL_TYPE_PICKLING_INFO * pxPicklingInfo,
const MIDL_STUB_DESC * pStubDesc,
PFORMAT_STRING pFormat,
const void * pObject
)
{
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
PMIDL_TYPE_PICKLING_INFOp pPicklingInfo;
pPicklingInfo = (PMIDL_TYPE_PICKLING_INFOp) pxPicklingInfo;
NDR_ASSERT( pPicklingInfo->Flags.Oicf, "Oicf should always be on" )
pStubMsg->fHasExtensions = 1;
if ( pPicklingInfo->Flags.HasNewCorrDesc )
{
void * pCorrInfo = alloca( NDR_DEFAULT_CORR_CACHE_SIZE );
NdrCorrelationInitialize( pStubMsg,
(unsigned long *) pCorrInfo,
NDR_DEFAULT_CORR_CACHE_SIZE,
0 /* flags */ );
}
RpcTryFinally
{
NdrMesTypeEncode(Handle, pStubDesc, pFormat, pObject);
if ( pStubMsg->pCorrInfo )
NdrCorrelationPass( pStubMsg );
}
RpcFinally
{
// while currently we are not using corrinfo in marshalling pass, we need this
// in case we are using corrinfo later (like info for free)
NdrCorrelationFree( pStubMsg );
}
RpcEndFinally
}
void RPC_ENTRY
NdrMesTypeEncode(
handle_t Handle,
const MIDL_STUB_DESC * pStubDesc,
PFORMAT_STRING pFormat,
const void * pObject
)
/*++
Routine description:
Encodes the object to the buffer depending on the state of the handle.
This means: sizing, allocating buffer, marshalling, writing buffer.
Arguments:
Handle - a pickling handle
pStubDesc - a pointer to the stub descriptor,
pFormat - a pointer to the format code describing the object type,
pObject - a pointer to the object being sized.
Returns:
The size.
Note:
The pickling header is included in the sizing.
--*/
{
NdrpValidateMesHandle( (PMIDL_ES_MESSAGE_EX)Handle );
uchar * pBufferSaved;
size_t RequiredLen, CommonHeaderSize, LengthSaved;
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
if ( ! pObject )
RpcRaiseException( RPC_X_NULL_REF_POINTER );
if( (LONG_PTR)pStubMsg->Buffer & 0x7 )
RpcRaiseException( RPC_X_INVALID_BUFFER );
pStubMsg->StubDesc = pStubDesc;
pStubMsg->pfnAllocate = pStubDesc->pfnAllocate;
pStubMsg->pfnFree = pStubDesc->pfnFree;
// Size and allocate the buffer.
// The req len includes: (the common header), the header and the data
// Take the pointer alignment to come up with the right size.
pStubMsg->BufferLength = 0xf & PtrToUlong( pStubMsg->Buffer );
RequiredLen = NdrMesTypeAlignSize( Handle,
pStubDesc,
pFormat,
pObject );
NdrpAllocPicklingBuffer( pMesMsg, RequiredLen );
pBufferSaved = pStubMsg->Buffer;
LengthSaved = RequiredLen;
// See if we need to marshall the common type header
CommonHeaderSize = NdrpCommonTypeHeaderMarshall( pMesMsg );
// Marshall the header and the object.
// zero out the type header (will contain type buffer length after
// encoding is done )
memset( pStubMsg->Buffer, 0, MES_HEADER_SIZE );
pStubMsg->Buffer += MES_HEADER_SIZE;
if ( IS_POINTER_TYPE(*pFormat) )
{
// We have to dereference the pointer once.
pObject = *(void * *)pObject;
}
(*pfnMarshallRoutines[ ROUTINE_INDEX(*pFormat) ])
( pStubMsg,
(uchar *)pObject,
pFormat );
// We adjust the buffer to the next align by 8 and
// so, we tell the user that we've written out till next mod 8.
ALIGN( pStubMsg->Buffer, 7 );
size_t WriteLength = (size_t)(pStubMsg->Buffer - pBufferSaved);
// We always save the rounded up object length in the type header.
*(unsigned long *)(pBufferSaved + CommonHeaderSize) =
WriteLength - CommonHeaderSize - MES_HEADER_SIZE;
if ( LengthSaved < WriteLength )
{
NDR_ASSERT( 0, "NdrMesTypeEncode: encode buffer overflow" );
RpcRaiseException( RPC_S_INTERNAL_ERROR );
}
NdrpWritePicklingBuffer( pMesMsg, pBufferSaved, WriteLength );
}
void
NdrpCommonTypeHeaderUnmarshall(
PMIDL_ES_MESSAGE pMesMsg
)
{
if ( pMesMsg->Operation != MES_DECODE )
RpcRaiseException( RPC_X_INVALID_ES_ACTION );
if ( ! GET_COMMON_TYPE_HEADER_IN( pMesMsg ) )
{
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
NdrpReadPicklingBuffer( pMesMsg, MES_CTYPE_HEADER_SIZE );
// Check the version number, endianness.
if ( *pStubMsg->Buffer != MIDL_ES_VERSION )
RpcRaiseException( RPC_X_WRONG_ES_VERSION );
if ( pStubMsg->Buffer[1] == NDR_LOCAL_ENDIAN )
{
// Read the note about endianess at NdrMesTypeDecode.
//
pMesMsg->AlienDataRep = NDR_LOCAL_DATA_REPRESENTATION;
}
else
{
unsigned char temp = pStubMsg->Buffer[2];
pStubMsg->Buffer[2] = pStubMsg->Buffer[3];
pStubMsg->Buffer[3] = temp;
pMesMsg->AlienDataRep = ( NDR_ASCII_CHAR | // chars
pStubMsg->Buffer[1] | // endianness
NDR_IEEE_FLOAT ); // float
}
pStubMsg->Buffer += MES_CTYPE_HEADER_SIZE;
SET_COMMON_TYPE_HEADER_IN( pMesMsg );
}
}
void RPC_ENTRY
NdrMesTypeDecode2(
handle_t Handle,
const MIDL_TYPE_PICKLING_INFO * pxPicklingInfo,
const MIDL_STUB_DESC * pStubDesc,
PFORMAT_STRING pFormat,
void * pObject
)
{
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
PMIDL_TYPE_PICKLING_INFOp pPicklingInfo;
pPicklingInfo = (PMIDL_TYPE_PICKLING_INFOp) pxPicklingInfo;
NDR_ASSERT( pPicklingInfo->Flags.Oicf, "Oicf should always be on" )
pStubMsg->fHasExtensions = 1;
RpcTryFinally
{
if ( pPicklingInfo->Flags.HasNewCorrDesc )
{
void * pCorrInfo = alloca( NDR_DEFAULT_CORR_CACHE_SIZE );
NdrCorrelationInitialize( pStubMsg,
(unsigned long *) pCorrInfo,
NDR_DEFAULT_CORR_CACHE_SIZE,
0 /* flags */ );
}
NdrMesTypeDecode(Handle, pStubDesc, pFormat, pObject);
if ( pStubMsg->pCorrInfo )
NdrCorrelationPass( pStubMsg );
}
RpcFinally
{
NdrCorrelationFree( pStubMsg );
}
RpcEndFinally
}
void RPC_ENTRY
NdrMesTypeDecode(
handle_t Handle,
const MIDL_STUB_DESC * pStubDesc,
PFORMAT_STRING pFormat,
void * pObject
)
/*++
Routine description:
Decodes the object to the buffer depending on the state of the handle.
This means: reads the header, reads the buffer, unmarshalls.
Arguments:
Handle - a pickling handle
pStubDesc - a pointer to the stub descriptor,
pFormat - a pointer to the format code describing the object type,
pObject - a pointer to the object being sized.
Returns:
The size.
Note:
Endianness and other conversions when decoding *types*.
Starting with Mac implementation, types have a conversion that
takes care of different endianness. ASCII and VAX_FLOAT are still
assummed for types.
Common header conveys the endianness information. The handle gets the
endian info from the common header and so when decoding types, the
handle is used to check if the conversion is needed.
We cannot convert the whole buffer at the time of processing the common
header as the buffer may not be there yet (for incremental handle).
--*/
{
NdrpValidateMesHandle( (PMIDL_ES_MESSAGE_EX)Handle );
size_t RequiredLen;
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
uchar * BufferSaved;
if ( ! pObject )
RpcRaiseException( RPC_X_NULL_REF_POINTER );
pStubMsg->StubDesc = pStubDesc;
pStubMsg->pfnAllocate = pStubDesc->pfnAllocate;
pStubMsg->pfnFree = pStubDesc->pfnFree;
// See if we need to unmarshall the common type header.
NdrpCommonTypeHeaderUnmarshall( pMesMsg );
// Now the individual data object.
NdrpReadPicklingBuffer( pMesMsg, MES_HEADER_SIZE );
// Reading the object. Get the length of the buffer first.
if ( pMesMsg->AlienDataRep != NDR_LOCAL_DATA_REPRESENTATION )
{
pStubMsg->RpcMsg->DataRepresentation = pMesMsg->AlienDataRep;
BufferSaved = pStubMsg->Buffer;
NdrSimpleTypeConvert( pStubMsg, FC_LONG );
pStubMsg->Buffer = BufferSaved;
}
RequiredLen = (size_t) *(unsigned long *)pStubMsg->Buffer;
pStubMsg->Buffer += MES_HEADER_SIZE;
NdrpReadPicklingBuffer( pMesMsg, RequiredLen );
// Now the conversion of the object, if needed.
if ( pMesMsg->AlienDataRep != NDR_LOCAL_DATA_REPRESENTATION )
{
BufferSaved = pStubMsg->Buffer;
(*pfnConvertRoutines[ ROUTINE_INDEX( *pFormat) ])
( pStubMsg,
pFormat,
FALSE );
pStubMsg->Buffer = BufferSaved;
}
// Unmarshalling.
pStubMsg->pfnAllocate = pStubDesc->pfnAllocate;
pStubMsg->pfnFree = pStubDesc->pfnFree;
void * pArg = pObject;
if ( IS_POINTER_TYPE(*pFormat) )
{
// We have to dereference the pointer once.
//
pArg = *(void **)pArg;
}
(*pfnUnmarshallRoutines[ ROUTINE_INDEX( *pFormat )])
( pStubMsg,
(uchar * *)&pArg,
pFormat,
FALSE );
if ( IS_POINTER_TYPE(*pFormat) )
{
// Don't drop the pointee, if it was allocated.
*(void **)pObject = pArg;
}
// Next decoding needs to start at aligned to 8.
ALIGN( pStubMsg->Buffer, 7 );
}
void RPC_ENTRY
NdrMesTypeFree(
handle_t Handle,
const MIDL_STUB_DESC * pStubDesc,
PFORMAT_STRING pFormat,
void * pObject
)
/*++
Routine description:
Free the object.
Arguments:
Handle - a pickling handle,
pStubDesc - a pointer to the stub descriptor,
pFormat - a pointer to the format code describing the object type
pObject - a pointer to the object being freed.
Returns:
Note:
The pickling header is included in the sizing.
--*/
{
NdrpValidateMesHandle( (PMIDL_ES_MESSAGE_EX)Handle );
PMIDL_STUB_MESSAGE pStubMsg = &((PMIDL_ES_MESSAGE)Handle)->StubMsg;
if ( ! pObject )
RpcRaiseException( RPC_X_NULL_REF_POINTER );
if( (LONG_PTR)pStubMsg->Buffer & 0x7 )
RpcRaiseException( RPC_X_INVALID_BUFFER );
pStubMsg->StubDesc = pStubDesc;
pStubMsg->pfnAllocate = pStubDesc->pfnAllocate;
pStubMsg->pfnFree = pStubDesc->pfnFree;
// Now the individual type object.
if ( IS_POINTER_TYPE(*pFormat) )
{
// We have to dereference the pointer once.
pObject = *(void * *)pObject;
}
(*pfnFreeRoutines[ ROUTINE_INDEX(*pFormat) ])
( pStubMsg,
(uchar *)pObject,
pFormat );
}
void RPC_ENTRY
NdrMesTypeFree2(
handle_t Handle,
const MIDL_TYPE_PICKLING_INFO * pxPicklingInfo,
const MIDL_STUB_DESC * pStubDesc,
PFORMAT_STRING pFormat,
void * pObject
)
{
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
PMIDL_TYPE_PICKLING_INFOp pPicklingInfo;
pPicklingInfo = (PMIDL_TYPE_PICKLING_INFOp) pxPicklingInfo;
NDR_ASSERT( pPicklingInfo->Flags.Oicf, "Oicf should always be on" )
pStubMsg->fHasExtensions = 1;
if ( pPicklingInfo->Flags.HasNewCorrDesc )
{
void * pCorrInfo = alloca( NDR_DEFAULT_CORR_CACHE_SIZE );
NdrCorrelationInitialize( pStubMsg,
(unsigned long *) pCorrInfo,
NDR_DEFAULT_CORR_CACHE_SIZE,
0 /* flags */ );
}
NdrMesTypeFree(Handle, pStubDesc, pFormat, pObject);
}
// =======================================================================
//
// Ready to use AlignSize routines for simple types
//
// =======================================================================
size_t RPC_ENTRY
NdrMesSimpleTypeAlignSize(
handle_t Handle )
/*++
Size is always 8 bytes for data and there is no header here per data.
However, the common header gets included for the first object.
--*/
{
NdrpValidateMesHandle( (PMIDL_ES_MESSAGE_EX)Handle );
PMIDL_STUB_MESSAGE pStubMsg = &((PMIDL_ES_MESSAGE) Handle)->StubMsg;
if( (long)( pStubMsg->BufferLength & 0x7 ) )
RpcRaiseException( RPC_X_INVALID_BUFFER );
unsigned long OldLength = pStubMsg->BufferLength;
NdrpCommonTypeHeaderSize( (PMIDL_ES_MESSAGE)Handle );
pStubMsg->BufferLength += 8;
return( (size_t)(pStubMsg->BufferLength - OldLength) );
}
// =======================================================================
//
// Ready to use Encode routines for simple types
//
// =======================================================================
void RPC_ENTRY
NdrMesSimpleTypeEncode(
handle_t Handle,
const MIDL_STUB_DESC * pStubDesc,
const void * pData,
short Size )
/*++
Marshall a simple type entity. There is no header here per data.
However, the common header gets included for the first object.
--*/
{
NdrpValidateMesHandle( (PMIDL_ES_MESSAGE_EX)Handle );
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
pStubMsg->pfnAllocate = pStubDesc->pfnAllocate;
pStubMsg->pfnFree = pStubDesc->pfnFree;
size_t RequiredLen;
// Size and allocate the buffer.
// The req len includes: (the common header) and the data
// Take the pointer alignment to come up with the right size.
pStubMsg->BufferLength = 0xf & PtrToUlong( pStubMsg->Buffer );
RequiredLen = NdrMesSimpleTypeAlignSize( Handle );
NdrpAllocPicklingBuffer( pMesMsg, RequiredLen );
// See if we need to marshall the common type header
uchar * pBufferSaved = pStubMsg->Buffer;
NdrpCommonTypeHeaderMarshall( pMesMsg );
switch ( Size )
{
case 1:
* PCHAR_CAST pStubMsg->Buffer = * PCHAR_CAST pData;
break;
case 2:
* PSHORT_CAST pStubMsg->Buffer = * PSHORT_CAST pData;
break;
case 4:
* PLONG_CAST pStubMsg->Buffer = * PLONG_CAST pData;
break;
case 8:
* PHYPER_CAST pStubMsg->Buffer = * PHYPER_CAST pData;
break;
default:
NDR_ASSERT( 0, " Size generation problem" );
}
pStubMsg->Buffer += 8;
NdrpWritePicklingBuffer( pMesMsg, pBufferSaved, RequiredLen );
}
// =======================================================================
//
// Ready to use Decode routines for simple types
//
// =======================================================================
void RPC_ENTRY
NdrMesSimpleTypeDecode(
handle_t Handle,
void * pData,
short FormatChar )
/*++
Does not include the header for the data.
However, the common header gets included for the first object.
Note. Endianness and other conversions for decode.
This has been deemed as not worthy doing in the Daytona time frame.
However, to be able to add it in future without backward compatibility
problems, we have the last argument to be the format character as
opposed to the size.
This makes it possible to call NdrSimpleTypeConvert, if needed.
--*/
{
NdrpValidateMesHandle( (PMIDL_ES_MESSAGE_EX)Handle );
PMIDL_ES_MESSAGE pMesMsg = (PMIDL_ES_MESSAGE) Handle;
PMIDL_STUB_MESSAGE pStubMsg = &((PMIDL_ES_MESSAGE)Handle)->StubMsg;
uchar * BufferSaved;
// See if we need to unmarshall the common type header.
NdrpCommonTypeHeaderUnmarshall( (PMIDL_ES_MESSAGE) Handle );
// Now the data.
NdrpReadPicklingBuffer( (PMIDL_ES_MESSAGE) Handle, 8);
if ( pMesMsg->AlienDataRep != NDR_LOCAL_DATA_REPRESENTATION )
{
pStubMsg->RpcMsg->DataRepresentation = pMesMsg->AlienDataRep;
BufferSaved = pStubMsg->Buffer;
NdrSimpleTypeConvert( pStubMsg, (unsigned char)FormatChar );
pStubMsg->Buffer = BufferSaved;
}
switch ( FormatChar )
{
case FC_BYTE:
case FC_CHAR:
case FC_SMALL:
case FC_USMALL:
* PCHAR_CAST pData = * PCHAR_CAST pStubMsg->Buffer;
break;
case FC_WCHAR:
case FC_SHORT:
case FC_USHORT:
case FC_ENUM16:
* PSHORT_CAST pData = * PSHORT_CAST pStubMsg->Buffer;
break;
case FC_LONG:
case FC_ULONG:
case FC_FLOAT:
case FC_ENUM32:
case FC_ERROR_STATUS_T:
* PLONG_CAST pData = * PLONG_CAST pStubMsg->Buffer;
break;
case FC_HYPER:
case FC_DOUBLE:
* PHYPER_CAST pData = * PHYPER_CAST pStubMsg->Buffer;
break;
#if defined(__RPC_WIN64__)
case FC_INT3264:
*((INT64 *)pData) = *((long *) pStubMsg->Buffer);
break;
case FC_UINT3264:
*((UINT64 *)pData) = *((ulong *)pStubMsg->Buffer);
break;
#endif
default:
NDR_ASSERT( 0, " Size generation problem for simple types" );
}
pStubMsg->Buffer += 8;
}
void
NdrpProcHeaderMarshallAll(
PMIDL_ES_MESSAGE pMesMsg
)
{
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
// Marshall DCE pickle header.
if( (LONG_PTR)pStubMsg->Buffer & 0x7 )
RpcRaiseException( RPC_X_INVALID_BUFFER );
if ( pMesMsg->Operation == MES_ENCODE )
* pStubMsg->Buffer++ = MIDL_ES_VERSION;
else
* pStubMsg->Buffer++ = MIDL_NDR64_ES_VERSION;
* pStubMsg->Buffer++ = NDR_LOCAL_ENDIAN_LOW;
*( PSHORT_LV_CAST pStubMsg->Buffer)++ = (short)0xcccc; // filler
// Marshall transfer syntax from the stub.
RpcpMemoryCopy( pStubMsg->Buffer,
&( ( PMIDL_ES_MESSAGE_EX)pMesMsg )->TransferSyntax,
sizeof(RPC_SYNTAX_IDENTIFIER) );
// We need to remember InterfaceId for inquiries.
RpcpMemoryCopy( & pMesMsg->InterfaceId,
& ((PRPC_CLIENT_INTERFACE)(pStubMsg->
StubDesc->RpcInterfaceInformation))->InterfaceId,
sizeof(RPC_SYNTAX_IDENTIFIER) );
// Marshall InterfaceId and ProcNumber from the handle.
RpcpMemoryCopy( pStubMsg->Buffer + sizeof(RPC_SYNTAX_IDENTIFIER),
& pMesMsg->InterfaceId,
sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(long) );
SET_MES_INFO_AVAILABLE( pMesMsg );
pStubMsg->Buffer += 2 * sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(long);
* pStubMsg->Buffer++ = NDR_LOCAL_ENDIAN_LOW;
* pStubMsg->Buffer++ = NDR_ASCII_CHAR;
* pStubMsg->Buffer++ = (char) (NDR_IEEE_FLOAT >> 8);
* pStubMsg->Buffer++ = 0; // filler
// This is non-DCE element as they have just 4 more bytes of filler here.
// This field is used only when unmarshalling in our incremental style.
*( PLONG_LV_CAST pStubMsg->Buffer)++ = pStubMsg->BufferLength -
MES_PROC_HEADER_SIZE;
}
void
NdrpProcHeaderUnmarshallAll(
PMIDL_ES_MESSAGE pMesMsg
)
{
unsigned char * BufferToRestore;
PMIDL_STUB_MESSAGE pStubMsg = &pMesMsg->StubMsg;
if ( GET_MES_HEADER_PEEKED( pMesMsg ) )
return;
NdrpReadPicklingBuffer( pMesMsg, MES_PROC_HEADER_SIZE );
// Unmarshalling the header
if ( *pStubMsg->Buffer != MIDL_ES_VERSION &&
*pStubMsg->Buffer != MIDL_NDR64_ES_VERSION)
RpcRaiseException( RPC_X_WRONG_ES_VERSION );
BufferToRestore = pStubMsg->Buffer + 4;
if ( pStubMsg->Buffer[1] != NDR_LOCAL_ENDIAN_LOW )
{
// The DCE header has the endianness on the low nibble, while
// our DataRep has it on the high nibble.
// We need only endianess to convert the proc header.
byte Endianness = (pStubMsg->Buffer[1] << 4 );
pStubMsg->RpcMsg->DataRepresentation = Endianness;
pStubMsg->Buffer += 4;
NdrSimpleStructConvert( pStubMsg,
&__MIDLFormatString.Format[32],
FALSE );
}
pStubMsg->Buffer = BufferToRestore;
// Verify the transfer syntax
RpcpMemoryCopy( &((PMIDL_ES_MESSAGE_EX)pMesMsg)->TransferSyntax,
pStubMsg->Buffer,
sizeof( RPC_SYNTAX_IDENTIFIER ) );
pStubMsg->Buffer += sizeof(RPC_SYNTAX_IDENTIFIER);
// We need to remember the last InterfaceId and ProcNumber for inquiries.
RpcpMemoryCopy( & pMesMsg->InterfaceId,
pStubMsg->Buffer,
sizeof(RPC_SYNTAX_IDENTIFIER) );
pStubMsg->Buffer += sizeof(RPC_SYNTAX_IDENTIFIER);
pMesMsg->ProcNumber = *(ulong *)pStubMsg->Buffer;
pStubMsg->Buffer += 4;
SET_MES_INFO_AVAILABLE( pMesMsg );
unsigned long AlienDataRepresentation =
( (pStubMsg->Buffer[0] << 4) | // endianness
pStubMsg->Buffer[1] | // chars
((unsigned long)(pStubMsg->Buffer[2]) << 8) ); // float
pMesMsg->AlienDataRep = AlienDataRepresentation;
pMesMsg->IncrDataSize = (size_t) *(unsigned long __RPC_FAR *)
(pStubMsg->Buffer + 4);
pStubMsg->Buffer += 8;
}
extern const MIDL_FORMAT_STRING __MIDLFormatString =
{
0,
{
0x1d, /* FC_SMFARRAY */
0x0, /* 0 */
/* 2 */ 0x6, 0x0, /* 6 */
/* 4 */ 0x1, /* FC_BYTE */
0x5b, /* FC_END */
/* 6 */
0x15, /* FC_STRUCT */
0x3, /* 3 */
/* 8 */ 0x10, 0x0, /* 16 */
/* 10 */ 0x8, /* FC_LONG */
0x6, /* FC_SHORT */
/* 12 */ 0x6, /* FC_SHORT */
0x3, /* FC_SMALL */
/* 14 */ 0x3, /* FC_SMALL */
0x4c, /* FC_EMBEDDED_COMPLEX */
/* 16 */ 0x0, /* 0 */
0xef, 0xff, /* Offset= -17 (0) */
0x5b, /* FC_END */
/* 20 */
0x15, /* FC_STRUCT */
0x3, /* 3 */
/* 22 */ 0x14, 0x0, /* 20 */
/* 24 */ 0x4c, /* FC_EMBEDDED_COMPLEX */
0x0, /* 0 */
/* 26 */ 0xec, 0xff, /* Offset= -20 (6) */
/* 28 */ 0x6, /* FC_SHORT */
0x6, /* FC_SHORT */
/* 30 */ 0x5c, /* FC_PAD */
0x5b, /* FC_END */
/* 32 */
0x15, /* FC_STRUCT */
0x3, /* 3 */
/* 34 */ 0x34, 0x0, /* 52 */
/* 36 */ 0x4c, /* FC_EMBEDDED_COMPLEX */
0x0, /* 0 */
/* 38 */ 0xee, 0xff, /* Offset= -18 (20) */
/* 40 */ 0x4c, /* FC_EMBEDDED_COMPLEX */
0x0, /* 0 */
/* 42 */ 0xea, 0xff, /* Offset= -22 (20) */
/* 44 */ 0x8, /* FC_LONG */
0x1, /* FC_BYTE */
/* 46 */ 0x1, /* FC_BYTE */
0x1, /* FC_BYTE */
/* 48 */ 0x1, /* FC_BYTE */
0x38, /* FC_ALIGNM4 */
/* 50 */ 0x8, /* FC_LONG */
0x5b, /* FC_END */
0x0
}
};