Merge branch 'msw-fnmatch-all'

Fix using *.* and similar patterns in wxDir under MSW: they're supposed
to match all files and not only files with extensions.

See #23910.
This commit is contained in:
Vadim Zeitlin 2023-10-02 19:29:31 +02:00
commit a4d2e36cec
2 changed files with 77 additions and 31 deletions

View file

@ -27,8 +27,11 @@
#include "wx/dir.h"
#ifdef __WINDOWS__
#include "wx/msw/private.h"
#include "wx/msw/private.h"
#include <shlwapi.h>
#ifdef __VISUALC__
#pragma comment(lib, "shlwapi")
#endif
// ----------------------------------------------------------------------------
@ -60,11 +63,6 @@ inline void FreeFindData(FIND_DATA fd)
}
}
const wxChar *GetNameFromFindData(const FIND_STRUCT *finddata)
{
return finddata->cFileName;
}
// 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
@ -78,17 +76,7 @@ CheckFoundMatch(const FIND_STRUCT* finddata, const wxString& filter)
if ( filter.empty() )
return true;
// Otherwise do check the match validity. Notice that we must do it
// case-insensitively because the case of the file names is not supposed to
// matter under Windows.
wxString fn(GetNameFromFindData(finddata));
// However if the filter contains only special characters (which is a
// common case), we can skip the case conversion.
if ( filter.find_first_not_of(wxS("*?.")) == wxString::npos )
return fn.Matches(filter);
return fn.MakeUpper().Matches(filter.Upper());
return ::PathMatchSpec(finddata->cFileName, filter) == TRUE;
}
inline bool
@ -130,11 +118,6 @@ FindFirst(const wxString& spec,
return fd;
}
inline FIND_ATTR GetAttrFromFindData(FIND_STRUCT *finddata)
{
return finddata->dwFileAttributes;
}
inline bool IsDir(FIND_ATTR attr)
{
return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
@ -231,7 +214,6 @@ bool wxDirData::Read(wxString *filename)
bool first = false;
WIN32_FIND_DATA finddata;
#define PTR_TO_FINDDATA (&finddata)
if ( !IsFindDataOk(m_finddata) )
{
@ -246,7 +228,7 @@ bool wxDirData::Read(wxString *filename)
else
filespec += m_filespec;
m_finddata = FindFirst(filespec, m_filespec, PTR_TO_FINDDATA);
m_finddata = FindFirst(filespec, m_filespec, &finddata);
first = true;
}
@ -265,9 +247,6 @@ bool wxDirData::Read(wxString *filename)
return false;
}
const wxChar *name;
FIND_ATTR attr;
for ( ;; )
{
if ( first )
@ -276,7 +255,7 @@ bool wxDirData::Read(wxString *filename)
}
else
{
if ( !FindNext(m_finddata, m_filespec, PTR_TO_FINDDATA) )
if ( !FindNext(m_finddata, m_filespec, &finddata) )
{
DWORD err = ::GetLastError();
@ -290,8 +269,8 @@ bool wxDirData::Read(wxString *filename)
}
}
name = GetNameFromFindData(PTR_TO_FINDDATA);
attr = GetAttrFromFindData(PTR_TO_FINDDATA);
const wxChar* const name = finddata.cFileName;
const FIND_ATTR attr = finddata.dwFileAttributes;
// don't return "." and ".." unless asked for
if ( name[0] == wxT('.') &&

View file

@ -20,6 +20,16 @@
#define DIRTEST_FOLDER wxString("dirTest_folder")
#define SEP wxFileName::GetPathSeparator()
// We can't use wxFileSelectorDefaultWildcardStr from wxCore here, so define
// our own.
const wxString WILDCARD_ALL =
#if defined(__WXMSW__)
"*.*"
#else // Unix/Mac
"*"
#endif
;
// ----------------------------------------------------------------------------
// test fixture
// ----------------------------------------------------------------------------
@ -145,6 +155,21 @@ TEST_CASE_METHOD(DirTestCase, "Dir::Traverse", "[dir]")
wxArrayString files;
CHECK( wxDir::GetAllFiles(DIRTEST_FOLDER, &files) == 4 );
// enum all files using an explicit wildcard
CHECK(wxDir::GetAllFiles(DIRTEST_FOLDER, &files, WILDCARD_ALL) == 4);
// enum all files using an explicit wildcard different from WILDCARD_ALL
//
// broken under Wine, see https://bugs.winehq.org/show_bug.cgi?id=55677
if ( !wxIsRunningUnderWine() )
{
CHECK(wxDir::GetAllFiles(DIRTEST_FOLDER, &files, "d" + WILDCARD_ALL) == 4);
}
else if (wxDir::GetAllFiles(DIRTEST_FOLDER, &files, "d" + WILDCARD_ALL) == 4)
{
WARN("PathMatchSpec() seems to work under Wine now");
}
// enum all files according to the filter
CHECK( wxDir::GetAllFiles(DIRTEST_FOLDER, &files, "*.foo") == 1 );
@ -232,3 +257,45 @@ TEST_CASE_METHOD(DirTestCase, "Dir::GetName", "[dir]")
CHECK( d.GetNameWithSep() == "/" );
#endif
}
// Disabled by default test allowing to check the result of matching against
// the given filter.
#ifdef __WXMSW__
#include "wx/msw/wrapwin.h"
#include <shlwapi.h>
#ifdef __VISUALC__
#pragma comment(lib, "shlwapi")
#endif
#include "wx/crt.h"
#include "wx/filefn.h"
TEST_CASE("Dir::Match", "[.]")
{
wxString filter;
REQUIRE( wxGetEnv("WX_TEST_DIR_FILTER", &filter) );
static const wxString filenames[] =
{
"foo",
"foo.bar",
"foo.bar.baz",
".hidden",
".hidden.ext",
};
// Show the results of matching the pattern using various functions.
wxPrintf("%-15s %20s %20s %20s\n",
"File", "wxString::Matches", "wxMatchWild", "PathMatchSpec");
for ( const auto& fn : filenames )
{
wxPrintf("%-15s %20d %20d %20d\n",
fn,
fn.Matches(filter),
wxMatchWild(filter, fn),
PathMatchSpec(fn.wc_str(), filter.wc_str()) == TRUE);
}
}
#endif // __WXMSW__