4 * @brief Implementation file for Directory traversal functions.
11 #include <Poco/DirectoryIterator.h>
12 #include <Poco/Timestamp.h>
16 #include "UnicodeString.h"
21 using Poco::DirectoryIterator;
22 using Poco::Timestamp;
24 static void LoadFiles(const String& sDir, DirItemArray * dirs, DirItemArray * files);
25 static void Sort(DirItemArray * dirs, bool casesensitive);
28 * @brief Load arrays with all directories & files in specified dir
30 void LoadAndSortFiles(const String& sDir, DirItemArray * dirs, DirItemArray * files, bool casesensitive)
32 LoadFiles(sDir, dirs, files);
33 Sort(dirs, casesensitive);
34 Sort(files, casesensitive);
38 * @brief Find files and subfolders from given folder.
39 * This function saves all files and subfolders in given folder to arrays.
40 * We use 64-bit version of stat() to get times since find doesn't return
41 * valid times for very old files (around year 1970). Even stat() seems to
42 * give negative time values but we can live with that. Those around 1970
43 * times can happen when file is created so that it doesn't get valid
44 * creation or modificatio dates.
45 * @param [in] sDir Base folder for files and subfolders.
46 * @param [in, out] dirs Array where subfolders are stored.
47 * @param [in, out] files Array where files are stored.
49 static void LoadFiles(const String& sDir, DirItemArray * dirs, DirItemArray * files)
51 boost::flyweight<String> dir(sDir);
53 DirectoryIterator it(ucr::toUTF8(sDir));
54 DirectoryIterator end;
56 for (; it != end; ++it)
58 bool bIsDirectory = it->isDirectory();
63 ent.ctime = it->created();
66 ent.mtime = it->getLastModified();
69 ent.size = it->getSize();
71 ent.filename = ucr::toTString(it.name());
73 ent.flags.attributes = GetFileAttributes(ucr::toTString(it.name()).c_str());;
77 (bIsDirectory ? dirs : files)->push_back(ent);
81 String sPattern = paths::ConcatPath(sDir, _T("*.*"));
86 vi.dwOSVersionInfoSize = sizeof(vi);
89 poco_assert(wcsncmp(sPattern.c_str(), L"\\\\?\\", 4) != 0); // Prefix better not be there yet
90 if (vi.dwMajorVersion * 10 + vi.dwMinorVersion >= 61)
91 h = FindFirstFileEx((L"\\\\?\\" + sPattern).c_str(), FindExInfoBasic, &ff, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);
93 h = FindFirstFile((L"\\\\?\\" + sPattern).c_str(), &ff);
94 if (h != INVALID_HANDLE_VALUE)
98 bool bIsDirectory = (ff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0;
99 if (bIsDirectory && _tcsstr(_T(".."), ff.cFileName))
104 // Save filetimes as seconds since January 1, 1970
105 // Note that times can be < 0 if they are around that 1970..
106 // Anyway that is not sensible case for normal files so we can
107 // just use zero for their time.
108 ent.ctime = Timestamp::fromFileTimeNP(ff.ftCreationTime.dwLowDateTime, ff.ftCreationTime.dwHighDateTime);
111 ent.mtime = Timestamp::fromFileTimeNP(ff.ftLastWriteTime.dwLowDateTime, ff.ftLastWriteTime.dwHighDateTime);
115 if (ff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
116 ent.size = DirItem::FILE_SIZE_NONE; // No size for directories
119 ent.size = ((int64_t)ff.nFileSizeHigh << 32) + ff.nFileSizeLow;
123 ent.filename = ff.cFileName;
124 ent.flags.attributes = ff.dwFileAttributes;
126 (bIsDirectory ? dirs : files)->push_back(ent);
127 } while (FindNextFile(h, &ff));
134 static inline int collate(const String &str1, const String &str2)
136 return _tcscoll(str1.c_str(), str2.c_str());
139 static inline int collate_ignore_case(const String &str1, const String &str2)
141 return _tcsicoll(str1.c_str(), str2.c_str());
145 template<int (*compfunc)(const TCHAR *, const TCHAR *)>
146 struct StringComparer
148 bool operator()(const DirItem &elem1, const DirItem &elem2)
150 return compfunc(elem1.filename.get().c_str(), elem2.filename.get().c_str()) < 0;
155 * @brief sort specified array
157 static void Sort(DirItemArray * dirs, bool casesensitive)
160 std::sort(dirs->begin(), dirs->end(), StringComparer<_tcscoll>());
162 std::sort(dirs->begin(), dirs->end(), StringComparer<_tcsicoll>());
166 * @brief Compare (NLS aware) two strings, either case-sensitive or
167 * case-insensitive as caller specifies
169 int collstr(const String & s1, const String & s2, bool casesensitive)
172 return collate(s1, s2);
174 return collate_ignore_case(s1, s2);