Skip to content

Commit 20d4f2f

Browse files
committed
Fix using *.* and similar patterns in wxDir under MSW
These patterns are supposed to match all files and not only files with extensions, but our own code only matched the latter. Switch to using shell PathMatchSpec() function to check for matching instead to use the usual Windows rules. See wxWidgets#23905, wxWidgets#23910. (cherry picked from commit a4d2e36)
1 parent d178223 commit 20d4f2f

File tree

3 files changed

+79
-31
lines changed

3 files changed

+79
-31
lines changed

docs/changes.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ wxMSW:
312312
- Fix (deprecated) build without Unicode support broken in 3.2.2 (#23516).
313313
- Fix crash when using wxBitmapDataObject in wxDataObjectComposite (#23564).
314314
- Fix setting locale for wxLANGUAGE_UKRAINIAN (Ulrich Telle, #23210).
315+
- Fix matching wildcards ending with "*.*" in wxDir (#23905).
315316
- Don't reset custom wxToolBar background on system colour change (#23386).
316317
- Fix wxUILocale::GetPreferredUILanguages() with OS < 10 (Brian Nixon, #23416).
317318
- Fix building with LLVM clang (Sergey Khalyutn, Maarten Bent, #23464).

src/msw/dir.cpp

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727

2828
#include "wx/dir.h"
2929

30-
#ifdef __WINDOWS__
31-
#include "wx/msw/private.h"
30+
#include "wx/msw/private.h"
31+
#include <shlwapi.h>
32+
33+
#ifdef __VISUALC__
34+
#pragma comment(lib, "shlwapi")
3235
#endif
3336

3437
// ----------------------------------------------------------------------------
@@ -60,11 +63,6 @@ inline void FreeFindData(FIND_DATA fd)
6063
}
6164
}
6265

63-
const wxChar *GetNameFromFindData(const FIND_STRUCT *finddata)
64-
{
65-
return finddata->cFileName;
66-
}
67-
6866
// Helper function checking that the contents of the given FIND_STRUCT really
6967
// match our filter. We need to do it ourselves as native Windows functions
7068
// 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)
7876
if ( filter.empty() )
7977
return true;
8078

81-
// Otherwise do check the match validity. Notice that we must do it
82-
// case-insensitively because the case of the file names is not supposed to
83-
// matter under Windows.
84-
wxString fn(GetNameFromFindData(finddata));
85-
86-
// However if the filter contains only special characters (which is a
87-
// common case), we can skip the case conversion.
88-
if ( filter.find_first_not_of(wxS("*?.")) == wxString::npos )
89-
return fn.Matches(filter);
90-
91-
return fn.MakeUpper().Matches(filter.Upper());
79+
return ::PathMatchSpec(finddata->cFileName, filter.t_str()) == TRUE;
9280
}
9381

9482
inline bool
@@ -130,11 +118,6 @@ FindFirst(const wxString& spec,
130118
return fd;
131119
}
132120

133-
inline FIND_ATTR GetAttrFromFindData(FIND_STRUCT *finddata)
134-
{
135-
return finddata->dwFileAttributes;
136-
}
137-
138121
inline bool IsDir(FIND_ATTR attr)
139122
{
140123
return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
@@ -231,7 +214,6 @@ bool wxDirData::Read(wxString *filename)
231214
bool first = false;
232215

233216
WIN32_FIND_DATA finddata;
234-
#define PTR_TO_FINDDATA (&finddata)
235217

236218
if ( !IsFindDataOk(m_finddata) )
237219
{
@@ -246,7 +228,7 @@ bool wxDirData::Read(wxString *filename)
246228
else
247229
filespec += m_filespec;
248230

249-
m_finddata = FindFirst(filespec, m_filespec, PTR_TO_FINDDATA);
231+
m_finddata = FindFirst(filespec, m_filespec, &finddata);
250232

251233
first = true;
252234
}
@@ -265,9 +247,6 @@ bool wxDirData::Read(wxString *filename)
265247
return false;
266248
}
267249

268-
const wxChar *name;
269-
FIND_ATTR attr;
270-
271250
for ( ;; )
272251
{
273252
if ( first )
@@ -276,7 +255,7 @@ bool wxDirData::Read(wxString *filename)
276255
}
277256
else
278257
{
279-
if ( !FindNext(m_finddata, m_filespec, PTR_TO_FINDDATA) )
258+
if ( !FindNext(m_finddata, m_filespec, &finddata) )
280259
{
281260
DWORD err = ::GetLastError();
282261

@@ -290,8 +269,8 @@ bool wxDirData::Read(wxString *filename)
290269
}
291270
}
292271

293-
name = GetNameFromFindData(PTR_TO_FINDDATA);
294-
attr = GetAttrFromFindData(PTR_TO_FINDDATA);
272+
const wxChar* const name = finddata.cFileName;
273+
const FIND_ATTR attr = finddata.dwFileAttributes;
295274

296275
// don't return "." and ".." unless asked for
297276
if ( name[0] == wxT('.') &&

tests/file/dir.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@
2020
#define DIRTEST_FOLDER wxString("dirTest_folder")
2121
#define SEP wxFileName::GetPathSeparator()
2222

23+
// We can't use wxFileSelectorDefaultWildcardStr from wxCore here, so define
24+
// our own.
25+
const wxString WILDCARD_ALL =
26+
#if defined(__WXMSW__)
27+
"*.*"
28+
#else // Unix/Mac
29+
"*"
30+
#endif
31+
;
32+
2333
// ----------------------------------------------------------------------------
2434
// test fixture
2535
// ----------------------------------------------------------------------------
@@ -145,6 +155,21 @@ TEST_CASE_METHOD(DirTestCase, "Dir::Traverse", "[dir]")
145155
wxArrayString files;
146156
CHECK( wxDir::GetAllFiles(DIRTEST_FOLDER, &files) == 4 );
147157

158+
// enum all files using an explicit wildcard
159+
CHECK(wxDir::GetAllFiles(DIRTEST_FOLDER, &files, WILDCARD_ALL) == 4);
160+
161+
// enum all files using an explicit wildcard different from WILDCARD_ALL
162+
//
163+
// broken under Wine, see https://bugs.winehq.org/show_bug.cgi?id=55677
164+
if ( !wxIsRunningUnderWine() )
165+
{
166+
CHECK(wxDir::GetAllFiles(DIRTEST_FOLDER, &files, "d" + WILDCARD_ALL) == 4);
167+
}
168+
else if (wxDir::GetAllFiles(DIRTEST_FOLDER, &files, "d" + WILDCARD_ALL) == 4)
169+
{
170+
WARN("PathMatchSpec() seems to work under Wine now");
171+
}
172+
148173
// enum all files according to the filter
149174
CHECK( wxDir::GetAllFiles(DIRTEST_FOLDER, &files, "*.foo") == 1 );
150175

@@ -232,3 +257,46 @@ TEST_CASE_METHOD(DirTestCase, "Dir::GetName", "[dir]")
232257
CHECK( d.GetNameWithSep() == "/" );
233258
#endif
234259
}
260+
261+
// Disabled by default test allowing to check the result of matching against
262+
// the given filter.
263+
#ifdef __WXMSW__
264+
265+
#include "wx/msw/wrapwin.h"
266+
#include <shlwapi.h>
267+
#ifdef __VISUALC__
268+
#pragma comment(lib, "shlwapi")
269+
#endif
270+
271+
#include "wx/crt.h"
272+
#include "wx/filefn.h"
273+
274+
TEST_CASE("Dir::Match", "[.]")
275+
{
276+
wxString filter;
277+
REQUIRE( wxGetEnv("WX_TEST_DIR_FILTER", &filter) );
278+
279+
static const wxString filenames[] =
280+
{
281+
"foo",
282+
"foo.bar",
283+
"foo.bar.baz",
284+
".hidden",
285+
".hidden.ext",
286+
};
287+
288+
// Show the results of matching the pattern using various functions.
289+
wxPrintf("%-15s %20s %20s %20s\n",
290+
"File", "wxString::Matches", "wxMatchWild", "PathMatchSpec");
291+
for ( size_t n = 0; n < WXSIZEOF(filenames); ++n )
292+
{
293+
const wxString fn = filenames[n];
294+
wxPrintf("%-15s %20d %20d %20d\n",
295+
fn,
296+
fn.Matches(filter),
297+
wxMatchWild(filter, fn),
298+
PathMatchSpec(fn.t_str(), filter.t_str()) == TRUE);
299+
}
300+
}
301+
302+
#endif // __WXMSW__

0 commit comments

Comments
 (0)