You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IEntryEnumerator.cpp 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #include "IEntryEnumerator.h"
  2. #include <string>
  3. #include <cstring>
  4. #include <stack>
  5. #if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
  6. #include <glob.h>
  7. #include <sys/stat.h>
  8. #elif defined TARGET_OS_Windows
  9. #ifndef UNICODE
  10. #define UNICODE
  11. #endif
  12. #include <Windows.h>
  13. #include <codecvt>
  14. #include <locale>
  15. #else
  16. #endif
  17. #include <iostream>
  18. namespace FS {
  19. class CEntry final : public IEntryEnumerator::IEntry
  20. {
  21. public:
  22. explicit CEntry(const std::string& name) : m_Name(name) {}
  23. const char* getName() override { return m_Name.c_str(); }
  24. std::string m_Name;
  25. };
  26. class CAttributes final : public IEntryEnumerator::IAttributes
  27. {
  28. public:
  29. CAttributes() {}
  30. ~CAttributes() override {}
  31. bool isFile() override { return m_IsFile; }
  32. bool isDirectory() override { return m_IsDirectory; }
  33. bool isSymbolicLink() override { return m_IsSymbolicLink; }
  34. bool isArchive() override { return m_IsArchive; }
  35. bool isReadOnly() override { return m_IsReadOnly; }
  36. bool isHidden() override { return m_IsHidden; }
  37. bool isSystem() override { return m_IsSystem; }
  38. bool isExecutable() override { return m_IsExecutable; }
  39. size_t getSize() override { return m_Size; }
  40. bool m_IsFile = false;
  41. bool m_IsDirectory = false;
  42. bool m_IsSymbolicLink = false;
  43. bool m_IsArchive = false;
  44. bool m_IsReadOnly = false;
  45. bool m_IsHidden = false;
  46. bool m_IsSystem = false;
  47. bool m_IsExecutable = false;
  48. size_t m_Size = 0;
  49. };
  50. class CEntryEnumerator : public IEntryEnumerator
  51. {
  52. public:
  53. explicit CEntryEnumerator(IEntryEnumeratorCallBack& rEntryEnumeratorCallBack) : m_entryEnumeratorCB(rEntryEnumeratorCallBack) {}
  54. void release() override { delete this; }
  55. protected:
  56. IEntryEnumeratorCallBack& m_entryEnumeratorCB;
  57. };
  58. #if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
  59. class CEntryEnumeratorLinux final : public CEntryEnumerator
  60. {
  61. public:
  62. CEntryEnumeratorLinux(IEntryEnumeratorCallBack& rEntryEnumeratorCallBack) : CEntryEnumerator(rEntryEnumeratorCallBack) { }
  63. virtual bool enumerate(const char* sWildCard, bool bRecursive=false);
  64. };
  65. #elif defined TARGET_OS_Windows
  66. class CEntryEnumeratorWindows final : public CEntryEnumerator
  67. {
  68. public:
  69. explicit CEntryEnumeratorWindows(IEntryEnumeratorCallBack& rEntryEnumeratorCallBack) : CEntryEnumerator(rEntryEnumeratorCallBack) {}
  70. bool enumerate(const char* sWildCard, bool bRecursive = false) override;
  71. };
  72. #else
  73. class CEntryEnumeratorDummy : public CEntryEnumerator
  74. {
  75. public:
  76. explicit CEntryEnumeratorDummy(IEntryEnumeratorCallBack& rEntryEnumeratorCallBack) : CEntryEnumerator(rEntryEnumeratorCallBack) { }
  77. virtual bool enumerate(const char* sWildCard, bool bRecursive=false) { return !sWildCard ? false : true; }
  78. };
  79. #endif
  80. #if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
  81. bool CEntryEnumeratorLinux::enumerate(const char* sWildCard, bool bRecursive)
  82. {
  83. if(!sWildCard) { return false; }
  84. glob_t globStruc;
  85. memset(&globStruc, GLOB_NOSORT, sizeof(globStruc));
  86. // Glob can retrn
  87. switch (glob(sWildCard, 0, nullptr, &globStruc))
  88. {
  89. case GLOB_NOSPACE:
  90. case GLOB_ABORTED:
  91. return false;
  92. break;
  93. case GLOB_NOMATCH:
  94. return true;
  95. break;
  96. default:
  97. break;
  98. }
  99. if(globStruc.gl_pathc<=0)
  100. {
  101. // Nothing found
  102. return true;
  103. }
  104. size_t i=0;
  105. bool finished=false;
  106. while(!finished)
  107. {
  108. if(i<globStruc.gl_pathc)
  109. {
  110. char* name=globStruc.gl_pathv[i];
  111. CEntry entry(name);
  112. CAttributes att;
  113. struct stat sL;
  114. struct stat s;
  115. if(!lstat(name, &sL) && !stat(name, &s))
  116. {
  117. att.m_IsDirectory = S_ISDIR(s.st_mode) ? true : false;
  118. att.m_IsFile = S_ISREG(s.st_mode) ? true : false;
  119. att.m_IsSymbolicLink = S_ISLNK(sL.st_mode) ? true : false;
  120. att.m_IsArchive = false;
  121. att.m_IsReadOnly = s.st_mode&S_IWUSR ? false : true;
  122. att.m_IsHidden = false;
  123. att.m_IsSystem = S_ISBLK(s.st_mode)|S_ISFIFO(s.st_mode)|S_ISSOCK(s.st_mode)|S_ISCHR(s.st_mode) ? true : false;
  124. att.m_IsExecutable = s.st_mode&S_IXUSR ? true : false;
  125. att.m_Size=s.st_size;
  126. // Sends to callback
  127. if(!m_entryEnumeratorCB.callback(entry, att)) { finished=true; }
  128. }
  129. i++;
  130. }
  131. else { finished = true; }
  132. }
  133. return true;
  134. }
  135. #elif defined TARGET_OS_Windows
  136. bool CEntryEnumeratorWindows::enumerate(const char* sWildCard, bool bRecursive)
  137. {
  138. if (!sWildCard || strlen(sWildCard) == 0) { return false; }
  139. wchar_t wildCardUtf16[1024];
  140. MultiByteToWideChar(CP_UTF8, 0, sWildCard, -1, wildCardUtf16, 1024);
  141. // $$$ TODO
  142. // $$$ Find better method to enumerate files
  143. // $$$ under windows including their initial path
  144. // $$$ (cFileName member of WIN32_FIND_DATA structure
  145. // $$$ loses the initial path !!)
  146. // $$$ TODO
  147. wchar_t extendedWildCard[1024];
  148. wchar_t* extendedWildCardFilename = nullptr;
  149. GetFullPathName(wildCardUtf16, 1024, extendedWildCard, &extendedWildCardFilename);
  150. std::wstring path(wildCardUtf16, wcslen(wildCardUtf16) - (extendedWildCardFilename ? wcslen(extendedWildCardFilename) : 0));
  151. std::stack<std::wstring> foldersToEnumerate;
  152. foldersToEnumerate.push(path);
  153. // if we need to recurse over subfolders, let's fetch all subfolders in foldersToEnumerate
  154. if (bRecursive)
  155. {
  156. std::stack<std::wstring> temporaryFolderSearchStack;
  157. temporaryFolderSearchStack.push(path);
  158. std::wstring currentSearchPath;
  159. while (! temporaryFolderSearchStack.empty())
  160. {
  161. currentSearchPath = temporaryFolderSearchStack.top();
  162. temporaryFolderSearchStack.pop();
  163. WIN32_FIND_DATA findData;
  164. HANDLE fileHandle;
  165. fileHandle = FindFirstFile((currentSearchPath + L"*").c_str(), &findData);
  166. if (fileHandle != INVALID_HANDLE_VALUE)
  167. {
  168. bool finished = false;
  169. while (!finished)
  170. {
  171. if (std::wstring(findData.cFileName) != L"." && std::wstring(findData.cFileName) != L"..")
  172. {
  173. if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  174. {
  175. foldersToEnumerate.push(currentSearchPath + findData.cFileName + L"/");
  176. temporaryFolderSearchStack.push(currentSearchPath + findData.cFileName + L"/");
  177. }
  178. }
  179. if (!FindNextFile(fileHandle, &findData)) { finished = true; }
  180. }
  181. FindClose(fileHandle);
  182. }
  183. }
  184. }
  185. std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
  186. std::wstring currentPath;
  187. while (! foldersToEnumerate.empty())
  188. {
  189. currentPath = foldersToEnumerate.top();
  190. foldersToEnumerate.pop();
  191. WIN32_FIND_DATA findData;
  192. HANDLE fileHandle;
  193. fileHandle = FindFirstFile((currentPath + extendedWildCardFilename).c_str(), &findData);
  194. if (fileHandle != INVALID_HANDLE_VALUE)
  195. {
  196. bool finished = false;
  197. while (!finished)
  198. {
  199. std::string entryName = converter.to_bytes(currentPath + findData.cFileName);
  200. CEntry entry(entryName);
  201. CAttributes attributes;
  202. attributes.m_IsDirectory = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false;
  203. attributes.m_IsFile = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? false : true;
  204. attributes.m_IsSymbolicLink = false;
  205. attributes.m_IsArchive = (findData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? true : false;
  206. attributes.m_IsReadOnly = (findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? true : false;
  207. attributes.m_IsHidden = (findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? true : false;
  208. attributes.m_IsSystem = (findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? true : false;
  209. attributes.m_IsExecutable = false; // TODO
  210. attributes.m_Size = (findData.nFileSizeHigh << 16) + findData.nFileSizeLow;
  211. // Sends to callback
  212. if (!m_entryEnumeratorCB.callback(entry, attributes)) { finished = true; }
  213. if (!FindNextFile(fileHandle, &findData)) { finished = true; }
  214. }
  215. FindClose(fileHandle);
  216. }
  217. }
  218. return true;
  219. }
  220. #endif
  221. FS_API IEntryEnumerator* createEntryEnumerator(IEntryEnumeratorCallBack& rCallBack)
  222. {
  223. #if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
  224. IEntryEnumerator* res = new CEntryEnumeratorLinux(rCallBack);
  225. #elif defined TARGET_OS_Windows
  226. IEntryEnumerator* res = new CEntryEnumeratorWindows(rCallBack);
  227. #else
  228. IEntryEnumerator* res = new CEntryEnumeratorDummy(rCallBack);
  229. #endif
  230. return res;
  231. }
  232. } // namespace FS