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