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

386 lines
10 KiB
C++

/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
ParseDde.cpp
Abstract:
Useful routines for parsing DDE commands.
History:
08/14/2001 robkenny Moved code inside the ShimLib namespace.
--*/
//
// This code was copied from:
// \\index1\src\shell\shell32\unicpp\dde.cpp
// with minimal processing.
//
#include "Windows.h"
#include "ParseDDE.h"
#include <ShlObj.h>
namespace ShimLib
{
//--------------------------------------------------------------------------
// Returns a pointer to the first non-whitespace character in a string.
LPSTR SkipWhite(LPSTR lpsz)
{
/* prevent sign extension in case of DBCS */
while (*lpsz && (UCHAR)*lpsz <= ' ')
lpsz++;
return(lpsz);
}
LPSTR GetCommandName(LPSTR lpCmd, const char * lpsCommands[], UINT *lpW)
{
CHAR chT;
UINT iCmd = 0;
LPSTR lpT;
/* Eat any white space. */
lpCmd = SkipWhite(lpCmd);
lpT = lpCmd;
/* Find the end of the token. */
while (IsCharAlpha(*lpCmd))
lpCmd = CharNextA(lpCmd);
/* Temporarily NULL terminate it. */
chT = *lpCmd;
*lpCmd = 0;
/* Look up the token in a list of commands. */
*lpW = (UINT)-1;
while (*lpsCommands)
{
const char * knownCommand = *lpsCommands;
if (!_strcmpi(knownCommand, lpT))
{
*lpW = iCmd;
break;
}
iCmd++;
++lpsCommands;
}
*lpCmd = chT;
return(lpCmd);
}
//--------------------------------------------------------------------------
// Reads a parameter out of a string removing leading and trailing whitespace.
// Terminated by , or ). ] [ and ( are not allowed. Exception: quoted
// strings are treated as a whole parameter and may contain []() and ,.
// Places the offset of the first character of the parameter into some place
// and NULL terminates the parameter.
// If fIncludeQuotes is false it is assumed that quoted strings will contain single
// commands (the quotes will be removed and anything following the quotes will
// be ignored until the next comma). If fIncludeQuotes is TRUE, the contents of
// the quoted string will be ignored as before but the quotes won't be
// removed and anything following the quotes will remain.
LPSTR GetOneParameter(LPCSTR lpCmdStart, LPSTR lpCmd,
UINT *lpW, BOOL fIncludeQuotes)
{
LPSTR lpT;
switch (*lpCmd)
{
case ',':
*lpW = (UINT) (lpCmd - lpCmdStart); // compute offset
*lpCmd++ = 0; /* comma: becomes a NULL string */
break;
case '"':
if (fIncludeQuotes)
{
//TraceMsg(TF_DDE, "GetOneParameter: Keeping quotes.");
// quoted string... don't trim off "
*lpW = (UINT) (lpCmd - lpCmdStart); // compute offset
++lpCmd;
while (*lpCmd && *lpCmd != '"')
lpCmd = CharNextA(lpCmd);
if (!*lpCmd)
return(NULL);
lpT = lpCmd;
++lpCmd;
goto skiptocomma;
}
else
{
// quoted string... trim off "
++lpCmd;
*lpW = (UINT) (lpCmd - lpCmdStart); // compute offset
while (*lpCmd && *lpCmd != '"')
lpCmd = CharNextA(lpCmd);
if (!*lpCmd)
return(NULL);
*lpCmd++ = 0;
lpCmd = SkipWhite(lpCmd);
// If there's a comma next then skip over it, else just go on as
// normal.
if (*lpCmd == ',')
lpCmd++;
}
break;
case ')':
return(lpCmd); /* we ought not to hit this */
case '(':
case '[':
case ']':
return(NULL); /* these are illegal */
default:
lpT = lpCmd;
*lpW = (UINT) (lpCmd - lpCmdStart); // compute offset
skiptocomma:
while (*lpCmd && *lpCmd != ',' && *lpCmd != ')')
{
/* Check for illegal characters. */
if (*lpCmd == ']' || *lpCmd == '[' || *lpCmd == '(' )
return(NULL);
/* Remove trailing whitespace */
/* prevent sign extension */
if (*lpCmd > ' ')
lpT = lpCmd;
lpCmd = CharNextA(lpCmd);
}
/* Eat any trailing comma. */
if (*lpCmd == ',')
lpCmd++;
/* NULL terminator after last nonblank character -- may write over
* terminating ')' but the caller checks for that because this is
* a hack.
*/
#ifdef UNICODE
lpT[1] = 0;
#else
lpT[IsDBCSLeadByte(*lpT) ? 2 : 1] = 0;
#endif
break;
}
// Return next unused character.
return(lpCmd);
}
// Extracts an alphabetic string and looks it up in a list of possible
// commands, returning a pointer to the character after the command and
// sticking the command index somewhere.
UINT* GetDDECommands(LPSTR lpCmd, const char * lpsCommands[], BOOL fLFN)
{
UINT cParm, cCmd = 0;
UINT *lpW;
UINT *lpRet;
LPCSTR lpCmdStart = lpCmd;
BOOL fIncludeQuotes = FALSE;
if (lpCmd == NULL)
return NULL;
lpRet = lpW = (UINT*)GlobalAlloc(GPTR, 512L);
if (!lpRet)
return 0;
while (*lpCmd)
{
/* Skip leading whitespace. */
lpCmd = SkipWhite(lpCmd);
/* Are we at a NULL? */
if (!*lpCmd)
{
/* Did we find any commands yet? */
if (cCmd)
goto GDEExit;
else
goto GDEErrExit;
}
/* Each command should be inside square brackets. */
if (*lpCmd != '[')
goto GDEErrExit;
lpCmd++;
/* Get the command name. */
lpCmd = GetCommandName(lpCmd, lpsCommands, lpW);
if (*lpW == (UINT)-1)
goto GDEErrExit;
// We need to leave quotes in for the first param of an AddItem.
if (fLFN && *lpW == 2)
{
//TraceMsg(TF_DDE, "GetDDECommands: Potential LFN AddItem command...");
fIncludeQuotes = TRUE;
}
lpW++;
/* Start with zero parms. */
cParm = 0;
lpCmd = SkipWhite(lpCmd);
/* Check for opening '(' */
if (*lpCmd == '(')
{
lpCmd++;
/* Skip white space and then find some parameters (may be none). */
lpCmd = SkipWhite(lpCmd);
while (*lpCmd != ')')
{
if (!*lpCmd)
goto GDEErrExit;
// Only the first param of the AddItem command needs to
// handle quotes from LFN guys.
if (fIncludeQuotes && (cParm != 0))
fIncludeQuotes = FALSE;
/* Get the parameter. */
lpCmd = GetOneParameter(lpCmdStart, lpCmd, lpW + (++cParm), fIncludeQuotes);
if (!lpCmd)
goto GDEErrExit;
/* HACK: Did GOP replace a ')' with a NULL? */
if (!*lpCmd)
break;
/* Find the next one or ')' */
lpCmd = SkipWhite(lpCmd);
}
// Skip closing bracket.
lpCmd++;
/* Skip the terminating stuff. */
lpCmd = SkipWhite(lpCmd);
}
/* Set the count of parameters and then skip the parameters. */
*lpW++ = cParm;
lpW += cParm;
/* We found one more command. */
cCmd++;
/* Commands must be in square brackets. */
if (*lpCmd != ']')
goto GDEErrExit;
lpCmd++;
}
GDEExit:
/* Terminate the command list with -1. */
*lpW = (UINT)-1;
return lpRet;
GDEErrExit:
GlobalFree(lpW);
return(0);
}
BOOL SHTestTokenMembership (HANDLE hToken, ULONG ulRID)
{
static SID_IDENTIFIER_AUTHORITY sSystemSidAuthority = SECURITY_NT_AUTHORITY;
BOOL fResult;
PSID pSIDLocalGroup;
fResult = FALSE;
if (AllocateAndInitializeSid(&sSystemSidAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
ulRID,
0, 0, 0, 0, 0, 0,
&pSIDLocalGroup) != FALSE)
{
if (CheckTokenMembership(hToken, pSIDLocalGroup, &fResult) == FALSE)
{
//TraceMsg(TF_WARNING, "shell32: SHTestTokenMembership call to advapi32!CheckTokenMembership failed with error %d", GetLastError());
fResult = FALSE;
}
(void*)FreeSid(pSIDLocalGroup);
}
return(fResult);
}
BOOL IsUserAnAdmin()
{
return(SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_ADMINS));
}
// Map the group name to a proper path taking care of the startup group and
// app hacks on the way.
void GetGroupPath(LPCSTR pszName, LPSTR pszPath, DWORD /*dwFlags*/, INT iCommonGroup)
{
BOOL bCommonGroup;
if (IsUserAnAdmin()) {
if (iCommonGroup == 0) {
bCommonGroup = FALSE;
} else if (iCommonGroup == 1) {
bCommonGroup = TRUE;
} else {
//
// Administrators get common groups created by default
// when the setup application doesn't specificly state
// what kind of group to create. This feature can be
// turned off in the cabinet state flags.
//
//CABINETSTATE cs;
//ReadCabinetState(&cs, sizeof(cs));
//if (cs.fAdminsCreateCommonGroups) {
// bFindPersonalGroup = TRUE;
// bCommonGroup = FALSE; // This might get turned on later
// // if find is unsuccessful
//} else {
// bCommonGroup = FALSE;
//}
bCommonGroup = TRUE;
}
} else {
//
// Regular users can't create common group items.
//
bCommonGroup = FALSE;
}
// Build a path to the directory
if (bCommonGroup) {
SHGetSpecialFolderPathA(NULL, pszPath, CSIDL_COMMON_PROGRAMS, TRUE);
} else {
SHGetSpecialFolderPathA(NULL, pszPath, CSIDL_PROGRAMS, TRUE);
}
strcat(pszPath, "\\");
strcat(pszPath, pszName);
}
}; // end of namespace ShimLib