2025-11-27 16:46:48 +09:00

499 lines
14 KiB
C++

// ==========================================================================
// Class Implementation : COXIteratorUNC
// ==========================================================================
// Source file : OXIteratorUNC.cpp
// Version: 9.3
// This software along with its related components, documentation and files ("The Libraries")
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office. For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
// //////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "OXIteratorUNC.h"
#include "OXUNCStandardActor.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// Definition of static members
// Data members -------------------------------------------------------------
// protected:
// struct COXSearchData
// {
// COXUNC m_searchUNC;
// --- The directory (and file spec) from which the search is tarted
// HANDLE m_hFindFile;
// --- The hadnle used during file search
// WIN32_FIND_DATA m_findFileData;
// --- The last find result
// };
// CList<COXSearchData*, COXSearchData*> m_dirSearchStack;
// --- List of search data while recursively searching subdirectories
// this is only used to get the subdiretories themselves (not their contents)
// COXSearchData m_fileSearch;
// --- The search data used to iterate files in the current directory (m_searchUNC)
// BOOL m_bIncludeFiles;
// --- Whether to include files (non-directories) in the result
// BOOL m_bIncludeDirs;
// --- Whether to include directories in the result
// BOOL m_bRecursive;
// --- Whether to serach directories recursively
// BOOL m_bDepthFirst;
// --- Whether the directory are traversed in depth first (TRUE) or breadth first
// order. This is only important during recursive searching.
// private:
// Member functions ---------------------------------------------------------
// public:
COXIteratorUNC::COXIteratorUNC(LPCTSTR pszUNC /* = NULL */, BOOL bURLPart /* = FALSE */)
:
COXUNC(pszUNC, bURLPart),
m_bIncludeFiles(FALSE),
m_bIncludeDirs(FALSE),
m_bRecursive(FALSE),
m_bDepthFirst(FALSE)
{
}
COXIteratorUNC::COXIteratorUNC(LPCTSTR pszServer, LPCTSTR pszShare, LPCTSTR pszDirectory,
LPCTSTR pszFile, BOOL bURLPart /* = FALSE */)
:
COXUNC(pszServer, pszShare, pszDirectory, pszFile, bURLPart),
m_bIncludeFiles(FALSE),
m_bIncludeDirs(FALSE),
m_bRecursive(FALSE),
m_bDepthFirst(FALSE)
{
}
COXIteratorUNC::COXIteratorUNC(const COXUNC& UNC)
:
COXUNC(UNC),
m_bIncludeFiles(FALSE),
m_bIncludeDirs(FALSE),
m_bRecursive(FALSE),
m_bDepthFirst(FALSE)
{
// Do not copy search specific data, because find handles cannot be copied
}
COXIteratorUNC::COXIteratorUNC(const COXIteratorUNC& iterUNC)
:
COXUNC(iterUNC),
m_bIncludeFiles(FALSE),
m_bIncludeDirs(FALSE),
m_bRecursive(FALSE),
m_bDepthFirst(FALSE)
{
// Do not copy search specific data, because find handles cannot be copied
// TRACE0("COXIteratorUNC::COXIteratorUNC : Warning search specific data is not copied.\n");
}
BOOL COXIteratorUNC::Start(BOOL bIncludeFiles /* = TRUE */, BOOL bIncludeDirs /* = FALSE */,
BOOL bRecursive /* = FALSE */, BOOL bDepthFirst /* = FALSE */)
{
// Store required attributes
m_bIncludeFiles = bIncludeFiles;
m_bIncludeDirs = bIncludeDirs;
m_bRecursive = bRecursive;
m_bDepthFirst = bDepthFirst;
// If an iteration is still running, end it
End();
// Start search with this UNC
ASSERT(m_dirSearchStack.IsEmpty());
ASSERT(m_fileSearch.m_hFindFile == NULL);
m_fileSearch.m_searchUNC = *this;
// If we want a recursive directory search with depth first:
// start from on the deepest dir level
if (m_bRecursive && m_bDepthFirst)
{
COXSearchData* pDirSearchData = new COXSearchData;
pDirSearchData->m_searchUNC = m_fileSearch.m_searchUNC;
pDirSearchData->m_searchUNC.File() = _T("*.*");
m_dirSearchStack.AddHead(pDirSearchData);
CString sDir = GetNextSearchDirectory();
if (!sDir.IsEmpty())
{
m_fileSearch.m_searchUNC.Directory() = sDir;
}
}
// ... Get the first one
return Next();
}
BOOL COXIteratorUNC::Next()
{
// Get next find
ASSERT_VALID(m_pActor);
BOOL bKeepSearching = TRUE;
while(bKeepSearching)
{
// Start or continue searching for the right file
if (m_fileSearch.m_hFindFile == NULL)
m_nLastError = m_pActor->FindFirstFile(m_fileSearch.m_searchUNC, m_fileSearch.m_hFindFile,
m_fileSearch.m_findFileData);
else
m_nLastError = m_pActor->FindNextFile(m_fileSearch.m_hFindFile, m_fileSearch.m_findFileData);
if (SUCCEEDED(m_nLastError))
{
if (IsAcceptableFile())
{
// ... Use FileForm so that we can always overwrite tle last part of the UNC
// even if it is part of a directory
// e.g. When we find Test when we are looking for C:\Test\ .
// This will be handled as C:\Test\ -> C:\Test -> C:\ ,
// then C:\ + Test\ = C:\Test\ .
COXUNC::operator=(m_fileSearch.m_searchUNC.FileForm());
if ((m_fileSearch.m_findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
File() = m_fileSearch.m_findFileData.cFileName;
else
{
Directory() += CString(m_fileSearch.m_findFileData.cFileName) + PreferedSlash();
File().Empty();
}
bKeepSearching = FALSE;
}
}
else
{
if (m_bRecursive)
{
// Get one level down the directory hierarchy
CString sDir = GetNextSearchDirectory();
if (!sDir.IsEmpty())
{
EndFileSearch();
m_fileSearch.m_searchUNC.Directory() = sDir;
}
else
{
// ... End of recursive search
Empty();
bKeepSearching = FALSE;
}
}
else
{
// ... Last file in specified dir and not searching recursively
Empty();
bKeepSearching = FALSE;
}
}
} // while
return (SUCCEEDED(m_nLastError));
}
BOOL COXIteratorUNC::End()
{
// ... Assume success
m_nLastError = ERROR_SUCCESS;
// End a possible ongoing file search and all recursive searches
// (will set m_nLastError)
EndFileSearch();
EndAllDirectorySearches();
return (SUCCEEDED(m_nLastError));
}
COXIteratorUNC& COXIteratorUNC::operator++()
// Prefix increment operator.
{
Next();
return *this;
}
COXIteratorUNC COXIteratorUNC::operator++(int)
// Postfix increment operator.
{
COXIteratorUNC tempIteratorUNC = *this;
Next();
return tempIteratorUNC;
}
#ifdef _DEBUG
#endif //_DEBUG
COXIteratorUNC::~COXIteratorUNC()
{
// ... End a psssible ongoing search
End();
ASSERT(m_dirSearchStack.IsEmpty());
}
// protected:
CString COXIteratorUNC::GetNextSearchDirectory()
// --- In :
// --- Out :
// --- Returns : The new directory specification (absolute but with drive or share spec)
// --- Effect : Gets the next directory in the recursive search
// Directories are searched depth first
{
// ... This function should only be called during recursive search
ASSERT(m_bRecursive);
if (m_dirSearchStack.IsEmpty())
{
if (m_bDepthFirst)
{
// We have been searching depth first and we are now back at the top level
// this concludes aour recursive search
return _T("");
}
else
{
// We are not searching depth first, so when the search stack is empty
// we will push the starting directory (file search UNC) on the stack
COXSearchData* pDirSearchData = new COXSearchData;
pDirSearchData->m_searchUNC = m_fileSearch.m_searchUNC;
pDirSearchData->m_searchUNC.File() = _T("*.*");
m_dirSearchStack.AddHead(pDirSearchData);
}
}
ASSERT(!m_dirSearchStack.IsEmpty());
// ... Top of the stack is the directory we are searching now
COXSearchData* pDirSearchData = m_dirSearchStack.GetHead();
CString sDirectory;
BOOL bKeepSearching = TRUE;
while(bKeepSearching)
{
// Start or continue searching for the subdirectory
if (pDirSearchData->m_hFindFile == NULL)
m_nLastError = m_pActor->FindFirstFile(pDirSearchData->m_searchUNC, pDirSearchData->m_hFindFile,
pDirSearchData->m_findFileData, TRUE);
else
m_nLastError = m_pActor->FindNextFile(pDirSearchData->m_hFindFile, pDirSearchData->m_findFileData);
if (SUCCEEDED(m_nLastError))
{
if (IsAcceptableDirectory())
{
COXSearchData* pNewDirSearchData = new COXSearchData;
pNewDirSearchData->m_searchUNC = pDirSearchData->m_searchUNC;
pNewDirSearchData->m_searchUNC.Directory() += CString(pDirSearchData->m_findFileData.cFileName) + PreferedSlash();
ASSERT(pNewDirSearchData->m_searchUNC.File() == _T("*.*"));
m_dirSearchStack.AddHead(pNewDirSearchData);
// ... Found a good directory
pDirSearchData = pNewDirSearchData;
// ... Keep searching when we are traversing depth first,
// otherwise stop looking
if (!m_bDepthFirst)
{
sDirectory = pDirSearchData->m_searchUNC.Directory();
bKeepSearching = FALSE;
}
}
}
else
{
if (!m_bDepthFirst)
// ... No more directories found, get the next one one level up
// ... Pop the current dir from the stack
EndLastDirectorySearch();
if (!m_dirSearchStack.IsEmpty())
{
if (m_bDepthFirst)
{
// .. Use the current top of the stackl before popping it
// and return this as result
ASSERT(pDirSearchData == m_dirSearchStack.GetHead());
sDirectory = pDirSearchData->m_searchUNC.Directory();
bKeepSearching = FALSE;
}
else
// .. Get the search which is now the new top of the stack
// and continue searching there
pDirSearchData = m_dirSearchStack.GetHead();
}
else
{
// ... End of recursive search
sDirectory.Empty();
bKeepSearching = FALSE;
}
if (m_bDepthFirst)
// ... Pop the current dir from the stack after we have used it
EndLastDirectorySearch();
}
}
return sDirectory;
}
BOOL COXIteratorUNC::IsAcceptableFile() const
// --- In :
// --- Out :
// --- Returns : Whether the file is acceptable
// --- Effect : Checks whether the current file specification
// is something we are interested in
{
// We accept everything, except those we explicitely reject
BOOL bAccept = TRUE;
// ... Reject names "." and ".."
if ( ( m_fileSearch.m_findFileData.cFileName[0] == _T('.') ) &&
( m_fileSearch.m_findFileData.cFileName[1] == _T('\0') ||
(m_fileSearch.m_findFileData.cFileName[1] == _T('.') &&
m_fileSearch.m_findFileData.cFileName[2] == _T('\0') ) ) )
bAccept = FALSE;
// ... Reject files if not wanted
if (!m_bIncludeFiles &&
((m_fileSearch.m_findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) )
bAccept = FALSE;
// ... Reject directories if not wanted
if (!m_bIncludeDirs &&
((m_fileSearch.m_findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) )
bAccept = FALSE;
return bAccept;
}
BOOL COXIteratorUNC::IsAcceptableDirectory() const
// --- In :
// --- Out :
// --- Returns : Whether the dir is acceptable
// --- Effect : Checks whether the last directory specification (top of the stack)
// is something we are interested in
{
// We accept all directories except those we explicitely reject (. and ..)
BOOL bAccept = m_bRecursive;
if (!bAccept)
return bAccept;
// ... Start should have added an item to the top of the list
ASSERT(!m_dirSearchStack.IsEmpty());
COXSearchData* pDirSearchData = m_dirSearchStack.GetHead();
// ... Reject names "." and ".."
if ( ( pDirSearchData->m_findFileData.cFileName[0] == _T('.') ) &&
( pDirSearchData->m_findFileData.cFileName[1] == _T('\0') ||
(pDirSearchData->m_findFileData.cFileName[1] == _T('.') &&
pDirSearchData->m_findFileData.cFileName[2] == _T('\0') ) ) )
bAccept = FALSE;
// ... Reject files
if ((pDirSearchData->m_findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
bAccept = FALSE;
return bAccept;
}
BOOL COXIteratorUNC::EndFileSearch()
// --- In :
// --- Out :
// --- Returns : Whether it succeeded (will set last error upon failure)
// --- Effect : Ends a possible ongoing file search
{
HRESULT nLastError = ERROR_SUCCESS;
if (m_fileSearch.m_hFindFile != NULL)
{
ASSERT_VALID(m_pActor);
nLastError = m_pActor->FindClose(m_fileSearch.m_hFindFile);
if (FAILED(nLastError))
m_nLastError = nLastError;
m_fileSearch.m_hFindFile = NULL;
}
return (SUCCEEDED(m_nLastError));
}
BOOL COXIteratorUNC::EndAllDirectorySearches()
// --- In :
// --- Out :
// --- Returns : Whether it succeeded (will set last error upon failure)
// --- Effect : Ends possible ongoing directory searches
{
// Close directory find(s) if necessary
if (!m_dirSearchStack.IsEmpty())
{
ASSERT_VALID(m_pActor);
POSITION pos;
COXSearchData* pDirSearchData = NULL;
HRESULT nLastError = ERROR_SUCCESS;
pos = m_dirSearchStack.GetHeadPosition();
while (pos != NULL)
{
pDirSearchData = m_dirSearchStack.GetNext(pos);
if (pDirSearchData->m_hFindFile != NULL)
{
nLastError = m_pActor->FindClose(pDirSearchData->m_hFindFile);
if (FAILED(nLastError))
m_nLastError = nLastError;
}
delete pDirSearchData;
}
m_dirSearchStack.RemoveAll();
}
return (SUCCEEDED(m_nLastError));
}
BOOL COXIteratorUNC::EndLastDirectorySearch()
// --- In :
// --- Out :
// --- Returns : Whether it succeeded (will set last error upon failure)
// --- Effect : Ends the last (most recent) directory search
{
// Close directory find(s) if necessary
if (!m_dirSearchStack.IsEmpty())
{
ASSERT_VALID(m_pActor);
POSITION pos;
COXSearchData* pDirSearchData = NULL;
HRESULT nLastError = ERROR_SUCCESS;
pos = m_dirSearchStack.GetHeadPosition();
if (pos != NULL)
{
pDirSearchData = m_dirSearchStack.GetNext(pos);
if (pDirSearchData->m_hFindFile != NULL)
{
nLastError = m_pActor->FindClose(pDirSearchData->m_hFindFile);
if (FAILED(nLastError))
m_nLastError = nLastError;
}
m_dirSearchStack.RemoveHead();
delete pDirSearchData;
}
}
return (SUCCEEDED(m_nLastError));
}
// private:
// ==========================================================================