/*++ Copyright (c) 1991 Microsoft Corporation Module Name: dataconv.cxx Abstract: This file contains routines used by the RPC stubs to assist in marshalling and unmarshalling data to and from an RPC message buffer. Each routine receives as a parameter a format string which drives its actions. The valid characters for the format string are : c - charater b - byte w - wide charater or short l - long f - float d - double s1, s2, sb - string of chars, wide chars, or bytes z - byte string )2, )4, )8, (2, (4, (8, 1, 2, 4, 8 - various alignment directives For more details consult the Network Computing Architecture documentation on Network Data Representation. Author: Donna Liu (donnali) 09-Nov-1990 Revision History: 26-Feb-1992 donnali Moved toward NT coding style. 09-Jul-1993 DKays Made wholesale source level optimizations for speed and size. --*/ #include #include #include #include // // alignment macros // #define ALIGN(buffer,increment) \ (((ULONG_PTR)buffer + increment) & ~ increment) #define ALIGN2(buffer) \ (((ULONG_PTR)buffer + 1) & ~1) #define ALIGN4(buffer) \ (((ULONG_PTR)buffer + 3) & ~3) #define ALIGN8(buffer) \ (((ULONG_PTR)buffer + 7) & ~7) // local routines static unsigned long NdrStrlenStrcpy ( char *, char * ); static unsigned long NdrWStrlenStrcpy ( wchar_t *, wchar_t * ); void RPC_ENTRY data_from_ndr ( PRPC_MESSAGE source, void * target, char * format, unsigned char MscPak) /*++ Routine Description: This routine copies data from the runtime buffer. Arguments: source - RPC message structure passed from the runtime to the stub. target - Buffer to receive the unmarshalled data. format - Format of the data. MscPak - Packing level. --*/ { unsigned long valid_lower; unsigned long valid_total; register char *pSource; register char *pTarget; unsigned long pack2, pack4, pack8; unsigned long pack, align; // pre-compute the possible alignment masks if ( MscPak ) MscPak--; pack2 = MscPak & 0x1; pack4 = MscPak & 0x3; pack8 = MscPak & 0x7; pSource = (char *) source->Buffer; if ((source->DataRepresentation & (unsigned long)0X0000FFFF) == NDR_LOCAL_DATA_REPRESENTATION) { pTarget = (char *) target; for (;;) { switch ( *format++ ) { case 'b' : case 'c' : *((char *)pTarget) = *((char *)pSource); pTarget += 1; pSource += 1; break; case 'w' : pSource = (char *) ALIGN2(pSource); pTarget = (char *) ALIGN(pTarget,pack2); *((short *)pTarget) = *((short *)pSource); pTarget += 2; pSource += 2; break; case 'l' : case 'f' : pSource = (char *) ALIGN4(pSource); pTarget = (char *) ALIGN(pTarget,pack4); *((long *)pTarget) = *((long *)pSource); pTarget += 4; pSource += 4; break; case 'h' : case 'd' : pSource = (char *) ALIGN8(pSource); pTarget = (char *) ALIGN(pTarget,pack8); #if defined(DOS) || defined(WIN) *((DWORD *) pTarget) = *((DWORD *) &pSource); *(((DWORD *) pTarget) + 1) = *(((DWORD *) &pSource) + 1); #else *((__int64 *)pTarget) = *((__int64 *)pSource); #endif pTarget += 8; pSource += 8; break; case 's' : pSource = (char *) ALIGN4(pSource); valid_lower = *((long *)pSource); pSource += 4; valid_total = *((long *)pSource); pSource += 4; // double the valid_total if this is a wide char string if ( *format++ == '2' ) valid_total <<= 1; RpcpMemoryCopy(pTarget, pSource, valid_total); pTarget += valid_total; pSource += valid_total; break; case 'z' : pSource = (char *) ALIGN4(pSource); valid_total = *((long *)pSource); pSource += 4; *((int *)pTarget - 1) = (int) valid_total; // double the valid_total if this is a wide char string if ( *format++ == '2' ) valid_total <<= 1; RpcpMemoryCopy(pTarget, pSource, valid_total); pTarget += valid_total; pSource += valid_total; break; case 'p' : pSource = (char *) ALIGN4(pSource); pTarget = (char *) ALIGN(pTarget,pack4); pTarget += 4; pSource += 4; break; case '(' : // *format == '2', '4', or '8'; align = 1, 3, or 7 align = *format - '0' - 1; pSource = (char *) ALIGN(pSource,align); case ')' : switch ( *format++ ) { case '8' : pack = pack8; break; case '4' : pack = pack4; break; case '2' : pack = pack2; break; default : continue; } pTarget = (char *) ALIGN(pTarget,pack); break; case '8' : pSource = (char *) ALIGN8(pSource); break; case '4' : pSource = (char *) ALIGN4(pSource); break; case '2' : pSource = (char *) ALIGN2(pSource); break; case '1' : break; default : source->Buffer = pSource; return; } // switch } // for } // if else { for (;;) { switch ( *format++ ) { case 'b' : *((char *)target) = *((char *)source->Buffer); source->Buffer = (void *)((ULONG_PTR)source->Buffer + 1); target = (void *)((ULONG_PTR)target + 1); break; case 'c' : char_from_ndr(source,(unsigned char *)target); target = (void *)((ULONG_PTR)target + 1); break; case 'w' : target = (void *) ALIGN(target,pack2); short_from_ndr(source,(unsigned short *)target); target = (void *)((ULONG_PTR)target + 2); break; case 'l' : target = (void *) ALIGN(target,pack4); long_from_ndr(source,(unsigned long *)target); target = (void *)((ULONG_PTR)target + 4); break; case 'f' : target = (void *) ALIGN(target,pack4); float_from_ndr(source, target); target = (void *)((ULONG_PTR)target + 4); break; case 'd' : target = (void *) ALIGN(target,pack8); double_from_ndr(source, target); target = (void *)((ULONG_PTR)target + 8); break; case 'h' : target = (void *) ALIGN(target,pack8); hyper_from_ndr(source, (hyper *)target); target = (void *)((ULONG_PTR)target + 8); break; case 's' : long_from_ndr(source, &valid_lower); long_from_ndr(source, &valid_total); switch ( *format++ ) { case '2' : short_array_from_ndr (source, 0, valid_total, (unsigned short *)target); valid_total <<= 1; break; case '1' : char_array_from_ndr (source, 0, valid_total, (unsigned char *)target); break; case 'b' : byte_array_from_ndr(source, 0, valid_total, target); break; default : continue; } target = (void *)((ULONG_PTR)target + valid_total); break; case 'z' : long_from_ndr(source, &valid_total); *((int *)target - 1) = (int) valid_total; switch ( *format++ ) { case '2' : short_array_from_ndr(source, 0, valid_total, (unsigned short *)target); valid_total <<= 1; break; case '1' : byte_array_from_ndr(source, 0, valid_total, target); break; } target = (void *)((ULONG_PTR)target + valid_total); break; case 'p' : source->Buffer = (void *) ALIGN4(source->Buffer); target = (void *) ALIGN(target,pack4); source->Buffer = (void *)((ULONG_PTR)source->Buffer + 4); target = (void *)((ULONG_PTR)target + 4); break; case '(' : // *format == '2', '4', or '8'; align = 1, 3, or 7 align = *format - '0' - 1; pSource = (char *) ALIGN(pSource,align); case ')' : switch (*format++) { case '8' : pack = pack8; break; case '4' : pack = pack4; break; case '2' : pack = pack2; break; default : continue; } target = (void *) ALIGN(target,pack); break; case '8' : source->Buffer = (void *)ALIGN8(source->Buffer); break; case '4' : source->Buffer = (void *)ALIGN4(source->Buffer); break; case '2' : source->Buffer = (void *)ALIGN2(source->Buffer); break; case '1' : break; default : return; } // switch } // for } // else } void RPC_ENTRY data_into_ndr ( void * source, PRPC_MESSAGE target, char * format, unsigned char MscPak) /*++ Routine Description: This routine copies data into the runtime buffer. Arguments: source - Buffer of data to be marshalled into the RPC message. target - RPC message structure to be passed to the runtime. format - Format of the data. MscPak - Packing level. --*/ { unsigned long valid_total; register char *pSource; register char *pTarget; unsigned long pack2, pack4, pack8; unsigned long increment; unsigned long pack, align; pSource = (char *)source; pTarget = (char *)target->Buffer; // pre-compute the possible alignment masks if ( MscPak ) MscPak--; pack2 = MscPak & 0x1; pack4 = MscPak & 0x3; pack8 = MscPak & 0x7; for (;;) { switch (*format++) { case 'b' : case 'c' : *((char *)pTarget) = *((char *)pSource); pTarget += 1; pSource += 1; break; case 'w' : pTarget = (char *) ALIGN2(pTarget); pSource = (char *) ALIGN(pSource,pack2); *((short *)pTarget) = *((short *)pSource); pTarget += 2; pSource += 2; break; case 'l' : case 'f' : pTarget = (char *) ALIGN4(pTarget); pSource = (char *) ALIGN(pSource,pack4); *((long *)pTarget) = *((long *)pSource); pTarget += 4; pSource += 4; break; case 'h' : case 'd' : pTarget = (char *) ALIGN8(pTarget); pSource = (char *) ALIGN(pSource,pack8); #if defined(DOS) || defined(WIN) *((DWORD *) pTarget) = *((DWORD *) &pSource); *(((DWORD *) pTarget) + 1) = *(((DWORD *) &pSource) + 1); #else *((__int64 *)pTarget) = *((__int64 *)pSource); #endif pTarget += 8; pSource += 8; break; case 's' : pTarget = (char *) ALIGN4(pTarget); switch (*format++) { case '2' : valid_total = NdrWStrlenStrcpy((wchar_t *)(pTarget + 8), (wchar_t *)pSource); increment = valid_total << 1; break; case '1' : valid_total = NdrStrlenStrcpy(pTarget + 8,pSource); increment = valid_total; break; default : continue; } *((long *)pTarget) = 0; // offset pTarget += 4; *((long *)pTarget) = valid_total; // count pTarget += 4; pTarget += increment; pSource += increment; break; case 'z' : valid_total = (long) *((int *)pSource - 1); pTarget = (char *) ALIGN4(pTarget); *((long *)pTarget) = valid_total; pTarget += 4; if ( *format++ == '2' ) valid_total <<= 1; RpcpMemoryCopy(pTarget, pSource, valid_total); pTarget += valid_total; pSource += valid_total; break; case 'p' : pTarget = (char *) ALIGN4(pTarget); pSource = (char *) ALIGN(pSource,pack4); pTarget += 4; pSource += 4; break; case '(' : // *format == '2', '4', or '8'; align = 1, 3, or 7 align = *format - '0' - 1; pTarget = (char *) ALIGN(pTarget,align); case ')' : switch (*format++) { case '8' : pack = pack8; break; case '4' : pack = pack4; break; case '2' : pack = pack2; break; default : continue; } pSource = (char *) ALIGN(pSource,pack); break; case '8' : pTarget = (char *) ALIGN8(pTarget); break; case '4' : pTarget = (char *) ALIGN4(pTarget); break; case '2' : pTarget = (char *) ALIGN2(pTarget); break; case '1' : break; default : target->Buffer = pTarget; return; } // switch } // for } void RPC_ENTRY tree_into_ndr ( void * source, PRPC_MESSAGE target, char * format, unsigned char MscPak) /*++ Routine Description: This routine copies data into the runtime buffer. Arguments: source - Buffer of data to be marshalled into the RPC message. target - RPC message structure to be passed to the runtime. format - Format of the data. MscPak - Packing level. --*/ { unsigned long valid_total; register char *pSource; register char *pTarget; unsigned long pack2, pack4, pack8; unsigned long increment; pSource = (char *)source; pTarget = (char *)target->Buffer; // pre-compute the possible alignment masks if ( MscPak ) MscPak--; pack2 = MscPak & 0x1; pack4 = MscPak & 0x3; pack8 = MscPak & 0x7; for (;;) { switch (*format++) { case 'b' : case 'c' : pSource += 1; break; case 'w' : pSource = (char *) ALIGN(pSource,pack2); pSource += 2; break; case 'l' : case 'f' : pSource = (char *) ALIGN(pSource,pack4); pSource += 4; break; case 'h' : case 'd' : pSource = (char *) ALIGN(pSource,pack8); pSource += 8; break; case 's' : pSource = (char *) ALIGN(pSource,pack4); if ( ! *(void **)pSource ) { pSource += 4; format++; break; } pTarget = (char *) ALIGN4(pTarget); switch (*format++) { case '2' : valid_total = NdrWStrlenStrcpy((wchar_t *)(pTarget+12), *(wchar_t **)pSource); increment = valid_total << 1; break; case '1' : valid_total = NdrStrlenStrcpy(pTarget + 12, *(char **)pSource); increment = valid_total; break; default : continue; } *((long *)pTarget) = valid_total; // max count pTarget += 4; *((long *)pTarget) = 0; // offset pTarget += 4; *((long *)pTarget) = valid_total; // actual count pTarget += 4; pSource += 4; pTarget += increment; break; case 'z' : pSource = (char *) ALIGN(pSource,pack4); if ( ! *(void **)pSource ) { pSource += 4; break; } valid_total = (long) *(*(int **)pSource - 1); pTarget = (char *) ALIGN4(pTarget); *((long *)pTarget) = valid_total; // max count pTarget += 4; *((long *)pTarget) = valid_total; // actual count pTarget += 4; if ( *format++ == '2' ) valid_total <<= 1; RpcpMemoryCopy(pTarget, *(char **)pSource, valid_total); pSource += 4; pTarget += valid_total; break; case '(' : case ')' : switch (*format++) { case '8' : pSource = (char *) ALIGN(pSource,pack8); break; case '4' : pSource = (char *) ALIGN(pSource,pack4); break; case '2' : pSource = (char *) ALIGN(pSource,pack2); break; default : break; } break; case '8' : case '4' : case '2' : case '1' : break; default : target->Buffer = pTarget; return; } // switch } // for } void RPC_ENTRY data_size_ndr ( void * source, PRPC_MESSAGE target, char * format, unsigned char MscPak) /*++ Routine Description: This routine calculates the size of the runtime buffer. Arguments: source - Buffer of data to be marshalled into the RPC message. target - RPC message structure to be passed to the runtime. format - Format of the data. MscPak - Packing level. --*/ { unsigned long valid_total; register char *pSource; register unsigned long targetLength; unsigned long pack2, pack4, pack8; unsigned long pack, align; pSource = (char *)source; targetLength = target->BufferLength; // pre-compute the possible alignment masks if ( MscPak ) MscPak--; pack2 = MscPak & 0x1; pack4 = MscPak & 0x3; pack8 = MscPak & 0x7; for (;;) { switch (*format++) { case 'b' : case 'c' : targetLength += 1; break; case 'w' : targetLength = (unsigned long) ALIGN2(targetLength); pSource = (char *) ALIGN(pSource,pack2); targetLength += 2; pSource += 2; break; case 'l' : case 'f' : targetLength = (unsigned long) ALIGN4(targetLength); pSource = (char *) ALIGN(pSource,pack4); targetLength += 4; pSource += 4; break; case 'h' : case 'd' : targetLength = (unsigned long) ALIGN8(targetLength); pSource = (char *) ALIGN(pSource,pack8); targetLength += 8; pSource += 8; break; case 's' : switch (*format++) { case '2' : valid_total = MIDL_wchar_strlen((wchar_t *)pSource) + 1; valid_total <<= 1; break; case '1' : valid_total = strlen(pSource) + 1; break; default : continue; } targetLength = (unsigned long) ALIGN4(targetLength); // add string length plus two longs (for offset and count) targetLength += 8 + valid_total; break; case 'z' : targetLength = (unsigned long) ALIGN4(targetLength); valid_total = (long) *((int *)pSource - 1); if ( *format++ == '2' ) valid_total <<= 1; // add byte string length plus one long (for count) targetLength += 4 + valid_total; break; case 'p' : targetLength = (unsigned long) ALIGN4(targetLength); pSource = (char *) ALIGN(pSource,pack4); target->Buffer = (void *)((ULONG_PTR)target->Buffer + 4); pSource += 4; break; case '(' : // *format == '2', '4', or '8'; align = 1, 3, or 7 align = *format - '0' - 1; targetLength = (unsigned long) ALIGN(targetLength,align); case ')' : switch (*format++) { case '8' : pack = pack8; break; case '4' : pack = pack4; break; case '2' : pack = pack2; break; default : continue; } pSource = (char *) ALIGN(pSource,pack); break; case '8' : targetLength = (unsigned long) ALIGN8(targetLength); break; case '4' : targetLength = (unsigned long) ALIGN4(targetLength); break; case '2' : targetLength = (unsigned long) ALIGN2(targetLength); break; case '1' : break; default : target->BufferLength = targetLength; return; } // switch } // for } void RPC_ENTRY tree_size_ndr ( void * source, PRPC_MESSAGE target, char * format, unsigned char MscPak) /*++ Routine Description: This routine calculates the size of the runtime buffer. Arguments: source - Buffer of data to be marshalled into the RPC message. target - RPC message structure to be passed to the runtime. format - Format of the data. MscPak - Packing level. --*/ { unsigned long valid_total; register char *pSource; unsigned long pack2, pack4, pack8; pSource = (char *)source; // pre-compute the possible alignment masks if ( MscPak ) MscPak--; pack2 = MscPak & 0x1; pack4 = MscPak & 0x3; pack8 = MscPak & 0x7; for (;;) { switch (*format++) { case 'b' : case 'c' : pSource += 1; break; case 'w' : pSource = (char *) ALIGN(pSource,pack2); pSource += 2; break; case 'l' : case 'f' : pSource = (char *) ALIGN(pSource,pack4); pSource += 4; break; case 'h' : case 'd' : pSource = (char *) ALIGN(pSource,pack8); pSource += 8; break; case 's' : pSource = (char *) ALIGN(pSource,pack4); if ( ! *(void __RPC_FAR * __RPC_FAR *)pSource ) { pSource += 4; format++; break; } switch (*format++) { case '2' : valid_total = MIDL_wchar_strlen( *(wchar_t __RPC_FAR * __RPC_FAR *)pSource)+1; valid_total <<= 1; break; case '1' : valid_total = strlen (*(char __RPC_FAR * __RPC_FAR *)pSource) + 1; break; default : continue; } target->BufferLength = (unsigned int) ALIGN4(target->BufferLength); // add string length plus 3 longs (max count, offset, and // actual count) target->BufferLength += 12 + valid_total; pSource += 4; break; case 'z' : pSource = (char *) ALIGN(pSource,pack4); if ( ! *(void __RPC_FAR * __RPC_FAR *)pSource ) { pSource += 4; break; } valid_total = (long) *(*(int **)pSource - 1); if ( *format++ == '2' ) valid_total <<= 1; target->BufferLength = (unsigned int) ALIGN4(target->BufferLength); // add string length plus 2 longs (max count and actual count) target->BufferLength += 8 + valid_total; pSource += 4; break; case '(' : case ')' : switch (*format++) { case '8' : pSource = (char *) ALIGN(pSource,pack8); break; case '4' : pSource = (char *) ALIGN(pSource,pack4); break; case '2' : pSource = (char *) ALIGN(pSource,pack2); break; default : break; } break; case '8' : case '4' : case '2' : case '1' : break; default : return; } } } void RPC_ENTRY tree_peek_ndr ( PRPC_MESSAGE source, unsigned char ** buffer, char * format, unsigned char MscPak) /*++ Routine Description: This routine peeks the runtime buffer. Arguments: source - RPC message structure passed from the runtime to the stubs. target - Buffer to receive the unmarshalled data. format - Format of the data. MscPak - Packing level. --*/ { unsigned long valid_total; register unsigned char *pBuffer; unsigned long pack8; int IsString; pBuffer = *buffer; // pre-compute the possible alignment masks if ( MscPak ) MscPak--; pack8 = MscPak & 0x7; IsString = (*format == 's' || *format == 'z'); for (;;) { switch (*format++) { case 'b' : case 'c' : pBuffer += 1; break; case 'w' : pBuffer = (unsigned char *) ALIGN2(pBuffer); pBuffer += 2; break; case 'l' : case 'f' : pBuffer = (unsigned char *) ALIGN4(pBuffer); pBuffer += 4; break; case 'h' : case 'd' : pBuffer = (unsigned char *) ALIGN8(pBuffer); pBuffer += 8; break; case 's' : if ( ! IsString ) { pBuffer = (unsigned char *) ALIGN4(pBuffer); if ( ! *(long *)pBuffer ) { pBuffer += 4; format++; break; } pBuffer += 4; long_from_ndr (source, &valid_total); // max count (ignore) } long_from_ndr (source, &valid_total); // offset (ignore) long_from_ndr (source, &valid_total); // actual count // if it's a wide char string if ( *format++ == '2' ) { // wide char string must be aligned on at least a // short boundary if ( ! MscPak ) pack8 = 0x1; valid_total <<= 1; } source->BufferLength = (unsigned int) ALIGN(source->BufferLength,pack8); *((unsigned long *)pBuffer - 1) = source->BufferLength; source->BufferLength += valid_total; source->Buffer = (void *)((ULONG_PTR)source->Buffer + valid_total); break; case 'z' : if ( ! IsString ) { pBuffer = (unsigned char *) ALIGN4(pBuffer); if ( ! *(long *)pBuffer ) { pBuffer += 4; format++; break; } pBuffer += 4; long_from_ndr (source, &valid_total); // max count (ignore) } long_from_ndr (source, &valid_total); // actual count // if it's a wide byte string if ( *format++ == '2' ) { // wide byte string must be aligned on at least a // short boundary if ( ! MscPak ) pack8 = 0x1; valid_total <<= 1; } source->BufferLength = (unsigned int) ALIGN(source->BufferLength,pack8); *((unsigned long *)pBuffer - 1) = source->BufferLength; source->BufferLength += valid_total; source->Buffer = (void *)((ULONG_PTR)source->Buffer + valid_total); break; case '(' : switch (*format++) { case '8' : pBuffer = (unsigned char *) ALIGN8(pBuffer); break; case '4' : pBuffer = (unsigned char *) ALIGN4(pBuffer); break; case '2' : pBuffer = (unsigned char *) ALIGN2(pBuffer); break; default : break; } break; case ')' : format++; break; case '8' : pBuffer = (unsigned char *) ALIGN8(pBuffer); break; case '4' : pBuffer = (unsigned char *) ALIGN4(pBuffer); break; case '2' : pBuffer = (unsigned char *) ALIGN2(pBuffer); break; case '1' : break; default : *buffer = pBuffer; return; } } } static unsigned long NdrStrlenStrcpy ( char *pTarget, char *pSource ) { register unsigned int count; for ( count = 1; *pTarget++ = *pSource++; count++ ) ; return count; } static unsigned long NdrWStrlenStrcpy ( wchar_t *pTarget, wchar_t *pSource ) { register unsigned int count; for ( count = 1; *pTarget++ = *pSource++; count++ ) ; return count; }