2025-04-27 07:49:33 -04:00

959 lines
23 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1998 - 1998.
//
// File: filelist.hxx
//
// Contents: CFileList class definition
//
// Classes: CFileList
//
// Functions:
//
// History: 22-Sep-99 PhilipLa Created
//
//----------------------------------------------------------------------------
#ifndef __FILELIST_HXX__
#define __FILELIST_HXX__
#include "fileutil.hxx"
#define FILELISTMAXNAMES 20
inline DWORD ComputeFitIndex(const TCHAR *ptsDir,
const TCHAR *ptsFile,
const TCHAR *ptsExt);
class CFileList
{
public:
inline CFileList();
inline ~CFileList();
inline DWORD SetName(const TCHAR * tsName,
DWORD *pdwIndex,
BOOL fDeconstruct);
inline ULONG GetNameCount(void) const;
inline DWORD SetDestination(const TCHAR *tsName, DWORD dwIndex);
inline const TCHAR *GetDestination(ULONG i) const;
inline const TCHAR * GetFullName(ULONG i) const;
inline const TCHAR * GetDirName(ULONG i) const;
inline const TCHAR * GetFileName(ULONG i) const;
inline const TCHAR * GetExtName(ULONG i) const;
inline const DWORD GetWeight(ULONG i) const;
inline CFileList * GetNextFileList(void) const;
private:
ULONG _cNames;
TCHAR * _aptsFullNames[FILELISTMAXNAMES];
TCHAR * _aptsDir[FILELISTMAXNAMES];
TCHAR * _aptsFile[FILELISTMAXNAMES];
TCHAR * _aptsExt[FILELISTMAXNAMES];
TCHAR * _aptsDestination[FILELISTMAXNAMES];
DWORD _dwWeight[FILELISTMAXNAMES];
CFileList *_pflNext;
};
inline CFileList::CFileList()
{
_cNames = 0;
for (ULONG i = 0; i < FILELISTMAXNAMES; i++)
{
_aptsFullNames[i] = NULL;
_aptsDir[i] = NULL;
_aptsFile[i] = NULL;
_aptsExt[i] = NULL;
_aptsDestination[i] = NULL;
_dwWeight[i] = 0;
}
_pflNext = NULL;
}
inline CFileList::~CFileList()
{
for (ULONG i = 0; i < FILELISTMAXNAMES; i++)
{
delete _aptsFullNames[i];
delete _aptsDir[i];
delete _aptsFile[i];
delete _aptsExt[i];
delete _aptsDestination[i];
}
}
inline DWORD CFileList::SetName(const TCHAR *tsName,
DWORD *pdwIndex,
BOOL fDeconstruct)
{
CFileList *pfl = this;
ULONG iName = _cNames;
while (iName >= FILELISTMAXNAMES)
{
if (pfl->_pflNext == NULL)
{
pfl->_pflNext = new CFileList;
if (pfl->_pflNext == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
}
pfl = pfl->_pflNext;
iName -= FILELISTMAXNAMES;
}
pfl->_aptsFullNames[iName] = new TCHAR[_tcslen(tsName) + 1];
if (pfl->_aptsFullNames[iName] == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
_tcscpy(pfl->_aptsFullNames[iName], tsName);
if (fDeconstruct)
{
TCHAR tsDir[MAX_PATH + 1];
TCHAR tsFile[MAX_PATH + 1];
TCHAR tsExt[MAX_PATH + 1];
DeconstructFilename(tsName,
tsDir,
tsFile,
tsExt);
pfl->_aptsDir[iName] = new TCHAR[_tcslen(tsDir) + 1];
if (pfl->_aptsDir[iName] == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
_tcscpy(pfl->_aptsDir[iName], tsDir);
pfl->_aptsFile[iName] = new TCHAR[_tcslen(tsFile) + 1];
if (pfl->_aptsDir[iName] == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
_tcscpy(pfl->_aptsFile[iName], tsFile);
pfl->_aptsExt[iName] = new TCHAR[_tcslen(tsExt) + 1];
if (pfl->_aptsExt[iName] == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
_tcscpy(pfl->_aptsExt[iName], tsExt);
_dwWeight[iName] = ComputeFitIndex(tsDir,
tsFile,
tsExt);
}
if (pdwIndex)
*pdwIndex = _cNames;
_cNames++;
return 0;
}
inline DWORD CFileList::SetDestination(const TCHAR *tsName, DWORD dwIndex)
{
CFileList *pfl = this;
while (dwIndex >= FILELISTMAXNAMES)
{
pfl = pfl->_pflNext;
dwIndex -= FILELISTMAXNAMES;
}
if (pfl->_aptsDestination[dwIndex] != NULL)
{
//Free old memory
delete pfl->_aptsDestination[dwIndex];
pfl->_aptsDestination[dwIndex] = NULL;
}
pfl->_aptsDestination[dwIndex] = new TCHAR[_tcslen(tsName) + 1];
if (pfl->_aptsDestination[dwIndex] == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
_tcscpy(pfl->_aptsDestination[dwIndex], tsName);
return 0;
}
inline const TCHAR * CFileList::GetDestination(ULONG i) const
{
const CFileList *pfl = this;
while (i >= FILELISTMAXNAMES)
{
DEBUG_ASSERT((i >= FILELISTMAXNAMES) && (pfl->_pflNext != NULL));
pfl = pfl->_pflNext;
i -= FILELISTMAXNAMES;
}
return pfl->_aptsDestination[i];
}
inline ULONG CFileList::GetNameCount(void) const
{
return _cNames;
}
inline const TCHAR * CFileList::GetFullName(ULONG i) const
{
const CFileList *pfl = this;
while (i >= FILELISTMAXNAMES)
{
DEBUG_ASSERT((i >= FILELISTMAXNAMES) && (pfl->_pflNext != NULL));
pfl = pfl->_pflNext;
i -= FILELISTMAXNAMES;
}
return pfl->_aptsFullNames[i];
}
inline const TCHAR * CFileList::GetFileName(ULONG i) const
{
const CFileList *pfl = this;
while (i >= FILELISTMAXNAMES)
{
DEBUG_ASSERT((i >= FILELISTMAXNAMES) && (pfl->_pflNext != NULL));
pfl = pfl->_pflNext;
i -= FILELISTMAXNAMES;
}
return pfl->_aptsFile[i];
}
inline const TCHAR * CFileList::GetDirName(ULONG i) const
{
const CFileList *pfl = this;
while (i >= FILELISTMAXNAMES)
{
DEBUG_ASSERT((i >= FILELISTMAXNAMES) && (pfl->_pflNext != NULL));
pfl = pfl->_pflNext;
i -= FILELISTMAXNAMES;
}
return pfl->_aptsDir[i];
}
inline const TCHAR * CFileList::GetExtName(ULONG i) const
{
const CFileList *pfl = this;
while (i >= FILELISTMAXNAMES)
{
DEBUG_ASSERT((i >= FILELISTMAXNAMES) && (pfl->_pflNext != NULL));
pfl = pfl->_pflNext;
i -= FILELISTMAXNAMES;
}
return pfl->_aptsExt[i];
}
inline const DWORD CFileList::GetWeight(ULONG i) const
{
const CFileList *pfl = this;
while (i >= FILELISTMAXNAMES)
{
DEBUG_ASSERT((i >= FILELISTMAXNAMES) && (pfl->_pflNext != NULL));
pfl = pfl->_pflNext;
i -= FILELISTMAXNAMES;
}
return pfl->_dwWeight[i];
}
inline CFileList * CFileList::GetNextFileList(void) const
{
return _pflNext;
}
inline void FreeFileList(CFileList *pfl)
{
CFileList *pflNext;
while (pfl != NULL)
{
pflNext = pfl->GetNextFileList();
delete pfl;
pfl = pflNext;
}
}
const DWORD MAX_WEIGHT = 0xFFFFFFFF;
class CRuleList
{
public:
inline CRuleList();
inline ~CRuleList();
inline DWORD SetName(const TCHAR * ptsName, CRuleList **pprl);
inline DWORD SetDestination(const TCHAR *tsName);
inline const TCHAR *GetDestination() const;
inline const TCHAR * GetFullName() const;
inline const TCHAR * GetDirName() const;
inline const TCHAR * GetFileName() const;
inline const TCHAR * GetExtName() const;
inline const DWORD GetWeight() const;
inline CRuleList * GetNextRule(void) const;
inline void SetNextRule(CRuleList *prl);
inline BOOL MatchAgainstRuleList(const TCHAR *ptsRoot,
const TCHAR *ptsName,
CRuleList **pprlMatch,
DWORD *pdwMatchFit) const;
private:
TCHAR * _ptsFullName;
TCHAR * _ptsDir;
TCHAR * _ptsFile;
TCHAR * _ptsExt;
TCHAR * _ptsDestination;
DWORD _dwWeight;
CRuleList *_prlNext;
};
inline CRuleList::CRuleList()
{
_ptsFullName = NULL;
_ptsDir = NULL;
_ptsFile = NULL;
_ptsExt = NULL;
_ptsDestination = NULL;
_dwWeight = MAX_WEIGHT;
_prlNext = NULL;
}
inline CRuleList::~CRuleList()
{
if (_dwWeight == MAX_WEIGHT)
{
CRuleList *prl = _prlNext;
while (prl)
{
CRuleList * prlNext = prl->GetNextRule();
delete prl;
prl = prlNext;
}
}
delete _ptsFullName;
delete _ptsDir;
delete _ptsFile;
delete _ptsExt;
delete _ptsDestination;
}
inline DWORD CRuleList::SetName(const TCHAR *ptsName, CRuleList **pprl)
{
TCHAR tsDir[MAX_PATH + 1];
TCHAR tsFile[MAX_PATH + 1];
TCHAR tsExt[MAX_PATH + 1];
DWORD dwWeight;
//This should only be called on the root node
DEBUG_ASSERT(_dwWeight == MAX_WEIGHT);
DeconstructFilename(ptsName,
tsDir,
tsFile,
tsExt);
dwWeight = ComputeFitIndex(tsDir,
tsFile,
tsExt);
//The weight can't be max weight or we'll get confused with the root node.
DEBUG_ASSERT(dwWeight != MAX_WEIGHT);
CRuleList *prl = new CRuleList;
if (prl == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
prl->_ptsFullName = new TCHAR[_tcslen(ptsName) + 1];
if (prl->_ptsFullName == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
_tcscpy(prl->_ptsFullName, ptsName);
prl->_ptsDir = new TCHAR[_tcslen(tsDir) + 1];
if (prl->_ptsDir == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
_tcscpy(prl->_ptsDir, tsDir);
prl->_ptsFile = new TCHAR[_tcslen(tsFile) + 1];
if (prl->_ptsDir == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
_tcscpy(prl->_ptsFile, tsFile);
prl->_ptsExt = new TCHAR[_tcslen(tsExt) + 1];
if (prl->_ptsExt == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
_tcscpy(prl->_ptsExt, tsExt);
prl->_dwWeight = dwWeight;
//Now place it in the appropriate place in the rules list.
CRuleList *prlPrev = NULL;
CRuleList *prlCurrent = this;
while ((prlCurrent != NULL) && (prlCurrent->GetWeight() > dwWeight))
{
prlPrev = prlCurrent;
prlCurrent = prlCurrent->GetNextRule();
}
//Insert
//prlPrev can't be NULL, since the root node is always max weight
DEBUG_ASSERT(prlPrev != NULL);
prl->SetNextRule(prlCurrent);
prlPrev->SetNextRule(prl);
if (pprl)
*pprl = prl;
return ERROR_SUCCESS;
}
inline DWORD CRuleList::SetDestination(const TCHAR *tsName)
{
_ptsDestination = new TCHAR[_tcslen(tsName) + 1];
if (_ptsDestination == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
_tcscpy(_ptsDestination, tsName);
return 0;
}
inline const TCHAR * CRuleList::GetDestination() const
{
return _ptsDestination;
}
inline const TCHAR * CRuleList::GetFullName() const
{
return _ptsFullName;
}
inline const TCHAR * CRuleList::GetFileName() const
{
return _ptsFile;
}
inline const TCHAR * CRuleList::GetDirName() const
{
return _ptsDir;
}
inline const TCHAR * CRuleList::GetExtName() const
{
return _ptsExt;
}
inline const DWORD CRuleList::GetWeight() const
{
return _dwWeight;
}
inline CRuleList * CRuleList::GetNextRule(void) const
{
return _prlNext;
}
inline void CRuleList::SetNextRule(CRuleList *prl)
{
_prlNext = prl;
}
inline DWORD ComputeFitIndex(const TCHAR *ptsDir,
const TCHAR *ptsFile,
const TCHAR *ptsExt)
{
DWORD dwFit = 1;
TCHAR tsFilePath[MAX_PATH];
TCHAR tsFileName[MAX_PATH];
TCHAR tsFileExt[MAX_PATH];
TCHAR *ptsEnd;
// Special cast for directories to calculate the correct value
// This is pretty much a hack. The code should be smarter
// before getting here. The problem starts in AddInfSectionToRuleList()
// where a blackslash is appended for directories.
ptsEnd = (TCHAR *) &(ptsDir[_tcslen(ptsDir) - 1]);
if( (*ptsEnd == TEXT('\\') && !(*ptsFile) && !(*ptsExt)) &&
( ((ptsEnd - 1) >= ptsDir) && (*(ptsEnd-1) != TEXT(':')) )
)
{
*ptsEnd = TEXT('\0');
DeconstructFilename(ptsDir, tsFilePath, tsFileName, tsFileExt);
*ptsEnd = TEXT('\\');
ptsDir = tsFilePath;
ptsFile = tsFileName;
ptsExt = tsFileExt;
}
//A thousand points for each backslash before the first wildcard
while (*ptsDir != 0)
{
if (*ptsDir == TEXT('\\'))
dwFit+= 1000;
else if ((TEXT('*') == *ptsDir) ||
(TEXT('?') == *ptsDir))
{
break;
}
ptsDir++;
}
//One point for each non wildcard in name portion
while (*ptsFile != 0)
{
if ((TEXT('*') != *ptsFile) &&
(TEXT('?') != *ptsFile))
{
dwFit+= 1;
}
ptsFile++;
}
//One point for each non wildcard in extension
while (*ptsExt != 0)
{
if ((TEXT('*') != *ptsExt) &&
(TEXT('?') != *ptsExt))
{
dwFit+= 1;
}
ptsExt++;
}
return dwFit;
}
inline BOOL CRuleList::MatchAgainstRuleList(const TCHAR *ptsRoot,
const TCHAR *ptsName,
CRuleList **pprlMatch,
DWORD *pdwMatchFit) const
{
CRuleList *prl = GetNextRule();
//Should only be called on root node.
DEBUG_ASSERT(_dwWeight == MAX_WEIGHT);
while (prl != NULL)
{
if (IsPatternMatch(prl->GetDirName(),
prl->GetFileName(),
prl->GetExtName(),
ptsRoot,
ptsName))
{
if (pprlMatch)
*pprlMatch = prl;
if (pdwMatchFit)
*pdwMatchFit = prl->GetWeight();
return TRUE;
}
prl = prl->GetNextRule();
}
return FALSE;
}
class CSysFile
{
public:
inline CSysFile();
inline ~CSysFile();
inline DWORD SetName(const TCHAR *ptsName);
inline const TCHAR * GetName(void) const;
inline void SetNext(CSysFile *psfNext);
inline CSysFile * GetNext(void) const;
private:
TCHAR *_ptsName;
CSysFile *_psfNext;
};
inline CSysFile::CSysFile()
{
_ptsName = NULL;
_psfNext = NULL;
}
inline CSysFile::~CSysFile()
{
delete _ptsName;
}
inline DWORD CSysFile::SetName(const TCHAR *ptsName)
{
_ptsName = new TCHAR[_tcslen(ptsName) + 1];
if (_ptsName == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
_tcscpy(_ptsName, ptsName);
return ERROR_SUCCESS;
}
inline const TCHAR * CSysFile::GetName(void) const
{
return _ptsName;
}
inline void CSysFile::SetNext(CSysFile *psfNext)
{
_psfNext = psfNext;
}
inline CSysFile * CSysFile::GetNext(void) const
{
return _psfNext;
}
const DWORD SYSFILE_BUCKETS = 100;
class CSysFileList
{
public:
inline CSysFileList();
inline ~CSysFileList();
inline void SetInitialSize(DWORD dwSize);
inline DWORD AddName(const TCHAR * ptsName);
inline DWORD RemoveName(const TCHAR *ptsName);
inline BOOL LookupName(const TCHAR *ptsName) const;
private:
static inline DWORD ShiftXOR(DWORD x, DWORD c)
{
if (x & 0x80000000)
return (x << 1) ^ c | 1;
else
return (x << 1) ^ c;
}
inline DWORD ComputeHash(const TCHAR *ptsName, DWORD dwBuckets) const;
CSysFile ** _papsfFiles;
DWORD *_padwEntries;
DWORD _dwTotalEntries;
DWORD _dwBuckets;
DWORD _dwInitialSize;
};
inline CSysFileList::CSysFileList()
{
_papsfFiles = NULL;
_padwEntries = NULL;
_dwTotalEntries = 0;
_dwBuckets = 0;
_dwInitialSize = SYSFILE_BUCKETS;
}
inline CSysFileList::~CSysFileList()
{
for (ULONG i = 0; i < _dwBuckets; i++)
{
CSysFile *psf = _papsfFiles[i];
while (psf != NULL)
{
CSysFile *psfNext = psf->GetNext();
delete psf;
psf = psfNext;
}
}
delete _papsfFiles;
delete _padwEntries;
}
inline void CSysFileList::SetInitialSize(DWORD dwSize)
{
_dwInitialSize = dwSize;
}
inline DWORD CSysFileList::AddName(const TCHAR *ptsFullName)
{
DWORD dwErr;
DWORD dwIndex;
const TCHAR * ptsName = _tcsrchr(ptsFullName, TEXT('\\'));
if (ptsName == NULL)
ptsName = ptsFullName;
if (_dwTotalEntries == _dwBuckets)
{
//Rehash
DWORD dwNewSize = (_dwBuckets == 0) ? _dwInitialSize : _dwBuckets * 2;
CSysFile **papsfNew = new CSysFile * [dwNewSize];
if (papsfNew == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
DWORD *padwNew = new DWORD[dwNewSize];
if (padwNew == NULL)
{
delete papsfNew;
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
for (ULONG i = 0; i < dwNewSize; i++)
{
papsfNew[i] = NULL;
padwNew[i] = 0;
}
//Since we got the information about the number of items
//and set it up front, we never need to execute this code,
//but I'm not deleting it just in case we need it later.
#if 0
for (i = 0; i < _dwBuckets; i++)
{
CSysFile *psf = _papsfFiles[i];
while (psf != NULL)
{
const TCHAR *pts = psf->GetName();
_papsfFiles[i] = psf->GetNext();
//Rehash
DWORD dwIndex = ComputeHash(pts, dwNewSize);
CSysFile *psfNew = papsfNew[dwIndex];
CSysFile *psfPrev = NULL;
while ((psfNew != NULL) &&
(_tcsicmp(pts, psfNew->GetName()) > 0))
{
psfPrev = psfNew;
psfNew = psfNew->GetNext();
}
if (psfPrev == NULL)
{
psf->SetNext(papsfNew[dwIndex]);
papsfNew[dwIndex] = psf;
}
else
{
psf->SetNext(psfPrev->GetNext());
psfPrev->SetNext(psf);
}
padwNew[dwIndex]++;
psf = _papsfFiles[i];
}
}
delete _papsfFiles;
delete _padwEntries;
#endif
_papsfFiles = papsfNew;
_padwEntries = padwNew;
_dwBuckets = dwNewSize;
}
dwIndex = ComputeHash(ptsName, _dwBuckets);
//Insert sorted into list
CSysFile *psfPrev = NULL;
CSysFile *psf = _papsfFiles[dwIndex];
while ((psf != NULL) && (_tcsicmp(ptsName, psf->GetName()) > 0))
{
psfPrev = psf;
psf = psf->GetNext();
}
CSysFile *psfNew;
psfNew = new CSysFile;
if (psfNew == NULL)
{
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY);
return ERROR_OUTOFMEMORY;
}
dwErr = psfNew->SetName(ptsName);
if (dwErr != ERROR_SUCCESS)
{
delete psfNew;
return dwErr;
}
if (psfPrev == NULL)
{
psfNew->SetNext(_papsfFiles[dwIndex]);
_papsfFiles[dwIndex] = psfNew;
}
else
{
psfNew->SetNext(psfPrev->GetNext());
psfPrev->SetNext(psfNew);
}
_padwEntries[dwIndex]++;
_dwTotalEntries++;
return ERROR_SUCCESS;
}
inline DWORD CSysFileList::RemoveName(const TCHAR *ptsFullName)
{
const TCHAR *ptsName = _tcsrchr(ptsFullName, TEXT('\\'));
if (ptsName == NULL)
ptsName = ptsFullName;
DWORD dwIndex;
if ( _dwBuckets == 0 )
return ERROR_FILE_NOT_FOUND;
dwIndex = ComputeHash(ptsName, _dwBuckets);
CSysFile *psfPrev = NULL;
CSysFile *psf = _papsfFiles[dwIndex];
int i;
while ((psf != NULL) && ((i = _tcsicmp(ptsName, psf->GetName())) > 0))
{
psfPrev = psf;
psf = psf->GetNext();
}
if (psf && (i == 0))
{
//Found it, delete it
if (psfPrev == NULL)
{
_papsfFiles[dwIndex] = psf->GetNext();
}
else
{
psfPrev->SetNext(psf->GetNext());
}
delete psf;
}
else
{
return ERROR_FILE_NOT_FOUND;
}
return ERROR_SUCCESS;
}
inline BOOL CSysFileList::LookupName(const TCHAR *ptsFullName) const
{
DWORD dwIndex;
if (0 == _dwBuckets)
return FALSE;
const TCHAR * ptsName = _tcsrchr(ptsFullName, TEXT('\\'));
if (ptsName == NULL)
ptsName = ptsFullName;
dwIndex = ComputeHash(ptsName, _dwBuckets);
CSysFile *psf = _papsfFiles[dwIndex];
while (psf != NULL)
{
int i = _tcsicmp(ptsName, psf->GetName());
if (i == 0)
{
return TRUE;
}
if (i < 0)
{
return FALSE;
}
psf = psf->GetNext();
}
return FALSE;
}
inline DWORD CSysFileList::ComputeHash(const TCHAR *ptsName,
DWORD dwBuckets) const
{
DWORD x = 0;
while (*ptsName != NULL)
{
x = ShiftXOR(x, _totupper(*ptsName));
ptsName++;
}
return (x % dwBuckets);
}
#endif // #ifndef __FILELIST_HXX__