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.
608 lines
14 KiB
608 lines
14 KiB
/*++
|
|
|
|
Copyright (C) 1996-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
WSTRING.CPP
|
|
|
|
Abstract:
|
|
|
|
Utility string class
|
|
|
|
History:
|
|
|
|
a-raymcc 30-May-96 Created.
|
|
a-dcrews 16-Mar-99 Added out-of-memory exception handling
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <stdio.h>
|
|
#include <wstring.h>
|
|
#include <corex.h>
|
|
|
|
static wchar_t g_szNullString[1] = {0};
|
|
|
|
/*inline*/ void WString::DeleteString(wchar_t *pStr)
|
|
{
|
|
if (pStr != g_szNullString)
|
|
delete [] pStr;
|
|
}
|
|
|
|
WString::WString()
|
|
{
|
|
m_pString = g_szNullString;
|
|
}
|
|
WString::WString(wchar_t *pSrc, BOOL bAcquire)
|
|
{
|
|
if (bAcquire) {
|
|
m_pString = pSrc;
|
|
if (m_pString == 0)
|
|
m_pString = g_szNullString;
|
|
return;
|
|
}
|
|
|
|
if (pSrc == 0) {
|
|
m_pString = g_szNullString;
|
|
return;
|
|
}
|
|
|
|
size_t length = wcslen(pSrc) + 1;
|
|
m_pString = new wchar_t[length];
|
|
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == m_pString )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
memcpy(m_pString, pSrc, sizeof wchar_t * length);
|
|
}
|
|
|
|
WString::WString(DWORD dwResourceID, HMODULE hMod)
|
|
{
|
|
int iSize = 100;
|
|
BOOL bNotDone = TRUE;
|
|
TCHAR* pTemp = NULL;
|
|
|
|
// load the string from the string table. Since we dont know what size, try increasing the
|
|
// buffer till it works, or until the clearly obsurd case is hit
|
|
|
|
while (iSize < 10240)
|
|
{
|
|
pTemp = new TCHAR [iSize];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == pTemp )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
int iRead = LoadString(hMod, dwResourceID, pTemp, iSize);
|
|
if(iRead == 0)
|
|
{
|
|
// Bad string
|
|
|
|
m_pString = g_szNullString;
|
|
delete [] pTemp;
|
|
return;
|
|
}
|
|
if(iRead +1 < iSize)
|
|
break; // all is well;
|
|
iSize += 100; // Try again
|
|
delete [] pTemp;
|
|
pTemp = NULL;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
//For unicode, this is the string we need!
|
|
m_pString = pTemp;
|
|
#else
|
|
//Only have to convert if we are not using unicode, otherwise it is already in wide mode!
|
|
if(pTemp)
|
|
{
|
|
// got a narrow string, allocate a large string buffer and convert
|
|
|
|
long len = mbstowcs(NULL, pTemp, lstrlen(pTemp)+1) + 1;
|
|
m_pString = new wchar_t[len];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == m_pString )
|
|
{
|
|
delete [] pTemp;
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
mbstowcs(m_pString, pTemp, lstrlen(pTemp)+1);
|
|
delete [] pTemp;
|
|
}
|
|
else
|
|
m_pString = g_szNullString;
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
WString::WString(const wchar_t *pSrc)
|
|
{
|
|
if (pSrc == 0) {
|
|
m_pString = g_szNullString;
|
|
return;
|
|
}
|
|
size_t tmpLength = wcslen(pSrc) + 1;
|
|
m_pString = new wchar_t[tmpLength];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == m_pString )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
memcpy(m_pString, pSrc, sizeof wchar_t * tmpLength);
|
|
}
|
|
|
|
WString::WString(const char *pSrc)
|
|
{
|
|
m_pString = new wchar_t[strlen(pSrc) + 1];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == m_pString )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
mbstowcs(m_pString, pSrc, strlen(pSrc) + 1);
|
|
}
|
|
|
|
LPSTR WString::GetLPSTR() const
|
|
{
|
|
long len = 2*(wcslen(m_pString) + 1);
|
|
char *pTmp = new char[len];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == pTmp )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
wcstombs(pTmp, m_pString, len);
|
|
return pTmp;
|
|
}
|
|
|
|
WString& WString::operator =(const WString &Src)
|
|
{
|
|
DeleteString(m_pString);
|
|
size_t stringSize = wcslen(Src.m_pString) + 1;
|
|
m_pString = new wchar_t[stringSize];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == m_pString )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
StringCchCopyW(m_pString, stringSize, Src.m_pString);
|
|
return *this;
|
|
}
|
|
|
|
WString& WString::operator =(LPCWSTR pSrc)
|
|
{
|
|
DeleteString(m_pString);
|
|
size_t stringSize = wcslen(pSrc) + 1;
|
|
m_pString = new wchar_t[stringSize];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == m_pString )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
StringCchCopyW(m_pString, stringSize, pSrc);
|
|
return *this;
|
|
}
|
|
|
|
WString& WString::operator +=(const wchar_t *pOther)
|
|
{
|
|
size_t tmpThisLength = wcslen(m_pString);
|
|
size_t tmpOtherLength = wcslen(pOther)+1;
|
|
size_t stringSize = tmpThisLength + tmpOtherLength;
|
|
|
|
wchar_t *pTmp = new wchar_t[stringSize];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == pTmp )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
memcpy(pTmp, m_pString, (sizeof wchar_t) * tmpThisLength);
|
|
memcpy(pTmp + tmpThisLength , pOther, (sizeof wchar_t) * tmpOtherLength);
|
|
DeleteString(m_pString);
|
|
m_pString = pTmp;
|
|
return *this;
|
|
}
|
|
|
|
WString& WString::operator +=(wchar_t NewChar)
|
|
{
|
|
wchar_t Copy[2];
|
|
Copy[0] = NewChar;
|
|
Copy[1] = 0;
|
|
return *this += Copy;
|
|
}
|
|
|
|
|
|
WString& WString::operator +=(const WString &Other)
|
|
{
|
|
return *this += Other.m_pString;
|
|
}
|
|
|
|
|
|
wchar_t WString::operator[](int nIndex) const
|
|
{
|
|
if (nIndex >= (int) wcslen(m_pString))
|
|
return 0;
|
|
return m_pString[nIndex];
|
|
}
|
|
|
|
|
|
WString& WString::TruncAtRToken(wchar_t Token)
|
|
{
|
|
for (int i = (int) wcslen(m_pString); i >= 0; i--) {
|
|
wchar_t wc = m_pString[i];
|
|
m_pString[i] = 0;
|
|
if (wc == Token)
|
|
break;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
WString& WString::TruncAtLToken(wchar_t Token)
|
|
{
|
|
int nStrlen = wcslen(m_pString);
|
|
for (int i = 0; i < nStrlen ; i++)
|
|
{
|
|
if (Token == m_pString[i])
|
|
{
|
|
m_pString[i] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
WString& WString::StripToToken(wchar_t Token, BOOL bIncludeToken)
|
|
{
|
|
int nStrlen = wcslen(m_pString);
|
|
wchar_t *pTmp = new wchar_t[nStrlen + 1];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == pTmp )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
*pTmp = 0;
|
|
|
|
BOOL bFound = FALSE;
|
|
|
|
for (int i = 0; i < nStrlen; i++) {
|
|
if (m_pString[i] == Token) {
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
delete [] pTmp;
|
|
return *this;
|
|
}
|
|
|
|
if (bIncludeToken) i++;
|
|
StringCchCopyW(pTmp, nStrlen + 1, &m_pString[i]);
|
|
DeleteString(m_pString);
|
|
m_pString = pTmp;
|
|
return *this;
|
|
}
|
|
|
|
LPWSTR WString::UnbindPtr()
|
|
{
|
|
if (m_pString == g_szNullString)
|
|
{
|
|
m_pString = new wchar_t[1];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == m_pString )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
*m_pString = 0;
|
|
}
|
|
wchar_t *pTmp = m_pString;
|
|
m_pString = g_szNullString;
|
|
return pTmp;
|
|
}
|
|
|
|
WString& WString::StripWs(int nType)
|
|
{
|
|
if (nType & leading)
|
|
{
|
|
size_t stringSize = wcslen(m_pString) + 1;
|
|
wchar_t *pTmp = new wchar_t[stringSize];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == pTmp )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
int i = 0;
|
|
while (iswspace(m_pString[i]) && m_pString[i]) i++;
|
|
StringCchCopyW(pTmp, stringSize , &m_pString[i]);
|
|
DeleteString(m_pString);
|
|
m_pString = pTmp;
|
|
}
|
|
|
|
if (nType & trailing)
|
|
{
|
|
wchar_t *pCursor = m_pString + wcslen(m_pString) - 1;
|
|
while (pCursor >= m_pString && iswspace(*pCursor))
|
|
*pCursor-- = 0;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wchar_t *WString::GetLToken(wchar_t Tok) const
|
|
{
|
|
wchar_t *pCursor = m_pString;
|
|
while (*pCursor && *pCursor != Tok) pCursor++;
|
|
if (*pCursor == Tok)
|
|
return pCursor;
|
|
return 0;
|
|
}
|
|
|
|
WString WString::operator()(int nLeft, int nRight) const
|
|
{
|
|
size_t stringSize = wcslen(m_pString) + 1;
|
|
wchar_t *pTmp = new wchar_t[stringSize];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == pTmp )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
wchar_t *pCursor = pTmp;
|
|
|
|
for (int i = nLeft; i < (int) wcslen(m_pString) && i <= nRight; i++)
|
|
*pCursor++ = m_pString[i];
|
|
*pCursor = 0;
|
|
|
|
return WString(pTmp, TRUE);
|
|
}
|
|
|
|
BOOL WString::ExtractToken(const wchar_t * pDelimiters, WString &Extract)
|
|
{
|
|
if(pDelimiters == NULL)
|
|
{
|
|
Extract.Empty();
|
|
return FALSE;
|
|
}
|
|
|
|
// Find which character in the list works. Use the first if none are
|
|
// present
|
|
|
|
int nLen = wcslen(m_pString);
|
|
int nDimLen = wcslen(pDelimiters);
|
|
|
|
for (int i = 0; i < nLen; i++)
|
|
for(int j = 0; j < nDimLen; j++)
|
|
if (m_pString[i] == pDelimiters[j])
|
|
return ExtractToken(pDelimiters[j], Extract);
|
|
|
|
// If none were found, just use the first.
|
|
|
|
return ExtractToken(*pDelimiters, Extract);
|
|
|
|
}
|
|
|
|
BOOL WString::ExtractToken(wchar_t Delimiter, WString &Extract)
|
|
{
|
|
int i, i2;
|
|
BOOL bTokFound = FALSE;
|
|
Extract.Empty();
|
|
int nLen = wcslen(m_pString);
|
|
wchar_t *pTmp = new wchar_t[nLen + 1];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == pTmp )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
for (i = 0; i < nLen; i++)
|
|
if (m_pString[i] == Delimiter) {
|
|
bTokFound = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
pTmp[i] = m_pString[i];
|
|
|
|
pTmp[i] = 0;
|
|
Extract.BindPtr(pTmp);
|
|
|
|
// Now make *this refer to any leftover stuff.
|
|
// ===========================================
|
|
pTmp = new wchar_t[nLen - wcslen(pTmp) + 1];
|
|
|
|
// Watch for allocation failures
|
|
if ( NULL == pTmp )
|
|
{
|
|
throw CX_MemoryException();
|
|
}
|
|
|
|
*pTmp = 0;
|
|
|
|
for (i2 = 0, i++; i <= nLen; i++)
|
|
pTmp[i2++] = m_pString[i];
|
|
|
|
DeleteString(m_pString);
|
|
m_pString = pTmp;
|
|
|
|
// Return TRUE if the token was encountered, FALSE if not.
|
|
// =======================================================
|
|
return bTokFound;
|
|
}
|
|
|
|
void WString::Empty()
|
|
{
|
|
DeleteString(m_pString);
|
|
m_pString = g_szNullString;
|
|
}
|
|
|
|
static int _WildcardAux(const wchar_t *pszWildstr, const wchar_t *pszTargetstr,
|
|
int iGreedy)
|
|
{
|
|
enum { start, wild, strip } eState;
|
|
wchar_t cInput, cInputw, cLaToken;
|
|
|
|
if (!wcslen(pszTargetstr) || !wcslen(pszWildstr))
|
|
return 0;
|
|
|
|
for (eState = start;;)
|
|
switch (eState)
|
|
{
|
|
case start:
|
|
cInputw = *pszWildstr++; // wildcard input
|
|
cInput = *pszTargetstr; // target input
|
|
|
|
if (!cInputw) // at end of wildcard string?
|
|
goto EndScan;
|
|
|
|
// Check for wildcard chars first
|
|
|
|
if (cInputw == L'?') { // Simply strips both inputs
|
|
if (!cInput) // If end of input, error
|
|
return 0;
|
|
pszTargetstr++;
|
|
continue;
|
|
}
|
|
if (cInputw == L'*') {
|
|
eState = wild;
|
|
break;
|
|
}
|
|
|
|
// If here, an exact match is required.
|
|
|
|
if (cInput != cInputw)
|
|
return 0;
|
|
|
|
// Else remain in same state, since match succeeded
|
|
pszTargetstr++;
|
|
break;
|
|
|
|
case wild:
|
|
cLaToken = *pszWildstr++; // Establish the lookahead token
|
|
eState = strip;
|
|
break;
|
|
|
|
case strip:
|
|
cInput = *pszTargetstr;
|
|
|
|
if (cInput == cLaToken) {
|
|
if (!cInput) // Match on a NULL
|
|
goto EndScan;
|
|
++pszTargetstr;
|
|
|
|
// If there is another occurrence of the lookahead
|
|
// token in the string, and we are in greedy mode,
|
|
// stay in this state
|
|
|
|
if (!iGreedy)
|
|
eState = start;
|
|
|
|
if (!wcschr(pszTargetstr, cLaToken))
|
|
eState = start;
|
|
|
|
break;
|
|
}
|
|
|
|
if (cLaToken && !cInput) // End of input with a non-null la token
|
|
return 0;
|
|
|
|
++pszTargetstr; // Still stripping input
|
|
break;
|
|
}
|
|
|
|
|
|
// Here if the wildcard input is exhausted. If the
|
|
// target string is also empty, we have a match,
|
|
// otherwise not.
|
|
|
|
EndScan:
|
|
if (wcslen(pszTargetstr))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
// Run the test both with greedy and non-greedy matching, allowing the
|
|
// greatest possible chance of a match.
|
|
|
|
BOOL WString::WildcardTest(const wchar_t *pszWildstr) const
|
|
{
|
|
return (_WildcardAux(pszWildstr, m_pString, 0) |
|
|
_WildcardAux(pszWildstr, m_pString, 1));
|
|
}
|
|
|
|
|
|
void WString::Unquote()
|
|
{
|
|
if (!m_pString)
|
|
return;
|
|
int nLen = wcslen(m_pString);
|
|
if (nLen == 0)
|
|
return;
|
|
|
|
// Remove trailing quote.
|
|
// ======================
|
|
|
|
if (m_pString[nLen - 1] == L'"')
|
|
m_pString[nLen - 1] = 0;
|
|
|
|
// Remove leading quote.
|
|
// =====================
|
|
|
|
if (m_pString[0] == L'"')
|
|
{
|
|
for (int i = 0; i < nLen; i++)
|
|
m_pString[i] = m_pString[i + 1];
|
|
}
|
|
}
|
|
|
|
WString WString::EscapeQuotes() const
|
|
{
|
|
WString ws;
|
|
|
|
int nLen = Length();
|
|
for(int i = 0; i < nLen; i++)
|
|
{
|
|
if(m_pString[i] == '"' || m_pString[i] == '\\')
|
|
{
|
|
ws += L'\\';
|
|
}
|
|
|
|
ws += m_pString[i];
|
|
}
|
|
|
|
return ws;
|
|
}
|
|
|