483 lines
13 KiB
C++
483 lines
13 KiB
C++
|
/*++
|
||
|
|
||
|
Microsoft Windows
|
||
|
Copyright (C) Microsoft Corporation, 1981 - 2000
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
path.cxx
|
||
|
|
||
|
Abstract:
|
||
|
Implementation of the methods in the CRedirPath class. This class
|
||
|
parses a path and breaks it up into different components and categorizes
|
||
|
it into one of the well known paths:
|
||
|
(a) a path in the local user profile location
|
||
|
(b) a path in the user's home directory
|
||
|
(c) a specific user specified path
|
||
|
(d) a per-user path in a user specified location
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Rahul Thombre (RahulTh) 3/3/2000
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
3/3/2000 RahulTh Created this module.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.hxx"
|
||
|
|
||
|
CRedirPath::CRedirPath(UINT cookie) : _bDataValid (FALSE), _cookie(cookie)
|
||
|
{
|
||
|
_szPrefix.Empty();
|
||
|
_szSuffix.Empty();
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CRedirPath::GeneratePath
|
||
|
//
|
||
|
// Synopsis: Generate the full path from the components
|
||
|
//
|
||
|
// Arguments: [out] szPath : the generated path
|
||
|
// [in, optional] szUser : sample username
|
||
|
//
|
||
|
// Returns: TRUE : if the generated path is valid.
|
||
|
// FALSE: if there is no valid path stored in this object. In
|
||
|
// this case szPath is set to an empty string.
|
||
|
//
|
||
|
// History: 3/3/2000 RahulTh created
|
||
|
//
|
||
|
// Notes: For per user paths, this function uses a sample username
|
||
|
// if supplied, otherwise, it uses the username variable
|
||
|
// string %username%
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
BOOL CRedirPath::GeneratePath (OUT CString & szPath,
|
||
|
OPTIONAL IN const CString & szUser //= USERNAME_STR
|
||
|
) const
|
||
|
{
|
||
|
BOOL bStatus;
|
||
|
|
||
|
if (! _bDataValid)
|
||
|
return FALSE;
|
||
|
|
||
|
szPath = L"";
|
||
|
bStatus = TRUE;
|
||
|
switch (_type)
|
||
|
{
|
||
|
case IDS_SPECIFIC_PATH:
|
||
|
szPath = _szPrefix;
|
||
|
if (! IsValidPrefix (_type, (LPCTSTR) _szPrefix))
|
||
|
bStatus = FALSE;
|
||
|
break;
|
||
|
case IDS_HOMEDIR_PATH:
|
||
|
szPath = HOMEDIR_STR;
|
||
|
if (!_szSuffix.IsEmpty())
|
||
|
szPath += _szSuffix;
|
||
|
bStatus = TRUE;
|
||
|
break;
|
||
|
case IDS_PERUSER_PATH:
|
||
|
if (_szPrefix.IsEmpty() ||
|
||
|
! IsValidPrefix (_type, (LPCTSTR) _szPrefix))
|
||
|
{
|
||
|
bStatus = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
szPath = (_szPrefix + L'\\') + szUser;
|
||
|
if (! _szSuffix.IsEmpty())
|
||
|
szPath += _szSuffix;
|
||
|
bStatus = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
case IDS_USERPROFILE_PATH:
|
||
|
if (_szSuffix.IsEmpty())
|
||
|
{
|
||
|
bStatus = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
szPath = PROFILE_STR + _szSuffix;
|
||
|
bStatus = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
bStatus = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CRedirPath::GenerateSuffix
|
||
|
//
|
||
|
// Synopsis: generates a new suffix based on a given path type and folder
|
||
|
//
|
||
|
// Arguments: [out] szSuffix
|
||
|
// [in] cookie
|
||
|
// [in] pathType
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 3/7/2000 RahulTh created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
void CRedirPath::GenerateSuffix (OUT CString & szSuffix,
|
||
|
IN UINT cookie,
|
||
|
IN UINT pathType
|
||
|
) const
|
||
|
{
|
||
|
AFX_MANAGE_STATE (AfxGetStaticModuleState());
|
||
|
|
||
|
szSuffix.Empty();
|
||
|
|
||
|
if (IDS_HOMEDIR_PATH == pathType)
|
||
|
return;
|
||
|
|
||
|
if (IDS_MYPICS == cookie)
|
||
|
{
|
||
|
//
|
||
|
// Use the full My Documents\My Pictures path
|
||
|
// only if we are going to the user profile.
|
||
|
// Otherwise stick to vanilla My Pictures
|
||
|
// This ensures that when My Pictures is redirected independently
|
||
|
// to another location, we do not create an extra level of folders
|
||
|
// as this might cause security problems for MyDocs if they are
|
||
|
// also redirected to the same share.
|
||
|
//
|
||
|
if (IDS_USERPROFILE_PATH == pathType)
|
||
|
szSuffix.LoadString (IDS_MYPICS_RELPATH);
|
||
|
else
|
||
|
szSuffix.LoadString (IDS_MYPICS);
|
||
|
}
|
||
|
else
|
||
|
szSuffix.LoadString (cookie);
|
||
|
|
||
|
// Precede it with a "\"
|
||
|
szSuffix = L'\\' + szSuffix;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CRedirPath::Load
|
||
|
//
|
||
|
// Synopsis: parses a given path and breaks it into different components
|
||
|
// so that it can be categorized into one of the well known
|
||
|
// types
|
||
|
//
|
||
|
// Arguments: [in] szPath : the given full path
|
||
|
//
|
||
|
// Returns: TRUE: if the categorization was succesful.
|
||
|
// FALSE otherwise
|
||
|
//
|
||
|
// History: 3/3/2000 RahulTh created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
BOOL CRedirPath::Load (IN LPCTSTR pwszPath)
|
||
|
{
|
||
|
CString szPath;
|
||
|
BOOL bStatus = FALSE;
|
||
|
|
||
|
szPath = pwszPath;
|
||
|
szPath.TrimLeft();
|
||
|
szPath.TrimRight();
|
||
|
szPath.TrimRight (L'\\');
|
||
|
|
||
|
// First check to see if it is a homedir path.
|
||
|
bStatus = this->LoadHomedir ((LPCTSTR)szPath);
|
||
|
|
||
|
// If not, try per-user
|
||
|
if (!bStatus)
|
||
|
bStatus = this->LoadPerUser ((LPCTSTR) szPath);
|
||
|
|
||
|
// If not, try local userprofile
|
||
|
if (!bStatus)
|
||
|
bStatus = this->LoadUserprofile ((LPCTSTR) szPath);
|
||
|
|
||
|
//
|
||
|
// If not try a user defined path.
|
||
|
// Note: we cannot use the value blindly here because we need to
|
||
|
// make sure that there are no environment variables in there.
|
||
|
//
|
||
|
if (!bStatus)
|
||
|
bStatus = this->LoadSpecific ((LPCTSTR) szPath);
|
||
|
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
// Determines if a valid path is stored in this object.
|
||
|
BOOL CRedirPath::IsPathValid (void) const
|
||
|
{
|
||
|
return _bDataValid;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Determines if the supplied path is different from the path stored in the
|
||
|
// object. Note: the suffix is immaterial in these comparisons.
|
||
|
//
|
||
|
BOOL CRedirPath::IsPathDifferent (IN UINT type, IN LPCTSTR pwszPrefix) const
|
||
|
{
|
||
|
CString szPrefix;
|
||
|
|
||
|
// Make sure that a path has been loaded in this object first.
|
||
|
if (! _bDataValid)
|
||
|
return TRUE;
|
||
|
|
||
|
// If the types of the paths aren't the same, tnen the paths surely aren't
|
||
|
if (type != _type)
|
||
|
return TRUE;
|
||
|
|
||
|
// If we are here, the types of the path are the same
|
||
|
|
||
|
//
|
||
|
// Comparing the prefix does not make sense for a homedir path or
|
||
|
// a userprofile path
|
||
|
//
|
||
|
if (IDS_USERPROFILE_PATH == type ||
|
||
|
IDS_HOMEDIR_PATH == type)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
szPrefix = pwszPrefix;
|
||
|
szPrefix.TrimLeft();
|
||
|
szPrefix.TrimRight();
|
||
|
szPrefix.TrimRight (L'\\');
|
||
|
if (szPrefix != _szPrefix)
|
||
|
return TRUE;
|
||
|
else
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// parse the path to see if it is a homedir path
|
||
|
BOOL CRedirPath::LoadHomedir (LPCTSTR pwszPath)
|
||
|
{
|
||
|
BOOL bStatus = FALSE;
|
||
|
int len, lenHomedir;
|
||
|
|
||
|
// Only the My Documents folder is allowed to have a homedir path
|
||
|
if (IDS_MYDOCS != _cookie)
|
||
|
return FALSE;
|
||
|
|
||
|
len = lstrlen (pwszPath);
|
||
|
lenHomedir = lstrlen (HOMEDIR_STR);
|
||
|
|
||
|
if (lenHomedir <= len &&
|
||
|
0 == _wcsnicmp (pwszPath, HOMEDIR_STR, lenHomedir) &&
|
||
|
(L'\0' == pwszPath[lenHomedir] || L'\\' == pwszPath[lenHomedir]) &&
|
||
|
NULL == wcsstr (&pwszPath[lenHomedir], L"%") // Variables are not allowed anywhere else
|
||
|
)
|
||
|
{
|
||
|
bStatus = TRUE;
|
||
|
_type = IDS_HOMEDIR_PATH;
|
||
|
_szPrefix.Empty();
|
||
|
_szSuffix = &pwszPath[lenHomedir];
|
||
|
}
|
||
|
|
||
|
_bDataValid = bStatus;
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
// parse the path to see if it is a per-user path
|
||
|
BOOL CRedirPath::LoadPerUser (LPCTSTR pwszPath)
|
||
|
{
|
||
|
BOOL bStatus = FALSE;
|
||
|
WCHAR * pwszPos = NULL;
|
||
|
int lenUsername, len;
|
||
|
|
||
|
// Start menu is not allowed to have a per user path.
|
||
|
if (IDS_STARTMENU == _cookie)
|
||
|
return FALSE;
|
||
|
|
||
|
pwszPos = wcsstr (pwszPath, L"%");
|
||
|
|
||
|
if (pwszPos)
|
||
|
{
|
||
|
*pwszPos = L'\0'; // Temporarily look at only the prefix.
|
||
|
if (!IsValidPrefix (IDS_PERUSER_PATH, pwszPath))
|
||
|
{
|
||
|
*pwszPos = L'%'; // Reset the character at pwszPos
|
||
|
goto LoadPerUser_End;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*pwszPos = L'%'; // Reset the character at pwszPos
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// %username% should be the first variable that appears in the path
|
||
|
// if this is to be a per-user path, but it should not be the first
|
||
|
// thing in the path
|
||
|
//
|
||
|
if (NULL != pwszPos && pwszPos != pwszPath)
|
||
|
{
|
||
|
len = lstrlen (pwszPos);
|
||
|
lenUsername = lstrlen (USERNAME_STR);
|
||
|
if (lenUsername <= len &&
|
||
|
0 == _wcsnicmp (pwszPos, USERNAME_STR, lenUsername) &&
|
||
|
NULL == wcsstr (&pwszPos[lenUsername], L"%")
|
||
|
)
|
||
|
{
|
||
|
bStatus = TRUE;
|
||
|
_type = IDS_PERUSER_PATH;
|
||
|
_szPrefix = pwszPath;
|
||
|
_szPrefix = _szPrefix.Left (pwszPos - pwszPath);
|
||
|
_szPrefix.TrimLeft();
|
||
|
_szPrefix.TrimRight();
|
||
|
_szPrefix.TrimRight(L'\\');
|
||
|
_szSuffix = &pwszPos[lenUsername];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LoadPerUser_End:
|
||
|
_bDataValid = bStatus;
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
// parse the path to see if it is a userprofile path
|
||
|
BOOL CRedirPath::LoadUserprofile (LPCTSTR pwszPath)
|
||
|
{
|
||
|
BOOL bStatus = FALSE;
|
||
|
int len, lenUserprofile;
|
||
|
|
||
|
len = lstrlen (pwszPath);
|
||
|
lenUserprofile = lstrlen (PROFILE_STR);
|
||
|
|
||
|
//
|
||
|
// Note: it is considered a userprofile path only if it is of the form
|
||
|
// %userprofile%\<name> where <name> does not contain any variables
|
||
|
//
|
||
|
if (lenUserprofile + 1 < len &&
|
||
|
0 == _wcsnicmp (pwszPath, PROFILE_STR, lenUserprofile) &&
|
||
|
(L'\0' == pwszPath[lenUserprofile] || L'\\' == pwszPath[lenUserprofile]) &&
|
||
|
NULL == wcsstr (&pwszPath[lenUserprofile], L"%")
|
||
|
)
|
||
|
{
|
||
|
bStatus = TRUE;
|
||
|
_type = IDS_USERPROFILE_PATH;
|
||
|
_szPrefix.Empty();
|
||
|
_szSuffix = &pwszPath[lenUserprofile];
|
||
|
}
|
||
|
|
||
|
_bDataValid = bStatus;
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
// parse the path to see if it is a specific path provided by the user
|
||
|
BOOL CRedirPath::LoadSpecific (LPCTSTR pwszPath)
|
||
|
{
|
||
|
BOOL bStatus = FALSE;
|
||
|
|
||
|
// We pretty much allow all paths other than empty paths.
|
||
|
|
||
|
if (NULL != pwszPath && L'\0' != *pwszPath)
|
||
|
{
|
||
|
bStatus = TRUE;
|
||
|
_type = IDS_SPECIFIC_PATH;
|
||
|
_szPrefix = pwszPath;
|
||
|
_szPrefix.TrimLeft();
|
||
|
_szPrefix.TrimRight();
|
||
|
_szPrefix.TrimRight(L'\\');
|
||
|
// use X:\ rather than X: to make sure client does not fail
|
||
|
if (2 == _szPrefix.GetLength() && L':' == ((LPCTSTR)_szPrefix)[1])
|
||
|
_szPrefix += L'\\';
|
||
|
_szSuffix.Empty();
|
||
|
}
|
||
|
|
||
|
_bDataValid = bStatus;
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validates the arguments and loads the path into the object.
|
||
|
// The existing object is not modified if the data is invalid
|
||
|
//
|
||
|
BOOL CRedirPath::Load (UINT type, LPCTSTR pwszPrefix, LPCTSTR pwszSuffix)
|
||
|
{
|
||
|
CString szPrefix;
|
||
|
CString szSuffix;
|
||
|
|
||
|
// First process the strings.
|
||
|
szPrefix = pwszPrefix;
|
||
|
szPrefix.TrimLeft();
|
||
|
szPrefix.TrimRight();
|
||
|
szPrefix.TrimRight(L'\\');
|
||
|
|
||
|
szSuffix = pwszSuffix;
|
||
|
szSuffix.TrimLeft();
|
||
|
szSuffix.TrimRight();
|
||
|
szSuffix.TrimRight(L'\\');
|
||
|
|
||
|
//
|
||
|
// The suffix should never have a variable name in it, except
|
||
|
// IDS_SPECIFIC_PATH, for which a suffix really does not make
|
||
|
// much sense.
|
||
|
//
|
||
|
if (IDS_SPECIFIC_PATH != type &&
|
||
|
-1 != szSuffix.Find (L'%'))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Now do the remaining validation on the type and the suffix.
|
||
|
switch (type)
|
||
|
{
|
||
|
case IDS_PERUSER_PATH:
|
||
|
if (szPrefix.IsEmpty() ||
|
||
|
! IsValidPrefix (type, (LPCTSTR) szPrefix))
|
||
|
return FALSE;
|
||
|
break;
|
||
|
case IDS_SPECIFIC_PATH:
|
||
|
if (!IsValidPrefix (type, (LPCTSTR) szPrefix))
|
||
|
return FALSE;
|
||
|
// use X:\ rather than X: to make sure client does not fail.
|
||
|
if (2 == szPrefix.GetLength() && L':' == ((LPCTSTR)szPrefix)[1])
|
||
|
szPrefix += L'\\';
|
||
|
szSuffix.Empty(); // The entire path is in the prefix. Suffix does not make sense here.
|
||
|
break;
|
||
|
case IDS_USERPROFILE_PATH:
|
||
|
case IDS_HOMEDIR_PATH:
|
||
|
szPrefix.Empty(); // The prefix does not make sense for these paths
|
||
|
break;
|
||
|
default:
|
||
|
return FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we are here, the data is okay. So populate the members.
|
||
|
// Note: It is okay for the suffix to be an empty string.
|
||
|
//
|
||
|
_bDataValid = TRUE;
|
||
|
_type = type;
|
||
|
_szPrefix = szPrefix;
|
||
|
_szSuffix = szSuffix;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void CRedirPath::GetPrefix (OUT CString & szPrefix) const
|
||
|
{
|
||
|
if (_bDataValid)
|
||
|
szPrefix = _szPrefix;
|
||
|
else
|
||
|
szPrefix.Empty();
|
||
|
}
|
||
|
|
||
|
UINT CRedirPath::GetType (void) const
|
||
|
{
|
||
|
return _type;
|
||
|
}
|
||
|
|