Allow for WinCE drive-less single backslash
[wxWidgets.git] / src / msw / dir.cpp
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>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
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"
33 #include "wx/filefn.h" // for wxDirExists()
34
35 #ifdef __WINDOWS__
36 #include "wx/msw/private.h"
37 #endif
38
39 // ----------------------------------------------------------------------------
40 // define the types and functions used for file searching
41 // ----------------------------------------------------------------------------
42
43 typedef WIN32_FIND_DATA FIND_STRUCT;
44 typedef HANDLE FIND_DATA;
45 typedef DWORD FIND_ATTR;
46
47 static inline FIND_DATA InitFindData() { return INVALID_HANDLE_VALUE; }
48
49 static inline bool IsFindDataOk(FIND_DATA fd)
50 {
51 return fd != INVALID_HANDLE_VALUE;
52 }
53
54 static inline void FreeFindData(FIND_DATA fd)
55 {
56 if ( !::FindClose(fd) )
57 {
58 wxLogLastError(_T("FindClose"));
59 }
60 }
61
62 static inline FIND_DATA FindFirst(const wxString& spec,
63 FIND_STRUCT *finddata)
64 {
65 return ::FindFirstFile(spec, finddata);
66 }
67
68 static inline bool FindNext(FIND_DATA fd, FIND_STRUCT *finddata)
69 {
70 return ::FindNextFile(fd, finddata) != 0;
71 }
72
73 static const wxChar *GetNameFromFindData(FIND_STRUCT *finddata)
74 {
75 return finddata->cFileName;
76 }
77
78 static const FIND_ATTR GetAttrFromFindData(FIND_STRUCT *finddata)
79 {
80 return finddata->dwFileAttributes;
81 }
82
83 static inline bool IsDir(FIND_ATTR attr)
84 {
85 return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
86 }
87
88 static inline bool IsHidden(FIND_ATTR attr)
89 {
90 return (attr & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0;
91 }
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
112 class wxDirData
113 {
114 public:
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
125 const wxString& GetName() const { return m_dirname; }
126
127 private:
128 FIND_DATA m_finddata;
129
130 wxString m_dirname;
131 wxString m_filespec;
132
133 int m_flags;
134
135 DECLARE_NO_COPY_CLASS(wxDirData)
136 };
137
138 // ============================================================================
139 // implementation
140 // ============================================================================
141
142 // ----------------------------------------------------------------------------
143 // wxDirData
144 // ----------------------------------------------------------------------------
145
146 wxDirData::wxDirData(const wxString& dirname)
147 : m_dirname(dirname)
148 {
149 m_finddata = InitFindData();
150 }
151
152 wxDirData::~wxDirData()
153 {
154 Close();
155 }
156
157 void wxDirData::Close()
158 {
159 if ( IsFindDataOk(m_finddata) )
160 {
161 FreeFindData(m_finddata);
162
163 m_finddata = InitFindData();
164 }
165 }
166
167 void wxDirData::Rewind()
168 {
169 Close();
170 }
171
172 bool wxDirData::Read(wxString *filename)
173 {
174 bool first = false;
175
176 WIN32_FIND_DATA finddata;
177 #define PTR_TO_FINDDATA (&finddata)
178
179 if ( !IsFindDataOk(m_finddata) )
180 {
181 // open first
182 wxString filespec = m_dirname;
183 if ( !wxEndsWithPathSeparator(filespec) )
184 {
185 filespec += _T('\\');
186 }
187 filespec += (!m_filespec ? _T("*.*") : m_filespec.c_str());
188
189 m_finddata = FindFirst(filespec, PTR_TO_FINDDATA);
190
191 first = true;
192 }
193
194 if ( !IsFindDataOk(m_finddata) )
195 {
196 #ifdef __WIN32__
197 DWORD err = ::GetLastError();
198
199 if ( err != ERROR_FILE_NOT_FOUND && err != ERROR_NO_MORE_FILES )
200 {
201 wxLogSysError(err, _("Can not enumerate files in directory '%s'"),
202 m_dirname.c_str());
203 }
204 #endif // __WIN32__
205 //else: not an error, just no (such) files
206
207 return false;
208 }
209
210 const wxChar *name;
211 FIND_ATTR attr;
212
213 for ( ;; )
214 {
215 if ( first )
216 {
217 first = false;
218 }
219 else
220 {
221 if ( !FindNext(m_finddata, PTR_TO_FINDDATA) )
222 {
223 #ifdef __WIN32__
224 DWORD err = ::GetLastError();
225
226 if ( err != ERROR_NO_MORE_FILES )
227 {
228 wxLogLastError(_T("FindNext"));
229 }
230 #endif // __WIN32__
231 //else: not an error, just no more (such) files
232
233 return false;
234 }
235 }
236
237 name = GetNameFromFindData(PTR_TO_FINDDATA);
238 attr = GetAttrFromFindData(PTR_TO_FINDDATA);
239
240 // don't return "." and ".." unless asked for
241 if ( name[0] == _T('.') &&
242 ((name[1] == _T('.') && name[2] == _T('\0')) ||
243 (name[1] == _T('\0'))) )
244 {
245 if ( !(m_flags & wxDIR_DOTDOT) )
246 continue;
247 }
248
249 // check the type now
250 if ( !(m_flags & wxDIR_FILES) && !IsDir(attr) )
251 {
252 // it's a file, but we don't want them
253 continue;
254 }
255 else if ( !(m_flags & wxDIR_DIRS) && IsDir(attr) )
256 {
257 // it's a dir, and we don't want it
258 continue;
259 }
260
261 // finally, check whether it's a hidden file
262 if ( !(m_flags & wxDIR_HIDDEN) )
263 {
264 if ( IsHidden(attr) )
265 {
266 // it's a hidden file, skip it
267 continue;
268 }
269 }
270
271 *filename = name;
272
273 break;
274 }
275
276 return true;
277 }
278
279 // ----------------------------------------------------------------------------
280 // wxDir helpers
281 // ----------------------------------------------------------------------------
282
283 /* static */
284 bool wxDir::Exists(const wxString& dir)
285 {
286 return wxDirExists(dir);
287 }
288
289 // ----------------------------------------------------------------------------
290 // wxDir construction/destruction
291 // ----------------------------------------------------------------------------
292
293 wxDir::wxDir(const wxString& dirname)
294 {
295 m_data = NULL;
296
297 (void)Open(dirname);
298 }
299
300 bool wxDir::Open(const wxString& dirname)
301 {
302 delete M_DIR;
303 m_data = new wxDirData(dirname);
304
305 return true;
306 }
307
308 bool wxDir::IsOpened() const
309 {
310 return m_data != NULL;
311 }
312
313 wxString wxDir::GetName() const
314 {
315 wxString name;
316 if ( m_data )
317 {
318 name = M_DIR->GetName();
319 if ( !name.empty() )
320 {
321 // bring to canonical Windows form
322 name.Replace(_T("/"), _T("\\"));
323
324 if ( name.Last() == _T('\\') )
325 {
326 // chop off the last (back)slash
327 name.Truncate(name.length() - 1);
328 }
329 }
330 }
331
332 return name;
333 }
334
335 wxDir::~wxDir()
336 {
337 delete M_DIR;
338 }
339
340 // ----------------------------------------------------------------------------
341 // wxDir enumerating
342 // ----------------------------------------------------------------------------
343
344 bool wxDir::GetFirst(wxString *filename,
345 const wxString& filespec,
346 int flags) const
347 {
348 wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
349
350 M_DIR->Rewind();
351
352 M_DIR->SetFileSpec(filespec);
353 M_DIR->SetFlags(flags);
354
355 return GetNext(filename);
356 }
357
358 bool wxDir::GetNext(wxString *filename) const
359 {
360 wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
361
362 wxCHECK_MSG( filename, false, _T("bad pointer in wxDir::GetNext()") );
363
364 return M_DIR->Read(filename);
365 }
366
367 // ----------------------------------------------------------------------------
368 // wxGetDirectoryTimes: used by wxFileName::GetTimes()
369 // ----------------------------------------------------------------------------
370
371 #ifdef __WIN32__
372
373 extern bool
374 wxGetDirectoryTimes(const wxString& dirname,
375 FILETIME *ftAccess, FILETIME *ftCreate, FILETIME *ftMod)
376 {
377 #ifdef __WXWINCE__
378 // FindFirst() is going to fail
379 wxASSERT_MSG( !dirname.empty(),
380 _T("incorrect directory name format in wxGetDirectoryTimes") );
381 #else
382 // FindFirst() is going to fail
383 wxASSERT_MSG( !dirname.empty() && dirname.Last() != _T('\\'),
384 _T("incorrect directory name format in wxGetDirectoryTimes") );
385 #endif
386
387 FIND_STRUCT fs;
388 FIND_DATA fd = FindFirst(dirname, &fs);
389 if ( !IsFindDataOk(fd) )
390 {
391 return false;
392 }
393
394 *ftAccess = fs.ftLastAccessTime;
395 *ftCreate = fs.ftCreationTime;
396 *ftMod = fs.ftLastWriteTime;
397
398 FindClose(fd);
399
400 return true;
401 }
402
403 #endif // __WIN32__
404