pathfinder.cpp
1 //------------------------------------------------------------------------------
2 // pathfinder.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2009 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "pathfinder.h"
24 
25 #include "configuration/doomseekerconfig.h"
26 #include "datapaths.h"
27 #include "fileseeker.h"
28 #include "log.h"
29 #include "pathfinder/filesearchpath.h"
30 #include "strings.hpp"
31 
32 #include <cstdlib>
33 #include <QDir>
34 #include <QFileInfo>
35 #include <QScopedPointer>
36 #include <QSharedPointer>
37 
38 DClass<PathFinderResult>
39 {
40 public:
41  QStringList foundFiles;
42  QStringList missingFiles;
43 };
44 
45 
46 DPointered(PathFinderResult)
47 
48 
50 {
51 }
52 
53 PathFinderResult::~PathFinderResult()
54 {
55 }
56 
58 {
59  return d->foundFiles;
60 }
61 
62 const QStringList &PathFinderResult::foundFiles() const
63 {
64  return d->foundFiles;
65 }
66 
68 {
69  return d->missingFiles;
70 }
71 
72 const QStringList &PathFinderResult::missingFiles() const
73 {
74  return d->missingFiles;
75 }
76 
78 
79 DClass<PathFinder>
80 {
81 public:
82  QSharedPointer <QList<FileSearchPath> > searchPaths;
83 
84  QString resolveDir(const QString &dir)
85  {
86  QFileInfo fileInfo(dir);
87  if (fileInfo.isSymLink())
88  fileInfo = QFileInfo(fileInfo.symLinkTarget());
89 
90  if (fileInfo.isBundle())
91  return fileInfo.absoluteFilePath() + "/Contents/MacOS";
92  else
93  {
94  if (fileInfo.isFile())
95  return fileInfo.absoluteDir().absolutePath();
96  else
97  return fileInfo.absoluteFilePath();
98  }
99  }
100 };
101 
102 
103 DPointered(PathFinder)
104 
105 
107 {
108  d->searchPaths.reset(new QList<FileSearchPath>());
109  d->searchPaths->append(gConfig.combinedWadseekPaths());
110  removeUnneededPaths();
111 }
112 
113 PathFinder::PathFinder(const QStringList &paths)
114 {
115  d->searchPaths.reset(new QList<FileSearchPath>());
116  for (const QString &path : paths)
117  d->searchPaths->append(path);
118  removeUnneededPaths();
119 }
120 
121 PathFinder::~PathFinder()
122 {
123 }
124 
125 PathFinder PathFinder::genericPathFinder(const QStringList &suffixes)
126 {
127  QStringList paths;
128  #if defined(Q_OS_WIN32)
129  paths << "." << ".."
130  << gDefaultDataPaths->workingDirectory()
131  << gDefaultDataPaths->workingDirectory() + "/.."
132  << DataPaths::programFilesDirectory(DataPaths::x64)
133  << DataPaths::programFilesDirectory(DataPaths::x86);
134  #else
135  paths << "/usr/bin" << "/usr/local/bin" << "/usr/share/bin"
136  << "/usr/games/" << "/usr/local/games/"
137  << "/usr/share/games/" << gDefaultDataPaths->workingDirectory() << ".";
138  #endif
139  QStringList pathsCopy(paths);
140  for (const QString &path : pathsCopy)
141  {
142  for (const QString &suffix : suffixes)
143  {
144  paths << Strings::combinePaths(path, suffix);
145  }
146  }
147  return PathFinder(paths);
148 }
149 
150 void PathFinder::addPrioritySearchDir(const QString &dir)
151 {
152  d->searchPaths->prepend(d->resolveDir(dir));
153  removeUnneededPaths();
154 }
155 
156 void PathFinder::addSearchDir(const QString &dir)
157 {
158  d->searchPaths->append(d->resolveDir(dir));
159  removeUnneededPaths();
160 }
161 
162 QString PathFinder::findFile(const QString &fileName) const
163 {
164  if (d->searchPaths->count() == 0)
165  return QString();
166  QScopedPointer<FileSeeker> seeker(FileSeeker::createSeeker(d->searchPaths));
167  QString result = seeker->findFile(fileName);
168  return result;
169 }
170 
171 PathFinderResult PathFinder::findFiles(const QStringList &files) const
172 {
173  PathFinderResult result;
174  for (const QString file : files)
175  {
176  QString filePath = findFile(file);
177  if (filePath.isNull())
178  {
179  result.missingFiles() << file;
180  }
181  else
182  {
183  result.foundFiles() << filePath;
184  }
185  }
186 
187  return result;
188 }
189 
190 void PathFinder::removeUnneededPaths() const
191 {
192  Qt::CaseSensitivity caseSensitivity;
193  #ifdef Q_OS_WIN32
194  caseSensitivity = Qt::CaseInsensitive;
195  #else
196  caseSensitivity = Qt::CaseSensitive;
197  #endif
198 
199  for (int mainIterator = 0; mainIterator < d->searchPaths->length(); ++mainIterator)
200  {
201  for (int subIterator = mainIterator + 1; subIterator < d->searchPaths->length(); ++subIterator)
202  {
203  const FileSearchPath &mainPath = d->searchPaths->at(mainIterator);
204  const FileSearchPath &subPath = d->searchPaths->at(subIterator);
205 
206  // are they equal?
207  if (QDir(mainPath.path()).absolutePath().compare(QDir(subPath.path()).absolutePath(), caseSensitivity) == 0)
208  {
209  (*d->searchPaths.data())[mainIterator]
210  .setRecursive(mainPath.isRecursive() || subPath.isRecursive());
211  d->searchPaths->removeAt(subIterator);
212  --subIterator;
213  continue;
214  }
215 
216  // is sub inside main and main is recursive?
217  if (mainPath.isRecursive() &&
218  QDir(subPath.path()).absolutePath().startsWith(QDir(mainPath.path()).absolutePath(), caseSensitivity))
219  {
220  d->searchPaths->removeAt(subIterator);
221  subIterator = mainIterator;
222  continue;
223  }
224 
225  // is main inside sub and sub is recursive?
226  if (subPath.isRecursive() &&
227  QDir(mainPath.path()).absolutePath().startsWith(QDir(subPath.path()).absolutePath(), caseSensitivity))
228  {
229  d->searchPaths->removeAt(mainIterator);
230  mainIterator = 0;
231  break;
232  }
233  }
234  }
235 }
static QString combinePaths(QString pathFront, QString pathEnd)
Definition: strings.cpp:147
Result of multiple file search operation done by PathFinder.
Definition: pathfinder.h:41
Performs a case-insensitive (OS independent) file searches.
Definition: pathfinder.h:81
QStringList & missingFiles()
Names of not found files.
Definition: pathfinder.cpp:67
void addSearchDir(const QString &dir)
Adds directory where search will be performed.
Definition: pathfinder.cpp:156
QStringList & foundFiles()
Paths to found files.
Definition: pathfinder.cpp:57
PathFinderResult findFiles(const QStringList &files) const
Performs a search for multiple files, marking them as found or missing.
Definition: pathfinder.cpp:171
PathFinder()
Constructs PathFinder where paths are read from program configuration from file (WAD) path list setti...
static QString programFilesDirectory(MachineType machineType)
Definition: datapaths.cpp:345
QString findFile(const QString &fileName) const
Performs a search for a single file.
Definition: pathfinder.cpp:162
static PathFinder genericPathFinder(const QStringList &suffixes)
Generic PathFinder that looks in PATH and other common dirs.
Definition: pathfinder.cpp:125
void addPrioritySearchDir(const QString &dir)
Definition: pathfinder.cpp:150