windows-nt/Source/XPSP1/NT/windows/appcompat/shimdbc/globals.cpp
2020-09-26 16:20:57 +08:00

1155 lines
27 KiB
C++

////////////////////////////////////////////////////////////////////////////////////
//
// File: globals.cpp
//
// History: 16-Nov-00 markder Created.
//
// Desc: This file contains miscellaneous helper functions.
//
////////////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include <errno.h>
////////////////////////////////////////////////////////////////////////////////////
//
// Func: PrintError, PrintErrorStack, Print
//
// Desc: Helper functions for console output
//
////////////////////////////////////////////////////////////////////////////////////
TCHAR gszT[1024]; // Global buffer for console output
void _cdecl PrintError(
LPCTSTR pszFmt,
...)
{
va_list arglist;
va_start(arglist, pszFmt);
StringCchVPrintf(gszT, ARRAYSIZE(gszT), pszFmt, arglist);
gszT[1023] = _T('\0'); // ensure null termination
va_end(arglist);
_tprintf(_T("\nNMAKE : U8604: 'ShimDBC': %s"), gszT);
}
void PrintErrorStack()
{
CString csError;
INT_PTR i, j;
Print(_T("\n\nErrors were encountered during compilation:\n"));
for (i = g_rgErrors.GetSize() - 1; i >= 0; i--) {
csError.Empty();
j = g_rgErrors.GetSize() - i;
while(--j) {
csError += _T(" ");
}
csError += g_rgErrors[i];
csError += _T("\n");
PrintError(csError);
}
}
void _cdecl Print(
LPCTSTR pszFmt,
...)
{
va_list arglist;
if (g_bQuiet)
return;
va_start(arglist, pszFmt);
StringCchVPrintf(gszT, ARRAYSIZE(gszT), pszFmt, arglist);
gszT[1023] = _T('\0'); // ensure null termination
va_end(arglist);
_tprintf(_T("%s"), gszT);
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: StringToDword
//
// Desc: Converts a string to a DWORD. Handles the 0x prefix for hex strings.
//
DWORD StringToDword(
CString cs)
{
DWORD dwRet;
cs.MakeLower();
if (cs.Left(2) == _T("0x")) {
_stscanf(cs, _T("0x%x"), &dwRet);
} else {
dwRet = _ttol(cs);
}
return dwRet;
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: StringToULong
//
// Desc: Converts a string to a unsigned long.
//
ULONG StringToULong(
LPCTSTR lpszVal)
{
TCHAR* pEnd;
return _tcstoul(lpszVal, &pEnd, 0);
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: StringToMask
//
// Desc: Converts a string to a mask, with some checking
//
BOOL
StringToMask(
LPDWORD pdwMask,
LPCTSTR lpszVal
)
{
DWORD dwMask = 0;
LPCTSTR pVal;
BOOL bSuccess;
TCHAR* pEnd = NULL;
pVal = lpszVal + _tcsspn(lpszVal, _T(" \t"));
dwMask = (DWORD)_tcstoul(pVal, &pEnd, 0);
if (dwMask == 0) { // suspicious, possibly check errno
if (errno != 0) {
goto errHandle;
}
}
//
// if a mask is ending with some garbage -- it's an error
//
if (pEnd && *pEnd != _T('\0') && !_istspace(*pEnd)) {
goto errHandle;
}
if (pdwMask) {
*pdwMask = dwMask;
}
return TRUE;
errHandle:
SDBERROR_FORMAT((_T("Failed to parse \"%s\"\n"), lpszVal));
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: StringToQword
//
// Desc: Converts a string to a 64-bit ULONGLONG (aka QWORD). Handles the 0x
// prefix for hex strings.
//
ULONGLONG StringToQword(
CString cs)
{
ULONGLONG ullRet;
cs.MakeLower();
if (cs.Left(2) == _T("0x")) {
_stscanf(cs, _T("0x%I64x"), &ullRet);
} else {
ullRet = _ttoi64(cs);
}
return ullRet;
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: VersionToQword
//
// Desc: Converts a version string to a 64-bit ULONGLONG (aka QWORD).
// Version strings are of the form xx.xx.xx.xx, where each of
// numbers is turned into a word and combined into a single
// quad word. If a portion of the version string is a * or is
// missing, it is stored as 0xFFFF.
//
BOOL VersionToQword(
LPCTSTR lpszVersion,
ULONGLONG* pullRet
)
{
BOOL bSuccess = FALSE;
ULONG ulPart;
LPTSTR pEnd = NULL;
int i;
*pullRet = 0;
for (i = 0; i < 4; i++) {
ulPart = (WORD)0xFFFF;
//
// skip whitespace
//
lpszVersion += _tcsspn(lpszVersion, _T(" \t"));
if (*lpszVersion == _T('*')) {
//
// we expect to see either *\0 or *.xxx
// so move past *
//
pEnd = (LPTSTR)(lpszVersion + 1);
}
else {
//
// not a wildcard - if we have not reached the end of the string,
// keep parsing numbers
//
if (*lpszVersion) {
pEnd = NULL;
ulPart = _tcstol(lpszVersion, &pEnd, 0);
//
// check to see that the part was converted properly
//
if (pEnd == NULL) {
SDBERROR_FORMAT((_T("Internal error, failed to parse \"%s\"\n"), lpszVersion));
goto eh;
}
}
}
if (pEnd == NULL) {
break;
}
//
// skip whitespace first
//
pEnd += _tcsspn(pEnd, _T(" \t"));
//
// at this point we should be at the end of
// the string OR at the '.'
//
if (*pEnd && *pEnd != _T('.')) {
SDBERROR_FORMAT((_T("Bad version specification, parsing stopped at \"%s\"\n"), pEnd));
goto eh;
}
lpszVersion = (*pEnd == _T('.') ? pEnd + 1 : pEnd);
*pullRet = (*pullRet << 16) | ((WORD)ulPart);
}
bSuccess = TRUE;
eh:
return bSuccess;
}
BOOL VersionQwordToString(
OUT CString& rString,
ULONGLONG ullVersion
)
{
// we do conversion to string
int i;
WORD wPart;
CString csPart;
ULONGLONG ullMask = (((ULONGLONG)0xFFFF) << 48);
ULONGLONG ullPart;
rString.Empty();
for (i = 0; i < 4; ++i) {
ullPart = ullVersion & ullMask;
ullVersion = (ullVersion << 16) | (WORD)0xFFFF;
//
// get the part into the lower portion
//
wPart = (WORD)(ullPart >> 48);
if (wPart == (WORD)0xFFFF) {
csPart = _T('*');
} else {
csPart.Format(_T("%hu"), wPart);
}
if (i > 0) {
rString += _T('.');
}
rString += csPart;
if (ullVersion == (ULONGLONG)-1) {
break;
}
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: TrimParagraph
//
// Desc: Trims extra whitespace from a string
//
//
CString TrimParagraph(CString csInput)
{
CString csOutput;
long i;
// Expand CString's buffer to size of input
csOutput.GetBuffer(csInput.GetLength());
csOutput.ReleaseBuffer();
for (i = 0; i < csInput.GetLength(); i++) {
TCHAR c = csInput.GetAt(i);
if (_istspace(c)) {
if (csOutput.GetLength() == 0)
continue;
if (csOutput.Mid(csOutput.GetLength() - 1) == _T(' ') ||
csOutput.Mid(csOutput.GetLength() - 4, 4) == _T("BR/>") ||
csOutput.Mid(csOutput.GetLength() - 3, 3) == _T("P/>"))
continue;
csOutput += _T(' ');
continue;
}
if (csInput.Left(3) == _T("<BR") ||
csInput.Left(2) == _T("<P")) {
//
// Get rid of spaces preceding a <BR/> tag
//
csOutput.TrimRight();
}
csOutput += c;
}
csOutput.TrimLeft();
csOutput.TrimRight();
return csOutput;
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: ReplaceStringNoCase
//
// Desc: Replaces all instances of lpszFindThis with lpszReplaceWithThis
// within csText (case insensitive).
//
VOID ReplaceStringNoCase(CString& csText, LPCTSTR lpszFindThis, LPCTSTR lpszReplaceWithThis)
{
LPTSTR lpszBuffer;
LPTSTR lpszFind;
if (0 == csText.GetLength()) {
return;
}
CString strFindNoCase(lpszFindThis);
lpszBuffer = csText.GetBuffer(csText.GetLength());
strFindNoCase.MakeUpper();
do {
lpszFind = StrStrI(lpszBuffer, strFindNoCase);
if (NULL != lpszFind) {
memcpy(lpszFind, (LPCTSTR)strFindNoCase, strFindNoCase.GetLength() * sizeof(*lpszFind));
lpszBuffer = lpszFind + strFindNoCase.GetLength();
}
} while (NULL != lpszFind);
// now that all the instances of the lpszFindThis had been replaced with
// the upper-cased version... do a regular replace
csText.ReleaseBuffer();
csText.Replace(strFindNoCase, lpszReplaceWithThis);
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: MakeFullPath
//
// Desc: Creates a full path from a (possible) relative one. Uses
// GetCurrentDirectory to prepend the passed in string.
//
CString MakeFullPath(CString cs)
{
CString csNewPath;
DWORD dwCurDirSize;
LPTSTR lpszCurDir;
return cs;
#if 0
//
// Check if it's already a full path
//
if (cs.Mid(1, 1) == _T(":") ||
cs.Left(2) == _T("\\\\")) {
//
// This is either a UNC full path or a DOS full path.
// Drop out.
//
return cs;
}
dwCurDirSize = GetCurrentDirectory(0, NULL);
lpszCurDir = csNewPath.GetBuffer(dwCurDirSize);
if (0 == GetCurrentDirectory(dwCurDirSize, lpszCurDir)) {
//
// Something really weird happened. Not sure how to error out.
//
return cs;
}
csNewPath.ReleaseBuffer();
if (csNewPath.Right(1) != _T("\\")) {
csNewPath += _T("\\");
}
csNewPath += cs;
return csNewPath;
#endif
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: GetByteStringSize
//
// Desc: Parses a 'byte string' (used in <PATCH> declarations) to determine
// how many bytes it contains.
//
DWORD GetByteStringSize(
CString csBytes)
{
DWORD dwByteCount = 0;
BOOL bOnByte = FALSE;
csBytes.MakeUpper();
for (long i = 0; i < csBytes.GetLength(); i++) {
if (_istxdigit(csBytes.GetAt(i))) {
if (!bOnByte) {
dwByteCount++;
bOnByte = TRUE;
}
} else if (_istspace(csBytes.GetAt(i))) {
bOnByte = FALSE;
} else {
SDBERROR_FORMAT((_T("Unrecognized byte character '%c' in <PATCH> block:\n%s\n"),
csBytes.GetAt(i), ((LPCTSTR)csBytes)+i));
return 0xFFFFFFFF;
}
}
return dwByteCount;
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: GetBytesFromString
//
// Desc: Parses a 'byte string' (used in <PATCH> declarations) into an actual
// memory block.
//
DWORD GetBytesFromString(
CString csBytes,
BYTE* pBuffer,
DWORD dwBufferSize)
{
csBytes.MakeUpper();
CString csByte;
DWORD dwRequiredBufferSize;
LONG nFirstByteChar = -1;
DWORD dwBufferCursor = 0;
DWORD dwByte;
dwRequiredBufferSize = GetByteStringSize(csBytes);
if (dwRequiredBufferSize < dwBufferSize || dwRequiredBufferSize == 0xFFFFFFFF) {
return dwRequiredBufferSize;
}
for (long i = 0; i < csBytes.GetLength() + 1; i++) {
if (_istxdigit(csBytes.GetAt(i))) {
if (nFirstByteChar == -1) {
nFirstByteChar = i;
}
} else if (_istspace(csBytes.GetAt(i)) ||
csBytes.GetAt(i) == _T('\0')) {
if (nFirstByteChar != -1) {
csByte = csBytes.Mid(nFirstByteChar, i - nFirstByteChar);
_stscanf(csByte, _T("%x"), &dwByte);
memcpy(pBuffer + dwBufferCursor++, &dwByte, sizeof(BYTE));
}
nFirstByteChar = -1;
} else {
SDBERROR_FORMAT((_T("Unrecognized byte character '%c' in <PATCH> block:\n%s\n"),
csBytes.GetAt(i), ((LPCTSTR)csBytes)+i));
return 0xFFFFFFFF;
}
}
return dwRequiredBufferSize;
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: DecodeString
//
// Desc: Decodes a list of strings with flags
//
// [00] [00] [00] [00]
// ^ Arch1 Arch2 Arch3
// |- flags
//
// syntax for the runtime platform:
// [!] ( [!] STR1 [; STR2 ] ... )
// example:
// !STR1 - will evaluate to TRUE when the the string is NOT STR1
// !(STR1; STR2) - will evaluate to TRUE when the string doesn't contain STR1 or STR2
//
BOOL DecodeString(LPCTSTR pszStr, LPDWORD pdwMask, PFNGETSTRINGMASK pfnGetStringMask)
{
BOOL bNot = FALSE;
BOOL bBracket = FALSE;
LPTSTR pEnd;
TCHAR chSave;
DWORD dwElement;
BOOL bNotElement;
DWORD dwMask = 0;
INT nElement = 0;
BOOL bSuccess = FALSE;
pszStr += _tcsspn(pszStr, _T(" \t"));
//
// Got the first char
//
if (*pszStr == _T('!')) {
//
// Peek ahead and see whether we have a bracket
//
pEnd = (LPTSTR)(pszStr + 1);
pEnd += _tcsspn(pEnd, _T(" \t"));
if (*pEnd == '(') {
// global not
bNot = TRUE;
pszStr = pEnd;
} else {
// local NOT -- so jump to parsing it
goto ParseStart;
}
}
if (*pszStr == _T('(')) {
// bracket, we need to find closing one too
++pszStr;
bBracket = TRUE;
}
ParseStart:
do {
dwElement = 0;
pszStr += _tcsspn(pszStr, _T(" ;,\t"));
if (*pszStr == _T('\0') || *pszStr == _T(')')) {
break;
}
bNotElement = (*pszStr == _T('!'));
if (bNotElement) {
pszStr++;
}
// find the end of this token
pEnd = _tcspbrk(pszStr, _T(" \t;,)"));
if (pEnd != NULL) {
chSave = *pEnd;
*pEnd = _T('\0');
}
dwElement = (*pfnGetStringMask)(pszStr);
if (pEnd) {
*pEnd = chSave;
}
if (dwElement == OS_SKU_NONE) {
goto HandleError;
}
if (bNotElement) {
dwElement ^= 0xFFFFFFFF;
}
dwMask |= dwElement;
pszStr = pEnd;
} while (pEnd); // when pEnd == NULL -- it was the last token
if (bBracket && (!pszStr || *pszStr != ')')) {
// we expected a bracket here
goto HandleError;
}
if (bNot) {
dwMask ^= 0xFFFFFFFF;
}
*pdwMask = dwMask;
bSuccess = TRUE;
HandleError:
if (!bSuccess) {
SDBERROR_FORMAT((_T("Failed to decode \"%s\"\n"), pszStr));
}
return bSuccess;
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: DecodeRuntimePlatformString
//
// Desc: Decodes a list of Platform Strings with flags
//
// [00] [00] [00] [00]
// ^ Arch1 Arch2 Arch3
// |- flags
//
// syntax for the runtime platform:
// [!] ( [!] Platform1 [; Platform2 ] ... )
// example:
// !(IA64; !X86) - will evaluate to TRUE when it's NOT IA64 (native) and X86
// (IA3264; X86) - will evaluate to TRUE when it's running on X86 or 32-bit subsystem on IA64
// (AMD64; IA3264) - will evaluate to TRUE when it's running on AMD64 or 32-bit subsystem on ia64
//
BOOL DecodeRuntimePlatformString(LPCTSTR pszPlatform, LPDWORD pdwRuntimePlatform)
{
BOOL bNot = FALSE;
BOOL bBracket = FALSE;
LPTSTR pEnd;
TCHAR chSave;
DWORD dwElement;
DWORD dwNotElementFlag;
DWORD dwRuntimePlatform = 0;
INT nElement = 0;
BOOL bSuccess = FALSE;
pszPlatform += _tcsspn(pszPlatform, _T(" \t"));
// got the first char
if (*pszPlatform == _T('!')) {
// peek ahead and see whether we have a bracket
pEnd = (LPTSTR)(pszPlatform + 1);
pEnd += _tcsspn(pEnd, _T(" \t"));
if (*pEnd == '(') {
// global not
bNot = TRUE;
pszPlatform = pEnd;
} else {
// local NOT -- so jump to parsing it
goto ParseStart;
}
}
if (*pszPlatform == _T('(')) {
// bracket, we need to find closing one too
++pszPlatform;
bBracket = TRUE;
}
ParseStart:
do {
dwElement = 0;
pszPlatform += _tcsspn(pszPlatform, _T(" ;,\t"));
if (*pszPlatform == _T('\0') || *pszPlatform == _T(')')) {
break;
}
dwNotElementFlag = (*pszPlatform == _T('!')) ? RUNTIME_PLATFORM_FLAG_NOT_ELEMENT : 0;
// find the end of this token
pEnd = _tcspbrk(pszPlatform, _T(" \t;,)"));
if (pEnd != NULL) {
chSave = *pEnd;
*pEnd = _T('\0');
}
dwElement = GetRuntimePlatformType(pszPlatform);
if (pEnd) {
*pEnd = chSave;
}
if (dwElement == PROCESSOR_ARCHITECTURE_UNKNOWN) {
goto HandleError;
}
dwElement |= dwNotElementFlag | RUNTIME_PLATFORM_FLAG_VALID;
if (nElement >= 3) {
goto HandleError;
}
// now shift
dwElement <<= (nElement * 8);
++nElement; // on to the next element
dwRuntimePlatform |= dwElement;
pszPlatform = pEnd;
} while(pEnd); // when pEnd == NULL -- it was the last token
if (bBracket && (!pszPlatform || *pszPlatform != ')')) {
// we expected a bracket here
goto HandleError;
}
if (bNot && nElement > 1) {
dwRuntimePlatform |= RUNTIME_PLATFORM_FLAG_NOT;
}
*pdwRuntimePlatform = dwRuntimePlatform;
bSuccess = TRUE;
HandleError:
return bSuccess;
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: ReadName
//
// Desc: Wrapper to read the name attribute from an XML node.
//
BOOL ReadName( IXMLDOMNode* pNode, CString* pcsName)
{
BOOL bSuccess = FALSE;
if (!GetAttribute(_T("NAME"), pNode, pcsName)) {
SDBERROR_FORMAT((_T("NAME attribute required:\n%s\n\n"),
GetXML(pNode)));
goto eh;
}
bSuccess = TRUE;
eh:
return TRUE;
}
BOOL ReadLangID(IXMLDOMNode* pNode, SdbDatabase* pDB, CString* pcsLangID)
{
if (!GetAttribute(_T("LANGID"), pNode, pcsLangID)) {
if (!pDB->m_csCurrentLangID.GetLength())
{
SDBERROR_FORMAT((
_T("Tag requires LANGID attribute if there is no LANGID on the DATABASE node\n%s\n"),
GetXML(pNode)));
return FALSE;
}
*pcsLangID = pDB->m_csCurrentLangID;
}
return TRUE;
}
BOOL FilterOSVersion(DOUBLE flOSVersion, CString csOSVersionSpec, LPDWORD lpdwSPMask)
{
DOUBLE flVerXML;
CString csTemp;
long nBeg, i, nIndSP;
int nSPVersion;
TCHAR chSP;
BOOL bFilter = TRUE;
DWORD dwSPMask;
if (flOSVersion == 0.0 || csOSVersionSpec.IsEmpty()) {
*lpdwSPMask = 0xFFFFFFFF;
return FALSE;
}
*lpdwSPMask = 0;
nBeg = 0;
for (i = 0; i <= csOSVersionSpec.GetLength(); i++) {
if (csOSVersionSpec.GetAt(i) == _T('\0') || csOSVersionSpec.GetAt(i) == _T(';')) {
csTemp = csOSVersionSpec.Mid(nBeg, i - nBeg);
nBeg = i + 1;
if (csTemp.GetLength() == 0) {
continue;
}
dwSPMask = 0xFFFFFFFF;
nSPVersion = -1;
nIndSP = -1;
if ((nIndSP = csTemp.Find('.')) != -1) {
if ((nIndSP = csTemp.Find('.', nIndSP + 1)) != -1) {
CString csSP = csTemp.Right(csTemp.GetLength() - nIndSP - 1);
chSP = csTemp.GetAt(nIndSP);
csTemp.SetAt(nIndSP, 0);
nSPVersion = _ttoi(csSP);
}
}
if (csTemp.Left(2) == _T("gt")) {
if (csTemp.Left(3) == _T("gte")) {
flVerXML = _tcstod(csTemp.Right(csTemp.GetLength() - 3), NULL);
if (flOSVersion >= flVerXML) {
bFilter = FALSE;
}
if (nSPVersion != -1 && flOSVersion == flVerXML) {
dwSPMask = 0xFFFFFFFF - (1 << nSPVersion) + 1;
}
} else {
flVerXML = _tcstod(csTemp.Right(csTemp.GetLength() - 2), NULL);
if (flOSVersion > flVerXML) {
bFilter = FALSE;
}
if (nSPVersion != -1 && flOSVersion == flVerXML) {
bFilter = FALSE;
dwSPMask = 0xFFFFFFFF - (1 << (nSPVersion + 1)) + 1;
}
}
} else if (csTemp.Left(2) == _T("lt")) {
if (csTemp.Left(3) == _T("lte")) {
flVerXML = _tcstod(csTemp.Right(csTemp.GetLength() - 3), NULL);
if (flOSVersion <= flVerXML) {
bFilter = FALSE;
}
if (nSPVersion != -1 && flOSVersion == flVerXML) {
dwSPMask = 0xFFFFFFFF - (1 << (nSPVersion + 1)) + 1;
dwSPMask ^= 0xFFFFFFFF;
}
} else {
flVerXML = _tcstod(csTemp.Right(csTemp.GetLength() - 2), NULL);
if (flOSVersion < flVerXML) {
bFilter = FALSE;
}
if (nSPVersion != -1 && flOSVersion == flVerXML) {
bFilter = FALSE;
dwSPMask = 0xFFFFFFFF - (1 << nSPVersion) + 1;
dwSPMask ^= 0xFFFFFFFF;
}
}
} else {
if (flOSVersion == _tcstod(csTemp, NULL)) {
bFilter = FALSE;
if (nSPVersion != -1) {
dwSPMask = (1 << nSPVersion);
}
}
}
if (nIndSP != -1) {
csTemp.SetAt(nIndSP, chSP);
*lpdwSPMask |= dwSPMask;
}
}
}
if (*lpdwSPMask == 0) {
*lpdwSPMask = 0xFFFFFFFF;
}
return bFilter;
}
VOID ExpandEnvStrings(CString* pcs)
{
LPTSTR lpszBuf;
DWORD cchReqBufSize;
CString cs(*pcs);
cchReqBufSize = ExpandEnvironmentStrings(cs, NULL, 0);
lpszBuf = pcs->GetBuffer(cchReqBufSize);
ExpandEnvironmentStrings(cs, lpszBuf, cchReqBufSize);
pcs->ReleaseBuffer();
}
BOOL MakeUTCTime(CString& cs, time_t* pt)
{
BOOL bSuccess = FALSE;
CString csTZ;
//
// Set TZ environment variable to override locale
// settings so that date/time conversion routines
// never do any localizations.
//
csTZ = _tgetenv(_T("TZ"));
csTZ = _T("TZ=") + csTZ;
_tputenv(_T("TZ=UTC0"));
_tzset();
COleDateTime odt;
SYSTEMTIME st;
CTime time;
if (!odt.ParseDateTime(cs)) {
goto eh;
}
if (!odt.GetAsSystemTime(st)) {
goto eh;
}
time = st;
*pt = time.GetTime();
bSuccess = TRUE;
eh:
_tputenv(csTZ);
_tzset();
return bSuccess;
}
BOOL ParseLanguageID(LPCTSTR pszLanguage, DWORD* pdwLanguageID)
{
LPCTSTR pch;
LPTSTR pend = NULL;
BOOL bSuccess = FALSE;
BOOL bBracket = FALSE;
DWORD dwLangID = 0;
pch = _tcschr(pszLanguage, TEXT('['));
if (NULL != pch) {
bBracket = TRUE;
++pch;
} else {
pch = pszLanguage;
}
while (_istspace(*pch)) {
++pch;
}
dwLangID = _tcstoul(pch, &pend, 0);
if (dwLangID == 0) {
goto cleanup;
}
if (pend != NULL) {
bSuccess = bBracket ? (_istspace(*pend) || *pend == TEXT(']')) :
(_istspace(*pend) || *pend == TEXT('\0'));
}
cleanup:
if (bSuccess) {
*pdwLanguageID = dwLangID;
}
return bSuccess;
}
BOOL ParseLanguagesString(CString csLanguages, CStringArray* prgLanguages)
{
BOOL bSuccess = FALSE, bExistsAlready = FALSE;
int nLastSemicolon = -1, i, j;
CString csLangID;
for (i = 0; i <= csLanguages.GetLength(); i++)
{
if (csLanguages[i] == _T(';') || csLanguages[i] == _T('\0')) {
csLangID = csLanguages.Mid(nLastSemicolon + 1, i - nLastSemicolon - 1);
csLangID.TrimLeft();
csLangID.TrimRight();
csLangID.MakeUpper();
bExistsAlready = FALSE;
for (j = 0; j < prgLanguages->GetSize(); j++)
{
if (prgLanguages->GetAt(j) == csLangID)
{
bExistsAlready = TRUE;
break;
}
}
if (!bExistsAlready)
{
prgLanguages->Add(csLangID);
}
nLastSemicolon = i;
}
}
bSuccess = TRUE;
return bSuccess;
}
CString GetGUID(REFGUID guid)
{
CString csRet;
LPOLESTR lpszGUID = NULL;
StringFromCLSID(guid, &lpszGUID);
csRet = lpszGUID;
CoTaskMemFree(lpszGUID);
return csRet;
}
CString ProcessShimCmdLine(
CString& csCommandLine,
GUID& guidDB,
TAGID tiShimRef
)
{
//
// find whether we have anything to expand in csCommandLine
//
LPCTSTR pch;
int nIndex;
CString csNewCmdLine = csCommandLine;
CString csToken;
int nIndexStart = 0;
int nIndexEnd;
while (nIndexStart < csNewCmdLine.GetLength()) {
nIndex = csNewCmdLine.Find(_T('%'), nIndexStart);
if (nIndex < 0) {
goto Done;
}
nIndexEnd = csNewCmdLine.Find(_T('%'), nIndex + 1);
if (nIndexEnd < 0) {
goto Done;
}
//
// we matched a token, see whether it's something we're interested in
//
csToken = csNewCmdLine.Mid(nIndex + 1, nIndexEnd - nIndex - 1);
if (0 == csToken.CompareNoCase(_T("DBINFO"))) {
csToken.Format(_T("-d%ls -t0x%lx"), (LPCTSTR)GetGUID(guidDB), tiShimRef);
//
// replace the token with csToken
//
csNewCmdLine.Delete(nIndex, nIndexEnd - nIndex + 1);
csNewCmdLine.Insert(nIndex, csToken);
//
// adjust our position for scanning
//
nIndexEnd = nIndex + csToken.GetLength() - 1; // one char before the end of this token
}
nIndexStart = nIndexEnd + 1;
}
Done:
return csNewCmdLine;
}