windows-nt/Source/XPSP1/NT/printscan/print/spooler/spllib/string.cxx
2020-09-26 16:20:57 +08:00

596 lines
10 KiB
C++

/*++
Copyright (c) 1994 Microsoft Corporation
All rights reserved.
Module Name:
String.cxx
Abstract:
Short strings
Author:
Albert Ting (AlbertT) 9-June-1994
Revision History:
--*/
#include "spllibp.hxx"
#pragma hdrstop
//
// Class specific NULL state.
//
TCHAR TString::gszNullState[2] = {0,0};
//
// Default construction.
//
TString::
TString(
VOID
) : _pszString( &TString::gszNullState[kValid] )
{
}
//
// Construction using an existing LPCTSTR string.
//
TString::
TString(
IN LPCTSTR psz
) : _pszString( &TString::gszNullState[kValid] )
{
bUpdate( psz );
}
//
// Destruction, ensure we don't free our NULL state.
//
TString::
~TString(
VOID
)
{
vFree( _pszString );
}
//
// Copy constructor.
//
TString::
TString(
const TString &String
) : _pszString( &TString::gszNullState[kValid] )
{
bUpdate( String._pszString );
}
//
// Indicates if a string has any usable data.
//
BOOL
TString::
bEmpty(
VOID
) const
{
return _pszString[0] == 0;
}
//
// Indicates if a string object is valid.
//
BOOL
TString::
bValid(
VOID
) const
{
return _pszString != &TString::gszNullState[kInValid];
}
//
// Return the length of the string.
//
UINT
TString::
uLen(
VOID
) const
{
return lstrlen( _pszString );
}
BOOL
TString::
bCat(
IN LPCTSTR psz
)
/*++
Routine Description:
Safe concatenation of the specified string to the string
object. If the allocation fails, return FALSE and the
original string is not modified.
Arguments:
psz - Input string, may be NULL.
Return Value:
TRUE = update successful
FALSE = update failed
--*/
{
BOOL bStatus = FALSE;
//
// If a valid string was passed.
//
if( psz ){
LPTSTR pszTmp = _pszString;
//
// Allocate the new buffer consisting of the size of the orginal
// string plus the sizeof of the new string plus the null terminator.
//
_pszString = (LPTSTR)AllocMem(
( lstrlen( pszTmp ) +
lstrlen( psz ) +
1 ) *
sizeof ( pszTmp[0] ) );
//
// If memory was not available.
//
if( !_pszString ){
//
// Release the original buffer.
//
vFree( pszTmp );
//
// Mark the string object as invalid.
//
_pszString = &TString::gszNullState[kInValid];
} else {
//
// Copy the string and concatenate the passed string.
//
lstrcpy( _pszString, pszTmp );
lstrcat( _pszString, psz );
//
// Release the original buffer.
//
vFree( pszTmp );
//
// Indicate success.
//
bStatus = TRUE;
}
//
// Skip null pointers, not an error.
//
} else {
bStatus = TRUE;
}
return bStatus;
}
BOOL
TString::
bUpdate(
IN LPCTSTR psz
)
/*++
Routine Description:
Safe updating of string. If the allocation fails, return FALSE
and leave the string as is.
Arguments:
psz - Input string, may be NULL.
Return Value:
TRUE = update successful
FALSE = update failed
--*/
{
//
// Check if the null pointer is passed.
//
if( !psz ){
//
// If not pointing to the gszNullState
//
vFree( _pszString );
//
// Mark the object as valid.
//
_pszString = &TString::gszNullState[kValid];
return TRUE;
}
//
// Create temp pointer and allocate the new string.
//
LPTSTR pszTmp = _pszString;
_pszString = (LPTSTR) AllocMem(( lstrlen(psz)+1 ) * sizeof( psz[0] ));
//
// If memory was not available.
//
if( !_pszString ){
//
// Ensure we free any previous string.
//
vFree( pszTmp );
//
// Mark the string object as invalid.
//
_pszString = &TString::gszNullState[kInValid];
return FALSE;
}
//
// Copy the string and
//
lstrcpy( _pszString, psz );
//
// If the old string object was not pointing to our
// class specific gszNullStates then release the memory.
//
vFree( pszTmp );
return TRUE;
}
BOOL
TString::
bLoadString(
IN HINSTANCE hInst,
IN UINT uID
)
/*++
Routine Description:
Safe load of a string from a resources file.
Arguments:
hInst - Instance handle of resource file.
uId - Resource id to load.
Return Value:
TRUE = load successful
FALSE = load failed
--*/
{
LPTSTR pszString = NULL;
BOOL bStatus = FALSE;
INT iSize;
INT iLen;
//
// Continue increasing the buffer until
// the buffer is big enought to hold the entire string.
//
for( iSize = kStrMax; ; iSize += kStrMax ){
//
// Allocate string buffer.
//
pszString = (LPTSTR)AllocMem( iSize * sizeof( pszString[0] ) );
if( pszString ){
iLen = LoadString( hInst, uID, pszString, iSize );
if( iLen == 0 ) {
DBGMSG( DBG_ERROR, ( "String.vLoadString: failed to load IDS 0x%x, %d\n", uID, GetLastError() ));
FreeMem( pszString );
break;
//
// Since LoadString does not indicate if the string was truncated or it
// just happened to fit. When we detect this ambiguous case we will
// try one more time just to be sure.
//
} else if( iSize - iLen <= sizeof( pszString[0] ) ){
FreeMem( pszString );
//
// LoadString was successful release original string buffer
// and update new buffer pointer.
//
} else {
vFree( _pszString );
_pszString = pszString;
bStatus = TRUE;
break;
}
} else {
DBGMSG( DBG_ERROR, ( "String.vLoadString: unable to allocate memory, %d\n", GetLastError() ));
break;
}
}
return bStatus;
}
VOID
TString::
vFree(
IN LPTSTR pszString
)
/*++
Routine Description:
Safe free, frees the string memory. Ensures
we do not try an free our global memory block.
Arguments:
pszString pointer to string meory to free.
Return Value:
Nothing.
--*/
{
//
// If this memory was not pointing to our
// class specific gszNullStates then release the memory.
//
if( pszString != &TString::gszNullState[kValid] &&
pszString != &TString::gszNullState[kInValid] ){
FreeMem( pszString );
}
}
BOOL
TString::
bFormat(
IN LPCTSTR pszFmt,
IN ...
)
{
/*++
Routine Description:
Format the string opbject similar to sprintf.
Arguments:
pszFmt pointer format string.
.. variable number of arguments similar to sprintf.
Return Value:
TRUE if string was format successfully. FALSE if error
occurred creating the format string, string object will be
invalid and the previous string lost.
--*/
BOOL bStatus = TRUE;
va_list pArgs;
va_start( pArgs, pszFmt );
bStatus = bvFormat( pszFmt, pArgs );
va_end( pArgs );
return bStatus;
}
BOOL
TString::
bvFormat(
IN LPCTSTR pszFmt,
IN va_list avlist
)
/*++
Routine Description:
Format the string opbject similar to vsprintf.
Arguments:
pszFmt pointer format string.
pointer to variable number of arguments similar to vsprintf.
Return Value:
TRUE if string was format successfully. FALSE if error
occurred creating the format string, string object will be
invalid and the previous string lost.
--*/
{
BOOL bStatus;
//
// Save previous string value.
//
LPTSTR pszTemp = _pszString;
//
// Format the string.
//
_pszString = vsntprintf( pszFmt, avlist );
//
// If format failed mark object as invalid and
// set the return value.
//
if( !_pszString )
{
_pszString = &TString::gszNullState[kInValid];
bStatus = FALSE;
}
else
{
bStatus = TRUE;
}
//
// Release near the end because the format string or arguments
// may be referencing this string object.
//
vFree( pszTemp );
return bStatus;
}
LPTSTR
TString::
vsntprintf(
IN LPCTSTR szFmt,
IN va_list pArgs
)
/*++
Routine Description:
//
// Formats a string and returns a heap allocated string with the
// formated data. This routine can be used to for extremely
// long format strings. Note: If a valid pointer is returned
// the callng functions must release the data with a call to delete.
// Example:
//
// LPCTSTR p = vsntprintf("Test %s", pString );
//
// SetTitle( p );
//
// delete [] p;
//
Arguments:
pszString pointer format string.
pointer to a variable number of arguments.
Return Value:
Pointer to format string. NULL if error.
--*/
{
LPTSTR pszBuff = NULL;
INT iSize = kStrIncrement;
for( ; ; )
{
//
// Allocate the message buffer.
//
pszBuff = (LPTSTR)AllocMem( iSize * sizeof(TCHAR) );
if( !pszBuff )
{
break;
}
//
// Attempt to format the string. snprintf fails with a
// negative number when the buffer is too small.
//
INT iReturn = _vsntprintf( pszBuff, iSize, szFmt, pArgs );
//
// If the return value positive and not equal to the buffer size
// then the format succeeded. _vsntprintf will not null terminate
// the string if the resultant string is exactly the lenght of the
// provided buffer.
//
if( iReturn > 0 && iReturn != iSize )
{
break;
}
//
// String did not fit release the current buffer.
//
if( pszBuff )
{
FreeMem( pszBuff );
}
//
// Double the buffer size after each failure.
//
iSize *= 2;
//
// If the size is greater than 100k exit without formatting a string.
//
if( iSize > kStrMaxFormatSize )
{
DBGMSG( DBG_ERROR, ("TString::vsntprintf failed string too long.\n") );
pszBuff = NULL;
break;
}
}
return pszBuff;
}