/* Copyright (C) 2012 Sebastian Herbord. All rights reserved. This file is part of Mod Organizer. Mod Organizer is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Mod Organizer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see . */ #ifndef MO_REGISTER_DIRECTORYENTRY_INCLUDED #define MO_REGISTER_DIRECTORYENTRY_INCLUDED #include "fileregister.h" #include namespace env { class DirectoryWalker; struct Directory; struct File; } namespace std { template <> struct hash { using argument_type = MOShared::DirectoryEntryFileKey; using result_type = std::size_t; inline result_type operator()(const argument_type& key) const; }; } namespace MOShared { class DirectoryEntry { public: using FileKey = DirectoryEntryFileKey; DirectoryEntry( std::wstring name, DirectoryEntry *parent, int originID); DirectoryEntry( std::wstring name, DirectoryEntry *parent, int originID, boost::shared_ptr fileRegister, boost::shared_ptr originConnection); // noncopyable DirectoryEntry(const DirectoryEntry&) = delete; DirectoryEntry& operator=(const DirectoryEntry&) = delete; ~DirectoryEntry(); void clear(); bool isPopulated() const { return m_Populated; } bool isTopLevel() const { return m_TopLevel; } bool isEmpty() const { return m_Files.empty() && m_SubDirectories.empty(); } bool hasFiles() const { return !m_Files.empty(); } const DirectoryEntry *getParent() const { return m_Parent; } // add files to this directory (and subdirectories) from the specified origin. // That origin may exist or not void addFromOrigin( const std::wstring &originName, const std::wstring &directory, int priority, DirectoryStats& stats); void addFromOrigin( env::DirectoryWalker& walker, const std::wstring &originName, const std::wstring &directory, int priority, DirectoryStats& stats); void addFromBSA( const std::wstring &originName, std::wstring &directory, const std::wstring &fileName, int priority, int order); void addFromList( const std::wstring &originName, const std::wstring &directory, env::Directory& root, int priority, DirectoryStats& stats); void propagateOrigin(int origin); const std::wstring &getName() const { return m_Name; } boost::shared_ptr getFileRegister() { return m_FileRegister; } bool originExists(const std::wstring &name) const; FilesOrigin &getOriginByID(int ID) const; FilesOrigin &getOriginByName(const std::wstring &name) const; const FilesOrigin* findOriginByID(int ID) const; int anyOrigin() const; std::vector getFiles() const; void getSubDirectories( std::vector::const_iterator &begin, std::vector::const_iterator &end) const { begin = m_SubDirectories.begin(); end = m_SubDirectories.end(); } const std::vector& getSubDirectories() const { return m_SubDirectories; } template void forEachDirectory(F&& f) const { for (auto&& d : m_SubDirectories) { if (!f(*d)) { break; } } } template void forEachFile(F&& f) const { for (auto&& p : m_Files) { if (auto file=m_FileRegister->getFile(p.second)) { if (!f(*file)) { break; } } } } template void forEachFileIndex(F&& f) const { for (auto&& p : m_Files) { if (!f(p.second)) { break; } } } FileEntryPtr getFileByIndex(FileIndex index) const { return m_FileRegister->getFile(index); } DirectoryEntry *findSubDirectory( const std::wstring &name, bool alreadyLowerCase=false) const; DirectoryEntry *findSubDirectoryRecursive(const std::wstring &path); /** retrieve a file in this directory by name. * @param name name of the file * @return fileentry object for the file or nullptr if no file matches */ const FileEntryPtr findFile(const std::wstring &name, bool alreadyLowerCase=false) const; const FileEntryPtr findFile(const FileKey& key) const; bool hasFile(const std::wstring& name) const; bool containsArchive(std::wstring archiveName); // search through this directory and all subdirectories for a file by the // specified name (relative path). // // if directory is not nullptr, the referenced variable will be set to the // path containing the file // const FileEntryPtr searchFile( const std::wstring &path, const DirectoryEntry **directory=nullptr) const; void removeFile(FileIndex index); // remove the specified file from the tree. This can be a path leading to a // file in a subdirectory bool removeFile(const std::wstring &filePath, int *origin = nullptr); /** * @brief remove the specified directory * @param path directory to remove */ void removeDir(const std::wstring &path); bool remove(const std::wstring &fileName, int *origin); bool hasContentsFromOrigin(int originID) const; FilesOrigin &createOrigin( const std::wstring &originName, const std::wstring &directory, int priority, DirectoryStats& stats); void removeFiles(const std::set &indices); void dump(const std::wstring& file) const; private: using FilesMap = std::map; using FilesLookup = std::unordered_map; using SubDirectories = std::vector; using SubDirectoriesLookup = std::unordered_map; boost::shared_ptr m_FileRegister; boost::shared_ptr m_OriginConnection; std::wstring m_Name; FilesMap m_Files; FilesLookup m_FilesLookup; SubDirectories m_SubDirectories; SubDirectoriesLookup m_SubDirectoriesLookup; DirectoryEntry *m_Parent; std::set m_Origins; bool m_Populated; bool m_TopLevel; mutable std::mutex m_SubDirMutex; mutable std::mutex m_FilesMutex; mutable std::mutex m_OriginsMutex; FileEntryPtr insert( std::wstring_view fileName, FilesOrigin &origin, FILETIME fileTime, std::wstring_view archive, int order, DirectoryStats& stats); FileEntryPtr insert( env::File& file, FilesOrigin &origin, std::wstring_view archive, int order, DirectoryStats& stats); void addFiles( env::DirectoryWalker& walker, FilesOrigin &origin, const std::wstring& path, DirectoryStats& stats); void addFiles( FilesOrigin &origin, BSA::Folder::Ptr archiveFolder, FILETIME &fileTime, const std::wstring &archiveName, int order); void addDir(FilesOrigin& origin, env::Directory& d, DirectoryStats& stats); DirectoryEntry* getSubDirectory( std::wstring_view name, bool create, DirectoryStats& stats, int originID = -1); DirectoryEntry* getSubDirectory( env::Directory& dir, bool create, DirectoryStats& stats, int originID = -1); DirectoryEntry* getSubDirectoryRecursive( const std::wstring &path, bool create, int originID = -1); void removeDirRecursive(); void addDirectoryToList(DirectoryEntry* e, std::wstring nameLc); void removeDirectoryFromList(SubDirectories::iterator itor); void addFileToList(std::wstring fileNameLower, FileIndex index); void removeFileFromList(FileIndex index); void removeFilesFromList(const std::set& indices); struct Context; static void onDirectoryStart(Context* cx, std::wstring_view path); static void onDirectoryEnd(Context* cx, std::wstring_view path); static void onFile(Context* cx, std::wstring_view path, FILETIME ft); void dump(std::FILE* f, const std::wstring& parentPath) const; }; } // namespace MOShared namespace std { hash::result_type hash::operator()( const argument_type& key) const { return key.hash; } } #endif // MO_REGISTER_DIRECTORYENTRY_INCLUDED