You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4843 lines
128 KiB
4843 lines
128 KiB
// ****************************************************************************
|
|
//
|
|
// Copyright (c) Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
//
|
|
// cmdline.c
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This modules implements common functionality for all the
|
|
// command line tools.
|
|
//
|
|
//
|
|
// Author:
|
|
//
|
|
// Sunil G.V.N. Murali ([email protected]) 01-Sep-2000
|
|
//
|
|
// Revision History:
|
|
//
|
|
// Sunil G.V.N. Murali ([email protected]) 01-Sep-2000 : Created It.
|
|
//
|
|
// ****************************************************************************
|
|
|
|
#include "pch.h"
|
|
|
|
// indexes to the internal array
|
|
#define INDEX_ERROR_TEXT 0
|
|
#define INDEX_RESOURCE_STRING 1
|
|
#define INDEX_QUOTE_STRING 2
|
|
#define INDEX_TEMP_BUFFER 3
|
|
|
|
// permanent indexes to the temporary buffers
|
|
#define INDEX_TEMP_SHOWMESSAGE 3
|
|
#define INDEX_TEMP_RESOURCE 4
|
|
#define INDEX_TEMP_REASON 5
|
|
#define INDEX_TEMP_PATTERN 6
|
|
|
|
//
|
|
// global variable(s)
|
|
//
|
|
BOOL g_bInitialized = FALSE;
|
|
BOOL g_bWinsockLoaded = FALSE;
|
|
static TARRAY g_arrData = NULL;
|
|
static DWORD g_dwMajorVersion = 5;
|
|
static DWORD g_dwMinorVersion = 1;
|
|
static WORD g_wServicePackMajor = 0;
|
|
|
|
//
|
|
// global constants
|
|
//
|
|
const WCHAR cwchNullChar = L'\0';
|
|
const WCHAR cwszNullString[ 2 ] = L"\0";
|
|
|
|
//
|
|
// internal structures
|
|
//
|
|
typedef struct __tagBuffer
|
|
{
|
|
CHAR szSignature[ 7 ]; // "BUFFER\0"
|
|
DWORD dwLength;
|
|
LPWSTR pwszData;
|
|
} TBUFFER;
|
|
|
|
//
|
|
// private functions
|
|
//
|
|
BOOL InternalRecursiveMatchPatternEx( IN LPCWSTR pwszText, IN LPCWSTR pwszPattern,
|
|
IN DWORD dwLocale, IN DWORD dwCompareFlags, IN DWORD dwDepth );
|
|
|
|
// prototypes
|
|
BOOL SetThreadUILanguage0( DWORD dwReserved );
|
|
|
|
__inline LPWSTR
|
|
GetTempBuffer(
|
|
IN DWORD dwIndexNumber,
|
|
IN LPCWSTR pwszText,
|
|
IN DWORD dwLength,
|
|
IN BOOL bNullify
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
NOTE: since every file will need the temporary buffers -- in order to see
|
|
that their buffers wont be override with other functions, we are
|
|
creating a for each file
|
|
so, the temporary buffers in this file will range from index 0 to 5
|
|
thisgives total of 6 temporary buffers for this file
|
|
|
|
Arguments:
|
|
[IN] dwIndexNumber : Index number
|
|
[IN] pwszText : Text string
|
|
[IN] dwLength : length of the text string
|
|
[IN] bNullify : flag to specify either TRUE/FALSE
|
|
|
|
Return Value:
|
|
NULL : On failure
|
|
LPWSTR : On success
|
|
--*/
|
|
{
|
|
if ( dwIndexNumber >= TEMP_CMDLINE_C_COUNT )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// check if caller is requesting existing buffer contents
|
|
if ( pwszText == NULL && dwLength == 0 && bNullify == FALSE )
|
|
{
|
|
// yes -- we need to pass the existing buffer contents
|
|
return GetInternalTemporaryBufferRef(
|
|
dwIndexNumber + INDEX_TEMP_CMDLINE_C );
|
|
}
|
|
|
|
// ...
|
|
return GetInternalTemporaryBuffer(
|
|
dwIndexNumber + INDEX_TEMP_CMDLINE_C, pwszText, dwLength, bNullify );
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
InitGlobals()
|
|
/*++
|
|
Routine Description:
|
|
Initializes the global variables
|
|
|
|
Arguments: None
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check whether the initialization is already done or not
|
|
if ( g_bInitialized == TRUE )
|
|
{
|
|
if ( IsValidArray( g_arrData ) == FALSE )
|
|
{
|
|
// some one corrupted the data
|
|
UNEXPECTED_ERROR();
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// just inform the caller that the function call is successful
|
|
return TRUE;
|
|
}
|
|
}
|
|
else if ( g_arrData != NULL )
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
return FALSE;
|
|
}
|
|
|
|
// create the dynamic array
|
|
g_arrData = CreateDynamicArray();
|
|
if ( IsValidArray( g_arrData ) == FALSE )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// prepare for the data storage
|
|
|
|
// error text
|
|
if ( DynArrayAppendString(g_arrData, cwszNullString, 0) != INDEX_ERROR_TEXT ||
|
|
DynArrayAppendRow( g_arrData, 3 ) != INDEX_RESOURCE_STRING ||
|
|
DynArrayAppendRow( g_arrData, 3 ) != INDEX_QUOTE_STRING ||
|
|
DynArrayAppendRow( g_arrData, 3 ) != INDEX_TEMP_BUFFER )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
// every thing went well -- return
|
|
// though the rest of the code still needs to execute
|
|
// we treat as initialized once we create the global data structure
|
|
g_bInitialized = TRUE;
|
|
|
|
//
|
|
// initialize the thread specific resource information to use
|
|
//
|
|
// NOTE: since there is nothing much to do here,
|
|
// we are intentionally not checking the error code
|
|
//
|
|
if ( SetThreadUILanguage0( 0 ) == FALSE )
|
|
{
|
|
// SetThreadUILanguage0 is supposed to set the errro value
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LPWSTR
|
|
GetInternalTemporaryBufferRef( IN DWORD dwIndexNumber )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
[IN] dwIndexNumber : Index number
|
|
|
|
Return Value:
|
|
NULL : On failure
|
|
LPWSTR : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
TBUFFER* pBuffer = NULL;
|
|
const CHAR cszSignature[ 7 ] = "BUFFER";
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// initialize the global data structure
|
|
if ( g_bInitialized == FALSE )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// get the temp buffer array
|
|
dw = DynArrayGetCount2( g_arrData, INDEX_TEMP_BUFFER );
|
|
if ( dw <= dwIndexNumber )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// check whether we need to allocate a new TBUFFER or we can use the
|
|
// already allocated
|
|
if ( DynArrayGetItemType2( g_arrData,
|
|
INDEX_TEMP_BUFFER,
|
|
dwIndexNumber ) != DA_TYPE_NONE )
|
|
{
|
|
// we can use the already created buffer
|
|
pBuffer = DynArrayItem2( g_arrData, INDEX_TEMP_BUFFER, dwIndexNumber );
|
|
if ( pBuffer == NULL )
|
|
{
|
|
// unexpected behavior
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// verify the signature of the buffer
|
|
// this is just to ensure that we have everything in right place
|
|
if ( StringCompareA( pBuffer->szSignature, cszSignature, TRUE, 0 ) != 0 )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// return
|
|
return pBuffer->pwszData;
|
|
}
|
|
|
|
|
|
LPWSTR
|
|
GetInternalTemporaryBuffer( IN DWORD dwIndexNumber,
|
|
IN OUT LPCWSTR pwszText,
|
|
IN DWORD dwLength,
|
|
IN BOOL bNullify )
|
|
/*++
|
|
Routine Description:
|
|
Get the temporary buffer by allocating the buffer dynamically
|
|
|
|
Arguments:
|
|
[IN] dwIndexNumber : Index number
|
|
[IN] pwszText : Text string
|
|
[IN] dwLength : length of the text string
|
|
[IN] bNullify : flag to specify either TRUE/FALSE
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
DWORD dwNewLength = 0;
|
|
TARRAY arrTemp = NULL;
|
|
TBUFFER* pBuffer = NULL;
|
|
const CHAR cszSignature[ 7 ] = "BUFFER";
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input
|
|
if ( pwszText == NULL && dwLength == 0 )
|
|
{
|
|
// caller should pass either of them -- if not fail
|
|
return NULL;
|
|
}
|
|
|
|
// initialize the global data structure
|
|
if ( InitGlobals() == FALSE )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// get the temp buffer array
|
|
dw = DynArrayGetCount2( g_arrData, INDEX_TEMP_BUFFER );
|
|
if ( dw <= dwIndexNumber )
|
|
{
|
|
// add the some more buffers so that requirement can be satisfied
|
|
arrTemp = DynArrayItem( g_arrData, INDEX_TEMP_BUFFER );
|
|
if ( arrTemp == NULL ||
|
|
DynArrayAddColumns( arrTemp, dwIndexNumber - dw + 1 ) == -1 )
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// check whether we need to allocate a new TBUFFER or we can use the
|
|
// already allocated
|
|
if ( DynArrayGetItemType2( g_arrData,
|
|
INDEX_TEMP_BUFFER,
|
|
dwIndexNumber ) != DA_TYPE_NONE )
|
|
{
|
|
// we can use the already created buffer
|
|
pBuffer = DynArrayItem2( g_arrData, INDEX_TEMP_BUFFER, dwIndexNumber );
|
|
if ( pBuffer == NULL )
|
|
{
|
|
// unexpected behavior
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we need to allocate temporary buffer
|
|
pBuffer = (TBUFFER*) AllocateMemory( sizeof( TBUFFER ) );
|
|
if ( pBuffer == NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// initialize the block
|
|
pBuffer->dwLength = 0;
|
|
pBuffer->pwszData = NULL;
|
|
StringCopyA( pBuffer->szSignature, cszSignature, SIZE_OF_ARRAY( pBuffer->szSignature ) );
|
|
|
|
// save the buffer in array
|
|
if ( DynArraySet2( g_arrData,
|
|
INDEX_TEMP_BUFFER,
|
|
dwIndexNumber, pBuffer ) == FALSE )
|
|
{
|
|
// failed to set the buffer -- release the newly allocated
|
|
// and return
|
|
FreeMemory( &pBuffer );
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// once we save the newly allocated buffer in array -- we are set
|
|
// we need to worry about the furthur return statements -- the memory
|
|
// that is allocated in this section will be automatically released
|
|
// by ReleaseGlobals
|
|
//
|
|
}
|
|
|
|
// verify the signature of the buffer
|
|
// this is just to ensure that we have everything in right place
|
|
if ( StringCompareA( pBuffer->szSignature, cszSignature, TRUE, 0 ) != 0 )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// indentify the amount of memory required
|
|
// we need extra space for NULL
|
|
dwNewLength = ((pwszText == NULL) ? dwLength : (StringLength(pwszText, 0) + 1));
|
|
|
|
// allocate memory for temporary buffer -- if needed
|
|
// NOTE: we will re-allocate memory even if the two-time of current
|
|
// requested buffer length is less than the buffer length that is
|
|
// currently allocated on heap -- this we are doing to use the
|
|
// heap effectively
|
|
if ( dwNewLength > pBuffer->dwLength ||
|
|
( dwNewLength > 256 && (dwNewLength * 2) < pBuffer->dwLength ) )
|
|
{
|
|
// we need to toggle between allocate / reallocate based on the
|
|
// current length of the string in the TBUFFER
|
|
if ( pBuffer->dwLength == 0 )
|
|
{
|
|
pBuffer->pwszData = AllocateMemory( dwNewLength * sizeof( WCHAR ) );
|
|
if ( pBuffer->pwszData == NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ReallocateMemory( &pBuffer->pwszData,
|
|
dwNewLength * sizeof( WCHAR ) ) == FALSE )
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// save the current length of the data
|
|
pBuffer->dwLength = dwNewLength;
|
|
}
|
|
|
|
// safety check
|
|
if ( pBuffer->pwszData == NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// copy the data
|
|
if ( pwszText != NULL )
|
|
{
|
|
StringCopy( pBuffer->pwszData, pwszText, dwNewLength );
|
|
}
|
|
else if ( bNullify == TRUE )
|
|
{
|
|
ZeroMemory( pBuffer->pwszData, dwNewLength * sizeof( WCHAR ) );
|
|
}
|
|
|
|
// return
|
|
return pBuffer->pwszData;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetThreadUILanguage0( IN DWORD dwReserved )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Complex scripts cannot be rendered in the console, so we
|
|
force the English (US) resource.
|
|
|
|
Arguments:
|
|
[ in ] dwReserved => must be zero
|
|
|
|
Return Value:
|
|
TRUE : on Success
|
|
FALSE : On Failure
|
|
--*/
|
|
{
|
|
// local variables
|
|
UINT ui = 0;
|
|
UINT uiSize = 0;
|
|
OSVERSIONINFOEX osvi;
|
|
LPWSTR pwszPath = NULL;
|
|
LPCWSTR pwszLibPath = NULL;
|
|
HMODULE hKernel32Lib = NULL;
|
|
DWORDLONG dwlConditionMask = 0;
|
|
const CHAR cszFunctionName[] = "SetThreadUILanguage";
|
|
typedef BOOLEAN (WINAPI * FUNC_SetThreadUILanguage)( DWORD dwReserved );
|
|
FUNC_SetThreadUILanguage pfnSetThreadUILanguage = NULL;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// Initialize the OSVERSIONINFOEX structure
|
|
ZeroMemory( &osvi, sizeof( OSVERSIONINFOEX ) );
|
|
osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
|
|
osvi.dwMajorVersion = 5; // WINDOWS 2000
|
|
osvi.dwMinorVersion = 0; // ...
|
|
osvi.wServicePackMajor = 0; // ...
|
|
|
|
// Initialize the condition mask.
|
|
VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_EQUAL );
|
|
VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_EQUAL );
|
|
VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
|
|
|
|
// now check if the current os version is 5.0
|
|
if ( VerifyVersionInfo( &osvi,
|
|
VER_MAJORVERSION | VER_MINORVERSION,
|
|
dwlConditionMask ) == TRUE )
|
|
{
|
|
// currently os is W2K -- no need to proceed furthur
|
|
// still the function didn't encounter any error
|
|
// but return success as well as set the error code
|
|
SetLastError( ERROR_OLD_WIN_VERSION );
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// get the system files path
|
|
uiSize = MAX_PATH + 1;
|
|
do
|
|
{
|
|
pwszPath = GetTempBuffer( 0, NULL, uiSize + 10, TRUE );
|
|
if ( pwszPath == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
// ...
|
|
ui = GetSystemDirectory( pwszPath, uiSize );
|
|
if ( ui == 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
else if ( ui > uiSize )
|
|
{
|
|
// buffer is not sufficient -- need more buffer
|
|
// but check whether this is the first time that
|
|
// API is reported that the buffer is not sufficient
|
|
// if not, then it is an error -- something is going wrong
|
|
if ( uiSize != MAX_PATH + 1 )
|
|
{
|
|
uiSize = ui + 1;
|
|
ui = 0;
|
|
}
|
|
else
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
return FALSE;
|
|
}
|
|
}
|
|
} while ( ui == 0 );
|
|
|
|
// we will make use of failure buffer to format the
|
|
// string for file path
|
|
if ( SetReason2( 2, L"%s\\%s", pwszPath, L"kernel32.dll" ) == FALSE )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
// try loading the kernel32 dynamic link library
|
|
pwszLibPath = GetReason();
|
|
hKernel32Lib = LoadLibrary( pwszLibPath );
|
|
if ( hKernel32Lib != NULL )
|
|
{
|
|
// library loaded successfully ... now load the addresses of functions
|
|
pfnSetThreadUILanguage =
|
|
(FUNC_SetThreadUILanguage) GetProcAddress( hKernel32Lib, cszFunctionName );
|
|
|
|
// we will keep the library loaded in memory only if all the
|
|
// functions were loaded successfully
|
|
if ( pfnSetThreadUILanguage == NULL )
|
|
{
|
|
// some (or) all of the functions were not loaded ... unload the library
|
|
FreeLibrary( hKernel32Lib );
|
|
hKernel32Lib = NULL;
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// call the function
|
|
((FUNC_SetThreadUILanguage) pfnSetThreadUILanguage)( dwReserved );
|
|
}
|
|
|
|
// unload the library and return success
|
|
FreeLibrary( hKernel32Lib );
|
|
hKernel32Lib = NULL;
|
|
pfnSetThreadUILanguage = NULL;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// success
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// public functions
|
|
//
|
|
|
|
LPCWSTR
|
|
GetReason()
|
|
/*++
|
|
Routine Description:
|
|
|
|
Get the reason depends on the GetLastError() (WIN32 API error code)
|
|
set by the SaveLastError()
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
LPCWSTR : on Success
|
|
NULL_STRING : On Failure
|
|
--*/
|
|
{
|
|
//
|
|
// we should not clear the error code here
|
|
//
|
|
|
|
// check whether buffer is allocated or not ... if not, empty string
|
|
if ( g_arrData == NULL || IsValidArray( g_arrData ) == FALSE )
|
|
{
|
|
return cwszNullString;
|
|
}
|
|
|
|
// returh the reason for the last failure
|
|
return DynArrayItemAsString( g_arrData, INDEX_ERROR_TEXT );
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetReason( LPCWSTR pwszReason )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Set the reason depends on the GetLastError() (WIN32 API error code)
|
|
set by the SaveLastError()
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
TRUE : on Success
|
|
FALSE : On Failure
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dwLastError = 0;
|
|
|
|
//
|
|
// we should not clear the error code here
|
|
//
|
|
|
|
// preserve the last error
|
|
dwLastError = GetLastError();
|
|
|
|
// check the input value
|
|
if ( pwszReason == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
// initialize the global data structure
|
|
if ( InitGlobals() == FALSE )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// set the reason ..
|
|
if ( DynArraySetString( g_arrData, INDEX_ERROR_TEXT, pwszReason, 0 ) == FALSE )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
SetLastError( dwLastError );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetReason2( IN DWORD dwCount,
|
|
IN LPCWSTR pwszFormat, ... )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Saves text in memory
|
|
Generally used for saving the reason for the failure but can be used
|
|
in any context.
|
|
|
|
This variant of SetReason accepts variable no. of arguments just as
|
|
sprintf statements and does the formatting
|
|
|
|
Arguments:
|
|
[ in ] dwCount : Specifies no. of variable no. of arguments being
|
|
passed to this function
|
|
[ in ] pwszFormat : Specifies the format string -- to format the text
|
|
[ in ] ... : Variable no. of arguments specification
|
|
|
|
Return Value:
|
|
TRUE : on Success
|
|
FALSE : On Failure
|
|
--*/
|
|
{
|
|
// local variables
|
|
va_list vargs;
|
|
DWORD dwBufferLength = 0;
|
|
LPWSTR pwszBuffer = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// we should not clear the error code here
|
|
//
|
|
|
|
// check the input
|
|
if ( pwszFormat == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
else if ( dwCount == 0 )
|
|
{
|
|
SetReason( pwszFormat );
|
|
return TRUE;
|
|
}
|
|
|
|
do
|
|
{
|
|
// get the variable args start position
|
|
va_start( vargs, pwszFormat );
|
|
if ( vargs == NULL )
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
return FALSE;
|
|
}
|
|
|
|
// we will start with buffer length of 256 bytes and then increment
|
|
// the buffer by 256 bytes each time we run thru this loop
|
|
dwBufferLength += 256;
|
|
if ( (pwszBuffer = GetTempBuffer( INDEX_TEMP_REASON,
|
|
NULL, dwBufferLength, TRUE )) == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
// try the printf
|
|
hr = StringCchVPrintfW( pwszBuffer, dwBufferLength, pwszFormat, vargs );
|
|
|
|
// reset the va_list parameter
|
|
va_end( vargs );
|
|
} while ( hr == STRSAFE_E_INSUFFICIENT_BUFFER );
|
|
|
|
// check the hr (vprintf might have failed for some other reason)
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SetLastError( HRESULT_CODE( hr ) );
|
|
return FALSE;
|
|
}
|
|
|
|
// now save the reason
|
|
return SetReason( pwszBuffer );
|
|
}
|
|
|
|
|
|
BOOL
|
|
SaveLastError()
|
|
/*++
|
|
Routine Description:
|
|
Format the message depends on GetLastError() error code and set the
|
|
message to SetReason().
|
|
|
|
Arguments: None
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
BOOL bResult = FALSE;
|
|
LPVOID lpMsgBuf = NULL; // pointer to handle error message
|
|
|
|
//
|
|
// we should not clear the error text here
|
|
//
|
|
|
|
// load the system error message from the windows itself
|
|
dw = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL, GetLastError(), 0, (LPWSTR) &lpMsgBuf, 0, NULL );
|
|
|
|
// check the function call succeeded or not
|
|
if ( dw == 0 || lpMsgBuf == NULL )
|
|
{
|
|
// return
|
|
if ( lpMsgBuf != NULL )
|
|
{
|
|
LocalFree( lpMsgBuf );
|
|
|
|
// since there is a chance of last error to get clear
|
|
// by LocalFree, set the last error once again
|
|
OUT_OF_MEMORY();
|
|
}
|
|
|
|
// ...
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
// save the error message
|
|
bResult = SetReason( ( LPCWSTR ) lpMsgBuf );
|
|
|
|
// Free the buffer ... using LocalFree is slow, but still, we are using ...
|
|
// later on need to replaced with HeapXXX functions
|
|
LocalFree( lpMsgBuf );
|
|
lpMsgBuf = NULL;
|
|
|
|
// return
|
|
return bResult;
|
|
}
|
|
|
|
|
|
DWORD
|
|
WNetSaveLastError()
|
|
/*++
|
|
Routine Description:
|
|
Format the message depends on most recent extended error code and set the
|
|
message to SetReason().
|
|
|
|
Arguments: None
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dwResult = 0;
|
|
DWORD dwErrorCode = 0;
|
|
LPWSTR pwszMessage = NULL; // handle error message
|
|
LPWSTR pwszProvider = NULL; // store the provider for error
|
|
|
|
//
|
|
// we should not clear error here
|
|
//
|
|
|
|
//
|
|
// get the memory for message and provider buffers
|
|
|
|
// message
|
|
if ( (pwszMessage = GetTempBuffer( 0, NULL, 256, TRUE )) == NULL )
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
// provider
|
|
if ( (pwszProvider = GetTempBuffer( 1, NULL, 256, TRUE )) == NULL )
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
// load the system error message from the windows itself
|
|
dwResult = WNetGetLastError( &dwErrorCode,
|
|
pwszMessage, (GetBufferSize( pwszMessage ) / sizeof( WCHAR )) - 1,
|
|
pwszProvider, (GetBufferSize( pwszProvider ) / sizeof( WCHAR )) - 1 );
|
|
|
|
// check whether the function succeeded or not
|
|
if ( dwResult != NO_ERROR )
|
|
{
|
|
return dwResult;
|
|
}
|
|
|
|
// save the error
|
|
if ( SetReason( pwszMessage ) == FALSE )
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
// return the error code obtained
|
|
return dwErrorCode;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ShowLastError( IN FILE* fp )
|
|
/*++
|
|
Routine Description:
|
|
Displays the message for most recent error code (GetLastError())
|
|
based on the file pointer
|
|
|
|
Arguments: None
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
//
|
|
// we should not clear error here
|
|
//
|
|
|
|
// save the last error first
|
|
if ( SaveLastError() == FALSE )
|
|
{
|
|
// error occured while trying to save the error message
|
|
return FALSE;
|
|
}
|
|
|
|
// display error message on console screen ...
|
|
if ( ShowMessage( fp, GetReason() ) == FALSE )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// return
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ShowLastErrorEx( IN FILE* fp,
|
|
IN DWORD dwFlags )
|
|
/*++
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
--*/
|
|
{
|
|
// check the input
|
|
if ( NULL == fp || 0 == (dwFlags & SLE_MASK) )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
// check whether to display the internal error message
|
|
// or the system error
|
|
if ( dwFlags & SLE_SYSTEM )
|
|
{
|
|
SaveLastError();
|
|
}
|
|
|
|
// check the flags and show the appropriate tag
|
|
// NOTE: some times, caller even might not need the flag to show
|
|
if ( dwFlags & SLE_TYPE_ERROR )
|
|
{
|
|
ShowMessageEx( fp, 1, TRUE, L"%s ", TAG_ERROR );
|
|
}
|
|
else if ( dwFlags & SLE_TYPE_WARNING )
|
|
{
|
|
ShowMessageEx( fp, 1, TRUE, L"%s ", TAG_WARNING );
|
|
}
|
|
else if ( dwFlags & SLE_TYPE_INFO )
|
|
{
|
|
ShowMessageEx( fp, 1, TRUE, L"%s ", TAG_INFORMATION );
|
|
}
|
|
else if ( dwFlags & SLE_TYPE_SUCCESS )
|
|
{
|
|
ShowMessageEx( fp, 1, TRUE, L"%s ", TAG_SUCCESS );
|
|
}
|
|
|
|
|
|
// show the actual error message
|
|
ShowMessage( fp, GetReason() );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ReleaseGlobals()
|
|
/*++
|
|
Routine Description:
|
|
De-allocate the memory for all the global variables
|
|
|
|
Arguments: None
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
DWORD dwCount = 0;
|
|
TBUFFER* pBuffer = NULL;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
//
|
|
// memory is allocated then free memory
|
|
// do this only if the memory is allocated
|
|
|
|
if ( IsValidArray( g_arrData ) == TRUE )
|
|
{
|
|
// release memory allocated for temporary buffers
|
|
dwCount = DynArrayGetCount2( g_arrData, INDEX_TEMP_BUFFER );
|
|
for( dw = dwCount; dw != 0; dw-- )
|
|
{
|
|
if ( DynArrayGetItemType2( g_arrData,
|
|
INDEX_TEMP_BUFFER, dw - 1 ) == DA_TYPE_GENERAL )
|
|
{
|
|
pBuffer = DynArrayItem2( g_arrData, INDEX_TEMP_BUFFER, dw - 1 );
|
|
if ( pBuffer == NULL )
|
|
{
|
|
// this is error condition -- still ignore
|
|
continue;
|
|
}
|
|
|
|
// release data first
|
|
FreeMemory( &pBuffer->pwszData );
|
|
|
|
// now release the memory
|
|
FreeMemory( &pBuffer );
|
|
|
|
// remove the item from dynamic array
|
|
DynArrayRemoveColumn( g_arrData, INDEX_TEMP_BUFFER, dw - 1 );
|
|
}
|
|
}
|
|
|
|
// free the memory allocated for global data storage
|
|
DestroyDynamicArray( &g_arrData );
|
|
}
|
|
|
|
// if winsock module is loaded, release it
|
|
if ( g_bWinsockLoaded == TRUE )
|
|
{
|
|
WSACleanup();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsWin2KOrLater()
|
|
/*++
|
|
Routine Description:
|
|
Checks whether the OS version of target system is WINDOWS 2000 or later
|
|
|
|
Arguments: None
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
OSVERSIONINFOEX osvi;
|
|
DWORDLONG dwlConditionMask = 0;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// Initialize the OSVERSIONINFOEX structure.
|
|
ZeroMemory( &osvi, sizeof( OSVERSIONINFOEX ) );
|
|
osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
|
|
osvi.dwMajorVersion = g_dwMajorVersion;
|
|
osvi.dwMinorVersion = g_dwMinorVersion;
|
|
osvi.wServicePackMajor = g_wServicePackMajor;
|
|
|
|
// Initialize the condition mask.
|
|
VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL );
|
|
VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL );
|
|
VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
|
|
|
|
// Perform the test.
|
|
return VerifyVersionInfo( &osvi, VER_MAJORVERSION | VER_MINORVERSION, dwlConditionMask );
|
|
}
|
|
|
|
BOOL
|
|
IsCompatibleOperatingSystem( IN DWORD dwVersion )
|
|
/*++
|
|
Routine Description:
|
|
Checks whether the OS version of target system is compatible or not
|
|
|
|
Arguments: None
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// OS version above windows 2000 is compatible
|
|
return (dwVersion >= 5000);
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetOsVersion( IN DWORD dwMajor,
|
|
IN DWORD dwMinor,
|
|
IN WORD wServicePackMajor )
|
|
/*++
|
|
Routine Description:
|
|
Sets the OS version of target system with the specified mask
|
|
|
|
Arguments:
|
|
[IN] dwMajor : Major version
|
|
[IN] dwMinor : Minor version
|
|
[IN] wServicePackMajor : Service pack major version
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
static BOOL bSet = FALSE;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// we won't support below Windows 2000
|
|
if ( dwMajor < 5 || bSet == TRUE )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
// rest of information we need not bother
|
|
bSet = TRUE;
|
|
g_dwMajorVersion = dwMajor;
|
|
g_dwMinorVersion = dwMinor;
|
|
g_wServicePackMajor = wServicePackMajor;
|
|
|
|
// return
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LPCWSTR
|
|
GetResString( IN UINT uID )
|
|
/*++
|
|
Routine Description:
|
|
Sets the OS version of target system with the specified mask
|
|
|
|
Arguments:
|
|
[IN] uID : Resource ID
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
static DWORD dwCount = 0;
|
|
|
|
dwCount++;
|
|
return GetResString2( uID, 4 + (dwCount % 10) );
|
|
}
|
|
|
|
|
|
LPCWSTR
|
|
GetResString2( IN UINT uID,
|
|
IN DWORD dwIndexNumber )
|
|
/*++
|
|
Routine Description:
|
|
Sets the OS version of target system with the specified mask
|
|
|
|
Arguments:
|
|
[IN] uID : Resource ID
|
|
[IN] dwIndexNumber : Index number
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dwCount = 0;
|
|
DWORD dwLength = 0;
|
|
LPVOID pvBuffer = NULL;
|
|
TARRAY arrTemp = NULL;
|
|
LPWSTR pwszTemp = NULL; // pointer to handle error message
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input value
|
|
if ( uID == 0 )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// initialize the gloabal data structure
|
|
if ( InitGlobals() == FALSE )
|
|
{
|
|
return cwszNullString;
|
|
}
|
|
|
|
// check whether we have sufficient indexes or not
|
|
dwCount = DynArrayGetCount2( g_arrData, INDEX_RESOURCE_STRING );
|
|
if ( dwCount <= dwIndexNumber )
|
|
{
|
|
// requested index is more than existing
|
|
// add new columns to the array so that request can be satisfied
|
|
arrTemp = DynArrayItem( g_arrData, INDEX_RESOURCE_STRING );
|
|
if ( arrTemp == NULL ||
|
|
DynArrayAddColumns( arrTemp, dwIndexNumber - dwCount + 1 ) == -1 )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return cwszNullString;
|
|
}
|
|
}
|
|
|
|
//
|
|
// we need to load the entire string that is defined string table
|
|
// we will try to load the string incrementing our buffer by 128 bytes
|
|
// at a time
|
|
dwCount = 0;
|
|
dwLength = 128;
|
|
|
|
// ...
|
|
do
|
|
{
|
|
// increment the buffer length by 256
|
|
// we will always double the length we curretly have
|
|
dwLength *= 2;
|
|
|
|
//
|
|
// LoadString will null terminate the string with null character
|
|
// and will return the no. of characters read from string table
|
|
// not including the null terminator -- so at all times, in order
|
|
// make sure that we load the entire string from the string table
|
|
// check the no. of characters returned with one less than the buffer
|
|
// we have -- if that condition matches, we will loop once again
|
|
// to load the rest of the string and we will continue this way
|
|
// until we got the entire string into memory
|
|
//
|
|
|
|
// loading the string from resource file string table
|
|
if ( (pwszTemp = GetTempBuffer( INDEX_TEMP_RESOURCE,
|
|
NULL, dwLength, TRUE )) == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// try to load the string
|
|
dwCount = LoadString( NULL, uID, pwszTemp, dwLength );
|
|
if ( dwCount == 0 )
|
|
{
|
|
// check the last error
|
|
if ( GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND )
|
|
{
|
|
// try if message exists in the message table
|
|
dwCount = FormatMessageW( FORMAT_MESSAGE_FROM_HMODULE |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
|
NULL, uID, 0, (LPWSTR) &pvBuffer, 0, NULL );
|
|
|
|
// check the result
|
|
if ( dwCount != 0 )
|
|
{
|
|
pwszTemp = (LPWSTR) pvBuffer;
|
|
}
|
|
}
|
|
|
|
if ( dwCount == 0 )
|
|
{
|
|
// error occurred -- return
|
|
return cwszNullString;
|
|
}
|
|
}
|
|
} while ( dwCount >= (dwLength - 1) );
|
|
|
|
|
|
// save the resource message
|
|
// and check whether we are successful in saving the resource text or not
|
|
if ( DynArraySetString2( g_arrData,
|
|
INDEX_RESOURCE_STRING,
|
|
dwIndexNumber, pwszTemp, 0 ) == FALSE )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// free the memory allocated with FormatMessage function
|
|
if ( pvBuffer != NULL )
|
|
{
|
|
LocalFree( pvBuffer );
|
|
pvBuffer = NULL;
|
|
}
|
|
|
|
// return
|
|
return DynArrayItemAsString2( g_arrData, INDEX_RESOURCE_STRING, dwIndexNumber );
|
|
}
|
|
|
|
|
|
double
|
|
AsFloat( IN LPCWSTR pwszValue )
|
|
/*++
|
|
Routine Description:
|
|
Gets the float value for a given string
|
|
|
|
Arguments:
|
|
[IN] pwszValue : Input string
|
|
|
|
Return Value:
|
|
0.0f : On failure
|
|
double value : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
double dblValue = 0.0f;
|
|
LPWSTR pwszStopString = NULL;
|
|
LPCWSTR pwszValueString = NULL;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input value
|
|
if ( pwszValue == NULL || StringLength( pwszValue, 0 ) == 0 )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return 0.0f;
|
|
}
|
|
|
|
// initialize the global data structure
|
|
if ( InitGlobals() == FALSE )
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
// get the temporary memory location
|
|
pwszValueString = GetTempBuffer( 0, pwszValue, 0, FALSE );
|
|
if ( pwszValueString == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return 0.0f;
|
|
}
|
|
|
|
// convert the string value into double value and return the same
|
|
dblValue = wcstod( pwszValueString, &pwszStopString );
|
|
|
|
// determine whether the conversion took place properly or not
|
|
// value is invalid if
|
|
// 1. overflow / underflow occured
|
|
// 2. pwszStopString's length is not equal to 0
|
|
if ( errno == ERANGE ||
|
|
( pwszStopString != NULL && StringLength( pwszStopString, 0 ) != 0 ) )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return 0.0f;
|
|
}
|
|
|
|
// return the value
|
|
return dblValue;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsFloatingPoint( IN LPCWSTR pwszValue )
|
|
/*++
|
|
Routine Description:
|
|
Checks whether the given string is float value or not
|
|
|
|
Arguments:
|
|
[IN] pwszValue : Input string
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// attempt to convert the value
|
|
AsFloat( pwszValue );
|
|
|
|
// check the error code
|
|
return (GetLastError() == NO_ERROR);
|
|
}
|
|
|
|
|
|
LONG
|
|
AsLong( IN LPCWSTR pwszValue,
|
|
IN DWORD dwBase )
|
|
/*++
|
|
Routine Description:
|
|
Gets the long value for a given string
|
|
|
|
Arguments:
|
|
[IN] pwszValue : Input string
|
|
[IN] dwBase : Base value
|
|
|
|
|
|
Return Value:
|
|
0L : On failure
|
|
Long value : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lValue = 0L;
|
|
LPWSTR pwszStopString = NULL;
|
|
LPWSTR pwszValueString = NULL;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// validate the base
|
|
// value should be in the range of 2 - 36 only
|
|
if ( dwBase < 2 || dwBase > 36 || pwszValue == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return 0L;
|
|
}
|
|
|
|
// initialize the global data structure
|
|
// and save the current value in global data structure
|
|
if ( InitGlobals() == FALSE )
|
|
{
|
|
return 0L;
|
|
}
|
|
|
|
// get the temporary buffer
|
|
pwszValueString = GetTempBuffer( 0, pwszValue, 0, FALSE );
|
|
if ( pwszValueString == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return 0L;
|
|
}
|
|
|
|
// trim the string
|
|
TrimString2( pwszValueString, NULL, TRIM_ALL );
|
|
if ( StringLength( pwszValueString, 0 ) == 0 )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return 0L;
|
|
}
|
|
|
|
// convert the string value into long value and return the same
|
|
// based on the "sign" of the number choose the path
|
|
if ( pwszValueString[ 0 ] == L'-' )
|
|
{
|
|
lValue = wcstol( pwszValueString, &pwszStopString, dwBase );
|
|
}
|
|
else
|
|
{
|
|
// NOTE: though we are not capturing the return value into
|
|
// unsigned long we do need to call the unsigned long conversion function
|
|
lValue = wcstoul( pwszValueString, &pwszStopString, dwBase );
|
|
}
|
|
|
|
// determine whether the conversion took place properly or not
|
|
// value is invalid if
|
|
// 1. overflow / underflow occured
|
|
// 2. pwszStopString's length is not equal to 0
|
|
if ( errno == ERANGE ||
|
|
( pwszStopString != NULL && StringLength( pwszStopString, 0 ) != 0 ) )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return 0L;
|
|
}
|
|
|
|
// return
|
|
return lValue;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsNumeric( IN LPCWSTR pwszValue,
|
|
IN DWORD dwBase,
|
|
IN BOOL bSigned )
|
|
/*++
|
|
Routine Description:
|
|
Checks whether the given string is numeric or not
|
|
|
|
Arguments:
|
|
[IN] pwszValue : Input string
|
|
[IN] dwBase : Base value
|
|
[IN] bSigned : Sign Value (+/-)
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LPWSTR pwszNumber = NULL;
|
|
LPWSTR pwszStopString = NULL;
|
|
|
|
// check the input:
|
|
// validate the base
|
|
// value should be in the range of 2 - 36 only
|
|
if ( dwBase < 2 || dwBase > 36 || pwszValue == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return 0L;
|
|
}
|
|
|
|
// to better validate the numeric values we need the TRIMmed string
|
|
pwszNumber = GetTempBuffer( 0, pwszValue, 0, FALSE );
|
|
if ( pwszNumber == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
// trim the string contents
|
|
TrimString2( pwszNumber, NULL, TRIM_ALL );
|
|
|
|
// check the length
|
|
if( StringLength( pwszNumber, 0 ) == 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// validate the "sign"
|
|
if ( bSigned == FALSE && pwszNumber[ 0 ] == L'-' )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// convert the string value into long value and return the same
|
|
if ( bSigned == TRUE )
|
|
{
|
|
wcstol( pwszNumber, &pwszStopString, dwBase );
|
|
}
|
|
else
|
|
{
|
|
wcstoul( pwszNumber, &pwszStopString, dwBase );
|
|
}
|
|
|
|
// determine whether the conversion took place properly or not
|
|
// value is invalid if
|
|
// 1. overflow / underflow occured
|
|
// 2. pwszStopString's length is not equal to 0
|
|
if ( errno == ERANGE ||
|
|
( pwszStopString != NULL && StringLength( pwszStopString, 0 ) != 0 ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// value is valid numeric
|
|
return TRUE;
|
|
}
|
|
|
|
LPCWSTR
|
|
FindChar( IN LPCWSTR pwszString,
|
|
IN WCHAR wch,
|
|
IN DWORD dwFrom )
|
|
/*++
|
|
Routine Description:
|
|
Searches a string for the first occurrence of a character that
|
|
matches the specified character. The comparison is not case sensitive.
|
|
|
|
Arguments:
|
|
[IN] pwszValue : Address of the string to be searched.
|
|
[IN] wch : Character to be used for comparison.
|
|
[IN] dwFrom : to start from the location
|
|
|
|
Return Value:
|
|
NULL : On failure
|
|
LPWSTR : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lIndex = 0;
|
|
|
|
lIndex = FindChar2( pwszString, wch, TRUE, dwFrom );
|
|
if ( lIndex == -1 )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return pwszString + lIndex;
|
|
}
|
|
|
|
|
|
LONG
|
|
FindChar2( IN LPCWSTR pwszString,
|
|
IN WCHAR wch,
|
|
IN BOOL bIgnoreCase,
|
|
IN DWORD dwFrom )
|
|
/*++
|
|
Routine Description:
|
|
Searches a string for the first occurrence of a character that
|
|
matches the specified character. The comparison either (case sensitive/in-sensitive)
|
|
depends on the bIgoneCase value.
|
|
|
|
Arguments:
|
|
[IN] pwszValue : Address of the string to be searched.
|
|
[IN] wch : Character to be used for comparison.
|
|
[IN] bIgnoreCase : Flag to check for case sensitive/in-sensitive
|
|
If FALSE, case sensitive else in-sensitive
|
|
[IN] dwFrom : to start from the location
|
|
|
|
Return Value:
|
|
0 : On failure
|
|
Long value : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dwLength = 0;
|
|
LPWSTR pwsz = NULL;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the inputs
|
|
if ( pwszString == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return -1;
|
|
}
|
|
|
|
// check the length of the text that has to be find. if it is
|
|
// more than the original it is obvious that it cannot be found
|
|
dwLength = StringLength( pwszString, 0 );
|
|
if ( dwLength == 0 || dwFrom >= dwLength )
|
|
{
|
|
SetLastError( ERROR_NOT_FOUND );
|
|
return -1;
|
|
}
|
|
|
|
// search for the character
|
|
if ( bIgnoreCase == TRUE )
|
|
{
|
|
pwsz = StrChrI( pwszString + dwFrom, wch );
|
|
}
|
|
else
|
|
{
|
|
pwsz = StrChr( pwszString + dwFrom, wch );
|
|
}
|
|
|
|
// check the result
|
|
if ( pwsz == NULL )
|
|
{
|
|
SetLastError( ERROR_NOT_FOUND );
|
|
return -1;
|
|
}
|
|
|
|
// determine the position and return
|
|
return (LONG) (DWORD_PTR)(pwsz - pwszString);
|
|
}
|
|
|
|
|
|
BOOL
|
|
InString( IN LPCWSTR pwszString,
|
|
IN LPCWSTR pwszList,
|
|
IN BOOL bIgnoreCase )
|
|
/*++
|
|
Routine Description:
|
|
Checks for the first occurrence of one string within the list.
|
|
|
|
Arguments:
|
|
[IN] pwszValue : Address of the string
|
|
[IN] pwsz : List of string to be searched for
|
|
[IN] bIgnoreCase : Flag to check for case sensitive/in-sensitive
|
|
If FALSE, case sensitive else in-sensitive
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dwListLength = 0;
|
|
DWORD dwStringLength = 0;
|
|
LPWSTR pwszFmtList = NULL;
|
|
LPWSTR pwszFmtString = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input value
|
|
if ( pwszString == NULL || pwszList == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// get memory for the temporary buffers
|
|
// | + length of the original string ( list / string ) + | + NULL + NULL
|
|
|
|
// format list
|
|
dwListLength = StringLength( pwszList, 0 ) + 4;
|
|
if ( (pwszFmtList = GetTempBuffer( 0,
|
|
NULL,
|
|
dwListLength, TRUE )) == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
// format string
|
|
dwStringLength = StringLength( pwszString, 0 ) + 4;
|
|
if ( (pwszFmtString = GetTempBuffer( 1,
|
|
NULL,
|
|
dwStringLength, TRUE )) == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
// prepare the strings for searching
|
|
hr = StringCchPrintfW( pwszFmtList, dwListLength, L"|%s|", pwszList );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SetLastError( HRESULT_CODE( hr ) );
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintfW( pwszFmtString, dwStringLength, L"|%s|", pwszString );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SetLastError( HRESULT_CODE( hr ) );
|
|
return FALSE;
|
|
}
|
|
|
|
// search for the string in the list and return result
|
|
return (FindString2( pwszFmtList, pwszFmtString, bIgnoreCase, 0 ) != -1);
|
|
}
|
|
|
|
|
|
LPCWSTR
|
|
FindOneOf( IN LPCWSTR pwszText,
|
|
IN LPCWSTR pwszTextToFind,
|
|
IN DWORD dwFrom )
|
|
/*++
|
|
Routine Description:
|
|
Finds the first occurrence one of characters from a substring within a string.
|
|
The comparison is not case sensitive.
|
|
|
|
Arguments:
|
|
[IN] pwszText : Address of the string being searched.
|
|
[IN] pwszTextToFind : Substring to search for.
|
|
[IN] dwFrom : to start from the location
|
|
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lIndex = 0;
|
|
|
|
lIndex = FindOneOf2( pwszText, pwszTextToFind, TRUE, dwFrom );
|
|
if ( lIndex == -1 )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return pwszText + lIndex;
|
|
}
|
|
|
|
|
|
LONG
|
|
FindOneOf2( IN LPCWSTR pwszText,
|
|
IN LPCWSTR pwszTextToFind,
|
|
IN BOOL bIgnoreCase,
|
|
IN DWORD dwFrom )
|
|
/*++
|
|
Routine Description:
|
|
Finds the first occurrence one of characters from a substring within a string.
|
|
The comparison is either case sensitive/in-sensitive depends on
|
|
bIgnoreCase value.
|
|
|
|
Arguments:
|
|
[IN] pwszText : Address of the string being searched.
|
|
[IN] pwszTextToFind : Substring to search for.
|
|
[IN] bIgnoreCase : Flag to check for case sensitive/in-sensitive
|
|
If FALSE, case sensitive else in-sensitive
|
|
[IN] dwFrom : to start from the location
|
|
|
|
|
|
Return Value:
|
|
0L : On failure
|
|
Long value : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
LONG lResult = 0;
|
|
DWORD dwFindLength = 0;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the inputs
|
|
if ( pwszText == NULL || pwszTextToFind == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return -1;
|
|
}
|
|
|
|
// get the length of the find string
|
|
dwFindLength = StringLength( pwszTextToFind, 0 );
|
|
|
|
// check the length of the text that has to be find. if it is
|
|
// more than the original it is obvious that it cannot be found
|
|
if ( dwFindLength == 0 ||
|
|
StringLength( pwszText, 0 ) == 0 ||
|
|
dwFrom >= (DWORD) StringLength( pwszText, 0 ) )
|
|
{
|
|
SetLastError( ERROR_NOT_FOUND );
|
|
return -1;
|
|
}
|
|
|
|
// traverse thru the original text
|
|
for( dw = 0; dw < dwFindLength; dw++ )
|
|
{
|
|
// search for the character
|
|
lResult = FindChar2( pwszText, pwszTextToFind[ dw ], bIgnoreCase, dwFrom );
|
|
if ( lResult != -1 )
|
|
{
|
|
return lResult;
|
|
}
|
|
}
|
|
|
|
// string not found
|
|
SetLastError( ERROR_NOT_FOUND );
|
|
return -1;
|
|
}
|
|
|
|
LPCWSTR
|
|
FindString( IN LPCWSTR pwszText,
|
|
IN LPCWSTR pwszTextToFind,
|
|
IN DWORD dwFrom )
|
|
/*++
|
|
Routine Description:
|
|
Finds the first occurrence of a substring within a string.
|
|
The comparison is not case sensitive.
|
|
|
|
Arguments:
|
|
[IN] pwszText : Address of the string being searched.
|
|
[IN] pwszTextToFind : Substring to search for.
|
|
[IN] dwFrom : to start from the location
|
|
|
|
|
|
Return Value:
|
|
0L : On failure
|
|
Long value : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lIndex = 0;
|
|
|
|
lIndex = FindString2( pwszText, pwszTextToFind, TRUE, dwFrom );
|
|
if ( lIndex == -1 )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return pwszText + lIndex;
|
|
}
|
|
|
|
|
|
LONG
|
|
FindString2( IN LPCWSTR pwszText,
|
|
IN LPCWSTR pwszTextToFind,
|
|
IN BOOL bIgnoreCase,
|
|
IN DWORD dwFrom )
|
|
/*++
|
|
Routine Description:
|
|
Finds the first occurrence of a substring within a string.
|
|
The comparison is either case sensitive/in-sensitive depends on
|
|
bIgnoreCase value.
|
|
|
|
Arguments:
|
|
[IN] pwszText : Address of the string being searched.
|
|
[IN] pwszTextToFind : Substring to search for.
|
|
[IN] bIgnoreCase : Flag to check for case sensitive/in-sensitive
|
|
If FALSE, case sensitive else in-sensitive
|
|
[IN] dwFrom : to start from the location
|
|
|
|
|
|
Return Value:
|
|
0L : On failure
|
|
Long value : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dwLength = 0;
|
|
DWORD dwFindLength = 0;
|
|
LPWSTR pwsz = NULL;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the inputs
|
|
if ( pwszText == NULL || pwszTextToFind == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return -1;
|
|
}
|
|
|
|
// get the lengths
|
|
dwLength = StringLength( pwszText, 0 );
|
|
dwFindLength = StringLength( pwszTextToFind, 0 );
|
|
|
|
// check the length of the text that has to be find. if it is
|
|
// more than the original it is obvious that it cannot be found
|
|
if ( dwFindLength == 0 || dwLength == 0 ||
|
|
dwFrom >= dwLength || (dwLength - dwFrom < dwFindLength) )
|
|
{
|
|
SetLastError( ERROR_NOT_FOUND );
|
|
return -1;
|
|
}
|
|
|
|
// do the search
|
|
if ( bIgnoreCase == TRUE )
|
|
{
|
|
pwsz = StrStrI( pwszText + dwFrom, pwszTextToFind );
|
|
}
|
|
else
|
|
{
|
|
pwsz = StrStr( pwszText + dwFrom, pwszTextToFind );
|
|
}
|
|
|
|
if ( pwsz == NULL )
|
|
{
|
|
// string not found
|
|
SetLastError( ERROR_NOT_FOUND );
|
|
return -1;
|
|
}
|
|
|
|
// determine the position an return
|
|
return (LONG) (DWORD_PTR)(pwsz - pwszText);
|
|
}
|
|
|
|
|
|
LONG
|
|
StringLengthInBytes( IN LPCWSTR pwszText )
|
|
/*++
|
|
Routine Description:
|
|
Finds length of a given string
|
|
|
|
Arguments:
|
|
[IN] pwszText : Address of the string being searched.
|
|
|
|
Return Value:
|
|
0L : On failure
|
|
Long value : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lLength = 0;
|
|
|
|
if ( NULL == pwszText || StringLength( pwszText, 0 ) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// get the length of the string in bytes
|
|
// since this function includes the count for null character also, ignore that information
|
|
lLength = WideCharToMultiByte( _DEFAULT_CODEPAGE, 0, pwszText, -1, NULL, 0, NULL, NULL ) - 1;
|
|
|
|
// return the length information
|
|
return lLength;
|
|
}
|
|
|
|
|
|
LPCWSTR
|
|
TrimString( IN OUT LPWSTR pwszString,
|
|
IN DWORD dwFlags )
|
|
/*++
|
|
Routine Description:
|
|
Removes (trims) spaces/tabs from a string.
|
|
|
|
Arguments:
|
|
[IN] pwszString : Address of the string to be trimmed.
|
|
[IN] dwFlags : Flags to trim LEFT or RIGHT or both sides
|
|
|
|
Return Value:
|
|
0L : On failure
|
|
Long value : On success
|
|
--*/
|
|
{
|
|
return TrimString2( pwszString, NULL, dwFlags );
|
|
|
|
}
|
|
|
|
|
|
LPCWSTR
|
|
TrimString2( IN OUT LPWSTR pwszString,
|
|
IN LPCWSTR pwszTrimChars,
|
|
IN DWORD dwFlags )
|
|
/*++
|
|
Routine Description:
|
|
Removes (trims) specified leading and trailing characters from a string.
|
|
|
|
Arguments:
|
|
[IN] pwszString : Address of the string to be trimmed.
|
|
[IN] pwszString : characters will be trimmed from pwszString.
|
|
[IN] dwFlags : Flags to trim LEFT or RIGHT or both sides
|
|
|
|
Return Value:
|
|
0L : On failure
|
|
Long value : On success
|
|
--*/
|
|
{
|
|
//sub-local variables
|
|
LPWSTR psz = NULL;
|
|
LPWSTR pszStartMeAt = NULL;
|
|
LPWSTR pszMark = NULL;
|
|
const WCHAR wszDefaultTrimChars[3] = L" \t";
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check for empty string
|
|
if ( NULL == pwszString || StringLength( pwszString , 0 ) == 0 )
|
|
{
|
|
// there is no need to set any error here..
|
|
// if string is empty.. then return the same.
|
|
return cwszNullString;
|
|
}
|
|
|
|
// check for empty string.. if pwszTrimChars is empty,
|
|
// by default it trims spaces and tabs
|
|
if ( NULL == pwszTrimChars || StringLength( pwszTrimChars, 0 ) == 0 )
|
|
{
|
|
pwszTrimChars = wszDefaultTrimChars;
|
|
|
|
}
|
|
|
|
//
|
|
// Trim leading characters.
|
|
//
|
|
psz = pwszString;
|
|
|
|
//check whether to trim left or both side(s)
|
|
if ( (dwFlags == TRIM_ALL) || (dwFlags == TRIM_LEFT) )
|
|
{
|
|
//search for character(s) to trim
|
|
while (*psz && StrChrW(pwszTrimChars, *psz))
|
|
{
|
|
//increment the address
|
|
psz++;
|
|
}
|
|
|
|
pszStartMeAt = psz;
|
|
}
|
|
|
|
//
|
|
// Trim trailing characters.
|
|
//
|
|
|
|
//check whether to trim right or both side(s)
|
|
if ( (dwFlags == TRIM_ALL) || (dwFlags == TRIM_RIGHT) )
|
|
{
|
|
if (dwFlags == TRIM_RIGHT)
|
|
{
|
|
psz = pwszString;
|
|
}
|
|
|
|
while (*psz)
|
|
{
|
|
//search for character(s) to trim
|
|
if (StrChrW(pwszTrimChars, *psz))
|
|
{
|
|
if (!pszMark)
|
|
{
|
|
pszMark = psz;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pszMark = NULL;
|
|
}
|
|
|
|
//increment the address
|
|
psz++;
|
|
}
|
|
|
|
// Any trailing characters to clip?
|
|
if ( pszMark != NULL )
|
|
{
|
|
// Yes.. set NULL character..
|
|
*pszMark = '\0';
|
|
}
|
|
|
|
}
|
|
|
|
/* Relocate stripped string. */
|
|
|
|
if (pszStartMeAt > pwszString)
|
|
{
|
|
/* (+ 1) for null terminator. */
|
|
StringCopy ( pwszString, pszStartMeAt, StringLength(pszStartMeAt, 0) + 1 );
|
|
}
|
|
|
|
// return the trimmed string
|
|
return pwszString;
|
|
}
|
|
|
|
|
|
LPCWSTR
|
|
QuoteMeta( IN LPCWSTR pwszText,
|
|
IN DWORD dwQuoteIndex )
|
|
/*++
|
|
Routine Description:
|
|
Formats the string properly if the string contains any '%' characters
|
|
|
|
Arguments:
|
|
[IN] pwszString : Address of the string.
|
|
[IN] dwQuoteIndex : Index number
|
|
|
|
Return Value:
|
|
NULL : On failure
|
|
LPWSTR : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
DWORD dwIndex = 0;
|
|
DWORD dwBufLen = 0;
|
|
DWORD dwLength = 0;
|
|
TARRAY arrQuotes = NULL;
|
|
LPCWSTR pwszTemp = NULL;
|
|
LPWSTR pwszQuoteText = NULL;
|
|
const WCHAR pwszQuoteChars[] = L"%";
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the inputs
|
|
if ( pwszText == NULL || dwQuoteIndex == 0 )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// determine the length of the text that needs to be quoted
|
|
dwLength = StringLength( pwszText, 0 );
|
|
if ( dwLength == 0 )
|
|
{
|
|
return pwszText;
|
|
}
|
|
|
|
// check whether the special chacters do exist in the text or not
|
|
// if not, simply return
|
|
else if ( FindOneOf( pwszText, pwszQuoteChars, 0 ) == NULL )
|
|
{
|
|
return pwszText;
|
|
}
|
|
|
|
// initialize the global data structure
|
|
if ( InitGlobals() == FALSE )
|
|
{
|
|
return cwszNullString;
|
|
}
|
|
|
|
// get the quotes array pointer
|
|
arrQuotes = DynArrayItem( g_arrData, INDEX_QUOTE_STRING );
|
|
if ( arrQuotes == NULL )
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// though the quote index needs to be > 0 when passing to this function,
|
|
// internally we need this to be 1 less than the value passed -- so
|
|
dwQuoteIndex--;
|
|
|
|
// check whether needed indexes exist or not
|
|
dwIndex = DynArrayGetCount( arrQuotes );
|
|
if ( dwIndex <= dwQuoteIndex )
|
|
{
|
|
// add the needed no. of columns
|
|
dw = DynArrayAddColumns( arrQuotes, dwQuoteIndex - dwIndex + 1 );
|
|
|
|
// check whether columns were added or not
|
|
if ( dw != dwQuoteIndex - dwIndex + 1 )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return cwszNullString;
|
|
}
|
|
}
|
|
|
|
// allocate the buffer ... it should twice the original
|
|
dwBufLen = (dwLength + 1) * 2;
|
|
pwszQuoteText = GetTempBuffer( 0, NULL, dwBufLen, TRUE );
|
|
if ( pwszQuoteText == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// do the quoting ...
|
|
dwIndex = 0;
|
|
for( dw = 0; dw < dwLength; dw++ )
|
|
{
|
|
// check whether the current character is quote char or not
|
|
// NOTE: for time being this function only suppresses the '%' character escape sequences
|
|
if ( FindChar( pwszQuoteChars, pwszText[ dw ], 0 ) != NULL )
|
|
{
|
|
pwszQuoteText[ dwIndex++ ] = L'%';
|
|
}
|
|
|
|
// copy the character
|
|
pwszQuoteText[ dwIndex++ ] = pwszText[ dw ];
|
|
|
|
// it is obvious that we wont come into this condition
|
|
// but, makes no difference if we are more cautious on this
|
|
if ( dwIndex == dwBufLen - 1 )
|
|
{
|
|
// error, error -- we should never come here
|
|
// this is because even if the original string is full of
|
|
// '%' characters, we are allocating memory for two null characters
|
|
// which means, the loop should be terminated before falling into
|
|
// this condition
|
|
break;
|
|
}
|
|
}
|
|
|
|
// put the null character
|
|
pwszQuoteText[ dwIndex ] = cwchNullChar;
|
|
|
|
// save the quoted text in dynamic array
|
|
if ( DynArraySetString( arrQuotes, dwQuoteIndex, pwszQuoteText, 0 ) == FALSE )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// get the text from the array
|
|
pwszTemp = DynArrayItemAsString( arrQuotes, dwQuoteIndex );
|
|
if ( pwszTemp == NULL )
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// return
|
|
return pwszTemp;
|
|
}
|
|
|
|
|
|
LPCWSTR
|
|
AdjustStringLength( IN LPWSTR pwszValue,
|
|
IN DWORD dwLength,
|
|
IN BOOL bPadLeft )
|
|
/*++
|
|
Routine Description:
|
|
Adjusts the string length by padding spaces for displaying output in
|
|
LIST, TABLE or CSV formats
|
|
|
|
Arguments:
|
|
[IN] pwszValue : Address of the string.
|
|
[IN] dwLength : Index number
|
|
[IN] bPadLeft : Flag to pad left/right spaces
|
|
|
|
Return Value:
|
|
NULL : On failure
|
|
LPWSTR : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
DWORD dwTemp = 0;
|
|
DWORD dwBufLen = 0;
|
|
DWORD dwCurrLength = 0;
|
|
LPWSTR pwszBuffer = NULL;
|
|
LPWSTR pwszSpaces = NULL;
|
|
WCHAR wszCharacter[ 3 ] = L"\0"; // two WCHAR's is enough -- but took 3
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input value
|
|
if ( pwszValue == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// determine the buffer length required
|
|
// ( accomadate some extra space than the original buffer/required length -
|
|
// this will save us from crashes )
|
|
dw = StringLengthInBytes( pwszValue );
|
|
dwBufLen = (( dw > dwLength ) ? dw : dwLength ) + 10;
|
|
|
|
// ...
|
|
if ( (pwszBuffer = GetTempBuffer( 0, NULL, dwBufLen, TRUE )) == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// ...
|
|
dwCurrLength = dw;
|
|
|
|
// adjust the string value
|
|
if ( dwCurrLength < dwLength )
|
|
{
|
|
//
|
|
// length of the current value is less than the needed
|
|
|
|
// get the pointers to the temporary buffers
|
|
if ( (pwszSpaces = GetTempBuffer( 1, NULL, dwBufLen, TRUE )) == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// get the spaces for the rest of the length
|
|
Replicate( pwszSpaces, L" ", dwLength - dwCurrLength, dwBufLen );
|
|
|
|
// append the spaces either to the end of the value or begining of the value
|
|
// based on the padding property
|
|
if ( bPadLeft == TRUE )
|
|
{
|
|
// spaces first and then value
|
|
StringCopy( pwszBuffer, pwszSpaces, dwBufLen );
|
|
StringConcat( pwszBuffer, pwszValue, dwBufLen );
|
|
}
|
|
else
|
|
{
|
|
// value first and then spaces
|
|
StringCopy( pwszBuffer, pwszValue, dwBufLen );
|
|
StringConcat( pwszBuffer, pwszSpaces, dwBufLen );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// copy only the characters of required length
|
|
// copy character by character
|
|
dwCurrLength = 0;
|
|
for( dw = 0; dwCurrLength < dwLength; dw++ )
|
|
{
|
|
// get the character -- 1 + 1 ( character + NULL character )
|
|
StringCopy( wszCharacter, pwszValue + dw, 2 );
|
|
|
|
// determine whether character can be appended or not
|
|
dwTemp = dwCurrLength + StringLengthInBytes( wszCharacter );
|
|
if ( dwTemp <= dwLength )
|
|
{
|
|
StringConcat( pwszBuffer, wszCharacter, dwBufLen );
|
|
}
|
|
else if ( dwTemp > dwLength )
|
|
{
|
|
break;
|
|
}
|
|
|
|
// get the current string length
|
|
dwCurrLength = dwTemp;
|
|
}
|
|
|
|
// target buffer might not got filled completely
|
|
// so, add needed no. of spaces
|
|
for( ; dwCurrLength < dwLength; dwCurrLength++ )
|
|
{
|
|
StringConcat( pwszBuffer, L" ", dwBufLen );
|
|
}
|
|
}
|
|
|
|
// copy the contents back to the original buffer
|
|
// NOTE: Buffer length assumed to be passed +1 to the length asked to adjust
|
|
StringCopy( pwszValue, pwszBuffer, dwLength + 1 );
|
|
|
|
// return the same buffer back to the caller
|
|
return pwszValue;
|
|
}
|
|
|
|
|
|
LPCWSTR
|
|
Replicate( IN LPWSTR pwszBuffer,
|
|
IN LPCWSTR pwszText,
|
|
IN DWORD dwCount,
|
|
IN DWORD dwLength )
|
|
/*++
|
|
Routine Description:
|
|
Adjusts the string length by padding spaces for displaying output in
|
|
LIST, TABLE or CSV formats
|
|
|
|
Arguments:
|
|
[IN] pwszBuffer : Address of the string to be replicated.
|
|
[IN] pwszText : String used for replicate
|
|
[IN] dwCount : Number of characters
|
|
[IN] dwLength : Length of a string
|
|
|
|
Return Value:
|
|
NULL : On failure
|
|
LPWSTR : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// validate the input buffers
|
|
if ( pwszBuffer == NULL || pwszText == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return cwszNullString;
|
|
}
|
|
|
|
// form the string of required length
|
|
StringCopy( pwszBuffer, cwszNullString, dwLength );
|
|
for( dw = 0; dw < dwCount; dw++ )
|
|
{
|
|
// append the replication character
|
|
if ( StringConcat( pwszBuffer, pwszText, dwLength ) == FALSE )
|
|
{
|
|
// not an error condition -- but might destination buffer
|
|
// might have got filled
|
|
break;
|
|
}
|
|
}
|
|
|
|
// return the replicated buffer
|
|
return pwszBuffer;
|
|
}
|
|
|
|
BOOL
|
|
IsConsoleFile( IN FILE* fp )
|
|
/*++
|
|
Routine Description:
|
|
checks whether the file handle passed is console file or not
|
|
|
|
Arguments:
|
|
[IN] fp : File pointer
|
|
|
|
Return Value:
|
|
NULL : On failure
|
|
LPWSTR : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
INT filenum = 0;
|
|
LONG_PTR lHandle = 0;
|
|
HANDLE hFile = NULL;
|
|
DWORD dwType = 0;
|
|
DWORD dwMode = 0;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input file pointer
|
|
if ( fp == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
// get internal file index
|
|
filenum = (_fileno)( fp ); // forcing for the function version
|
|
|
|
// now get the file handle from file index and then get the type of the file
|
|
lHandle = _get_osfhandle( filenum );
|
|
if ( lHandle == -1 || errno == EBADF )
|
|
{
|
|
// set the last error
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
|
|
// return
|
|
return FALSE;
|
|
}
|
|
|
|
// now get the type of the file handle
|
|
dwType = GetFileType( ( HANDLE ) lHandle );
|
|
|
|
// check the type of the file -- if it is not ANSI, we wont treat it as a console file
|
|
if ( dwType != FILE_TYPE_CHAR )
|
|
{
|
|
// return -- this is not an error condition --
|
|
// so we are not setting error
|
|
return FALSE;
|
|
}
|
|
|
|
// now based on the file index, get the appropriate handle
|
|
switch( filenum )
|
|
{
|
|
case 0:
|
|
{
|
|
// stdin
|
|
hFile = GetStdHandle( STD_INPUT_HANDLE );
|
|
break;
|
|
}
|
|
|
|
case 1:
|
|
{
|
|
// stdout
|
|
hFile = GetStdHandle( STD_OUTPUT_HANDLE );
|
|
break;
|
|
}
|
|
|
|
|
|
case 2:
|
|
{
|
|
// stderr
|
|
hFile = GetStdHandle( STD_ERROR_HANDLE );
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hFile = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// check the file handle
|
|
if ( hFile == NULL )
|
|
{
|
|
// file internal index couldn't be found
|
|
// this is also not an error check -- so no error
|
|
return FALSE;
|
|
}
|
|
else if ( hFile == INVALID_HANDLE_VALUE )
|
|
{
|
|
// this is a failure case
|
|
// GetStdHandle would have set the appropriate error
|
|
return FALSE;
|
|
}
|
|
|
|
// get the console file mode
|
|
if ( GetConsoleMode( hFile, &dwMode ) == FALSE )
|
|
{
|
|
// error occured in getting the console mode --
|
|
// this means, it is not a valid console file
|
|
// GetConsoleMode would have set the error code
|
|
return FALSE;
|
|
}
|
|
|
|
// yes -- the file handle passed to this function is console file
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LCID
|
|
GetSupportedUserLocale( IN OUT BOOL* pbLocaleChanged )
|
|
/*++
|
|
Routine Description:
|
|
check whether the current locale is supported by our tool or not
|
|
|
|
Arguments:
|
|
[IN] pbLocaleChanged : Flag
|
|
|
|
Return Value:
|
|
0 : On failure
|
|
LCID : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LCID lcid;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// get the current locale
|
|
lcid = GetUserDefaultLCID();
|
|
|
|
// check whether the current locale is supported by our tool or not
|
|
// if not change the locale to the english which is our default locale
|
|
if ( pbLocaleChanged != NULL )
|
|
{
|
|
*pbLocaleChanged = FALSE;
|
|
}
|
|
|
|
// ...
|
|
if ( PRIMARYLANGID( lcid ) == LANG_ARABIC || PRIMARYLANGID( lcid ) == LANG_HEBREW ||
|
|
PRIMARYLANGID( lcid ) == LANG_THAI || PRIMARYLANGID( lcid ) == LANG_HINDI ||
|
|
PRIMARYLANGID( lcid ) == LANG_TAMIL || PRIMARYLANGID( lcid ) == LANG_FARSI )
|
|
{
|
|
if ( pbLocaleChanged != NULL )
|
|
{
|
|
*pbLocaleChanged = TRUE;
|
|
|
|
}
|
|
|
|
// ...
|
|
lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ), SORT_DEFAULT ); // 0x409;
|
|
}
|
|
|
|
// return the locale
|
|
return lcid;
|
|
}
|
|
|
|
|
|
BOOL
|
|
StringCopyA( IN OUT LPSTR pszDest,
|
|
IN LPCSTR pszSource,
|
|
IN LONG lSize )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Copies static ANSI string to a buffer
|
|
|
|
Arguments:
|
|
[ in/out ] pszDest => Destination buffer
|
|
[ in ] pszSource => Source buffer
|
|
[ in ] lSize => length of destination buffer
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// for historical reasons we neither clear the error
|
|
// not set the error in this function
|
|
//
|
|
|
|
// validate the arguments
|
|
if ( pszDest == NULL || pszSource == NULL || lSize <= 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// do the copy
|
|
hr = StringCchCopyA( pszDest, lSize, pszSource );
|
|
|
|
// check for hr value
|
|
if ( FAILED( hr ) )
|
|
{
|
|
//set the error code
|
|
SetLastError( HRESULT_CODE( hr ) );
|
|
return FALSE;
|
|
}
|
|
|
|
// return success
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
StringCopyW( IN OUT LPWSTR pwszDest,
|
|
IN LPCWSTR pwszSource,
|
|
IN LONG lSize )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Copies static UNICODE string to a buffer
|
|
|
|
Arguments:
|
|
[ in/out ] pwszDest => Destination buffer
|
|
[ in ] pszSource => Source buffer
|
|
[ in ] lSize => length of destination buffer
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// for historical reasons we neither clear the error
|
|
// not set the error in this function
|
|
//
|
|
|
|
// validate the arguments
|
|
if ( pwszDest == NULL || pwszSource == NULL || lSize <= 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// do the copy
|
|
hr = StringCchCopyW( pwszDest, lSize, pwszSource );
|
|
|
|
// check for hr value
|
|
if ( FAILED( hr ) )
|
|
{
|
|
//set the error code
|
|
SetLastError( HRESULT_CODE( hr ) );
|
|
return FALSE;
|
|
}
|
|
|
|
// return
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
StringConcatA( IN OUT LPSTR pszDest,
|
|
IN LPCSTR pszSource,
|
|
IN LONG lSize )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Appends one static ANSI string to another
|
|
|
|
Arguments:
|
|
[ in/out ] pwszDest => Destination buffer
|
|
[ in ] pszSource => Source buffer
|
|
[ in ] lSize => length of destination buffer
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variable
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// for historical reasons we neither clear the error
|
|
// not set the error in this function
|
|
//
|
|
|
|
// validate the arguments
|
|
if ( pszDest == NULL || pszSource == NULL || lSize <= 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// get the current length of the current contents in the destination
|
|
hr = StringCchCatA( pszDest, lSize, pszSource );
|
|
|
|
// check for hr value
|
|
if ( FAILED( hr ) )
|
|
{
|
|
//set the error code
|
|
SetLastError( HRESULT_CODE( hr ) );
|
|
return FALSE;
|
|
}
|
|
|
|
// return
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
StringConcatW( IN OUT LPWSTR pwszDest,
|
|
IN LPCWSTR pwszSource,
|
|
IN LONG lSize )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Appends one UNICODE string to another
|
|
|
|
Arguments:
|
|
[ in/out ] pwszDest => Destination buffer
|
|
[ in ] pszSource => Source buffer
|
|
[ in ] lSize => length of destination buffer
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variable
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// for historical reasons we neither clear the error
|
|
// not set the error in this function
|
|
//
|
|
|
|
// validate the arguments
|
|
if ( pwszDest == NULL || pwszSource == NULL || lSize <= 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// do the concatenation
|
|
hr = StringCchCatW( pwszDest, lSize, pwszSource );
|
|
|
|
// check for hr value
|
|
if ( FAILED( hr ) )
|
|
{
|
|
//set the error code
|
|
SetLastError( HRESULT_CODE( hr ) );
|
|
return FALSE;
|
|
}
|
|
|
|
// return
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
StringCopyExA( IN OUT LPSTR pszDest,
|
|
IN LPCSTR pszSource )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Copies dynamic ANSI string to a buffer
|
|
|
|
Arguments:
|
|
[ in/out ] pszDest => Destination buffer
|
|
[ in ] pszSource => Source buffer
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lSize = 0;
|
|
|
|
//
|
|
// for historical reasons we neither clear the error
|
|
// not set the error in this function
|
|
//
|
|
|
|
// validate the inputs
|
|
if ( pszDest == NULL || pszSource == NULL )
|
|
{
|
|
// invalid arguments passed to the function
|
|
return FALSE;
|
|
}
|
|
|
|
// get the size of the destination buffer
|
|
lSize = GetBufferSize( pszDest );
|
|
if ( lSize < 0 )
|
|
{
|
|
// the source buffer is not allocated on heap
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// convert the size into TCHARs
|
|
lSize /= sizeof( CHAR );
|
|
}
|
|
|
|
// do the copy and return
|
|
return StringCopyA( pszDest, pszSource, lSize );
|
|
}
|
|
|
|
|
|
BOOL StringCopyExW( IN OUT LPWSTR pwszDest,
|
|
IN LPCWSTR pwszSource )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Copies dynamic ANSI string to another
|
|
|
|
Arguments:
|
|
[ in/out ] pwszDest => Destination buffer
|
|
[ in ] pwszSource => Source buffer
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lSize = 0;
|
|
|
|
//
|
|
// for historical reasons we neither clear the error
|
|
// not set the error in this function
|
|
//
|
|
|
|
// validate the inputs
|
|
if ( pwszDest == NULL || pwszSource == NULL )
|
|
{
|
|
// invalid arguments passed to the function
|
|
return FALSE;
|
|
}
|
|
|
|
// get the size of the destination buffer
|
|
lSize = GetBufferSize( pwszDest );
|
|
if ( lSize < 0 )
|
|
{
|
|
// the source buffer is not allocated on heap
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// convert the size into TCHARs
|
|
lSize /= sizeof( WCHAR );
|
|
}
|
|
|
|
// do the copy and return
|
|
return StringCopyW( pwszDest, pwszSource, lSize );
|
|
}
|
|
|
|
|
|
BOOL
|
|
StringConcatExA( IN OUT LPSTR pszDest,
|
|
IN LPCSTR pszSource )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Appends dynamic ANSI string to a buffer
|
|
|
|
Arguments:
|
|
[ in/out ] pszDest => Destination buffer
|
|
[ in ] pszSource => Source buffer
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lSize = 0;
|
|
|
|
//
|
|
// for historical reasons we neither clear the error
|
|
// not set the error in this function
|
|
//
|
|
|
|
// validate the inputs
|
|
if ( pszDest == NULL || pszSource == NULL )
|
|
{
|
|
// invalid arguments passed to the function
|
|
return FALSE;
|
|
}
|
|
|
|
// get the size of the destination buffer
|
|
lSize = GetBufferSize( pszDest );
|
|
if ( lSize < 0 )
|
|
{
|
|
// the source buffer is not allocated on heap
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// convert the size into CHARs
|
|
lSize /= sizeof( CHAR );
|
|
}
|
|
|
|
// do the concatenation and return
|
|
return StringConcatA( pszDest, pszSource, lSize );
|
|
}
|
|
|
|
BOOL
|
|
StringConcatExW( IN OUT LPWSTR pwszDest,
|
|
IN LPCWSTR pwszSource )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Appends one dynamic ANSI string to another
|
|
|
|
Arguments:
|
|
[ in/out ] pwszDest => Destination buffer
|
|
[ in ] pwszSource => Source buffer
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lSize = 0;
|
|
|
|
//
|
|
// for historical reasons we neither clear the error
|
|
// not set the error in this function
|
|
//
|
|
|
|
// validate the inputs
|
|
if ( pwszDest == NULL || pwszSource == NULL )
|
|
{
|
|
// invalid arguments passed to the function
|
|
return FALSE;
|
|
}
|
|
|
|
// get the size of the destination buffer
|
|
lSize = GetBufferSize( pwszDest );
|
|
if ( lSize < 0 )
|
|
{
|
|
// the source buffer is not allocated on heap
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// convert the size into WCHARs
|
|
lSize /= sizeof( WCHAR );
|
|
}
|
|
|
|
// do the concatenation and return
|
|
return StringConcatW( pwszDest, pwszSource, lSize );
|
|
}
|
|
|
|
|
|
DWORD
|
|
StringLengthA( IN LPCSTR pszSource,
|
|
IN DWORD dwReserved )
|
|
/*++
|
|
Routine Description:
|
|
Finds the number of bytes in a ANSI string
|
|
|
|
Arguments:
|
|
[ in ] pszSource => String
|
|
|
|
Return Value:
|
|
int
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER( dwReserved );
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// validate the input
|
|
if ( NULL == pszSource )
|
|
{
|
|
// empty string..return 0..
|
|
return 0;
|
|
}
|
|
|
|
// return the length of string
|
|
return ( lstrlenA( pszSource ) );
|
|
}
|
|
|
|
|
|
DWORD
|
|
StringLengthW( IN LPCWSTR pwszSource,
|
|
IN DWORD dwReserved )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Finds the number of characters in a UNICODE string
|
|
|
|
Arguments:
|
|
[ in ] pszSource => String
|
|
|
|
Return Value:
|
|
int
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER( dwReserved );
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// validate the input
|
|
if ( NULL == pwszSource )
|
|
{
|
|
// empty string..return 0..
|
|
return 0;
|
|
}
|
|
|
|
// return the length of string
|
|
return ( lstrlenW( pwszSource ) );
|
|
}
|
|
|
|
|
|
LONG
|
|
StringCompareW( IN LPCWSTR pwszString1,
|
|
IN LPCWSTR pwszString2,
|
|
IN BOOL bIgnoreCase,
|
|
IN DWORD dwCount )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Compares two character strings, using the specified locale.
|
|
|
|
Arguments:
|
|
[in] pwszString1 => first string
|
|
[in] pwszString2 => second string
|
|
[in] bIgnoreCase => Flag to indicate case sensitive/in-sensitive
|
|
[in] dwCount => number of characters to be compared
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lResult = 0;
|
|
LONG lLength = 0;
|
|
DWORD dwFlags = 0;
|
|
|
|
// check the input value
|
|
if ( pwszString1 == NULL || pwszString2 == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return 0;
|
|
}
|
|
|
|
// determine the flags
|
|
dwFlags = (bIgnoreCase == TRUE) ? NORM_IGNORECASE : 0;
|
|
|
|
// determine the length
|
|
lLength = (dwCount == 0) ? -1 : dwCount;
|
|
|
|
lResult = CompareStringW( GetThreadLocale(),
|
|
dwFlags, pwszString1, lLength, pwszString2, lLength );
|
|
|
|
// now return comparision result
|
|
// to this function in consistent with C-runtime, we need to subtract 2
|
|
// lResult return from CompareString
|
|
return lResult - 2;
|
|
}
|
|
|
|
|
|
LONG
|
|
StringCompareA( IN LPCSTR pszString1,
|
|
IN LPCSTR pszString2,
|
|
IN BOOL bIgnoreCase,
|
|
IN DWORD dwCount )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Compares two character strings, using the specified locale.
|
|
|
|
Arguments:
|
|
[in] pwszString1 => first string
|
|
[in] pwszString2 => second string
|
|
[in] bIgnoreCase => Flag to indicate case sensitive/in-sensitive
|
|
[in] dwCount => number of characters to be compared
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lResult = 0;
|
|
LONG lLength = 0;
|
|
DWORD dwFlags = 0;
|
|
|
|
// check the input value
|
|
if ( pszString1 == NULL || pszString2 == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return 0;
|
|
}
|
|
|
|
// determine the flags
|
|
dwFlags = (bIgnoreCase == TRUE) ? NORM_IGNORECASE : 0;
|
|
|
|
// determine the length
|
|
lLength = (dwCount == 0) ? -1 : dwCount;
|
|
|
|
lResult = CompareStringA( GetThreadLocale(),
|
|
dwFlags, pszString1, lLength, pszString2, lLength );
|
|
|
|
// now return comparision result
|
|
// to this function in consistent with C-runtime, we need to subtract 2
|
|
// lResult return from CompareString
|
|
return lResult - 2;
|
|
}
|
|
|
|
|
|
LONG
|
|
StringCompareExW( IN LPCWSTR pwszString1,
|
|
IN LPCWSTR pwszString2,
|
|
IN BOOL bIgnoreCase,
|
|
IN DWORD dwCount )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Compares two character strings, using the specified locale.
|
|
|
|
Arguments:
|
|
[in] pwszString1 => first string
|
|
[in] pwszString2 => second string
|
|
[in] bIgnoreCase => Flag to indicate case sensitive/in-sensitive
|
|
[in] dwCount => number of characters to be compared
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lResult = 0;
|
|
LONG lLength = 0;
|
|
DWORD dwFlags = 0;
|
|
DWORD lcid = 0;
|
|
|
|
// check the input value
|
|
if ( pwszString1 == NULL || pwszString2 == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return 0;
|
|
}
|
|
|
|
// determine the flags
|
|
dwFlags = (bIgnoreCase == TRUE) ? NORM_IGNORECASE : 0;
|
|
|
|
// determine the length
|
|
lLength = (dwCount == 0) ? -1 : dwCount;
|
|
|
|
// prepare the LCID
|
|
// if this tool is designed to work on XP and earlier, then
|
|
// we can use LOCALE_INVARIANT -- otherwise, we need to prepare the lcid
|
|
lcid = LOCALE_INVARIANT;
|
|
if ( g_dwMajorVersion == 5 && g_dwMinorVersion == 0 )
|
|
{
|
|
// tool desgined to work on pre-windows xp
|
|
lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT );
|
|
}
|
|
|
|
lResult = CompareStringW( lcid,
|
|
dwFlags, pwszString1, lLength, pwszString2, lLength );
|
|
|
|
// now return comparision result
|
|
// to this function in consistent with C-runtime, we need to subtract 2
|
|
// lResult return from CompareString
|
|
return lResult - 2;
|
|
}
|
|
|
|
|
|
LONG
|
|
StringCompareExA( IN LPCSTR pszString1,
|
|
IN LPCSTR pszString2,
|
|
IN BOOL bIgnoreCase,
|
|
IN DWORD dwCount )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Compares two character strings, using the specified locale.
|
|
|
|
Arguments:
|
|
[in] pszString1 => first string
|
|
[in] pszString2 => second string
|
|
[in] bIgnoreCase => Flag to indicate case sensitive/in-sensitive
|
|
[in] dwCount => number of characters to be compared
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lResult = 0;
|
|
LONG lLength = 0;
|
|
DWORD dwFlags = 0;
|
|
DWORD lcid = 0;
|
|
|
|
// check the input value
|
|
if ( pszString1 == NULL || pszString2 == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return 0;
|
|
}
|
|
|
|
// determine the flags
|
|
dwFlags = (bIgnoreCase == TRUE) ? NORM_IGNORECASE : 0;
|
|
|
|
// determine the length
|
|
lLength = (dwCount == 0) ? -1 : dwCount;
|
|
|
|
// prepare the LCID
|
|
// if this tool is designed to work on XP and earlier, then
|
|
// we can use LOCALE_INVARIANT -- otherwise, we need to prepare the lcid
|
|
lcid = LOCALE_INVARIANT;
|
|
if ( g_dwMajorVersion == 5 && g_dwMinorVersion == 0 )
|
|
{
|
|
// tool desgined to work on pre-windows xp
|
|
lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT );
|
|
}
|
|
|
|
lResult = CompareStringA( lcid,
|
|
dwFlags, pszString1, lLength, pszString2, lLength );
|
|
|
|
// now return comparision result
|
|
// to this function in consistent with C-runtime, we need to subtract 2
|
|
// lResult return from CompareString
|
|
return lResult - 2;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ShowResMessage( IN FILE* fp,
|
|
IN UINT uID )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Displays the message based on resource ID
|
|
|
|
Arguments:
|
|
[in] fp => file pointer
|
|
[in] uID => resource ID
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// show the string from the resource table and return
|
|
return ShowMessage( fp, GetResString( uID ) );
|
|
}
|
|
|
|
BOOL
|
|
ShowMessage( FILE* fp,
|
|
LPCWSTR pwszMessage )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Displays the message with the given file pointer
|
|
|
|
Arguments:
|
|
[in] fp => file pointer
|
|
[in] pwszMessage => Message
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
DWORD dwTemp = 0;
|
|
DWORD dwLength = 0;
|
|
DWORD dwBufferSize = 0;
|
|
DWORD dwSourceBuffer = 0;
|
|
BOOL bResult = FALSE;
|
|
HANDLE hOutput = NULL;
|
|
LPCWSTR pwszTemp = NULL;
|
|
static char szBuffer[ 256 ] = "\0";
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input value
|
|
if ( fp == NULL || pwszMessage == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
// determine whether the handle passed is a console file or not
|
|
if ( IsConsoleFile( fp ) == TRUE )
|
|
{
|
|
// determine the file handle
|
|
if ( fp == stdout )
|
|
{
|
|
// handle to stdout
|
|
hOutput = GetStdHandle( STD_OUTPUT_HANDLE );
|
|
}
|
|
else if ( fp == stderr )
|
|
{
|
|
// handle to stderr
|
|
hOutput = GetStdHandle( STD_ERROR_HANDLE );
|
|
}
|
|
else
|
|
{
|
|
// there is no way that fp will not match with
|
|
// stderr and stdout -- but still
|
|
UNEXPECTED_ERROR();
|
|
return FALSE;
|
|
}
|
|
|
|
// get the length info.
|
|
dwTemp = 0;
|
|
dwLength = StringLength( pwszMessage, 0 );
|
|
|
|
// display the output
|
|
bResult = WriteConsole( hOutput, pwszMessage, dwLength, &dwTemp, NULL );
|
|
if ( bResult == FALSE || dwLength != dwTemp )
|
|
{
|
|
// buffer might not be sufficient -- check it
|
|
if ( GetLastError() == ERROR_NOT_ENOUGH_MEMORY )
|
|
{
|
|
// this is the only error that could occur
|
|
// NOTE: we will display the buffer in chunks of 1024 characters
|
|
dwLength = StringLength( pwszMessage, 0 );
|
|
for( dw = 0; dw < dwLength; dw += 1024 )
|
|
{
|
|
// write 256 characters at time
|
|
dwBufferSize = ((dwLength - dw) > 1024 ? 1024 : (dwLength - dw));
|
|
bResult = WriteConsole( hOutput,
|
|
pwszMessage + dw, dwBufferSize, &dwTemp, NULL );
|
|
if ( bResult == FALSE || dwBufferSize != dwTemp )
|
|
{
|
|
// can't help -- still the same error -- unexpected behaviour
|
|
ShowLastError( stderr );
|
|
ReleaseGlobals();
|
|
ExitProcess( 1 );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// unexpected error occured -- no idea
|
|
ShowLastError( stderr );
|
|
ReleaseGlobals();
|
|
ExitProcess( 1 );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// determine the length(s)
|
|
// NOTE: we need to the surround all '%' characters with extra '%'
|
|
// character to show it as it is
|
|
pwszTemp = QuoteMeta( pwszMessage, 1 );
|
|
dwLength = StringLength( pwszTemp, 0 );
|
|
dwBufferSize = SIZE_OF_ARRAY( szBuffer );
|
|
|
|
// zero the szBuffer
|
|
ZeroMemory( szBuffer, dwBufferSize * sizeof( CHAR ) );
|
|
|
|
// show the text in shunks of buffer size
|
|
dw = 0;
|
|
dwBufferSize--; // from this point lets assume that the ANSI
|
|
// buffer is 1 less than its actual size
|
|
while ( dwLength > dw )
|
|
{
|
|
dwTemp = 0;
|
|
dwSourceBuffer = ((dwBufferSize < (dwLength - dw)) ? dwBufferSize : (dwLength - dw));
|
|
while ( dwTemp == 0 )
|
|
{
|
|
// determine the ANSI buffer space required sufficient to
|
|
// transform the current UNICODE string length
|
|
dwTemp = WideCharToMultiByte( GetConsoleOutputCP(),
|
|
0, pwszTemp + dw, dwSourceBuffer, NULL, 0, NULL, NULL );
|
|
|
|
// if the ANSI buffer space is not sufficient
|
|
if ( dwTemp == 0 )
|
|
{
|
|
ShowLastError( stdout );
|
|
ReleaseGlobals();
|
|
ExitProcess( 1 );
|
|
}
|
|
else if ( dwTemp > dwBufferSize )
|
|
{
|
|
if ( (dwTemp - dwBufferSize) > 3 )
|
|
{
|
|
dwSourceBuffer -= (dwTemp - dwBufferSize) / 2;
|
|
}
|
|
else
|
|
{
|
|
dwSourceBuffer--;
|
|
}
|
|
|
|
// reset the temp variable inorder to continue the loop
|
|
dwTemp = 0;
|
|
|
|
// check the source buffer contents
|
|
if ( dwSourceBuffer == 0 )
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
ShowLastError( stdout );
|
|
ReleaseGlobals();
|
|
ExitProcess( 1 );
|
|
}
|
|
}
|
|
else if ( dwTemp < dwSourceBuffer )
|
|
{
|
|
dwSourceBuffer = dwTemp;
|
|
}
|
|
}
|
|
|
|
// get the string in 'multibyte' format
|
|
ZeroMemory( szBuffer, SIZE_OF_ARRAY( szBuffer ) * sizeof( CHAR ) );
|
|
dwTemp = WideCharToMultiByte( GetConsoleOutputCP(), 0,
|
|
pwszTemp + dw, dwSourceBuffer, szBuffer, dwBufferSize, NULL, NULL );
|
|
|
|
// check the result
|
|
if ( dwTemp == 0 )
|
|
{
|
|
ShowLastError( stdout );
|
|
ReleaseGlobals();
|
|
ExitProcess( 1 );
|
|
}
|
|
|
|
// determine the remaining buffer length
|
|
dw += dwSourceBuffer;
|
|
|
|
// display string onto the specified file
|
|
fprintf( fp, szBuffer );
|
|
fflush( fp );
|
|
// bResult = WriteFile( fp, szBuffer, StringLengthA( szBuffer, 0 ), &dwTemp, NULL );
|
|
// if ( bResult == FALSE ||
|
|
// StringLengthA( szBuffer, 0 ) != (LONG) dwTemp ||
|
|
// FlushFileBuffers( fp ) == FALSE )
|
|
// {
|
|
// UNEXPECTED_ERROR();
|
|
// ReleaseGlobals();
|
|
// ExitProcess( 1 );
|
|
// }
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ShowMessageEx(
|
|
FILE* fp,
|
|
DWORD dwCount,
|
|
BOOL bStyle,
|
|
LPCWSTR pwszFormat,
|
|
...)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Replaces a string containing " %1, %2 ... " or "%s, %d, %f ..." with
|
|
appropriate values depending upon the way arguments are given as input.
|
|
|
|
Arguments:
|
|
|
|
[ IN ] FILE* fp - Contains file on to which message is to be copied.
|
|
[ IN ] DWORD dwCount - Contains number of arguments for 'va_list'
|
|
following 'lpszFormat'.
|
|
[ IN ] BOOL bStyle - If TRUE then formatting is done using "_vstprint",
|
|
if FALSE then formatting is done using "FormatMessage".
|
|
[ IN ] LPCTSTR lpszFormat - String which needs to formatted.
|
|
|
|
Return value:
|
|
|
|
TRUE - If successful in displaying message.
|
|
FALSE - If failed to display message or memory is insufficient.
|
|
|
|
---*/
|
|
|
|
{
|
|
// local variables
|
|
va_list vargs; // Contains start variable of variable arguments.
|
|
BOOL bResult = FALSE; // Contains return value.
|
|
LPWSTR pwszBuffer = NULL; // Contains mem location of variable arguments.
|
|
DWORD dwBufferLength = 0;
|
|
LONG lCount = -1;
|
|
HRESULT hr = S_OK;
|
|
|
|
// Check for any NULL argument passed as input.
|
|
if( NULL == pwszFormat || NULL == fp )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
// check how many variable arguments did caller passed
|
|
// if it is zero, just call the ShowMessage -- no need to proceed furthur
|
|
if ( dwCount == 0 )
|
|
{
|
|
return ShowMessage( fp, pwszFormat );
|
|
}
|
|
|
|
// Formatting is done using 'Format message' or '_vstprintf'?
|
|
if ( FALSE == bStyle )
|
|
{
|
|
// init
|
|
lCount = -1;
|
|
dwBufferLength = 0;
|
|
|
|
// try the FormatMessage
|
|
do
|
|
{
|
|
// get the variable args start position
|
|
va_start( vargs, pwszFormat );
|
|
if ( vargs == NULL )
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
return FALSE;
|
|
}
|
|
|
|
// we will start with buffer length of 4K buffer and then increment
|
|
// the buffer by 2K each time we run thru this loop
|
|
dwBufferLength += (lCount == -1) ? 4096 : 2048;
|
|
if ( (pwszBuffer = GetTempBuffer( INDEX_TEMP_SHOWMESSAGE,
|
|
NULL, dwBufferLength, TRUE )) == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
// try the FormatMessage
|
|
lCount = FormatMessageW( FORMAT_MESSAGE_FROM_STRING,
|
|
pwszFormat, 0, 0, pwszBuffer, dwBufferLength - 1, &vargs );
|
|
|
|
// check the result
|
|
if ( lCount == 0 )
|
|
{
|
|
if ( GetLastError() == NO_ERROR )
|
|
{
|
|
// there is nothing to show
|
|
return TRUE;
|
|
}
|
|
else if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// reset the va_list parameter
|
|
va_end( vargs );
|
|
} while ( lCount == 0 );
|
|
}
|
|
|
|
// Formatting is done using '_vsnwprintf'.
|
|
else
|
|
{
|
|
// init
|
|
dwBufferLength = 0;
|
|
|
|
// try the printf
|
|
do
|
|
{
|
|
// get the variable args start position
|
|
va_start( vargs, pwszFormat );
|
|
if ( vargs == NULL )
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
return FALSE;
|
|
}
|
|
|
|
// we will start with buffer length of 4K buffer and then increment
|
|
// the buffer by 2K each time we run thru this loop
|
|
dwBufferLength += (lCount == 0) ? 4096 : 2048;
|
|
if ( (pwszBuffer = GetTempBuffer( INDEX_TEMP_SHOWMESSAGE,
|
|
NULL, dwBufferLength, TRUE )) == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
// try the printf
|
|
hr = StringCchVPrintfW( pwszBuffer, dwBufferLength, pwszFormat, vargs );
|
|
|
|
// reset the va_list parameter
|
|
va_end( vargs );
|
|
} while ( hr == STRSAFE_E_INSUFFICIENT_BUFFER );
|
|
|
|
// check whether we came out of the loop 'coz of the some other error
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SetLastError( HRESULT_CODE( hr ) );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// a safety check
|
|
if ( pwszBuffer == NULL )
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
return FALSE;
|
|
}
|
|
|
|
// show the output
|
|
bResult = ShowMessage( fp, pwszBuffer );
|
|
|
|
// return
|
|
return bResult;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Routine Description:
|
|
//
|
|
// ///////////////////////////////////////////////////////////////////////////
|
|
// NOTE:
|
|
// ----
|
|
// functions which i dont want to support any more -- they are just lying for
|
|
// compatiblity sake -- if at all you are facing any problem with these
|
|
// functions you better upgrade to version 2.0 -- but absoultely there is no
|
|
// support for this function
|
|
//
|
|
// ///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Return Value:
|
|
//
|
|
// ***************************************************************************
|
|
LPSTR
|
|
GetAsMultiByteString( IN LPCWSTR pwszSource,
|
|
IN OUT LPSTR pszDestination,
|
|
IN DWORD dwLength )
|
|
/*++
|
|
Routine Description:
|
|
convert string from UNICODE version to ANSI version
|
|
|
|
Arguments:
|
|
[IN] pszSource : UNICODE version of string
|
|
[IN/OUT] pwszDestination : ANSI version of string
|
|
[IN/OUT] dwLength : Length of a string
|
|
|
|
Return Value:
|
|
NULL_STRING : On failure
|
|
LPWSTR : On success
|
|
--*/
|
|
{
|
|
if ( GetAsMultiByteString2( pwszSource,
|
|
pszDestination,
|
|
&dwLength ) == FALSE )
|
|
{
|
|
return "";
|
|
}
|
|
|
|
// return the destination buffer
|
|
return pszDestination;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
//
|
|
// ///////////////////////////////////////////////////////////////////////////
|
|
// NOTE:
|
|
// ----
|
|
// functions which i dont want to support any more -- they are just lying for
|
|
// compatiblity sake -- if at all you are facing any problem with these
|
|
// functions you better upgrade to version 2.0 -- but absoultely there is no
|
|
// support for this function
|
|
//
|
|
// ///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ***************************************************************************
|
|
|
|
LPWSTR
|
|
GetAsUnicodeStringEx( IN LPCSTR pszSource,
|
|
IN OUT LPWSTR pwszDestination,
|
|
IN DWORD dwLength )
|
|
/*++
|
|
Routine Description:
|
|
convert string from ANSI version to UNICODE version
|
|
|
|
Arguments:
|
|
[IN] pszSource : Source string
|
|
[IN/OUT] pwszDestination : Unicode version of String
|
|
[IN/OUT] dwLength : Length of a string
|
|
|
|
Return Value:
|
|
NULL_STRING : On failure
|
|
LPWSTR : On success
|
|
--*/
|
|
{
|
|
if ( GetAsUnicodeString2( pszSource,
|
|
pwszDestination,
|
|
&dwLength ) == FALSE )
|
|
{
|
|
return L"";
|
|
}
|
|
|
|
// return the destination buffer
|
|
return pwszDestination;
|
|
}
|
|
|
|
BOOL
|
|
GetAsUnicodeString2( IN LPCSTR pszSource,
|
|
IN OUT LPWSTR pwszDestination,
|
|
IN OUT DWORD* pdwLength )
|
|
/*++
|
|
Routine Description:
|
|
convert string from ANSI version to UNICODE version
|
|
|
|
Arguments:
|
|
[IN] pszSource : Source string
|
|
[IN/OUT] pwszDestination : Unicode version of String
|
|
[IN/OUT] dwLength : Length of a string
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
DWORD dwLength = 0;
|
|
LONG lSourceLength = 0;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input values
|
|
if ( pszSource == NULL || pdwLength == NULL ||
|
|
( pwszDestination == NULL && *pdwLength != 0 ) )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
// ...
|
|
if ( *pdwLength != 0 )
|
|
{
|
|
if ( *pdwLength > 1 )
|
|
{
|
|
dwLength = (*pdwLength) - 1;
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory( pwszDestination, *pdwLength * sizeof( wchar_t ) );
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// initialize the values with zeros
|
|
// NOTE:- MultiByteToWideChar wont null terminate its result so
|
|
// if its not initialized to nulls, you'll get junk after
|
|
// the converted string and will result in crashes
|
|
if ( pwszDestination != NULL && dwLength != 0 )
|
|
{
|
|
ZeroMemory( pwszDestination, (dwLength + 1) * sizeof( wchar_t ) );
|
|
}
|
|
|
|
// determine the source length to pass to the function call
|
|
lSourceLength = -1;
|
|
if ( dwLength != 0 )
|
|
{
|
|
lSourceLength = StringLengthA( pszSource, 0 );
|
|
if ( lSourceLength > (LONG) dwLength )
|
|
{
|
|
lSourceLength = dwLength;
|
|
}
|
|
}
|
|
|
|
// convert string from ANSI version to UNICODE version
|
|
dw = MultiByteToWideChar( _DEFAULT_CODEPAGE, 0,
|
|
pszSource, lSourceLength, pwszDestination, dwLength );
|
|
if ( dw == 0 )
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
|
|
// to keep the destination buffer clean and safe
|
|
if ( pwszDestination != NULL && dwLength != 0 )
|
|
{
|
|
ZeroMemory( pwszDestination, (dwLength + 1) * sizeof( wchar_t ) );
|
|
}
|
|
|
|
// failure
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
*pdwLength = dw;
|
|
}
|
|
|
|
// success
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetAsMultiByteString2( IN LPCWSTR pwszSource,
|
|
IN OUT LPSTR pszDestination,
|
|
IN OUT DWORD* pdwLength )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Complex scripts cannot be rendered in the console, so we
|
|
force the English (US) resource.
|
|
|
|
Arguments:
|
|
[IN] pwszSource : Source string
|
|
[IN|OUT] pszDestination : Multibyte string
|
|
[IN] pdwLength : length of the text string
|
|
|
|
Return Value:
|
|
TRUE : on Success
|
|
FALSE : On Failure
|
|
--*/
|
|
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
DWORD dwLength = 0;
|
|
LONG lSourceLength = 0;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input values
|
|
if ( pwszSource == NULL || pdwLength == NULL ||
|
|
( pszDestination == NULL && *pdwLength != 0 ) )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
// ...
|
|
if ( *pdwLength != 0 )
|
|
{
|
|
if ( *pdwLength > 1 )
|
|
{
|
|
dwLength = (*pdwLength) - 1;
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory( pszDestination, *pdwLength * sizeof( char ) );
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// initialize the values with zeros
|
|
// NOTE:- WideCharToMultiByte wont null terminate its result so
|
|
// if its not initialized to nulls, you'll get junk after
|
|
// the converted string and will result in crashes
|
|
if ( pszDestination != NULL && dwLength != 0 )
|
|
{
|
|
ZeroMemory( pszDestination, (dwLength + 1) * sizeof( char ) );
|
|
}
|
|
|
|
// determine the source length to pass to the function call
|
|
lSourceLength = -1;
|
|
if ( dwLength != 0 )
|
|
{
|
|
lSourceLength = StringLengthW( pwszSource, 0 );
|
|
if ( lSourceLength > (LONG) dwLength )
|
|
{
|
|
lSourceLength = dwLength;
|
|
}
|
|
}
|
|
// convert string from UNICODE version to ANSI version
|
|
dw = WideCharToMultiByte( _DEFAULT_CODEPAGE, 0,
|
|
pwszSource, lSourceLength, pszDestination, dwLength, NULL, NULL );
|
|
if ( dw == 0 )
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
|
|
// to keep the destination buffer clean and safe
|
|
if ( pszDestination != NULL && dwLength != 0 )
|
|
{
|
|
ZeroMemory( pszDestination, (dwLength + 1) * sizeof( char ) );
|
|
}
|
|
|
|
// failure
|
|
return FALSE;
|
|
}
|
|
|
|
// success
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetPassword( LPWSTR pwszPassword,
|
|
DWORD dwMaxPasswordSize )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Takes the password from the keyboard. While entering the password it shows
|
|
the charecters as '*'
|
|
|
|
Arguments:
|
|
[in] pszPassword --password string to store password
|
|
[in] dwMaxPasswordSize --Maximun size of the password. MAX_PASSWORD_LENGTH.
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
CHAR ch;
|
|
WCHAR wch;
|
|
DWORD dwIndex = 0;
|
|
DWORD dwCharsRead = 0;
|
|
DWORD dwCharsWritten = 0;
|
|
DWORD dwPrevConsoleMode = 0;
|
|
HANDLE hInputConsole = NULL;
|
|
CHAR szBuffer[ 10 ] = "\0"; // actually contains only character at all the times
|
|
WCHAR wszBuffer[ 10 ] = L"\0"; // actually contains only character at all the times
|
|
BOOL bIndirectionInput = FALSE;
|
|
|
|
// check the input value
|
|
if ( pwszPassword == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
// get the handle for the standard input
|
|
hInputConsole = GetStdHandle( STD_INPUT_HANDLE );
|
|
if ( hInputConsole == NULL )
|
|
{
|
|
// could not get the handle so return failure
|
|
return FALSE;
|
|
}
|
|
|
|
// check for the input redirection on console and telnet session
|
|
if( ( hInputConsole != (HANDLE)0x0000000F ) &&
|
|
( hInputConsole != (HANDLE)0x00000003 ) &&
|
|
( hInputConsole != INVALID_HANDLE_VALUE ) )
|
|
{
|
|
bIndirectionInput = TRUE;
|
|
}
|
|
|
|
// redirect the data from StdIn.txt file into the console
|
|
if ( bIndirectionInput == FALSE )
|
|
{
|
|
// Get the current input mode of the input buffer
|
|
GetConsoleMode( hInputConsole, &dwPrevConsoleMode );
|
|
|
|
// Set the mode such that the control keys are processed by the system
|
|
if ( SetConsoleMode( hInputConsole, ENABLE_PROCESSED_INPUT ) == 0 )
|
|
{
|
|
// could not set the mode, return failure
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// init the unicode and ansi buffers to NULL
|
|
ZeroMemory( szBuffer, SIZE_OF_ARRAY( szBuffer ) * sizeof( CHAR ) );
|
|
ZeroMemory( wszBuffer, SIZE_OF_ARRAY( wszBuffer ) * sizeof( WCHAR ) );
|
|
|
|
// Read the characters until a carriage return is hit
|
|
for( ;; )
|
|
{
|
|
if ( bIndirectionInput == TRUE )
|
|
{
|
|
//read the contents of file
|
|
if ( ReadFile( hInputConsole, &ch, 1, &dwCharsRead, NULL ) == FALSE )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// check for end of file
|
|
if ( dwCharsRead == 0 )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// convert the ANSI character into UNICODE character
|
|
szBuffer[ 0 ] = ch;
|
|
dwCharsRead = SIZE_OF_ARRAY( wszBuffer );
|
|
GetAsUnicodeString2( szBuffer, wszBuffer, &dwCharsRead );
|
|
wch = wszBuffer[ 0 ];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ReadConsole( hInputConsole, &wch, 1, &dwCharsRead, NULL ) == 0 )
|
|
{
|
|
// Set the original console settings
|
|
SetConsoleMode( hInputConsole, dwPrevConsoleMode );
|
|
|
|
// return failure
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Check for carraige return
|
|
if ( wch == CARRIAGE_RETURN )
|
|
{
|
|
// break from the loop
|
|
break;
|
|
}
|
|
|
|
// Check id back space is hit
|
|
if ( wch == BACK_SPACE )
|
|
{
|
|
if ( dwIndex != 0 )
|
|
{
|
|
//
|
|
// Remove a asterix from the console
|
|
|
|
// move the cursor one character back
|
|
StringCchPrintfW(
|
|
wszBuffer,
|
|
SIZE_OF_ARRAY( wszBuffer ), L"%c", BACK_SPACE );
|
|
WriteConsole(
|
|
GetStdHandle( STD_OUTPUT_HANDLE ),
|
|
wszBuffer, 1, &dwCharsWritten, NULL );
|
|
|
|
// replace the existing character with space
|
|
StringCchPrintfW(
|
|
wszBuffer,
|
|
SIZE_OF_ARRAY( wszBuffer ), L"%c", BLANK_CHAR );
|
|
WriteConsole(
|
|
GetStdHandle( STD_OUTPUT_HANDLE ),
|
|
wszBuffer, 1, &dwCharsWritten, NULL );
|
|
|
|
// now set the cursor at back position
|
|
StringCchPrintfW(
|
|
wszBuffer,
|
|
SIZE_OF_ARRAY( wszBuffer ), L"%c", BACK_SPACE );
|
|
WriteConsole(
|
|
GetStdHandle( STD_OUTPUT_HANDLE ),
|
|
wszBuffer, 1, &dwCharsWritten, NULL );
|
|
|
|
// decrement the index
|
|
dwIndex--;
|
|
}
|
|
|
|
// process the next character
|
|
continue;
|
|
}
|
|
|
|
// if the max password length has been reached then sound a beep
|
|
if ( dwIndex == ( dwMaxPasswordSize - 1 ) )
|
|
{
|
|
WriteConsole(
|
|
GetStdHandle( STD_OUTPUT_HANDLE ),
|
|
BEEP_SOUND, 1, &dwCharsWritten, NULL );
|
|
}
|
|
else
|
|
{
|
|
// check for new line character
|
|
if ( wch != L'\n' )
|
|
{
|
|
// store the input character
|
|
*( pwszPassword + dwIndex ) = wch;
|
|
dwIndex++;
|
|
|
|
// display asterix onto the console
|
|
WriteConsole(
|
|
GetStdHandle( STD_OUTPUT_HANDLE ),
|
|
ASTERIX, 1, &dwCharsWritten, NULL );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add the NULL terminator
|
|
*( pwszPassword + dwIndex ) = cwchNullChar;
|
|
|
|
//Set the original console settings
|
|
SetConsoleMode( hInputConsole, dwPrevConsoleMode );
|
|
|
|
// display the character ( new line character )
|
|
StringCopy( wszBuffer, L"\n\n", SIZE_OF_ARRAY( wszBuffer ) );
|
|
WriteConsole(
|
|
GetStdHandle( STD_OUTPUT_HANDLE ),
|
|
wszBuffer, 2, &dwCharsWritten, NULL );
|
|
|
|
// Return success
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
FreeMemory( IN OUT LPVOID* ppv )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Frees a memory block allocated from a heap
|
|
|
|
Arguments:
|
|
[in] ppv => buffer
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LONG lSize = 0;
|
|
HANDLE hHeap = NULL;
|
|
BOOL bResult = FALSE;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input
|
|
if ( ppv == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
else if ( *ppv == NULL )
|
|
{
|
|
// just a NULL pointer -- not an error -- just return
|
|
return TRUE;
|
|
}
|
|
|
|
// get the handle to process heap
|
|
hHeap = GetProcessHeap();
|
|
if ( hHeap == NULL )
|
|
{
|
|
// GetProcessHeap will set the error code
|
|
return FALSE;
|
|
}
|
|
|
|
// it is a safe technique to clear the contents of the memory being released
|
|
lSize = GetBufferSize( *ppv );
|
|
if ( lSize == -1 )
|
|
{
|
|
// looks like this is not a valid buffer pointer
|
|
SetLastError( (DWORD) E_POINTER );
|
|
return FALSE;
|
|
}
|
|
|
|
// ...
|
|
ZeroMemory( *ppv, lSize );
|
|
|
|
// release the memory
|
|
bResult = HeapFree( hHeap, 0, *ppv );
|
|
|
|
// we need not check the result here
|
|
// ir-respective of whether the function call is successful or not
|
|
// clear the contents of the pointer -- this will help us in eliminating
|
|
// furthur failures
|
|
*ppv = NULL;
|
|
|
|
// return
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CheckMemory( IN OUT LPVOID pv )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Attempts to validate a specified heap.
|
|
|
|
Arguments:
|
|
[in/out] ppv => buffer
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
HANDLE hHeap = NULL;
|
|
BOOL bResult = FALSE;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input
|
|
if ( pv == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
// get the handle to process heap
|
|
hHeap = GetProcessHeap();
|
|
if ( hHeap == NULL )
|
|
{
|
|
// GetProcessHeap will set the error code
|
|
return FALSE;
|
|
}
|
|
|
|
// validate the memory address
|
|
bResult = HeapValidate( hHeap, 0, pv );
|
|
if ( bResult == FALSE )
|
|
{
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
return FALSE;
|
|
}
|
|
|
|
// return
|
|
return bResult;
|
|
}
|
|
|
|
|
|
LPVOID
|
|
AllocateMemory( IN DWORD dwBytes )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Allocates a block of memory from a heap.
|
|
|
|
|
|
Arguments:
|
|
[in] dwBytesNew => number of bytes to reallocate
|
|
|
|
Return Value:
|
|
NULL : On failure
|
|
pv : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LPVOID pv = NULL;
|
|
HANDLE hHeap = NULL;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input
|
|
if ( dwBytes <= 0 )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return NULL;
|
|
}
|
|
|
|
// get the handle to process heap
|
|
hHeap = GetProcessHeap();
|
|
if ( hHeap == NULL )
|
|
{
|
|
// GetProcessHeap will set the error code
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// for safe play with heap allocation -- we use structured exception handling
|
|
//
|
|
|
|
__try
|
|
{
|
|
// allocate memory
|
|
pv = HeapAlloc( hHeap,
|
|
HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, dwBytes );
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
if ( GetExceptionCode() == STATUS_NO_MEMORY )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return NULL;
|
|
}
|
|
else if ( GetExceptionCode() == STATUS_ACCESS_VIOLATION )
|
|
{
|
|
SetLastError( ERROR_FILE_CORRUPT );
|
|
SaveLastError();
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// return the allocated the memory pointer
|
|
return pv;
|
|
}
|
|
|
|
BOOL
|
|
ReallocateMemory( IN OUT LPVOID* ppv,
|
|
IN DWORD dwBytesNew )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Reallocates a block of memory from a heap.
|
|
|
|
|
|
Arguments:
|
|
[in] ppv => buffer
|
|
[in] dwBytesNew => number of bytes to reallocate
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
LPVOID pvNew = NULL;
|
|
HANDLE hHeap = NULL;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input
|
|
if ( ppv == NULL || *ppv == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
else if ( dwBytesNew == 0 )
|
|
{
|
|
// caller wants to free the memory
|
|
return FreeMemory( ppv );
|
|
}
|
|
else if ( CheckMemory( *ppv ) == FALSE )
|
|
{
|
|
// memory handle is invalid
|
|
// set it to NULL -- this is to avoid furthur errors
|
|
*ppv = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
// get the handle to process heap
|
|
hHeap = GetProcessHeap();
|
|
if ( hHeap == NULL )
|
|
{
|
|
// GetProcessHeap will set the error code
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// for safe play with heap allocation -- we use structured exception handling
|
|
//
|
|
|
|
__try
|
|
{
|
|
// allocate memory
|
|
pvNew = HeapReAlloc( hHeap,
|
|
HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, *ppv, dwBytesNew );
|
|
|
|
// check for failure case
|
|
if ( pvNew == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
|
|
//assign the value ...
|
|
*ppv = pvNew;
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// we will not alter the passed memory pointer to this function
|
|
// in case of error -- the pointer will be returned as it is
|
|
//
|
|
|
|
if ( GetExceptionCode() == STATUS_NO_MEMORY )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
else if ( GetExceptionCode() == STATUS_ACCESS_VIOLATION )
|
|
{
|
|
SetLastError( ERROR_FILE_CORRUPT );
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// return the allocated the memory pointer
|
|
return TRUE;
|
|
}
|
|
|
|
LONG
|
|
GetBufferSize( IN OUT LPVOID pv )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Gets the size, in bytes, of a memory block allocated from a heap
|
|
|
|
|
|
Arguments:
|
|
[in] pv => buffer
|
|
|
|
Return Value:
|
|
FALSE : On failure
|
|
TRUE : On success
|
|
--*/
|
|
{
|
|
// local variables
|
|
HANDLE hHeap = NULL;
|
|
|
|
//
|
|
// for historical reasons we wont neither clear nor set the error code here
|
|
//
|
|
|
|
// check the input
|
|
if ( pv == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return -1;
|
|
}
|
|
else if ( CheckMemory( pv ) == FALSE )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
// get the handle to process heap
|
|
hHeap = GetProcessHeap();
|
|
if ( hHeap == NULL )
|
|
{
|
|
// GetProcessHeap will set the error code
|
|
return -1;
|
|
}
|
|
|
|
// return
|
|
return (DWORD)((DWORD_PTR)(HeapSize( hHeap, 0, pv )));
|
|
}
|
|
|
|
BOOL
|
|
MatchPattern(
|
|
IN LPWSTR szPat,
|
|
IN LPWSTR szFile
|
|
)
|
|
/*++
|
|
Routine Description : This routine is used to check whether file is mathced against
|
|
pattern or not.
|
|
|
|
[ IN ] szPat : A string variable pattern against which the file name to be matched.
|
|
|
|
[ IN ] szFile : A pattern string which specifies the file name to be matched.
|
|
|
|
|
|
Return Value : BOOL
|
|
Returns successfully if function is success other wise return failure.
|
|
--*/
|
|
|
|
{
|
|
switch (*szPat) {
|
|
case '\0':
|
|
return *szFile == L'\0';
|
|
case '?':
|
|
return *szFile != L'\0' && MatchPattern(szPat + 1, szFile + 1);
|
|
case '*':
|
|
do {
|
|
if (MatchPattern(szPat + 1, szFile))
|
|
return TRUE;
|
|
} while (*szFile++);
|
|
return FALSE;
|
|
default:
|
|
return toupper (*szFile) == toupper (*szPat) && MatchPattern(szPat + 1, szFile + 1);
|
|
}
|
|
}
|
|
|
|
|
|
LPCWSTR
|
|
ParsePattern( LPCWSTR pwszPattern )
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
DWORD dwLength = 0;
|
|
DWORD dwNewIndex = 0;
|
|
LPWSTR pwszNewPattern = NULL;
|
|
|
|
// check the pattern
|
|
if( pwszPattern == NULL ||
|
|
(dwLength = StringLength( pwszPattern, 0 )) == 0 )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return NULL;
|
|
}
|
|
|
|
// allocate the buffer for the pattern
|
|
pwszNewPattern = GetTempBuffer( INDEX_TEMP_PATTERN, NULL, dwLength + 10, TRUE );
|
|
if ( pwszNewPattern == NULL )
|
|
{
|
|
OUT_OF_MEMORY();
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// detect the un-necessary wild-card repetitions
|
|
// *, **, *****, *?*, *?*? etc -- all this combinations
|
|
// will result in just '*'
|
|
dwNewIndex = 0;
|
|
pwszNewPattern[ 0 ] = pwszPattern[ 0 ];
|
|
for( dw = 1; dw < dwLength; dw++ )
|
|
{
|
|
switch( pwszPattern[ dw ] )
|
|
{
|
|
case L'*':
|
|
case L'?':
|
|
{
|
|
if ( pwszNewPattern[ dwNewIndex ] == L'*' )
|
|
{
|
|
// since the pattern already contains the
|
|
// '*' and having another '*' after the existing
|
|
// '*' or having '?' after the '*' is of no use
|
|
// we will skip this character
|
|
break;
|
|
}
|
|
}
|
|
|
|
default:
|
|
dwNewIndex++;
|
|
pwszNewPattern[ dwNewIndex ] = pwszPattern[ dw ];
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwNewIndex++;
|
|
pwszNewPattern[ dwNewIndex ] = L'\0';
|
|
return pwszNewPattern;
|
|
}
|
|
|
|
|
|
BOOL
|
|
InternalRecursiveMatchPatternEx(
|
|
IN LPCWSTR pwszText,
|
|
IN LPCWSTR pwszPattern,
|
|
IN DWORD dwLocale,
|
|
IN DWORD dwCompareFlags,
|
|
IN DWORD dwDepth )
|
|
{
|
|
// local variables
|
|
BOOL bResult = FALSE;
|
|
DWORD dwTextIndex = 0;
|
|
DWORD dwPatternIndex = 0;
|
|
DWORD dwTextLength = 0;
|
|
DWORD dwPatternLength = 0;
|
|
|
|
// check the input
|
|
if ( pwszText == NULL || pwszPattern == NULL )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// search the string for the specified pattern
|
|
bResult = TRUE;
|
|
dwTextLength = StringLength( pwszText, 0 );
|
|
dwPatternLength = StringLength( pwszPattern, 0 );
|
|
for( dwPatternIndex = 0, dwTextIndex = 0; dwPatternIndex < dwPatternLength; )
|
|
{
|
|
// check the current text position --
|
|
// if it reached the end of the string, exit from the loop
|
|
if ( dwTextIndex >= dwTextLength )
|
|
{
|
|
break;
|
|
}
|
|
|
|
switch( pwszPattern[ dwPatternIndex ] )
|
|
{
|
|
case L'?':
|
|
{
|
|
// pattern allows any character at this position
|
|
// increment the text and pattern index
|
|
dwTextIndex++;
|
|
dwPatternIndex++;
|
|
break;
|
|
}
|
|
|
|
case L'*':
|
|
{
|
|
// pattern allows sequence of any characters
|
|
// to be specified from the current text index
|
|
// until the next character the index is found
|
|
// if the current '*' itself is the end of the
|
|
// pattern, then this text matches the pattern
|
|
if ( dwPatternIndex + 1 < dwPatternLength )
|
|
{
|
|
for( ; dwTextIndex < dwTextLength; dwTextIndex++ )
|
|
{
|
|
if ( CompareString( dwLocale,
|
|
dwCompareFlags,
|
|
pwszText + dwTextIndex, 1,
|
|
pwszPattern + dwPatternIndex + 1, 1 ) == CSTR_EQUAL )
|
|
{
|
|
// the current character in the text matched with the
|
|
// next character in the pattern --
|
|
// now check whether the text from the current index
|
|
// matches with the rest of the pattern
|
|
bResult = InternalRecursiveMatchPatternEx(
|
|
pwszText + dwTextIndex,
|
|
pwszPattern + dwPatternIndex + 1,
|
|
dwLocale, dwCompareFlags, dwDepth + 1 );
|
|
if ( bResult == TRUE )
|
|
{
|
|
// text matched with the pattern
|
|
// set the text index to its length
|
|
// this makes the end result to give TRUE
|
|
dwTextIndex = dwTextLength;
|
|
dwPatternIndex = dwPatternLength;
|
|
|
|
// break from the loop
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// looks like pattern is not matching
|
|
// from the current position -- skip some more characters
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// since we make the entire text matched with the pattern
|
|
// set the text index also to the length of the text
|
|
dwTextIndex = dwTextLength;
|
|
dwPatternIndex = dwPatternLength;
|
|
}
|
|
|
|
// ...
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
if ( CompareString( dwLocale,
|
|
dwCompareFlags,
|
|
pwszText + dwTextIndex, 1,
|
|
pwszPattern + dwPatternIndex, 1 ) == CSTR_EQUAL )
|
|
{
|
|
// update the text position by one character
|
|
dwTextIndex++;
|
|
dwPatternIndex++;
|
|
}
|
|
else
|
|
{
|
|
// character didn't match -- we should exit from the loop
|
|
bResult = FALSE;
|
|
}
|
|
|
|
// ...
|
|
break;
|
|
}
|
|
}
|
|
|
|
// check if any error is triggered in between or not
|
|
if ( bResult == FALSE )
|
|
{
|
|
// at some place mismatch is found
|
|
break;
|
|
}
|
|
}
|
|
|
|
// now the final check -- we need to know how we did we come out of the loop
|
|
// this we can determine by checking the pattern index position
|
|
// if the pattern index is equal to the length of the pattern length -- and
|
|
// the text index is equal to the the length of the text then the pattern is
|
|
// matched
|
|
if ( bResult != FALSE )
|
|
{
|
|
bResult = FALSE;
|
|
if ( dwTextIndex == dwTextLength && dwPatternIndex == dwPatternLength )
|
|
{
|
|
// pattern is matched
|
|
bResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// still our conclusion might not be correct
|
|
// for ex: the text "abc" perfectly matches with "???*"
|
|
// but our logic says this is not a valid text -- to aovid
|
|
// this sort of conflicts, we will do one more additional
|
|
// final check to confirm whether the text we have is valid or not
|
|
if ( dwTextIndex == dwTextLength &&
|
|
dwPatternIndex + 1 == dwPatternLength &&
|
|
StringCompareEx( pwszPattern + dwPatternIndex, L"*", TRUE, 1 ) == 0 )
|
|
{
|
|
// the text matches the pattern
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// return the result of the pattern matching
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MatchPatternEx(
|
|
IN LPCWSTR pwszText,
|
|
IN LPCWSTR pwszPattern,
|
|
IN DWORD dwFlags )
|
|
{
|
|
// local variables
|
|
BOOL bResult = FALSE;
|
|
|
|
// text comparision flags
|
|
LCID lcid = 0;
|
|
DWORD dwCompareFlags = 0;
|
|
|
|
// check the input
|
|
if ( pwszText == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// check the pattern
|
|
if ( pwszPattern == NULL )
|
|
{
|
|
// get the parsed pattern information
|
|
pwszPattern = GetTempBuffer( INDEX_TEMP_PATTERN, NULL, 0, FALSE );
|
|
if ( pwszPattern == NULL || StringLength( pwszPattern, 0 ) == 0 )
|
|
{
|
|
INVALID_PARAMETER();
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( (dwFlags & PATTERN_NOPARSING) == 0 )
|
|
{
|
|
// user passed a new pattern information parse and validate it
|
|
pwszPattern = ParsePattern( pwszPattern );
|
|
if ( pwszPattern == FALSE )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check whether we have the pattern information or not -- safety check
|
|
if ( pwszPattern == NULL )
|
|
{
|
|
UNEXPECTED_ERROR();
|
|
return FALSE;
|
|
}
|
|
|
|
// if the pattern is '*' we dont need to do any thing
|
|
// just pass TRUE to the caller
|
|
// the pattern will match to the any string
|
|
if ( StringCompareEx( pwszPattern, L"*", TRUE, 0 ) == 0 )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// determine the locale
|
|
if ( dwFlags & PATTERN_LOCALE_USENGLISH )
|
|
{
|
|
// prepare the LCID
|
|
// if this tool is designed to work on XP and earlier, then
|
|
// we can use LOCALE_INVARIANT -- otherwise, we need to prepare the lcid
|
|
lcid = LOCALE_INVARIANT;
|
|
if ( g_dwMajorVersion == 5 && g_dwMinorVersion == 0 )
|
|
{
|
|
// tool desgined to work on pre-windows xp
|
|
lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lcid = GetThreadLocale();
|
|
}
|
|
|
|
//
|
|
// determine the comparision flags
|
|
|
|
// NORM_IGNORECASE
|
|
if ( dwFlags & PATTERN_COMPARE_IGNORECASE )
|
|
{
|
|
dwCompareFlags |= NORM_IGNORECASE;
|
|
}
|
|
|
|
// NORM_IGNOREKANATYPE
|
|
if ( dwFlags & PATTERN_COMPARE_IGNOREKANATYPE )
|
|
{
|
|
dwCompareFlags |= NORM_IGNOREKANATYPE;
|
|
}
|
|
|
|
// NORM_IGNORENONSPACE
|
|
if ( dwFlags & PATTERN_COMPARE_IGNORENONSPACE )
|
|
{
|
|
dwCompareFlags |= NORM_IGNORENONSPACE;
|
|
}
|
|
|
|
// NORM_IGNORESYMBOLS
|
|
if ( dwFlags & PATTERN_COMPARE_IGNORESYMBOLS )
|
|
{
|
|
dwCompareFlags |= NORM_IGNORESYMBOLS;
|
|
}
|
|
|
|
// NORM_IGNOREWIDTH
|
|
if ( dwFlags & PATTERN_COMPARE_IGNOREWIDTH )
|
|
{
|
|
dwCompareFlags |= NORM_IGNOREWIDTH;
|
|
}
|
|
|
|
// SORT_STRINGSORT
|
|
if ( dwFlags & PATTERN_COMPARE_STRINGSORT )
|
|
{
|
|
dwCompareFlags |= SORT_STRINGSORT;
|
|
}
|
|
|
|
//
|
|
// check the pattern match
|
|
bResult = InternalRecursiveMatchPatternEx(
|
|
pwszText, pwszPattern, lcid, dwCompareFlags, 0 );
|
|
|
|
// return
|
|
return bResult;
|
|
}
|