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