2008-09-15 01:00:17 -05:00
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
// These are redefined in the project settings to prevent anyone from using them.
// We in this module are of a higher caste and thus are privileged in their use.
# ifdef strncpy
# undef strncpy
# endif
# ifdef _snprintf
# undef _snprintf
# endif
# if defined( sprintf )
# undef sprintf
# endif
# if defined( vsprintf )
# undef vsprintf
# endif
# ifdef _vsnprintf
# ifdef _WIN32
# undef _vsnprintf
# endif
# endif
# ifdef vsnprintf
# ifndef _WIN32
# undef vsnprintf
# endif
# endif
# if defined( strcat )
# undef strcat
# endif
# ifdef strncat
# undef strncat
# endif
// NOTE: I have to include stdio + stdarg first so vsnprintf gets compiled in
# include <stdio.h>
# include <stdarg.h>
# ifdef _LINUX
# include <ctype.h>
# include <unistd.h>
# include <stdlib.h>
# define _getcwd getcwd
# elif _WIN32
# include <direct.h>
# if !defined( _XBOX )
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# else
# include <xtl.h>
# endif
# endif
# ifdef _WIN32
# ifndef CP_UTF8
# define CP_UTF8 65001
# endif
# endif
# include "tier0/dbg.h"
# include "tier1/strtools.h"
# include <string.h>
# include <stdlib.h>
# include "tier0/basetypes.h"
# include "tier1/utldict.h"
# include "tier0/memdbgon.h"
void _V_memset ( const char * file , int line , void * dest , int fill , int count )
{
Assert ( count > = 0 ) ;
AssertValidWritePtr ( dest , count ) ;
memset ( dest , fill , count ) ;
}
void _V_memcpy ( const char * file , int line , void * dest , const void * src , int count )
{
Assert ( count > = 0 ) ;
AssertValidReadPtr ( src , count ) ;
AssertValidWritePtr ( dest , count ) ;
memcpy ( dest , src , count ) ;
}
void _V_memmove ( const char * file , int line , void * dest , const void * src , int count )
{
Assert ( count > = 0 ) ;
AssertValidReadPtr ( src , count ) ;
AssertValidWritePtr ( dest , count ) ;
memmove ( dest , src , count ) ;
}
int _V_memcmp ( const char * file , int line , const void * m1 , const void * m2 , int count )
{
Assert ( count > = 0 ) ;
AssertValidReadPtr ( m1 , count ) ;
AssertValidReadPtr ( m2 , count ) ;
return memcmp ( m1 , m2 , count ) ;
}
int _V_strlen ( const char * file , int line , const char * str )
{
AssertValidStringPtr ( str ) ;
return strlen ( str ) ;
}
void _V_strcpy ( const char * file , int line , char * dest , const char * src )
{
AssertValidWritePtr ( dest ) ;
AssertValidStringPtr ( src ) ;
strcpy ( dest , src ) ;
}
int _V_wcslen ( const char * file , int line , const wchar_t * pwch )
{
return wcslen ( pwch ) ;
}
char * _V_strrchr ( const char * file , int line , const char * s , char c )
{
AssertValidStringPtr ( s ) ;
int len = V_strlen ( s ) ;
s + = len ;
while ( len - - )
if ( * - - s = = c ) return ( char * ) s ;
return 0 ;
}
int _V_strcmp ( const char * file , int line , const char * s1 , const char * s2 )
{
AssertValidStringPtr ( s1 ) ;
AssertValidStringPtr ( s2 ) ;
return strcmp ( s1 , s2 ) ;
}
int _V_wcscmp ( const char * file , int line , const wchar_t * s1 , const wchar_t * s2 )
{
while ( 1 )
{
if ( * s1 ! = * s2 )
return - 1 ; // strings not equal
if ( ! * s1 )
return 0 ; // strings are equal
s1 + + ;
s2 + + ;
}
return - 1 ;
}
int _V_stricmp ( const char * file , int line , const char * s1 , const char * s2 )
{
AssertValidStringPtr ( s1 ) ;
AssertValidStringPtr ( s2 ) ;
return stricmp ( s1 , s2 ) ;
}
char * _V_strstr ( const char * file , int line , const char * s1 , const char * search )
{
AssertValidStringPtr ( s1 ) ;
AssertValidStringPtr ( search ) ;
2008-09-15 01:33:59 -05:00
// Casting the args to (char*) in order to get the overload of strstr() that returns a (char*) instead of (const char *). This is a change brought about by VS2005.
2008-09-15 01:00:17 -05:00
return strstr ( ( char * ) s1 , ( char * ) search ) ;
}
char * _V_strupr ( const char * file , int line , char * start )
{
AssertValidStringPtr ( start ) ;
return strupr ( start ) ;
}
char * _V_strlower ( const char * file , int line , char * start )
{
AssertValidStringPtr ( start ) ;
return strlwr ( start ) ;
}
int V_strncmp ( const char * s1 , const char * s2 , int count )
{
Assert ( count > = 0 ) ;
AssertValidStringPtr ( s1 , count ) ;
AssertValidStringPtr ( s2 , count ) ;
while ( count - - > 0 )
{
if ( * s1 ! = * s2 )
return * s1 < * s2 ? - 1 : 1 ; // string different
if ( * s1 = = ' \0 ' )
return 0 ; // null terminator hit - strings the same
s1 + + ;
s2 + + ;
}
return 0 ; // count characters compared the same
}
char * V_strnlwr ( char * s , size_t count )
{
Assert ( count > = 0 ) ;
AssertValidStringPtr ( s , count ) ;
char * pRet = s ;
if ( ! s )
return s ;
while ( - - count > = 0 )
{
if ( ! * s )
break ;
* s = tolower ( * s ) ;
+ + s ;
}
return pRet ;
}
int V_strncasecmp ( const char * s1 , const char * s2 , int n )
{
Assert ( n > = 0 ) ;
AssertValidStringPtr ( s1 ) ;
AssertValidStringPtr ( s2 ) ;
while ( n - - > 0 )
{
int c1 = * s1 + + ;
int c2 = * s2 + + ;
if ( c1 ! = c2 )
{
if ( c1 > = ' a ' & & c1 < = ' z ' )
c1 - = ( ' a ' - ' A ' ) ;
if ( c2 > = ' a ' & & c2 < = ' z ' )
c2 - = ( ' a ' - ' A ' ) ;
if ( c1 ! = c2 )
return c1 < c2 ? - 1 : 1 ;
}
if ( c1 = = ' \0 ' )
return 0 ; // null terminator hit - strings the same
}
return 0 ; // n characters compared the same
}
int V_strcasecmp ( const char * s1 , const char * s2 )
{
AssertValidStringPtr ( s1 ) ;
AssertValidStringPtr ( s2 ) ;
return V_strncasecmp ( s1 , s2 , 99999 ) ;
}
int V_strnicmp ( const char * s1 , const char * s2 , int n )
{
Assert ( n > = 0 ) ;
AssertValidStringPtr ( s1 ) ;
AssertValidStringPtr ( s2 ) ;
return V_strncasecmp ( s1 , s2 , n ) ;
}
int V_atoi ( const char * str )
{
AssertValidStringPtr ( str ) ;
int val ;
int sign ;
int c ;
Assert ( str ) ;
if ( * str = = ' - ' )
{
sign = - 1 ;
str + + ;
}
else
sign = 1 ;
val = 0 ;
//
// check for hex
//
if ( str [ 0 ] = = ' 0 ' & & ( str [ 1 ] = = ' x ' | | str [ 1 ] = = ' X ' ) )
{
str + = 2 ;
while ( 1 )
{
c = * str + + ;
if ( c > = ' 0 ' & & c < = ' 9 ' )
val = ( val < < 4 ) + c - ' 0 ' ;
else if ( c > = ' a ' & & c < = ' f ' )
val = ( val < < 4 ) + c - ' a ' + 10 ;
else if ( c > = ' A ' & & c < = ' F ' )
val = ( val < < 4 ) + c - ' A ' + 10 ;
else
return val * sign ;
}
}
//
// check for character
//
if ( str [ 0 ] = = ' \' ' )
{
return sign * str [ 1 ] ;
}
//
// assume decimal
//
while ( 1 )
{
c = * str + + ;
if ( c < ' 0 ' | | c > ' 9 ' )
return val * sign ;
val = val * 10 + c - ' 0 ' ;
}
return 0 ;
}
float V_atof ( const char * str )
{
AssertValidStringPtr ( str ) ;
double val ;
int sign ;
int c ;
int decimal , total ;
if ( * str = = ' - ' )
{
sign = - 1 ;
str + + ;
}
else
sign = 1 ;
val = 0 ;
//
// check for hex
//
if ( str [ 0 ] = = ' 0 ' & & ( str [ 1 ] = = ' x ' | | str [ 1 ] = = ' X ' ) )
{
str + = 2 ;
while ( 1 )
{
c = * str + + ;
if ( c > = ' 0 ' & & c < = ' 9 ' )
val = ( val * 16 ) + c - ' 0 ' ;
else if ( c > = ' a ' & & c < = ' f ' )
val = ( val * 16 ) + c - ' a ' + 10 ;
else if ( c > = ' A ' & & c < = ' F ' )
val = ( val * 16 ) + c - ' A ' + 10 ;
else
return val * sign ;
}
}
//
// check for character
//
if ( str [ 0 ] = = ' \' ' )
{
return sign * str [ 1 ] ;
}
//
// assume decimal
//
decimal = - 1 ;
total = 0 ;
while ( 1 )
{
c = * str + + ;
if ( c = = ' . ' )
{
decimal = total ;
continue ;
}
if ( c < ' 0 ' | | c > ' 9 ' )
break ;
val = val * 10 + c - ' 0 ' ;
total + + ;
}
if ( decimal = = - 1 )
return val * sign ;
while ( total > decimal )
{
val / = 10 ;
total - - ;
}
return val * sign ;
}
//-----------------------------------------------------------------------------
// Normalizes a float string in place.
//
// (removes leading zeros, trailing zeros after the decimal point, and the decimal point itself where possible)
//-----------------------------------------------------------------------------
void V_normalizeFloatString ( char * pFloat )
{
// If we have a decimal point, remove trailing zeroes:
if ( strchr ( pFloat , ' . ' ) )
{
int len = V_strlen ( pFloat ) ;
while ( len > 1 & & pFloat [ len - 1 ] = = ' 0 ' )
{
pFloat [ len - 1 ] = ' \0 ' ;
len - - ;
}
if ( len > 1 & & pFloat [ len - 1 ] = = ' . ' )
{
pFloat [ len - 1 ] = ' \0 ' ;
len - - ;
}
}
// TODO: Strip leading zeros
}
//-----------------------------------------------------------------------------
// Finds a string in another string with a case insensitive test
//-----------------------------------------------------------------------------
char const * V_stristr ( char const * pStr , char const * pSearch )
{
AssertValidStringPtr ( pStr ) ;
AssertValidStringPtr ( pSearch ) ;
if ( ! pStr | | ! pSearch )
return 0 ;
char const * pLetter = pStr ;
// Check the entire string
while ( * pLetter ! = 0 )
{
// Skip over non-matches
if ( tolower ( ( unsigned char ) * pLetter ) = = tolower ( ( unsigned char ) * pSearch ) )
{
// Check for match
char const * pMatch = pLetter + 1 ;
char const * pTest = pSearch + 1 ;
while ( * pTest ! = 0 )
{
// We've run off the end; don't bother.
if ( * pMatch = = 0 )
return 0 ;
if ( tolower ( ( unsigned char ) * pMatch ) ! = tolower ( ( unsigned char ) * pTest ) )
break ;
+ + pMatch ;
+ + pTest ;
}
// Found a match!
if ( * pTest = = 0 )
return pLetter ;
}
+ + pLetter ;
}
return 0 ;
}
char * V_stristr ( char * pStr , char const * pSearch )
{
AssertValidStringPtr ( pStr ) ;
AssertValidStringPtr ( pSearch ) ;
return ( char * ) V_stristr ( ( char const * ) pStr , pSearch ) ;
}
//-----------------------------------------------------------------------------
// Finds a string in another string with a case insensitive test w/ length validation
//-----------------------------------------------------------------------------
char const * V_strnistr ( char const * pStr , char const * pSearch , int n )
{
AssertValidStringPtr ( pStr ) ;
AssertValidStringPtr ( pSearch ) ;
if ( ! pStr | | ! pSearch )
return 0 ;
char const * pLetter = pStr ;
// Check the entire string
while ( * pLetter ! = 0 )
{
if ( n < = 0 )
return 0 ;
// Skip over non-matches
if ( tolower ( * pLetter ) = = tolower ( * pSearch ) )
{
int n1 = n - 1 ;
// Check for match
char const * pMatch = pLetter + 1 ;
char const * pTest = pSearch + 1 ;
while ( * pTest ! = 0 )
{
if ( n1 < = 0 )
return 0 ;
// We've run off the end; don't bother.
if ( * pMatch = = 0 )
return 0 ;
if ( tolower ( * pMatch ) ! = tolower ( * pTest ) )
break ;
+ + pMatch ;
+ + pTest ;
- - n1 ;
}
// Found a match!
if ( * pTest = = 0 )
return pLetter ;
}
+ + pLetter ;
- - n ;
}
return 0 ;
}
const char * V_strnchr ( const char * pStr , char c , int n )
{
char const * pLetter = pStr ;
char const * pLast = pStr + n ;
// Check the entire string
while ( ( pLetter < pLast ) & & ( * pLetter ! = 0 ) )
{
if ( * pLetter = = c )
return pLetter ;
+ + pLetter ;
}
return NULL ;
}
void V_strncpy ( char * pDest , char const * pSrc , int maxLen )
{
Assert ( maxLen > = 0 ) ;
AssertValidWritePtr ( pDest , maxLen ) ;
AssertValidStringPtr ( pSrc ) ;
strncpy ( pDest , pSrc , maxLen ) ;
if ( maxLen > 0 )
{
pDest [ maxLen - 1 ] = 0 ;
}
}
void V_wcsncpy ( wchar_t * pDest , wchar_t const * pSrc , int maxLenInBytes )
{
Assert ( maxLenInBytes > = 0 ) ;
AssertValidWritePtr ( pDest , maxLenInBytes ) ;
AssertValidReadPtr ( pSrc ) ;
int maxLen = maxLenInBytes / sizeof ( wchar_t ) ;
wcsncpy ( pDest , pSrc , maxLen ) ;
if ( maxLen )
{
pDest [ maxLen - 1 ] = 0 ;
}
}
int V_snprintf ( char * pDest , int maxLen , char const * pFormat , . . . )
{
Assert ( maxLen > = 0 ) ;
AssertValidWritePtr ( pDest , maxLen ) ;
AssertValidStringPtr ( pFormat ) ;
va_list marker ;
va_start ( marker , pFormat ) ;
# ifdef _WIN32
int len = _vsnprintf ( pDest , maxLen , pFormat , marker ) ;
# elif _LINUX
int len = vsnprintf ( pDest , maxLen , pFormat , marker ) ;
# else
# error "define vsnprintf type."
# endif
va_end ( marker ) ;
// Len < 0 represents an overflow
if ( len < 0 )
{
len = maxLen ;
pDest [ maxLen - 1 ] = 0 ;
}
return len ;
}
int V_vsnprintf ( char * pDest , int maxLen , char const * pFormat , va_list params )
{
Assert ( maxLen > 0 ) ;
AssertValidWritePtr ( pDest , maxLen ) ;
AssertValidStringPtr ( pFormat ) ;
int len = _vsnprintf ( pDest , maxLen , pFormat , params ) ;
if ( len < 0 )
{
len = maxLen ;
pDest [ maxLen - 1 ] = 0 ;
}
return len ;
}
//-----------------------------------------------------------------------------
// Purpose: If COPY_ALL_CHARACTERS == max_chars_to_copy then we try to add the whole pSrc to the end of pDest, otherwise
// we copy only as many characters as are specified in max_chars_to_copy (or the # of characters in pSrc if thats's less).
// Input : *pDest - destination buffer
// *pSrc - string to append
// destBufferSize - sizeof the buffer pointed to by pDest
// max_chars_to_copy - COPY_ALL_CHARACTERS in pSrc or max # to copy
// Output : char * the copied buffer
//-----------------------------------------------------------------------------
char * V_strncat ( char * pDest , const char * pSrc , size_t destBufferSize , int max_chars_to_copy )
{
size_t charstocopy = ( size_t ) 0 ;
Assert ( destBufferSize > = 0 ) ;
AssertValidStringPtr ( pDest ) ;
AssertValidStringPtr ( pSrc ) ;
size_t len = strlen ( pDest ) ;
size_t srclen = strlen ( pSrc ) ;
if ( max_chars_to_copy < = COPY_ALL_CHARACTERS )
{
charstocopy = srclen ;
}
else
{
2011-04-28 01:29:22 -05:00
charstocopy = ( size_t ) MIN ( max_chars_to_copy , ( int ) srclen ) ;
2008-09-15 01:00:17 -05:00
}
if ( len + charstocopy > = destBufferSize )
{
charstocopy = destBufferSize - len - 1 ;
}
if ( ! charstocopy )
{
return pDest ;
}
char * pOut = strncat ( pDest , pSrc , charstocopy ) ;
pOut [ destBufferSize - 1 ] = 0 ;
return pOut ;
}
//-----------------------------------------------------------------------------
// Purpose: Converts value into x.xx MB/ x.xx KB, x.xx bytes format, including commas
// Input : value -
// 2 -
// false -
// Output : char
//-----------------------------------------------------------------------------
# define NUM_PRETIFYMEM_BUFFERS 8
char * V_pretifymem ( float value , int digitsafterdecimal /*= 2*/ , bool usebinaryonek /*= false*/ )
{
static char output [ NUM_PRETIFYMEM_BUFFERS ] [ 32 ] ;
static int current ;
# ifdef _XBOX
// undo the confusing metric reports
usebinaryonek = true ;
# endif
float onekb = usebinaryonek ? 1024.0f : 1000.0f ;
float onemb = onekb * onekb ;
char * out = output [ current ] ;
current = ( current + 1 ) & ( NUM_PRETIFYMEM_BUFFERS - 1 ) ;
char suffix [ 8 ] ;
// First figure out which bin to use
if ( value > onemb )
{
value / = onemb ;
V_snprintf ( suffix , sizeof ( suffix ) , " MB " ) ;
}
else if ( value > onekb )
{
value / = onekb ;
V_snprintf ( suffix , sizeof ( suffix ) , " KB " ) ;
}
else
{
V_snprintf ( suffix , sizeof ( suffix ) , " bytes " ) ;
}
char val [ 32 ] ;
// Clamp to >= 0
2011-04-28 01:29:22 -05:00
digitsafterdecimal = MAX ( digitsafterdecimal , 0 ) ;
2008-09-15 01:00:17 -05:00
// If it's basically integral, don't do any decimals
if ( FloatMakePositive ( value - ( int ) value ) < 0.00001 )
{
V_snprintf ( val , sizeof ( val ) , " %i%s " , ( int ) value , suffix ) ;
}
else
{
char fmt [ 32 ] ;
// Otherwise, create a format string for the decimals
V_snprintf ( fmt , sizeof ( fmt ) , " %%.%if%s " , digitsafterdecimal , suffix ) ;
V_snprintf ( val , sizeof ( val ) , fmt , value ) ;
}
// Copy from in to out
char * i = val ;
char * o = out ;
// Search for decimal or if it was integral, find the space after the raw number
char * dot = strstr ( i , " . " ) ;
if ( ! dot )
{
dot = strstr ( i , " " ) ;
}
// Compute position of dot
int pos = dot - i ;
// Don't put a comma if it's <= 3 long
pos - = 3 ;
while ( * i )
{
// If pos is still valid then insert a comma every third digit, except if we would be
// putting one in the first spot
if ( pos > = 0 & & ! ( pos % 3 ) )
{
// Never in first spot
if ( o ! = out )
{
* o + + = ' , ' ;
}
}
// Count down comma position
pos - - ;
// Copy rest of data as normal
* o + + = * i + + ;
}
// Terminate
* o = 0 ;
return out ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns a string representation of an integer with commas
// separating the 1000s (ie, 37,426,421)
// Input : value - Value to convert
// Output : Pointer to a static buffer containing the output
//-----------------------------------------------------------------------------
# define NUM_PRETIFYNUM_BUFFERS 8
char * V_pretifynum ( int64 value )
{
static char output [ NUM_PRETIFYMEM_BUFFERS ] [ 32 ] ;
static int current ;
char * out = output [ current ] ;
current = ( current + 1 ) & ( NUM_PRETIFYMEM_BUFFERS - 1 ) ;
* out = 0 ;
// Render the leading -, if necessary
if ( value < 0 )
{
char * pchRender = out + V_strlen ( out ) ;
V_snprintf ( pchRender , 32 , " - " ) ;
value = - value ;
}
// Render quadrillions
2008-09-15 01:33:59 -05:00
if ( value > = 1000000000000LL )
2008-09-15 01:00:17 -05:00
{
char * pchRender = out + V_strlen ( out ) ;
2008-09-15 01:33:59 -05:00
V_snprintf ( pchRender , 32 , " %d, " , value / 1000000000000LL ) ;
2008-09-15 01:00:17 -05:00
}
// Render trillions
2008-09-15 01:33:59 -05:00
if ( value > = 1000000000000LL )
2008-09-15 01:00:17 -05:00
{
char * pchRender = out + V_strlen ( out ) ;
2008-09-15 01:33:59 -05:00
V_snprintf ( pchRender , 32 , " %d, " , value / 1000000000000LL ) ;
2008-09-15 01:00:17 -05:00
}
// Render billions
2008-09-15 01:33:59 -05:00
if ( value > = 1000000000LL )
2008-09-15 01:00:17 -05:00
{
char * pchRender = out + V_strlen ( out ) ;
2008-09-15 01:33:59 -05:00
V_snprintf ( pchRender , 32 , " %d, " , value / 1000000000LL ) ;
2008-09-15 01:00:17 -05:00
}
// Render millions
2008-09-15 01:33:59 -05:00
if ( value > = 1000000LL )
2008-09-15 01:00:17 -05:00
{
char * pchRender = out + V_strlen ( out ) ;
if ( value > = 1000000000 )
2008-09-15 01:33:59 -05:00
V_snprintf ( pchRender , 32 , " %03d, " , ( value / 1000000LL ) % 1000LL ) ;
2008-09-15 01:00:17 -05:00
else
2008-09-15 01:33:59 -05:00
V_snprintf ( pchRender , 32 , " %d, " , ( value / 1000000LL ) % 1000LL ) ;
2008-09-15 01:00:17 -05:00
}
// Render thousands
2008-09-15 01:33:59 -05:00
if ( value > = 1000LL )
2008-09-15 01:00:17 -05:00
{
char * pchRender = out + V_strlen ( out ) ;
if ( value > = 1000000 )
2008-09-15 01:33:59 -05:00
V_snprintf ( pchRender , 32 , " %03d, " , ( value / 1000LL ) % 1000LL ) ;
2008-09-15 01:00:17 -05:00
else
2008-09-15 01:33:59 -05:00
V_snprintf ( pchRender , 32 , " %d, " , ( value / 1000LL ) % 1000LL ) ;
2008-09-15 01:00:17 -05:00
}
// Render units
char * pchRender = out + V_strlen ( out ) ;
2008-09-15 01:33:59 -05:00
if ( value > 1000LL )
V_snprintf ( pchRender , 32 , " %03d " , value % 1000LL ) ;
2008-09-15 01:00:17 -05:00
else
2008-09-15 01:33:59 -05:00
V_snprintf ( pchRender , 32 , " %d " , value % 1000LL ) ;
2008-09-15 01:00:17 -05:00
return out ;
}
//-----------------------------------------------------------------------------
// Purpose: Converts a UTF8 string into a unicode string
//-----------------------------------------------------------------------------
int V_UTF8ToUnicode ( const char * pUTF8 , wchar_t * pwchDest , int cubDestSizeInBytes )
{
AssertValidStringPtr ( pUTF8 ) ;
AssertValidWritePtr ( pwchDest ) ;
pwchDest [ 0 ] = 0 ;
# ifdef _WIN32
int cchResult = MultiByteToWideChar ( CP_UTF8 , 0 , pUTF8 , - 1 , pwchDest , cubDestSizeInBytes / sizeof ( wchar_t ) ) ;
# elif _LINUX
int cchResult = mbstowcs ( pwchDest , pUTF8 , cubDestSizeInBytes / sizeof ( wchar_t ) ) ;
# endif
pwchDest [ ( cubDestSizeInBytes / sizeof ( wchar_t ) ) - 1 ] = 0 ;
return cchResult ;
}
//-----------------------------------------------------------------------------
// Purpose: Converts a unicode string into a UTF8 (standard) string
//-----------------------------------------------------------------------------
int V_UnicodeToUTF8 ( const wchar_t * pUnicode , char * pUTF8 , int cubDestSizeInBytes )
{
AssertValidStringPtr ( pUTF8 , cubDestSizeInBytes ) ;
AssertValidReadPtr ( pUnicode ) ;
pUTF8 [ 0 ] = 0 ;
# ifdef _WIN32
int cchResult = WideCharToMultiByte ( CP_UTF8 , 0 , pUnicode , - 1 , pUTF8 , cubDestSizeInBytes , NULL , NULL ) ;
# elif _LINUX
int cchResult = wcstombs ( pUTF8 , pUnicode , cubDestSizeInBytes ) ;
# endif
pUTF8 [ cubDestSizeInBytes - 1 ] = 0 ;
return cchResult ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the 4 bit nibble for a hex character
// Input : c -
// Output : unsigned char
//-----------------------------------------------------------------------------
static unsigned char V_nibble ( char c )
{
if ( ( c > = ' 0 ' ) & &
( c < = ' 9 ' ) )
{
return ( unsigned char ) ( c - ' 0 ' ) ;
}
if ( ( c > = ' A ' ) & &
( c < = ' F ' ) )
{
return ( unsigned char ) ( c - ' A ' + 0x0a ) ;
}
if ( ( c > = ' a ' ) & &
( c < = ' f ' ) )
{
return ( unsigned char ) ( c - ' a ' + 0x0a ) ;
}
return ' 0 ' ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *in -
// numchars -
// *out -
// maxoutputbytes -
//-----------------------------------------------------------------------------
void V_hextobinary ( char const * in , int numchars , byte * out , int maxoutputbytes )
{
int len = V_strlen ( in ) ;
2011-04-28 01:29:22 -05:00
numchars = MIN ( len , numchars ) ;
2008-09-15 01:00:17 -05:00
// Make sure it's even
numchars = ( numchars ) & ~ 0x1 ;
// Must be an even # of input characters (two chars per output byte)
Assert ( numchars > = 2 ) ;
memset ( out , 0x00 , maxoutputbytes ) ;
byte * p ;
int i ;
p = out ;
for ( i = 0 ;
( i < numchars ) & & ( ( p - out ) < maxoutputbytes ) ;
i + = 2 , p + + )
{
* p = ( V_nibble ( in [ i ] ) < < 4 ) | V_nibble ( in [ i + 1 ] ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *in -
// inputbytes -
// *out -
// outsize -
//-----------------------------------------------------------------------------
void V_binarytohex ( const byte * in , int inputbytes , char * out , int outsize )
{
Assert ( outsize > = 1 ) ;
char doublet [ 10 ] ;
int i ;
out [ 0 ] = 0 ;
for ( i = 0 ; i < inputbytes ; i + + )
{
unsigned char c = in [ i ] ;
V_snprintf ( doublet , sizeof ( doublet ) , " %02x " , c ) ;
V_strncat ( out , doublet , outsize , COPY_ALL_CHARACTERS ) ;
}
}
# if defined( _WIN32 ) || defined( WIN32 )
# define PATHSEPARATOR(c) ((c) == '\\' || (c) == ' / ')
# else //_WIN32
# define PATHSEPARATOR(c) ((c) == ' / ')
# endif //_WIN32
//-----------------------------------------------------------------------------
// Purpose: Extracts the base name of a file (no path, no extension, assumes '/' or '\' as path separator)
// Input : *in -
// *out -
// maxlen -
//-----------------------------------------------------------------------------
void V_FileBase ( const char * in , char * out , int maxlen )
{
Assert ( maxlen > = 1 ) ;
Assert ( in ) ;
Assert ( out ) ;
if ( ! in | | ! in [ 0 ] )
{
* out = 0 ;
return ;
}
int len , start , end ;
len = V_strlen ( in ) ;
// scan backward for '.'
end = len - 1 ;
while ( end & & in [ end ] ! = ' . ' & & ! PATHSEPARATOR ( in [ end ] ) )
{
end - - ;
}
if ( in [ end ] ! = ' . ' ) // no '.', copy to end
{
end = len - 1 ;
}
else
{
end - - ; // Found ',', copy to left of '.'
}
// Scan backward for '/'
start = len - 1 ;
while ( start > = 0 & & ! PATHSEPARATOR ( in [ start ] ) )
{
start - - ;
}
if ( start < 0 | | ! PATHSEPARATOR ( in [ start ] ) )
{
start = 0 ;
}
else
{
start + + ;
}
// Length of new sting
len = end - start + 1 ;
2011-04-28 01:29:22 -05:00
int maxcopy = MIN ( len + 1 , maxlen ) ;
2008-09-15 01:00:17 -05:00
// Copy partial string
V_strncpy ( out , & in [ start ] , maxcopy ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *ppath -
//-----------------------------------------------------------------------------
void V_StripTrailingSlash ( char * ppath )
{
Assert ( ppath ) ;
int len = V_strlen ( ppath ) ;
if ( len > 0 )
{
if ( PATHSEPARATOR ( ppath [ len - 1 ] ) )
{
ppath [ len - 1 ] = 0 ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *in -
// *out -
// outSize -
//-----------------------------------------------------------------------------
void V_StripExtension ( const char * in , char * out , int outSize )
{
// Find the last dot. If it's followed by a dot or a slash, then it's part of a
// directory specifier like ../../somedir/./blah.
const char * pLastExt = in ;
const char * pTest = strrchr ( pLastExt , ' . ' ) ;
if ( pTest )
{
// This handles things like ".\blah" or "c:\my@email.com\abc\def\geh"
// Which would otherwise wind up with "" and "c:\my@email", respectively.
if ( strrchr ( in , ' \\ ' ) < pTest & & strrchr ( in , ' / ' ) < pTest )
{
pLastExt = pTest + 1 ;
}
}
// Copy up to the last dot.
if ( pLastExt > in )
{
int nChars = pLastExt - in - 1 ;
2011-04-28 01:29:22 -05:00
nChars = MIN ( nChars , outSize - 1 ) ;
2008-09-15 01:00:17 -05:00
memcpy ( out , in , nChars ) ;
out [ nChars ] = 0 ;
}
else
{
if ( out ! = in )
{
V_strncpy ( out , in , outSize ) ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *path -
// *extension -
// pathStringLength -
//-----------------------------------------------------------------------------
void V_DefaultExtension ( char * path , const char * extension , int pathStringLength )
{
Assert ( path ) ;
Assert ( pathStringLength > = 1 ) ;
Assert ( extension ) ;
Assert ( extension [ 0 ] = = ' . ' ) ;
char * src ;
// if path doesn't have a .EXT, append extension
// (extension should include the .)
src = path + V_strlen ( path ) - 1 ;
while ( ! PATHSEPARATOR ( * src ) & & ( src > path ) )
{
if ( * src = = ' . ' )
{
// it has an extension
return ;
}
src - - ;
}
// Concatenate the desired extension
V_strncat ( path , extension , pathStringLength , COPY_ALL_CHARACTERS ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Force extension...
// Input : *path -
// *extension -
// pathStringLength -
//-----------------------------------------------------------------------------
void V_SetExtension ( char * path , const char * extension , int pathStringLength )
{
V_StripExtension ( path , path , pathStringLength ) ;
V_DefaultExtension ( path , extension , pathStringLength ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Remove final filename from string
// Input : *path -
// Output : void V_StripFilename
//-----------------------------------------------------------------------------
void V_StripFilename ( char * path )
{
int length ;
length = V_strlen ( path ) - 1 ;
if ( length < = 0 )
return ;
while ( length > 0 & &
! PATHSEPARATOR ( path [ length ] ) )
{
length - - ;
}
path [ length ] = 0 ;
}
# ifdef _WIN32
# define CORRECT_PATH_SEPARATOR '\\'
# define INCORRECT_PATH_SEPARATOR ' / '
# elif _LINUX
# define CORRECT_PATH_SEPARATOR ' / '
# define INCORRECT_PATH_SEPARATOR '\\'
# endif
//-----------------------------------------------------------------------------
// Purpose: Changes all '/' or '\' characters into separator
// Input : *pname -
// separator -
//-----------------------------------------------------------------------------
void V_FixSlashes ( char * pname , char separator /* = CORRECT_PATH_SEPARATOR */ )
{
while ( * pname )
{
if ( * pname = = INCORRECT_PATH_SEPARATOR | | * pname = = CORRECT_PATH_SEPARATOR )
{
* pname = separator ;
}
pname + + ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Strip off the last directory from dirName
// Input : *dirName -
// maxlen -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool V_StripLastDir ( char * dirName , int maxlen )
{
if ( dirName [ 0 ] = = 0 | |
! V_stricmp ( dirName , " ./ " ) | |
! V_stricmp ( dirName , " . \\ " ) )
return false ;
int len = V_strlen ( dirName ) ;
Assert ( len < maxlen ) ;
// skip trailing slash
if ( PATHSEPARATOR ( dirName [ len - 1 ] ) )
{
len - - ;
}
while ( len > 0 )
{
if ( PATHSEPARATOR ( dirName [ len - 1 ] ) )
{
dirName [ len ] = 0 ;
V_FixSlashes ( dirName , CORRECT_PATH_SEPARATOR ) ;
return true ;
}
len - - ;
}
// Allow it to return an empty string and true. This can happen if something like "tf2/" is passed in.
// The correct behavior is to strip off the last directory ("tf2") and return true.
if ( len = = 0 )
{
V_snprintf ( dirName , maxlen , " .%c " , CORRECT_PATH_SEPARATOR ) ;
return true ;
}
return true ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns a pointer to the beginning of the unqualified file name
// (no path information)
// Input: in - file name (may be unqualified, relative or absolute path)
// Output: pointer to unqualified file name
//-----------------------------------------------------------------------------
const char * V_UnqualifiedFileName ( const char * in )
{
// back up until the character after the first path separator we find,
// or the beginning of the string
const char * out = in + strlen ( in ) - 1 ;
while ( ( out > in ) & & ( ! PATHSEPARATOR ( * ( out - 1 ) ) ) )
out - - ;
return out ;
}
//-----------------------------------------------------------------------------
// Purpose: Composes a path and filename together, inserting a path separator
// if need be
// Input: path - path to use
// filename - filename to use
// dest - buffer to compose result in
// destSize - size of destination buffer
//-----------------------------------------------------------------------------
void V_ComposeFileName ( const char * path , const char * filename , char * dest , int destSize )
{
V_strncpy ( dest , path , destSize ) ;
V_AppendSlash ( dest , destSize ) ;
V_strncat ( dest , filename , destSize , COPY_ALL_CHARACTERS ) ;
V_FixSlashes ( dest ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *path -
// *dest -
// destSize -
// Output : void V_ExtractFilePath
//-----------------------------------------------------------------------------
bool V_ExtractFilePath ( const char * path , char * dest , int destSize )
{
Assert ( destSize > = 1 ) ;
if ( destSize < 1 )
{
return false ;
}
// Last char
int len = V_strlen ( path ) ;
const char * src = path + ( len ? len - 1 : 0 ) ;
// back up until a \ or the start
while ( src ! = path & & ! PATHSEPARATOR ( * ( src - 1 ) ) )
{
src - - ;
}
2011-04-28 01:29:22 -05:00
int copysize = MIN ( src - path , destSize - 1 ) ;
2008-09-15 01:00:17 -05:00
memcpy ( dest , path , copysize ) ;
dest [ copysize ] = 0 ;
return copysize ! = 0 ? true : false ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *path -
// *dest -
// destSize -
// Output : void V_ExtractFileExtension
//-----------------------------------------------------------------------------
void V_ExtractFileExtension ( const char * path , char * dest , int destSize )
{
2008-09-15 01:33:59 -05:00
* dest = ' \0 ' ;
2008-09-15 01:00:17 -05:00
const char * extension = V_GetFileExtension ( path ) ;
if ( NULL ! = extension )
V_strncpy ( dest , extension , destSize ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns a pointer to the file extension within a file name string
// Input: in - file name
// Output: pointer to beginning of extension (after the "."), or NULL
// if there is no extension
//-----------------------------------------------------------------------------
const char * V_GetFileExtension ( const char * path )
{
const char * src ;
src = path + strlen ( path ) - 1 ;
//
// back up until a . or the start
//
while ( src ! = path & & * ( src - 1 ) ! = ' . ' )
src - - ;
// check to see if the '.' is part of a pathname
if ( src = = path | | PATHSEPARATOR ( * src ) )
{
return NULL ; // no extension
}
return src ;
}
bool V_RemoveDotSlashes ( char * pFilename )
{
// Get rid of "./"'s
char * pIn = pFilename ;
char * pOut = pFilename ;
while ( * pIn )
{
// The logic on the second line is preventing it from screwing up "../"
if ( pIn [ 0 ] = = ' . ' & & PATHSEPARATOR ( pIn [ 1 ] ) & &
( pIn = = pFilename | | pIn [ - 1 ] ! = ' . ' ) )
{
pIn + = 2 ;
}
else
{
* pOut = * pIn ;
+ + pIn ;
+ + pOut ;
}
}
* pOut = 0 ;
// Get rid of a trailing "/." (needless).
int len = strlen ( pFilename ) ;
if ( len > 2 & & pFilename [ len - 1 ] = = ' . ' & & PATHSEPARATOR ( pFilename [ len - 2 ] ) )
{
pFilename [ len - 2 ] = 0 ;
}
// Each time we encounter a "..", back up until we've read the previous directory name,
// then get rid of it.
pIn = pFilename ;
while ( * pIn )
{
if ( pIn [ 0 ] = = ' . ' & &
pIn [ 1 ] = = ' . ' & &
( pIn = = pFilename | | PATHSEPARATOR ( pIn [ - 1 ] ) ) & & // Preceding character must be a slash.
( pIn [ 2 ] = = 0 | | PATHSEPARATOR ( pIn [ 2 ] ) ) ) // Following character must be a slash or the end of the string.
{
char * pEndOfDots = pIn + 2 ;
char * pStart = pIn - 2 ;
// Ok, now scan back for the path separator that starts the preceding directory.
while ( 1 )
{
if ( pStart < pFilename )
return false ;
if ( PATHSEPARATOR ( * pStart ) )
break ;
- - pStart ;
}
// Now slide the string down to get rid of the previous directory and the ".."
memmove ( pStart , pEndOfDots , strlen ( pEndOfDots ) + 1 ) ;
// Start over.
pIn = pFilename ;
}
else
{
+ + pIn ;
}
}
V_FixSlashes ( pFilename ) ;
return true ;
}
void V_AppendSlash ( char * pStr , int strSize )
{
int len = V_strlen ( pStr ) ;
if ( len > 0 & & ! PATHSEPARATOR ( pStr [ len - 1 ] ) )
{
if ( len + 1 > = strSize )
Error ( " V_AppendSlash: ran out of space on %s. " , pStr ) ;
pStr [ len ] = CORRECT_PATH_SEPARATOR ;
pStr [ len + 1 ] = 0 ;
}
}
void V_MakeAbsolutePath ( char * pOut , int outLen , const char * pPath , const char * pStartingDir )
{
if ( V_IsAbsolutePath ( pPath ) )
{
// pPath is not relative.. just copy it.
V_strncpy ( pOut , pPath , outLen ) ;
}
else
{
// Make sure the starting directory is absolute..
if ( pStartingDir & & V_IsAbsolutePath ( pStartingDir ) )
{
V_strncpy ( pOut , pStartingDir , outLen ) ;
}
else
{
# ifndef _XBOX
if ( ! _getcwd ( pOut , outLen ) )
Error ( " V_MakeAbsolutePath: _getcwd failed. " ) ;
# else
Assert ( 0 ) ;
if ( outLen )
* pOut = 0 ;
# endif
if ( pStartingDir )
{
V_AppendSlash ( pOut , outLen ) ;
V_strncat ( pOut , pStartingDir , outLen , COPY_ALL_CHARACTERS ) ;
}
}
// Concatenate the paths.
V_AppendSlash ( pOut , outLen ) ;
V_strncat ( pOut , pPath , outLen , COPY_ALL_CHARACTERS ) ;
}
if ( ! V_RemoveDotSlashes ( pOut ) )
Error ( " V_MakeAbsolutePath: tried to \" .. \" past the root. " ) ;
V_FixSlashes ( pOut ) ;
}
// small helper function shared by lots of modules
bool V_IsAbsolutePath ( const char * pStr )
{
return ( pStr [ 0 ] & & pStr [ 1 ] = = ' : ' ) | | pStr [ 0 ] = = ' / ' | | pStr [ 0 ] = = ' \\ ' ;
}
// Copies at most nCharsToCopy bytes from pIn into pOut.
// Returns false if it would have overflowed pOut's buffer.
static bool CopyToMaxChars ( char * pOut , int outSize , const char * pIn , int nCharsToCopy )
{
if ( outSize = = 0 )
return false ;
int iOut = 0 ;
while ( * pIn & & nCharsToCopy > 0 )
{
if ( iOut = = ( outSize - 1 ) )
{
pOut [ iOut ] = 0 ;
return false ;
}
pOut [ iOut ] = * pIn ;
+ + iOut ;
+ + pIn ;
- - nCharsToCopy ;
}
pOut [ iOut ] = 0 ;
return true ;
}
// Returns true if it completed successfully.
// If it would overflow pOut, it fills as much as it can and returns false.
bool V_StrSubst (
const char * pIn ,
const char * pMatch ,
const char * pReplaceWith ,
char * pOut ,
int outLen ,
bool bCaseSensitive
)
{
int replaceFromLen = strlen ( pMatch ) ;
int replaceToLen = strlen ( pReplaceWith ) ;
const char * pInStart = pIn ;
char * pOutPos = pOut ;
pOutPos [ 0 ] = 0 ;
while ( 1 )
{
int nRemainingOut = outLen - ( pOutPos - pOut ) ;
const char * pTestPos = ( bCaseSensitive ? strstr ( pInStart , pMatch ) : V_stristr ( pInStart , pMatch ) ) ;
if ( pTestPos )
{
// Found an occurence of pMatch. First, copy whatever leads up to the string.
int copyLen = pTestPos - pInStart ;
if ( ! CopyToMaxChars ( pOutPos , nRemainingOut , pInStart , copyLen ) )
return false ;
// Did we hit the end of the output string?
if ( copyLen > nRemainingOut - 1 )
return false ;
pOutPos + = strlen ( pOutPos ) ;
nRemainingOut = outLen - ( pOutPos - pOut ) ;
// Now add the replacement string.
if ( ! CopyToMaxChars ( pOutPos , nRemainingOut , pReplaceWith , replaceToLen ) )
return false ;
pInStart + = copyLen + replaceFromLen ;
pOutPos + = replaceToLen ;
}
else
{
// We're at the end of pIn. Copy whatever remains and get out.
int copyLen = strlen ( pInStart ) ;
V_strncpy ( pOutPos , pInStart , nRemainingOut ) ;
return ( copyLen < = nRemainingOut - 1 ) ;
}
}
}
char * AllocString ( const char * pStr , int nMaxChars )
{
int allocLen ;
if ( nMaxChars = = - 1 )
allocLen = strlen ( pStr ) + 1 ;
else
2011-04-28 01:29:22 -05:00
allocLen = MIN ( ( int ) strlen ( pStr ) , nMaxChars ) + 1 ;
2008-09-15 01:00:17 -05:00
char * pOut = new char [ allocLen ] ;
V_strncpy ( pOut , pStr , allocLen ) ;
return pOut ;
}
void V_SplitString2 ( const char * pString , const char * * pSeparators , int nSeparators , CUtlVector < char * > & outStrings )
{
outStrings . Purge ( ) ;
const char * pCurPos = pString ;
while ( 1 )
{
int iFirstSeparator = - 1 ;
const char * pFirstSeparator = 0 ;
for ( int i = 0 ; i < nSeparators ; i + + )
{
const char * pTest = V_stristr ( pCurPos , pSeparators [ i ] ) ;
if ( pTest & & ( ! pFirstSeparator | | pTest < pFirstSeparator ) )
{
iFirstSeparator = i ;
pFirstSeparator = pTest ;
}
}
if ( pFirstSeparator )
{
// Split on this separator and continue on.
int separatorLen = strlen ( pSeparators [ iFirstSeparator ] ) ;
if ( pFirstSeparator > pCurPos )
{
outStrings . AddToTail ( AllocString ( pCurPos , pFirstSeparator - pCurPos ) ) ;
}
pCurPos = pFirstSeparator + separatorLen ;
}
else
{
// Copy the rest of the string
if ( strlen ( pCurPos ) )
{
outStrings . AddToTail ( AllocString ( pCurPos , - 1 ) ) ;
}
return ;
}
}
}
void V_SplitString ( const char * pString , const char * pSeparator , CUtlVector < char * > & outStrings )
{
V_SplitString2 ( pString , & pSeparator , 1 , outStrings ) ;
}
// This function takes a slice out of pStr and stores it in pOut.
// It follows the Python slice convention:
// Negative numbers wrap around the string (-1 references the last character).
// Numbers are clamped to the end of the string.
void V_StrSlice ( const char * pStr , int firstChar , int lastCharNonInclusive , char * pOut , int outSize )
{
if ( outSize = = 0 )
return ;
int length = strlen ( pStr ) ;
// Fixup the string indices.
if ( firstChar < 0 )
{
firstChar = length - ( - firstChar % length ) ;
}
else if ( firstChar > = length )
{
pOut [ 0 ] = 0 ;
return ;
}
if ( lastCharNonInclusive < 0 )
{
lastCharNonInclusive = length - ( - lastCharNonInclusive % length ) ;
}
else if ( lastCharNonInclusive > length )
{
lastCharNonInclusive % = length ;
}
if ( lastCharNonInclusive < = firstChar )
{
pOut [ 0 ] = 0 ;
return ;
}
int copyLen = lastCharNonInclusive - firstChar ;
if ( copyLen < = ( outSize - 1 ) )
{
memcpy ( pOut , & pStr [ firstChar ] , copyLen ) ;
pOut [ copyLen ] = 0 ;
}
else
{
memcpy ( pOut , & pStr [ firstChar ] , outSize - 1 ) ;
pOut [ outSize - 1 ] = 0 ;
}
}
void V_StrLeft ( const char * pStr , int nChars , char * pOut , int outSize )
{
if ( nChars = = 0 )
{
if ( outSize ! = 0 )
pOut [ 0 ] = 0 ;
return ;
}
V_StrSlice ( pStr , 0 , nChars , pOut , outSize ) ;
}
void V_StrRight ( const char * pStr , int nChars , char * pOut , int outSize )
{
int len = strlen ( pStr ) ;
if ( nChars > = len )
{
V_strncpy ( pOut , pStr , outSize ) ;
}
else
{
V_StrSlice ( pStr , - nChars , strlen ( pStr ) , pOut , outSize ) ;
}
}
//-----------------------------------------------------------------------------
// Convert multibyte to wchar + back
//-----------------------------------------------------------------------------
# ifndef _XBOX
void V_strtowcs ( const char * pString , int nInSize , wchar_t * pWString , int nOutSize )
{
# ifdef _WIN32
if ( ! MultiByteToWideChar ( CP_UTF8 , 0 , pString , nInSize , pWString , nOutSize ) )
{
* pWString = L ' \0 ' ;
}
# elif _LINUX
if ( mbstowcs ( pWString , pString , nOutSize / sizeof ( wchar_t ) ) < = 0 )
{
* pWString = 0 ;
}
# endif
}
void V_wcstostr ( const wchar_t * pWString , int nInSize , char * pString , int nOutSize )
{
# ifdef _WIN32
if ( ! WideCharToMultiByte ( CP_UTF8 , 0 , pWString , nInSize , pString , nOutSize , NULL , NULL ) )
{
* pString = ' \0 ' ;
}
# elif _LINUX
if ( wcstombs ( pString , pWString , nOutSize ) < = 0 )
{
* pString = ' \0 ' ;
}
# endif
}
# endif