summaryrefslogtreecommitdiff
path: root/src/shared/directoryentry.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/directoryentry.h')
-rw-r--r--src/shared/directoryentry.h313
1 files changed, 313 insertions, 0 deletions
diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h
new file mode 100644
index 00000000..72e96357
--- /dev/null
+++ b/src/shared/directoryentry.h
@@ -0,0 +1,313 @@
+/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DIRECTORYENTRY_H
+#define DIRECTORYENTRY_H
+
+#include <string>
+#include <set>
+#include <vector>
+#include <map>
+#include <cassert>
+#define WIN32_MEAN_AND_LEAN
+#include <Windows.h>
+#include <bsatk.h>
+#include <boost/shared_ptr.hpp>
+#include "util.h"
+
+
+class DirectoryEntry;
+class OriginConnection;
+class FileRegister;
+
+
+class FileEntry {
+
+public:
+
+ typedef unsigned int Index;
+
+public:
+
+ FileEntry() : m_Index(UINT_MAX), m_Name(), m_Parent(NULL) {}
+
+ FileEntry(Index index, const std::wstring &name, DirectoryEntry *parent);
+
+ Index getIndex() const { return m_Index; }
+
+ void addOrigin(int origin, FILETIME fileTime, const std::wstring &archive);
+ // 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 std::vector<int> &getAlternatives() const { return m_Alternatives; }
+
+ const std::wstring &getName() const { return m_Name; }
+ int getOrigin(bool &archive) const { archive = (m_Archive.length() != 0); return m_Origin; }
+ const std::wstring &getArchive() const { return m_Archive; }
+ bool isFromArchive() const { return m_Archive.length() != 0; }
+ 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; }
+
+private:
+
+ bool recurseParents(std::wstring &path, const DirectoryEntry *parent) const;
+
+ void determineTime();
+
+private:
+
+ Index m_Index;
+ std::wstring m_Name;
+ int m_Origin;
+ std::wstring m_Archive;
+ std::vector<int> m_Alternatives;
+ DirectoryEntry *m_Parent;
+ mutable FILETIME m_FileTime;
+
+ 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;
+ }
+};
+
+
+// represents a mod or the data directory, providing files to the tree
+class FilesOrigin {
+ friend class OriginConnection;
+public:
+
+ FilesOrigin()
+ : m_ID(0), m_Disabled(false), m_Name(), m_Path(), m_Priority(0) { }
+
+ // sets priority for this origin, but it will overwrite the exisiting mapping for this priority,
+ // the previous origin will no longer be referenced
+ void setPriority(int priority);
+
+ int getPriority() const { return m_Priority; }
+
+ void setName(const std::wstring &name);
+ const std::wstring &getName() const { return m_Name; }
+
+ int getID() const { return m_ID; }
+ const std::wstring &getPath() const { return m_Path; }
+
+ std::vector<FileEntry*> getFiles() const;
+
+ void enable(bool enabled);
+ bool isDisabled() const { return m_Disabled; }
+
+ void addFile(FileEntry::Index index) { m_Files.insert(index); }
+ void removeFile(FileEntry::Index index);
+
+private:
+
+ FilesOrigin(int ID, const std::wstring &name, const std::wstring &path, int priority,
+ boost::shared_ptr<FileRegister> fileRegister, boost::shared_ptr<OriginConnection> originConnection)
+ : m_ID(ID), m_Disabled(false), m_Name(name), m_Path(path), m_Priority(priority),
+ m_FileRegister(fileRegister), m_OriginConnection(originConnection) {}
+
+private:
+
+ int m_ID;
+
+ bool m_Disabled;
+
+ std::set<FileEntry::Index> m_Files;
+ std::wstring m_Name;
+ std::wstring m_Path;
+ int m_Priority;
+ boost::shared_ptr<FileRegister> m_FileRegister;
+ boost::shared_ptr<OriginConnection> m_OriginConnection;
+
+};
+
+
+class FileRegister
+{
+
+public:
+
+ FileRegister(boost::shared_ptr<OriginConnection> originConnection);
+
+ bool indexValid(FileEntry::Index index) const;
+
+ FileEntry &createFile(const std::wstring &name, DirectoryEntry *parent);
+ FileEntry *getFile(FileEntry::Index index);
+
+ void removeFile(FileEntry::Index index);
+ void removeOrigin(FileEntry::Index index, int originID);
+
+ void sortOrigins();
+
+private:
+
+ FileEntry::Index generateIndex();
+
+ void unregisterFile(FileEntry &file);
+
+private:
+
+ std::map<FileEntry::Index, FileEntry> m_Files;
+
+ boost::shared_ptr<OriginConnection> m_OriginConnection;
+
+};
+
+
+class DirectoryEntry
+{
+public:
+
+ 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();
+
+ void clear();
+ bool isPopulated() const { return m_Populated; }
+
+ boost::shared_ptr<FileRegister> getRegister() { return m_FileRegister; }
+ 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);
+ void addFromBSA(const std::wstring &originName, std::wstring &directory, const std::wstring &fileName, int priority);
+
+ const std::wstring &getName() const;
+
+ 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;
+
+ int getOrigin(const std::wstring &path, bool &archive);
+
+ std::vector<FileEntry*> 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();
+ }
+
+ DirectoryEntry *findSubDirectory(const std::wstring &name) const;
+
+ /** retrieve a file in this directory by name.
+ * @param name name of the file
+ * @return fileentry object for the file or NULL if no file matches
+ */
+ const FileEntry *findFile(const std::wstring &name);
+
+ /** search through this directory and all subdirectories for a file by the specified name.
+ if directory is not NULL, the referenced variable will be set to true if the path refers to a directory.
+ the returned pointer is NULL in that case */
+ const FileEntry *searchFile(const std::wstring &path, const DirectoryEntry **directory) 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
+ void removeFile(const std::wstring &filePath, int *origin = NULL);
+
+ /**
+ * @brief remove the specified directory
+ * @param path directory to remove
+ */
+ void removeDir(const std::wstring &path);
+
+ void remove(const std::wstring &fileName, int *origin) {
+ auto iter = m_Files.find(fileName);
+ if (iter != m_Files.end()) {
+ if (origin != NULL) {
+ FileEntry *entry = m_FileRegister->getFile(iter->second);
+ if (entry != NULL) {
+ bool ignore;
+ *origin = entry->getOrigin(ignore);
+ }
+ }
+ m_FileRegister->removeFile(iter->second);
+ }
+ }
+
+private:
+
+ void insert(const std::wstring &fileName, FilesOrigin &origin, FILETIME fileTime, const std::wstring &archive) {
+ auto iter = m_Files.find(fileName);
+ FileEntry *file = NULL;
+ if (iter != m_Files.end()) {
+ file = m_FileRegister->getFile(iter->second);
+ } else {
+ file = &m_FileRegister->createFile(fileName, this);
+ m_Files[fileName] = file->getIndex();
+ }
+ file->addOrigin(origin.getID(), fileTime, archive);
+ origin.addFile(file->getIndex());
+ }
+
+ FilesOrigin &createOrigin(const std::wstring &originName, const std::wstring &directory, int priority);
+ void addFiles(FilesOrigin &origin, wchar_t *buffer, int bufferOffset);
+ void addFiles(FilesOrigin &origin, BSA::Folder::Ptr archiveFolder, FILETIME &fileTime, const std::wstring &archiveName);
+
+ DirectoryEntry *getSubDirectory(const std::wstring &name, bool create, int originID = -1);
+
+ DirectoryEntry *getSubDirectoryRecursive(const std::wstring &path, bool create, int originID = -1);
+
+ int anyOrigin() const;
+
+ void removeDirRecursive();
+
+private:
+
+ struct WStrLess {
+ bool operator()(const std::wstring &LHS, const std::wstring &RHS) const {
+ return _wcsicmp(LHS.c_str(), RHS.c_str()) < 0;
+ }
+ };
+
+
+private:
+
+ boost::shared_ptr<FileRegister> m_FileRegister;
+ boost::shared_ptr<OriginConnection> m_OriginConnection;
+
+ std::wstring m_Name;
+ std::map<std::wstring, FileEntry::Index, WStrLess> m_Files;
+ std::vector<DirectoryEntry*> m_SubDirectories;
+
+ DirectoryEntry *m_Parent;
+ int m_Origin;
+
+ bool m_Populated;
+
+};
+
+
+#endif // DIRECTORYENTRY_H