1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
|
/*
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 MO_REGISTER_DIRECTORYENTRY_INCLUDED
#define MO_REGISTER_DIRECTORYENTRY_INCLUDED
#include <bsatk/bsatk.h>
#include "fileregister.h"
namespace env
{
class DirectoryWalker;
struct Directory;
struct File;
} // namespace env
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 std
namespace MOShared
{
struct DirCompareByName
{
bool operator()(const DirectoryEntry* a, const DirectoryEntry* b) const;
};
class DirectoryEntry
{
public:
using SubDirectories = std::set<DirectoryEntry*, DirCompareByName>;
DirectoryEntry(std::wstring name, DirectoryEntry* parent, OriginID originID);
DirectoryEntry(std::wstring name, DirectoryEntry* parent, OriginID originID,
boost::shared_ptr<FileRegister> fileRegister,
boost::shared_ptr<OriginConnection> originConnection);
~DirectoryEntry();
// noncopyable
DirectoryEntry(const DirectoryEntry&) = delete;
DirectoryEntry& operator=(const DirectoryEntry&) = delete;
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 addFromAllBSAs(const std::wstring& originName, const std::wstring& directory,
int priority, const std::vector<std::wstring>& archives,
const std::set<std::wstring>& enabledArchives,
const std::vector<std::wstring>& loadOrder,
DirectoryStats& stats);
void addFromBSA(const std::wstring& originName, const std::wstring& directory,
const std::wstring& archivePath, int priority, int order,
DirectoryStats& stats);
void addFromList(const std::wstring& originName, const std::wstring& directory,
env::Directory& root, int priority, DirectoryStats& stats);
void propagateOrigin(OriginID origin);
const std::wstring& getName() const { return m_Name; }
boost::shared_ptr<FileRegister> getFileRegister() { return m_FileRegister; }
bool originExists(const std::wstring& name) const;
FilesOrigin& getOriginByID(OriginID ID) const;
FilesOrigin& getOriginByName(const std::wstring& name) const;
const FilesOrigin* findOriginByID(OriginID ID) const;
OriginID anyOrigin() const;
std::vector<FileEntryPtr> getFiles() const;
const SubDirectories& 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;
}
}
}
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 DirectoryEntryFileKey& 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, OriginID* origin = nullptr);
/**
* @brief remove the specified directory
* @param path directory to remove
*/
void removeDir(const std::wstring& path);
bool remove(const std::wstring& fileName, OriginID* origin);
bool hasContentsFromOrigin(OriginID originID) const;
FilesOrigin& createOrigin(const std::wstring& originName,
const std::wstring& directory, int priority,
DirectoryStats& stats);
void removeFiles(const std::set<FileIndex>& indices);
void dump(const std::wstring& file) const;
private:
using FilesMap = std::map<std::wstring, FileIndex>;
using FilesLookup = std::unordered_map<DirectoryEntryFileKey, FileIndex>;
using SubDirectoriesLookup = std::unordered_map<std::wstring, DirectoryEntry*>;
boost::shared_ptr<FileRegister> m_FileRegister;
boost::shared_ptr<OriginConnection> m_OriginConnection;
std::wstring m_Name;
FilesMap m_Files;
FilesLookup m_FilesLookup;
SubDirectories m_SubDirectories;
SubDirectoriesLookup m_SubDirectoriesLookup;
DirectoryEntry* m_Parent;
std::set<OriginID> 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, DirectoryStats& stats);
void addDir(FilesOrigin& origin, env::Directory& d, DirectoryStats& stats);
DirectoryEntry* getSubDirectory(std::wstring_view name, bool create,
DirectoryStats& stats,
OriginID originID = InvalidOriginID);
DirectoryEntry* getSubDirectory(env::Directory& dir, bool create,
DirectoryStats& stats,
OriginID originID = InvalidOriginID);
DirectoryEntry* getSubDirectoryRecursive(const std::wstring& path, bool create,
DirectoryStats& stats,
OriginID originID = InvalidOriginID);
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<FileIndex>& 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<MOShared::DirectoryEntryFileKey>::result_type
hash<MOShared::DirectoryEntryFileKey>::operator()(const argument_type& key) const
{
return key.hash;
}
} // namespace std
#endif // MO_REGISTER_DIRECTORYENTRY_INCLUDED
|