#include "IEntryEnumerator.h" #include #include #include #if defined TARGET_OS_Linux || defined TARGET_OS_MacOS #include #include #elif defined TARGET_OS_Windows #ifndef UNICODE #define UNICODE #endif #include #include #include #else #endif #include namespace FS { class CEntry final : public IEntryEnumerator::IEntry { public: explicit CEntry(const std::string& name) : m_Name(name) {} const char* getName() override { return m_Name.c_str(); } std::string m_Name; }; class CAttributes final : public IEntryEnumerator::IAttributes { public: CAttributes() {} ~CAttributes() override {} bool isFile() override { return m_IsFile; } bool isDirectory() override { return m_IsDirectory; } bool isSymbolicLink() override { return m_IsSymbolicLink; } bool isArchive() override { return m_IsArchive; } bool isReadOnly() override { return m_IsReadOnly; } bool isHidden() override { return m_IsHidden; } bool isSystem() override { return m_IsSystem; } bool isExecutable() override { return m_IsExecutable; } size_t getSize() override { return m_Size; } bool m_IsFile = false; bool m_IsDirectory = false; bool m_IsSymbolicLink = false; bool m_IsArchive = false; bool m_IsReadOnly = false; bool m_IsHidden = false; bool m_IsSystem = false; bool m_IsExecutable = false; size_t m_Size = 0; }; class CEntryEnumerator : public IEntryEnumerator { public: explicit CEntryEnumerator(IEntryEnumeratorCallBack& rEntryEnumeratorCallBack) : m_entryEnumeratorCB(rEntryEnumeratorCallBack) {} void release() override { delete this; } protected: IEntryEnumeratorCallBack& m_entryEnumeratorCB; }; #if defined TARGET_OS_Linux || defined TARGET_OS_MacOS class CEntryEnumeratorLinux final : public CEntryEnumerator { public: CEntryEnumeratorLinux(IEntryEnumeratorCallBack& rEntryEnumeratorCallBack) : CEntryEnumerator(rEntryEnumeratorCallBack) { } virtual bool enumerate(const char* sWildCard, bool bRecursive=false); }; #elif defined TARGET_OS_Windows class CEntryEnumeratorWindows final : public CEntryEnumerator { public: explicit CEntryEnumeratorWindows(IEntryEnumeratorCallBack& rEntryEnumeratorCallBack) : CEntryEnumerator(rEntryEnumeratorCallBack) {} bool enumerate(const char* sWildCard, bool bRecursive = false) override; }; #else class CEntryEnumeratorDummy : public CEntryEnumerator { public: explicit CEntryEnumeratorDummy(IEntryEnumeratorCallBack& rEntryEnumeratorCallBack) : CEntryEnumerator(rEntryEnumeratorCallBack) { } virtual bool enumerate(const char* sWildCard, bool bRecursive=false) { return !sWildCard ? false : true; } }; #endif #if defined TARGET_OS_Linux || defined TARGET_OS_MacOS bool CEntryEnumeratorLinux::enumerate(const char* sWildCard, bool bRecursive) { if(!sWildCard) { return false; } glob_t globStruc; memset(&globStruc, GLOB_NOSORT, sizeof(globStruc)); // Glob can retrn switch (glob(sWildCard, 0, nullptr, &globStruc)) { case GLOB_NOSPACE: case GLOB_ABORTED: return false; break; case GLOB_NOMATCH: return true; break; default: break; } if(globStruc.gl_pathc<=0) { // Nothing found return true; } size_t i=0; bool finished=false; while(!finished) { if(i foldersToEnumerate; foldersToEnumerate.push(path); // if we need to recurse over subfolders, let's fetch all subfolders in foldersToEnumerate if (bRecursive) { std::stack temporaryFolderSearchStack; temporaryFolderSearchStack.push(path); std::wstring currentSearchPath; while (! temporaryFolderSearchStack.empty()) { currentSearchPath = temporaryFolderSearchStack.top(); temporaryFolderSearchStack.pop(); WIN32_FIND_DATA findData; HANDLE fileHandle; fileHandle = FindFirstFile((currentSearchPath + L"*").c_str(), &findData); if (fileHandle != INVALID_HANDLE_VALUE) { bool finished = false; while (!finished) { if (std::wstring(findData.cFileName) != L"." && std::wstring(findData.cFileName) != L"..") { if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { foldersToEnumerate.push(currentSearchPath + findData.cFileName + L"/"); temporaryFolderSearchStack.push(currentSearchPath + findData.cFileName + L"/"); } } if (!FindNextFile(fileHandle, &findData)) { finished = true; } } FindClose(fileHandle); } } } std::wstring_convert> converter; std::wstring currentPath; while (! foldersToEnumerate.empty()) { currentPath = foldersToEnumerate.top(); foldersToEnumerate.pop(); WIN32_FIND_DATA findData; HANDLE fileHandle; fileHandle = FindFirstFile((currentPath + extendedWildCardFilename).c_str(), &findData); if (fileHandle != INVALID_HANDLE_VALUE) { bool finished = false; while (!finished) { std::string entryName = converter.to_bytes(currentPath + findData.cFileName); CEntry entry(entryName); CAttributes attributes; attributes.m_IsDirectory = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false; attributes.m_IsFile = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? false : true; attributes.m_IsSymbolicLink = false; attributes.m_IsArchive = (findData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? true : false; attributes.m_IsReadOnly = (findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? true : false; attributes.m_IsHidden = (findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? true : false; attributes.m_IsSystem = (findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? true : false; attributes.m_IsExecutable = false; // TODO attributes.m_Size = (findData.nFileSizeHigh << 16) + findData.nFileSizeLow; // Sends to callback if (!m_entryEnumeratorCB.callback(entry, attributes)) { finished = true; } if (!FindNextFile(fileHandle, &findData)) { finished = true; } } FindClose(fileHandle); } } return true; } #endif FS_API IEntryEnumerator* createEntryEnumerator(IEntryEnumeratorCallBack& rCallBack) { #if defined TARGET_OS_Linux || defined TARGET_OS_MacOS IEntryEnumerator* res = new CEntryEnumeratorLinux(rCallBack); #elif defined TARGET_OS_Windows IEntryEnumerator* res = new CEntryEnumeratorWindows(rCallBack); #else IEntryEnumerator* res = new CEntryEnumeratorDummy(rCallBack); #endif return res; } } // namespace FS