1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dir.cpp
3 // Purpose: wxDir implementation for Win32
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
34 #include "wx/msw/private.h"
37 // ----------------------------------------------------------------------------
38 // define the types and functions used for file searching
39 // ----------------------------------------------------------------------------
44 typedef WIN32_FIND_DATA FIND_STRUCT
;
45 typedef HANDLE FIND_DATA
;
46 typedef DWORD FIND_ATTR
;
48 inline FIND_DATA
InitFindData()
50 return INVALID_HANDLE_VALUE
;
53 inline bool IsFindDataOk(FIND_DATA fd
)
55 return fd
!= INVALID_HANDLE_VALUE
;
58 inline void FreeFindData(FIND_DATA fd
)
60 if ( !::FindClose(fd
) )
62 wxLogLastError(wxT("FindClose"));
66 const wxChar
*GetNameFromFindData(const FIND_STRUCT
*finddata
)
68 return finddata
->cFileName
;
71 // Helper function checking that the contents of the given FIND_STRUCT really
72 // match our filter. We need to do it ourselves as native Windows functions
73 // apply the filter to both the long and the short names of the file, so
74 // something like "*.bar" matches "foo.bar.baz" too and not only "foo.bar", so
75 // we have to double check that we have a real match.
77 CheckFoundMatch(const FIND_STRUCT
* finddata
, const wxString
& filter
)
79 // If there is no filter, the found file must be the one we really are
84 // Otherwise do check the match validity. Notice that we must do it
85 // case-insensitively because the case of the file names is not supposed to
86 // matter under Windows.
87 wxString
fn(GetNameFromFindData(finddata
));
89 // However if the filter contains only special characters (which is a
90 // common case), we can skip the case conversion.
91 if ( filter
.find_first_not_of(wxS("*?.")) == wxString::npos
)
92 return fn
.Matches(filter
);
94 return fn
.MakeUpper().Matches(filter
.Upper());
98 FindNext(FIND_DATA fd
, const wxString
& filter
, FIND_STRUCT
*finddata
)
102 if ( !::FindNextFile(fd
, finddata
) )
105 // If we did find something, check that it really matches.
106 if ( CheckFoundMatch(finddata
, filter
) )
112 FindFirst(const wxString
& spec
,
113 const wxString
& filter
,
114 FIND_STRUCT
*finddata
)
116 FIND_DATA fd
= ::FindFirstFile(spec
.t_str(), finddata
);
118 // As in FindNext() above, we need to check that the file name we found
119 // really matches our filter and look for the next match if it doesn't.
120 if ( IsFindDataOk(fd
) && !CheckFoundMatch(finddata
, filter
) )
122 if ( !FindNext(fd
, filter
, finddata
) )
124 // As we return the invalid handle from here to indicate that we
125 // didn't find anything, close the one we initially received
129 return INVALID_HANDLE_VALUE
;
136 inline FIND_ATTR
GetAttrFromFindData(FIND_STRUCT
*finddata
)
138 return finddata
->dwFileAttributes
;
141 inline bool IsDir(FIND_ATTR attr
)
143 return (attr
& FILE_ATTRIBUTE_DIRECTORY
) != 0;
146 inline bool IsHidden(FIND_ATTR attr
)
148 return (attr
& (FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
)) != 0;
151 } // anonymous namespace
153 // ----------------------------------------------------------------------------
155 // ----------------------------------------------------------------------------
158 #define MAX_PATH 260 // from VC++ headers
161 // ----------------------------------------------------------------------------
163 // ----------------------------------------------------------------------------
165 #define M_DIR ((wxDirData *)m_data)
167 // ----------------------------------------------------------------------------
169 // ----------------------------------------------------------------------------
171 // this class stores everything we need to enumerate the files
175 wxDirData(const wxString
& dirname
);
178 void SetFileSpec(const wxString
& filespec
) { m_filespec
= filespec
; }
179 void SetFlags(int flags
) { m_flags
= flags
; }
183 bool Read(wxString
*filename
);
185 const wxString
& GetName() const { return m_dirname
; }
188 FIND_DATA m_finddata
;
195 wxDECLARE_NO_COPY_CLASS(wxDirData
);
198 // ============================================================================
200 // ============================================================================
202 // ----------------------------------------------------------------------------
204 // ----------------------------------------------------------------------------
206 wxDirData::wxDirData(const wxString
& dirname
)
209 m_finddata
= InitFindData();
212 wxDirData::~wxDirData()
217 void wxDirData::Close()
219 if ( IsFindDataOk(m_finddata
) )
221 FreeFindData(m_finddata
);
223 m_finddata
= InitFindData();
227 void wxDirData::Rewind()
232 bool wxDirData::Read(wxString
*filename
)
236 WIN32_FIND_DATA finddata
;
237 #define PTR_TO_FINDDATA (&finddata)
239 if ( !IsFindDataOk(m_finddata
) )
242 wxString filespec
= m_dirname
;
243 if ( !wxEndsWithPathSeparator(filespec
) )
245 filespec
+= wxT('\\');
248 filespec
+= wxT("*.*");
250 filespec
+= m_filespec
;
252 m_finddata
= FindFirst(filespec
, m_filespec
, PTR_TO_FINDDATA
);
257 if ( !IsFindDataOk(m_finddata
) )
260 DWORD err
= ::GetLastError();
262 if ( err
!= ERROR_FILE_NOT_FOUND
&& err
!= ERROR_NO_MORE_FILES
)
264 wxLogSysError(err
, _("Cannot enumerate files in directory '%s'"),
268 //else: not an error, just no (such) files
284 if ( !FindNext(m_finddata
, m_filespec
, PTR_TO_FINDDATA
) )
287 DWORD err
= ::GetLastError();
289 if ( err
!= ERROR_NO_MORE_FILES
)
291 wxLogLastError(wxT("FindNext"));
294 //else: not an error, just no more (such) files
300 name
= GetNameFromFindData(PTR_TO_FINDDATA
);
301 attr
= GetAttrFromFindData(PTR_TO_FINDDATA
);
303 // don't return "." and ".." unless asked for
304 if ( name
[0] == wxT('.') &&
305 ((name
[1] == wxT('.') && name
[2] == wxT('\0')) ||
306 (name
[1] == wxT('\0'))) )
308 if ( !(m_flags
& wxDIR_DOTDOT
) )
312 // check the type now
313 if ( !(m_flags
& wxDIR_FILES
) && !IsDir(attr
) )
315 // it's a file, but we don't want them
318 else if ( !(m_flags
& wxDIR_DIRS
) && IsDir(attr
) )
320 // it's a dir, and we don't want it
324 // finally, check whether it's a hidden file
325 if ( !(m_flags
& wxDIR_HIDDEN
) )
327 if ( IsHidden(attr
) )
329 // it's a hidden file, skip it
342 // ----------------------------------------------------------------------------
343 // wxDir construction/destruction
344 // ----------------------------------------------------------------------------
346 wxDir::wxDir(const wxString
& dirname
)
353 bool wxDir::Open(const wxString
& dirname
)
357 // The Unix code does a similar test
358 if (wxDirExists(dirname
))
360 m_data
= new wxDirData(dirname
);
372 bool wxDir::IsOpened() const
374 return m_data
!= NULL
;
377 wxString
wxDir::GetName() const
382 name
= M_DIR
->GetName();
385 // bring to canonical Windows form
386 name
.Replace(wxT("/"), wxT("\\"));
388 if ( name
.Last() == wxT('\\') )
390 // chop off the last (back)slash
391 name
.Truncate(name
.length() - 1);
408 // ----------------------------------------------------------------------------
410 // ----------------------------------------------------------------------------
412 bool wxDir::GetFirst(wxString
*filename
,
413 const wxString
& filespec
,
416 wxCHECK_MSG( IsOpened(), false, wxT("must wxDir::Open() first") );
420 M_DIR
->SetFileSpec(filespec
);
421 M_DIR
->SetFlags(flags
);
423 return GetNext(filename
);
426 bool wxDir::GetNext(wxString
*filename
) const
428 wxCHECK_MSG( IsOpened(), false, wxT("must wxDir::Open() first") );
430 wxCHECK_MSG( filename
, false, wxT("bad pointer in wxDir::GetNext()") );
432 return M_DIR
->Read(filename
);
435 // ----------------------------------------------------------------------------
436 // wxGetDirectoryTimes: used by wxFileName::GetTimes()
437 // ----------------------------------------------------------------------------
442 wxGetDirectoryTimes(const wxString
& dirname
,
443 FILETIME
*ftAccess
, FILETIME
*ftCreate
, FILETIME
*ftMod
)
446 // FindFirst() is going to fail
447 wxASSERT_MSG( !dirname
.empty(),
448 wxT("incorrect directory name format in wxGetDirectoryTimes") );
450 // FindFirst() is going to fail
451 wxASSERT_MSG( !dirname
.empty() && dirname
.Last() != wxT('\\'),
452 wxT("incorrect directory name format in wxGetDirectoryTimes") );
456 FIND_DATA fd
= FindFirst(dirname
, wxEmptyString
, &fs
);
457 if ( !IsFindDataOk(fd
) )
462 *ftAccess
= fs
.ftLastAccessTime
;
463 *ftCreate
= fs
.ftCreationTime
;
464 *ftMod
= fs
.ftLastWriteTime
;