]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dir.cpp
fix crash which happened if you called SetAttr(NULL) followed by SetAttr(attr) (...
[wxWidgets.git] / src / msw / dir.cpp
CommitLineData
1944c6bd
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: msw/dir.cpp
3// Purpose: wxDir implementation for Win32
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 08.12.99
7// RCS-ID: $Id$
8// Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 9// Licence: wxWindows licence
1944c6bd
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
1944c6bd
VZ
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#ifndef WX_PRECOMP
28 #include "wx/intl.h"
29 #include "wx/log.h"
30#endif // PCH
31
32#include "wx/dir.h"
da865fdd 33#include "wx/filefn.h" // for wxDirExists()
1944c6bd 34
532d575b 35#ifdef __WINDOWS__
4676948b
JS
36 #include "wx/msw/private.h"
37#endif
38
8f177c8e
VZ
39// ----------------------------------------------------------------------------
40// define the types and functions used for file searching
41// ----------------------------------------------------------------------------
42
3a5bcc4d
VZ
43typedef WIN32_FIND_DATA FIND_STRUCT;
44typedef HANDLE FIND_DATA;
45typedef DWORD FIND_ATTR;
8f177c8e 46
3a5bcc4d 47static inline FIND_DATA InitFindData() { return INVALID_HANDLE_VALUE; }
8f177c8e 48
3a5bcc4d
VZ
49static inline bool IsFindDataOk(FIND_DATA fd)
50{
8f177c8e 51 return fd != INVALID_HANDLE_VALUE;
3a5bcc4d 52}
8f177c8e 53
3a5bcc4d
VZ
54static inline void FreeFindData(FIND_DATA fd)
55{
8f177c8e
VZ
56 if ( !::FindClose(fd) )
57 {
58 wxLogLastError(_T("FindClose"));
59 }
3a5bcc4d 60}
8f177c8e 61
3a5bcc4d 62static inline FIND_DATA FindFirst(const wxString& spec,
8f177c8e 63 FIND_STRUCT *finddata)
3a5bcc4d 64{
e0a050e3 65 return ::FindFirstFile(spec.fn_str(), finddata);
3a5bcc4d 66}
8f177c8e 67
3a5bcc4d
VZ
68static inline bool FindNext(FIND_DATA fd, FIND_STRUCT *finddata)
69{
8f177c8e 70 return ::FindNextFile(fd, finddata) != 0;
3a5bcc4d 71}
8f177c8e 72
3a5bcc4d
VZ
73static const wxChar *GetNameFromFindData(FIND_STRUCT *finddata)
74{
8f177c8e 75 return finddata->cFileName;
3a5bcc4d 76}
8f177c8e 77
3a5bcc4d
VZ
78static const FIND_ATTR GetAttrFromFindData(FIND_STRUCT *finddata)
79{
8f177c8e 80 return finddata->dwFileAttributes;
3a5bcc4d 81}
8f177c8e 82
3a5bcc4d
VZ
83static inline bool IsDir(FIND_ATTR attr)
84{
8f177c8e 85 return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
3a5bcc4d 86}
8f177c8e 87
3a5bcc4d
VZ
88static inline bool IsHidden(FIND_ATTR attr)
89{
8f177c8e 90 return (attr & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0;
3a5bcc4d 91}
1944c6bd
VZ
92
93// ----------------------------------------------------------------------------
94// constants
95// ----------------------------------------------------------------------------
96
97#ifndef MAX_PATH
98 #define MAX_PATH 260 // from VC++ headers
99#endif
100
101// ----------------------------------------------------------------------------
102// macros
103// ----------------------------------------------------------------------------
104
105#define M_DIR ((wxDirData *)m_data)
106
107// ----------------------------------------------------------------------------
108// private classes
109// ----------------------------------------------------------------------------
110
111// this class stores everything we need to enumerate the files
112class wxDirData
113{
114public:
115 wxDirData(const wxString& dirname);
116 ~wxDirData();
117
118 void SetFileSpec(const wxString& filespec) { m_filespec = filespec; }
119 void SetFlags(int flags) { m_flags = flags; }
120
121 void Close();
122 void Rewind();
123 bool Read(wxString *filename);
124
35332784
VZ
125 const wxString& GetName() const { return m_dirname; }
126
1944c6bd 127private:
8f177c8e 128 FIND_DATA m_finddata;
1944c6bd
VZ
129
130 wxString m_dirname;
131 wxString m_filespec;
132
133 int m_flags;
22f3361e
VZ
134
135 DECLARE_NO_COPY_CLASS(wxDirData)
1944c6bd
VZ
136};
137
138// ============================================================================
139// implementation
140// ============================================================================
141
142// ----------------------------------------------------------------------------
143// wxDirData
144// ----------------------------------------------------------------------------
145
146wxDirData::wxDirData(const wxString& dirname)
147 : m_dirname(dirname)
148{
8f177c8e 149 m_finddata = InitFindData();
1944c6bd
VZ
150}
151
152wxDirData::~wxDirData()
153{
154 Close();
155}
156
157void wxDirData::Close()
158{
8f177c8e 159 if ( IsFindDataOk(m_finddata) )
1944c6bd 160 {
8f177c8e 161 FreeFindData(m_finddata);
4afd7529 162
8f177c8e 163 m_finddata = InitFindData();
1944c6bd
VZ
164 }
165}
166
167void wxDirData::Rewind()
168{
169 Close();
170}
171
172bool wxDirData::Read(wxString *filename)
173{
d71cc120 174 bool first = false;
1944c6bd
VZ
175
176 WIN32_FIND_DATA finddata;
8f177c8e 177 #define PTR_TO_FINDDATA (&finddata)
8f177c8e
VZ
178
179 if ( !IsFindDataOk(m_finddata) )
1944c6bd
VZ
180 {
181 // open first
ad0dc53b
VZ
182 wxString filespec = m_dirname;
183 if ( !wxEndsWithPathSeparator(filespec) )
184 {
185 filespec += _T('\\');
186 }
c9f78968
VS
187 if ( !m_filespec )
188 filespec += _T("*.*");
189 else
190 filespec += m_filespec;
4afd7529 191
8f177c8e 192 m_finddata = FindFirst(filespec, PTR_TO_FINDDATA);
1944c6bd 193
d71cc120 194 first = true;
1944c6bd
VZ
195 }
196
8f177c8e 197 if ( !IsFindDataOk(m_finddata) )
1944c6bd 198 {
8f177c8e 199#ifdef __WIN32__
1944c6bd
VZ
200 DWORD err = ::GetLastError();
201
5613bc20 202 if ( err != ERROR_FILE_NOT_FOUND && err != ERROR_NO_MORE_FILES )
1944c6bd 203 {
a236aa20 204 wxLogSysError(err, _("Can not enumerate files in directory '%s'"),
1944c6bd
VZ
205 m_dirname.c_str());
206 }
8f177c8e 207#endif // __WIN32__
1944c6bd
VZ
208 //else: not an error, just no (such) files
209
d71cc120 210 return false;
1944c6bd
VZ
211 }
212
1944c6bd 213 const wxChar *name;
8f177c8e 214 FIND_ATTR attr;
1944c6bd 215
4afd7529 216 for ( ;; )
1944c6bd
VZ
217 {
218 if ( first )
219 {
d71cc120 220 first = false;
1944c6bd
VZ
221 }
222 else
223 {
8f177c8e 224 if ( !FindNext(m_finddata, PTR_TO_FINDDATA) )
1944c6bd 225 {
8f177c8e 226#ifdef __WIN32__
1944c6bd
VZ
227 DWORD err = ::GetLastError();
228
229 if ( err != ERROR_NO_MORE_FILES )
230 {
231 wxLogLastError(_T("FindNext"));
232 }
8f177c8e 233#endif // __WIN32__
1944c6bd
VZ
234 //else: not an error, just no more (such) files
235
d71cc120 236 return false;
1944c6bd
VZ
237 }
238 }
239
8f177c8e
VZ
240 name = GetNameFromFindData(PTR_TO_FINDDATA);
241 attr = GetAttrFromFindData(PTR_TO_FINDDATA);
1944c6bd
VZ
242
243 // don't return "." and ".." unless asked for
244 if ( name[0] == _T('.') &&
245 ((name[1] == _T('.') && name[2] == _T('\0')) ||
246 (name[1] == _T('\0'))) )
247 {
248 if ( !(m_flags & wxDIR_DOTDOT) )
249 continue;
250 }
251
252 // check the type now
8f177c8e 253 if ( !(m_flags & wxDIR_FILES) && !IsDir(attr) )
1944c6bd
VZ
254 {
255 // it's a file, but we don't want them
256 continue;
257 }
8f177c8e 258 else if ( !(m_flags & wxDIR_DIRS) && IsDir(attr) )
1944c6bd
VZ
259 {
260 // it's a dir, and we don't want it
261 continue;
262 }
263
264 // finally, check whether it's a hidden file
265 if ( !(m_flags & wxDIR_HIDDEN) )
266 {
8f177c8e 267 if ( IsHidden(attr) )
4afd7529
VZ
268 {
269 // it's a hidden file, skip it
270 continue;
271 }
1944c6bd 272 }
1944c6bd 273
4afd7529
VZ
274 *filename = name;
275
276 break;
277 }
1944c6bd 278
d71cc120 279 return true;
1944c6bd
VZ
280}
281
282// ----------------------------------------------------------------------------
283// wxDir helpers
284// ----------------------------------------------------------------------------
285
286/* static */
287bool wxDir::Exists(const wxString& dir)
288{
da865fdd 289 return wxDirExists(dir);
1944c6bd
VZ
290}
291
292// ----------------------------------------------------------------------------
293// wxDir construction/destruction
294// ----------------------------------------------------------------------------
295
296wxDir::wxDir(const wxString& dirname)
297{
298 m_data = NULL;
299
300 (void)Open(dirname);
301}
302
303bool wxDir::Open(const wxString& dirname)
304{
305 delete M_DIR;
89432923
RR
306
307 // The Unix code does a similar test
308 if (wxDirExists(dirname))
309 {
310 m_data = new wxDirData(dirname);
1944c6bd 311
89432923
RR
312 return true;
313 }
314 else
315 {
316 m_data = NULL;
317
318 return false;
319 }
1944c6bd
VZ
320}
321
322bool wxDir::IsOpened() const
323{
324 return m_data != NULL;
325}
326
35332784
VZ
327wxString wxDir::GetName() const
328{
329 wxString name;
330 if ( m_data )
331 {
332 name = M_DIR->GetName();
333 if ( !name.empty() )
334 {
335 // bring to canonical Windows form
336 name.Replace(_T("/"), _T("\\"));
337
338 if ( name.Last() == _T('\\') )
339 {
340 // chop off the last (back)slash
341 name.Truncate(name.length() - 1);
342 }
343 }
344 }
345
346 return name;
347}
348
1944c6bd
VZ
349wxDir::~wxDir()
350{
351 delete M_DIR;
352}
353
354// ----------------------------------------------------------------------------
355// wxDir enumerating
356// ----------------------------------------------------------------------------
357
358bool wxDir::GetFirst(wxString *filename,
359 const wxString& filespec,
360 int flags) const
361{
d71cc120 362 wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
1944c6bd
VZ
363
364 M_DIR->Rewind();
365
366 M_DIR->SetFileSpec(filespec);
367 M_DIR->SetFlags(flags);
368
369 return GetNext(filename);
370}
371
372bool wxDir::GetNext(wxString *filename) const
373{
d71cc120 374 wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
1944c6bd 375
d71cc120 376 wxCHECK_MSG( filename, false, _T("bad pointer in wxDir::GetNext()") );
1944c6bd
VZ
377
378 return M_DIR->Read(filename);
379}
2b5f62a0
VZ
380
381// ----------------------------------------------------------------------------
382// wxGetDirectoryTimes: used by wxFileName::GetTimes()
383// ----------------------------------------------------------------------------
384
385#ifdef __WIN32__
386
387extern bool
388wxGetDirectoryTimes(const wxString& dirname,
389 FILETIME *ftAccess, FILETIME *ftCreate, FILETIME *ftMod)
390{
4de1b652
JS
391#ifdef __WXWINCE__
392 // FindFirst() is going to fail
393 wxASSERT_MSG( !dirname.empty(),
394 _T("incorrect directory name format in wxGetDirectoryTimes") );
395#else
2b5f62a0
VZ
396 // FindFirst() is going to fail
397 wxASSERT_MSG( !dirname.empty() && dirname.Last() != _T('\\'),
398 _T("incorrect directory name format in wxGetDirectoryTimes") );
4de1b652 399#endif
2b5f62a0
VZ
400
401 FIND_STRUCT fs;
402 FIND_DATA fd = FindFirst(dirname, &fs);
403 if ( !IsFindDataOk(fd) )
404 {
d71cc120 405 return false;
2b5f62a0
VZ
406 }
407
408 *ftAccess = fs.ftLastAccessTime;
409 *ftCreate = fs.ftCreationTime;
410 *ftMod = fs.ftLastWriteTime;
411
412 FindClose(fd);
413
d71cc120 414 return true;
2b5f62a0
VZ
415}
416
417#endif // __WIN32__
418