//+--------------------------------------------------------------------------- // // 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__