/************************************************************************ Copyright (c) 1993-2000 Microsoft Corporation Module Name : mrshl.c Abstract : This file contains the marshalling routines called by MIDL generated stubs and the interpreter. Author : David Kays dkays September 1993. Revision History : ***********************************************************************/ #include "ndrp.h" #include "hndl.h" #include "ndrole.h" #include "attack.h" #include "pointerq.h" unsigned char *RPC_ENTRY NdrUDTSimpleTypeMarshall1( PMIDL_STUB_MESSAGE pStubMsg, unsigned char * pMemory, PFORMAT_STRING pFormat ); // // Function table of marshalling routines. // extern const PMARSHALL_ROUTINE MarshallRoutinesTable[] = { NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrUDTSimpleTypeMarshall1, NdrPointerMarshall, NdrPointerMarshall, NdrPointerMarshall, NdrPointerMarshall, NdrSimpleStructMarshall, NdrSimpleStructMarshall, NdrConformantStructMarshall, NdrConformantStructMarshall, NdrConformantVaryingStructMarshall, NdrComplexStructMarshall, NdrConformantArrayMarshall, NdrConformantVaryingArrayMarshall, NdrFixedArrayMarshall, NdrFixedArrayMarshall, NdrVaryingArrayMarshall, NdrVaryingArrayMarshall, NdrComplexArrayMarshall, NdrConformantStringMarshall, NdrConformantStringMarshall, NdrConformantStringMarshall, NdrConformantStringMarshall, NdrNonConformantStringMarshall, NdrNonConformantStringMarshall, NdrNonConformantStringMarshall, NdrNonConformantStringMarshall, NdrEncapsulatedUnionMarshall, NdrNonEncapsulatedUnionMarshall, NdrByteCountPointerMarshall, NdrXmitOrRepAsMarshall, // transmit as NdrXmitOrRepAsMarshall, // represent as NdrPointerMarshall, NdrMarshallHandle, // New Post NT 3.5 token serviced from here on. 0, // NdrHardStructMarshall, NdrXmitOrRepAsMarshall, // transmit as ptr NdrXmitOrRepAsMarshall, // represent as ptr NdrUserMarshalMarshall, 0, // FC_PIPE 0, // FC_BLK_HOLE NdrpRangeMarshall, 0, // FC_INT3264 0, // FC_UINT3264 0, // NdrCsArrayMarshall, 0, // NdrCsTagMarshall }; extern const PMARSHALL_ROUTINE * pfnMarshallRoutines = MarshallRoutinesTable; unsigned char * NdrpInterfacePointerMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ); RPCRTAPI unsigned char *RPC_ENTRY NdrTypeMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) { return (*pfnMarshallRoutines[ROUTINE_INDEX(*pFormat)])( pStubMsg, pMemory, pFormat ); } __inline unsigned char *RPC_ENTRY NdrUDTSimpleTypeMarshall1( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING FormatString ) { NdrSimpleTypeMarshall(pStubMsg,pMemory,*FormatString); return 0; } void __fastcall NdrpSimpleTypeCharMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory) { ZEROOUT_GAP( pStubMsg->Buffer ); *(pStubMsg->Buffer)++ = *pMemory; } void __fastcall NdrpSimpleTypeShortMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory) { ZEROOUT_GAP( pStubMsg->Buffer ); ALIGN(pStubMsg->Buffer,1); *((ushort *&)pStubMsg->Buffer)++ = *((ushort *)pMemory); } void __fastcall NdrpSimpleTypeLongMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory) { ZEROOUT_GAP( pStubMsg->Buffer ); ALIGN(pStubMsg->Buffer,3); *((ulong *&)pStubMsg->Buffer)++ = *((ulong *)pMemory); } void __fastcall NdrpSimpleTypeHyperMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory) { ZEROOUT_GAP( pStubMsg->Buffer ); ZeroOutGapAndAlign( pStubMsg , 7) ; // // Let's stay away from casts to double. // *((ulong *&)pStubMsg->Buffer)++ = *((ulong *)pMemory); *((ulong *&)pStubMsg->Buffer)++ = *((ulong *)(pMemory + 4)); } void __fastcall NdrpSimpleTypeEnum16Marshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory) { if ( *((int *)pMemory) & ~((int)0x7fff) ) { RpcRaiseException(RPC_X_ENUM_VALUE_OUT_OF_RANGE); } ZEROOUT_GAP( pStubMsg->Buffer ); ALIGN(pStubMsg->Buffer,1); *((ushort *&)pStubMsg->Buffer)++ = *((ushort *)pMemory); } void __fastcall NdrpSimpleTypeIgnoreMarshall ( PMIDL_STUB_MESSAGE , uchar * ) { } void __fastcall NdrpSimpleTypeInvalidMarshall ( PMIDL_STUB_MESSAGE , uchar * ) { NDR_ASSERT(0,"NdrSimpleTypeMarshall : bad format char"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); } // make this extern as this will be call from ClientMarshal & ServerMarshal also. extern const PSIMPLETYPE_MARSHAL_ROUTINE SimpleTypeMarshallRoutinesTable[] = { NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeCharMarshall, NdrpSimpleTypeCharMarshall, NdrpSimpleTypeCharMarshall, NdrpSimpleTypeCharMarshall, NdrpSimpleTypeShortMarshall, NdrpSimpleTypeShortMarshall, NdrpSimpleTypeShortMarshall, NdrpSimpleTypeLongMarshall, NdrpSimpleTypeLongMarshall, NdrpSimpleTypeLongMarshall, // FC_FLOAT NdrpSimpleTypeHyperMarshall, NdrpSimpleTypeHyperMarshall, NdrpSimpleTypeEnum16Marshall, // FC_ENUM16 NdrpSimpleTypeLongMarshall, NdrpSimpleTypeIgnoreMarshall, NdrpSimpleTypeLongMarshall, // fc_error_status_t NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, // transmit as NdrpSimpleTypeInvalidMarshall, // represent as NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, // New Post NT 3.5 token serviced from here on. NdrpSimpleTypeInvalidMarshall, // NdrHardStructMarshall, NdrpSimpleTypeInvalidMarshall, // transmit as ptr NdrpSimpleTypeInvalidMarshall, // represent as ptr NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, // FC_PIPE NdrpSimpleTypeInvalidMarshall, // FC_BLK_HOLE NdrpSimpleTypeInvalidMarshall, #if defined(__RPC_WIN64__) NdrpSimpleTypeLongMarshall, // FC_INT3264 NdrpSimpleTypeLongMarshall, // FC_UINT3264 #else NdrpSimpleTypeInvalidMarshall, NdrpSimpleTypeInvalidMarshall, #endif NdrpSimpleTypeInvalidMarshall, // NdrCsArrayMarshall, NdrpSimpleTypeInvalidMarshall, // NdrCsTagMarshall }; void RPC_ENTRY NdrSimpleTypeMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, uchar FormatChar ) /*++ Routine Description : Marshalls a simple type. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the data to be marshalled. FormatChar - Simple type format character. Return : None. --*/ { SimpleTypeMarshallRoutinesTable[ROUTINE_INDEX(FormatChar)](pStubMsg, pMemory ); } unsigned char * RPC_ENTRY NdrpRangeMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ --*/ { uchar FcType = pFormat[1] & 0x0f; NdrSimpleTypeMarshall( pStubMsg, pMemory, FcType ); return 0; } unsigned char * RPC_ENTRY NdrPointerMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls a top level pointer to anything. Pointers embedded in structures, arrays, or unions call NdrpPointerMarshall directly. Used for FC_RP, FC_UP, FC_FP, FC_OP. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the data to be marshalled. pFormat - Pointer's format string description. Return : None. --*/ { uchar * pBufferMark; // // If this is not a ref pointer then set buffer mark and increment the // stub message buffer pointer. // if ( *pFormat != FC_RP ) { ALIGN( pStubMsg->Buffer, 3 ); // This is where we marshall the node id. pBufferMark = pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; } else pBufferMark = 0; // // For ref pointers pBufferMark will not be used and can be left // unitialized. // NdrpPointerMarshall( pStubMsg, pBufferMark, pMemory, pFormat ); return 0; } __forceinline void NdrpPointerMarshallInternal( PMIDL_STUB_MESSAGE pStubMsg, uchar * pBufferMark, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Private routine for marshalling a pointer and its pointee. This is the entry point for pointers embedded in structures, arrays, and unions. Used for FC_RP, FC_UP, FC_FP, FC_OP. Arguments : pStubMsg - Pointer to the stub message. pBufferMark - The location in the buffer where the pointer itself is marshalled. Important for full pointers, unfortunately it's overkill for unique pointers. pMemory - Pointer to the data to be marshalled. pFormat - Pointer format string description. pStubMsg->Buffer - the place for the pointee. Return : None. --*/ { // // Check the pointer type. // switch ( *pFormat ) { case FC_RP : if ( ! pMemory ) RpcRaiseException( RPC_X_NULL_REF_POINTER ); break; case FC_UP : case FC_OP : // Put the pointer in the buffer. *((ulong*&)pBufferMark)++ = PTR_WIRE_REP(pMemory, pStubMsg); if ( ! pMemory ) return; break; case FC_IP : if ( IS_BROKEN_INTERFACE_POINTER(pStubMsg->uFlags) ) { // The pointee is effectivly both the pointer // and the pointee. NdrInterfacePointerMarshall( pStubMsg, pMemory, pFormat ); return; } // Interface pointers behave like unique pointers *((ulong*&)pBufferMark)++ = PTR_WIRE_REP(pMemory, pStubMsg); if ( ! pMemory ) return; NdrpInterfacePointerMarshall( pStubMsg, pMemory, pFormat ); return; case FC_FP : // // Marshall the pointer's ref id and see if we've already // marshalled the pointer's data. // if ( NdrFullPointerQueryPointer( pStubMsg->FullPtrXlatTables, pMemory, FULL_POINTER_MARSHALLED, (ulong *) pBufferMark ) ) return; break; default : NDR_ASSERT(0,"NdrpPointerMarshall : bad pointer type"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return; } // // Check for a pointer to a complex type. // if ( ! SIMPLE_POINTER(pFormat[1]) ) { uchar uFlagsSave; if ( POINTER_DEREF(pFormat[1]) ) pMemory = *((uchar **)pMemory); // Increment to offset_to_complex_description<2> field. pFormat += 2; // // Set format string to complex type description. // Cast must be to a signed short since some offsets are negative. // pFormat += *((signed short *)pFormat); // // Look up the proper marshalling routine in the marshalling function // table. // uFlagsSave = pStubMsg->uFlags; RESET_CONF_FLAGS_TO_STANDALONE(pStubMsg->uFlags); (*pfnMarshallRoutines[ROUTINE_INDEX(*pFormat)])( pStubMsg, pMemory, pFormat ); pStubMsg->uFlags = uFlagsSave; return; } // // Else it's a pointer to a simple type or a string pointer. // switch ( pFormat[2] ) { case FC_C_CSTRING : case FC_C_BSTRING : case FC_C_WSTRING : case FC_C_SSTRING : NdrConformantStringMarshall( pStubMsg, pMemory, pFormat + 2 ); break; default : NdrSimpleTypeMarshall( pStubMsg, pMemory, pFormat[2] ); break; } } NDR_MRSHL_POINTER_QUEUE_ELEMENT::NDR_MRSHL_POINTER_QUEUE_ELEMENT( MIDL_STUB_MESSAGE *pStubMsg, uchar * const pBufferMarkNew, uchar * const pMemoryNew, const PFORMAT_STRING pFormatNew) : pBufferMark(pBufferMarkNew), pMemory(pMemoryNew), pFormat(pFormatNew), Memory(pStubMsg->Memory), uFlags(pStubMsg->uFlags) { } void NDR_MRSHL_POINTER_QUEUE_ELEMENT::Dispatch( MIDL_STUB_MESSAGE *pStubMsg) { SAVE_CONTEXT MemorySave( pStubMsg->Memory, Memory ); SAVE_CONTEXT uFlagsSave( pStubMsg->uFlags, uFlags ); NDR_ASSERT( !pStubMsg->PointerBufferMark, "PointerBufferMark is not 0\n"); NdrpPointerMarshallInternal( pStubMsg, pBufferMark, pMemory, pFormat ); } #if defined(DBG) void NDR_MRSHL_POINTER_QUEUE_ELEMENT::Print() { DbgPrint("NDR_MRSHL_POINTER_QUEUE_ELEMENT\n"); DbgPrint("pNext: %p\n", pNext ); DbgPrint("pBufferMark: %p\n", pBufferMark ); DbgPrint("pMemory: %p\n", pMemory ); DbgPrint("pFormat: %p\n", pFormat ); DbgPrint("Memory: %p\n", Memory ); DbgPrint("uFlags: %x\n", uFlags ); } #endif void NdrpEnquePointerMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pBufferMark, uchar * pMemory, PFORMAT_STRING pFormat ) { NDR32_POINTER_CONTEXT PointerContext( pStubMsg ); RpcTryFinally { NDR_MRSHL_POINTER_QUEUE_ELEMENT*pElement = new(PointerContext.GetActiveState()) NDR_MRSHL_POINTER_QUEUE_ELEMENT(pStubMsg, pBufferMark, pMemory, pFormat); PointerContext.Enque( pElement ); PointerContext.DispatchIfRequired(); } RpcFinally { PointerContext.EndContext(); } RpcEndFinally } void NdrpPointerMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pBufferMark, uchar * pMemory, PFORMAT_STRING pFormat ) { if ( !NdrIsLowStack(pStubMsg) ) { NdrpPointerMarshallInternal( pStubMsg, pBufferMark, pMemory, pFormat ); return; } NdrpEnquePointerMarshall( pStubMsg, pBufferMark, pMemory, pFormat ); } unsigned char * RPC_ENTRY NdrSimpleStructMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine description : Marshalls a simple structure. Used for FC_STRUCT and FC_PSTRUCT. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the structure to be marshalled. pFormat - Structure's format string description. Return : None. --*/ { uint StructSize; ZeroOutGapAndAlign(pStubMsg,pFormat[1]); StructSize = (uint) *((ushort *)(pFormat + 2)); RpcpMarshalMemoryCopy( pStubMsg->Buffer, pMemory, StructSize ); // Mark the start of the structure in the buffer. pStubMsg->BufferMark = pStubMsg->Buffer; pStubMsg->Buffer += StructSize; // Marshall embedded pointers. if ( *pFormat == FC_PSTRUCT ) { NdrpEmbeddedPointerMarshall( pStubMsg, pMemory, pFormat + 4 ); } return 0; } unsigned char * RPC_ENTRY NdrConformantStructMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine description : Marshalls a conformant structure. Used for FC_CSTRUCT and FC_CPSTRUCT. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the structure to be marshalled. pFormat - Structure's format string description. Return : None. - may set the CONF_ARRAY_DONE flag. Note Due to problems with MIDL generated code, the ConformantStruct routine always marshals the conformant array. Only a bogus struct can embed a conf struct, and there is a flag that bogus struct watches in order not to marshal the array second time. --*/ { PFORMAT_STRING pFormatArray; uint StructSize; uchar Alignment; uchar fIsEmbeddedStruct = IS_EMBED_CONF_STRUCT( pStubMsg->uFlags ); // Save structure's alignment. Alignment = pFormat[1]; // Increment format string to struct size field. pFormat += 2; // Get flat struct size and increment format string. StructSize = (uint) *((ushort *&)pFormat)++; // Set conformant array format string description. pFormatArray = pFormat + *((signed short *)pFormat); // // Compute conformance information. Pass a memory pointer to the // end of the non-conformant part of the structure. // NdrpComputeConformance( pStubMsg, pMemory + StructSize, pFormatArray ); // Only a bogus struct can embed a conf struct. if ( fIsEmbeddedStruct ) *(ulong *)pStubMsg->BufferMark = (ulong)pStubMsg->MaxCount; else { // Align the buffer for conformance count marshalling. ALIGN(pStubMsg->Buffer,3); // Marshall conformance count. *((ulong *&)pStubMsg->Buffer)++ = (ulong)pStubMsg->MaxCount; } // Re-align buffer ZeroOutGapAndAlign(pStubMsg,Alignment); // Increment array format string to array element size field. pFormatArray += 2; // Add the size of the conformant array to the structure size. StructSize += (ulong)pStubMsg->MaxCount * *((ushort *)pFormatArray); RpcpMarshalMemoryCopy( pStubMsg->Buffer, pMemory, StructSize ); // Update the buffer pointer. pStubMsg->Buffer += StructSize; // Increment format string past offset to array description field. pFormat += 2; // Marshall embedded pointers. This covers the struct and the conf array. if ( *pFormat == FC_PP ) { // Mark the start of the structure in the buffer. pStubMsg->BufferMark = pStubMsg->Buffer - StructSize; NdrpEmbeddedPointerMarshall( pStubMsg, pMemory, pFormat ); } // Only a complex struct may set up this flag for embedding. // Set the reverse flag to signal that array has been marshaled. if ( fIsEmbeddedStruct ) SET_CONF_ARRAY_DONE( pStubMsg->uFlags ); return 0; } unsigned char * RPC_ENTRY NdrConformantVaryingStructMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine description : Marshalls a structure which contains a conformant varying array. Used for FC_CVSTRUCT. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the structure to be marshalled. pFormat - Structure's format string description. Return : None. --*/ { PFORMAT_STRING pFormatArray; uint StructSize; uchar Alignment; uchar fIsEmbeddedStruct = IS_EMBED_CONF_STRUCT( pStubMsg->uFlags ); uchar* pBuffer; if ( !fIsEmbeddedStruct ) { // Align the buffer for marshalling conformance info. ALIGN(pStubMsg->Buffer,3); // Mark the location in the buffer where the conformance will be marshalled. pStubMsg->BufferMark = pStubMsg->Buffer; // Increment buffer pointer past where conformance will be marshalled. pStubMsg->Buffer += 4; } // else BufferMark is set by the ComplexStruct code. // Save the structure's alignment. Alignment = pFormat[1]; // Increment format string to struct size field. pFormat += 2; // Get non-conformance struct size and increment format string. StructSize = (uint) *((ushort *&)pFormat)++; // Get conformant array's description. pFormatArray = pFormat + *((signed short *)pFormat); // Align buffer for struct ZeroOutGapAndAlign(pStubMsg, Alignment); pBuffer = pStubMsg->Buffer; RpcpMarshalMemoryCopy( pStubMsg->Buffer, pMemory, StructSize ); // Set stub message buffer pointer past non-conformant part of struct. pStubMsg->Buffer += StructSize; // // Call the correct private array or string marshalling routine. // We must pass a memory pointer to the beginning of the array/string. // if ( *pFormatArray == FC_CVARRAY ) { NdrpConformantVaryingArrayMarshall( pStubMsg, pMemory + StructSize, pFormatArray ); } else { NdrpConformantStringMarshall( pStubMsg, pMemory + StructSize, pFormatArray ); } // Increment format string past the offset_to_array_description<2> field. pFormat += 2; // // Marshall embedded pointers. // if ( *pFormat == FC_PP ) { // Mark the start of the structure in the buffer. pStubMsg->BufferMark = pBuffer; pStubMsg->MaxCount = pStubMsg->ActualCount; NdrpEmbeddedPointerMarshall( pStubMsg, pMemory, pFormat ); } // Only a complex struct may set up this flag for embedding. // Set the reverse flag to signal that array has been marshaled. if ( fIsEmbeddedStruct ) SET_CONF_ARRAY_DONE( pStubMsg->uFlags ); return 0; } #if 0 unsigned char * RPC_ENTRY NdrHardStructMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine description : Marshalls a hard structure. Used for FC_HARD_STRUCT. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the structure being marshalled. pFormat - Structure's format string description. Return : None. --*/ { ALIGN(pStubMsg->Buffer,pFormat[1]); pFormat += 8; // // Do any needed enum16 exception check. // if ( *((short *)pFormat) != (short) -1 ) { if ( *((int *)(pMemory + *((ushort *)pFormat))) & ~((int)0x7fff) ) { RpcRaiseException(RPC_X_ENUM_VALUE_OUT_OF_RANGE); } } pFormat += 2; RpcpMemoryCopy( pStubMsg->Buffer, pMemory, *((ushort *)pFormat) ); pStubMsg->Buffer += *((ushort *)pFormat)++; // // See if we have a union. // if ( *((short *)&pFormat[2]) ) { pMemory += *((ushort *)pFormat)++; pFormat += *((short *)pFormat); (*pfnMarshallRoutines[ROUTINE_INDEX(*pFormat)])( pStubMsg, pMemory, pFormat ); } return 0; } #endif // 0 unsigned char * RPC_ENTRY NdrComplexStructMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine description : Marshalls a complex structure. Used for FC_BOGUS_STRUCT. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the structure being marshalled. pFormat - Structure's format string description. Return : None. Notes : pStubMsg->BufferMark is set to a place where conformance would be marhaled. pStubMsg->pPointerBufferMark is a pointee buffer mark a usual. --*/ { uchar * pBufferSave; uchar * pBufferMark; uchar * pMemorySave; PFORMAT_STRING pFormatPointers; PFORMAT_STRING pFormatArray; PFORMAT_STRING pFormatSave; PFORMAT_STRING pFormatComplex; long Alignment; long Align8Mod; uchar fSetPointerBufferMark; uchar fIsEmbeddedStruct = IS_EMBED_CONF_STRUCT( pStubMsg->uFlags ); BOOL fEmbedConfStructContext; // Get struct's wire alignment. Alignment = pFormat[1]; // // This is used for support of structs with doubles passed on an // i386 stack. // // A cast to long is what we need. Align8Mod = 0x7 & PtrToLong( pMemory ); pFormatSave = pFormat; pBufferSave = pStubMsg->Buffer; pMemorySave = pStubMsg->Memory; pStubMsg->Memory = pMemory; // Increment to conformant array offset field. pFormat += 4; // Get conformant array description. if ( *((ushort *)pFormat) ) { pFormatArray = pFormat + *((signed short *)pFormat); if ( !fIsEmbeddedStruct ) { // Align for conformance marshalling. ALIGN(pStubMsg->Buffer,3); // Remember where the conformance count(s) will be marshalled. pStubMsg->BufferMark = pStubMsg->Buffer; // Increment the buffer pointer 4 bytes for every array dimension. pStubMsg->Buffer += NdrpArrayDimensions( pStubMsg, pFormatArray, FALSE ) * 4; } } else pFormatArray = 0; // Mark the place to marshal conformant size(s), this may come from upper levels. pBufferMark = pStubMsg->BufferMark; pFormat += 2; // Get pointer layout description. if ( *((ushort *)pFormat) ) pFormatPointers = pFormat + *((ushort *)pFormat); else pFormatPointers = 0; pFormat += 2; // Align buffer on struct's alignment. ZeroOutGapAndAlign(pStubMsg,Alignment); // // If the the stub message PointerBufferMark field is 0, then determine // the position in the buffer where pointees will be marshalled. // // We have to do this to handle embedded pointers. // if ( fSetPointerBufferMark = ! pStubMsg->PointerBufferMark ) { BOOL fOldIgnore; ulong BufferLenOffset; fOldIgnore = pStubMsg->IgnoreEmbeddedPointers; pStubMsg->IgnoreEmbeddedPointers = TRUE; // // Set BufferLength equal to the current buffer pointer, and then // when we return from NdrComplexStructBufferSize it will pointer to // the location in the buffer where the pointees should be marshalled. // pStubMsg->BufferLength = pBufferSave; // Instead of pointer, we now calculate pointer increment explicitly. // Set the pointer alignment as a base. // We use pBufferSave as the sizing routine accounts for the conf sizes. // BufferLenOffset = 0xf & PtrToUlong( pBufferSave ); ulong BufferLengthSave = pStubMsg->BufferLength; pStubMsg->BufferLength = BufferLenOffset; NdrComplexStructBufferSize( pStubMsg, pMemory, pFormatSave ); // Pointer increment including alignments. BufferLenOffset = pStubMsg->BufferLength - BufferLenOffset; // Set the location in the buffer where pointees will be marshalled. pStubMsg->PointerBufferMark = pBufferSave + BufferLenOffset; pStubMsg->BufferLength = BufferLengthSave; pStubMsg->IgnoreEmbeddedPointers = fOldIgnore; // in NDR20, we have trailing pad issue where if a complex struct contains pointer to simple type // and trailing simple type, the first pointee will be written immediately after the last element of // the structure, BEFORE we write the last flat element. If we zero out the alignment gap // we only need to zero out when there is pointer in the struct. if ( pFormatPointers ) { ULONG_PTR CopyLength = (ulong)( ( (ULONG_PTR)(pBufferSave + BufferLenOffset + 3 ) & ~3) - (ULONG_PTR)pBufferSave); // we need to memset always. memset( pBufferSave, 0, CopyLength ); } } fEmbedConfStructContext = fIsEmbeddedStruct || pFormatArray && FixWireRepForDComVerGTE54( pStubMsg ); RESET_EMBED_CONF_STRUCT( pStubMsg->uFlags ); // // Marshall the structure member by member. // for ( ; ; pFormat++ ) { switch ( *pFormat ) { // // Simple types. // case FC_CHAR : case FC_BYTE : case FC_SMALL : case FC_USMALL: *(pStubMsg->Buffer)++ = *pMemory; pMemory += 1; break; case FC_ENUM16 : if ( *((int *)pMemory) & ~((int)0x7fff) ) { RpcRaiseException(RPC_X_ENUM_VALUE_OUT_OF_RANGE); } ALIGN(pStubMsg->Buffer,1); *((ushort *&)pStubMsg->Buffer)++ = *((ushort *)pMemory); pMemory += 4; break; case FC_WCHAR : case FC_SHORT : case FC_USHORT: ALIGN(pStubMsg->Buffer,1); *((ushort *&)pStubMsg->Buffer)++ = *((ushort *)pMemory); pMemory += 2; break; #if defined(__RPC_WIN64__) case FC_INT3264 : case FC_UINT3264 : ALIGN( pStubMsg->Buffer, 3 ); * ((ulong *&)pStubMsg->Buffer)++ = *((ulong *)pMemory); pMemory += 8; break; #endif case FC_LONG : case FC_ULONG: case FC_FLOAT : case FC_ENUM32 : ALIGN( pStubMsg->Buffer, 3 ); * ((ulong *&)pStubMsg->Buffer)++ = *((ulong *)pMemory); pMemory += 4; break; case FC_HYPER : case FC_DOUBLE : ALIGN( pStubMsg->Buffer, 7 ); *((ulong *&)pStubMsg->Buffer)++ = *((ulong *)pMemory); *((ulong *&)pStubMsg->Buffer)++ = *((ulong *)(pMemory + 4)); pMemory += 8; break; case FC_IGNORE : ALIGN(pStubMsg->Buffer,3); pStubMsg->Buffer += PTR_WIRE_SIZE; pMemory += PTR_MEM_SIZE; break; case FC_POINTER : { ALIGN( pStubMsg->Buffer, 0x3 ); uchar *pPointerId = pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; NDR_ASSERT(pFormatPointers, "NdrComplexStructMarshall: pointer field but no pointer layout"); { POINTER_BUFFER_SWAP_CONTEXT NewContext(pStubMsg); NdrpPointerMarshall( pStubMsg, pPointerId, *((uchar **)pMemory), pFormatPointers ); } // // Increment memory pointers past the pointer. // pMemory += PTR_MEM_SIZE; pFormatPointers += 4; break; } // // Embedded complex types. // case FC_EMBEDDED_COMPLEX : // Increment memory pointer by padding. pMemory += pFormat[1]; pFormat += 2; // Get the type's description. pFormatComplex = pFormat + *((signed short UNALIGNED *)pFormat); if ( FC_IP == *pFormatComplex ) { // Treat the same as an embedded pointer ALIGN( pStubMsg->Buffer, 0x3 ); uchar *pPointerId = pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; { POINTER_BUFFER_SWAP_CONTEXT NewContext(pStubMsg); NdrpPointerMarshall( pStubMsg, pPointerId, *((uchar **)pMemory), pFormatComplex ); } pMemory += PTR_MEM_SIZE; pFormat++; break; } // Context needed for the embedded conf struct. // pStubMsg->BufferMark = pBufferMark; if ( fEmbedConfStructContext ) SET_EMBED_CONF_STRUCT( pStubMsg->uFlags ); // Marshall complex type. (*pfnMarshallRoutines[ROUTINE_INDEX(*pFormatComplex)]) ( pStubMsg, pMemory, pFormatComplex ); // // Increment the memory pointer. // pMemory = NdrpMemoryIncrement( pStubMsg, pMemory, pFormatComplex ); RESET_EMBED_CONF_STRUCT( pStubMsg->uFlags ); // // Increment the main format string one byte. The loop // will increment it one more byte past the offset field. // pFormat++; break; case FC_ALIGNM2 : ALIGN( pMemory, 0x1 ); break; case FC_ALIGNM4 : ALIGN( pMemory, 0x3 ); break; case FC_ALIGNM8 : // // We have to play some tricks for the i386 to handle the case // when an 8 byte aligned structure is passed by value. The // alignment of the struct on the stack is not guaranteed to be // on an 8 byte boundary. // pMemory -= Align8Mod; ALIGN(pMemory, 0x7 ); pMemory += Align8Mod; break; case FC_STRUCTPAD1 : case FC_STRUCTPAD2 : case FC_STRUCTPAD3 : case FC_STRUCTPAD4 : case FC_STRUCTPAD5 : case FC_STRUCTPAD6 : case FC_STRUCTPAD7 : // // Increment memory pointer by amount of padding. // pMemory += (*pFormat - FC_STRUCTPAD1) + 1; break; case FC_STRUCTPADN : // FC_STRUCTPADN 0 pMemory += *(((unsigned short *)pFormat) + 1); pFormat += 3; break; case FC_PAD : break; // // Done with layout. // case FC_END : goto ComplexMarshallEnd; default : NDR_ASSERT(0,"NdrComplexStructMarshall : bad format char"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return 0; } // switch } // for ComplexMarshallEnd: // // Marshall conformant array if we have one. // .. but not when embedded and not when it had been marshaled by conf struct. // if ( pFormatArray && !fIsEmbeddedStruct && ! IS_CONF_ARRAY_DONE( pStubMsg->uFlags ) ) { // Normal case: top level marshaling. PPRIVATE_MARSHALL_ROUTINE pfnPMarshall; switch ( *pFormatArray ) { case FC_CARRAY : pfnPMarshall = NdrpConformantArrayMarshall; break; case FC_CVARRAY : pfnPMarshall = NdrpConformantVaryingArrayMarshall; break; case FC_BOGUS_ARRAY : pfnPMarshall = NdrpComplexArrayMarshall; break; case FC_C_WSTRING : ALIGN(pMemory,1); // fall through // case FC_C_CSTRING : // case FC_C_BSTRING : // case FC_C_SSTRING : default : pfnPMarshall = NdrpConformantStringMarshall; break; } // // Mark where the conformance count(s) will be marshalled. // pStubMsg->BufferMark = pBufferMark; // Marshall the array. (*pfnPMarshall)( pStubMsg, pMemory, pFormatArray ); } // // Now fix up the stub message Buffer field if we set the PointerBufferMark // field. // if ( fSetPointerBufferMark ) { pStubMsg->Buffer = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; } pStubMsg->Memory = pMemorySave; if ( fIsEmbeddedStruct ) SET_EMBED_CONF_STRUCT( pStubMsg->uFlags ); else RESET_CONF_ARRAY_DONE( pStubMsg->uFlags ); return 0; } unsigned char * RPC_ENTRY NdrNonConformantStringMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine description : Marshalls a non conformant string. Used for FC_CSTRING, FC_WSTRING, FC_SSTRING, and FC_BSTRING (NT Beta2 compatability only). Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the string to be marshalled. pFormat - String's format string description. Return : None. --*/ { uint Count; uint CopySize; // Align the buffer for offset and count marshalling. ALIGN(pStubMsg->Buffer,3); switch ( *pFormat ) { case FC_CSTRING : case FC_BSTRING : CopySize = Count = MIDL_ascii_strlen((char *)pMemory) + 1; break; case FC_WSTRING : Count = wcslen((wchar_t *)pMemory) + 1; CopySize = Count * sizeof(wchar_t); break; case FC_SSTRING : Count = NdrpStringStructLen( pMemory, pFormat[1] ) + 1; CopySize = Count * pFormat[1]; break; default : NDR_ASSERT(0,"NdrNonConformantStringMarshall : bad format char"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return 0; } // Marshall variance. *((ulong *&)pStubMsg->Buffer)++ = 0; *((ulong *&)pStubMsg->Buffer)++ = Count; // Copy the string. RpcpMarshalMemoryCopy( pStubMsg->Buffer, pMemory, CopySize ); // Update buffer pointer. pStubMsg->Buffer += CopySize; return 0; } unsigned char * RPC_ENTRY NdrConformantStringMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine description : Marshalls a top level conformant string. Used for FC_C_CSTRING, FC_C_WSTRING, FC_C_SSTRING, and FC_C_BSTRING (NT Beta2 compatability only). Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the string to be marshalled. pFormat - String's format string description. Return : None. --*/ { if ( pStubMsg->pArrayInfo != 0 ) { // // If this is part of a multidimensional array then we get the location // where the conformance is marshalled from a special place. // pStubMsg->BufferMark = ( uchar * ) &(pStubMsg->pArrayInfo-> BufferConformanceMark[pStubMsg->pArrayInfo->Dimension]); } else { // Align the buffer for max count marshalling. ALIGN(pStubMsg->Buffer,3); // Mark where the max count will be marshalled. pStubMsg->BufferMark = pStubMsg->Buffer; // Increment the buffer past where the max count will be marshalled. pStubMsg->Buffer += 4; } // Call the private marshalling routine. NdrpConformantStringMarshall( pStubMsg, pMemory, pFormat ); return 0; } void NdrpConformantStringMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine description : Private routine for marshalling a conformant string. This is the entry point for marshalling an embedded conformant strings. Used for FC_C_CSTRING, FC_C_WSTRING, FC_C_SSTRING, and FC_C_BSTRING (NT Beta2 compatability only). Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the string to be marshalled. pFormat - String's format string description. Return : None. --*/ { ulong MaxCount; uint ActualCount, CopySize; BOOL IsSized; IsSized = (pFormat[1] == FC_STRING_SIZED); // Compute the element count of the string and the total copy size. switch ( *pFormat ) { case FC_C_CSTRING : case FC_C_BSTRING : CopySize = ActualCount = MIDL_ascii_strlen((char *)pMemory) + 1; break; case FC_C_WSTRING : ActualCount = wcslen((wchar_t *)pMemory) + 1; CopySize = ActualCount * sizeof(wchar_t); break; case FC_C_SSTRING : ActualCount = NdrpStringStructLen( pMemory, pFormat[1] ) + 1; CopySize = ActualCount * pFormat[1]; // Redo this check correctly. IsSized = (pFormat[2] == FC_STRING_SIZED); break; default : NDR_ASSERT(0,"NdrpConformantStringMarshall : bad format char"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return; } // // If the string is sized then compute the max count, otherwise the // max count is equal to the actual count. // if ( IsSized ) { MaxCount = (ulong) NdrpComputeConformance( pStubMsg, pMemory, pFormat ); } else { MaxCount = ActualCount; } // Marshall the max count. *((ulong *)pStubMsg->BufferMark) = MaxCount; // Align the buffer for variance marshalling. ALIGN(pStubMsg->Buffer,3); // Marshall variance. *((ulong *&)pStubMsg->Buffer)++ = 0; *((ulong *&)pStubMsg->Buffer)++ = ActualCount; RpcpMarshalMemoryCopy( pStubMsg->Buffer, pMemory, CopySize ); // Update the Buffer pointer. pStubMsg->Buffer += CopySize; } unsigned char * RPC_ENTRY NdrFixedArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls a fixed array of any number of dimensions. Used for FC_SMFARRAY and FC_LGFARRAY. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the array to be marshalled. pFormat - Array's format string description. Return : None. --*/ { uint Size; // Align the buffer. ZeroOutGapAndAlign(pStubMsg,pFormat[1]); // Get total array size. if ( *pFormat == FC_SMFARRAY ) { pFormat += 2; Size = (ulong) *((ushort *&)pFormat)++; } else // *pFormat == FC_LGFARRAY { pFormat += 2; Size = *((ulong UNALIGNED *&)pFormat)++; } // Copy the array. RpcpMarshalMemoryCopy( pStubMsg->Buffer, pMemory, Size ); // Increment stub message buffer pointer. pStubMsg->Buffer += Size; // Marshall embedded pointers. if ( *pFormat == FC_PP ) { // Mark the start of the array in the buffer. pStubMsg->BufferMark = pStubMsg->Buffer - Size; NdrpEmbeddedPointerMarshall( pStubMsg, pMemory, pFormat ); } return 0; } unsigned char * RPC_ENTRY NdrConformantArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls a top level one dimensional conformant array. Used for FC_CARRAY. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the array being marshalled. pFormat - Array's format string description. Return : None. --*/ { // Align the buffer for conformance marshalling. ALIGN(pStubMsg->Buffer,3); // Mark where the conformance will be marshalled. pStubMsg->BufferMark = pStubMsg->Buffer; // Increment past where the conformance will go. pStubMsg->Buffer += 4; // Call the private marshalling routine to do the work. NdrpConformantArrayMarshall( pStubMsg, pMemory, pFormat ); return 0; } void NdrpConformantArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Private routine for marshalling a one dimensional conformant array. This is the entry point for marshalling an embedded conformant array. Used for FC_CARRAY. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the array being marshalled. pFormat - Array's format string description. Return : None. --*/ { ulong Count; uint CopySize; // Compute conformance information. Count = (ulong) NdrpComputeConformance( pStubMsg, pMemory, pFormat ); // Marshall the conformance. *((ulong *)pStubMsg->BufferMark) = Count; // // Return if size is 0. // if ( ! Count ) return; ZeroOutGapAndAlign(pStubMsg,pFormat[1]); // Compute the total array size in bytes. CopySize = Count * *((ushort *)(pFormat + 2)); RpcpMarshalMemoryCopy( pStubMsg->Buffer, pMemory, CopySize ); // Update buffer pointer. pStubMsg->Buffer += CopySize; // Increment to possible pointer layout. pFormat += 8; CORRELATION_DESC_INCREMENT( pFormat ); // Marshall embedded pointers. if ( *pFormat == FC_PP ) { // // Mark the start of the array in the buffer. // pStubMsg->BufferMark = pStubMsg->Buffer - CopySize; NdrpEmbeddedPointerMarshall( pStubMsg, pMemory, pFormat ); } } unsigned char * RPC_ENTRY NdrConformantVaryingArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls a top level one dimensional conformant varying array. Used for FC_CVARRAY. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the array being marshalled. pFormat - Array's format string description. Return : None. --*/ { // Align the buffer for conformance marshalling. ALIGN(pStubMsg->Buffer,3); // Mark where the conformance will be marshalled. pStubMsg->BufferMark = pStubMsg->Buffer; // Increment past where the conformance will go. pStubMsg->Buffer += 4; // Call the private marshalling routine to do the work. NdrpConformantVaryingArrayMarshall( pStubMsg, pMemory, pFormat ); return 0; } void NdrpConformantVaryingArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Private routine for marshalling a one dimensional conformant varying array. This is the entry point for marshalling an embedded conformant varying array. Used for FC_CVARRAY. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the array to be marshalled. pFormat - Array's format string description. Return : None. --*/ { uint CopyOffset, CopySize; ushort ElemSize; // Compute and marshall the conformant size. *((ulong *)pStubMsg->BufferMark) = (ulong) NdrpComputeConformance( pStubMsg, pMemory, pFormat ); // Compute variance offset and count. NdrpComputeVariance( pStubMsg, pMemory, pFormat ); // Align the buffer for variance marshalling. ALIGN(pStubMsg->Buffer,3); // Marshall variance. *((ulong *&)pStubMsg->Buffer)++ = pStubMsg->Offset; *((ulong *&)pStubMsg->Buffer)++ = pStubMsg->ActualCount; // // Return if length is 0. // if ( ! pStubMsg->ActualCount ) return; ZeroOutGapAndAlign(pStubMsg, pFormat[1]); ElemSize = *((ushort *)(pFormat + 2)); // Compute byte offset and size for the array copy. CopyOffset = pStubMsg->Offset * ElemSize; CopySize = pStubMsg->ActualCount * ElemSize; RpcpMarshalMemoryCopy( pStubMsg->Buffer, pMemory + CopyOffset, CopySize ); pStubMsg->Buffer += CopySize; // Increment to a possible pointer layout. pFormat += 12; CORRELATION_DESC_INCREMENT( pFormat ); CORRELATION_DESC_INCREMENT( pFormat ); // Marshall embedded pointers. if ( *pFormat == FC_PP ) { // // Set the MaxCount field equal to the ActualCount field. The pointer // marshalling routine uses the MaxCount field to determine the number // of times an FC_VARIABLE_REPEAT pointer is marshalled. In the face // of variance the correct number of time is the ActualCount, not the // the MaxCount. // pStubMsg->MaxCount = pStubMsg->ActualCount; // // Mark the start of the array in the buffer. // pStubMsg->BufferMark = pStubMsg->Buffer - CopySize; NdrpEmbeddedPointerMarshall( pStubMsg, pMemory, pFormat ); } } unsigned char * RPC_ENTRY NdrVaryingArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls a top level or embedded one dimensional varying array. Used for FC_SMVARRAY and FC_LGVARRAY. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the array being marshalled. pFormat - Array's format string description. Return : None. --*/ { uint CopyOffset, CopySize; ushort ElemSize; // Compute the variance offset and count. NdrpComputeVariance( pStubMsg, pMemory, pFormat ); // Align the buffer for variance marshalling. ALIGN(pStubMsg->Buffer,3); // Marshall variance. *((ulong *&)pStubMsg->Buffer)++ = pStubMsg->Offset; *((ulong *&)pStubMsg->Buffer)++ = pStubMsg->ActualCount; // // Return if length is 0. // if ( ! pStubMsg->ActualCount ) return 0; ZeroOutGapAndAlign(pStubMsg, pFormat[1]); // Increment the format string to the element_size field. if ( *pFormat == FC_SMVARRAY ) pFormat += 6; else // *pFormat == FC_LGVARRAY pFormat += 10; // Get element size. ElemSize = *((ushort *)pFormat); // // Compute the byte offset from the beginning of the array for the copy // and the number of bytes to copy. // CopyOffset = pStubMsg->Offset * ElemSize; CopySize = pStubMsg->ActualCount * ElemSize; // Copy the array. RpcpMarshalMemoryCopy( pStubMsg->Buffer, pMemory + CopyOffset, CopySize ); // Update buffer pointer. pStubMsg->Buffer += CopySize; // Increment format string to possible pointer layout. pFormat += 6; CORRELATION_DESC_INCREMENT( pFormat ); // Marshall embedded pointers. if ( *pFormat == FC_PP ) { // Mark the start of the array in the buffer. pStubMsg->BufferMark = pStubMsg->Buffer - CopySize; // // Set the MaxCount field equal to the ActualCount field. The pointer // marshalling routine uses the MaxCount field to determine the number // of times an FC_VARIABLE_REPEAT pointer is marshalled. In the face // of variance the correct number of time is the ActualCount, not the // the MaxCount. // pStubMsg->MaxCount = pStubMsg->ActualCount; // // Marshall the embedded pointers. // Make sure to pass a memory pointer to the first array element // which is actually being marshalled. // NdrpEmbeddedPointerMarshall( pStubMsg, pMemory + CopyOffset, pFormat ); } return 0; } unsigned char * RPC_ENTRY NdrComplexArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls a top level complex array. Used for FC_BOGUS_STRUCT. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the array being marshalled. pFormat - Array's format string description. Return : None. --*/ { BOOL fSetPointerBufferMark; PFORMAT_STRING pFormatPP; // // Setting this flag means that the array is not embedded inside of // another complex struct or array. // pFormatPP = pFormat + 12; CORRELATION_DESC_INCREMENT( pFormatPP ); CORRELATION_DESC_INCREMENT( pFormatPP ); fSetPointerBufferMark = (! pStubMsg->PointerBufferMark) && (*pFormatPP != FC_RP); if ( fSetPointerBufferMark ) { BOOL fOldIgnore; ULONG_PTR MaxCountSave; ulong Offset, ActualCount; ulong BufferLenOffset; // // Save the current conformance and variance fields. The sizing // routine can overwrite them. // MaxCountSave = pStubMsg->MaxCount; Offset = pStubMsg->Offset; ActualCount = pStubMsg->ActualCount; fOldIgnore = pStubMsg->IgnoreEmbeddedPointers; pStubMsg->IgnoreEmbeddedPointers = TRUE; // // Set BufferLength equal to the current buffer pointer, and then // when we return from NdrComplexArrayBufferSize it will point to // the location in the buffer where the pointers should be marshalled // into. // Instead of pointer, we now calculate pointer increment explicitly. // // Set the pointer alignment as a base. BufferLenOffset = 0xf & PtrToUlong( pStubMsg->Buffer ); ulong BufferLengthSave = pStubMsg->BufferLength; pStubMsg->BufferLength = BufferLenOffset; NdrComplexArrayBufferSize( pStubMsg, pMemory, pFormat ); // Pointer increment including alignments. BufferLenOffset = pStubMsg->BufferLength - BufferLenOffset; // // This is the buffer pointer to the position where embedded pointers // will be marshalled. // pStubMsg->PointerBufferMark = pStubMsg->Buffer + BufferLenOffset; pStubMsg->BufferLength = BufferLengthSave; pStubMsg->IgnoreEmbeddedPointers = fOldIgnore; // Restore conformance and variance fields. pStubMsg->MaxCount = MaxCountSave; pStubMsg->Offset = Offset; pStubMsg->ActualCount = ActualCount; } if ( ( *((long UNALIGNED *)(pFormat + 4)) != 0xffffffff ) && ( pStubMsg->pArrayInfo == 0 ) ) { // // Outer most dimension sets the conformance marker. // // Align the buffer for conformance marshalling. ALIGN(pStubMsg->Buffer,3); // Mark where the conformance count(s) will be marshalled. pStubMsg->BufferMark = pStubMsg->Buffer; // Increment past where the conformance will go. pStubMsg->Buffer += NdrpArrayDimensions( pStubMsg, pFormat, FALSE ) * 4; } // Call the private marshalling routine to do all the work. NdrpComplexArrayMarshall( pStubMsg, pMemory, pFormat ); if ( fSetPointerBufferMark ) { // // This will set the buffer pointer to end of all of the array's // unmarshalled data in the buffer. // pStubMsg->Buffer = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; } return 0; } void NdrpComplexArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Private routine for marshalling a complex array. This is the entry point for marshalling an embedded complex array. Used for FC_BOGUS_ARRAY. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the array being marshalled. pFormat - Array's format string description. pStubMsg->Buffer - array pointer pStubMsg->BufferMark - a place to marshal the conformant size pStubMsg->BufferPointerMark - a place to marshal the pointees Return : None. --*/ { ARRAY_INFO ArrayInfo; PARRAY_INFO pArrayInfo; PMARSHALL_ROUTINE pfnMarshall; PFORMAT_STRING pFormatStart; uint Elements; uint Offset, Count; uint MemoryElementSize; long Dimension; uchar Alignment; bool UseBrokenInterfacePointerRep = false; // // Lots of setup if we are the outer dimension. All this is for // multidimensional array support. If we didn't have to worry about // Beta2 stub compatability we could this much better. // // if ( ! pStubMsg->pArrayInfo ) { NdrpInitArrayInfo(pStubMsg, &ArrayInfo ); } pFormatStart = pFormat; pArrayInfo = pStubMsg->pArrayInfo; Dimension = pArrayInfo->Dimension; // Get the array's alignment. Alignment = pFormat[1]; pFormat += 2; // Get number of elements (0 if the array has conformance). Elements = *((ushort *&)pFormat)++; // // Check for conformance description. // if ( *((long UNALIGNED *)pFormat) != 0xffffffff ) { Elements = (ulong) NdrpComputeConformance( pStubMsg, pMemory, pFormatStart ); // Marshall this dimension's conformance count. pArrayInfo->BufferConformanceMark[Dimension] = Elements; } pFormat += 4; CORRELATION_DESC_INCREMENT( pFormat ); // // Check for variance description. // if ( *((long UNALIGNED *)pFormat) != 0xffffffff ) { if ( Dimension == 0 ) { // // Set the variance marker. // ALIGN(pStubMsg->Buffer,0x3); // Mark where the variance count(s) will be marshalled. pArrayInfo->BufferVarianceMark = (unsigned long *) pStubMsg->Buffer; // Increment past where the variance will go. pStubMsg->Buffer += NdrpArrayDimensions( pStubMsg, pFormatStart, TRUE ) * 8; } NdrpComputeVariance( pStubMsg, pMemory, pFormatStart ); Offset = pStubMsg->Offset; Count = pStubMsg->ActualCount; // // Marshall the outer dimension's variance. // pArrayInfo->BufferVarianceMark[Dimension * 2] = Offset; pArrayInfo->BufferVarianceMark[(Dimension * 2) + 1] = Count; } else { Offset = 0; Count = Elements; } pFormat += 4; CORRELATION_DESC_INCREMENT( pFormat ); // // Return if count is 0. // if ( ! Count ) goto ComplexArrayMarshallEnd; // Align on array's alignment. ZeroOutGapAndAlign(pStubMsg,Alignment); switch ( *pFormat ) { case FC_EMBEDDED_COMPLEX : pFormat += 2; pFormat += *((signed short *)pFormat); if ( FC_IP == *pFormat ) goto HandleInterfacePointer; // Get the proper marshalling routine. pfnMarshall = pfnMarshallRoutines[ROUTINE_INDEX(*pFormat)]; pArrayInfo->Dimension = Dimension + 1; // Compute the size of an array element. MemoryElementSize = (uint) (NdrpMemoryIncrement( pStubMsg, pMemory, pFormat ) - pMemory); break; case FC_RP : case FC_UP : case FC_FP : case FC_OP : pfnMarshall = (PMARSHALL_ROUTINE) NdrpPointerMarshall; // Need this in case we have a variant offset. MemoryElementSize = PTR_MEM_SIZE; break; case FC_IP : HandleInterfacePointer: UseBrokenInterfacePointerRep = !FixWireRepForDComVerGTE54( pStubMsg ); // Probably does not exercise this code path, for IP the compiler // generates embedded complex as an array element. // pfnMarshall = (PMARSHALL_ROUTINE) NdrpPointerMarshall; // Need this in case we have a variant offset. MemoryElementSize = PTR_MEM_SIZE; break; case FC_ENUM16 : pfnMarshall = 0; // Need this in case we have a variant offset. MemoryElementSize = sizeof(int); break; #if defined(__RPC_WIN64__) case FC_INT3264: case FC_UINT3264: pfnMarshall = 0; MemoryElementSize = sizeof(__int64); break; #endif case FC_RANGE: // let's just memcpy in marshalling phase: don't need to check value here. Count *= SIMPLE_TYPE_BUFSIZE( pFormat[1] ); pMemory += Offset * SIMPLE_TYPE_MEMSIZE( pFormat[1] ); RpcpMarshalMemoryCopy( pStubMsg->Buffer, pMemory, Count ); pStubMsg->Buffer += Count; break; default : NDR_ASSERT( IS_SIMPLE_TYPE(*pFormat), "NdrpComplexArrayMarshall : bad format char" ); Count *= SIMPLE_TYPE_BUFSIZE(*pFormat); pMemory += Offset * SIMPLE_TYPE_MEMSIZE(*pFormat); // Copy the array. RpcpMarshalMemoryCopy( pStubMsg->Buffer, pMemory, Count ); pStubMsg->Buffer += Count; goto ComplexArrayMarshallEnd; } // // If there is variance then increment the memory pointer to the first // element actually being marshalled. // if ( Offset ) pMemory += Offset * MemoryElementSize; // // Array of enum16 or int3264. // if ( ! pfnMarshall ) { #if defined(__RPC_WIN64__) if ( *pFormat != FC_ENUM16 ) { for ( ; Count--; ) *((long * &)pStubMsg->Buffer)++ = (long)*((INT64 * &)pMemory)++; } else #endif { for ( ; Count--; ) { if ( *((int *)pMemory) & ~((int)0x7fff) ) RpcRaiseException(RPC_X_ENUM_VALUE_OUT_OF_RANGE); *((ushort *&)pStubMsg->Buffer)++ = (ushort) *((int *&)pMemory)++; } } goto ComplexArrayMarshallEnd; } // // For 32b, an array of ref or interface pointers. // For 64b, an array of any pointers. // if ( pfnMarshall == (PMARSHALL_ROUTINE) NdrpPointerMarshall ) { pStubMsg->pArrayInfo = 0; uchar * pPointerId = (*pFormat == FC_RP) ? 0 : pStubMsg->Buffer; if ( UseBrokenInterfacePointerRep ) { // If were using the broken array format, do no increment the // buffer pointer for the flat part, and throw everything // where the pointee should go. SET_BROKEN_INTERFACE_POINTER( pStubMsg->uFlags ); POINTER_BUFFER_SWAP_CONTEXT NewContext(pStubMsg); for ( ; Count--; ) { // This effectively calls NdrInterfacePointerMarshall. Doinging // this so another queue structure/callback isn't needed just for // this rare code. NdrpPointerMarshall( pStubMsg, pPointerId, *((uchar **&)pMemory)++, pFormat ); pPointerId += PTR_WIRE_SIZE; } RESET_BROKEN_INTERFACE_POINTER( pStubMsg->uFlags ); } else { { POINTER_BUFFER_SWAP_CONTEXT NewContext(pStubMsg); for ( ; Count--; ) { NdrpPointerMarshall( pStubMsg, pPointerId, *((uchar **&)pMemory)++, pFormat ); // // Needed only for non ref pointers, but pPointerIds is not used for refs. // pPointerId += PTR_WIRE_SIZE; } } // Increment buffer pointer past the flat part of the array. if ( *pFormat != FC_RP ) pStubMsg->Buffer = pPointerId; } goto ComplexArrayMarshallEnd; } // // It's an array of complex types. // if ( ! IS_ARRAY_OR_STRING(*pFormat) ) pStubMsg->pArrayInfo = 0; // Marshall the array elements. for ( ; Count--; ) { // Keep track of multidimensional array dimension. if ( IS_ARRAY_OR_STRING(*pFormat) ) pArrayInfo->Dimension = Dimension + 1; (*pfnMarshall)( pStubMsg, pMemory, pFormat ); // Increment the memory pointer by the element size. pMemory += MemoryElementSize; } ComplexArrayMarshallEnd: // pArrayInfo must be zero when not valid. pStubMsg->pArrayInfo = (Dimension == 0) ? 0 : pArrayInfo; } unsigned char * RPC_ENTRY NdrEncapsulatedUnionMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls an encapsulated union. Used for FC_ENCAPSULATED_UNION. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the union being marshalled. pFormat - Union's format string description. Return : None. --*/ { long SwitchIs; uchar SwitchType; NO_CORRELATION; SwitchType = LOW_NIBBLE(pFormat[1]); switch ( SwitchType ) { case FC_SMALL : case FC_CHAR : SwitchIs = (long) *((char *)pMemory); break; case FC_USMALL : SwitchIs = (long) *((uchar *)pMemory); break; case FC_ENUM16 : case FC_SHORT : SwitchIs = (long) *((short *)pMemory); break; case FC_USHORT : case FC_WCHAR : SwitchIs = (long) *((ushort *)pMemory); break; case FC_LONG : case FC_ULONG : case FC_ENUM32 : // FC_INT3264 gets mapped to FC_LONG SwitchIs = *((long *)pMemory); break; default : NDR_ASSERT(0,"NdrEncapsulatedUnionMarshall : bad swith type"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return 0; } // Increment the memory pointer to the union. pMemory += HIGH_NIBBLE(pFormat[1]); NdrpUnionMarshall( pStubMsg, pMemory, pFormat + 2, SwitchIs, SwitchType ); return 0; } unsigned char * RPC_ENTRY NdrNonEncapsulatedUnionMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls a non encapsulated union. Used for FC_NON_ENCAPSULATED_UNION. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the union being marshalled. pFormat - Union's format string description. Return : None. --*/ { long SwitchIs; uchar SwitchType; SwitchType = pFormat[1]; SwitchIs = (ulong) NdrpComputeSwitchIs( pStubMsg, pMemory, pFormat ); // // Set the format string to the memory size and arm description. // pFormat += 6; CORRELATION_DESC_INCREMENT( pFormat ); pFormat += *((signed short *)pFormat); NdrpUnionMarshall( pStubMsg, pMemory, pFormat, SwitchIs, SwitchType ); return 0; } void NdrpUnionMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat, long SwitchIs, uchar SwitchType ) /*++ Routine Description : Private routine for marshalling a union. This routine is shared for both encapsulated and non-encapsulated unions and handles the actual marshalling of the proper union arm. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the union being marshalled. pFormat - The memory size and arm description portion of the format string for the union. SwitchIs - Union's switch is. SwitchType - Union's switch is type. Return : None. --*/ { long Arms; uchar Alignment; // Marshall the switch is value. NdrSimpleTypeMarshall( pStubMsg, (uchar *)&SwitchIs, SwitchType ); // Skip the memory size field. pFormat += 2; // // We're at the union_arms<2> field now, which contains both the // Microsoft union aligment value and the number of union arms. // // // Get the union alignment (0 if this is a DCE union). // Alignment = (uchar) ( *((ushort *)pFormat) >> 12 ); ZeroOutGapAndAlign(pStubMsg,Alignment); // // Number of arms is the lower 12 bits. // Arms = (long) ( *((ushort *&)pFormat)++ & 0x0fff); // // Search for the correct arm. // for ( ; Arms; Arms-- ) { if ( *((long UNALIGNED *&)pFormat)++ == SwitchIs ) { // // Found the right arm, break out. // break; } // Else increment format string. pFormat += 2; } // // Check if we took the default arm and no default arm is specified. // if ( ! Arms && (*((ushort *)pFormat) == (ushort) 0xffff) ) { RpcRaiseException( RPC_S_INVALID_TAG ); } // // Return if the arm is empty. // if ( ! *((ushort *)pFormat) ) return; // // Get the arm's description. // // We need a real solution after beta for simple type arms. This could // break if we have a format string larger than about 32K. // if ( IS_MAGIC_UNION_BYTE(pFormat) ) { NdrSimpleTypeMarshall( pStubMsg, pMemory, pFormat[0] ); return; } pFormat += *((signed short *)pFormat); // // If the union arm we take is a pointer, we have to dereference the // current memory pointer since we're passed a pointer to the union // (regardless of whether the actual parameter was a by-value union // or a pointer to a union). // // We also have to do a bunch of other special stuff to handle unions // embedded inside of strutures. // if ( IS_POINTER_TYPE(*pFormat) ) { pMemory = *((uchar **)pMemory); // // If we're embedded in a struct or array we have do some extra stuff. // if ( pStubMsg->PointerBufferMark ) { ALIGN(pStubMsg->Buffer,3); uchar *pPointerId = pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; POINTER_BUFFER_SWAP_CONTEXT SwapContext( pStubMsg ); NdrpPointerMarshall( pStubMsg, pPointerId, pMemory, pFormat ); return; } } // // Union arm of a non-simple type. // (*pfnMarshallRoutines[ROUTINE_INDEX(*pFormat)]) ( pStubMsg, pMemory, pFormat ); } unsigned char * RPC_ENTRY NdrByteCountPointerMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls a pointer with the byte count attribute applied to it. Used for FC_BYTE_COUNT_POINTER. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the byte count pointer being marshalled. pFormat - Byte count pointer's format string description. Return : None. --*/ { // // We don't do anything special here. Just pass things on to the // right marshalling routine. // if ( pFormat[1] != FC_PAD ) { NdrSimpleTypeMarshall( pStubMsg, pMemory, pFormat[1] ); } else { pFormat += 6; CORRELATION_DESC_INCREMENT( pFormat ); pFormat += *((signed short *)pFormat); (*pfnMarshallRoutines[ROUTINE_INDEX(*pFormat)])( pStubMsg, pMemory, pFormat ); } return 0; } unsigned char * RPC_ENTRY NdrXmitOrRepAsMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls a transmit as or represent as argument: - translate the presented object into a transmitted object - marshall the transmitted object - free the transmitted object Format string layout: 0 FC_TRANSMIT_AS or FC_REPRESENT_AS Oi array flag/alignment<1> +2 quintuple index<2> +4 pres type mem size<2> +6 tran type buf size<2> +8 offset<2> Arguments : pStubMsg - a pointer to the stub message pMemory - presented type translated into transmitted type and than to be marshalled pFormat - format string description --*/ { unsigned char * pTransmittedType; const XMIT_ROUTINE_QUINTUPLE * pQuintuple = pStubMsg->StubDesc->aXmitQuintuple; unsigned short QIndex; BOOL fXmitByPtr = *pFormat == FC_TRANSMIT_AS_PTR || *pFormat == FC_REPRESENT_AS_PTR; // Skip the token itself and Oi flag. Fetch the QuintupleIndex. QIndex = *(unsigned short *)(pFormat + 2); // First translate the presented type into the transmitted type. // This includes an allocation of a transmitted type object. pStubMsg->pPresentedType = pMemory; pStubMsg->pTransmitType = NULL; pQuintuple[ QIndex ].pfnTranslateToXmit( pStubMsg ); // Marshall the transmitted type. pFormat += 8; pFormat = pFormat + *(short *) pFormat; pTransmittedType = pStubMsg->pTransmitType; if ( IS_SIMPLE_TYPE( *pFormat )) { NdrSimpleTypeMarshall( pStubMsg, pTransmittedType, *pFormat ); } else { uchar *PointerBufferMarkSave = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; NDR_POINTER_QUEUE *pOldQueue = NULL; // Reset the current queue to NULL so that all the pointers // in the transmitted type will be queued and marshalled togother. if ( pStubMsg->pPointerQueueState ) { pOldQueue = pStubMsg->pPointerQueueState->GetActiveQueue(); pStubMsg->pPointerQueueState->SetActiveQueue(NULL); } RpcTryFinally { (*pfnMarshallRoutines[ROUTINE_INDEX(*pFormat)]) ( pStubMsg, fXmitByPtr ? *(uchar **)pTransmittedType : pTransmittedType, pFormat ); } RpcFinally { pStubMsg->PointerBufferMark = PointerBufferMarkSave; if ( pStubMsg->pPointerQueueState ) { pStubMsg->pPointerQueueState->SetActiveQueue( pOldQueue ); } } RpcEndFinally } pStubMsg->pTransmitType = pTransmittedType; // Free the temporary transmitted object (it was allocated by the user). pQuintuple[ QIndex ].pfnFreeXmit( pStubMsg ); return 0; } void NdrpUserMarshalMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat, unsigned long * pWireMarkerPtr ) /*++ Routine Description : Marshals a usr_marshall object. The format string layout is as follows: FC_USER_MARSHAL flags & alignment<1> quadruple index<2> memory size<2> wire size<2> type offset<2> The wire layout description is at the type offset. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the usr_marshall object to marshall. pFormat - Object's format string description. Return : None. --*/ { const USER_MARSHAL_ROUTINE_QUADRUPLE * pQuadruple; unsigned short QIndex; unsigned char * pUserBuffer; USER_MARSHAL_CB UserMarshalCB; unsigned char * pUserBufferSaved; pUserBufferSaved = pUserBuffer = pStubMsg->Buffer; // We always call user's routine to marshall. NdrpInitUserMarshalCB( pStubMsg, pFormat, USER_MARSHAL_CB_MARSHALL, & UserMarshalCB ); QIndex = *(unsigned short *)(pFormat + 2); pQuadruple = pStubMsg->StubDesc->aUserMarshalQuadruple; if ((pUserBufferSaved < (uchar *) pStubMsg->RpcMsg->Buffer) || ((unsigned long) (pUserBufferSaved - (uchar *) pStubMsg->RpcMsg->Buffer) > pStubMsg->RpcMsg->BufferLength)) { RpcRaiseException( RPC_X_INVALID_BUFFER ); } pUserBuffer = pQuadruple[ QIndex ].pfnMarshall( (ulong*) &UserMarshalCB, pUserBuffer, pMemory ); if ((pUserBufferSaved > pUserBuffer) || ((unsigned long) (pUserBuffer - (uchar *) pStubMsg->RpcMsg->Buffer) > pStubMsg->RpcMsg->BufferLength )) { RpcRaiseException( RPC_X_INVALID_BUFFER ); } if ( pUserBuffer == pUserBufferSaved ) { // This is valid only if the wire type was a unique type. if ( (pFormat[1] & USER_MARSHAL_UNIQUE) ) { *pWireMarkerPtr = 0; return; } else RpcRaiseException( RPC_X_NULL_REF_POINTER ); } pStubMsg->Buffer = pUserBuffer; return; } void NDR_USR_MRSHL_MRSHL_POINTER_QUEUE_ELEMENT::Dispatch(MIDL_STUB_MESSAGE *pStubMsg) { NdrpUserMarshalMarshall( pStubMsg, pMemory, pFormat, pWireMarkerPtr ); } #if defined(DBG) void NDR_USR_MRSHL_MRSHL_POINTER_QUEUE_ELEMENT::Print() { DbgPrint("NDR_USR_MRSHL_MRSHL_POINTER_QUEUE_ELEMENT\n"); DbgPrint("pMemory: %p\n", pMemory ); DbgPrint("pFormat: %p\n", pFormat ); DbgPrint("pWireMarkerPtr: %p\n", pWireMarkerPtr ); } #endif unsigned char * RPC_ENTRY NdrUserMarshalMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) { unsigned long * pWireMarkerPtr = 0; // Align for the object or a pointer to it. ZeroOutGapAndAlign( pStubMsg, LOW_NIBBLE(pFormat[1]) ); if ( pFormat[1] & USER_MARSHAL_POINTER ) { if ( (pFormat[1] & USER_MARSHAL_UNIQUE) || ((pFormat[1] & USER_MARSHAL_REF) && pStubMsg->PointerBufferMark) ) { pWireMarkerPtr = (unsigned long *) pStubMsg->Buffer; *((unsigned long *&)pStubMsg->Buffer)++ = USER_MARSHAL_MARKER; } if ( !pStubMsg->pPointerQueueState || !pStubMsg->pPointerQueueState->GetActiveQueue() ) { // If we are embedded, switch to the pointee buffer. POINTER_BUFFER_SWAP_CONTEXT SwapContext(pStubMsg); NdrpUserMarshalMarshall( pStubMsg, pMemory, pFormat, pWireMarkerPtr ); } else { NDR_USR_MRSHL_MRSHL_POINTER_QUEUE_ELEMENT*pElement = new(pStubMsg->pPointerQueueState) NDR_USR_MRSHL_MRSHL_POINTER_QUEUE_ELEMENT(pMemory, pFormat, pWireMarkerPtr); pStubMsg->pPointerQueueState->GetActiveQueue()->Enque( pElement ); } return 0; } NdrpUserMarshalMarshall( pStubMsg, pMemory, pFormat, pWireMarkerPtr ); return 0; } unsigned char * NdrpInterfacePointerMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls an interface pointer. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the interface pointer being marshalled. pFormat - Interface pointer's format string description. Return : None. Notes : There is now one representation of a marshalled interface pointer. The format string contains FC_IP followed by either FC_CONSTANT_IID or FC_PAD. typedef struct { unsigned long size; [size_is(size)] byte data[]; }MarshalledInterface; --*/ { HRESULT hr; IID iid; IID * piid; unsigned long * pSize; unsigned long * pMaxCount; unsigned long cbData = 0; unsigned long cbMax; unsigned long position; IStream * pStream; LARGE_INTEGER libMove; ULARGE_INTEGER libPosition; ALIGN(pStubMsg->Buffer,0x3); // // Get an IID pointer. // if ( pFormat[1] != FC_CONSTANT_IID ) { // // This is like computing a variance with a long. // piid = (IID *) NdrpComputeIIDPointer( pStubMsg, pMemory, pFormat ); if(piid == 0) RpcRaiseException( RPC_S_INVALID_ARG ); } else { // // The IID may not be aligned properly in the format string, // so we copy it to a local variable. // // we don't need to zero out the end pad as the size is 16. piid = &iid; RpcpMemoryCopy( &iid, &pFormat[2], sizeof(iid) ); } // Leave space in the buffer for the conformant size and the size field. pMaxCount = (unsigned long *) pStubMsg->Buffer; pStubMsg->Buffer += sizeof(unsigned long); pSize = (unsigned long *) pStubMsg->Buffer; pStubMsg->Buffer += sizeof(unsigned long); if(pMemory) { //Calculate the maximum size of the stream. position = (ulong)( pStubMsg->Buffer - (uchar *)pStubMsg->RpcMsg->Buffer); cbMax = pStubMsg->RpcMsg->BufferLength - position; //Create a stream on memory. pStream = NdrpCreateStreamOnMemory(pStubMsg->Buffer, cbMax); if(pStream == 0) RpcRaiseException(RPC_S_OUT_OF_MEMORY); hr = (*pfnCoMarshalInterface)(pStream, *piid, (IUnknown *)pMemory, pStubMsg->dwDestContext, pStubMsg->pvDestContext, 0); if(FAILED(hr)) { pStream->Release(); pStream = 0; RpcRaiseException(hr); } //Calculate the size of the data written libMove.LowPart = 0; libMove.HighPart = 0; pStream->Seek(libMove, STREAM_SEEK_CUR, &libPosition); pStream->Release(); pStream = 0; cbData = libPosition.LowPart; } //Update the array bounds. *pMaxCount = cbData; *pSize = cbData; //Advance the stub message buffer pointer. pStubMsg->Buffer += cbData; return 0; } unsigned char * RPC_ENTRY NdrInterfacePointerMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) { // Always put the pointer itself on wire, it behaves like a unique. // // This function is only called for toplevel interface pointers with Os mode, // or when being backward compatible with the incorrect wire format. // Oicf uses NdrPointerMarshall. ALIGN(pStubMsg->Buffer,0x3); *((ulong *&)pStubMsg->Buffer)++ = PTR_WIRE_REP(pMemory, pStubMsg ); // If the pointer is null, it's done. if ( pMemory == 0 ) return 0; return NdrpInterfacePointerMarshall( pStubMsg, pMemory, pFormat ); } // // Context handle marshalling routines. // void RPC_ENTRY NdrClientContextMarshall( PMIDL_STUB_MESSAGE pStubMsg, NDR_CCONTEXT ContextHandle, int fCheck ) /*++ Routine Description : Marshalls a context handle on the client side. Arguments : pStubMsg - Pointer to stub message. ContextHandle - Context handle to marshall. fCheck - TRUE if an exception check should be made on the handle, FALSE otherwise. Return : None. --*/ { // Note, this is a routine called directly from -Os stubs. // The routine called by interpreter is called NdrMarshallHandle // and can be found in hndl.c if ( fCheck && ! ContextHandle ) RpcRaiseException( RPC_X_SS_IN_NULL_CONTEXT ); ALIGN(pStubMsg->Buffer,3); // This call will check for bogus handles now and will raise // an exception when necessary. NDRCContextMarshall( ContextHandle, pStubMsg->Buffer ); pStubMsg->Buffer += CONTEXT_HANDLE_WIRE_SIZE; } void RPC_ENTRY NdrServerContextMarshall( PMIDL_STUB_MESSAGE pStubMsg, NDR_SCONTEXT ContextHandle, NDR_RUNDOWN RundownRoutine ) /*++ Routine Description : Marshalls a context handle on the server side. Arguments : pStubMsg - Pointer to stub message. ContextHandle - Context handle to marshall. RundownRoutine - The context rundown routine. Return : None. --*/ { // Note, this is a routine called directly from -Os stubs. // The routine called by interpreter is called NdrMarshallHandle // and can be found in hndl.c ALIGN(pStubMsg->Buffer,3); NDRSContextMarshall2(pStubMsg->RpcMsg->Handle, ContextHandle, pStubMsg->Buffer, RundownRoutine, RPC_CONTEXT_HANDLE_DEFAULT_GUARD, RPC_CONTEXT_HANDLE_DEFAULT_FLAGS ); pStubMsg->Buffer += CONTEXT_HANDLE_WIRE_SIZE; } void RPC_ENTRY NdrServerContextNewMarshall( PMIDL_STUB_MESSAGE pStubMsg, NDR_SCONTEXT ContextHandle, NDR_RUNDOWN RundownRoutine, PFORMAT_STRING pFormat ) /* This is a non-optimized NDR engine entry for context handle marshaling. In particular it is able to handle all the new NT5 context handle flavors. The optimized routine follows below. ContextHandle - note, this is not the user's handle but a NDR_SCONTEXT pointer from the stub local stack. User's handle is a field in that object. Note that intepreter calls NdrMarshallHandle. However, we can't use it as it assumes a helper array of saved context handles that we don't need. */ { void * pGuard = RPC_CONTEXT_HANDLE_DEFAULT_GUARD; DWORD Flags = RPC_CONTEXT_HANDLE_DEFAULT_FLAGS; // NT5 beta2 features: strict context handle, serialize and noserialize. if ( pFormat[1] & NDR_STRICT_CONTEXT_HANDLE ) { pGuard = pStubMsg->StubDesc->RpcInterfaceInformation; pGuard = & ((PRPC_SERVER_INTERFACE)pGuard)->InterfaceId; } if ( pFormat[1] & NDR_CONTEXT_HANDLE_NOSERIALIZE ) { Flags = RPC_CONTEXT_HANDLE_DONT_SERIALIZE; } else if ( pFormat[1] & NDR_CONTEXT_HANDLE_SERIALIZE ) { Flags = RPC_CONTEXT_HANDLE_SERIALIZE; } ALIGN( pStubMsg->Buffer, 0x3 ); NDRSContextMarshall2( pStubMsg->RpcMsg->Handle, ContextHandle, pStubMsg->Buffer, RundownRoutine, pGuard, Flags ); pStubMsg->Buffer += CONTEXT_HANDLE_WIRE_SIZE; } void NdrpGetArraySizeLength ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat, long ElementSize, long * pSize, long * pLength, long * pWireSize ) /*++ Routine Description : Return the size and length of an array. We need to have this routine rather than just calling BufferSize since we need the actual length of the array, not the length plus whatever goop the NDR format puts in from of it. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the local array. pFormat - Pointer to the array to get the size of. Return : The size and length. Notes: --*/ { switch ( *pFormat ) { case FC_SMFARRAY: *pWireSize = * (short *) ( pFormat + 2 ); *pSize = *pWireSize; *pLength = *pSize; return; case FC_LGFARRAY: *pWireSize = * (int *) ( pFormat + 2 ); *pSize = *pWireSize; *pLength = *pSize; return; case FC_CARRAY: *pSize = (long) NdrpComputeConformance( pStubMsg, pMemory, pFormat ); *pWireSize = *pLength * ElementSize; *pLength = *pSize; return; case FC_LGVARRAY: *pWireSize = * (long *) ( pFormat + 2 ); *pSize = * (short *) ( pFormat + 6 ); NdrpComputeVariance( pStubMsg, pMemory, pFormat ); *pLength = pStubMsg->ActualCount; return; case FC_SMVARRAY: *pWireSize = * (short *) ( pFormat + 2 ); *pSize = * (short *) ( pFormat + 4 ); NdrpComputeVariance( pStubMsg, pMemory, pFormat ); *pLength = pStubMsg->ActualCount; return; case FC_CVARRAY: *pSize = (long) NdrpComputeConformance( pStubMsg, pMemory, pFormat ); *pWireSize = *pSize * ElementSize; NdrpComputeVariance( pStubMsg, pMemory, pFormat ); *pLength = pStubMsg->ActualCount; return; case FC_CSTRING: *pSize = strlen( (char*)pMemory ) + 1; *pWireSize = *pSize; *pLength = *pSize; return; case FC_WSTRING: *pSize = wcslen( (wchar_t *) pMemory ) + 1; *pWireSize = *pSize * 2; *pLength = *pSize; return; } NDR_ASSERT( 0, "NdrpGetArraySizeLength: Unhandled type" ); RpcRaiseException( RPC_S_INTERNAL_ERROR ); *pSize = 0; *pWireSize = 0; *pLength = 0; } #ifdef _CS_CHAR_ unsigned char * RPC_ENTRY NdrCsTagMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls a cs tag (i.e. a parameter marked with [cs_stag], [cs_drtag], or [cs_rtag]. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the value on the stack. pFormat - Pointer to the FC_CS_TAG entry in the format string. Return : None. --*/ { ulong Codeset = NdrpGetSetCSTagMarshall( pStubMsg, pMemory, (NDR_CS_TAG_FORMAT *) pFormat); * (ulong *) pStubMsg->Buffer = Codeset; pStubMsg->Buffer += sizeof( ulong ); return 0; } extern const byte NdrpArrayMarshallFlags[] = { MARSHALL_CONFORMANCE, // Conformant array MARSHALL_CONFORMANCE | MARSHALL_VARIANCE, // Conformant varying 0, // Small fixed 0, // Large fixed MARSHALL_VARIANCE, // Small varying MARSHALL_VARIANCE, // Large varying MARSHALL_BOGUS, // Bogus array MARSHALL_CONFORMANCE | MARSHALL_VARIANCE, // Conformant C string MARSHALL_CONFORMANCE | MARSHALL_VARIANCE, // Conformant byte string MARSHALL_CONFORMANCE | MARSHALL_VARIANCE, // Conformant struct string MARSHALL_CONFORMANCE | MARSHALL_VARIANCE, // Conformant Unicode string MARSHALL_VARIANCE, // C string MARSHALL_VARIANCE, // byte string MARSHALL_VARIANCE, // struct string MARSHALL_VARIANCE // Unicode string }; void NdrpUpdateArrayProlog( PFORMAT_STRING pFormat, uchar * BufferMark, ulong WireSize, ulong Offset, ulong WireLength ) { int flags; NDR_ASSERT( *pFormat >= FC_CARRAY, "Invalid array descriptor" ); NDR_ASSERT( *pFormat <= FC_WSTRING, "Invalid array descriptor" ); // We don't support bogus arrays for now NDR_ASSERT( *pFormat != FC_BOGUS_ARRAY, "Bogus arrays are not supported" ); flags = NdrpArrayMarshallFlags[ *pFormat - FC_CARRAY ]; if ( flags & MARSHALL_CONFORMANCE ) { * (ulong *) BufferMark = WireSize; BufferMark += 4; } if ( flags & MARSHALL_VARIANCE ) { * (ulong *) BufferMark = Offset; BufferMark += 4; * (ulong *) BufferMark = WireLength; } } unsigned char * RPC_ENTRY NdrCsArrayMarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Marshalls a [cs_char] array. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the local array. pFormat - Pointer to the FC_CSARRAY entry in the format string. Return : None. Notes : Arrays of [cs_char] are defined as arrays of bytes on the wire so marshalling is pretty simple once you know which bytes to marshall and how many of them. Since the existing array marshalling routines are not very general (they don't take size/length parameters) and since the overhead of a call to memcpy isn't very high we do the marshalling ourselves. --*/ { ulong SendingCodeset; ulong ReceivingCodeset; ulong ArraySize; ulong ArrayLength; ulong WireSize; ulong WireLength; uchar *BufferMark; error_status_t status; NDR_CS_ARRAY_FORMAT *pCSFormat; NDR_CS_SIZE_CONVERT_ROUTINES *CSRoutines; CS_TYPE_NET_SIZE_ROUTINE NetSizeRoutine; CS_TYPE_TO_NETCS_ROUTINE ToNetCSRoutine; IDL_CS_CONVERT ConversionType; pCSFormat = (NDR_CS_ARRAY_FORMAT *) pFormat; // Get all the info out of the FC_CS_ARRAY structure and bump pFormat // to point to the underlying data descriptor NDR_ASSERT( NULL != pStubMsg->pCSInfo, "cs_char info is not set up"); if ( pStubMsg->IsClient ) SendingCodeset = pStubMsg->pCSInfo->WireCodeset; else SendingCodeset = pStubMsg->pCSInfo->DesiredReceivingCodeset; CSRoutines = pStubMsg->StubDesc->CsRoutineTables->pSizeConvertRoutines; NetSizeRoutine = CSRoutines[pCSFormat->CSRoutineIndex].pfnNetSize; ToNetCSRoutine = CSRoutines[pCSFormat->CSRoutineIndex].pfnToNetCs; pFormat += pCSFormat->DescriptionOffset; // Get the size and length of the unconverted array. NdrpGetArraySizeLength( pStubMsg, pMemory, pFormat, pCSFormat->UserTypeSize, (long*)&ArraySize, (long*)&ArrayLength, (long*)&WireSize ); // Figure out whether we need to convert the data WireSize = ArraySize; NetSizeRoutine( pStubMsg->RpcMsg->Handle, SendingCodeset, ArraySize, &ConversionType, NdrpIsConformantArray( pFormat ) ? &WireSize : NULL, &status); if ( RPC_S_OK != status ) RpcRaiseException( status ); // Skip the buffer ahead to where the actual bits will go. We'll patch // up the array prolog later. ALIGN( pStubMsg->Buffer, 3 ); BufferMark = pStubMsg->Buffer; pStubMsg->Buffer += NdrpArrayPrologLength( pFormat ); // If we need to convert do so, otherwise just memcpy // WireLength = WireSize; WireLength = ArrayLength * pCSFormat->UserTypeSize; if ( IDL_CS_NO_CONVERT == ConversionType ) { CopyMemory( pStubMsg->Buffer, pMemory, WireLength ); pStubMsg->Buffer += WireLength; } else { ToNetCSRoutine( pStubMsg->RpcMsg->Handle, SendingCodeset, pMemory, ArrayLength, pStubMsg->Buffer, // ! NdrpIsVaryingArray( pFormat ) ? NULL : &WireLength, NdrpIsFixedArray( pFormat ) ? NULL : &WireLength, &status); if ( RPC_S_OK != status ) RpcRaiseException( status ); NDR_ASSERT( WireLength <= WireSize, "Buffer overflow during [cs_char] conversion"); pStubMsg->Buffer += WireLength; /* // For conformant or fixed arrays we must have WireSize bytes on the // wire so pad it out if necessary if ( ! NdrpIsVaryingArray( pFormat ) && WireLength < WireSize ) { // REVIEW: Is zero'ing necessary? ZeroMemory( pStubMsg->Buffer, WireSize - WireLength ); pStubMsg->Buffer += WireSize - WireLength; } */ if ( ! NdrpIsVaryingArray( pFormat ) ) WireSize = WireLength; } NdrpUpdateArrayProlog( pFormat, BufferMark, WireSize, pStubMsg->Offset, WireLength ); return 0; } #endif // _CS_CHAR void RPC_ENTRY NdrPartialIgnoreClientMarshall( PMIDL_STUB_MESSAGE pStubMsg, void * pMemory ) { ALIGN( pStubMsg->Buffer, 0x3 ); *(ulong *)pStubMsg->Buffer = pMemory ? 1 : 0; pStubMsg->Buffer += PTR_WIRE_SIZE; }