562 lines
12 KiB
C++
562 lines
12 KiB
C++
/******************************************************************************
|
|
|
|
Source File: String.CPP
|
|
|
|
String Handling class implementation, v 98.6 1/2
|
|
|
|
Copyright (c) 1997 by Microsoft Corporation. All Rights Reserved.
|
|
|
|
Change History:
|
|
01-08-97 Bob Kjelgaard
|
|
01-03-97 Bob Kjelgaard Added special functions to aid port extraction
|
|
for plug-and-play.
|
|
07-05-97 Tim Wells Ported to NT.
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
//
|
|
// Precompiled header
|
|
//
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// Include
|
|
//
|
|
|
|
#include "sti_ci.h"
|
|
|
|
//
|
|
// Extern
|
|
//
|
|
|
|
extern HINSTANCE g_hDllInstance;
|
|
|
|
//
|
|
// Function
|
|
//
|
|
|
|
|
|
CString::CString(const CString& csRef) {
|
|
|
|
m_lpstr = (csRef.m_lpstr && *csRef.m_lpstr) ?
|
|
new TCHAR[1 + lstrlen(csRef.m_lpstr)] : NULL;
|
|
|
|
if (m_lpstr)
|
|
lstrcpy(m_lpstr, csRef.m_lpstr);
|
|
}
|
|
|
|
CString::CString(LPCTSTR lpstrRef){
|
|
|
|
DWORD dwLength;
|
|
|
|
_try {
|
|
dwLength = lstrlen(lpstrRef);
|
|
} // _try {
|
|
_except(EXCEPTION_EXECUTE_HANDLER) {
|
|
dwLength = 0;
|
|
} // _except(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
if( (NULL != lpstrRef)
|
|
&& (NULL != *lpstrRef)
|
|
&& (0 != dwLength) )
|
|
{
|
|
m_lpstr = new TCHAR[dwLength+1];
|
|
lstrcpy(m_lpstr, lpstrRef);
|
|
}
|
|
|
|
} // CString::CString(LPCTSTR lpstrRef)
|
|
|
|
const CString& CString::operator =(const CString& csRef) {
|
|
|
|
Empty();
|
|
|
|
m_lpstr = (csRef.m_lpstr && *csRef.m_lpstr) ?
|
|
new TCHAR[1 + lstrlen(csRef.m_lpstr)] : NULL;
|
|
|
|
if (m_lpstr)
|
|
lstrcpy(m_lpstr, csRef.m_lpstr);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
const
|
|
CString&
|
|
CString::operator =(
|
|
LPCTSTR lpstrRef
|
|
)
|
|
{
|
|
|
|
DWORD dwLength;
|
|
|
|
Empty();
|
|
|
|
_try {
|
|
dwLength = lstrlen(lpstrRef);
|
|
} // _try {
|
|
_except(EXCEPTION_EXECUTE_HANDLER) {
|
|
dwLength = 0;
|
|
} // _except(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
if( (NULL != lpstrRef)
|
|
&& (NULL != *lpstrRef)
|
|
&& (0 != dwLength) )
|
|
{
|
|
m_lpstr = new TCHAR[dwLength+1];
|
|
lstrcpy(m_lpstr, lpstrRef);
|
|
}
|
|
|
|
return *this;
|
|
} // CString::operator =(LPCTSTR lpstrRef)
|
|
|
|
void CString::GetContents(HWND hwnd) {
|
|
|
|
Empty();
|
|
|
|
if (!IsWindow(hwnd))
|
|
return;
|
|
|
|
unsigned u = (unsigned) SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
|
|
|
|
if (!u)
|
|
return;
|
|
|
|
m_lpstr = new TCHAR[++u];
|
|
if(NULL != m_lpstr){
|
|
SendMessage(hwnd, WM_GETTEXT, u, (LPARAM) m_lpstr);
|
|
}
|
|
}
|
|
|
|
void CString::FromTable(unsigned uid) {
|
|
|
|
TCHAR acTemp[MAX_PATH+1];
|
|
|
|
memset(acTemp, 0, sizeof(acTemp));
|
|
|
|
LoadString(g_hDllInstance, uid, acTemp, ARRAYSIZE(acTemp)-1);
|
|
|
|
*this = acTemp;
|
|
}
|
|
|
|
void CString::Load(ATOM at, BOOL bGlobal) {
|
|
|
|
TCHAR acTemp[MAX_PATH+1];
|
|
|
|
memset(acTemp, 0, sizeof(acTemp));
|
|
|
|
if(bGlobal){
|
|
GlobalGetAtomName(at,
|
|
acTemp,
|
|
ARRAYSIZE(acTemp)-1);
|
|
} else {
|
|
GetAtomName(at,
|
|
acTemp,
|
|
sizeof(acTemp)/sizeof(TCHAR));
|
|
}
|
|
|
|
*this = acTemp;
|
|
}
|
|
|
|
void
|
|
CString::Load(
|
|
HINF hInf,
|
|
LPCTSTR lpstrSection,
|
|
LPCTSTR lpstrKeyword,
|
|
DWORD dwFieldIndex,
|
|
LPCTSTR lpstrDefault
|
|
)
|
|
{
|
|
|
|
INFCONTEXT InfContext;
|
|
TCHAR szKeyBuffer[MAX_PATH+1];
|
|
TCHAR szValueBuffer[MAX_PATH+1];
|
|
|
|
//
|
|
// Initialize local.
|
|
//
|
|
memset(&InfContext, 0, sizeof(InfContext));
|
|
memset(szKeyBuffer, 0, sizeof(szKeyBuffer));
|
|
memset(szValueBuffer, 0, sizeof(szValueBuffer));
|
|
|
|
//
|
|
// Cleanup contents;
|
|
//
|
|
|
|
Empty();
|
|
|
|
//
|
|
// Check all parameters.
|
|
//
|
|
|
|
if( (NULL == lpstrSection)
|
|
|| (NULL == lpstrKeyword)
|
|
|| (!IS_VALID_HANDLE(hInf)) )
|
|
{
|
|
//
|
|
// Invalid parameter.
|
|
//
|
|
|
|
goto Load_return;
|
|
}
|
|
|
|
//
|
|
// Get matching line.
|
|
//
|
|
|
|
while(SetupFindFirstLine(hInf, lpstrSection, lpstrKeyword, &InfContext)){
|
|
|
|
//
|
|
// Get a field of a line.
|
|
//
|
|
|
|
if(SetupGetStringField(&InfContext, dwFieldIndex, szValueBuffer, ARRAYSIZE(szValueBuffer)-1, NULL)){
|
|
|
|
*this = szValueBuffer;
|
|
break;
|
|
}// if(SetupGetStringField(&InfContext, dwFieldIndex, szValueBuffer, ARRAYSIZE(szValueBuffer)-1))
|
|
} // while(SetupFindFirstLine(hInf, lpstrSection, lpstrKeyword, &InfContext))
|
|
|
|
Load_return:
|
|
|
|
return;
|
|
|
|
} // CString::Load() Load from INF
|
|
|
|
void CString::Load(HKEY hk, LPCTSTR lpstrKeyword) {
|
|
|
|
TCHAR abTemp[MAX_PATH+1];
|
|
ULONG lcbNeeded = sizeof(abTemp)-sizeof(TCHAR);
|
|
|
|
memset(abTemp, 0, sizeof(abTemp));
|
|
|
|
RegQueryValueEx(hk, lpstrKeyword, NULL, NULL, (PBYTE)abTemp, &lcbNeeded);
|
|
*this = (LPCTSTR) abTemp;
|
|
}
|
|
|
|
void CString::MakeSystemPath(LPCTSTR lpstrFileName) {
|
|
|
|
DWORD dwLength;
|
|
|
|
if (m_lpstr)
|
|
delete m_lpstr;
|
|
|
|
_try {
|
|
dwLength = lstrlen(lpstrFileName);
|
|
} // _try {
|
|
_except(EXCEPTION_EXECUTE_HANDLER) {
|
|
dwLength = 0;
|
|
} // _except(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
m_lpstr = new TCHAR[MAX_PATH * 2];
|
|
if( (NULL != m_lpstr)
|
|
&& (0 != dwLength)
|
|
&& (MAX_PATH >= dwLength) )
|
|
{
|
|
memset(m_lpstr, 0, MAX_PATH*2*sizeof(TCHAR));
|
|
|
|
UINT uiLength = GetSystemDirectory (m_lpstr, MAX_PATH);
|
|
|
|
if ( *(m_lpstr + uiLength) != TEXT('\\'))
|
|
lstrcat (m_lpstr, TEXT("\\"));
|
|
|
|
lstrcat (m_lpstr, lpstrFileName);
|
|
}
|
|
}
|
|
|
|
void CString::Store(HKEY hk, LPCTSTR lpstrKey, LPCTSTR lpstrType) {
|
|
|
|
DWORD dwLength;
|
|
|
|
if (IsEmpty())
|
|
return;
|
|
|
|
_try {
|
|
dwLength = lstrlen(lpstrKey);
|
|
} // _try {
|
|
_except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return;
|
|
} // _except(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
if (lpstrType && *lpstrType == TEXT('1')) {
|
|
|
|
DWORD dwValue = Decode();
|
|
RegSetValueEx(hk, lpstrKey, NULL, REG_DWORD, (LPBYTE) &dwValue,
|
|
sizeof (DWORD));
|
|
|
|
} else {
|
|
|
|
RegSetValueEx(hk, lpstrKey, NULL, REG_SZ, (LPBYTE) m_lpstr,
|
|
(1 + lstrlen(m_lpstr)) * sizeof(TCHAR) );
|
|
}
|
|
}
|
|
|
|
// This one is a bit lame, but it does the job.
|
|
|
|
DWORD CString::Decode() {
|
|
|
|
if (IsEmpty())
|
|
return 0;
|
|
|
|
for (LPTSTR lpstrThis = m_lpstr;
|
|
*lpstrThis && *lpstrThis == TEXT(' ');
|
|
lpstrThis++)
|
|
;
|
|
|
|
if (!*lpstrThis)
|
|
return 0;
|
|
|
|
// BIUGBUG
|
|
if (lpstrThis[0] == TEXT('0') && (lpstrThis[1] | TEXT('\x20') ) == TEXT('x')) {
|
|
// Hex string
|
|
lpstrThis += 2;
|
|
DWORD dwReturn = 0;
|
|
|
|
while (*lpstrThis) {
|
|
switch (*lpstrThis) {
|
|
case TEXT('0'):
|
|
case TEXT('1'):
|
|
case TEXT('2'):
|
|
case TEXT('3'):
|
|
case TEXT('4'):
|
|
case TEXT('5'):
|
|
case TEXT('6'):
|
|
case TEXT('7'):
|
|
case TEXT('8'):
|
|
case TEXT('9'):
|
|
dwReturn <<= 4;
|
|
dwReturn += ((*lpstrThis) - TEXT('0'));
|
|
break;
|
|
|
|
case TEXT('a'):
|
|
case TEXT('A'):
|
|
case TEXT('b'):
|
|
case TEXT('c'):
|
|
case TEXT('d'):
|
|
case TEXT('e'):
|
|
case TEXT('f'):
|
|
case TEXT('B'):
|
|
case TEXT('C'):
|
|
case TEXT('D'):
|
|
case TEXT('E'):
|
|
case TEXT('F'):
|
|
dwReturn <<= 4;
|
|
dwReturn += 10 + ((*lpstrThis | TEXT('\x20')) - TEXT('a'));
|
|
break;
|
|
|
|
default:
|
|
return dwReturn;
|
|
}
|
|
lpstrThis++;
|
|
}
|
|
return dwReturn;
|
|
}
|
|
|
|
for (DWORD dwReturn = 0;
|
|
*lpstrThis && *lpstrThis >= TEXT('0') && *lpstrThis <= TEXT('9');
|
|
lpstrThis++) {
|
|
|
|
dwReturn *= 10;
|
|
dwReturn += *lpstrThis - TEXT('0');
|
|
}
|
|
|
|
return dwReturn;
|
|
|
|
}
|
|
|
|
|
|
CString operator + (const CString& cs1, const CString& cs2) {
|
|
|
|
if (cs1.IsEmpty())
|
|
return cs2;
|
|
|
|
if (cs2.IsEmpty())
|
|
return cs1;
|
|
|
|
CString csReturn;
|
|
|
|
csReturn.m_lpstr = new TCHAR[ 1 + lstrlen(cs1) +lstrlen(cs2)];
|
|
|
|
if(NULL != csReturn.m_lpstr){
|
|
lstrcat(lstrcpy(csReturn.m_lpstr, cs1.m_lpstr), cs2.m_lpstr);
|
|
}
|
|
|
|
return csReturn;
|
|
}
|
|
|
|
CString operator + (const CString& cs1, LPCTSTR lpstr2) {
|
|
|
|
DWORD dwLength;
|
|
|
|
_try {
|
|
dwLength = lstrlen(lpstr2);
|
|
} // _try {
|
|
_except(EXCEPTION_EXECUTE_HANDLER) {
|
|
dwLength = 0;
|
|
} // _except(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
if(0 == dwLength)
|
|
return cs1;
|
|
|
|
if(cs1.IsEmpty())
|
|
return lpstr2;
|
|
|
|
CString csReturn;
|
|
|
|
csReturn.m_lpstr = new TCHAR[ 1 + lstrlen(cs1) + dwLength];
|
|
if(NULL != csReturn.m_lpstr){
|
|
lstrcat(lstrcpy(csReturn.m_lpstr, cs1.m_lpstr), lpstr2);
|
|
}
|
|
|
|
return csReturn;
|
|
}
|
|
|
|
CString operator + (LPCTSTR lpstr1,const CString& cs2) {
|
|
|
|
DWORD dwLength;
|
|
|
|
_try {
|
|
dwLength = lstrlen(lpstr1);
|
|
} // _try {
|
|
_except(EXCEPTION_EXECUTE_HANDLER) {
|
|
dwLength = 0;
|
|
} // _except(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
if(0 == dwLength)
|
|
return cs2;
|
|
|
|
if (cs2.IsEmpty())
|
|
return lpstr1;
|
|
|
|
CString csReturn;
|
|
|
|
csReturn.m_lpstr = new TCHAR[ 1 + dwLength +lstrlen(cs2)];
|
|
|
|
if(NULL != csReturn.m_lpstr){
|
|
lstrcat(lstrcpy(csReturn.m_lpstr, lpstr1), cs2.m_lpstr);
|
|
}
|
|
return csReturn;
|
|
}
|
|
|
|
|
|
// CStringArray class- the implementation is a bit lame, but it isn't
|
|
// really necessary to not be lame, at this point...
|
|
|
|
CStringArray::CStringArray(unsigned uGrowBy) {
|
|
m_ucItems = m_ucMax = 0;
|
|
m_pcsContents = NULL;
|
|
m_uGrowBy = uGrowBy ? uGrowBy : 10;
|
|
}
|
|
|
|
CStringArray::~CStringArray() {
|
|
if (m_pcsContents)
|
|
delete[] m_pcsContents;
|
|
}
|
|
|
|
VOID
|
|
CStringArray::Cleanup() {
|
|
if (m_pcsContents){
|
|
delete[] m_pcsContents;
|
|
}
|
|
m_pcsContents = NULL;
|
|
m_ucItems = m_ucMax = 0;
|
|
}
|
|
|
|
void CStringArray::Add(LPCTSTR lpstr) {
|
|
|
|
if (m_ucItems >= m_ucMax) {
|
|
CString *pcsNew = new CString[m_ucMax += m_uGrowBy];
|
|
|
|
if (!pcsNew) {
|
|
m_ucMax -= m_uGrowBy;
|
|
return;
|
|
}
|
|
|
|
for (unsigned u = 0; u < m_ucItems; u++)
|
|
pcsNew[u] = m_pcsContents[u];
|
|
|
|
delete[] m_pcsContents;
|
|
m_pcsContents = pcsNew;
|
|
}
|
|
|
|
m_pcsContents[m_ucItems++] = lpstr;
|
|
}
|
|
|
|
CString& CStringArray::operator [](unsigned u) {
|
|
|
|
return (u < m_ucItems) ? m_pcsContents[u] : m_csEmpty;
|
|
}
|
|
|
|
// Split a string into tokens, and make an array of it
|
|
|
|
void CStringArray::Tokenize(LPTSTR lpstr, TCHAR cSeparator) {
|
|
|
|
BOOL fInsideQuotes = FALSE;
|
|
TCHAR cPreviousChar = TEXT('\0');
|
|
|
|
|
|
if (m_pcsContents) {
|
|
delete[] m_pcsContents;
|
|
m_pcsContents = NULL;
|
|
m_ucItems = m_ucMax = 0;
|
|
}
|
|
|
|
if (!lpstr)
|
|
return;
|
|
|
|
for (LPTSTR lpstrThis = lpstr; *lpstr; lpstr = lpstrThis) {
|
|
|
|
/*
|
|
for (; *lpstrThis && *lpstrThis != cSeparator; lpstrThis++) {
|
|
|
|
}
|
|
*/
|
|
|
|
//
|
|
// Skip for next separator , counting quotes
|
|
//
|
|
|
|
cPreviousChar = '\0';
|
|
for (;*lpstrThis; lpstrThis++) {
|
|
|
|
if (fInsideQuotes) {
|
|
if (*lpstrThis == TEXT('"')) {
|
|
if (cPreviousChar != TEXT('"')) {
|
|
// Previous was not a quote - going out of quotation
|
|
fInsideQuotes = FALSE;
|
|
}
|
|
else {
|
|
// Previous char was tab too - continue BUGBUG should coalesce
|
|
}
|
|
cPreviousChar = TEXT('\0');
|
|
}
|
|
else {
|
|
cPreviousChar = *lpstrThis;
|
|
}
|
|
continue;
|
|
}
|
|
else {
|
|
if (*lpstrThis == TEXT('"')) {
|
|
// Starting quote
|
|
fInsideQuotes = TRUE;
|
|
cPreviousChar = TEXT('\0');
|
|
continue;
|
|
}
|
|
if (*lpstrThis == cSeparator) {
|
|
// Got to separator outside of quote - break the loop
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*lpstrThis) {
|
|
*lpstrThis = '\0';
|
|
Add(lpstr);
|
|
*lpstrThis++ = cSeparator;
|
|
}
|
|
else
|
|
Add(lpstr);
|
|
}
|
|
}
|