#include #include #include #include #include "FileList.h" using namespace std; using namespace boost; namespace saracraft { namespace filesystem { namespace { struct Dir; typedef vector StringList; typedef map DirList; typedef vector IteratorList; struct Dir { StringList files; IteratorList subDirs; void AddFile(const string& file) { for(unsigned int i = 0; i < files.size(); ++i) { if(file == files[i]) return; } files.push_back(file); } }; void HaxFile(string& str) { for(unsigned int i = 0; i < str.size(); ++i) { if(str[i] == '\\') str[i] = '/'; } } void ConvertLower(string& str) { for(unsigned int i = 0; i < str.size(); ++i) { str[i] = tolower(str[i]); } } void GetDirPart(const string& file, string& dir) { string::size_type index = file.find_last_of("\\/"); if(index == file.npos) { dir = string(); return; } dir = file.substr(0, index); } int GetDirAmountImpl(const IteratorList& list) { int result = list.size(); /*for(IteratorList::const_iterator it = list.begin(); it != list.end(); ++i) { const DirList::const_iterator& i = *it; result += GetDirAmountImpl(i->second.subDirs); }*/ return result; } int GetDirNameImpl(const IteratorList& list, string& result, int currentIndex, int findIndex) { int original = currentIndex; for(IteratorList::const_iterator it = list.begin(); it != list.end(); ++it) { const DirList::const_iterator& i = *it; if(currentIndex++ == findIndex) { result = i->first; break; } //currentIndex += GetDirNameImpl(i->second.subDirs } return currentIndex - original; } string empty; } // Namespace unamed. struct FileList::Data { bool caseSensitive; DirList dirs; Data(void) : caseSensitive(false) {} // Might want to put some directory hierarchy stuff here? void AddDir(const string& dir) { DirList::iterator it; if(!FindDir(it, dir)) { dirs[dir] = Dir(); FindDir(it, dir); // Add a parent to the list. string current = dir; DirList::iterator currentIt = it; for(int i = 0; ; ++i) { string parent; GetDirPart(current, parent); if(parent.empty()) break; bool needAdd = false; DirList::iterator parentIt; if(!FindDir(parentIt, parent)) { dirs[parent] = Dir(); FindDir(parentIt, parent); needAdd = true; } parentIt->second.subDirs.push_back(currentIt); if(!needAdd) break; current = parent; currentIt = parentIt; } } } bool FindDir(DirList::iterator& it, const string& dir) { it = dirs.find(dir); if(it == dirs.end()) return false; return true; } }; FileList::FileList(void) { scoped_ptr tempData(new Data()); _data.swap(tempData); } FileList::~FileList(void) { } void FileList::SetCaseSensitivity(bool enable) { _data->caseSensitive = enable; } void FileList::AddDir(const string& dir_) { string dir = dir_; if(!_data->caseSensitive) ConvertLower(dir); HaxFile(dir); _data->AddDir(dir); } void FileList::AddFile(const string& file_) { string file = file_; if(!_data->caseSensitive) ConvertLower(file); HaxFile(file); string dir; GetDirPart(file, dir); _data->AddDir(dir); DirList::iterator it; _data->FindDir(it, dir); it->second.AddFile(file); } int FileList::GetDirAmount(const string& root_) const { string root = root_; if(!_data->caseSensitive) ConvertLower(root); HaxFile(root); DirList::iterator it; if(!_data->FindDir(it, root)) return 0; return GetDirAmountImpl(it->second.subDirs); } string FileList::GetDirName(const string& root_, int index) const { string root = root_; if(!_data->caseSensitive) ConvertLower(root); HaxFile(root); DirList::iterator it; if(!_data->FindDir(it, root)) return empty; string result; GetDirNameImpl(it->second.subDirs, result, 0, index); return result; } int FileList::GetFileAmount(const string& root_) const { string root = root_; if(!_data->caseSensitive) ConvertLower(root); HaxFile(root); DirList::iterator it; if(!_data->FindDir(it, root)) return 0; return it->second.files.size(); } const string& FileList::GetFileName(const string& root_, int index) const { string root = root_; if(!_data->caseSensitive) ConvertLower(root); HaxFile(root); DirList::iterator it; if(!_data->FindDir(it, root)) return empty; return it->second.files[index]; } // ============================================================ namespace { void GetAllFilesImpl(IFileList& list, const string& root, vector& result, bool recurse) { //if(root.find(" // The hell is your problem?! int fileAmount = list.GetFileAmount(root); for(int i = 0; i < fileAmount; ++i) { const string& file = list.GetFileName(root, i); result.push_back(file); } if(recurse) { int dirAmount = list.GetDirAmount(root); for(int i = 0; i < dirAmount; ++i) { const string& dir = list.GetDirName(root, i); if(dir.length() > 4 && dir.substr(dir.length() - 4, 4) == ".svn") { // We should never even get here.. } else { GetAllFilesImpl(list, dir, result, recurse); } } } } void GetAllDirsImpl(IFileList& list, const string& root, vector& result, bool recurse) { int dirAmount = list.GetDirAmount(root); for(int i = 0; i < dirAmount; ++i) { const string& dir = list.GetDirName(root, i); if(dir.length() > 4 && dir.substr(dir.length() - 4, 4) == ".svn") { // We should never even get here.. } else { result.push_back(dir); if(recurse) GetAllDirsImpl(list, dir, result, recurse); } } } } // Unamed namespace. void GetAllFiles(IFileList& list, const string& root_, vector& result, bool recurse, bool caseSensitive) { string root = root_; if(!caseSensitive) ConvertLower(root); HaxFile(root); GetAllFilesImpl(list, root, result, recurse); std::sort(result.begin(), result.end()); } void GetAllDirs(IFileList& list, const string& root_, vector& result, bool recurse, bool caseSensitive) { string root = root_; if(!caseSensitive) ConvertLower(root); HaxFile(root); GetAllDirsImpl(list, root, result, recurse); std::sort(result.begin(), result.end()); } } // Namespace filesystem. } // Namespace saracraft.