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: dir.cpp 42910 2006-11-01 15:29:58Z JS $ 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 43typedef WIN32_FIND_DATA FIND_STRUCT; 44typedef HANDLE FIND_DATA; 45typedef DWORD FIND_ATTR; 46 47static inline FIND_DATA InitFindData() { return INVALID_HANDLE_VALUE; } 48 49static inline bool IsFindDataOk(FIND_DATA fd) 50{ 51 return fd != INVALID_HANDLE_VALUE; 52} 53 54static inline void FreeFindData(FIND_DATA fd) 55{ 56 if ( !::FindClose(fd) ) 57 { 58 wxLogLastError(_T("FindClose")); 59 } 60} 61 62static inline FIND_DATA FindFirst(const wxString& spec, 63 FIND_STRUCT *finddata) 64{ 65 return ::FindFirstFile(spec, finddata); 66} 67 68static inline bool FindNext(FIND_DATA fd, FIND_STRUCT *finddata) 69{ 70 return ::FindNextFile(fd, finddata) != 0; 71} 72 73static const wxChar *GetNameFromFindData(FIND_STRUCT *finddata) 74{ 75 return finddata->cFileName; 76} 77 78static const FIND_ATTR GetAttrFromFindData(FIND_STRUCT *finddata) 79{ 80 return finddata->dwFileAttributes; 81} 82 83static inline bool IsDir(FIND_ATTR attr) 84{ 85 return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0; 86} 87 88static 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 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 125 const wxString& GetName() const { return m_dirname; } 126 127private: 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 146wxDirData::wxDirData(const wxString& dirname) 147 : m_dirname(dirname) 148{ 149 m_finddata = InitFindData(); 150} 151 152wxDirData::~wxDirData() 153{ 154 Close(); 155} 156 157void wxDirData::Close() 158{ 159 if ( IsFindDataOk(m_finddata) ) 160 { 161 FreeFindData(m_finddata); 162 163 m_finddata = InitFindData(); 164 } 165} 166 167void wxDirData::Rewind() 168{ 169 Close(); 170} 171 172bool 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 */ 284bool wxDir::Exists(const wxString& dir) 285{ 286 return wxDirExists(dir); 287} 288 289// ---------------------------------------------------------------------------- 290// wxDir construction/destruction 291// ---------------------------------------------------------------------------- 292 293wxDir::wxDir(const wxString& dirname) 294{ 295 m_data = NULL; 296 297 (void)Open(dirname); 298} 299 300bool wxDir::Open(const wxString& dirname) 301{ 302 delete M_DIR; 303 m_data = new wxDirData(dirname); 304 305 return true; 306} 307 308bool wxDir::IsOpened() const 309{ 310 return m_data != NULL; 311} 312 313wxString 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 335wxDir::~wxDir() 336{ 337 delete M_DIR; 338} 339 340// ---------------------------------------------------------------------------- 341// wxDir enumerating 342// ---------------------------------------------------------------------------- 343 344bool 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 358bool 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 373extern bool 374wxGetDirectoryTimes(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 405