/*++

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 <sysinc.h>
#include <rpc.h>
#include <rpcndr.h>

#if !defined(WIN32) && !defined(MAC)
#define strcpy _fstrcpy
#define strlen _fstrlen
#endif

//
// alignment macros
//

#define  ALIGN(buffer,increment) \
            (((unsigned long)buffer + increment) & ~ increment);

#define  ALIGN2(buffer) \
            (((unsigned long)buffer + 1) & 0xfffffffe)

#define  ALIGN4(buffer) \
            (((unsigned long)buffer + 3) & 0xfffffffc)

#define  ALIGN8(buffer) \
            (((unsigned long)buffer + 7) & 0xfffffff8)

// 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;

   if ((source->DataRepresentation & (unsigned long)0X0000FFFF) ==
      NDR_LOCAL_DATA_REPRESENTATION)
        {

        pSource = (char *) source->Buffer;
        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 *)((long)source->Buffer + 1);
                    target = (void *)((long)target + 1);
               break;
            case 'c' :
               char_from_ndr(source,(unsigned char *)target);
                    target = (void *)((long)target + 1);
               break;
            case 'w' :
               target = (void *) ALIGN(target,pack2);
               short_from_ndr(source,(unsigned short *)target);
                    target = (void *)((long)target + 2);
               break;
            case 'l' :
               target = (void *) ALIGN(target,pack4);
               long_from_ndr(source,(unsigned long *)target);
                    target = (void *)((long)target + 4);
               break;
            case 'f' :
               target = (void *) ALIGN(target,pack4);
               float_from_ndr(source, target);
                    target = (void *)((long)target + 4);
               break;
            case 'd' :
               target = (void *) ALIGN(target,pack8);
               double_from_ndr(source, target);
                    target = (void *)((long)target + 8);
               break;
            case 'h' :
               target = (void *) ALIGN(target,pack8);
               hyper_from_ndr(source, (hyper *)target);
                    target = (void *)((long)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 *)((long)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 *)((long)target + valid_total);
               break;
            case 'p' :
               source->Buffer = (void *) ALIGN4(source->Buffer);
               target = (void *) ALIGN(target,pack4);
               source->Buffer = (void *)((long)source->Buffer + 4);
                    target = (void *)((long)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 *)((long)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 *)((long)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 *)((long)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;
}