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.
1154 lines
28 KiB
1154 lines
28 KiB
////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|