Click here to Skip to main content
15,886,095 members
Articles / General Programming / Algorithms

Iterative Implementation of Recursively Enumerating Files and Sub Folders

Rate me:
Please Sign up or sign in to vote.
4.64/5 (19 votes)
30 Dec 2010CPOL3 min read 59.4K   3.6K   51  
Yet another implementation to enumerate files
/* 
 * Kenny Liu
 * http://www.codeproject.com/Members/yonken
 *
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 *
 * Permission is hereby granted to use or copy this program
 * for any purpose,  provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 */

#include "StdAfx.h"
#include "ObjInfoHolder.h"

#ifdef THREADED_OBJ_IN_CRT
#include <process.h>    /* _beginthreadex, _endthreadex */
#endif // CREATE_THREAD_CRT

// For StrStrI and StrFormatByteSize
#include <shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")

#define stristr		StrStrI

#include <algorithm>	// for sorting

/*----------------------------------------------------------------------------*/
/* IObserver
/*----------------------------------------------------------------------------*/
IObserver::~IObserver()
{
	LockableObjAccessLock(&m_Lock);
	UnSubscribeAll();
}

void IObserver::Subscribe( ISubject *pSubject, bool bAttachMe /*= true*/ )
{
	LockableObjAccessLock(&m_Lock);
	ASSERT(pSubject);
	ISubjects::iterator iter = m_Subjects.find(pSubject);
	if ( iter == m_Subjects.end() )	// not found
	{
		//TRACE("+++++++++++ Subscribe %x\n", this);
		m_Subjects.insert(pSubject);
		if ( bAttachMe )
			pSubject->Attach(this, false);	// we have subscribed it
	}
}

void IObserver::UnSubscribe( ISubject *pSubject, bool bDetachMe /*= true*/ )
{
	LockableObjAccessLock(&m_Lock);
	ASSERT(pSubject);
	ISubjects::iterator iter = m_Subjects.find(pSubject);
	if ( iter != m_Subjects.end() )	// found
	{
		//TRACE("----------- UnSubscribe %x\n", this);
		m_Subjects.erase(iter);
		if ( bDetachMe )
			pSubject->Detach(this, false);	// we have unsubscribed it
	}
}

void IObserver::UnSubscribeAll()
{
	LockableObjAccessLock(&m_Lock);
	for ( ISubjects::iterator iter = m_Subjects.begin(); iter != m_Subjects.end(); ++iter )
	{
		ASSERT(*iter);
		(*iter)->Detach(this, false);		// we have unsubscribed it
	}
	m_Subjects.clear();
}

/*----------------------------------------------------------------------------*/
/* ISubject
/*----------------------------------------------------------------------------*/
ISubject::ISubject()
	: m_wParam(-1)
	, m_lParam(-1)
{
	
}

ISubject::~ISubject()
{
	LockableObjAccessLock(&m_Lock);
	DttachAll();
}

void ISubject::Attach( IObserver *pObserver, bool bSubscribeMe /*= true*/ )
{
	LockableObjAccessLock(&m_Lock);
	ASSERT(pObserver);
	IObservers::iterator iter = m_Observers.find(pObserver);
	if ( iter == m_Observers.end() )	// not found
	{
		m_Observers.insert(pObserver);
		if ( bSubscribeMe )
			pObserver->Subscribe(this, false);		// we have attached it
	}
}

void ISubject::Detach( IObserver *pObserver, bool bUnSubscribeMe /*= true*/ )
{
	LockableObjAccessLock(&m_Lock);
	ASSERT(pObserver);
	IObservers::iterator iter = m_Observers.find(pObserver);
	if ( iter != m_Observers.end() )	// found
	{
		m_Observers.erase(pObserver);
		if ( bUnSubscribeMe )
			pObserver->UnSubscribe(this, false);	// we have detached it
	}
}

