4 * @brief Implementation file for Directory traversal functions.
7 // ID line follows -- this is updated by SVN
8 // $Id: DirTravel.cpp 5761 2008-08-08 04:54:52Z marcelgosselin $
10 #include "DirTravel.h"
12 #include <Poco/DirectoryIterator.h>
13 #include <Poco/Timestamp.h>
17 #include "UnicodeString.h"
21 using Poco::DirectoryIterator;
22 using Poco::Timestamp;
24 using boost::shared_ptr;
26 static void LoadFiles(const String& sDir, DirItemArray * dirs, DirItemArray * files);
27 static void Sort(DirItemArray * dirs, bool casesensitive);
30 * @brief Load arrays with all directories & files in specified dir
32 void LoadAndSortFiles(const String& sDir, DirItemArray * dirs, DirItemArray * files, bool casesensitive)
34 LoadFiles(sDir, dirs, files);
35 Sort(dirs, casesensitive);
36 Sort(files, casesensitive);
40 * @brief Find files and subfolders from given folder.
41 * This function saves all files and subfolders in given folder to arrays.
42 * We use 64-bit version of stat() to get times since find doesn't return
43 * valid times for very old files (around year 1970). Even stat() seems to
44 * give negative time values but we can live with that. Those around 1970
45 * times can happen when file is created so that it doesn't get valid
46 * creation or modificatio dates.
47 * @param [in] sDir Base folder for files and subfolders.
48 * @param [in, out] dirs Array where subfolders are stored.
49 * @param [in, out] files Array where files are stored.
51 static void LoadFiles(const String& sDir, DirItemArray * dirs, DirItemArray * files)
53 boost::flyweight<String> dir(sDir);
55 DirectoryIterator it(ucr::toUTF8(sDir));
56 DirectoryIterator end;
58 for (; it != end; ++it)
60 bool bIsDirectory = it->isDirectory();
65 ent.ctime = it->created();
68 ent.mtime = it->getLastModified();
71 ent.size = it->getSize();
73 ent.filename = ucr::toTString(it.name());
75 ent.flags.attributes = GetFileAttributes(ucr::toTString(it.name()).c_str());;
79 (bIsDirectory ? dirs : files)->push_back(ent);
83 String sPattern(sDir);
84 size_t len = sPattern.length();
85 if (sPattern[len - 1] != '\\')
86 sPattern += _T("\\*.*");
88 sPattern += _T("*.*");
91 HANDLE h = FindFirstFile(sPattern.c_str(), &ff);
92 if (h != INVALID_HANDLE_VALUE)
96 bool bIsDirectory = (ff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0;
97 if (bIsDirectory && _tcsstr(_T(".."), ff.cFileName))
102 // Save filetimes as seconds since January 1, 1970
103 // Note that times can be < 0 if they are around that 1970..
104 // Anyway that is not sensible case for normal files so we can
105 // just use zero for their time.
106 ent.ctime = Timestamp::fromFileTimeNP(ff.ftCreationTime.dwLowDateTime, ff.ftCreationTime.dwHighDateTime);
109 ent.mtime = Timestamp::fromFileTimeNP(ff.ftLastWriteTime.dwLowDateTime, ff.ftLastWriteTime.dwHighDateTime);
113 if (ff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
114 ent.size = -1; // No size for directories
117 ent.size = ((Int64)ff.nFileSizeHigh << 32) + ff.nFileSizeLow;
121 ent.filename = ff.cFileName;
122 ent.flags.attributes = ff.dwFileAttributes;
124 (bIsDirectory ? dirs : files)->push_back(ent);
125 } while (FindNextFile(h, &ff));
132 static int collate(const String &str1, const String &str2)
134 return _tcscoll(str1.c_str(), str2.c_str());
138 * @brief case-sensitive collate function for qsorting an array
140 static bool __cdecl cmpstring(const DirItem &elem1, const DirItem &elem2)
142 return collate(elem1.GetFileName(), elem2.GetFileName()) < 0;
145 static int collate_ignore_case(const String &str1, const String &str2)
149 String::size_type i = 0;
151 for (i = 0; i < s1.length(); i++)
152 s1[i] = _totlower(s1[i]);
153 for (i = 0; i < s2.length(); i++)
154 s2[i] = _totlower(s2[i]);
156 for (i = 0; i < s1.length(); i++)
158 if (_ismbblead(s1[i]))
161 s1[i] = _totlower(s1[i]);
163 for (i = 0; i < s2.length(); i++)
165 if (_ismbblead(s2[i]))
168 s2[i] = _totlower(s2[i]);
171 return _tcscoll(s1.c_str(), s2.c_str());
175 * @brief case-insensitive collate function for qsorting an array
177 static bool __cdecl cmpistring(const DirItem &elem1, const DirItem &elem2)
179 return collate_ignore_case(elem1.GetFileName(), elem2.GetFileName()) < 0;
183 * @brief sort specified array
185 static void Sort(DirItemArray * dirs, bool casesensitive)
188 std::sort(dirs->begin(), dirs->end(), cmpstring);
190 std::sort(dirs->begin(), dirs->end(), cmpistring);
194 * @brief Compare (NLS aware) two strings, either case-sensitive or
195 * case-insensitive as caller specifies
197 int collstr(const String & s1, const String & s2, bool casesensitive)
200 return collate(s1, s2);
202 return collate_ignore_case(s1, s2);