|
|
//+------------------------------------------------------------------
//
// Copyright (C) 1993, Microsoft Corporation.
//
// File: FileEnum.cxx
//
// Contents: class encapsulating file enumeration, including a deep option
//
// Classes: CFileEnumeration
//
// History: Nov-93 DaveMont Created.
// Feb-98 BrunoSc CFileEnumerate::Init changed to avoid problems with
// files with german Umlaute.
//
//-------------------------------------------------------------------
#include "pch.h"
#include "t2.hxx"
#include "FileEnum.hxx"
#include <locale.h>
#include <wchar.h>
#if DBG
extern ULONG Debug; #endif
//+---------------------------------------------------------------------------
//
// Member: CFileEnumerate::CFileEnumerate, public
//
// Synopsis: initializes data members, constructor will not throw
//
// Arguments: IN [fdeep] - TRUE = go into sub-directories
//
//----------------------------------------------------------------------------
CFileEnumerate::CFileEnumerate(BOOL fdeep) : _fdeep(fdeep), _findeep(FALSE), _froot(FALSE), _fcannotaccess(FALSE), _pcfe(NULL), _pwfileposition(NULL), _handle(INVALID_HANDLE_VALUE) { ENUMERATE_RETURNS((stderr, L"CFileEnumerate ctor\n")) } //+---------------------------------------------------------------------------
//
// Member: Dtor, public
//
// Synopsis: closes handles
//
// Arguments: none
//
//----------------------------------------------------------------------------
CFileEnumerate::~CFileEnumerate() { if (_handle != INVALID_HANDLE_VALUE) FindClose(_handle); ENUMERATE_RETURNS((stderr, L"CFileEnumerate dtor (%ws)\n", _wpath)) } //+---------------------------------------------------------------------------
//
// Member: CFileEnumerate::Init, public
//
// Synopsis: Init must be called before any other methods - this
// is not enforced. converts a ASCII file/path to a UNICODE
// file/path, and gets the first file in the enumeration
//
// Arguments: IN [filename] - the path/file to enumerate
// OUT [wfilename] - first file in the enumeration
// OUT [fdir] - TRUE = returned file is a directory
//
//----------------------------------------------------------------------------
/*
ULONG CFileEnumerate::Init(LPCWSTR filename, LPWSTR *wfilename, BOOL *fdir) { // Initialize the file name
int iError = 0;
if (filename && (wcslen(filename) < MAX_PATH)) { // make it wchar
WCHAR winfilename[MAX_PATH];
iError = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, (LPTSTR) filename, -1, winfilename, wcslen( filename ) * 2 ); if (!iError) { // error has occured during translation
return( iError = GetLastError()); }
_pwfileposition = NULL;
// finish initialization
return(_ialize(winfilename, wfilename, fdir)); } ENUMERATE_FAIL((stderr, "Init bad file name: %ld\n",ERROR_INVALID_NAME)) return(ERROR_INVALID_NAME); } */ //+---------------------------------------------------------------------------
//
// Member: CFileEnumerate::Init, public
//
// Synopsis: Same as previous, except takes UNICODE file/path as input
//
// Arguments: IN [filename] - the path/file to enumerate
// OUT [wfilename] - first file in the enumeration
// OUT [fdir] - TRUE = returned file is a directory
//
//----------------------------------------------------------------------------
ULONG CFileEnumerate::Init(LPCWSTR filename, LPWSTR *wfilename, BOOL *fdir) { // Initialize the file name
if (filename && (wcslen(filename) < MAX_PATH)) { return(_ialize(filename, wfilename, fdir)); } ENUMERATE_FAIL((stderr, L"Init bad file name: %ld\n",ERROR_INVALID_NAME)) return(ERROR_INVALID_NAME); } //+---------------------------------------------------------------------------
//
// Member: CFileEnumerate::_ialize, private
//
// Synopsis: finishes initialization and starts search for first file in
// the enumeration
//
// Arguments: OUT [wfilename] - first file in the enumeration
// OUT [fdir] - TRUE = returned file is a directory
//
//----------------------------------------------------------------------------
ULONG CFileEnumerate::_ialize(LPCWSTR winfilename, LPWSTR *wfilename, BOOL *fdir) { ENUMERATE_RETURNS((stderr, L"Init start, path = %ws\n", winfilename)) ULONG ret = ERROR_SUCCESS;
ENUMERATE_STAT((stderr, L"start path = %ws\n",winfilename))
// save the location of the filename or wildcards
ULONG cwcharcount;
if (!(cwcharcount = GetFullPathName((LPCTSTR)winfilename, MAX_PATH, (LPTSTR)_wpath, (LPTSTR*)&_pwfileposition))) { return(ERROR_INVALID_NAME); }
ENUMERATE_STAT((stderr, L"got full path name = %ws, filename = (%ws), total chars = %d\n",_wpath, _pwfileposition, cwcharcount))
// if the filepart (_pwfileposition) is NULL, then the name must end in a slash.
// add a *
if (NULL == _pwfileposition) { _pwfileposition = (LPWSTR) Add2Ptr(_wpath,wcslen(_wpath)*sizeof(WCHAR)); }
// save the filename/wildcards
wcscpy(_wwildcards, _pwfileposition);
ENUMERATE_EXTRA((stderr, L"wild cards = %ws\n",_wwildcards))
// if we are at a root (path ends in :\)
if ( (_wpath[wcslen(_wpath) - 1] == L'\\') && (wcslen(_wpath) > 1) && (_wpath[wcslen(_wpath) - 2] == L':') ) { _wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; _wfd.cFileName[0] = L'\0'; *wfilename = _wpath; *fdir = TRUE; _froot = TRUE; } else { // check to see if we can iterate through files
if ( (INVALID_HANDLE_VALUE == ( _handle = FindFirstFile((LPCTSTR)_wpath, &_wfd ) ) ) ) { ret = GetLastError(); _fcannotaccess = (ERROR_ACCESS_DENIED == ret); ENUMERATE_FAIL((stderr, L"find first returned: %ld\n",ret)) } if (ERROR_SUCCESS == ret) { // reject . & .. filenames (go on to next file )
if ( (0 == _wcsicmp(_wfd.cFileName, L".")) || (0 == _wcsicmp(_wfd.cFileName, L"..")) ) { ret = _NextLocal(wfilename,fdir); } else { // return the current directory
if (_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) *fdir = TRUE; else *fdir = FALSE; // add the filename to the path so the whole thing is returned
//_pwfileposition is pointer to postion of file in _wpath. _wpath is
//MAX_PATH long. MAX_PATH - (_pwfileposition - _wpath) is the length of
//buffer _pwfileposition
//
HRESULT hr = StringCchCopy((LPWSTR)_pwfileposition,MAX_PATH - (_pwfileposition- _wpath), (LPCWSTR )_wfd.cFileName); if(FAILED(hr)) { return HRESULT_CODE(hr); } *wfilename = _wpath; } }
ENUMERATE_STAT((stderr, L"next filename = %ws\n", *wfilename)) }
// if we are going deep and we did not find a file yet:
if ( _fdeep && ( ( ERROR_NO_MORE_FILES == ret ) || ( ERROR_FILE_NOT_FOUND == ret ) ) ) { if (_handle != INVALID_HANDLE_VALUE) { FindClose(_handle); _handle = INVALID_HANDLE_VALUE; } ret = _InitDir(wfilename, fdir); }
ENUMERATE_RETURNS((stderr, L"Init returning = %ws(%ld)\n\n", *wfilename, ret)) return(ret); } //+---------------------------------------------------------------------------
//
// Member: CFileEnumerate::Next, public
//
// Synopsis: finds the next file in the enumeration
//
// Arguments: OUT [wfilename] - first file in the enumeration
// OUT [fdir] - TRUE = returned file is a directory
//
//----------------------------------------------------------------------------
ULONG CFileEnumerate::Next(LPWSTR *wfilename, BOOL *fdir) { ENUMERATE_RETURNS((stderr, L"Next start, path = %ws\n", _wpath)) ULONG ret = ERROR_NO_MORE_FILES;
// if we failed to initialize with an ERROR_ACCESS_DENIED, then exit
if (_fcannotaccess) return(ERROR_NO_MORE_FILES);
// if we are not in deep
if (!_findeep) { if (!_froot) ret = _NextLocal(wfilename, fdir);
// if we ran out of files and we are going deep:
if ( _fdeep && ( ( ERROR_NO_MORE_FILES == ret ) || ( ERROR_FILE_NOT_FOUND == ret ) || _froot ) ) { if (_handle != INVALID_HANDLE_VALUE) { FindClose(_handle); _handle = INVALID_HANDLE_VALUE; } ret = _InitDir(wfilename, fdir); _froot = FALSE; // (we are past the root now)
}
} else { // if we are already down a directory (and in deep)
if (_pcfe) { if (ERROR_SUCCESS != (ret = _pcfe->Next(wfilename, fdir))) { if (ERROR_ACCESS_DENIED != ret) { delete _pcfe; _pcfe = NULL; } } }
// we need to go to the next directory in the current dir
if (ERROR_NO_MORE_FILES == ret) { ret = _NextDir(wfilename, fdir); } } ENUMERATE_RETURNS((stderr, L"Next returning = %ws(%ld)\n\n", *wfilename, ret)) return(ret); } //+---------------------------------------------------------------------------
//
// Member: CFileEnumerate::_NextLocal, private
//
// Synopsis: searchs for the next file in the current directory
//
// Arguments: OUT [wfilename] - first file in the enumeration
// OUT [fdir] - TRUE = returned file is a directory
//
//----------------------------------------------------------------------------
ULONG CFileEnumerate::_NextLocal(LPWSTR *wfilename, BOOL *fdir) { ENUMERATE_RETURNS((stderr, L"_NextLocal start, path = %ws\n", _wpath)) ULONG ret = ERROR_SUCCESS;
// ensure that we have a valid handle for a findnextfile
if (INVALID_HANDLE_VALUE == _handle) { ret = ERROR_INVALID_HANDLE; } else { do { if (!FindNextFile(_handle, &_wfd)) { ret = GetLastError(); ENUMERATE_FAIL((stderr, L"find next returned: %ld\n",ret)) } else ret = ERROR_SUCCESS; } while ( (ERROR_SUCCESS == ret) && ( (0 == _wcsicmp(_wfd.cFileName, L".")) || (0 == _wcsicmp(_wfd.cFileName, L"..")) ) );
// if we found a file
if (ERROR_SUCCESS == ret) { // return the directory attrib.
if (_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) *fdir = TRUE; else *fdir = FALSE;
//_pwfileposition is pointer to postion of file in _wpath. _wpath is
//MAX_PATH long. MAX_PATH - (_pwfileposition - _wpath) is the length of
//buffer _pwfileposition
//
HRESULT hr = StringCchCopy((LPWSTR)_pwfileposition, MAX_PATH - (_pwfileposition- _wpath), (const wchar_t*)_wfd.cFileName); if(FAILED(hr)) { return HRESULT_CODE(hr); }
*wfilename = _wpath;
ENUMERATE_STAT((stderr, L"next filename = %ws\n", *wfilename)) } } ENUMERATE_RETURNS((stderr, L"_NextLocal returning = %ws(%ld)\n", *wfilename, ret))
return(ret); } //+---------------------------------------------------------------------------
//
// Member: CFileEnumerate::_InitDir, private
//
// Synopsis: (only called if going deep)
// goes down a directory (and thus causing a new CFileEnumerator
// to be created, or re-initializies
//
// Arguments: OUT [wfilename] - first file in the enumeration
// OUT [fdir] - TRUE = returned file is a directory
//
//----------------------------------------------------------------------------
ULONG CFileEnumerate::_InitDir(LPWSTR *wfilename, BOOL *fdir) { ENUMERATE_RETURNS((stderr, L"_InitDir start, path = %ws\n", _wpath)) ULONG ret = ERROR_SUCCESS;
// check and see if a directory was entered as the filename
if ( (0 == _wcsicmp( _wwildcards, _wfd.cFileName)) && (_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { ENUMERATE_EXTRA((stderr, L"first file matched directory = %ws\n", _wpath)) _pwfileposition += wcslen((LPWSTR)_wfd.cFileName);
//_pwfileposition is pointer to postion of file in _wpath. _wpath is
//MAX_PATH long. MAX_PATH - (_pwfileposition - _wpath) is the length of
//buffer _pwfileposition
//
HRESULT hr = StringCchCopy((LPWSTR)_pwfileposition, MAX_PATH - (_pwfileposition- _wpath), L"\\*.*"); if(FAILED(hr)) { return HRESULT_CODE(hr); }
_pwfileposition++; wcscpy(_wwildcards, L"*.*"); ENUMERATE_EXTRA((stderr, L" path = %ws\n",_wpath)) ENUMERATE_EXTRA((stderr, L"wild cards = %ws\n",_wwildcards))
WCHAR winfilename[MAX_PATH] = L""; hr = StringCchCopy((LPWSTR)winfilename, MAX_PATH, _wpath); if(FAILED(hr)) { return HRESULT_CODE(hr); }
ret = _ialize(winfilename, wfilename, fdir); } else {
// we are in deep
_findeep = TRUE;
// search thru all directories
//_pwfileposition is pointer to postion of file in _wpath. _wpath is
//MAX_PATH long. MAX_PATH - (_pwfileposition - _wpath) is the length of
//buffer _pwfileposition
//
HRESULT hr = StringCchCopy((LPWSTR)_pwfileposition, MAX_PATH - (_pwfileposition- _wpath), L"*.*"); if(FAILED(hr)) { return HRESULT_CODE(hr); }
if (INVALID_HANDLE_VALUE == ( _handle = FindFirstFile((LPCTSTR)_wpath, &_wfd) )) { ret = GetLastError(); ENUMERATE_FAIL((stderr, L"find first (dir) returned: %ld\n",ret)) } else { if ( !(_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || (0 == wcscmp(( LPCWSTR)_wfd.cFileName, L".")) || (0 == wcscmp(( LPCWSTR)_wfd.cFileName, L"..")) ) { ret = _NextDir(wfilename, fdir); } else { // if we have a sub directory, go down it
ret = _DownDir(wfilename, fdir);
// if we found nothing in that first sub directory, go the the next one
if ( (ERROR_NO_MORE_FILES == ret ) || (ERROR_FILE_NOT_FOUND == ret ) ) { ret = _NextDir(wfilename, fdir); } } } } ENUMERATE_RETURNS((stderr, L"_InitDir returning = %ws(%ld)\n", *wfilename, ret))
return(ret); } //+---------------------------------------------------------------------------
//
// Member: CFileEnumerate::_NextDir, private
//
// Synopsis: (only called if going deep)
// finds the next sub-directory from the current directory,
// and then goes down into that directory
//
// Arguments: OUT [wfilename] - first file in the enumeration
// OUT [fdir] - TRUE = returned file is a directory
//
//----------------------------------------------------------------------------
ULONG CFileEnumerate::_NextDir(LPWSTR *wfilename, BOOL *fdir) { ENUMERATE_RETURNS((stderr, L"_NextDir start, path = %ws\n", _wpath)) ULONG ret = ERROR_SUCCESS;
// skip the . & .. & files we cannot access
if (INVALID_HANDLE_VALUE == _handle) { ret = ERROR_INVALID_HANDLE; } else { do { do { if (!FindNextFile(_handle, &_wfd)) { ret = GetLastError(); ENUMERATE_FAIL((stderr, L"find next returned: %ld\n",ret)) } else ret = ERROR_SUCCESS; } while ( (ERROR_SUCCESS == ret) && ( !(_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || (0 == wcscmp(( LPCWSTR )_wfd.cFileName, L".")) || (0 == wcscmp(( LPCWSTR )_wfd.cFileName, L"..")) ) );
// if we found a directory
if (ERROR_SUCCESS == ret) { ret = _DownDir(wfilename, fdir); } else { // out of subdirectories to search, break out of the loop
break; } } while (( ERROR_NO_MORE_FILES == ret) || (ERROR_FILE_NOT_FOUND == ret)); } ENUMERATE_RETURNS((stderr, L"_NextDir returning = %ws(%ld)\n", *wfilename, ret))
return(ret); } //+---------------------------------------------------------------------------
//
// Member: CFileEnumerate::_DownDir, private
//
// Synopsis: (only called if going deep)
// creates a new CFileEnumerator for a sub-directory
//
// Arguments: OUT [wfilename] - first file in the enumeration
// OUT [fdir] - TRUE = returned file is a directory
//
//----------------------------------------------------------------------------
ULONG CFileEnumerate::_DownDir(LPWSTR *wfilename, BOOL *fdir) { ENUMERATE_RETURNS((stderr, L"_DownDir start, path = %ws\n", _wpath)) ULONG ret;
// make a new file enumerator class (this one) We should only go down
// 8 directories at most.
_pcfe = new CFileEnumerate(_fdeep); if ( NULL == _pcfe ) { ret = GetLastError () ; ENUMERATE_RETURNS((stderr, L"_DownDir returning = %ws(%ld)\n", *wfilename, ret )) return(ret); }
// add the wildcards to the end of the directory we are going down
//_pwfileposition is pointer to postion of file in _wpath. _wpath is
//MAX_PATH long. MAX_PATH - (_pwfileposition - _wpath) is the length of
//buffer _pwfileposition
//
HRESULT hr = StringCchCopy((LPWSTR)_pwfileposition, MAX_PATH - (_pwfileposition- _wpath), ( const wchar_t *)_wfd.cFileName); if(FAILED(hr)) { return HRESULT_CODE(hr); }
hr = StringCchCat(_wpath,MAX_PATH,L"\\"); if(FAILED(hr)) { return HRESULT_CODE(hr); }
hr = StringCchCat(_wpath,MAX_PATH, _wwildcards); if(FAILED(hr)) { return HRESULT_CODE(hr); }
// start it up and see if we find a match
if (ERROR_SUCCESS != (ret = _pcfe->Init(_wpath, wfilename, fdir))) { if (ERROR_ACCESS_DENIED != ret) { delete _pcfe; _pcfe = NULL; } } ENUMERATE_RETURNS((stderr, L"_DownDir returning = %ws(%ld)\n", *wfilename, ret)) return(ret); }
|