void ISubject::DttachAll()
{
	LockableObjAccessLock(&m_Lock);
	for ( IObservers::iterator iter = m_Observers.begin(); iter != m_Observers.end(); ++iter )
	{
		ASSERT(*iter);
		(*iter)->UnSubscribe(this, false);	// we are going to detach all
	}
	m_Observers.clear();
}

void ISubject::Notify( WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
{
	LockableObjAccessLock(&m_Lock);
	m_wParam = wParam;
	m_lParam = lParam;
	for ( IObservers::iterator iter = m_Observers.begin(); iter != m_Observers.end(); ++iter )
	{
		ASSERT(*iter);
		(*iter)->OnNotify(this, wParam, lParam);
	}
}

/*----------------------------------------------------------------------------*/
/* CLockableObj
/*----------------------------------------------------------------------------*/
ILockableObj::ILockableObj()
{
	InitializeCriticalSection(&m_cs);
}

ILockableObj::~ILockableObj()
{
	DeleteCriticalSection(&m_cs);
}

bool ILockableObj::IsLockable() const
{
	return true;
}

void ILockableObj::Lock()
{
	EnterCriticalSection(&m_cs);
}

void ILockableObj::UnLock()
{
	LeaveCriticalSection(&m_cs);
}

/*----------------------------------------------------------------------------*/
/* CAutoLocker
/*----------------------------------------------------------------------------*/
CAutoLocker::CAutoLocker( ILockableObj* pObj )
{
	if ( pObj && pObj->IsLockable() )
	{
		pObj->Lock();
		m_pObj = pObj;
	}
	else
		m_pObj = NULL;
}

CAutoLocker::~CAutoLocker()
{
	if ( m_pObj )
	{
		m_pObj->UnLock();
	}
}

/*----------------------------------------------------------------------------*/
/* CThreadedObj
/*----------------------------------------------------------------------------*/
CThreadedObj::CThreadedObj()
	: m_hStopEvent(NULL)
	, m_hThread(NULL)
{
	m_hStopEvent	= ::CreateEvent(NULL, TRUE, FALSE, NULL);
#ifdef _DEBUG
	m_dwDebugTimeElapsed	= 0;
	m_dwDebugStartTime		= -1;
#endif // _DEBUG
}

CThreadedObj::~CThreadedObj()
{
	if ( IsRunning() )
	{
		// We have to force the thread to stop now, otherwise it will try to access invalid data.
		VERIFY( ForceStopThread() );
	}
	if ( m_hStopEvent )
	{
		::CloseHandle(m_hStopEvent);
		m_hStopEvent = NULL;
	}
	ASSERT(!m_hThread);
}

bool CThreadedObj::IsRunning() const
{
	//LockableObjAccessLock(this);
	DWORD dwExitCode = 0;
	return m_hThread && GetExitCodeThread(m_hThread, &dwExitCode) && (STILL_ACTIVE == dwExitCode);
}

bool CThreadedObj::IsTaskStopped()
{
	LockableObjAccessLock(this);
	return !IsRunning() || GetLastWParam() == EVENT_ONFINISH || GetLastWParam() == EVENT_ONFORCESTOP;
}

DWORD CThreadedObj::Suspend()
{
	return m_hThread ? SuspendThread(m_hThread) : -1;
}

DWORD CThreadedObj::Resume()
{
	return m_hThread ? ResumeThread(m_hThread) : -1;
}

bool CThreadedObj::RunInThread( PVOID pParam /*= NULL*/, HANDLE hStopEvent /*= NULL*/ )
{
	if ( SetStopEventHandle(hStopEvent) )
	{
		ASSERT( !IsRunning() && NULL == m_hThread);
		m_ThreadProcParam.pThreadedObj		= this;
		m_ThreadProcParam.pThreadParameter	= pParam;
		// create the thread suspended in case it returns before we ever catch the returned handle.
#ifdef THREADED_OBJ_IN_CRT
		m_hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, &m_ThreadProcParam, CREATE_SUSPENDED, NULL);
#else
		m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, &m_ThreadProcParam, CREATE_SUSPENDED, NULL);
#endif // CREATE_THREAD_CRT
		if ( m_hThread )
		{
			Notify(EVENT_PRESTART);
			ResumeThread(m_hThread);
		}
		return m_hThread != NULL;
	}
	return false;
}

