/********************************************************************** Copyright (c) 1993 Microsoft Corporation Module Name : unmrshl.c Abstract : This file contains the unmarshalling 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" // // Function table of unmarshalling routines. // const PUNMARSHALL_ROUTINE UnmarshallRoutinesTable[] = { NdrPointerUnmarshall, NdrPointerUnmarshall, NdrPointerUnmarshall, NdrPointerUnmarshall, NdrSimpleStructUnmarshall, NdrSimpleStructUnmarshall, NdrConformantStructUnmarshall, NdrConformantStructUnmarshall, NdrConformantVaryingStructUnmarshall, NdrComplexStructUnmarshall, NdrConformantArrayUnmarshall, NdrConformantVaryingArrayUnmarshall, NdrFixedArrayUnmarshall, NdrFixedArrayUnmarshall, NdrVaryingArrayUnmarshall, NdrVaryingArrayUnmarshall, NdrComplexArrayUnmarshall, NdrConformantStringUnmarshall, NdrConformantStringUnmarshall, NdrConformantStringUnmarshall, NdrConformantStringUnmarshall, NdrNonConformantStringUnmarshall, NdrNonConformantStringUnmarshall, NdrNonConformantStringUnmarshall, NdrNonConformantStringUnmarshall, NdrEncapsulatedUnionUnmarshall, NdrNonEncapsulatedUnionUnmarshall, NdrByteCountPointerUnmarshall, NdrXmitOrRepAsUnmarshall, // transmit as NdrXmitOrRepAsUnmarshall, // represent as NdrInterfacePointerUnmarshall, NdrUnmarshallHandle, // New Post NT 3.5 tokens serviced from here on. NdrHardStructUnmarshall, NdrXmitOrRepAsUnmarshall, // transmit as ptr NdrXmitOrRepAsUnmarshall, // represent as ptr NdrUserMarshalUnmarshall }; const PUNMARSHALL_ROUTINE * pfnUnmarshallRoutines = &UnmarshallRoutinesTable[-FC_RP]; #if defined( DOS ) && !defined( WIN ) #pragma code_seg( "NDR20_5" ) #endif void RPC_ENTRY NdrSimpleTypeUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, uchar FormatChar ) /*++ Routine Description : Unmarshalls a simple type. Arguments : pStubMsg - Pointer to the stub message. pMemory - Memory pointer to unmarshall into. FormatChar - Simple type format character. Return : None. --*/ { switch ( FormatChar ) { case FC_CHAR : case FC_BYTE : case FC_SMALL : case FC_USMALL : *pMemory = *(pStubMsg->Buffer)++; break; case FC_ENUM16 : #if !defined(DOS) && !defined(WIN16) *((ulong *)pMemory) &= 0x0000ffff; #endif #if defined(__RPC_MAC__) pMemory += 2; #endif // fall through... case FC_WCHAR : case FC_SHORT : case FC_USHORT : ALIGN(pStubMsg->Buffer,1); *((ushort *)pMemory) = *((ushort *)pStubMsg->Buffer)++; break; case FC_LONG : case FC_ULONG : case FC_FLOAT : case FC_ENUM32 : case FC_ERROR_STATUS_T: ALIGN(pStubMsg->Buffer,3); *((ulong *)pMemory) = *((ulong *)pStubMsg->Buffer)++; break; case FC_HYPER : case FC_DOUBLE : ALIGN(pStubMsg->Buffer,7); // // Let's stay away from casts to doubles. // *((ulong *)pMemory) = *((ulong *)pStubMsg->Buffer)++; *((ulong *)(pMemory + 4)) = *((ulong *)pStubMsg->Buffer)++; break; case FC_IGNORE : break; default : NDR_ASSERT(0,"NdrSimpleTypeUnmarshall : bad format char"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return; } } unsigned char * RPC_ENTRY NdrPointerUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fSkipRefCheck ) /*++ Routine Description : Unmarshalls a top level pointer to anything. Pointers embedded in structures, arrays, or unions call NdrpPointerUnmarshall directly. Used for FC_RP, FC_UP, FC_FP, FC_OP. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where to unmarshall the pointer. pFormat - Pointer's format string description. fSkipRefCheck - TRUE if we should skip the ref pointer exception check on the client, FALSE otherwise. Return : None. --*/ { uchar ** ppBufferPointer; uchar * pRefSpace; // // If the pointer is not a ref pointer then get a pointer to it's // incomming value's location in the buffer. If it's a ref then set // up some stack space to temporarily act as the buffer. // if ( *pFormat != FC_RP ) { ALIGN( pStubMsg->Buffer, 3 ); // This is where the incomming pointer's node id is. ppBufferPointer = (uchar **) pStubMsg->Buffer; pStubMsg->Buffer += 4; } else { // // If we're on the client unmarshalling a top level [out] ref pointer, // we have to make sure that it is non-null. // if ( pStubMsg->IsClient && ! fSkipRefCheck ) if ( ! *ppMemory ) RpcRaiseException( RPC_X_NULL_REF_POINTER ); // // Do this so unmarshalling ref pointers works the same as // unmarshalling unique and ptr pointers. // ppBufferPointer = &pRefSpace; } NdrpPointerUnmarshall( pStubMsg, ppBufferPointer, *ppMemory, pFormat ); // // The private pointer unmarshalling routine sets the final unmarshalled // value for the pointer in *ppBufferPointer. Copy it to *ppMemory. // *ppMemory = *ppBufferPointer; return 0; } void NdrpPointerUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppBufferPointer, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Private routine for unmarshalling a pointer to anything. 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. ppBufferPointer - Address of the location in the buffer which holds the incomming pointer's value and will hold the final unmarshalled pointer's value. pMemory - Current memory pointer's value which we want to unmarshall into. If this value is valid the it will be copied to *ppBufferPointer and this is where stuff will get unmarshalled into. pFormat - Pointer's format string description. Return : None. --*/ { ulong FullPtrRefId; uchar fPointeeAlloc; int fNewAllocAllNodes; int fNewDontFreeContext; fNewAllocAllNodes = FALSE; fNewDontFreeContext = FALSE; // // Check the pointer type. // switch ( *pFormat ) { case FC_RP : break; case FC_OP : // // Burn some instructions for OLE unique pointer support. // if ( pStubMsg->IsClient ) { // // It's ok if this is an [out] unique pointer. It will get // zeroed before this routine is called and NdrPointerFree // will simply return. // NdrPointerFree( pStubMsg, pMemory, pFormat ); // Set the current memory pointer to 0 so that we'll alloc. pMemory = 0; } // Fall through. case FC_UP : // // Check for a null incomming pointer. Routines which call this // routine insure that the memory pointer gets nulled. // if ( ! *ppBufferPointer ) return; break; case FC_FP : // // We have to remember the incomming ref id because we overwrite // it during the QueryRefId call. // FullPtrRefId = *((ulong *)ppBufferPointer); // // Lookup the ref id. // if ( NdrFullPointerQueryRefId( pStubMsg->FullPtrXlatTables, FullPtrRefId, FULL_POINTER_UNMARSHALLED, ppBufferPointer ) ) return; // // If our query returned false then check if the returned pointer // is 0. If so then we have to scribble away the ref id in the // stub message FullPtrRefId field so that we can insert the // pointer translation later, after we've allocated the pointer. // If the returned pointer was non-null then we leave the stub // message FullPtrRefId field alone so that we don't try to // re-insert the pointer to ref id translation later. // // We also copy the returned pointer value into pMemory. This // will allow our allocation decision to be made correctly. // if ( ! ( pMemory = *((uchar **)ppBufferPointer) ) ) { // // Put the unmarshalled ref id into the stub message to // be used later in a call to NdrFullPointerInsertRefId. // pStubMsg->FullPtrRefId = FullPtrRefId; } break; default : NDR_ASSERT(0,"NdrpPointerUnmarshall : bad pointer type"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return; } // // Make the initial "must allocate" decision. // // The fPointeeAlloc flag is set on the client side if the current memory // pointer is null, and on the server side it is set if the current memory // pointer has the allocate don't free attribute applied to it. // // On the client side we also set the pointer's value in the buffer equal // to the current memory pointer. // // On the server side we explicitly null out the pointer's value in the // buffer as long as it's not allocated on the stack, otherwise we set it // equal to the current memory pointer (stack allocated). // if ( pStubMsg->IsClient ) { *ppBufferPointer = pMemory; fPointeeAlloc = ! pMemory; } else { if ( ! ALLOCED_ON_STACK(pFormat[1]) ) *ppBufferPointer = 0; else *ppBufferPointer = pMemory; // // If this is a don't free pointer or a parent pointer of this pointer // was a don't free pointer then we set the alloc flag. // if ( fPointeeAlloc = (DONT_FREE(pFormat[1]) || pStubMsg->fInDontFree) ) { // // If we encounter a don't free pointer which is not nested inside // of another don't free pointer then set the local and stub message // flags. // if ( ! pStubMsg->fInDontFree ) { fNewDontFreeContext = TRUE; pStubMsg->fInDontFree = TRUE; } } // // We also set the alloc flag for object interface pointers. // if ( *pFormat == FC_OP ) fPointeeAlloc = TRUE; } // // Pointer to complex type. // if ( ! SIMPLE_POINTER(pFormat[1]) ) { PFORMAT_STRING pFormatPointee; pFormatPointee = pFormat + 2; // Set the pointee format string. // Cast must be to a signed short since some offsets are negative. pFormatPointee += *((signed short *)pFormatPointee); // // Right now the server will always allocate for allocate all nodes // when told to. Eventually we want to use the rpc buffer when // possible. // // // Check if this is an allocate all nodes pointer AND that we're // not already in an allocate all nodes context. // if ( ALLOCATE_ALL_NODES(pFormat[1]) && ! pStubMsg->AllocAllNodesMemory ) { unsigned int AllocSize; uchar * pBuffer; fNewAllocAllNodes = TRUE; pBuffer = pStubMsg->Buffer; // Clear memory size before calling mem size routine. pStubMsg->MemorySize = 0; // // Get the allocate all nodes memory size. // AllocSize = (*pfnMemSizeRoutines[ROUTINE_INDEX(*pFormatPointee)]) ( pStubMsg, pFormatPointee ); pStubMsg->AllocAllNodesMemory = NdrAllocate( pStubMsg, AllocSize ); // This is used to catch memory allocation errors. pStubMsg->AllocAllNodesMemoryEnd = pStubMsg->AllocAllNodesMemory + AllocSize; pStubMsg->Buffer = pBuffer; *ppBufferPointer = 0; fPointeeAlloc = TRUE; // // I think this is what we'll have to add to support an [in,out] // allocate all nodes full pointer ([in] only and [out] only // allocate all nodes full pointer shouldn't need any special // treatment). // // if ( *pFormat == FC_FP ) // { // pStubMsg->FullPtrRefId = FullPtrRefId; // } // } if ( POINTER_DEREF(pFormat[1]) ) { // // Re-align the buffer. This is to cover embedded pointer to // pointers. // ALIGN(pStubMsg->Buffer,0x3); // // We can't re-use the buffer for a pointer to a pointer // because we can't null out the pointee before we've unmarshalled // it. We need the stubs to alloc pointers to pointers on the // stack. // if ( ! *ppBufferPointer && ! pStubMsg->IsClient ) fPointeeAlloc = TRUE; if ( fPointeeAlloc ) { *ppBufferPointer = NdrAllocate( pStubMsg, sizeof(void *) ); *((void **)*ppBufferPointer) = 0; } if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppBufferPointer ); ppBufferPointer = (uchar **) *ppBufferPointer; } // // Now call the proper unmarshalling routine. // (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormatPointee)]) ( pStubMsg, ppBufferPointer, pFormatPointee, fPointeeAlloc ); // // Reset the memory allocator and allocate all nodes flag if this was // an allocate all nodes case. // if ( fNewAllocAllNodes ) { pStubMsg->AllocAllNodesMemory = 0; pStubMsg->AllocAllNodesMemoryEnd = 0; } goto PointerUnmarshallEnd; } // // Else handle a pointer to a simple type, pointer, or string. // switch ( pFormat[2] ) { case FC_C_CSTRING : case FC_C_BSTRING : case FC_C_WSTRING : case FC_C_SSTRING : NdrConformantStringUnmarshall( pStubMsg, ppBufferPointer, &pFormat[2], fPointeeAlloc ); goto PointerUnmarshallEnd; default : // Break to handle a simple type. break; } // // Handle pointers to simple types. // // // Align the buffer. // ALIGN(pStubMsg->Buffer,SIMPLE_TYPE_ALIGNMENT(pFormat[2])); // // We can't use the buffer for pointers to enum16 since these force // us to zero out the upper 16 bits of the memory pointer, and this // might overwrite data in the buffer that we still need! // if ( pFormat[2] == FC_ENUM16 ) { if ( ! pStubMsg->IsClient && ! *ppBufferPointer ) fPointeeAlloc = TRUE; } // // Check for allocation or buffer reuse. // if ( fPointeeAlloc ) { *ppBufferPointer = NdrAllocate( pStubMsg, SIMPLE_TYPE_MEMSIZE(pFormat[2]) ); } else { if ( ! pStubMsg->IsClient && ! *ppBufferPointer ) { // Set pointer into buffer. *ppBufferPointer = pStubMsg->Buffer; } } if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppBufferPointer ); // // We always get here for simple types. What this means is that // when we reuse the buffer on the server side we end up copying the // data with source and destination memory pointer equal. But this // way we can cover the enum and error_status_t cases without duplicating // a lot of code. // NdrSimpleTypeUnmarshall( pStubMsg, *ppBufferPointer, pFormat[2] ); PointerUnmarshallEnd: if ( fNewDontFreeContext ) pStubMsg->fInDontFree = FALSE; } unsigned char * RPC_ENTRY NdrSimpleStructUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls a simple structure. Used for FC_STRUCT and FC_PSTRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to the structure being unmarshalled. pFormat - Structure's format string description. fMustAlloc - TRUE if the structure must be allocate, FALSE otherwise. --*/ { uchar * pBufferSave; uint StructSize; // Align the buffer. ALIGN(pStubMsg->Buffer,pFormat[1]); // Increment to the struct size field. pFormat += 2; // Get struct size and increment. StructSize = (ulong) *((ushort *)pFormat)++; // Remember the current buffer position for the struct copy later. pBufferSave = pStubMsg->Buffer; // Set BufferMark to the beginning of the struct in the buffer. pStubMsg->BufferMark = pBufferSave; // Increment Buffer past struct data. pStubMsg->Buffer += StructSize; // Initialize the memory pointer if needed. if ( fMustAlloc ) *ppMemory = (uchar *) NdrAllocate( pStubMsg, StructSize ); else if ( pStubMsg->ReuseBuffer && ! *ppMemory ) *ppMemory = pBufferSave; // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // Unmarshall embedded pointers before copying the struct. if ( *pFormat == FC_PP ) { NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, fMustAlloc ); } // Copy the struct if we're not using the rpc buffer. if ( *ppMemory != pBufferSave ) { RpcpMemoryCopy( *ppMemory, pBufferSave, StructSize ); } return 0; } unsigned char * RPC_ENTRY NdrConformantStructUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls a conformant structure. Used for FC_CSTRUCT and FC_CPSTRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the structure should be unmarshalled. pFormat - Structure's format string description. fMustAlloc - TRUE if the structure must be allocate, FALSE otherwise. Return : None. --*/ { uchar * pBufferStart; PFORMAT_STRING pFormatArray; uint StructSize; uchar Alignment; // Align the buffer for unmarshalling the conformance count. ALIGN(pStubMsg->Buffer,3); // Unmarshall the conformance count into the stub message. pStubMsg->MaxCount = *((ulong *)pStubMsg->Buffer)++; // Save the structure's alignment. Alignment = pFormat[1]; // Increment format string to structure size field. pFormat += 2; // Get flat struct size and increment format string. StructSize = (ulong) *((ushort *)pFormat)++; // Get the conformant array's description. pFormatArray = pFormat + *((signed short *)pFormat); // Add the size of the conformant array to the structure size. StructSize += pStubMsg->MaxCount * *((ushort *)(pFormatArray + 2)); if ( pStubMsg->fCheckBounds && ! pStubMsg->IsClient ) { CHECK_BOUND( pStubMsg->MaxCount, pFormatArray[4] & 0x0f ); if ( (pStubMsg->Buffer + StructSize) > pStubMsg->BufferEnd ) RpcRaiseException( RPC_X_INVALID_BOUND ); } // Re-align the buffer if an 8 byte alignment is needed. if ( Alignment == 7 ) ALIGN(pStubMsg->Buffer,7); // // Remember where we're going to copy from. // pBufferStart = pStubMsg->Buffer; // Set stub message Buffer field to the end of the structure in the buffer. pStubMsg->Buffer += StructSize; // Increment pFormat past the array description pFormat += 2; // Initialize the memory pointer if needed. if ( fMustAlloc ) *ppMemory = (uchar *) NdrAllocate( pStubMsg, StructSize ); else if ( pStubMsg->ReuseBuffer && ! *ppMemory ) *ppMemory = pBufferStart; // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // Unmarshall embedded pointers before copying the struct. if ( *pFormat == FC_PP ) { // // Set BufferMark to the beginning of the structure in the buffer. // pStubMsg->BufferMark = pBufferStart; NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, fMustAlloc ); } // Copy the struct if we're not using the rpc buffer. if ( *ppMemory != pBufferStart ) { RpcpMemoryCopy( *ppMemory, pBufferStart, StructSize ); } return 0; } #if defined( DOS ) || defined( WIN ) #pragma code_seg( "NDR20_4" ) #endif unsigned char * RPC_ENTRY NdrConformantVaryingStructUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls a structure which contains a conformant varying array. Used for FC_CVSTRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the structure should be unmarshalled. pFormat - Structure's format string description. fMustAlloc - Ignored. Return : None. --*/ { PFORMAT_STRING pFormatArray; uchar * pBufferStruct; uchar * pBufferArray; uint StructSize, ArrayCopySize, ArrayOffset; ulong AllocationSize; ulong Elements; uchar Alignment; IGNORED(fMustAlloc); // Align the buffer for conformance count unmarshalling. ALIGN(pStubMsg->Buffer,3); // Save structure's alignment. Alignment = pFormat[1]; // Increment format string to struct size field. pFormat += 2; // Get non-conformant struct size and increment format string. StructSize = (ulong) *((ushort *)pFormat)++; // Get conformant varying array's description. pFormatArray = pFormat + *((signed short *)pFormat); AllocationSize = 0; Elements = *((ulong *)pStubMsg->Buffer)++; if ( pStubMsg->fCheckBounds && ! pStubMsg->IsClient ) { if ( *pFormatArray == FC_CVARRAY ) CHECK_BOUND( Elements, pFormatArray[4] & 0x0f ); else if ( pFormatArray[1] == FC_STRING_SIZED ) CHECK_BOUND( Elements, pFormatArray[2] & 0x0f ); } // // For a conformant varying struct we ignore all allocation flags. // Memory must always be allocated on both client and server stubs // if the current memory pointer is null. // if ( ! *ppMemory ) { AllocationSize = StructSize; if ( *pFormatArray == FC_CVARRAY ) { AllocationSize += Elements * *((ushort *)(pFormatArray + 2)); } else // must be a conformant string { if ( *pFormatArray != FC_C_WSTRING ) AllocationSize += Elements; else AllocationSize += Elements * 2; } *ppMemory = (uchar *) NdrAllocate( pStubMsg, (uint) AllocationSize ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // Align on an 8 byte boundary only. if ( Alignment == 7 ) ALIGN(pStubMsg->Buffer,7); // Remember where the structure starts in the buffer. pBufferStruct = pStubMsg->Buffer; // Mark the start of the structure in the buffer. pStubMsg->BufferMark = pStubMsg->Buffer; // Increment past the non-conformant part of the structure. pStubMsg->Buffer += StructSize; // Align again for variance unmarshalling. ALIGN(pStubMsg->Buffer,3); // // Get offset and actual count. Put the actual count into the MaxCount // field of the stub message, where it is used if the array has pointers. // pStubMsg->Offset = ArrayOffset = *((ulong *)pStubMsg->Buffer)++; pStubMsg->MaxCount = ArrayCopySize = *((ulong *)pStubMsg->Buffer)++; if ( pStubMsg->fCheckBounds && ! pStubMsg->IsClient ) { if ( *pFormatArray == FC_CVARRAY ) CHECK_BOUND( ArrayCopySize, pFormatArray[8] & 0x0f ); if ( (ArrayOffset < 0) || (Elements < (ArrayOffset + ArrayCopySize)) ) RpcRaiseException( RPC_X_INVALID_BOUND ); } // Remember where the array starts in the buffer. pBufferArray = pStubMsg->Buffer; if ( *pFormatArray == FC_CVARRAY ) { // Skip to array element size field. pFormatArray += 2; // // Compute the real offset (in bytes) from the beginning of the // array for the copy and the real total number of bytes to copy. // ArrayOffset *= *((ushort *)pFormatArray); ArrayCopySize *= *((ushort *)pFormatArray); } else { // Conformant string. if ( *pFormatArray == FC_C_WSTRING ) { // Double the offset and copy size for wide char string. ArrayOffset *= 2; ArrayCopySize *= 2; } } // Set the stub message Buffer field to the end of the array/string. pStubMsg->Buffer += ArrayCopySize; // Increment format string past offset to array description field. pFormat += 2; // // Unmarshall embedded pointers before copying the struct. // if ( *pFormat == FC_PP ) { NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, (uchar) (AllocationSize != 0) ); } // // Copy the non-conformant part of the structure. // RpcpMemoryCopy( *ppMemory, pBufferStruct, StructSize ); // // Copy the array. Make sure the destination memory pointer is at // the proper offset from the beginning of the array in memory. // RpcpMemoryCopy( *ppMemory + StructSize + ArrayOffset, pBufferArray, ArrayCopySize ); return 0; } #if defined( DOS ) && !defined( WIN ) #pragma code_seg( "NDR20_5" ) #endif unsigned char * RPC_ENTRY NdrHardStructUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls a hard structure. Used for FC_HARD_STRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the structure should be unmarshalled. pFormat - Structure's format string description. fMustAlloc - Ignored. Return : None. --*/ { uchar * pUnion; uchar * pEnum; BOOL fNewMemory; ALIGN(pStubMsg->Buffer,pFormat[1]); pFormat += 2; if ( fNewMemory = (! *ppMemory || fMustAlloc) ) { // // Allocate if forced to, or if we have a union. // if ( fMustAlloc || *((short *)&pFormat[12]) ) *ppMemory = (uchar *) NdrAllocate( pStubMsg, *((ushort *)pFormat) ); else // pStubMsg->ReuseBuffer assumed *ppMemory = pStubMsg->Buffer; } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); pFormat += 8; if ( *ppMemory != pStubMsg->Buffer ) { RpcpMemoryCopy( *ppMemory, pStubMsg->Buffer, *((ushort *)pFormat) ); } // // Zero out the upper two bytes of enums! // if ( *((short *)&pFormat[-2]) != (short) -1 ) { pEnum = *ppMemory + *((ushort *)&pFormat[-2]); *((int *)(pEnum)) = *((int *)pEnum) & ((int)0x7fff) ; } pStubMsg->Buffer += *((ushort *)pFormat)++; // // See if we have a union. // if ( *((short *)&pFormat[2]) ) { pUnion = *ppMemory + *((ushort *)pFormat); if ( fNewMemory ) MIDL_memset( pUnion, 0, *((ushort *)&pFormat[-10]) - *((ushort *)pFormat) ); pFormat += 2; pFormat += *((short *)pFormat); (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormat)])( pStubMsg, &pUnion, pFormat, FALSE ); } return 0; } #if defined( DOS ) || defined( WIN ) #pragma code_seg( "NDR20_4" ) #endif unsigned char * RPC_ENTRY NdrComplexStructUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls a complex structure. Used for FC_BOGUS_STRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the structure should be unmarshalled. pFormat - Structure's format string description. fMustAlloc - Ignored. Return : None. --*/ { uchar * pBuffer; uchar * pBufferMark; uchar * pMemory; PFORMAT_STRING pFormatPointers; PFORMAT_STRING pFormatArray; PFORMAT_STRING pFormatComplex; PFORMAT_STRING pFormatSave; uint StructSize; long Alignment; long Align8Mod; #if defined(__RPC_DOS__) || defined(__RPC_WIN16__) long Align4Mod; #endif BOOL fOldIgnore; BOOL fSetPointerBufferMark; IGNORED(fMustAlloc); pFormatSave = pFormat; StructSize = 0; // Get structure's buffer alignment. Alignment = pFormat[1]; // Increment to the conformat array offset field. pFormat += 4; // Get conformant array description. if ( *((ushort *)pFormat) ) pFormatArray = pFormat + *((signed short *)pFormat); else pFormatArray = 0; pFormat += 2; // Get pointer layout description. if ( *((ushort *)pFormat) ) pFormatPointers = pFormat + *((ushort *)pFormat); else pFormatPointers = 0; pFormat += 2; // // If the stub message PointerBufferMark field is not currently set, then // set it to the end of the flat part of structure in the buffer. // // We do this to handle embedded pointers. // if ( fSetPointerBufferMark = ! pStubMsg->PointerBufferMark ) { pBuffer = pStubMsg->Buffer; // Save field. fOldIgnore = pStubMsg->IgnoreEmbeddedPointers; pStubMsg->IgnoreEmbeddedPointers = TRUE; // Clear MemorySize. pStubMsg->MemorySize = 0; // // Get a buffer pointer to where the struct's pointees will be // unmarshalled from and remember the flat struct size in case we // have to allocate. // StructSize = NdrComplexStructMemorySize( pStubMsg, pFormatSave ); // This is where any pointees begin in the buffer. pStubMsg->PointerBufferMark = pStubMsg->Buffer; pStubMsg->IgnoreEmbeddedPointers = fOldIgnore; pStubMsg->Buffer = pBuffer; } if ( fMustAlloc || ! *ppMemory ) { // // We can only get here if pStubMsg->PointerBufferMark was 0 upon // entry to this proc. // NDR_ASSERT( StructSize ,"Complex struct size is 0" ); *ppMemory = NdrAllocate( pStubMsg, StructSize ); // // Zero out all of the allocated memory so that deeply nested pointers // getted properly zeroed out. // MIDL_memset( *ppMemory, 0, StructSize ); } // Insert the full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // // Now check if there is a conformant array and mark where the conformance // will be unmarshalled from. // if ( pFormatArray ) { ALIGN(pStubMsg->Buffer,3); pBufferMark = pStubMsg->Buffer; // // Increment the buffer pointer 4 bytes for every dimension in the // conformant array. // pStubMsg->Buffer += NdrpArrayDimensions( pFormatArray, FALSE ) * 4; } else pBufferMark = 0; // Align the buffer on the struct's alignment. ALIGN(pStubMsg->Buffer,Alignment); // Get the beginning memory pointer. pMemory = *ppMemory; // // This is used for support of structs with doubles passed on an // i386 stack. The alignment of such struct's is no guaranteed to be on // an 8 byte boundary. Similarly, od 16 bit platforms for 4 byte align. // Align8Mod = (long) pMemory % 8; #if defined(__RPC_DOS__) || defined(__RPC_WIN16__) Align4Mod = (long) pMemory % 4; #endif // // Unmarshall the structure member by member. // for ( ; ; pFormat++ ) { switch ( *pFormat ) { // // simple types // case FC_CHAR : case FC_BYTE : case FC_SMALL : case FC_WCHAR : case FC_SHORT : case FC_LONG : case FC_FLOAT : case FC_HYPER : case FC_DOUBLE : case FC_ENUM16 : case FC_ENUM32 : NdrSimpleTypeUnmarshall( pStubMsg, pMemory, *pFormat ); pMemory += SIMPLE_TYPE_MEMSIZE(*pFormat); break; case FC_IGNORE : ALIGN(pStubMsg->Buffer,3); pStubMsg->Buffer += 4; break; case FC_POINTER : { uchar * pBuffer; ALIGN( pStubMsg->Buffer, 0x3 ); // Remember the current buffer position. pBuffer = pStubMsg->Buffer; // // Set the buffer pointer to where the pointees are being // unmarshalled from in the buffer. // pStubMsg->Buffer = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; NdrpPointerUnmarshall( pStubMsg, (uchar **)pBuffer, *((uchar **)pMemory), pFormatPointers ); // Update. pStubMsg->PointerBufferMark = pStubMsg->Buffer; pStubMsg->Buffer = pBuffer; // // On return from NdrpPointerUnmarshall the proper pointer // value will be in the message buffer. If we're unmarshalling // on the client side and the current memory pointer was valid // then that pointer value will be written into the message // buffer and this copy does nothing new. // *((void **)pMemory) = *((void **)pStubMsg->Buffer)++; pMemory += PTR_MEM_SIZE; pFormatPointers += 4; break; } // // Embedded complex things. // case FC_EMBEDDED_COMPLEX : // Add memory padding. pMemory += pFormat[1]; pFormat += 2; // Get the type's description. pFormatComplex = pFormat + *((signed short UNALIGNED *)pFormat); (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormatComplex)]) ( pStubMsg, (*pFormatComplex == FC_IP) ? (uchar **) pMemory : &pMemory, pFormatComplex, FALSE ); pMemory = NdrpMemoryIncrement( pStubMsg, pMemory, pFormatComplex ); // // 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 : #if defined(__RPC_DOS__) || defined(__RPC_WIN16__) // // We have to play some tricks for the dos and win16 // to handle the case when an 4 byte aligned structure // is passed by value. The alignment of the struct on // the stack is not guaranteed to be on an 4 byte boundary. // pMemory -= Align4Mod; ALIGN( pMemory, 0x3 ); pMemory += Align4Mod; #else ALIGN( pMemory, 0x3 ); #endif 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_PAD : break; // // Done with layout. // case FC_END : goto ComplexUnmarshallEnd; default : NDR_ASSERT(0,"NdrComplexStructUnmarshall : bad format char"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return 0; } } ComplexUnmarshallEnd: // // Unmarshall conformant array if the struct has one. // if ( pFormatArray ) { PPRIVATE_UNMARSHALL_ROUTINE pfnPUnmarshall; switch ( *pFormatArray ) { case FC_CARRAY : pfnPUnmarshall = NdrpConformantArrayUnmarshall; break; case FC_CVARRAY : pfnPUnmarshall = NdrpConformantVaryingArrayUnmarshall; break; case FC_BOGUS_ARRAY : pfnPUnmarshall = NdrpComplexArrayUnmarshall; break; case FC_C_WSTRING : ALIGN( pMemory, 1 ); // fall through // case FC_C_CSTRING : // case FC_C_BSTRING : // case FC_C_SSTRING : default : pfnPUnmarshall = NdrpConformantStringUnmarshall; goto UnmarshallConfArray; } UnmarshallConfArray: // // Unmarshall the conformance count of the outer array dimension for // unidimensional arrays. // pStubMsg->MaxCount = *((ulong *)pBufferMark); // // Mark where conformace counts are in the buffer. // pStubMsg->BufferMark = pBufferMark; // // Unmarshall the array/string. The final flag is the fMustCopy flag, // which must be set. // (*pfnPUnmarshall)( pStubMsg, pMemory, pFormatArray, TRUE ); } // // Now fix up the stub message Buffer field if we set the PointerBufferMark // field. // if ( fSetPointerBufferMark ) { pStubMsg->Buffer = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; } return 0; } #if defined( DOS ) && !defined( WIN ) #pragma code_seg( "NDR20_5" ) #endif unsigned char * RPC_ENTRY NdrNonConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls 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 - Double pointer to the string should be unmarshalled. pFormat - String's format string description. fMustAlloc - Ignored. Return : None. --*/ { ulong Count, AllocSize; IGNORED(fMustAlloc); // Align the buffer. ALIGN(pStubMsg->Buffer,3); // Skip the offset. pStubMsg->Buffer += 4; // Get the count. Count = *((ulong *)pStubMsg->Buffer)++; // Adjust count for wide char strings and stringable structs. switch ( *pFormat ) { case FC_WSTRING : Count *= 2; break; case FC_SSTRING : Count *= pFormat[1]; break; default : break; } // Allocate memory if needed. if ( ! *ppMemory ) { // Get total number of elements. AllocSize = (ulong) *((ushort *)(pFormat + 2)); // Adjust alloc size for wide char strings and stringable structs. switch ( *pFormat ) { case FC_WSTRING : AllocSize *= 2; break; case FC_SSTRING : AllocSize *= pFormat[1]; break; default : break; } *ppMemory = NdrAllocate( pStubMsg, (uint) AllocSize ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); RpcpMemoryCopy( *ppMemory, pStubMsg->Buffer, (uint) Count ); // Update buffer pointer. pStubMsg->Buffer += Count; return 0; } unsigned char * RPC_ENTRY NdrConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls 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. ppMemory - Double pointer to where the string should be unmarshalled. pFormat - String's format string description. fMustAlloc - TRUE if the string must be allocated, FALSE otherwise. Return : None. --*/ { ulong AllocSize; uchar fMustCopy; if ( pStubMsg->fCheckBounds && ! pStubMsg->IsClient ) { uchar * pBuffer; ulong MaxCount, ActualCount, Offset; if ( (pStubMsg->pArrayInfo == 0) && (*pFormat != FC_C_SSTRING) ) { pBuffer = pStubMsg->Buffer; ALIGN( pBuffer, 0x3 ); MaxCount = *((ulong *)pBuffer)++; Offset = *((ulong *)pBuffer)++; ActualCount = *((ulong *)pBuffer)++; if ( pFormat[1] == FC_STRING_SIZED ) CHECK_BOUND( MaxCount, pFormat[2] & 0x0f ); if ( (Offset != 0) || (MaxCount < ActualCount) ) RpcRaiseException( RPC_X_INVALID_BOUND ); if ( *pFormat == FC_C_WSTRING ) MaxCount *= 2; if ( (pBuffer + MaxCount) > pStubMsg->BufferEnd ) RpcRaiseException( RPC_X_INVALID_BOUND ); } } if ( pStubMsg->pArrayInfo != 0 ) { // // If this string is part of a multidimensional array then we // must copy the string from the buffer to new memory. // fMustCopy = TRUE; } else { AllocSize = 0; // Align the buffer for conformance unmarshalling. ALIGN(pStubMsg->Buffer,3); // // Check for a sized string. // if ( ! pStubMsg->IsClient ) { if ( *pFormat != FC_C_SSTRING ) { if ( pFormat[1] == FC_STRING_SIZED ) fMustAlloc = TRUE; } else { if ( pFormat[2] == FC_STRING_SIZED ) fMustAlloc = TRUE; } } // // Initialize the memory pointer if needed. If the string is sized // then we always malloc on the server side. // if ( fMustAlloc ) { // Get the string size. AllocSize = *((ulong *)pStubMsg->Buffer); // Adjust alloc size for wide char strings and stringable structs // and for BSTRs. switch ( *pFormat ) { case FC_C_WSTRING : AllocSize *= 2; break; case FC_C_SSTRING : AllocSize *= pFormat[1]; break; default : break; } *ppMemory = (uchar *) NdrAllocate( pStubMsg, (uint) AllocSize ); } else if ( pStubMsg->ReuseBuffer ) *ppMemory = pStubMsg->Buffer + 12; // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); pStubMsg->Buffer += 4; fMustCopy = (AllocSize != 0); } // Call the private unmarshalling routine to do the work. NdrpConformantStringUnmarshall( pStubMsg, *ppMemory, pFormat, fMustCopy ); return 0; } void NdrpConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat, uchar fMustCopy ) /*++ Routine description : Private routine for unmarshalling a conformant string. This is the entry point for unmarshalling 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 where the string should be unmarshalled. pFormat - String's format string description. fMustCopy - TRUE if the string must be copied from the buffer to memory, FALSE otherwise. Return : None. --*/ { ulong Count; // Align for variance unmarshalling. ALIGN(pStubMsg->Buffer,3); // Get a buffer pointer to the string count - skip the offset. pStubMsg->Buffer += 4; // Unmarshall the string count. Count = *((ulong *)pStubMsg->Buffer)++; // Adjust the count for a wide strings and stringable structs. // This is good enough for BSTRs as the mem pointer has already moved. switch ( *pFormat ) { case FC_C_WSTRING : Count *= 2; break; case FC_C_SSTRING : Count *= pFormat[1]; break; default : break; } // Copy the string if needed. if ( pStubMsg->IsClient || fMustCopy ) { RpcpMemoryCopy( pMemory, pStubMsg->Buffer, (uint) Count ); } // Update buffer pointer. pStubMsg->Buffer += Count; } unsigned char * RPC_ENTRY NdrFixedArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a fixed array of any number of dimensions. Used for FC_SMFARRAY and FC_LGFARRAY. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to the array to unmarshall. pFormat - Array's format string description. fMustAlloc - TRUE if the array must be allocated, FALSE otherwise. Return : None. --*/ { uchar * pBufferStart; ulong Size; ALIGN(pStubMsg->Buffer,pFormat[1]); // Get the total array size. if ( *pFormat == FC_SMFARRAY ) { pFormat += 2; Size = (ulong) *((ushort *)pFormat)++; } else // *pFormat++ == FC_LGFARRAY { pFormat += 2; Size = *((ulong UNALIGNED *)pFormat)++; } pBufferStart = pStubMsg->Buffer; // Set stub message buffer pointer past array. pStubMsg->Buffer += Size; // Initialize the memory pointer if necessary. if ( fMustAlloc ) *ppMemory = NdrAllocate( pStubMsg, (uint) Size ); else if ( pStubMsg->ReuseBuffer && ! *ppMemory ) *ppMemory = pBufferStart; // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // Unmarshall embedded pointers. if ( *pFormat == FC_PP ) { // Mark the beginning of the array in the buffer. pStubMsg->BufferMark = pBufferStart; NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, fMustAlloc ); } // Copy the array if we're not using the rpc buffer to hold it. if ( *ppMemory != pBufferStart ) { RpcpMemoryCopy( *ppMemory, pBufferStart, (uint) Size ); } return 0; } unsigned char * RPC_ENTRY NdrConformantArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a top level one dimensional conformant array. Used for FC_CARRAY. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to array to be unmarshalled. pFormat - Array's format string description. Return : None. --*/ { ulong AllocSize; // Align the buffer for conformance unmarshalling. ALIGN(pStubMsg->Buffer,3); // Unmarshall the conformance count. pStubMsg->MaxCount = *((ulong *)pStubMsg->Buffer)++; if ( pStubMsg->fCheckBounds && ! pStubMsg->IsClient ) { ulong Size; CHECK_BOUND( pStubMsg->MaxCount, pFormat[4] & 0x0f ); Size = pStubMsg->MaxCount * *((ushort *)(pFormat + 2)); if ( (pStubMsg->Buffer + Size) > pStubMsg->BufferEnd ) RpcRaiseException( RPC_X_INVALID_BOUND ); } AllocSize = 0; // Initialize the memory pointer if necessary. if ( fMustAlloc ) { // Compute total array size in bytes. AllocSize = pStubMsg->MaxCount * *((ushort *)(pFormat + 2)); *ppMemory = NdrAllocate( pStubMsg, (uint) AllocSize ); } else if ( pStubMsg->ReuseBuffer && ! *ppMemory ) { *ppMemory = pStubMsg->Buffer; // // Align memory pointer on an 8 byte boundary if needed. // We can't align the buffer pointer because we haven't made // the check for size_is == 0 yet. // if ( pFormat[1] == 7 ) ALIGN(*ppMemory,7); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); NdrpConformantArrayUnmarshall( pStubMsg, *ppMemory, pFormat, (uchar) (AllocSize != 0) ); return 0; } void NdrpConformantArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat, uchar fMustCopy ) /*++ Routine Description : Private routine for unmarshalling a one dimensional conformant array. This is the entry point for unmarshalling an embedded conformant array. Used for FC_CARRAY. Arguments : pStubMsg - Pointer to the stub message. pMemory - Array being unmarshalled. pFormat - Array's format string description. Return : None. --*/ { uchar * pBufferStart; ulong CopySize; // Return if array size is 0 so that we don't align the buffer. if ( ! pStubMsg->MaxCount ) return; ALIGN(pStubMsg->Buffer,pFormat[1]); // Compute total array size in bytes. CopySize = pStubMsg->MaxCount * *((ushort *)(pFormat + 2)); pBufferStart = pStubMsg->Buffer; pStubMsg->Buffer += CopySize; // Increment the format string pointer to possible pointer layout. pFormat += 8; // Unmarshall embedded pointers. if ( *pFormat == FC_PP ) { // Mark the beginning of the array in the buffer. pStubMsg->BufferMark = pBufferStart; NdrpEmbeddedPointerUnmarshall( pStubMsg, pMemory, pFormat, fMustCopy ); } // Copy the array if we're not using the rpc message buffer for it. if ( pStubMsg->IsClient || fMustCopy ) { RpcpMemoryCopy( pMemory, pBufferStart, (uint) CopySize ); } } #if defined( DOS ) && !defined( WIN ) #pragma code_seg() #endif unsigned char * RPC_ENTRY NdrConformantVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a top level one dimensional conformant varying array. Used for FC_CVARRAY. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to the array being unmarshalled. pFormat - Array's format string description. fMustAlloc - Ignored. Return : None. --*/ { ulong AllocSize; IGNORED(fMustAlloc); // Align the buffer for conformance unmarshalling. ALIGN(pStubMsg->Buffer,3); // Unmarshall the conformance size. pStubMsg->MaxCount = *((ulong *)pStubMsg->Buffer)++; if ( pStubMsg->fCheckBounds && ! pStubMsg->IsClient ) { ulong Size; ulong Offset, ActualCount; CHECK_BOUND( pStubMsg->MaxCount, pFormat[4] & 0x0f ); Offset = *((ulong *)pStubMsg->Buffer); ActualCount = *((ulong *)(pStubMsg->Buffer + 4)); CHECK_BOUND( ActualCount, pFormat[8] & 0x0f ); Size = ActualCount * *((ushort *)(pFormat + 2)); if ( ((long)Offset < 0) || (pStubMsg->MaxCount < (Offset + ActualCount)) ) RpcRaiseException( RPC_X_INVALID_BOUND ); if ( (pStubMsg->Buffer + 8 + Size) > pStubMsg->BufferEnd ) RpcRaiseException( RPC_X_INVALID_BOUND ); } AllocSize = 0; // // For a conformant varying array, we can't reuse the buffer // because it doesn't hold the total size of the array. So // allocate if the current memory pointer is 0. // if ( ! *ppMemory ) { AllocSize = pStubMsg->MaxCount * *((ushort *)(pFormat + 2)); *ppMemory = NdrAllocate( pStubMsg, (uint) AllocSize ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); NdrpConformantVaryingArrayUnmarshall( pStubMsg, *ppMemory, pFormat, (uchar) (AllocSize != 0) ); return 0; } #if defined( DOS ) || defined( WIN ) #pragma code_seg( "NDR20_4" ) #endif void NdrpConformantVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat, uchar fMustCopy ) /*++ Routine Description : Private routine for unmarshalling a one dimensional conformant varying array. This is the entry point for unmarshalling an embedded conformant varying array. Used for FC_CVARRAY. Arguments : pStubMsg - Pointer to the stub message. pMemory - Array being unmarshalled. pFormat - Array's format string description. fMustCopy - Ignored. Return : None. --*/ { uchar * pBufferStart; ulong CopyOffset, CopySize; ushort ElemSize; IGNORED(fMustCopy); // Align the buffer for conformance unmarshalling. ALIGN(pStubMsg->Buffer,3); // Unmarshall offset and actual count. pStubMsg->Offset = *((ulong *)pStubMsg->Buffer)++; pStubMsg->ActualCount = *((ulong *)pStubMsg->Buffer)++; // // Return if length is 0. // if ( ! pStubMsg->ActualCount ) return; ElemSize = *((ushort *)(pFormat + 2)); CopyOffset = pStubMsg->Offset * ElemSize; CopySize = pStubMsg->ActualCount * ElemSize; // Align buffer if needed on 8 byte boundary. if ( pFormat[1] == 7 ) ALIGN(pStubMsg->Buffer,7); pBufferStart = pStubMsg->Buffer; // Increment buffer pointer past array. pStubMsg->Buffer += CopySize; // Increment format string to possible pointer description. pFormat += 12; // Unmarshall embedded pointers first. if ( *pFormat == FC_PP ) { // // Set the MaxCount field equal to the variance count. // The pointer unmarshalling routine uses the MaxCount field // to determine the number of times an FC_VARIABLE_REPEAT // pointer is unmarshalled. In the face of variance the // correct number of time is the actual count, not MaxCount. // pStubMsg->MaxCount = pStubMsg->ActualCount; // // Mark the location of the first transmitted array element in // the buffer. // pStubMsg->BufferMark = pBufferStart; NdrpEmbeddedPointerUnmarshall( pStubMsg, pMemory, pFormat, fMustCopy ); } // Always copy. Buffer reuse is not possible. RpcpMemoryCopy( pMemory + CopyOffset, pBufferStart, (uint) CopySize ); } #if defined( DOS ) || defined( WIN ) #pragma code_seg( "NDR20_4" ) #endif unsigned char * RPC_ENTRY NdrVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls top level or embedded a one dimensional varying array. Used for FC_SMVARRAY and FC_LGVARRAY. Arguments : pStubMsg - Pointer to the stub message. pMemory - Array being unmarshalled. pFormat - Array's format string description. fMustAlloc - Ignored. --*/ { uchar * pBufferStart; ulong TotalSize; ulong Offset, Count; ulong CopyOffset, CopySize; ushort ElemSize; uchar fNewMemory; // Align the buffer for variance unmarshalling. ALIGN(pStubMsg->Buffer,3); Offset = *((ulong *)pStubMsg->Buffer)++; Count = *((ulong *)pStubMsg->Buffer)++; if ( ! Count ) return 0; if ( pStubMsg->fCheckBounds && ! pStubMsg->IsClient ) { long Elements; CHECK_BOUND( Count, pFormat[(*pFormat == FC_SMVARRAY) ? 8 : 12] & 0x0f ); Elements = (*pFormat == FC_SMVARRAY) ? *((ushort *)(pFormat + 4)) : *((ulong UNALIGNED *)(pFormat + 6)); if ( ((long)Offset < 0 ) || (Elements < (long)(Count + Offset)) ) RpcRaiseException( RPC_X_INVALID_BOUND ); } // Align the buffer if needed on an 8 byte boundary. if ( pFormat[1] == 7 ) ALIGN(pStubMsg->Buffer,7); // Get array's total size and increment to element size field. if ( *pFormat == FC_SMVARRAY ) { TotalSize = (ulong) *((ushort *)(pFormat + 2)); pFormat += 6; } else { TotalSize = *((ulong UNALIGNED *)(pFormat + 2)); pFormat += 10; } if ( fNewMemory = ! *ppMemory ) { *ppMemory = NdrAllocate( pStubMsg, (uint) TotalSize ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); ElemSize = *((ushort *)pFormat); CopyOffset = Offset * ElemSize; CopySize = Count * ElemSize; pBufferStart = pStubMsg->Buffer; pStubMsg->Buffer += CopySize; // Increment format string to possible pointer description. pFormat += 6; // Unmarshall embedded pointers. if ( *pFormat == FC_PP ) { // // Set the MaxCount field equal to the variance count. // The pointer unmarshalling routine uses the MaxCount field // to determine the number of times an FC_VARIABLE_REPEAT // pointer is unmarshalled. In the face of variance the // correct number of time is the actual count, not MaxCount. // pStubMsg->MaxCount = Count; // // Mark the location of the first transmitted array element in // the buffer // pStubMsg->BufferMark = pBufferStart; NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, fNewMemory ); } RpcpMemoryCopy( *ppMemory + CopyOffset, pBufferStart, (uint) CopySize ); return 0; } unsigned char * RPC_ENTRY NdrComplexArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a top level complex array. Used for FC_BOGUS_STRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to the array being unmarshalled. pFormat - Array's format string description. fMustAlloc - Ignored. Return : None. --*/ { uchar * pBuffer; long ArraySize; BOOL fSetPointerBufferMark; ArraySize = 0; // // Setting this flag means that the array is not embedded inside of // another complex struct or array. // fSetPointerBufferMark = ! pStubMsg->PointerBufferMark; if ( fSetPointerBufferMark ) { BOOL fOldIgnore; pBuffer = pStubMsg->Buffer; fOldIgnore = pStubMsg->IgnoreEmbeddedPointers; pStubMsg->IgnoreEmbeddedPointers = TRUE; pStubMsg->MemorySize = 0; // // Get a buffer pointer to where the arrays's pointees will be // unmarshalled from and remember the array size in case we // have to allocate. // ArraySize = NdrComplexArrayMemorySize( pStubMsg, pFormat ); // // PointerBufferaMark is where the pointees begin in the buffer. // If this is an array of ref pointers then we don't want to set // this, all we wanted was the array size. // if ( pFormat[12] != FC_RP ) pStubMsg->PointerBufferMark = pStubMsg->Buffer; else fSetPointerBufferMark = FALSE; pStubMsg->IgnoreEmbeddedPointers = fOldIgnore; pStubMsg->Buffer = pBuffer; } if ( fMustAlloc || ! *ppMemory ) { *ppMemory = NdrAllocate( pStubMsg, (uint) ArraySize ); // // Zero out the memory of the array if we allocated it, to insure // that all embedded pointers are zeroed out. Blech. // MIDL_memset( *ppMemory, 0, (uint) ArraySize ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // // Check for a conformance description. // if ( ( *((long UNALIGNED *)(pFormat + 4)) != 0xffffffff ) && ( pStubMsg->pArrayInfo == 0 ) ) { // // The outer most array dimension sets the conformance marker. // ALIGN(pStubMsg->Buffer,0x3); // Mark where the conformance count(s) will be unmarshalled from. pStubMsg->BufferMark = pStubMsg->Buffer; // Increment past conformance count(s). pStubMsg->Buffer += NdrpArrayDimensions( pFormat, FALSE ) * 4; } NdrpComplexArrayUnmarshall( pStubMsg, *ppMemory, pFormat, TRUE ); 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; } #if defined( DOS ) && !defined( WIN ) #pragma code_seg( "NDR20_5" ) #endif void NdrpComplexArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat, uchar fMustCopy ) /*++ Routine Description : Private routine for unmarshalling a complex array. This is the entry point for unmarshalling an embedded complex array. Used for FC_BOGUS_ARRAY. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to the array being unmarshalled. pFormat - Array's format string description. fMustCopy - Ignored. Return : None. --*/ { ARRAY_INFO ArrayInfo; PARRAY_INFO pArrayInfo; PUNMARSHALL_ROUTINE pfnUnmarshall; PFORMAT_STRING pFormatSave; ulong Elements; ulong Offset, Count; ulong MemoryElementSize; long Dimension; uchar Alignment; // // 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 ) { pStubMsg->pArrayInfo = &ArrayInfo; ArrayInfo.Dimension = 0; ArrayInfo.BufferConformanceMark = (unsigned long *)pStubMsg->BufferMark; ArrayInfo.BufferVarianceMark = 0; } pFormatSave = pFormat; pArrayInfo = pStubMsg->pArrayInfo; Dimension = pArrayInfo->Dimension; Alignment = pFormat[1]; pFormat += 2; // This is 0 if the array has conformance. Elements = *((ushort *)pFormat)++; // // Check for conformance description. // if ( *((long UNALIGNED *)pFormat) != 0xffffffff ) { Elements = pArrayInfo->BufferConformanceMark[Dimension]; } pFormat += 4; // // Check for variance description. // if ( *((long UNALIGNED *)pFormat) != 0xffffffff ) { if ( Dimension == 0 ) { ALIGN(pStubMsg->Buffer,0x3); // Mark where the variance counts are. pArrayInfo->BufferVarianceMark = (unsigned long *)pStubMsg->Buffer; // Handle multidimensional arrays. pStubMsg->Buffer += NdrpArrayDimensions( pFormatSave, TRUE ) * 8; } Offset = pArrayInfo->BufferVarianceMark[Dimension * 2]; Count = pArrayInfo->BufferVarianceMark[(Dimension * 2) + 1]; } else { Offset = 0; Count = Elements; } pFormat += 4; if ( ! Count ) goto ComplexArrayUnmarshallEnd; ALIGN(pStubMsg->Buffer,Alignment); switch ( *pFormat ) { case FC_EMBEDDED_COMPLEX : pFormat += 2; pFormat += *((signed short *)pFormat); pfnUnmarshall = pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormat)]; pArrayInfo->Dimension = Dimension + 1; pArrayInfo->MaxCountArray = pArrayInfo->BufferConformanceMark; MemoryElementSize = NdrpMemoryIncrement( pStubMsg, pMemory, pFormat ) - pMemory; pArrayInfo->MaxCountArray = 0; break; case FC_RP : case FC_UP : case FC_FP : case FC_OP : pfnUnmarshall = (PUNMARSHALL_ROUTINE) NdrpPointerUnmarshall; // Need this in case we have a variant offset. MemoryElementSize = PTR_MEM_SIZE; break; case FC_IP : pfnUnmarshall = NdrInterfacePointerUnmarshall; // Need this in case we have a variant offset. MemoryElementSize = PTR_MEM_SIZE; break; case FC_ENUM16 : pfnUnmarshall = 0; MemoryElementSize = sizeof(int); break; default : NDR_ASSERT( IS_SIMPLE_TYPE(*pFormat), "NdrpComplexArrayUnmarshall : bad format char" ); Count *= SIMPLE_TYPE_BUFSIZE(*pFormat); pMemory += Offset * SIMPLE_TYPE_MEMSIZE(*pFormat); RpcpMemoryCopy( pMemory, pStubMsg->Buffer, (uint) Count ); pStubMsg->Buffer += Count; goto ComplexArrayUnmarshallEnd; } // // If there is variance then increment the memory pointer to the first // element actually being marshalled. // if ( Offset ) pMemory += Offset * MemoryElementSize; // // Check for an array of enum16. // if ( ! pfnUnmarshall ) { for ( ; Count--; ) { // Cast to ushort since we don't want to sign extend. *((int *)pMemory)++ = (int) *((ushort *)pStubMsg->Buffer)++; } goto ComplexArrayUnmarshallEnd; } // // Array of pointers. // if ( (pfnUnmarshall == (PUNMARSHALL_ROUTINE) NdrpPointerUnmarshall) || (pfnUnmarshall == NdrInterfacePointerUnmarshall) ) { uchar * pBuffer; pStubMsg->pArrayInfo = 0; // // If this field is set then we are embedded inside of another complex // array or a complex struct. Set the buffer pointer to where the // pointees are begin unmarshalled from. // if ( pStubMsg->PointerBufferMark ) { pBuffer = pStubMsg->Buffer; pStubMsg->Buffer = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; } else pBuffer = 0; if ( pfnUnmarshall == (PUNMARSHALL_ROUTINE) NdrpPointerUnmarshall ) { for ( ; Count--; ) { // // We pass in where we want the pointer unmarshalled into // and the current memory pointer. // NdrpPointerUnmarshall( pStubMsg, (uchar **)pMemory, *((uchar **)pMemory), pFormat ); pMemory += PTR_MEM_SIZE; } } else { for ( ; Count--; ) { NdrInterfacePointerUnmarshall( pStubMsg, ((uchar **)pMemory)++, pFormat, FALSE ); } } if ( pBuffer ) { // Record new pointee buffer position. pStubMsg->PointerBufferMark = pStubMsg->Buffer; pStubMsg->Buffer = pBuffer; } goto ComplexArrayUnmarshallEnd; } // // Unmarshall the complex array elements. // if ( ! IS_ARRAY_OR_STRING(*pFormat) ) pStubMsg->pArrayInfo = 0; for ( ; Count--; ) { // Keep track of multidimensional array dimension. if ( IS_ARRAY_OR_STRING(*pFormat) ) pArrayInfo->Dimension = Dimension + 1; (*pfnUnmarshall)( pStubMsg, &pMemory, pFormat, FALSE ); // Increment the memory pointer by the element size. pMemory += MemoryElementSize; } ComplexArrayUnmarshallEnd: // pArrayInfo must be zero when not valid. pStubMsg->pArrayInfo = (Dimension == 0) ? 0 : pArrayInfo; } #if defined( DOS ) && !defined( WIN ) #pragma code_seg() #endif unsigned char * RPC_ENTRY NdrEncapsulatedUnionUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls an encapsulated array. Used for FC_ENCAPSULATED_UNION. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the union should be unmarshalled. pFormat - Union's format string description. fMustAlloc - Ignored. Return : None. --*/ { uchar * pBuffer; uchar * pUnion; uchar SwitchType; IGNORED(fMustAlloc); // // Since we can never use the buffer to hold a union we simply have // to check the current memory pointer to see if memory must be allocated. // // The memory size of an encapsulated union is the union size plus // the memory needed for the switch_is member (including any padding // for alignment). // if ( ! *ppMemory ) { uint Size; Size = *((ushort *)(pFormat + 2)) + HIGH_NIBBLE(pFormat[1]); *ppMemory = NdrAllocate( pStubMsg, Size ); // // We must zero out all of the new memory in case there are pointers // in any of the arms. // MIDL_memset( *ppMemory, 0, Size ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); SwitchType = LOW_NIBBLE(pFormat[1]); pBuffer = pStubMsg->Buffer; // // Unmarshall the switch_is field into memory. // NdrSimpleTypeUnmarshall( pStubMsg, *ppMemory, SwitchType ); // // The above call incremented the buffer pointer. Set it back to before // the switch is value in the buffer. // pStubMsg->Buffer = pBuffer; // Get a memory pointer to the union. pUnion = *ppMemory + HIGH_NIBBLE(pFormat[1]); NdrpUnionUnmarshall( pStubMsg, &pUnion, pFormat + 2, SwitchType ); return 0; } unsigned char * RPC_ENTRY NdrNonEncapsulatedUnionUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a non encapsulated array. Used for FC_NON_ENCAPSULATED_UNION. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the union should be unmarshalled. pFormat - Union's format string description. fMustAlloc - Ignored. Return : None. --*/ { uchar SwitchType; IGNORED(fMustAlloc); SwitchType = pFormat[1]; // // Get the memory size and arm description part of the format string // description. // pFormat += 6; pFormat += *((signed short *)pFormat); // // Since we can never use the buffer to hold a union we simply have // to check the current memory pointer to see if memory must be allocated. // if ( fMustAlloc || ! *ppMemory ) { uint Size; Size = *((ushort *)pFormat); *ppMemory = NdrAllocate( pStubMsg, Size ); // // We must zero out all of the new memory in case there are pointers // in any of the arms. // MIDL_memset( *ppMemory, 0, Size ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); NdrpUnionUnmarshall( pStubMsg, ppMemory, pFormat, SwitchType ); return 0; } #if defined( DOS ) && !defined( WIN ) #pragma code_seg( "NDR20_5" ) #endif void NdrpUnionUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar SwitchType ) /*++ Routine description : Private routine for unmarshalling a union. This routine is shared for both encapsulated and non-encapsulated unions and handles the actual unmarshalling of the proper union arm. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the union should be unmarshalled. pFormat - Union's format string description. SwitchType - Union's switch type. Return : None. --*/ { long SwitchIs; long Arms; uchar Alignment; // // Unmarshall the switch is. We have to do it inline here so that a // switch_is which is negative will be properly sign extended. // switch ( SwitchType ) { case FC_SMALL : case FC_CHAR : SwitchIs = (long) *((char *)pStubMsg->Buffer)++; break; case FC_USMALL : SwitchIs = (long) *((uchar *)pStubMsg->Buffer)++; break; case FC_SHORT : case FC_ENUM16 : ALIGN(pStubMsg->Buffer,1); SwitchIs = (long) *((short *)pStubMsg->Buffer)++; break; case FC_USHORT : case FC_WCHAR : ALIGN(pStubMsg->Buffer,1); SwitchIs = (long) *((ushort *)pStubMsg->Buffer)++; break; case FC_LONG : case FC_ULONG : case FC_ENUM32 : ALIGN(pStubMsg->Buffer,3); SwitchIs = *((long *)pStubMsg->Buffer)++; break; default : NDR_ASSERT(0,"NdrpUnionUnmarshall : Illegal union switch_type"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return; } // 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). Get your gun. // Alignment = (uchar) ( *((ushort *)pFormat) >> 12 ); ALIGN(pStubMsg->Buffer,Alignment); // // Number of arms is the lower 12 bits. Ok shoot me. // Arms = (long) ( *((ushort *)pFormat)++ & 0x0fff); // // Search for union 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) ) { NdrSimpleTypeUnmarshall( pStubMsg, *ppMemory, #if defined(__RPC_MAC__) pFormat[1] ); #else pFormat[0] ); #endif return; } pFormat += *((signed short *)pFormat); // // Determine the double memory pointer that we pass to the arm's // unmarshalling routine. // If the union arm we take is a pointer, we have to dereference the // current memory pointer since we're passed the pointer to 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) ) { ppMemory = (uchar **) *ppMemory; } // // Non-interface pointer only. // if ( IS_BASIC_POINTER(*pFormat) ) { // // If we're embedded in a struct or array we have do some extra stuff. // if ( pStubMsg->PointerBufferMark ) { uchar * pBufferSave; pBufferSave = pStubMsg->Buffer; // We have to align pBufferSave as well. ALIGN(pBufferSave,3); pStubMsg->Buffer = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; // // We must call the private pointer unmarshalling routine. // It expects a pointer to the pointer in the buffer and the // current value of the memory pointer. // NdrpPointerUnmarshall( pStubMsg, (uchar **)pBufferSave, *((uchar **)ppMemory), pFormat ); // // On return from NdrpPointerUnmarshall the proper pointer // value will be in the message buffer. If we're unmarshalling // on the client side and the current memory pointer was valid // then that pointer value will be written into the message // buffer and this copy does nothing new. // *ppMemory = *((uchar **)pBufferSave); pStubMsg->PointerBufferMark = pStubMsg->Buffer; // Increment past the pointer in the buffer. pStubMsg->Buffer = pBufferSave + 4; return; } } // // Union arm of a non-simple type. // (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormat)]) ( pStubMsg, ppMemory, pFormat, FALSE ); } #if defined( DOS ) && !defined( WIN ) #pragma code_seg() #endif unsigned char * RPC_ENTRY NdrByteCountPointerUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a pointer with the byte count attribute applied to it. Used for FC_BYTE_COUNT_POINTER. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the byte count pointer should be unmarshalled. pFormat - Byte count pointer's format string description. fMustAlloc - Ignored. Return : None. --*/ { PFORMAT_STRING pFormatComplex; long ByteCount; long DataSize; ByteCount = NdrpComputeConformance( pStubMsg, NULL, pFormat ); pFormatComplex = pFormat + 6; pFormatComplex += *((signed short *)pFormatComplex); // // Determine incoming data size. // if ( pFormat[1] != FC_PAD ) { DataSize = SIMPLE_TYPE_MEMSIZE(pFormat[1]); } else { uchar * pBuffer; pBuffer = pStubMsg->Buffer; pStubMsg->MemorySize = 0; // // This will give us the allocate(all_nodes) size of the data. // DataSize = (*pfnMemSizeRoutines[ROUTINE_INDEX(*pFormatComplex)]) ( pStubMsg, pFormatComplex ); pStubMsg->Buffer = pBuffer; } if ( DataSize > ByteCount ) RpcRaiseException( RPC_X_BYTE_COUNT_TOO_SMALL ); // // Now make things look like we're handling an allocate all nodes. // pStubMsg->AllocAllNodesMemory = *ppMemory; pStubMsg->AllocAllNodesMemoryEnd = *ppMemory + ByteCount; // // Now unmarshall. // if ( pFormat[1] != FC_PAD ) { NdrSimpleTypeUnmarshall( pStubMsg, *ppMemory, pFormat[1] ); } else { (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormatComplex)]) ( pStubMsg, ppMemory, pFormatComplex, TRUE ); } pStubMsg->AllocAllNodesMemory = 0; return 0; } #if defined(__RPC_DOS__) || defined(__RPC_WIN16__) #pragma optimize( "", off ) #endif unsigned char * RPC_ENTRY NdrpXmitOrRepAsPtrUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a transmit as (or represent as) object given by pointers. (FC_TRANSMIT_AS_PTR or FC_REPRESENT_AS_PTR) See NdrXmitOrRepAsUnmarshall for more detals. Arguments : pStubMsg - a pointer to the stub message ppMemory - pointer to the presented type where to put data pFormat - format string description fMustAlloc - allocate flag Note. fMustAlloc is ignored as we always allocate outside of the buffer. --*/ { unsigned char * pTransmittedType; BOOL fMustFreeXmit = FALSE; const XMIT_ROUTINE_QUINTUPLE * pQuintuple = pStubMsg->StubDesc->aXmitQuintuple; unsigned short QIndex; unsigned long PresentedTypeSize; uchar * PointerBufferMarkSave; void * XmitTypePtr = 0; (void) fMustAlloc; // Fetch the QuintupleIndex. QIndex = *(unsigned short *)(pFormat + 2); PresentedTypeSize = *(unsigned short *)(pFormat + 4); // Allocate the transmitted object outside of the buffer // and unmarshall into it pFormat += 8; pFormat = pFormat + *(short *)pFormat; // // Clear PointerBufferMark in case it's currently set, which may // result in a 0 size allocation. // PointerBufferMarkSave = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; pTransmittedType = NULL; // asking the engine to allocate // only when ptr is ref: make it look like UP. if ( *pFormat == FC_RP ) pTransmittedType = (char *)& XmitTypePtr; (*pfnUnmarshallRoutines[ ROUTINE_INDEX( *pFormat )]) ( pStubMsg, & pTransmittedType, pFormat, TRUE ); pStubMsg->PointerBufferMark = PointerBufferMarkSave; // Translate from the transmitted type into the presented type. pStubMsg->pTransmitType = (char *)& pTransmittedType; pStubMsg->pPresentedType = *ppMemory; if ( ! pStubMsg->pPresentedType ) { // Allocate a presented type object first. pStubMsg->pPresentedType = (unsigned char *) NdrAllocate( pStubMsg, (uint) PresentedTypeSize ); MIDL_memset( pStubMsg->pPresentedType, 0, (uint) PresentedTypeSize ); } pQuintuple[ QIndex ].pfnTranslateFromXmit( pStubMsg ); *ppMemory = pStubMsg->pPresentedType; // Free the transmitted object (it was allocated by the engine) // and its pointees. The call through the table frees the pointees // plus it frees the object itself as it is a pointer. (*pfnFreeRoutines[ ROUTINE_INDEX( *pFormat )])( pStubMsg, pTransmittedType, pFormat ); return 0; } unsigned char * RPC_ENTRY NdrXmitOrRepAsUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a transmit as (or represent as)object. Means: allocate the transmitted object, unmarshall transmitted object, translate the transmitted into presented free the transmitted. See mrshl.c for the description of the FC layout. Arguments : pStubMsg - a pointer to the stub message ppMemory - pointer to the presented type where to put data pFormat - format string description fMustAlloc - allocate flag Note. fMustAlloc is ignored as we always allocate outside of the buffer. --*/ { unsigned char * pTransmittedType; char SimpleTypeValueBuffer[16]; BOOL fMustFreeXmit = FALSE; const XMIT_ROUTINE_QUINTUPLE * pQuintuple = pStubMsg->StubDesc->aXmitQuintuple; unsigned short QIndex; unsigned long PresentedTypeSize; uchar * PointerBufferMarkSave; BOOL fXmitByPtr = *pFormat == FC_TRANSMIT_AS_PTR || *pFormat == FC_REPRESENT_AS_PTR; (void) fMustAlloc; if ( fXmitByPtr ) { NdrpXmitOrRepAsPtrUnmarshall( pStubMsg, ppMemory, pFormat, fMustAlloc ); return 0; } // Fetch the QuintupleIndex. QIndex = *(unsigned short *)(pFormat + 2); PresentedTypeSize = *(unsigned short *)(pFormat + 4); // Allocate the transmitted object outside of the buffer // and unmarshall into it pFormat += 8; pFormat = pFormat + *(short *)pFormat; if ( IS_SIMPLE_TYPE( *pFormat )) { pTransmittedType = SimpleTypeValueBuffer; NdrSimpleTypeUnmarshall( pStubMsg, pTransmittedType, *pFormat ); } else { // // Clear PointerBufferMark in case it's currently set, which may // result in a 0 size allocation. // PointerBufferMarkSave = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; pTransmittedType = NULL; // asking the engine to allocate (*pfnUnmarshallRoutines[ ROUTINE_INDEX( *pFormat )]) ( pStubMsg, & pTransmittedType, pFormat, TRUE ); fMustFreeXmit = TRUE; pStubMsg->PointerBufferMark = PointerBufferMarkSave; } // Translate from the transmitted type into the presented type. pStubMsg->pTransmitType = pTransmittedType; pStubMsg->pPresentedType = *ppMemory; if ( ! pStubMsg->pPresentedType ) { // Allocate a presented type object first. pStubMsg->pPresentedType = (unsigned char *) NdrAllocate( pStubMsg, (uint) PresentedTypeSize ); MIDL_memset( pStubMsg->pPresentedType, 0, (uint) PresentedTypeSize ); } pQuintuple[ QIndex ].pfnTranslateFromXmit( pStubMsg ); *ppMemory = pStubMsg->pPresentedType; if ( fMustFreeXmit ) { // Free the transmitted object (it was allocated by the engine) // and its pointees. The call through the table frees the pointees // only (plus it'd free the object itself if it were a pointer). // As the transmitted type is not a pointer here, we need to free it // explicitely later. PFREE_ROUTINE pfnTableFree = *pfnFreeRoutines[ ROUTINE_INDEX(*pFormat)]; // Objects that don't embed pointers don't have a free routine. if ( *pfnTableFree ) (*pfnTableFree)( pStubMsg, pTransmittedType, pFormat ); // The buffer reusage check. if ( pTransmittedType < pStubMsg->BufferStart || pTransmittedType > pStubMsg->BufferEnd ) (*pStubMsg->pfnFree)( pTransmittedType ); } return 0; } #if defined(__RPC_DOS__) || defined(__RPC_WIN16__) #pragma optimize( "", on ) #endif unsigned char * RPC_ENTRY NdrUserMarshalUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshals a user_marshal object. The layout is described in marshalling. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to pointer to the usr_marshall object to unmarshall. pFormat - Object's format string description. Return : None. --*/ { const USER_MARSHAL_ROUTINE_QUADRUPLE * pQuadruple; unsigned short QIndex; unsigned long PointerMarker; unsigned char * pUserBuffer; USER_MARSHAL_CB UserMarshalCB; // Align for the object or a pointer to it. ALIGN( pStubMsg->Buffer, LOW_NIBBLE(pFormat[1]) ); // Take care of the pointer, if any. if ( (pFormat[1] & USER_MARSHAL_UNIQUE) || ((pFormat[1] & USER_MARSHAL_REF) && pStubMsg->PointerBufferMark) ) { PointerMarker = *((unsigned long *)pStubMsg->Buffer)++; } // We always call user's routine to unmarshall the user object. // However, the top level object is allocated by the engine. // Thus, the behavior is exactly the same as for represent_as(), // with regard to the top level presented type. if ( *ppMemory == NULL ) { // Allocate a presented type object first. uint MemSize = *(ushort *)(pFormat + 4); *ppMemory = (uchar *) NdrAllocate( pStubMsg, MemSize ); MIDL_memset( *ppMemory, 0, MemSize ); } if ( (pFormat[1] & USER_MARSHAL_UNIQUE) && (0 == PointerMarker )) { // The user type is a unique pointer, and it is 0. So, we are done. return(0); } // Check if the object is embedded to know where to get it from. if ( (pFormat[1] & USER_MARSHAL_POINTER) && pStubMsg->PointerBufferMark ) { // Embedded: User object among pointees. pUserBuffer = pStubMsg->PointerBufferMark; } else pUserBuffer = pStubMsg->Buffer; UserMarshalCB.pStubMsg = pStubMsg; if ( pFormat[1] & USER_MARSHAL_IID ) { UserMarshalCB.pReserve = pFormat + 10; } else { UserMarshalCB.pReserve = 0; } UserMarshalCB.Flags = USER_CALL_CTXT_MASK( pStubMsg->dwDestContext ) | (((pStubMsg->RpcMsg->DataRepresentation & (ulong)0x0000FFFF)) << 16 ); QIndex = *(unsigned short *)(pFormat + 2); pQuadruple = pStubMsg->StubDesc->aUserMarshalQuadruple; pUserBuffer = pQuadruple[ QIndex ].pfnUnmarshall( (ulong*) &UserMarshalCB, pUserBuffer, *ppMemory ); if ( (unsigned long)(pUserBuffer - (uchar *) pStubMsg->RpcMsg->Buffer) > pStubMsg->RpcMsg->BufferLength ) RpcRaiseException( RPC_X_INVALID_BUFFER ); // Step over the pointee. if ( (pFormat[1] & USER_MARSHAL_POINTER) && pStubMsg->PointerBufferMark ) pStubMsg->PointerBufferMark = pUserBuffer; else pStubMsg->Buffer = pUserBuffer; return(0); } unsigned char * RPC_ENTRY NdrInterfacePointerUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls an interface pointer. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to the interface pointer being unmarshalled. pFormat - Interface pointer's format string description. fMustAlloc - TRUE if the interface pointer must be allocated. Return : None. Notes : There are two data representation formats for a marshalled interface pointer. The NDR engine examines the format string to determine the appropriate data format. The format string contains FC_IP followed by either FC_CONSTANT_IID or FC_PAD. Here is the data representation for the FC_CONSTANT_IID case. typedef struct { unsigned long size; [size_is(size)] byte data[]; }MarshalledInterface; Here is the data representation for the FC_PAD case. This format is used when [iid_is] is specified in the IDL file. typedef struct { uuid_t iid; unsigned long size; [size_is(size)] byte data[]; }MarshalledInterfaceWithIid; --*/ { #if !defined( NDR_OLE_SUPPORT ) NDR_ASSERT(0, "Unimplemented"); #else //NT or Chicago HRESULT hr; unsigned long * pMaxCount; unsigned long * pSize; IStream * pStream; IUnknown ** ppunk = (IUnknown **)ppMemory; uchar * pBufferSave; #if DBG == 1 unsigned long position; unsigned long cbRemaining; #endif //DBG == 1 long PtrValue; // On the client side, release the [in,out] interface pointer. if((pStubMsg->IsClient == TRUE) && (*ppunk != 0)) (*ppunk)->lpVtbl->Release((*ppunk)); *ppunk = 0; // // We always have to pickup the pointer itself from the wire // as it behaves like a unique pointer. ALIGN(pStubMsg->Buffer,0x3); PtrValue = *((long *)pStubMsg->Buffer)++; // If the pointer is null, we are done. if ( 0 == PtrValue ) return 0; // // We need up to pickup the pointee. See if it is embedded. // if ( pStubMsg->PointerBufferMark ) { pBufferSave = pStubMsg->Buffer; pStubMsg->Buffer = pStubMsg->PointerBufferMark; //Align the buffer on an 4 byte boundary ALIGN(pStubMsg->Buffer,0x3); } else pBufferSave = 0; // Unmarshal the conformant size and the count field. pMaxCount = (unsigned long *) pStubMsg->Buffer; pStubMsg->Buffer += 4; pSize = (unsigned long *) pStubMsg->Buffer; pStubMsg->Buffer += 4; #if DBG == 1 //Check the array bounds NDR_ASSERT((*pSize == *pMaxCount), "Invalid array bounds for interface pointer"); position = pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer; cbRemaining = pStubMsg->RpcMsg->BufferLength - position; NDR_ASSERT((*pMaxCount <= cbRemaining), "Invalid array bounds for interface pointer"); #endif // DBG == 1 if(*pMaxCount > 0) { pStream = (*NdrpCreateStreamOnMemory)(pStubMsg->Buffer, *pMaxCount); if(pStream == 0) RpcRaiseException(RPC_S_OUT_OF_MEMORY); hr = (*pfnCoUnmarshalInterface)(pStream, & IID_NULL, ppMemory); pStream->lpVtbl->Release(pStream); pStream = 0; if(FAILED(hr)) RpcRaiseException(hr); } //Advance the stub message pointer. pStubMsg->Buffer += *pMaxCount; // // End of MAGIC. // if ( pBufferSave ) { pStubMsg->PointerBufferMark = pStubMsg->Buffer; pStubMsg->Buffer = pBufferSave; } #endif // NT or Chicago return 0; } void RPC_ENTRY NdrClientContextUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, NDR_CCONTEXT * pContextHandle, RPC_BINDING_HANDLE BindHandle ) /*++ Routine Description : Unmarshalls a context handle on the client side. Arguments : pStubMsg - Pointer to stub message. pContextHandle - Pointer to context handle to unmarshall. BindHandle - The handle value used by the client for binding. Return : None. --*/ { ALIGN(pStubMsg->Buffer,3); NDRCContextUnmarshall( pContextHandle, BindHandle, pStubMsg->Buffer, pStubMsg->RpcMsg->DataRepresentation ); pStubMsg->Buffer += 20; } NDR_SCONTEXT RPC_ENTRY NdrServerContextUnmarshall( PMIDL_STUB_MESSAGE pStubMsg ) /*++ Routine Description : Unmarshalls a context handle on the server side. Arguments : pStubMsg - Pointer to stub message. Return : The unmarshalled context handle. --*/ { #if defined( NDR_SERVER_SUPPORT ) NDR_SCONTEXT Context; ALIGN(pStubMsg->Buffer,3); Context = NDRSContextUnmarshall( pStubMsg->Buffer, pStubMsg->RpcMsg->DataRepresentation ); if ( ! Context ) RpcRaiseException( RPC_X_SS_CONTEXT_MISMATCH ); pStubMsg->Buffer += 20; return Context; #endif /* nothing for dos, windows, or Mac */ }