summaryrefslogtreecommitdiff
path: root/src/shared/directoryentry.h
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2020-02-09 08:52:03 -0500
committerGitHub <noreply@github.com>2020-02-09 08:52:03 -0500
commit1f1f99f253f981ae3d11e9df177a144d00dbce0e (patch)
tree01d38125329508f5628f9221f797e303180c8fc3 /src/shared/directoryentry.h
parent718c2a56f91f824c5eab69d8cc16294f77243370 (diff)
parent3a80685189967fbf4cfa002ac2b8a4fa421306ca (diff)
Merge pull request #994 from isanae/generic-file-list
New file tree
Diffstat (limited to 'src/shared/directoryentry.h')
-rw-r--r--src/shared/directoryentry.h461
1 files changed, 327 insertions, 134 deletions
diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h
index 785c3ff6..e26011d7 100644
--- a/src/shared/directoryentry.h
+++ b/src/shared/directoryentry.h
@@ -35,128 +35,211 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#endif
#include "util.h"
+namespace MOShared { struct DirectoryEntryFileKey; }
-namespace MOShared {
+namespace std
+{
+ template <>
+ struct hash<MOShared::DirectoryEntryFileKey>
+ {
+ using argument_type = MOShared::DirectoryEntryFileKey;
+ using result_type = std::size_t;
+
+ inline result_type operator()(const argument_type& key) const;
+ };
+}
+namespace MOShared
+{
+
class DirectoryEntry;
class OriginConnection;
class FileRegister;
-class FileEntry {
-
+class FileEntry
+{
public:
+ static constexpr uint64_t NoFileSize =
+ std::numeric_limits<uint64_t>::max();
typedef unsigned int Index;
typedef boost::shared_ptr<FileEntry> Ptr;
- typedef std::vector<std::pair<int, std::pair<std::wstring, int>>> AlternativesVector;
-public:
+ // a vector of {originId, {archiveName, order}}
+ //
+ // if a file is in an archive, archiveName is the name of the bsa and order
+ // is the order of the associated plugin in the plugins list
+ //
+ // is a file is not in an archive, archiveName is empty and order is usually
+ // -1
+ typedef std::vector<std::pair<int, std::pair<std::wstring, int>>>
+ AlternativesVector;
FileEntry();
-
FileEntry(Index index, const std::wstring &name, DirectoryEntry *parent);
- ~FileEntry();
+ Index getIndex() const
+ {
+ return m_Index;
+ }
- Index getIndex() const { return m_Index; }
+ time_t lastAccessed() const
+ {
+ return m_LastAccessed;
+ }
- time_t lastAccessed() const { return m_LastAccessed; }
+ void addOrigin(
+ int origin, FILETIME fileTime, const std::wstring &archive, int order);
- void addOrigin(int origin, FILETIME fileTime, const std::wstring &archive, int order);
- // remove the specified origin from the list of origins that contain this file. if no origin is left,
- // the file is effectively deleted and true is returned. otherwise, false is returned
+ // remove the specified origin from the list of origins that contain this
+ // file. if no origin is left, the file is effectively deleted and true is
+ // returned. otherwise, false is returned
bool removeOrigin(int origin);
+
void sortOrigins();
- // gets the list of alternative origins (origins with lower priority than the primary one).
- // if sortOrigins has been called, it is sorted by priority (ascending)
- const AlternativesVector &getAlternatives() const { return m_Alternatives; }
+ // gets the list of alternative origins (origins with lower priority than
+ // the primary one). if sortOrigins has been called, it is sorted by priority
+ // (ascending)
+ const AlternativesVector &getAlternatives() const
+ {
+ return m_Alternatives;
+ }
+
+ const std::wstring &getName() const
+ {
+ return m_Name;
+ }
+
+ int getOrigin() const
+ {
+ return m_Origin;
+ }
+
+ int getOrigin(bool &archive) const
+ {
+ archive = (m_Archive.first.length() != 0);
+ return m_Origin;
+ }
+
+ const std::pair<std::wstring, int> &getArchive() const
+ {
+ return m_Archive;
+ }
+
+ bool isFromArchive(std::wstring archiveName = L"") const;
+
+ // if originID is -1, uses the main origin; if this file doesn't exist in the
+ // given origin, returns an empty string
+ //
+ std::wstring getFullPath(int originID=-1) const;
- const std::wstring &getName() const { return m_Name; }
- int getOrigin() const { return m_Origin; }
- int getOrigin(bool &archive) const { archive = (m_Archive.first.length() != 0); return m_Origin; }
- const std::pair<std::wstring, int> &getArchive() const { return m_Archive; }
- bool isFromArchive(std::wstring archiveName = L"");
- std::wstring getFullPath() const;
std::wstring getRelativePath() const;
- DirectoryEntry *getParent() { return m_Parent; }
- void setFileTime(FILETIME fileTime) const { m_FileTime = fileTime; }
- FILETIME getFileTime() const { return m_FileTime; }
+ DirectoryEntry *getParent()
+ {
+ return m_Parent;
+ }
-private:
+ void setFileTime(FILETIME fileTime) const
+ {
+ m_FileTime = fileTime;
+ }
- bool recurseParents(std::wstring &path, const DirectoryEntry *parent) const;
+ FILETIME getFileTime() const
+ {
+ return m_FileTime;
+ }
- void determineTime();
+ void setFileSize(uint64_t size, uint64_t compressedSize)
+ {
+ m_FileSize = size;
+ m_CompressedFileSize = compressedSize;
+ }
-private:
+ uint64_t getFileSize() const
+ {
+ return m_FileSize;
+ }
+
+ uint64_t getCompressedFileSize() const
+ {
+ return m_CompressedFileSize;
+ }
+private:
Index m_Index;
std::wstring m_Name;
- int m_Origin = -1;
+ int m_Origin;
std::pair<std::wstring, int> m_Archive;
AlternativesVector m_Alternatives;
DirectoryEntry *m_Parent;
mutable FILETIME m_FileTime;
+ uint64_t m_FileSize, m_CompressedFileSize;
time_t m_LastAccessed;
- friend bool operator<(const FileEntry &lhs, const FileEntry &rhs) {
- return _wcsicmp(lhs.m_Name.c_str(), rhs.m_Name.c_str()) < 0;
- }
- friend bool operator==(const FileEntry &lhs, const FileEntry &rhs) {
- return _wcsicmp(lhs.m_Name.c_str(), rhs.m_Name.c_str()) == 0;
- }
+ bool recurseParents(std::wstring &path, const DirectoryEntry *parent) const;
};
// represents a mod or the data directory, providing files to the tree
-class FilesOrigin {
+class FilesOrigin
+{
friend class OriginConnection;
-public:
+public:
FilesOrigin();
FilesOrigin(const FilesOrigin &reference);
- ~FilesOrigin();
- // sets priority for this origin, but it will overwrite the exisiting mapping for this priority,
- // the previous origin will no longer be referenced
+ // sets priority for this origin, but it will overwrite the existing mapping
+ // for this priority, the previous origin will no longer be referenced
void setPriority(int priority);
- int getPriority() const { return m_Priority; }
+ int getPriority() const
+ {
+ return m_Priority;
+ }
void setName(const std::wstring &name);
- const std::wstring &getName() const { return m_Name; }
+ const std::wstring &getName() const
+ {
+ return m_Name;
+ }
- int getID() const { return m_ID; }
- const std::wstring &getPath() const { return m_Path; }
+ int getID() const
+ {
+ return m_ID;
+ }
+
+ const std::wstring &getPath() const
+ {
+ return m_Path;
+ }
std::vector<FileEntry::Ptr> getFiles() const;
FileEntry::Ptr findFile(FileEntry::Index index) const;
void enable(bool enabled, time_t notAfter = LONG_MAX);
- bool isDisabled() const { return m_Disabled; }
+ bool isDisabled() const
+ {
+ return m_Disabled;
+ }
+
+ void addFile(FileEntry::Index index)
+ {
+ m_Files.insert(index);
+ }
- void addFile(FileEntry::Index index) { m_Files.insert(index); }
void removeFile(FileEntry::Index index);
bool containsArchive(std::wstring archiveName);
private:
-
- FilesOrigin(int ID, const std::wstring &name, const std::wstring &path, int priority,
- boost::shared_ptr<FileRegister> fileRegister, boost::shared_ptr<OriginConnection> originConnection);
-
-
-private:
-
int m_ID;
-
bool m_Disabled;
-
std::set<FileEntry::Index> m_Files;
std::wstring m_Name;
std::wstring m_Path;
@@ -164,23 +247,27 @@ private:
boost::weak_ptr<FileRegister> m_FileRegister;
boost::weak_ptr<OriginConnection> m_OriginConnection;
+ FilesOrigin(
+ int ID, const std::wstring &name, const std::wstring &path, int priority,
+ boost::shared_ptr<FileRegister> fileRegister,
+ boost::shared_ptr<OriginConnection> originConnection);
};
class FileRegister
{
-
public:
-
FileRegister(boost::shared_ptr<OriginConnection> originConnection);
- ~FileRegister();
bool indexValid(FileEntry::Index index) const;
FileEntry::Ptr createFile(const std::wstring &name, DirectoryEntry *parent);
FileEntry::Ptr getFile(FileEntry::Index index) const;
- size_t size() const { return m_Files.size(); }
+ size_t size() const
+ {
+ return m_Files.size();
+ }
bool removeFile(FileEntry::Index index);
void removeOrigin(FileEntry::Index index, int originID);
@@ -189,84 +276,189 @@ public:
void sortOrigins();
private:
+ std::map<FileEntry::Index, FileEntry::Ptr> m_Files;
+ boost::shared_ptr<OriginConnection> m_OriginConnection;
FileEntry::Index generateIndex();
-
void unregisterFile(FileEntry::Ptr file);
+};
-private:
- std::map<FileEntry::Index, FileEntry::Ptr> m_Files;
+struct DirectoryEntryFileKey
+{
+ DirectoryEntryFileKey(std::wstring v)
+ : value(std::move(v)), hash(getHash(value))
+ {
+ }
- boost::shared_ptr<OriginConnection> m_OriginConnection;
+ bool operator==(const DirectoryEntryFileKey& o) const
+ {
+ return (value == o.value);
+ }
+
+ static std::size_t getHash(const std::wstring& value)
+ {
+ return std::hash<std::wstring>()(value);
+ }
+ const std::wstring value;
+ const std::size_t hash;
};
class DirectoryEntry
{
public:
+ using FileKey = DirectoryEntryFileKey;
- DirectoryEntry(const std::wstring &name, DirectoryEntry *parent, int originID);
+ DirectoryEntry(
+ const std::wstring &name, DirectoryEntry *parent, int originID);
- DirectoryEntry(const std::wstring &name, DirectoryEntry *parent, int originID,
- boost::shared_ptr<FileRegister> fileRegister,
- boost::shared_ptr<OriginConnection> originConnection);
+ DirectoryEntry(
+ const std::wstring &name, DirectoryEntry *parent, int originID,
+ boost::shared_ptr<FileRegister> fileRegister,
+ boost::shared_ptr<OriginConnection> originConnection);
~DirectoryEntry();
void clear();
- bool isPopulated() const { return m_Populated; }
- bool isEmpty() const { return m_Files.empty() && m_SubDirectories.empty(); }
+ 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;
+ }
- 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);
- // 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);
- void addFromBSA(const std::wstring &originName, std::wstring &directory, const std::wstring &fileName, int priority, int order);
+ void addFromBSA(
+ const std::wstring &originName, std::wstring &directory,
+ const std::wstring &fileName, int priority, int order);
void propagateOrigin(int origin);
- const std::wstring &getName() const;
+ const std::wstring &getName() const
+ {
+ return m_Name;
+ }
- boost::shared_ptr<FileRegister> getFileRegister() { return m_FileRegister; }
+ boost::shared_ptr<FileRegister> 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;
- //int getOrigin(const std::wstring &path, bool &archive);
-
std::vector<FileEntry::Ptr> getFiles() const;
- void getSubDirectories(std::vector<DirectoryEntry*>::const_iterator &begin
- , std::vector<DirectoryEntry*>::const_iterator &end) const {
- begin = m_SubDirectories.begin(); end = m_SubDirectories.end();
+ void getSubDirectories(
+ std::vector<DirectoryEntry*>::const_iterator &begin,
+ std::vector<DirectoryEntry*>::const_iterator &end) const
+ {
+ begin = m_SubDirectories.begin();
+ end = m_SubDirectories.end();
+ }
+
+ const std::vector<DirectoryEntry*>& getSubDirectories() const
+ {
+ return m_SubDirectories;
+ }
+
+ template <class F>
+ void forEachDirectory(F&& f) const
+ {
+ for (auto&& d : m_SubDirectories) {
+ if (!f(*d)) {
+ break;
+ }
+ }
+ }
+
+ template <class F>
+ void forEachFile(F&& f) const
+ {
+ for (auto&& p : m_Files) {
+ if (auto file=m_FileRegister->getFile(p.second)) {
+ if (!f(*file)) {
+ break;
+ }
+ }
+ }
+ }
+
+ template <class F>
+ void forEachFileIndex(F&& f) const
+ {
+ for (auto&& p : m_Files) {
+ if (!f(p.second)) {
+ break;
+ }
+ }
+ }
+
+ FileEntry::Ptr getFileByIndex(FileEntry::Index index) const
+ {
+ return m_FileRegister->getFile(index);
}
- DirectoryEntry *findSubDirectory(const std::wstring &name) const;
+ 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 FileEntry::Ptr findFile(const std::wstring &name) const;
+ const FileEntry::Ptr findFile(const std::wstring &name, bool alreadyLowerCase=false) const;
+ const FileEntry::Ptr 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 FileEntry::Ptr searchFile(const std::wstring &path, const DirectoryEntry **directory) const;
+ // 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 FileEntry::Ptr searchFile(
+ const std::wstring &path, const DirectoryEntry **directory=nullptr) const;
void insertFile(const std::wstring &filePath, FilesOrigin &origin, FILETIME fileTime);
void removeFile(FileEntry::Index index);
- // remove the specified file from the tree. This can be a path leading to a file in a subdirectory
+ // 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);
/**
@@ -275,76 +467,77 @@ public:
*/
void removeDir(const std::wstring &path);
- bool remove(const std::wstring &fileName, int *origin) {
- auto iter = m_Files.find(ToLower(fileName));
- if (iter != m_Files.end()) {
- if (origin != nullptr) {
- FileEntry::Ptr entry = m_FileRegister->getFile(iter->second);
- if (entry.get() != nullptr) {
- bool ignore;
- *origin = entry->getOrigin(ignore);
- }
- }
- return m_FileRegister->removeFile(iter->second);
- } else {
- return false;
- }
- }
+ 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);
+ FilesOrigin &createOrigin(
+ const std::wstring &originName,
+ const std::wstring &directory, int priority);
void removeFiles(const std::set<FileEntry::Index> &indices);
private:
+ using FilesMap = std::map<std::wstring, FileEntry::Index>;
+ using FilesLookup = std::unordered_map<FileKey, FileEntry::Index>;
+ using SubDirectories = std::vector<DirectoryEntry*>;
+ using SubDirectoriesLookup = std::unordered_map<std::wstring, DirectoryEntry*>;
- DirectoryEntry(const DirectoryEntry &reference);
- DirectoryEntry &operator=(const DirectoryEntry &reference);
+ boost::shared_ptr<FileRegister> m_FileRegister;
+ boost::shared_ptr<OriginConnection> m_OriginConnection;
- void insert(const std::wstring &fileName, FilesOrigin &origin, FILETIME fileTime, const std::wstring &archive, int order) {
- std::wstring fileNameLower = ToLower(fileName);
- auto iter = m_Files.find(fileNameLower);
- FileEntry::Ptr file;
- if (iter != m_Files.end()) {
- file = m_FileRegister->getFile(iter->second);
- } else {
- file = m_FileRegister->createFile(fileName, this);
- // TODO this has been observed to cause a crash, no clue why
- m_Files[fileNameLower] = file->getIndex();
- }
- file->addOrigin(origin.getID(), fileTime, archive, order);
- origin.addFile(file->getIndex());
- }
+ std::wstring m_Name;
+ FilesMap m_Files;
+ FilesLookup m_FilesLookup;
+ SubDirectories m_SubDirectories;
+ SubDirectoriesLookup m_SubDirectoriesLookup;
- void addFiles(FilesOrigin &origin, wchar_t *buffer, int bufferOffset);
- void addFiles(FilesOrigin &origin, BSA::Folder::Ptr archiveFolder, FILETIME &fileTime, const std::wstring &archiveName, int order);
+ DirectoryEntry *m_Parent;
+ std::set<int> m_Origins;
+ bool m_Populated;
+ bool m_TopLevel;
- DirectoryEntry *getSubDirectory(const std::wstring &name, bool create, int originID = -1);
- DirectoryEntry *getSubDirectoryRecursive(const std::wstring &path, bool create, int originID = -1);
+ DirectoryEntry(const DirectoryEntry &reference);
- void removeDirRecursive();
+ FileEntry::Ptr insert(
+ const std::wstring &fileName, FilesOrigin &origin, FILETIME fileTime,
+ const std::wstring &archive, int order);
-private:
+ void addFiles(
+ FilesOrigin &origin, wchar_t *buffer, int bufferOffset);
- boost::shared_ptr<FileRegister> m_FileRegister;
- boost::shared_ptr<OriginConnection> m_OriginConnection;
+ void addFiles(
+ FilesOrigin &origin, BSA::Folder::Ptr archiveFolder, FILETIME &fileTime,
+ const std::wstring &archiveName, int order);
- std::wstring m_Name;
- std::map<std::wstring, FileEntry::Index> m_Files;
- std::vector<DirectoryEntry*> m_SubDirectories;
+ DirectoryEntry *getSubDirectory(
+ const std::wstring &name, bool create, int originID = -1);
- DirectoryEntry *m_Parent;
- std::set<int> m_Origins;
+ DirectoryEntry *getSubDirectoryRecursive(
+ const std::wstring &path, bool create, int originID = -1);
- bool m_Populated;
+ void removeDirRecursive();
- bool m_TopLevel;
+ void addDirectoryToList(DirectoryEntry* e);
+ void removeDirectoryFromList(SubDirectories::iterator itor);
+ void addFileToList(std::wstring fileNameLower, FileEntry::Index index);
+ void removeFileFromList(FileEntry::Index index);
+ void removeFilesFromList(const std::set<FileEntry::Index>& indices);
};
-
} // namespace MOShared
+
+namespace std
+{
+ hash<MOShared::DirectoryEntryFileKey>::result_type
+ hash<MOShared::DirectoryEntryFileKey>::operator()(
+ const argument_type& key) const
+ {
+ return key.hash;
+ }
+}
+
#endif // DIRECTORYENTRY_H