bool CThreadedObj::SetStopEventHandle( HANDLE hStopEvent )
{
	//LockableObjAccessLock(this);
	if ( IsRunning() )
	{
		//ASSERT(0);	// a thread may has been started!
		return false;
	}
	if ( hStopEvent )
	{
		if ( m_hStopEvent )
		{
			CloseHandle(m_hStopEvent);
		}
		m_hStopEvent = hStopEvent;
	}
	return true;
}

bool CThreadedObj::SetStopEvent()
{
	LockableObjAccessLock(this);
	if (m_hStopEvent)
	{
		::SetEvent(m_hStopEvent);
	}
	return true;
}

bool CThreadedObj::ForceStopThread( DWORD dwTimeOutMilliseconds /*= INFINITE*/ )
{
	//LockableObjAccessLock(this);
	if ( IsRunning() )
	{
		ASSERT(m_hStopEvent);
		SetStopEvent();
		ASSERT(m_hThread);
		DWORD dwWaitRet = WaitForSingleObject(m_hThread, dwTimeOutMilliseconds);
		if ( WAIT_TIMEOUT == dwWaitRet )
		{
			ASSERT(0);	// this is bad because we have to terminate the thread before it ever has the chance to clean up.
			TerminateThread(m_hThread, 1);
			Notify(EVENT_TERMINATED);
		}
		CloseHandle(m_hThread);
		m_hThread = NULL;
	}
	return true;
}

UINT WINAPI CThreadedObj::ThreadProc( PVOID pThreadProcParam )
{
	PThreadProcParam pProcParam = static_cast<PThreadProcParam>(pThreadProcParam);
	if ( pProcParam && pProcParam->pThreadedObj )
	{
		pProcParam->pThreadedObj->_Run(pProcParam->pThreadParameter);
	}
#ifdef THREADED_OBJ_IN_CRT
	_endthreadex(0);
#endif // CREATE_THREAD_CRT
	return 0;
}

bool CThreadedObj::_Run( PVOID pParam /*= NULL*/ )
{
#ifdef _DEBUG
	UpdateTimeBegin();
#endif // _DEBUG

	Notify(EVENT_ONSTART);

	Lock();
	if ( m_hStopEvent )
	{
		::ResetEvent(m_hStopEvent);
	}
	UnLock();

	bool bRet = Run(pParam);

	if ( IsStopEventSignaled() )
		Notify(EVENT_ONFORCESTOP);
	else
		Notify(EVENT_ONFINISH);

	SetStopEvent();

	Lock();
	if ( m_hThread )
	{
		CloseHandle(m_hThread);
		m_hThread = NULL;
	}
	UnLock();
	return bRet;
}

/*----------------------------------------------------------------------------*/
/* CObjInfoHolder
/*----------------------------------------------------------------------------*/
CObjInfoHolder::CObjInfoHolder()
{
	
}

CObjInfoHolder::~CObjInfoHolder()
{
	
}

BOOL CObjInfoHolder::StopRetrievingObjInfo()
{
	return SetStopEvent();
}

bool CObjInfoHolder::Run( PVOID pParam /*= NULL*/ )
{
	return RetrieveObjInfo() ? true : false;
}

/*----------------------------------------------------------------------------*/
/* CMultiColInfoHolderCObjInfoHolder
/*----------------------------------------------------------------------------*/
CMultiColInfoHolder::CMultiColInfoHolder()
	: m_nSortColumn(INFOCOL_INVALID)
	, m_bSortAscending(DEFAULT_SORT_ASCENDING)
{
}

CMultiColInfoHolder::~CMultiColInfoHolder()
{
}

