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