/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Copyright (c) 1993 Microsoft Corporation

Module Name:

    bstr.cxx

Abstract:

    Windows Data Type Support by means of [user_marshal] attribute.

    Covers:
        BSTR
    

Author:

    Bill Morel (billmo)  Oct 14, 1995

    These routines provide [wire_marshal] support for BSTRs.

Revision History:

    14-Jun-96   MikeHill    Converted to use the new PrivSysAllocString,
                            PrivSysReAllocString, & PrivSysFreeString routines
                            (defined elsewhere in OLE32).

-------------------------------------------------------------------*/


//#include "stdrpc.hxx"
#pragma hdrstop

#include <wtypes.h>
#include "transmit.h"
#include <privoa.h>     // PrivSys* routines

// round up string alloc requests to nearest N-byte boundary, since allocator
// will round up anyway. Improves cache hits.
//
// UNDONE: optimal for Chicago is 4
// UNDONE: optimal for Daytona is 32
// UNDONE: 4 didn't help the a$ = a$ + "x" case at all.
// UNDONE: 8 did (gave 50% cache hit)
//
#define WIN32_ALLOC_ALIGN (4 - 1)	
#define DEFAULT_ALLOC_ALIGN (2 - 1)


/***
*unsigned int PrivSysStringByteLen(BSTR)
*Purpose:
*  return the length in bytes of the given BSTR.
*
*Entry:
*  bstr = the BSTR to return the length of
*
*Exit:
*  return value = unsigned int, length in bytes.
*
***********************************************************************/

// #########################################################################
//
//  BSTR
//
// #########################################################################

//+-------------------------------------------------------------------------
//
//  Function:   BSTR_UserSize
//
//  Synopsis:   Get the wire size for the BSTR handle and data.
//
//  Derivation: Conformant struct with a flag field:
//                  align + 12 + data size.
//
//--------------------------------------------------------------------------

unsigned long __RPC_USER
BSTR_UserSize (
    unsigned long * pFlags,
    unsigned long   Offset,
    BSTR          * pBstr)
{
    // Null bstr doesn't get marshalled.

    if ( pBstr == NULL  ||  *pBstr == NULL )
        return Offset;

    unsigned long   ulDataSize;

    LENGTH_ALIGN( Offset, 3 );

    // Takes the byte length of a unicode string

    ulDataSize = PrivSysStringByteLen( *pBstr );

    return( Offset + 12 + ulDataSize) ;
}

//+-------------------------------------------------------------------------
//
//  Function:   BSTR_UserMarshall
//
//  Synopsis:   Marshalls an BSTR object into the RPC buffer.
//
//  Derivation: Conformant struct with a flag field:
//                  align, size, null flag, size, data (bytes, if any)
//
//--------------------------------------------------------------------------

unsigned char __RPC_FAR * __RPC_USER
BSTR_UserMarshal (
    unsigned long * pFlags,
    unsigned char * pBuffer,
    BSTR          * pBstr)
{
    // A null Bstr is not marshalled, the engine will take care of it.

    if ( pBstr == NULL  ||  *pBstr == NULL )
        return pBuffer;

    unsigned long   ulDataSize;

    // Data size (in bytes): a null bstr gets a data size of zero.

    ulDataSize = PrivSysStringByteLen( *pBstr );

    // Conformant size.

    ALIGN( pBuffer, 3 );
    *( PULONG_LV_CAST pBuffer)++ = (ulDataSize >> 1);

    // FLAGGED_WORD_BLOB: Handle is the null/non-null flag

    *( PULONG_LV_CAST pBuffer)++ = (unsigned long)*pBstr;

    // Length on wire is in words.

    *( PULONG_LV_CAST pBuffer)++ = (ulDataSize >> 1);

    if( ulDataSize )
        {
        // we don't put the terminating string on wire

        WdtpMemoryCopy( pBuffer, *pBstr, ulDataSize );
        }

    return( pBuffer + ulDataSize );
}


//+-------------------------------------------------------------------------
//
//  Function:   BSTR_UserUnmarshall
//
//  Synopsis:   Unmarshalls an BSTR object from the RPC buffer.
//
//  Derivation: Conformant struct with a flag field:
//                  align, size, null flag, size, data (bytes, if any)
//
//--------------------------------------------------------------------------

unsigned char __RPC_FAR * __RPC_USER
BSTR_UserUnmarshal (
    unsigned long * pFlags,
    unsigned char * pBuffer,
    BSTR          * pBstr)
{
    unsigned long   ulDataSize, fHandle;
    BSTR            Bstr = NULL;    // Default to NULL BSTR

    ALIGN( pBuffer, 3 );

    ulDataSize = *( PULONG_LV_CAST pBuffer)++;
    fHandle = *(ulong *)pBuffer;
    pBuffer += 8;

    if ( fHandle  )
        {
        // Length on wire is in words, and the string is unicode.

        if ( *pBstr  &&
             *(((ulong *)*pBstr) -1) == (ulDataSize << 1) )
            WdtpMemoryCopy( *pBstr, pBuffer, (ulDataSize << 1) );
        else
            {
            if (!PrivSysReAllocStringLen( pBstr, 
                                          (OLECHAR *)pBuffer,
                                          ulDataSize ))
                RpcRaiseException( E_OUTOFMEMORY );
            }
        }
    else
        {
        // free the old one, make it NULL.

        PrivSysFreeString( *pBstr );
        *pBstr = NULL;
        }

    return( pBuffer + (ulDataSize << 1) );
}

//+-------------------------------------------------------------------------
//
//  Function:   BSTR_UserFree
//
//  Synopsis:   Free an BSTR.
//
//--------------------------------------------------------------------------
void __RPC_USER
BSTR_UserFree(
    unsigned long * pFlags,
    BSTR * pBstr)
{
    if( pBstr && *pBstr )
            {
            PrivSysFreeString(* pBstr);
            *pBstr = NULL;
            }
}