void CMultiColInfoHolder::SwitchSort( int infoType )
{
	if (IsSortable())
	{
		bool bAscending;
		if ( infoType == m_nSortColumn )
			bAscending = !m_bSortAscending;
		else
			bAscending	= DEFAULT_SORT_ASCENDING;
		Sort(infoType, bAscending);
	}
}

/*----------------------------------------------------------------------------*/
/* CObjInfoMatcher
/*----------------------------------------------------------------------------*/
CObjInfoMatcher::CObjInfoMatcher( CObjInfoHolder* pObjInfoHolder /*= NULL*/ )
	: m_pObjInfoHolder(pObjInfoHolder)
	, m_nMatchObjInfoCount(0)
{
	
}

CObjInfoMatcher::~CObjInfoMatcher()
{
	
}

void CObjInfoMatcher::Reset()
{
	m_nMatchObjInfoCount = 0;
}

BOOL CObjInfoMatcher::RetrieveObjInfo()
{
	Reset();
	if ( m_pObjInfoHolder )
		return m_pObjInfoHolder->RetrieveObjInfo();
	return FALSE;
}

BOOL CObjInfoMatcher::StopRetrievingObjInfo()
{
	if ( m_pObjInfoHolder )
		return m_pObjInfoHolder->StopRetrievingObjInfo();
	return FALSE;
}

bool CObjInfoMatcher::RunInThread( PVOID pParam /*= NULL*/, HANDLE hStopEvent /*= NULL*/ )
{
	Reset();
	if ( m_pObjInfoHolder )
		return m_pObjInfoHolder->RunInThread(pParam, hStopEvent);
	return FALSE;
}

size_t CObjInfoMatcher::GetObjInfoCount() const
{
	if ( m_pObjInfoHolder )
		return m_pObjInfoHolder->GetObjInfoCount();
	return 0;
}

bool CObjInfoMatcher::IsSortable() const
{
	if ( m_pObjInfoHolder )
		return m_pObjInfoHolder->IsSortable();
	return false;
}

/*----------------------------------------------------------------------------*/
/* CMultiPatternMatchHelper
/*----------------------------------------------------------------------------*/
CMultiColInfoMatcher::CMultiColInfoMatcher(CMultiColInfoHolder* pMultiColInfoHolder /*= NULL*/)
	: CObjInfoMatcher(pMultiColInfoHolder)
{
	
}

CMultiColInfoMatcher::~CMultiColInfoMatcher()
{
	
}

BOOL CMultiColInfoMatcher::SetPatterns( LPCTSTR lpcszPatterns )
{
	if ( lpcszPatterns )
	{
		ASSERT(*lpcszPatterns);
		bool bExpectingEndChar	= false;
		PatternInfo patternInfo;
		for (LPCTSTR pPatternBeg = lpcszPatterns; ; ++lpcszPatterns)
		{
			if ( _T(' ') == *lpcszPatterns || _T('\t') == *lpcszPatterns || _T('\0') == *lpcszPatterns )
			{
				if ( bExpectingEndChar )
				{
					if ( lpcszPatterns > pPatternBeg )
					{
						patternInfo.strPattern = pPatternBeg;
						size_t nPatLen = lpcszPatterns-pPatternBeg;
						//patternInfo.strPattern[nPatLen] = _T('\0');
						patternInfo.strPattern.resize(nPatLen);
						OnAddPattern(patternInfo);
					}
					bExpectingEndChar = false;
				}
				if ( _T('\0') == *lpcszPatterns )
					break;
			}
			else
			{
				if ( !bExpectingEndChar )
				{
					patternInfo.bWithMinus		= false;
					patternInfo.bWithBackSlash	= false;
					pPatternBeg = lpcszPatterns;
					bExpectingEndChar = true;
				}
				if ( lpcszPatterns-pPatternBeg <= 1 )
				{
					if ( _T('-') == *lpcszPatterns )
						patternInfo.bWithMinus = true;
					else if ( _T('\\') == *lpcszPatterns )
						patternInfo.bWithBackSlash = true;
					else
						continue;
					++pPatternBeg;
				}
			}
		}
	}
	return TRUE;
}

