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.
535 lines
14 KiB
535 lines
14 KiB
/**********************************************************************/
|
|
/** Microsoft Windows NT **/
|
|
/** Copyright(c) Microsoft Corp., 1999 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
string.hxx
|
|
|
|
This module contains a light weight string class.
|
|
|
|
|
|
FILE HISTORY:
|
|
Johnl 15-Aug-1994 Created
|
|
MuraliK 09-July-1996 Rewrote for efficiency with no unicode support
|
|
*/
|
|
|
|
|
|
#ifndef _STRINGA_HXX_
|
|
#define _STRINGA_HXX_
|
|
|
|
# include <irtlmisc.h>
|
|
# include <buffer.hxx>
|
|
class STRU;
|
|
|
|
//
|
|
// These are the characters that are considered to be white space
|
|
//
|
|
#define ISWHITE( ch ) ((ch) == L'\t' || (ch) == L' ' || (ch) == L'\r')
|
|
#define ISWHITEA( ch ) ((ch) == '\t' || (ch) == ' ' || (ch) == '\r')
|
|
|
|
//
|
|
// Is the specified character ASCII printable when dumping binary data?
|
|
//
|
|
#define IS_ASCII_PRINTABLE( ch ) ((ch > 31 && ch < 127) ? TRUE : FALSE)
|
|
#define IS_EXTENDED_ASCII_PRINTABLE( ch ) ((ch > 31 && ch < 176 ) ? TRUE : FALSE)
|
|
|
|
//
|
|
// Maximum number of characters a loadable string resource can be
|
|
//
|
|
#ifndef STR_MAX_RES_SIZE
|
|
#define STR_MAX_RES_SIZE ( 320 )
|
|
#endif
|
|
|
|
//
|
|
// If an application defines STR_MODULE_NAME, it will be used
|
|
// as the default module name on string loads
|
|
//
|
|
|
|
#ifndef STR_MODULE_NAME
|
|
#define STR_MODULE_NAME NULL
|
|
#endif
|
|
|
|
/*++
|
|
class STRA:
|
|
|
|
Intention:
|
|
A light-weight string class supporting encapsulated string class.
|
|
|
|
This object is derived from BUFFER class.
|
|
It maintains following state:
|
|
|
|
m_cchLen - string length cached when we update the string.
|
|
|
|
--*/
|
|
|
|
class IRTL_DLLEXP STRA;
|
|
|
|
class STRA
|
|
{
|
|
public:
|
|
|
|
STRA()
|
|
: m_Buff(),
|
|
m_cchLen( 0)
|
|
{
|
|
*QueryStr() = '\0';
|
|
}
|
|
|
|
//
|
|
// creates a stack version of the STRA object - uses passed in stack buffer
|
|
// STRA does not free this pbInit on its own.
|
|
//
|
|
STRA(CHAR *pbInit,
|
|
DWORD cbInit)
|
|
: m_Buff((BYTE *)pbInit, cbInit),
|
|
m_cchLen(0)
|
|
{
|
|
DBG_ASSERT(cbInit > 0);
|
|
|
|
*pbInit = '\0';
|
|
}
|
|
|
|
|
|
BOOL IsValid( VOID ) const { return ( m_Buff.IsValid() ) ; }
|
|
|
|
//
|
|
// Checks and returns TRUE if this string has no valid data else FALSE
|
|
//
|
|
BOOL IsEmpty() const
|
|
{
|
|
return (m_cchLen == 0);
|
|
}
|
|
|
|
//
|
|
// Returns TRUE if str has the same value as this string.
|
|
//
|
|
BOOL Equals(const STRA &str) const
|
|
{
|
|
return (str.QueryCCH() == QueryCCH()) &&
|
|
(strcmp(str.QueryStr(), QueryStr()) == 0);
|
|
}
|
|
|
|
//
|
|
// Returns TRUE if str has the same value as this string.
|
|
//
|
|
BOOL Equals(const PCHAR pchInit) const
|
|
{
|
|
if (pchInit == NULL || pchInit[0] == '\0')
|
|
{
|
|
return (IsEmpty());
|
|
}
|
|
return (strcmp(pchInit, QueryStr()) == 0);
|
|
}
|
|
|
|
//
|
|
// Case insensitive comparison
|
|
// Returns TRUE if str has the same value as this string.
|
|
//
|
|
BOOL EqualsNoCase(const STRA &str) const
|
|
{
|
|
return (str.QueryCCH() == QueryCCH()) &&
|
|
(_stricmp(str.QueryStr(), QueryStr()) == 0);
|
|
}
|
|
|
|
//
|
|
// Case insensitive comparison
|
|
// Returns TRUE if str has the same value as this string.
|
|
//
|
|
BOOL EqualsNoCase(const PCHAR pchInit) const
|
|
{
|
|
if (pchInit == NULL || pchInit[0] == '\0')
|
|
{
|
|
return (IsEmpty());
|
|
}
|
|
return (_stricmp(pchInit, QueryStr()) == 0);
|
|
}
|
|
|
|
//
|
|
// Returns the number of bytes in the string excluding the terminating
|
|
// NULL
|
|
//
|
|
UINT QueryCB() const
|
|
{
|
|
return m_cchLen;
|
|
}
|
|
|
|
//
|
|
// Returns # of characters in the string excluding the terminating NULL
|
|
//
|
|
UINT QueryCCH() const
|
|
{
|
|
return m_cchLen;
|
|
}
|
|
|
|
//
|
|
// Returns number of bytes in storage buffer
|
|
//
|
|
UINT QuerySize() const
|
|
{
|
|
return m_Buff.QuerySize();
|
|
}
|
|
|
|
//
|
|
// Return the string buffer
|
|
//
|
|
CHAR *QueryStr()
|
|
{
|
|
return (CHAR *)m_Buff.QueryPtr();
|
|
}
|
|
|
|
const CHAR *QueryStr() const
|
|
{
|
|
return (const CHAR *)m_Buff.QueryPtr();
|
|
}
|
|
|
|
|
|
//
|
|
// Resets the internal string to be NULL string. Buffer remains cached.
|
|
//
|
|
VOID Reset()
|
|
{
|
|
DBG_ASSERT( QueryStr() );
|
|
*(QueryStr()) = '\0';
|
|
m_cchLen = 0;
|
|
}
|
|
|
|
//
|
|
// Resize the internal buffer
|
|
//
|
|
HRESULT Resize(DWORD size)
|
|
{
|
|
if (!m_Buff.Resize(size))
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Append something to the end of the string
|
|
//
|
|
HRESULT Append(const CHAR *pchInit)
|
|
{
|
|
if (pchInit)
|
|
{
|
|
return AuxAppend((const BYTE *)pchInit,
|
|
(ULONG) strlen(pchInit),
|
|
QueryCB());
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT Append(const CHAR * pchInit,
|
|
DWORD cchLen)
|
|
{
|
|
if (pchInit && cchLen)
|
|
{
|
|
return AuxAppend((const BYTE *) pchInit,
|
|
cchLen,
|
|
QueryCB());
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT Append(const STRA & str)
|
|
{
|
|
if (str.QueryCCH())
|
|
{
|
|
return AuxAppend((const BYTE *)str.QueryStr(),
|
|
str.QueryCCH(),
|
|
QueryCCH());
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT AppendW(const WCHAR *pchInit)
|
|
{
|
|
return AuxAppendW( pchInit,
|
|
(ULONG) wcslen( pchInit ),
|
|
QueryCB());
|
|
}
|
|
|
|
HRESULT AppendW(const WCHAR *pchInit,
|
|
DWORD cchLen)
|
|
{
|
|
return AuxAppendW( pchInit,
|
|
cchLen,
|
|
QueryCB());
|
|
}
|
|
|
|
//
|
|
// The "Truncate" methods do not do proper conversion, use them only if
|
|
// the data is guaranteed to be in English (in effect, DO NOT use this
|
|
// for any data obtained from the wire)
|
|
//
|
|
HRESULT AppendWTruncate(const WCHAR *pchInit,
|
|
DWORD cchLen)
|
|
{
|
|
return AuxAppendWTruncate( pchInit,
|
|
cchLen,
|
|
QueryCB() );
|
|
}
|
|
|
|
HRESULT AppendWTruncate(const WCHAR *pchInit)
|
|
{
|
|
return AuxAppendWTruncate( pchInit,
|
|
(ULONG) wcslen( pchInit ),
|
|
QueryCB() );
|
|
}
|
|
|
|
//
|
|
// Copy the contents of another string to this one
|
|
//
|
|
|
|
HRESULT Copy(const CHAR *pchInit)
|
|
{
|
|
if (pchInit)
|
|
{
|
|
return AuxAppend((const BYTE *)pchInit,
|
|
(ULONG) strlen(pchInit),
|
|
0);
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
HRESULT Copy(const CHAR * pchInit,
|
|
DWORD cchLen)
|
|
{
|
|
if (pchInit && cchLen)
|
|
{
|
|
return AuxAppend((const BYTE *)pchInit,
|
|
cchLen,
|
|
0);
|
|
}
|
|
|
|
if (cchLen)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT Copy(const STRA & str)
|
|
{
|
|
return AuxAppend((const BYTE *)str.QueryStr(),
|
|
str.QueryCB(),
|
|
0);
|
|
}
|
|
|
|
HRESULT CopyW(const WCHAR *pchInit)
|
|
{
|
|
Reset();
|
|
return AuxAppendW( pchInit,
|
|
(ULONG) wcslen( pchInit ),
|
|
0 );
|
|
}
|
|
|
|
HRESULT CopyW(const WCHAR *pchInit,
|
|
DWORD cchLen)
|
|
{
|
|
Reset();
|
|
return AuxAppendW( pchInit,
|
|
cchLen,
|
|
0);
|
|
}
|
|
|
|
//
|
|
// The "Truncate" methods do not do proper conversion, use them only if
|
|
// the data is guaranteed to be in English (in effect, DO NOT use this
|
|
// for any data obtained from the wire)
|
|
//
|
|
HRESULT CopyWTruncate(const WCHAR *pchInit)
|
|
{
|
|
return AuxAppendWTruncate( pchInit,
|
|
(ULONG) wcslen( pchInit ),
|
|
0 );
|
|
}
|
|
|
|
HRESULT CopyWTruncate(const WCHAR *pchInit,
|
|
DWORD cchLen)
|
|
{
|
|
Reset();
|
|
return AuxAppendWTruncate( pchInit,
|
|
cchLen,
|
|
0 );
|
|
}
|
|
|
|
HRESULT CopyWToUTF8(const STRU& stru);
|
|
|
|
HRESULT CopyWToUTF8(LPCWSTR cpchStr)
|
|
{ return STRA::CopyWToUTF8(cpchStr, (DWORD) wcslen(cpchStr)); }
|
|
|
|
HRESULT CopyWToUTF8(LPCWSTR cpchStr,
|
|
DWORD cchLen);
|
|
|
|
HRESULT CopyWToUTF8Unescaped(const STRU& stru);
|
|
|
|
HRESULT CopyWToUTF8Unescaped(LPCWSTR cpchStr)
|
|
{ return STRA::CopyWToUTF8Unescaped(cpchStr, (DWORD) wcslen(cpchStr)); }
|
|
|
|
HRESULT CopyWToUTF8Unescaped(LPCWSTR cpchStr,
|
|
DWORD cchLen);
|
|
//
|
|
// Makes a copy of the stored string into the given buffer
|
|
//
|
|
HRESULT CopyToBuffer(CHAR *lpszBuffer,
|
|
LPDWORD lpcb) const;
|
|
|
|
BOOL SetLen(IN DWORD cchLen)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the length of the string and null terminate, if there
|
|
is sufficient buffer already allocated. Will not reallocate.
|
|
|
|
NOTE: The actual wcslen may be less than cchLen if you are
|
|
expanding the string. If this is the case SyncWithBuffer
|
|
should be called to ensure consistency. The real use of this
|
|
method is to truncate.
|
|
|
|
Arguments:
|
|
|
|
cchLen - The number of characters in the new string.
|
|
|
|
Return Value:
|
|
|
|
TRUE - if the buffer size is sufficient to hold the string.
|
|
FALSE - insufficient buffer.
|
|
|
|
--*/
|
|
{
|
|
if(cchLen >= m_Buff.QuerySize())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
*((CHAR *) m_Buff.QueryPtr() + cchLen) = '\0';
|
|
m_cchLen = cchLen;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Recalculate the length of the string, etc. because we've modified
|
|
// the buffer directly.
|
|
//
|
|
VOID
|
|
SyncWithBuffer(
|
|
VOID
|
|
)
|
|
{
|
|
m_cchLen = (LONG) strlen( QueryStr() );
|
|
}
|
|
|
|
//
|
|
// Makes a clone of the current string in the string pointer passed in.
|
|
//
|
|
HRESULT
|
|
Clone( OUT STRA * pstrClone ) const
|
|
{
|
|
return ( ( pstrClone == NULL ) ?
|
|
( HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ) ) :
|
|
( pstrClone->Copy( *this ) )
|
|
);
|
|
} // STR::Clone()
|
|
|
|
//
|
|
// Loads a string from this module's string resource table
|
|
//
|
|
|
|
HRESULT LoadString( IN DWORD dwResID,
|
|
IN LPCSTR lpszModuleName = STR_MODULE_NAME,
|
|
IN DWORD dwLangID = 0);
|
|
|
|
HRESULT LoadString( IN DWORD dwResID,
|
|
IN HMODULE hModule);
|
|
|
|
//
|
|
// Loads a string with insert params from this module's .mc resource
|
|
// table. Pass zero for the resource ID to use *this.
|
|
//
|
|
|
|
HRESULT
|
|
FormatString( IN DWORD dwResID,
|
|
IN LPCSTR apszInsertParams[],
|
|
IN LPCSTR lpszModuleName = STR_MODULE_NAME OPTIONAL,
|
|
IN DWORD cbMaxMsg = 1024 OPTIONAL );
|
|
//
|
|
// Useful for unescaping URL, QueryString etc
|
|
//
|
|
HRESULT Unescape();
|
|
|
|
HRESULT Escape(BOOL fEscapeHighBitCharsOnly = FALSE,
|
|
BOOL fDontEscapeQueryString = FALSE );
|
|
|
|
HRESULT HTMLEncode();
|
|
|
|
//
|
|
// Accept binary input and store it as a printable dump
|
|
//
|
|
|
|
HRESULT CopyBinary( LPVOID pData, DWORD cbData );
|
|
|
|
private:
|
|
|
|
//
|
|
// Avoid C++ errors. This object should never go through a copy
|
|
// constructor, unintended cast or assignment.
|
|
//
|
|
STRA( const STRA &)
|
|
{}
|
|
STRA( const CHAR *)
|
|
{}
|
|
STRA(CHAR *)
|
|
{}
|
|
STRA & operator = (const STRA &)
|
|
{ return *this; }
|
|
|
|
|
|
HRESULT AuxAppend(const BYTE *pStr,
|
|
ULONG cbStr,
|
|
ULONG cbOffset,
|
|
BOOL fAddSlop = TRUE);
|
|
|
|
HRESULT AuxAppendW(const WCHAR *pStr,
|
|
ULONG cchStr,
|
|
ULONG cbOffset,
|
|
BOOL fAddSlop = TRUE);
|
|
|
|
HRESULT AuxAppendWTruncate(const WCHAR *pStr,
|
|
ULONG cchStr,
|
|
ULONG cbOffset,
|
|
BOOL fAddSlop = TRUE);
|
|
|
|
BUFFER m_Buff;
|
|
LONG m_cchLen;
|
|
};
|
|
|
|
|
|
//
|
|
// Quick macro for declaring a STRA that will use stack memory of <size>
|
|
// bytes. If the buffer overflows then a heap buffer will be allocated
|
|
//
|
|
|
|
#define STACK_STRA(name, size) CHAR __ach##name[size]; \
|
|
STRA name( __ach##name, sizeof( __ach##name ))
|
|
|
|
//
|
|
// Macros for declaring and initializing a STRA that will use inline memory
|
|
// of <size> bytes as a member of an object.
|
|
//
|
|
|
|
#define INLINE_STRA(name, size) CHAR __ach##name[size]; \
|
|
STRA name;
|
|
|
|
#define INLINE_STRA_INIT(name) name( __ach##name, sizeof( __ach##name ) )
|
|
|
|
#endif
|