845 lines
19 KiB
C++
845 lines
19 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1997 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
string.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Vlad Sadovsky (vlads) 26-Jan-1997
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
26-Jan-1997 VladS created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
//
|
||
|
// Normal includes only for this module to be active
|
||
|
//
|
||
|
|
||
|
#include "cplusinc.h"
|
||
|
#include "sticomm.h"
|
||
|
|
||
|
//
|
||
|
// Private Definations
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// When appending data, this is the extra amount we request to avoid
|
||
|
// reallocations
|
||
|
//
|
||
|
#define STR_SLOP 128
|
||
|
|
||
|
//
|
||
|
// Converts a value between zero and fifteen to the appropriate hex digit
|
||
|
//
|
||
|
#define HEXDIGIT( nDigit ) \
|
||
|
(TCHAR)((nDigit) > 9 ? \
|
||
|
(nDigit) - 10 + 'A' \
|
||
|
: (nDigit) + '0')
|
||
|
|
||
|
//
|
||
|
// Converts a single hex digit to its decimal equivalent
|
||
|
//
|
||
|
#define TOHEX( ch ) \
|
||
|
((ch) > '9' ? \
|
||
|
(ch) >= 'a' ? \
|
||
|
(ch) - 'a' + 10 : \
|
||
|
(ch) - 'A' + 10 \
|
||
|
: (ch) - '0')
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Private Globals
|
||
|
//
|
||
|
|
||
|
WCHAR STR::_pszEmptyString[] = L"";
|
||
|
|
||
|
//
|
||
|
// Construction/Destruction
|
||
|
//
|
||
|
STR::STR( const CHAR * pchInit )
|
||
|
{
|
||
|
AuxInit( (PBYTE) pchInit, FALSE );
|
||
|
}
|
||
|
|
||
|
STR::STR( const WCHAR * pwchInit )
|
||
|
{
|
||
|
AuxInit( (PBYTE) pwchInit, TRUE );
|
||
|
}
|
||
|
|
||
|
STR::STR( const STR & str )
|
||
|
{
|
||
|
AuxInit( (PBYTE) str.QueryPtr(), str.IsUnicode() );
|
||
|
}
|
||
|
|
||
|
VOID STR::AuxInit( PBYTE pInit, BOOL fUnicode )
|
||
|
{
|
||
|
BOOL fRet;
|
||
|
|
||
|
_fUnicode = fUnicode;
|
||
|
_fValid = TRUE;
|
||
|
|
||
|
if ( pInit )
|
||
|
{
|
||
|
INT cbCopy = fUnicode ? (::wcslen( (WCHAR *) pInit ) + 1) * sizeof(WCHAR) :
|
||
|
(::strlen( (CHAR *) pInit ) + 1) * sizeof(CHAR);
|
||
|
|
||
|
fRet = Resize( cbCopy );
|
||
|
|
||
|
|
||
|
if ( !fRet )
|
||
|
{
|
||
|
_fValid = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
::memcpy( QueryPtr(), pInit, cbCopy );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Appends the string onto this one.
|
||
|
//
|
||
|
|
||
|
BOOL STR::Append( const CHAR * pchStr )
|
||
|
{
|
||
|
if ( pchStr )
|
||
|
{
|
||
|
ASSERT( !IsUnicode() );
|
||
|
|
||
|
return AuxAppend( (PBYTE) pchStr, ::strlen( pchStr ) );
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL STR::Append( const WCHAR * pwchStr )
|
||
|
{
|
||
|
if ( pwchStr )
|
||
|
{
|
||
|
ASSERT( IsUnicode() );
|
||
|
|
||
|
return AuxAppend( (PBYTE) pwchStr, ::wcslen( pwchStr ) * sizeof(WCHAR) );
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL STR::Append( const STR & str )
|
||
|
{
|
||
|
if ( str.IsUnicode() )
|
||
|
return Append( (const WCHAR *) str.QueryStrW() );
|
||
|
else
|
||
|
return Append( (const CHAR *) str.QueryStrA() );
|
||
|
}
|
||
|
|
||
|
BOOL STR::AuxAppend( PBYTE pStr, UINT cbStr, BOOL fAddSlop )
|
||
|
{
|
||
|
ASSERT( pStr != NULL );
|
||
|
|
||
|
UINT cbThis = QueryCB();
|
||
|
|
||
|
//
|
||
|
// Only resize when we have to. When we do resize, we tack on
|
||
|
// some extra space to avoid extra reallocations.
|
||
|
//
|
||
|
// Note: QuerySize returns the requested size of the string buffer,
|
||
|
// *not* the strlen of the buffer
|
||
|
//
|
||
|
|
||
|
if ( QuerySize() < cbThis + cbStr + sizeof(WCHAR) )
|
||
|
{
|
||
|
if ( !Resize( cbThis + cbStr + (fAddSlop ? STR_SLOP : sizeof(WCHAR) )) )
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
memcpy( (BYTE *) QueryPtr() + cbThis,
|
||
|
pStr,
|
||
|
cbStr + (IsUnicode() ? sizeof(WCHAR) : sizeof(CHAR)) );
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Convert in place
|
||
|
//
|
||
|
BOOL STR::ConvertToW(VOID)
|
||
|
{
|
||
|
if (IsUnicode()) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
UINT cbNeeded = (QueryCB()+1)*sizeof(WCHAR);
|
||
|
|
||
|
//
|
||
|
// Only resize when we have to.
|
||
|
//
|
||
|
if ( QuerySize() < cbNeeded ) {
|
||
|
if ( !Resize( cbNeeded)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BUFFER buf(cbNeeded);
|
||
|
|
||
|
if (!buf.QueryPtr()) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
int iRet;
|
||
|
int cch;
|
||
|
|
||
|
cch = QueryCCH() + 1;
|
||
|
|
||
|
iRet = MultiByteToWideChar( CP_ACP,
|
||
|
MB_PRECOMPOSED,
|
||
|
QueryStrA(),
|
||
|
-1,
|
||
|
(WCHAR *)buf.QueryPtr(),
|
||
|
cch);
|
||
|
|
||
|
if ( iRet == 0 ) {
|
||
|
|
||
|
//
|
||
|
// Error in conversion.
|
||
|
//
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
memcpy( (BYTE *) QueryPtr(),
|
||
|
buf.QueryPtr(),
|
||
|
cbNeeded);
|
||
|
|
||
|
SetUnicode(TRUE);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL STR::ConvertToA(VOID)
|
||
|
{
|
||
|
if (!IsUnicode()) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
UINT cbNeeded = (QueryCB()+1)*sizeof(CHAR);
|
||
|
BUFFER buf(cbNeeded);
|
||
|
|
||
|
if (!buf.QueryPtr()) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
int iRet;
|
||
|
int cch;
|
||
|
|
||
|
cch = cbNeeded;
|
||
|
|
||
|
iRet = WideCharToMultiByte(CP_ACP,
|
||
|
0L,
|
||
|
QueryStrW(),
|
||
|
-1,
|
||
|
(CHAR *)buf.QueryPtr(),
|
||
|
cch,
|
||
|
NULL,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if ( iRet == 0 ) {
|
||
|
|
||
|
//
|
||
|
// Error in conversion.
|
||
|
//
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Careful here , there might be DBCS characters in resultant buffer
|
||
|
memcpy( (BYTE *) QueryPtr(),
|
||
|
buf.QueryPtr(),
|
||
|
iRet);
|
||
|
|
||
|
SetUnicode(FALSE);
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Copies the string into this one.
|
||
|
//
|
||
|
|
||
|
|
||
|
BOOL STR::Copy( const CHAR * pchStr )
|
||
|
{
|
||
|
_fUnicode = FALSE;
|
||
|
|
||
|
if ( QueryPtr() )
|
||
|
*(QueryStrA()) = '\0';
|
||
|
|
||
|
if ( pchStr )
|
||
|
{
|
||
|
return AuxAppend( (PBYTE) pchStr, ::strlen( pchStr ), FALSE );
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL STR::Copy( const WCHAR * pwchStr )
|
||
|
{
|
||
|
_fUnicode = TRUE;
|
||
|
|
||
|
if ( QueryPtr() )
|
||
|
*(QueryStrW()) = TEXT('\0');
|
||
|
|
||
|
if ( pwchStr )
|
||
|
{
|
||
|
return AuxAppend( (PBYTE) pwchStr, ::wcslen( pwchStr ) * sizeof(WCHAR), FALSE );
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL STR::Copy( const STR & str )
|
||
|
{
|
||
|
_fUnicode = str.IsUnicode();
|
||
|
|
||
|
if ( str.IsEmpty() && QueryPtr() == NULL) {
|
||
|
|
||
|
// To avoid pathological allocation of small chunk of memory
|
||
|
return ( TRUE);
|
||
|
}
|
||
|
|
||
|
if ( str.IsUnicode() )
|
||
|
return Copy( str.QueryStrW() );
|
||
|
else
|
||
|
return Copy( str.QueryStrA() );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Resizes or allocates string memory, NULL terminating if necessary
|
||
|
//
|
||
|
|
||
|
BOOL STR::Resize( UINT cbNewRequestedSize )
|
||
|
{
|
||
|
BOOL fTerminate = QueryPtr() == NULL;
|
||
|
|
||
|
if ( !BUFFER::Resize( cbNewRequestedSize ))
|
||
|
return FALSE;
|
||
|
|
||
|
if ( fTerminate && cbNewRequestedSize > 0 )
|
||
|
{
|
||
|
if ( IsUnicode() )
|
||
|
{
|
||
|
ASSERT( cbNewRequestedSize > 1 );
|
||
|
*QueryStrW() = TEXT('\0');
|
||
|
}
|
||
|
else
|
||
|
*QueryStrA() = '\0';
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Loads a string resource from this module's string table
|
||
|
// or from the system string table
|
||
|
//
|
||
|
// dwResID - System error or module string ID
|
||
|
// lpszModuleName - name of the module from which to load.
|
||
|
// If NULL, then load the string from system table.
|
||
|
//
|
||
|
//
|
||
|
BOOL STR::LoadString( IN DWORD dwResID,
|
||
|
IN LPCTSTR lpszModuleName // Optional
|
||
|
)
|
||
|
{
|
||
|
BOOL fReturn = FALSE;
|
||
|
INT cch;
|
||
|
|
||
|
//
|
||
|
// If lpszModuleName is NULL, load the string from system's string table.
|
||
|
//
|
||
|
|
||
|
if ( lpszModuleName == NULL) {
|
||
|
|
||
|
BYTE * pchBuff = NULL;
|
||
|
|
||
|
//
|
||
|
// Call the appropriate function so we don't have to do the Unicode
|
||
|
// conversion
|
||
|
//
|
||
|
|
||
|
if ( IsUnicode() ) {
|
||
|
|
||
|
cch = ::FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
|
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||
|
FORMAT_MESSAGE_MAX_WIDTH_MASK |
|
||
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL,
|
||
|
dwResID,
|
||
|
0,
|
||
|
(LPWSTR) &pchBuff,
|
||
|
1024,
|
||
|
NULL );
|
||
|
if ( cch ) {
|
||
|
|
||
|
fReturn = Copy( (LPCWSTR) pchBuff );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cch = ::FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
|
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||
|
FORMAT_MESSAGE_MAX_WIDTH_MASK |
|
||
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL,
|
||
|
dwResID,
|
||
|
0,
|
||
|
(LPSTR) &pchBuff,
|
||
|
1024,
|
||
|
NULL );
|
||
|
|
||
|
if ( cch ) {
|
||
|
|
||
|
fReturn = Copy( (LPCSTR) pchBuff );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Free the buffer FormatMessage allocated
|
||
|
//
|
||
|
|
||
|
if ( cch )
|
||
|
{
|
||
|
::LocalFree( (VOID*) pchBuff );
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
WCHAR ach[STR_MAX_RES_SIZE];
|
||
|
|
||
|
if ( IsUnicode() )
|
||
|
{
|
||
|
cch = ::LoadStringW( GetModuleHandle( lpszModuleName),
|
||
|
dwResID,
|
||
|
(WCHAR *) ach,
|
||
|
sizeof(ach));
|
||
|
|
||
|
if ( cch )
|
||
|
{
|
||
|
fReturn = Copy( (LPWSTR) ach );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cch = ::LoadStringA( GetModuleHandle( lpszModuleName),
|
||
|
dwResID,
|
||
|
(CHAR *) ach,
|
||
|
sizeof(ach));
|
||
|
if ( cch )
|
||
|
{
|
||
|
fReturn = Copy( (LPSTR) ach );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ( fReturn);
|
||
|
|
||
|
} // STR::LoadString()
|
||
|
|
||
|
|
||
|
BOOL STR::LoadString( IN DWORD dwResID,
|
||
|
IN HMODULE hModule
|
||
|
)
|
||
|
{
|
||
|
BOOL fReturn = FALSE;
|
||
|
INT cch;
|
||
|
WCHAR ach[STR_MAX_RES_SIZE];
|
||
|
|
||
|
if ( IsUnicode()) {
|
||
|
|
||
|
cch = ::LoadStringW(hModule,
|
||
|
dwResID,
|
||
|
(WCHAR *) ach,
|
||
|
sizeof(ach));
|
||
|
|
||
|
if ( cch ) {
|
||
|
|
||
|
fReturn = Copy( (LPWSTR) ach );
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
cch = ::LoadStringA(hModule,
|
||
|
dwResID,
|
||
|
(CHAR *) ach,
|
||
|
sizeof(ach));
|
||
|
if ( cch ) {
|
||
|
|
||
|
fReturn = Copy( (LPSTR) ach );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ( fReturn);
|
||
|
|
||
|
} // STR::LoadString()
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
STR::FormatStringV(
|
||
|
IN LPCTSTR lpszModuleName,
|
||
|
...
|
||
|
)
|
||
|
{
|
||
|
DWORD cch;
|
||
|
LPSTR pchBuff;
|
||
|
BOOL fRet = FALSE;
|
||
|
DWORD dwErr;
|
||
|
|
||
|
va_list va;
|
||
|
|
||
|
va_start(va,lpszModuleName);
|
||
|
|
||
|
cch = ::FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
|
FORMAT_MESSAGE_FROM_STRING,
|
||
|
QueryStrA(),
|
||
|
0L,
|
||
|
0,
|
||
|
(LPSTR) &pchBuff,
|
||
|
1024,
|
||
|
&va);
|
||
|
|
||
|
dwErr = ::GetLastError();
|
||
|
|
||
|
if ( cch ) {
|
||
|
fRet = Copy( (LPCSTR) pchBuff );
|
||
|
|
||
|
::LocalFree( (VOID*) pchBuff );
|
||
|
}
|
||
|
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
STR::FormatString(
|
||
|
IN DWORD dwResID,
|
||
|
IN LPCTSTR apszInsertParams[],
|
||
|
IN LPCTSTR lpszModuleName
|
||
|
)
|
||
|
{
|
||
|
DWORD cch;
|
||
|
LPSTR pchBuff;
|
||
|
BOOL fRet;
|
||
|
|
||
|
if (!dwResID) {
|
||
|
cch = ::FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
|
FORMAT_MESSAGE_ARGUMENT_ARRAY |
|
||
|
FORMAT_MESSAGE_FROM_STRING,
|
||
|
QueryStrA(),
|
||
|
dwResID,
|
||
|
0,
|
||
|
(LPSTR) &pchBuff,
|
||
|
1024,
|
||
|
(va_list *) apszInsertParams );
|
||
|
}
|
||
|
else {
|
||
|
cch = ::FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
|
FORMAT_MESSAGE_ARGUMENT_ARRAY |
|
||
|
FORMAT_MESSAGE_FROM_HMODULE,
|
||
|
GetModuleHandle( lpszModuleName ),
|
||
|
dwResID,
|
||
|
0,
|
||
|
(LPSTR) &pchBuff,
|
||
|
1024,
|
||
|
(va_list *) apszInsertParams );
|
||
|
}
|
||
|
|
||
|
if ( cch )
|
||
|
{
|
||
|
fRet = Copy( (LPCSTR) pchBuff );
|
||
|
|
||
|
::LocalFree( (VOID*) pchBuff );
|
||
|
}
|
||
|
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
#if 1
|
||
|
CHAR * STR::QueryStrA( VOID ) const
|
||
|
{
|
||
|
ASSERT( !IsUnicode() );
|
||
|
ASSERT( *_pszEmptyString == TEXT('\0') );
|
||
|
|
||
|
return (QueryPtr() ? (CHAR *) QueryPtr() : (CHAR *) _pszEmptyString);
|
||
|
}
|
||
|
|
||
|
WCHAR * STR::QueryStrW( VOID ) const
|
||
|
{
|
||
|
ASSERT( IsUnicode() );
|
||
|
ASSERT( *_pszEmptyString == TEXT('\0') );
|
||
|
|
||
|
return (QueryPtr() ? (WCHAR *) QueryPtr() : (WCHAR *) _pszEmptyString);
|
||
|
}
|
||
|
#endif //DBG
|
||
|
|
||
|
|
||
|
|
||
|
BOOL STR::CopyToBuffer( WCHAR * lpszBuffer, LPDWORD lpcch) const
|
||
|
/*++
|
||
|
Description:
|
||
|
Copies the string into the WCHAR buffer passed in if the buffer
|
||
|
is sufficient to hold the translated string.
|
||
|
If the buffer is small, the function returns small and sets *lpcch
|
||
|
to contain the required number of characters.
|
||
|
|
||
|
Arguments:
|
||
|
lpszBuffer pointer to WCHAR buffer which on return contains
|
||
|
the UNICODE version of string on success.
|
||
|
lpcch pointer to DWORD containing the length of the buffer.
|
||
|
If *lpcch == 0 then the function returns TRUE with
|
||
|
the count of characters required stored in *lpcch.
|
||
|
Also in this case lpszBuffer is not affected.
|
||
|
Returns:
|
||
|
TRUE on success.
|
||
|
FALSE on failure. Use GetLastError() for further details.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
BOOL fReturn = TRUE;
|
||
|
|
||
|
if ( lpcch == NULL) {
|
||
|
SetLastError( ERROR_INVALID_PARAMETER);
|
||
|
return ( FALSE);
|
||
|
}
|
||
|
|
||
|
if ( *lpcch == 0) {
|
||
|
|
||
|
//
|
||
|
// Inquiring the size of buffer alone
|
||
|
//
|
||
|
*lpcch = QueryCCH() + 1; // add one character for terminating null
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Copy data to buffer
|
||
|
//
|
||
|
if ( IsUnicode()) {
|
||
|
|
||
|
//
|
||
|
// Do plain copy of the data.
|
||
|
//
|
||
|
if ( *lpcch >= QueryCCH()) {
|
||
|
|
||
|
wcscpy( lpszBuffer, QueryStrW());
|
||
|
} else {
|
||
|
|
||
|
SetLastError( ERROR_INSUFFICIENT_BUFFER);
|
||
|
fReturn = FALSE;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Copy after conversion from ANSI to Unicode
|
||
|
//
|
||
|
int iRet;
|
||
|
iRet = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED,
|
||
|
QueryStrA(), QueryCCH() + 1,
|
||
|
lpszBuffer, (int )*lpcch);
|
||
|
|
||
|
if ( iRet == 0 || iRet != (int ) *lpcch) {
|
||
|
|
||
|
//
|
||
|
// Error in conversion.
|
||
|
//
|
||
|
fReturn = FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ( fReturn);
|
||
|
} // STR::CopyToBuffer()
|
||
|
|
||
|
|
||
|
BOOL STR::CopyToBufferA( CHAR * lpszBuffer, LPDWORD lpcch) const
|
||
|
/*++
|
||
|
Description:
|
||
|
Copies the string into the CHAR buffer passed in if the buffer
|
||
|
is sufficient to hold the translated string.
|
||
|
If the buffer is small, the function returns small and sets *lpcch
|
||
|
to contain the required number of characters.
|
||
|
|
||
|
Arguments:
|
||
|
lpszBuffer pointer to CHAR buffer which on return contains
|
||
|
the MBCS version of string on success.
|
||
|
lpcch pointer to DWORD containing the length of the buffer.
|
||
|
If *lpcch == 0 then the function returns TRUE with
|
||
|
the count of characters required stored in *lpcch.
|
||
|
Also in this case lpszBuffer is not affected.
|
||
|
Returns:
|
||
|
TRUE on success.
|
||
|
FALSE on failure. Use GetLastError() for further details.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
BOOL fReturn = TRUE;
|
||
|
|
||
|
if ( lpcch == NULL) {
|
||
|
SetLastError( ERROR_INVALID_PARAMETER);
|
||
|
return ( FALSE);
|
||
|
}
|
||
|
|
||
|
if ( *lpcch == 0) {
|
||
|
|
||
|
//
|
||
|
// Inquiring the size of buffer alone
|
||
|
//
|
||
|
*lpcch = 2*(QueryCCH() + 1); // add one character for terminating null and on pessimistic side
|
||
|
// ask for largest possible buffer
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Copy data to buffer
|
||
|
//
|
||
|
if ( !IsUnicode()) {
|
||
|
lstrcpyA( lpszBuffer, QueryStrA());
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Copy after conversion from Unicode to MBCS
|
||
|
//
|
||
|
int iRet;
|
||
|
|
||
|
iRet = WideCharToMultiByte(CP_ACP,
|
||
|
0L,
|
||
|
QueryStrW(),
|
||
|
QueryCCH()+1,
|
||
|
lpszBuffer,
|
||
|
*lpcch,
|
||
|
NULL,NULL
|
||
|
);
|
||
|
|
||
|
if ( iRet == 0 || *lpcch < (DWORD)iRet) {
|
||
|
*lpcch = iRet;
|
||
|
fReturn = FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ( fReturn);
|
||
|
} // STR::CopyToBuffer()
|
||
|
|
||
|
|
||
|
/*
|
||
|
STRArray class implementation- this isn't very efficient, as
|
||
|
we'll copy every string over again whenever we grow the array, but
|
||
|
then again, that part of the code may never even get executed, anyway
|
||
|
*/
|
||
|
void STRArray::Grow() {
|
||
|
|
||
|
// We need to add some more strings to the array
|
||
|
|
||
|
STR *pcsNew = new STR[m_ucMax += m_uGrowBy];
|
||
|
|
||
|
if (!pcsNew) {
|
||
|
// We recover gracelessly by replacing the final
|
||
|
// string.
|
||
|
|
||
|
m_ucMax -= m_uGrowBy;
|
||
|
m_ucItems--;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (unsigned u = 0; u < m_ucItems; u++)
|
||
|
pcsNew[u] = (LPCTSTR) m_pcsContents[u];
|
||
|
|
||
|
delete[] m_pcsContents;
|
||
|
m_pcsContents = pcsNew;
|
||
|
}
|
||
|
|
||
|
STRArray::STRArray(unsigned uGrowBy) {
|
||
|
|
||
|
m_uGrowBy = uGrowBy ? uGrowBy : 10;
|
||
|
|
||
|
m_ucItems = m_ucMax = 0;
|
||
|
|
||
|
m_pcsContents = NULL;
|
||
|
}
|
||
|
|
||
|
STRArray::~STRArray() {
|
||
|
if (m_pcsContents)
|
||
|
delete[] m_pcsContents;
|
||
|
}
|
||
|
|
||
|
void STRArray::Add(LPCSTR lpstrNew) {
|
||
|
if (m_ucItems >= m_ucMax)
|
||
|
Grow();
|
||
|
|
||
|
m_pcsContents[m_ucItems++].Copy(lpstrNew);
|
||
|
}
|
||
|
|
||
|
void STRArray::Add(LPCWSTR lpstrNew) {
|
||
|
if (m_ucItems >= m_ucMax)
|
||
|
Grow();
|
||
|
|
||
|
m_pcsContents[m_ucItems++].Copy(lpstrNew);
|
||
|
}
|
||
|
|
||
|
void STRArray::Tokenize(LPCTSTR lpstrIn, TCHAR tcSplitter) {
|
||
|
|
||
|
if (m_pcsContents) {
|
||
|
delete[] m_pcsContents;
|
||
|
m_ucItems = m_ucMax = 0;
|
||
|
m_pcsContents = NULL;
|
||
|
}
|
||
|
|
||
|
if (!lpstrIn || !*lpstrIn)
|
||
|
return;
|
||
|
|
||
|
while (*lpstrIn) {
|
||
|
|
||
|
// First, strip off any leading blanks
|
||
|
|
||
|
while (*lpstrIn && *lpstrIn == _TEXT(' '))
|
||
|
lpstrIn++;
|
||
|
|
||
|
for (LPCTSTR lpstrMoi = lpstrIn;
|
||
|
*lpstrMoi && *lpstrMoi != tcSplitter;
|
||
|
lpstrMoi++)
|
||
|
;
|
||
|
// If we hit the end, just add the whole thing to the array
|
||
|
if (!*lpstrMoi) {
|
||
|
if (*lpstrIn)
|
||
|
Add(lpstrIn);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Otherwise, just add the string up to the splitter
|
||
|
|
||
|
TCHAR szNew[MAX_PATH];
|
||
|
SIZE_T uiLen = (SIZE_T)(lpstrMoi - lpstrIn);
|
||
|
|
||
|
if (uiLen < (sizeof(szNew)/sizeof(szNew[0])) - 1) {
|
||
|
|
||
|
lstrcpyn(szNew,lpstrIn,(UINT)uiLen);
|
||
|
szNew[uiLen] = TCHAR('\0');
|
||
|
|
||
|
Add((LPCTSTR) szNew);
|
||
|
}
|
||
|
|
||
|
lpstrIn = lpstrMoi + 1;
|
||
|
}
|
||
|
}
|
||
|
|