278 lines
7.9 KiB
C++
Executable File
278 lines
7.9 KiB
C++
Executable File
#include "IEntryEnumerator.h"
|
|
|
|
#include <string>
|
|
#include <cstring>
|
|
#include <stack>
|
|
|
|
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
|
#include <glob.h>
|
|
#include <sys/stat.h>
|
|
#elif defined TARGET_OS_Windows
|
|
#ifndef UNICODE
|
|
#define UNICODE
|
|
#endif
|
|
#include <Windows.h>
|
|
#include <codecvt>
|
|
#include <locale>
|
|
#else
|
|
#endif
|
|
|
|
#include <iostream>
|
|
|
|
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<globStruc.gl_pathc)
|
|
{
|
|
char* name=globStruc.gl_pathv[i];
|
|
CEntry entry(name);
|
|
CAttributes att;
|
|
|
|
struct stat sL;
|
|
struct stat s;
|
|
if(!lstat(name, &sL) && !stat(name, &s))
|
|
{
|
|
att.m_IsDirectory = S_ISDIR(s.st_mode) ? true : false;
|
|
att.m_IsFile = S_ISREG(s.st_mode) ? true : false;
|
|
att.m_IsSymbolicLink = S_ISLNK(sL.st_mode) ? true : false;
|
|
|
|
att.m_IsArchive = false;
|
|
att.m_IsReadOnly = s.st_mode&S_IWUSR ? false : true;
|
|
att.m_IsHidden = false;
|
|
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;
|
|
att.m_IsExecutable = s.st_mode&S_IXUSR ? true : false;
|
|
|
|
att.m_Size=s.st_size;
|
|
|
|
// Sends to callback
|
|
if(!m_entryEnumeratorCB.callback(entry, att)) { finished=true; }
|
|
}
|
|
i++;
|
|
}
|
|
else { finished = true; }
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#elif defined TARGET_OS_Windows
|
|
|
|
bool CEntryEnumeratorWindows::enumerate(const char* sWildCard, bool bRecursive)
|
|
{
|
|
if (!sWildCard || strlen(sWildCard) == 0) { return false; }
|
|
|
|
wchar_t wildCardUtf16[1024];
|
|
MultiByteToWideChar(CP_UTF8, 0, sWildCard, -1, wildCardUtf16, 1024);
|
|
|
|
// $$$ TODO
|
|
// $$$ Find better method to enumerate files
|
|
// $$$ under windows including their initial path
|
|
// $$$ (cFileName member of WIN32_FIND_DATA structure
|
|
// $$$ loses the initial path !!)
|
|
// $$$ TODO
|
|
wchar_t extendedWildCard[1024];
|
|
wchar_t* extendedWildCardFilename = nullptr;
|
|
GetFullPathName(wildCardUtf16, 1024, extendedWildCard, &extendedWildCardFilename);
|
|
std::wstring path(wildCardUtf16, wcslen(wildCardUtf16) - (extendedWildCardFilename ? wcslen(extendedWildCardFilename) : 0));
|
|
|
|
std::stack<std::wstring> foldersToEnumerate;
|
|
foldersToEnumerate.push(path);
|
|
|
|
// if we need to recurse over subfolders, let's fetch all subfolders in foldersToEnumerate
|
|
if (bRecursive)
|
|
{
|
|
std::stack<std::wstring> 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<std::codecvt_utf8<wchar_t>> 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
|