size_t CMultiColInfoMatcher::GetMatch(LPCTSTR lpcszPatterns /*= NULL*/, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
{
	UINT* pnActiveIndex = (PUINT)wParam;
	UINT nActiveIndex	= pnActiveIndex ? *pnActiveIndex : 0;
	UINT nObjInfoCount	= GetObjInfoCount();
	if ( !lpcszPatterns || !*lpcszPatterns )
	{
		// Empty pattern string means to display everything.
		m_nMatchObjInfoCount = nObjInfoCount;
		if (nActiveIndex < (int)m_matchedObjInfoIndices.size() && nActiveIndex < m_nMatchObjInfoCount)
			nActiveIndex = m_matchedObjInfoIndices[nActiveIndex];
	}
	else
	{
		int nActiveObjIndex = nActiveIndex;
		if ( m_nMatchObjInfoCount < GetObjInfoCount() )
		{
			if (nActiveIndex < (int)m_matchedObjInfoIndices.size() && nActiveIndex < m_nMatchObjInfoCount)
				nActiveObjIndex = m_matchedObjInfoIndices[nActiveIndex];
		}
		nActiveIndex = 0;

		SetPatterns(lpcszPatterns);
		m_nMatchObjInfoCount = 0;
		for (size_t ii = 0; ii < nObjInfoCount; ++ii)
		{
			if ( IsObjInfoMatch(ii) )
			{
				if (m_nMatchObjInfoCount >= (int)m_matchedObjInfoIndices.size())
				{
					m_matchedObjInfoIndices.push_back(ii);
				}
				else
				{
					m_matchedObjInfoIndices[m_nMatchObjInfoCount] = ii;
				}
				if ( ii == nActiveObjIndex )
				{
					nActiveIndex = m_nMatchObjInfoCount;
				}
				++m_nMatchObjInfoCount;
			}
		}
	}
	if ( pnActiveIndex )
		*pnActiveIndex = nActiveIndex;
	//TRACE("------------ match count %d\n", m_nMatchObjInfoCount);
	return m_nMatchObjInfoCount;
}

int CMultiColInfoMatcher::GetObjInfoIndexInMatches( int nItem ) const
{
	if ( m_nMatchObjInfoCount < GetObjInfoCount() 
		&& m_nMatchObjInfoCount > 0 
		&& nItem < (int)m_matchedObjInfoIndices.size()	// We have to check this in case the holder is retrieving info in a thread.
		)
	{
		ASSERT( nItem >= 0 );
		ASSERT((UINT)nItem < m_nMatchObjInfoCount);
		nItem = m_matchedObjInfoIndices[nItem];
	}
	return nItem;
}

LPCTSTR CMultiColInfoMatcher::GetObjInfoTextInMatches( WPARAM wParam, LPARAM lParam )
{
	int& nIndex = (int&)wParam;
	int& nCol = (int&)lParam;
	ASSERT(m_pObjInfoHolder);
	int nObjInfoIndex = GetObjInfoIndexInMatches(nIndex);
	return m_pObjInfoHolder->GetObjInfoText(nObjInfoIndex, nCol);
}

void CMultiColInfoMatcher::Reset()
{
	CObjInfoMatcher::Reset();
	m_matchedObjInfoIndices.clear();
}

bool CMultiColInfoMatcher::HasFilteredObjinfo() const
{
	return !m_matchedObjInfoIndices.empty();
}

/*----------------------------------------------------------------------------*/
/* CFileInfoEnumerator
/*----------------------------------------------------------------------------*/
CFileInfoEnumerator::CFileInfoEnumerator()
{
	
}

CFileInfoEnumerator::~CFileInfoEnumerator()
{
	
}

const CFileInfoEnumerator::FileInfo* CFileInfoEnumerator::GetFileInfo( size_t nIndex )
{
	if ( nIndex < (int)m_arrFileInfo.size() )
	{
		return &m_arrFileInfo.at(nIndex);
	}
	return NULL;
}

void CFileInfoEnumerator::HandleFile( LPCTSTR lpcszPath, const FindFileData& ffd )
{
	FileInfo fileInfo;
	fileInfo.sFileInfo[FIT_FILENAME] = ffd.cFileName;
	
	fileInfo.sFileInfo[FIT_FILEPATH] = lpcszPath;
	
	tstring::size_type nDotPos = fileInfo.sFileInfo[FIT_FILENAME].rfind(_T('.'));
	if ( nDotPos != tstring::npos )
		fileInfo.sFileInfo[FIT_FILEEXT] = fileInfo.sFileInfo[FIT_FILENAME].c_str()+nDotPos+1;
	
	SYSTEMTIME st;

	#define FTIME_BUFFER_SIZE	255
	
	TCHAR szModified[FTIME_BUFFER_SIZE+FTIME_BUFFER_SIZE], szLocalDate[FTIME_BUFFER_SIZE], szLocalTime[FTIME_BUFFER_SIZE];
	FILETIME ft = ffd.ftLastWriteTime;
	
	FileTimeToLocalFileTime( &ft, &ft );
	FileTimeToSystemTime( &ft, &st );
	GetDateFormat( LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, szLocalDate, FTIME_BUFFER_SIZE );
	GetTimeFormat( LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, szLocalTime, FTIME_BUFFER_SIZE );
	
#ifdef MSVC_NEW_VER
	_sntprintf_s(szModified, FTIME_BUFFER_SIZE+FTIME_BUFFER_SIZE, _TRUNCATE, _T("%s %s"), szLocalDate, szLocalTime);
#else
	_sntprintf(szModified, FTIME_BUFFER_SIZE+FTIME_BUFFER_SIZE, _T("%s %s"), szLocalDate, szLocalTime);
#endif // MSVC_NEW_VER

	fileInfo.sFileInfo[FIT_MODIFIED] = szModified;

	DWORDLONG dwHighBase = MAXDWORD;
	++dwHighBase;
	fileInfo.nFileSize = (ffd.nFileSizeHigh * dwHighBase) + ffd.nFileSizeLow;

	#define FILESIZEBUFFER_SIZE		100

	TCHAR szBuffer[FILESIZEBUFFER_SIZE];
#ifdef MSVC_NEW_VER
	StrFormatByteSize64(fileInfo.nFileSize, szBuffer, FILESIZEBUFFER_SIZE);
#else
	StrFormatByteSize(fileInfo.nFileSize, szBuffer, FILESIZEBUFFER_SIZE);
#endif // MSVC_NEW_VER

	fileInfo.sFileInfo[FIT_FILESIZE] = szBuffer;
	
	m_arrFileInfo.push_back(fileInfo);
}

/*----------------------------------------------------------------------------*/
/* class CFileInfoHolderSortHelper
/*----------------------------------------------------------------------------*/
#ifdef USE_STL_SORT
class CFileInfoHolderSortHelper
{
public:
	CFileInfoHolderSortHelper(CFileInfoHolder* pFileInfoHolder)
		: m_pFileInfoHolder(pFileInfoHolder)
	{
	}
public:
	bool operator()( const CFileInfoEnumerator::FileInfo& left, const CFileInfoEnumerator::FileInfo& right ) const
	{
		return m_pFileInfoHolder->IsSortAscending() 
			&& _tcsicmp(left.sFileInfo[m_pFileInfoHolder->GetSortColumn()].c_str(), 
						right.sFileInfo[m_pFileInfoHolder->GetSortColumn()].c_str()) < 0;
	}
protected:
	CFileInfoHolder* m_pFileInfoHolder;
};
#else
	bool CFileInfoHolder::s_bSortAscending	= DEFAULT_SORT_ASCENDING;
	int CFileInfoHolder::s_nSortInfoType	= INFOCOL_INVALID;
#endif // USE_STL_SORT

/*----------------------------------------------------------------------------*/
/* CFileInfoHolder
/*----------------------------------------------------------------------------*/

CFileInfoHolder::CFileInfoHolder( const EnumerateFolderArray* pEnumerateFolders /*= NULL*/ )
	: m_pEnumerateFolders(pEnumerateFolders)
{
	;
}

CFileInfoHolder::~CFileInfoHolder()
{
	
}

LPCTSTR CFileInfoHolder::GetObjInfoText( WPARAM wParam, LPARAM lParam )
{
	int& nIndex = (int&)wParam;
	int& nCol = (int&)lParam;
	ObjInfoHolderAccessLock(this);
#ifdef _DEBUG
	UINT nObjInfoCount = GetObjInfoCount();
#endif // _DEBUG
	ASSERT( 0 <= nIndex && (UINT)nIndex < nObjInfoCount );
	ASSERT( CFileInfoEnumerator::FIT_FIRST <= nCol && nCol < CFileInfoEnumerator::FIT_MAX );
	const CFileInfoEnumerator::FileInfo* pFileInfo = CFileInfoEnumerator::GetFileInfo(nIndex);
	if ( pFileInfo )
		return const_cast<TCHAR*>(pFileInfo->sFileInfo[nCol].c_str());
	return NULL;
}

BOOL CFileInfoHolder::RetrieveObjInfo()
{
	ASSERT(m_pEnumerateFolders);
	m_arrFileInfo.clear();
	BOOL bRet = TRUE;
	for (size_t ii = 0; ii < m_pEnumerateFolders->size(); ++ii)
	{
		const EnumerateFolder& folder = m_pEnumerateFolders->at(ii);
		SetFilterPatterns( folder.strFilterPatterns.c_str() );
		BOOL bOK = Enumerate( folder.strFolder.c_str(), true, m_hStopEvent );
		bRet = bRet && bOK;
	}
	return bRet;
}

void CFileInfoHolder::Sort( int infoType, bool bAscending /*= true*/ )
{
	ObjInfoHolderAccessLock(this);
	if ( m_arrFileInfo.empty() )
		return;
	ASSERT(FIT_FIRST <= infoType && infoType < FIT_MAX);

	Notify(EVENT_SORT_BEGIN);

#ifdef _DEBUG
	UpdateTimeBegin();
#endif // _DEBUG

	if ( infoType == m_nSortColumn && (bAscending ^ m_bSortAscending) )
	{
		std::reverse(m_arrFileInfo.begin(), m_arrFileInfo.end());
		m_bSortAscending = bAscending;
	}
	else
	{
		m_nSortColumn		= infoType;
		m_bSortAscending	= bAscending;
#ifdef USE_STL_SORT
		std::sort( m_arrFileInfo.begin(), m_arrFileInfo.end(), CFileInfoHolderSortHelper(this) );
#else
		s_bSortAscending	= bAscending;
		s_nSortInfoType		= infoType;
		GENERICCOMPAREFN pfnSort	= reinterpret_cast<GENERICCOMPAREFN>(CompareFileInfo);
		qsort(&m_arrFileInfo.front(), m_arrFileInfo.size(), sizeof(FileInfo), pfnSort);
#endif // USE_STL_SORT
	}

	Notify(EVENT_SORT_END);
}

#ifndef USE_STL_SORT
int CFileInfoHolder::CompareFileInfo( const FileInfo* left, const FileInfo* right )
{
	int nRet;
	if ( FIT_FILESIZE == s_nSortInfoType )
	{
		nRet = (int)(left->nFileSize - right->nFileSize);
	}
	else
	{
		nRet = _tcsicmp(left->sFileInfo[s_nSortInfoType].c_str(), right->sFileInfo[s_nSortInfoType].c_str());
	}
	if ( !s_bSortAscending )
		nRet = -nRet;
	return nRet;
}
#endif // USE_STL_SORT

void CFileInfoHolder::HandleFile( LPCTSTR lpcszPath, const FindFileData& ffd )
{
	ObjInfoHolderAccessLock(this);
	CFileInfoEnumerator::HandleFile(lpcszPath, ffd);
#ifdef FILEINFOHOLDER_NOTIFY_NEW_FILE
	Notify(CThreadedObj::EVENT_ONPROCEED);
#endif // FILEINFOHOLDER_NOTIFY_NEW_FILE
}

void CFileInfoHolder::SetEnumerateFolderArray( const EnumerateFolderArray* pEnumerateFolders )
{
	m_pEnumerateFolders = pEnumerateFolders;
}

/*----------------------------------------------------------------------------*/
/* CFileInfoMatcher
/*----------------------------------------------------------------------------*/
CFileInfoMatcher::CFileInfoMatcher()
{
	
}

CFileInfoMatcher::~CFileInfoMatcher()
{
	
}

BOOL CFileInfoMatcher::IsObjInfoMatch( UINT nIndex )
{
	ObjInfoHolderAccessLock(m_pObjInfoHolder);
	CFileInfoHolder* pFileInfoHolder = static_cast<CFileInfoHolder*>(m_pObjInfoHolder);
	ASSERT(pFileInfoHolder);
	const CFileInfoEnumerator::FileInfo* pFileInfo = pFileInfoHolder->GetFileInfo(nIndex);
	ASSERT(pFileInfo);
	LPCTSTR lpcszFileName			= const_cast<TCHAR*>(pFileInfo->sFileInfo[CFileInfoEnumerator::FIT_FILENAME].c_str());
	LPCTSTR lpcszFilePath			= const_cast<TCHAR*>(pFileInfo->sFileInfo[CFileInfoEnumerator::FIT_FILEPATH].c_str());
	const TCHAR* cszColumnText[]	= {lpcszFileName, lpcszFilePath};
	for (FilePatternArray::iterator iter = m_arrFilePatterns.begin(); iter != m_arrFilePatterns.end(); ++iter)
	{
		LPCTSTR lpcszMatchTargetText = cszColumnText[iter->bMatchPath];
		bool bFind	= stristr(lpcszMatchTargetText, iter->strPattern.c_str()) != NULL;
		bool bMatch	= bFind ^ iter->bExclude;
		if ( !bMatch )
			return FALSE;
	}
	return TRUE;
}

BOOL CFileInfoMatcher::SetPatterns( LPCTSTR lpcszPatterns )
{
	m_arrFilePatterns.clear();
	return CMultiColInfoMatcher::SetPatterns(lpcszPatterns);
}

void CFileInfoMatcher::OnAddPattern( const PatternInfo& patternInfo )
{
	m_arrFilePatterns.push_back( FilePattern(patternInfo) );
}

/*----------------------------------------------------------------------------*/
/* CComboFileInfoMatcher
/*----------------------------------------------------------------------------*/
BOOL CComboFileInfoMatcher::IsObjInfoMatch( UINT nIndex )
{
	ObjInfoHolderAccessLock(m_pObjInfoHolder);
	CFileInfoHolder* pFileInfoHolder = static_cast<CFileInfoHolder*>(m_pObjInfoHolder);
	ASSERT(pFileInfoHolder);
	const CFileInfoEnumerator::FileInfo* pFileInfo = pFileInfoHolder->GetFileInfo(nIndex);
	ASSERT(pFileInfo);
	LPCTSTR lpcszFilePath			= const_cast<TCHAR*>(pFileInfo->sFileInfo[CFileInfoEnumerator::FIT_FILEPATH].c_str());
	for (FilePatternArray::iterator iter = m_arrFilePatterns.begin(); iter != m_arrFilePatterns.end(); ++iter)
	{
		bool bFind	= stristr(lpcszFilePath, iter->strPattern.c_str()) != NULL;
		if ( !bFind )
			return FALSE;
	}
	return TRUE;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions