|
|
/************************************************************************
Copyright (c) 1999-2000 Microsoft Corporation
Module Name :
cssup.cxx
Abstract :
Support routines for international character (cs) support.
Author :
Mike Warning MikeW August 1999.
Revision History :
***********************************************************************/
#include "ndrp.h"
#include "cssup.h"
BOOL GetThreadACP( unsigned long *cp, error_status_t *pStatus) /*++
Routine Description :
Get the current codepage of this thread.
Arguments :
cp -- Pointer to where to return the codepage pStatus -- Pointer to where to return the status of the operation
Return :
TRUE and RPC_S_OK if we we're able to determine the codepage, FALSE and a Win32 derived error code if not.
--*/ { CPINFOEX info;
if ( ! GetCPInfoEx( CP_THREAD_ACP, 0, &info ) ) { *pStatus = HRESULT_FROM_WIN32( GetLastError() ); return FALSE; }
*pStatus = RPC_S_OK; *cp = info.CodePage; return TRUE; }
ulong TranslateCodeset( ulong Codeset) /*++
Routine Description :
Translate the given generic codeset value (CP_ACP, CP_OEMCP, or CP_THREAD_ACP) to it's true value.
Arguments :
Codeset -- The value to translate
Return :
The true value.
--*/ { CPINFOEX info;
if ( ! GetCPInfoEx( Codeset, 0, &info ) ) RpcRaiseException( HRESULT_FROM_WIN32( GetLastError () ) );
return info.CodePage; }
ulong NdrpGetSetCSTagMarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, NDR_CS_TAG_FORMAT * pTagFormat) /*++
Routine Description :
Extract the codeset referred to by pTagFormat and save it in the stub message for later buffer sizing / marshalling.
Arguments :
pStubMsg -- The stub message pMemory -- (possibly) The pointer to the tag value pTagFormat -- Pointer to FC_CS_TAG in the format string
Return :
The codeset
--*/ { ulong Codeset;
InitializeStubCSInfo( pStubMsg );
//
// If there is no tag getting routine then the value of the tag is on
// the stack like a normal parameter. If there is a tag routine, then
// the parameter is NOT on the stack (pMemory is invalid) and we need
// to call the tag routine to get the value.
//
if ( NDR_INVALID_TAG_ROUTINE_INDEX == pTagFormat->TagRoutineIndex ) { Codeset = * (ulong *) pMemory; } else { CS_TAG_GETTING_ROUTINE *TagRoutines; CS_TAG_GETTING_ROUTINE GetTagRoutine; ulong SendingCodeset; ulong DesiredReceivingCodeset; ulong ReceivingCodeset; error_status_t status;
if ( ! pStubMsg->IsClient )
DesiredReceivingCodeset = pStubMsg->pCSInfo->DesiredReceivingCodeset;
TagRoutines = pStubMsg->StubDesc->CsRoutineTables->pTagGettingRoutines;
GetTagRoutine = TagRoutines[ pTagFormat->TagRoutineIndex ];
GetTagRoutine( pStubMsg->RpcMsg->Handle, ! pStubMsg->IsClient, &SendingCodeset, &DesiredReceivingCodeset, &ReceivingCodeset, &status );
if ( RPC_S_OK != status ) RpcRaiseException( status );
if ( pTagFormat->Flags.STag ) Codeset = SendingCodeset; else if ( pTagFormat->Flags.DRTag ) Codeset = DesiredReceivingCodeset; else Codeset = ReceivingCodeset; }
//
// Don't allow generic psuedo codesets on the wire. Translate them to
// thier real values
//
// REVIEW: The is true for the standard sizing/translation routines but
// for user specified ones they should ideally be able to do
// anything they want.
//
if ( CP_ACP == Codeset || CP_OEMCP == Codeset || CP_THREAD_ACP == Codeset ) Codeset = TranslateCodeset( Codeset );
//
// Save the values away in the stub message for array size/marshal/etc.
//
if ( pTagFormat->Flags.STag ) pStubMsg->pCSInfo->WireCodeset = Codeset;
if (pTagFormat->Flags.DRTag ) pStubMsg->pCSInfo->DesiredReceivingCodeset = Codeset;
return Codeset; }
ulong NdrpGetSetCSTagUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, NDR_CS_TAG_FORMAT * pTagFormat) /*++
Routine Description :
Extract the codeset in the buffer and save it in the stub message for later memory sizing / unmarshalling.
Arguments :
pStubMsg -- The stub message pTagFormat -- Pointer to FC_CS_TAG in the format string
Return :
The codeset
--*/ { ulong Codeset;
InitializeStubCSInfo( pStubMsg );
Codeset = * (ulong *) pStubMsg->Buffer;
if ( pTagFormat->Flags.STag && ! pStubMsg->IsClient ) pStubMsg->pCSInfo->WireCodeset = Codeset;
if ( pTagFormat->Flags.DRTag ) pStubMsg->pCSInfo->DesiredReceivingCodeset = Codeset;
if ( pTagFormat->Flags.RTag && pStubMsg->IsClient ) pStubMsg->pCSInfo->WireCodeset = Codeset;
return Codeset; }
void GenericBufferSize( unsigned long DestCodeSet, unsigned long SourceCodeSet, unsigned long SourceBufferSize, IDL_CS_CONVERT * ConversionType, unsigned long * DestBufferSize, error_status_t * status) /*++
Routine Description :
Estimate the length of the buffer needed to hold [SourceBufferSize] characters if they we're translated into [DestCodeSet].
Arguments :
DestCodeSet - The codeset that the data will be translated to SourceCodeSet - The source codeset SourceBufferSize - The number of characters in the source codeset ConversionType - Returns whether or not conversion is needed DestBufferSize - Where to put the estimated buffer size status - The return status
--*/ { int DestMaxCharSize;
*status = NO_ERROR;
// Determine the maximum size of a character on the wire in bytes
if ( CP_UNICODE == DestCodeSet ) { DestMaxCharSize = 2; } else { CPINFO cpinfo;
if ( ! GetCPInfo( DestCodeSet, &cpinfo ) ) { *status = HRESULT_FROM_WIN32( GetLastError() ); return; } DestMaxCharSize = cpinfo.MaxCharSize; }
// Worst case: each char in the local buffer expands to the maximum number
// of bytes for a char in the network codeset
if ( NULL != DestBufferSize ) *DestBufferSize = SourceBufferSize * DestMaxCharSize;
if ( SourceCodeSet == DestCodeSet ) *ConversionType = IDL_CS_NO_CONVERT; else *ConversionType = IDL_CS_NEW_BUFFER_CONVERT; }
void RPC_ENTRY cs_byte_net_size( RPC_BINDING_HANDLE hBinding, unsigned long NetworkCodeSet, unsigned long LocalBufferSize, IDL_CS_CONVERT * ConversionType, unsigned long * NetworkBufferSize, error_status_t * status) /*++
Routine Description :
Estimate the length of the buffer needed to hold [LocalBufferSize] characters if they are translated from the current thread codeset into [NetworkCodeSet].
Arguments :
hBinding - The RPC binding handle NetworkCodeSet - The codeset that the data will be translated to LocalBufferSize - The number of bytes in the data ConversionType - Returns whether the conversion can be done inplace NetworkBufferSize - Where to put the estimated buffer size status - The return status
--*/ { ulong LocalCP;
if ( ! GetThreadACP( &LocalCP, status ) ) return;
// No conversion is necessary if the local and destination codesets are
// the same.
GenericBufferSize( NetworkCodeSet, LocalCP, LocalBufferSize, ConversionType, NetworkBufferSize, status); }
void RPC_ENTRY wchar_t_net_size( RPC_BINDING_HANDLE hBinding, unsigned long NetworkCodeSet, unsigned long LocalBufferSize, IDL_CS_CONVERT * ConversionType, unsigned long * NetworkBufferSize, error_status_t * status) /*++
Routine Description :
Estimate the length of the buffer needed to hold [LocalBufferSize] characters if they are translated from the current thread codeset into [NetworkCodeSet].
Arguments :
hBinding - The RPC binding handle NetworkCodeSet - The codeset that the data will be translated to LocalBufferSize - The number of bytes in the data ConversionType - Returns whether the conversion can be done inplace NetworkBufferSize - Where to put the estimated buffer size status - The return status
--*/ { ulong LocalCP = CP_UNICODE;
GenericBufferSize( NetworkCodeSet, LocalCP, LocalBufferSize, ConversionType, NetworkBufferSize, status); }
void RPC_ENTRY cs_byte_local_size( RPC_BINDING_HANDLE hBinding, unsigned long NetworkCodeSet, unsigned long NetworkBufferSize, IDL_CS_CONVERT * ConversionType, unsigned long * LocalBufferSize, error_status_t * status) /*++
Routine Description :
Estimate the length of the buffer needed to hold [NetworkBufferSize] characters if they are translated from [NetworkCodeSet] to the local thread codeset.
Arguments :
hBinding - The RPC binding handle NetworkCodeSet - The codeset that the data will be translated to NetworkBufferSize - The number of bytes in the data ConversionType - Returns whether the conversion can be done inplace LocalBufferSize - Where to put the estimated buffer size status - The return status
--*/ { ulong LocalCP;
if ( ! GetThreadACP(&LocalCP, status) ) return;
// In Unicode the minimum character size is 2 so we can save a bit of
// memory cutting the apparent source buffer size
if ( CP_UNICODE == NetworkCodeSet ) NetworkBufferSize /= 2;
GenericBufferSize( LocalCP, NetworkCodeSet, NetworkBufferSize, ConversionType, LocalBufferSize, status); }
void RPC_ENTRY wchar_t_local_size( RPC_BINDING_HANDLE hBinding, unsigned long NetworkCodeSet, unsigned long NetworkBufferSize, IDL_CS_CONVERT * ConversionType, unsigned long * LocalBufferSize, error_status_t * status) /*++
Routine Description :
Estimate the length of the buffer needed to hold [NetworkBufferSize] characters if they are translated from [NetworkCodeSet] to the local thread codeset.
Arguments :
hBinding - The RPC binding handle NetworkCodeSet - The codeset that the data will be translated to NetworkBufferSize - The number of bytes in the data ConversionType - Returns whether the conversion can be done inplace LocalBufferSize - Where to put the estimated buffer size status - The return status
--*/ { ulong LocalCP = CP_UNICODE;
// In Unicode the minimum character size is 2 so we can save a bit of
// memory cutting the apparent source buffer size
if ( CP_UNICODE == NetworkCodeSet ) NetworkBufferSize /= 2;
// No conversion is necessary if the local and destination codesets are
// the same.
GenericBufferSize( LocalCP, NetworkCodeSet, NetworkBufferSize, ConversionType, LocalBufferSize, status); }
void GenericCSConvert( unsigned long DestCodeSet, void *DestData, unsigned long DestBufferSize, unsigned long SourceCodeSet, void *SourceData, unsigned long SourceBufferSize, unsigned long *BytesWritten, error_status_t *status) /*++
Routine Description :
Convert data from one character encoding to another.
Arguments :
DestCodeSet - The target encoding DestData - The target buffer DestBufferSize - The size of the target buffer in bytes SourceCodeset - The source encoding SourceData - The source data SourceBufferSize - The size of the source data in bytes BytesWritten - The number of bytes written to the target buffer status - The return status
--*/ { wchar_t *TempBuffer = NULL; ulong BytesWrittenBuffer;
*status = RPC_S_OK;
// BytesWritten can be NULL in various circumstances. Make the following
// code a bit more generic by making sure it always points at something.
if ( NULL == BytesWritten ) BytesWritten = &BytesWrittenBuffer;
// If the source and destination code sets are the same, just memcpy.
// If there are 0 bytes in the source we don't need to do anything.
if ( DestCodeSet == SourceCodeSet || 0 == SourceBufferSize) { if ( DestBufferSize < SourceBufferSize ) { *status = RPC_S_BUFFER_TOO_SMALL; return; }
CopyMemory( DestData, SourceData, SourceBufferSize ); *BytesWritten = SourceBufferSize; return; }
// We can't convert from a non-Unicode codeset to a different non-Unicode
// codeset in one go, we have to convert to Unicode first. So regardless
// of what the destionation is supposed to be make the source Unicode.
if ( CP_UNICODE != SourceCodeSet ) { ulong TempBufferSize;
if ( CP_UNICODE != DestCodeSet ) { TempBufferSize = SourceBufferSize * 2; TempBuffer = (wchar_t *) I_RpcAllocate( TempBufferSize );
if ( NULL == TempBuffer ) RpcRaiseException( RPC_S_OUT_OF_MEMORY ); } else { TempBufferSize = DestBufferSize; TempBuffer = (wchar_t *) DestData; }
*BytesWritten = MultiByteToWideChar( SourceCodeSet, 0, (char *) SourceData, SourceBufferSize, TempBuffer, TempBufferSize / 2 );
if ( 0 == *BytesWritten ) *status = GetLastError();
*BytesWritten *= 2; SourceData = TempBuffer; SourceBufferSize = *BytesWritten; }
// Convert to the destination codeset if it's not Unicode.
if ( RPC_S_OK == *status && CP_UNICODE != DestCodeSet ) { *BytesWritten = WideCharToMultiByte( DestCodeSet, 0, (wchar_t *) SourceData, SourceBufferSize / 2, (char *) DestData, DestBufferSize, NULL, NULL);
if ( 0 == *BytesWritten ) *status = HRESULT_FROM_WIN32( GetLastError() ); }
if ( TempBuffer != DestData ) I_RpcFree( TempBuffer ); }
void RPC_ENTRY cs_byte_to_netcs( RPC_BINDING_HANDLE hBinding, unsigned long NetworkCodeSet, cs_byte * LocalData, unsigned long LocalDataLength, byte * NetworkData, unsigned long * NetworkDataLength, error_status_t * status) /*++
Routine Description :
Convert data from the current thread codeset to the network codeset
Arguments :
hBinding - The RPC binding handle NetworkCodeSet - The target codeset LocalData - The source data LocalDataLength - The size of the source data in bytes NetworkData - The target buffer NetworkDataLength - The number of bytes written to the target buffer status - The return status
--*/ { unsigned long LocalCP;
if ( ! GetThreadACP( &LocalCP, status ) ) return;
//
// For reasons known only to the gods, DCE didn't think it important to
// include the size of the destination buffer as a parameter. It
// *shouldn't* be an issue because in theory XXX_net_size was called to
// properly size the buffer. Just to be inconsistent, they did include
// it in XXX_from_netcs.
//
GenericCSConvert( NetworkCodeSet, NetworkData, INT_MAX, LocalCP, LocalData, LocalDataLength, NetworkDataLength, status); }
void RPC_ENTRY wchar_t_to_netcs( RPC_BINDING_HANDLE hBinding, unsigned long NetworkCodeSet, wchar_t * LocalData, unsigned long LocalDataLength, byte * NetworkData, unsigned long * NetworkDataLength, error_status_t * status) /*++
Routine Description :
Convert data from Unicode to the network codeset
Arguments :
hBinding - The RPC binding handle NetworkCodeSet - The target codeset LocalData - The source data LocalDataLength - The size of the source data in bytes NetworkData - The target buffer NetworkDataLength - The number of bytes written to the target buffer status - The return status
--*/ { unsigned long LocalCP = CP_UNICODE;
//
// For reasons known only to the gods, DCE didn't think it important to
// include the size of the destination buffer as a parameter. It
// *shouldn't* be an issue because in theory XXX_net_size was called to
// properly size the buffer. Just to be inconsistent, they did include
// it in XXX_from_netcs.
//
GenericCSConvert( NetworkCodeSet, NetworkData, INT_MAX, LocalCP, LocalData, LocalDataLength * 2, // We want bytes not chars
NetworkDataLength, status); }
void RPC_ENTRY cs_byte_from_netcs( RPC_BINDING_HANDLE hBinding, unsigned long NetworkCodeSet, cs_byte * NetworkData, unsigned long NetworkDataLength, unsigned long LocalDataBufferSize, byte * LocalData, unsigned long * LocalDataLength, error_status_t * status) /*++
Routine Description :
Convert data from the network codeset to the current thread codeset
Arguments :
hBinding - The RPC binding handle NetworkCodeSet - The source codeset NetworkData - The source data NetworkDataLength - The size of the source data in bytes LocalDataBufferSize - the size of the target buffer in bytes LocalData - The target buffer LocalDataLength - The number written to the target buffer status - The return status
--*/ { unsigned long LocalCP;
if ( ! GetThreadACP( &LocalCP, status ) ) return;
GenericCSConvert( LocalCP, LocalData, LocalDataBufferSize, NetworkCodeSet, NetworkData, NetworkDataLength, LocalDataLength, status); }
void RPC_ENTRY wchar_t_from_netcs( RPC_BINDING_HANDLE hBinding, unsigned long NetworkCodeSet, wchar_t * NetworkData, unsigned long NetworkDataLength, unsigned long LocalDataBufferSize, byte * LocalData, unsigned long * LocalDataLength, error_status_t * status) /*++
Routine Description :
Convert data from the network codeset to the current thread codeset
Arguments :
hBinding - The RPC binding handle NetworkCodeSet - The source codeset NetworkData - The source data NetworkDataLength - The size of the source data in bytes LocalDataBufferSize - the size of the target buffer in bytes LocalData - The target buffer LocalDataLength - The number written to the target buffer status - The return status
--*/ { unsigned long LocalCP = CP_UNICODE;
GenericCSConvert( LocalCP, LocalData, LocalDataBufferSize * 2, // Bytes not chars
NetworkCodeSet, NetworkData, NetworkDataLength, LocalDataLength, status);
if ( LocalDataLength ) *LocalDataLength /= 2; // Chars not bytes
}
void RPC_ENTRY RpcCsGetTags( handle_t hBinding, int ServerSide, unsigned long * SendingTag, unsigned long * DesiredReceivingTag, unsigned long * ReceivingTag, error_status_t * status) /*++
Routine Description :
Determine the codesets to use
Arguments :
hBinding - The RPC binding handle ServerSide - FALSE if this is the client SendingTag - Pointer to the returned sending tag DesiredReceivingTag - Pointer to the returned desired receiving tag ReceivingTag - Pointer to the returned receiving tag status - The return status
Notes :
On the server side, DesiredReceivingTag is an input instead of an output. The ReceivingTag will be set to this value.
--*/ { ulong Codeset;
if ( ! GetThreadACP( &Codeset, status ) ) return;
if ( SendingTag ) * SendingTag = Codeset;
if ( DesiredReceivingTag && ! ServerSide ) * DesiredReceivingTag = Codeset;
if ( ReceivingTag ) { if ( ServerSide && DesiredReceivingTag ) * ReceivingTag = * DesiredReceivingTag; else * ReceivingTag = Codeset; } * status = RPC_S_OK; }
|