From 4daceaacbd19768c766c20146771a3eeafc4ac2a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 8 Apr 2013 10:03:48 +0000 Subject: [PATCH] Check that files returned from wxDir::FindXXX() match the filter. Native Windows functions used by wxDir check the filter against both the short and the long name resulting in unexpected results, e.g. searching for "foo.baz" would find "foo.bazaar". Fix this by explicitly rechecking that we have a valid match ourselves. Closes #3432. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@73790 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + src/msw/dir.cpp | 60 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 7789ce6bd9..0e17ef80d4 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -658,6 +658,7 @@ wxMSW: - Improve wxCURSOR_RIGHT_ARROW appearance (DoltAlya). - Generate menu highlight events for popup menus in wxDialog (Sam Partington). - Return more native shell icons from wxArtProvider (Markus Juergens). +- Fix filter checks in wxDir::FindFirst/Next() (Catalin Raceanu). wxOSX/Cocoa: diff --git a/src/msw/dir.cpp b/src/msw/dir.cpp index 2eea8fe7ff..55f855cf6f 100644 --- a/src/msw/dir.cpp +++ b/src/msw/dir.cpp @@ -64,20 +64,60 @@ inline void FreeFindData(FIND_DATA fd) } } -inline FIND_DATA FindFirst(const wxString& spec, - FIND_STRUCT *finddata) +const wxChar *GetNameFromFindData(const FIND_STRUCT *finddata) { - return ::FindFirstFile(spec.t_str(), finddata); + return finddata->cFileName; } -inline bool FindNext(FIND_DATA fd, FIND_STRUCT *finddata) +// Helper function checking that the contents of the given FIND_STRUCT really +// match our filter. We need to do it ourselves as native Windows functions +// apply the filter to both the long and the short names of the file, so +// something like "*.bar" matches "foo.bar.baz" too and not only "foo.bar", so +// we have to double check that we have a real match. +inline bool +CheckFoundMatch(const FIND_STRUCT* finddata, const wxString& filter) { - return ::FindNextFile(fd, finddata) != 0; + return filter.empty() || + wxString(GetNameFromFindData(finddata)).Matches(filter); } -const wxChar *GetNameFromFindData(FIND_STRUCT *finddata) +inline bool +FindNext(FIND_DATA fd, const wxString& filter, FIND_STRUCT *finddata) { - return finddata->cFileName; + for ( ;; ) + { + if ( !::FindNextFile(fd, finddata) ) + return false; + + // If we did find something, check that it really matches. + if ( CheckFoundMatch(finddata, filter) ) + return true; + } +} + +inline FIND_DATA +FindFirst(const wxString& spec, + const wxString& filter, + FIND_STRUCT *finddata) +{ + FIND_DATA fd = ::FindFirstFile(spec.t_str(), finddata); + + // As in FindNext() above, we need to check that the file name we found + // really matches our filter and look for the next match if it doesn't. + if ( IsFindDataOk(fd) && !CheckFoundMatch(finddata, filter) ) + { + if ( !FindNext(fd, filter, finddata) ) + { + // As we return the invalid handle from here to indicate that we + // didn't find anything, close the one we initially received + // ourselves. + FreeFindData(fd); + + return INVALID_HANDLE_VALUE; + } + } + + return fd; } inline FIND_ATTR GetAttrFromFindData(FIND_STRUCT *finddata) @@ -196,7 +236,7 @@ bool wxDirData::Read(wxString *filename) else filespec += m_filespec; - m_finddata = FindFirst(filespec, PTR_TO_FINDDATA); + m_finddata = FindFirst(filespec, m_filespec, PTR_TO_FINDDATA); first = true; } @@ -228,7 +268,7 @@ bool wxDirData::Read(wxString *filename) } else { - if ( !FindNext(m_finddata, PTR_TO_FINDDATA) ) + if ( !FindNext(m_finddata, m_filespec, PTR_TO_FINDDATA) ) { #ifdef __WIN32__ DWORD err = ::GetLastError(); @@ -400,7 +440,7 @@ wxGetDirectoryTimes(const wxString& dirname, #endif FIND_STRUCT fs; - FIND_DATA fd = FindFirst(dirname, &fs); + FIND_DATA fd = FindFirst(dirname, wxEmptyString, &fs); if ( !IsFindDataOk(fd) ) { return false; -- 2.45.2