#include "Stdafx.h" #include "fileOperation.h" typedef BOOL (CALLBACK *PENUMDIRTREE_CALLBACK)(PCSTR, PVOID); typedef BOOL (CALLBACK *PENUMDIRTREE_CALLBACKW)(PCWSTR, PVOID); static inline BOOL is_sep(char ch) {return ch == '/' || ch == '//';} static inline BOOL is_sepW(WCHAR ch) {return ch == '/' || ch == '//';} BOOL WINAPI _SymMatchFileNameW(PCWSTR file, PCWSTR match, PWSTR* filestop, PWSTR* matchstop) { PCWSTR fptr; PCWSTR mptr; fptr = file + wcslen(file) - 1; mptr = match + wcslen(match) - 1; // It is more efficient that traversing from back to front. while (fptr >= file && mptr >= match) { if (toupper(*fptr) != toupper(*mptr) && !(is_sep(*fptr) && is_sep(*mptr))) break; fptr--; mptr--; } if (filestop) *filestop = (PWSTR)fptr; if (matchstop) *matchstop = (PWSTR)mptr; return mptr == match - 1; } static BOOL _do_searchW(PCWSTR file, PWSTR buffer, BOOL recurse, PENUMDIRTREE_CALLBACKW cb, PVOID user) { HANDLE h; WIN32_FIND_DATAW fd; unsigned pos; BOOL found = FALSE; static const WCHAR S_AllW[] = {'*','.','*','/0'}; static const WCHAR S_DotW[] = {'.','/0'}; static const WCHAR S_DotDotW[] = {'.','.','/0'}; pos = wcslen(buffer); if (buffer[pos - 1] != '//') buffer[pos++] = '//'; wcscpy(buffer + pos, S_AllW); if ((h = FindFirstFileW(buffer, &fd)) == INVALID_HANDLE_VALUE) return FALSE; /* doc doesn't specify how the tree is enumerated... * doing a depth first based on, but may be wrong */ do { if (!wcscmp(fd.cFileName, S_DotW) || !wcscmp(fd.cFileName, S_DotDotW)) continue; wcscpy(buffer + pos, fd.cFileName); if (recurse && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) found = _do_searchW(file, buffer, TRUE, cb, user); else if (_SymMatchFileNameW(buffer, file, NULL, NULL)) { if (!cb || cb(buffer, user)) found = TRUE; } } while (!found && FindNextFileW(h, &fd)); if (!found) buffer[--pos] = '/0'; FindClose(h); return found; } BOOL WINAPI _SearchTreeForFileW(PCWSTR root, PCWSTR file, PWSTR buffer) { wcscpy(buffer, root); return _do_searchW(file, buffer, TRUE, NULL, NULL); }