23 #include "datapaths.h"
25 #include "application.h"
26 #include "doomseekerfilepaths.h"
27 #include "fileutils.h"
29 #include "plugins/engineplugin.h"
30 #include "strings.hpp"
35 #include <QCoreApplication>
36 #include <QDesktopServices>
38 #include <QProcessEnvironment>
41 #include <QStandardPaths>
44 #if !defined(INSTALL_PREFIX) || !defined(INSTALL_LIBDIR)
45 #error Build system should provide definition for INSTALL_PREFIX and INSTALL_LIBDIR
53 extern Q_CORE_EXPORT
int qt_ntfs_permission_lookup;
56 int qt_ntfs_permission_lookup;
59 static QList<DataPaths::DirErrno> uniqueErrnosByDir(
const QList<DataPaths::DirErrno> &errnos)
61 QSet<QString> uniqueDirs;
62 QList<DataPaths::DirErrno> uniqueErrnos;
65 if (!uniqueDirs.contains(dirErrno.directory.path()))
67 uniqueDirs.insert(dirErrno.directory.path());
68 uniqueErrnos << dirErrno;
74 static QStringList uniquePaths(
const QStringList &paths)
76 QList<QFileInfo> uniqueMarkers;
78 for (
const QString &path : paths)
80 QFileInfo fileInfo(path);
81 if (!uniqueMarkers.contains(fileInfo))
83 uniqueMarkers << fileInfo;
93 static const QString PLUGINS_DIR_NAME;
99 QString workingDirectory;
101 bool bIsPortableModeOn;
108 static const QString LEGACY_APPDATA_DIR_NAME = ".doomseeker";
109 static const QString DEMOS_DIR_NAME = "demos";
111 const QString
DataPaths::CHATLOGS_DIR_NAME = "chatlogs";
113 const QString
DataPaths::TRANSLATIONS_DIR_NAME = "translations";
114 const QString
DataPaths::UPDATE_PACKAGES_DIR_NAME = "updates";
115 const QString
DataPaths::UPDATE_PACKAGE_FILENAME_PREFIX = "doomseeker-update-pkg-";
119 d->bIsPortableModeOn = bPortableModeOn;
127 d->cacheDirectory.setPath(systemAppDataDirectory(
".cache"));
128 d->configDirectory.setPath(systemAppDataDirectory(LEGACY_APPDATA_DIR_NAME));
129 d->dataDirectory.setPath(systemAppDataDirectory(
".static"));
133 d->cacheDirectory.setPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
134 #if QT_VERSION >= 0x050500
136 d->configDirectory.setPath(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation));
140 QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation),
143 d->dataDirectory.setPath(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
146 gLog << QString(
"Cache directory: %1").arg(d->cacheDirectory.absolutePath());
147 gLog << QString(
"Config directory: %1").arg(d->configDirectory.absolutePath());
148 gLog << QString(
"Data directory: %1").arg(d->dataDirectory.absolutePath());
151 DataPaths::~DataPaths()
157 return d->cacheDirectory.absolutePath();
162 QStringList failedList;
166 failedList.append(dataDirectory);
173 QList<DirErrno> failedDirs;
178 if (cacheDirError.isError())
179 failedDirs << cacheDirError;
185 if (!d->configDirectory.exists(DoomseekerFilePaths::INI_FILENAME))
188 if (configDirError.isError())
189 failedDirs << configDirError;
191 #if !defined(Q_OS_DARWIN)
192 else if (appDataDir.exists(
".doomseeker"))
195 const QDir oldConfigDir(appDataDir.absolutePath() + QDir::separator() +
".doomseeker");
196 gLog << QString(
"Migrating configuration data from '%1'\n\tto '%2'.")
197 .arg(oldConfigDir.absolutePath())
198 .arg(d->configDirectory.absolutePath());
200 for (QFileInfo fileinfo : oldConfigDir.entryInfoList(QStringList(
"*.ini"), QDir::Files))
202 QFile(fileinfo.absoluteFilePath()).copy(d->configDirectory.absoluteFilePath(fileinfo.fileName()));
211 if (!d->dataDirectory.exists(DEMOS_DIR_NAME))
214 const QString legacyPrefDirectory =
"Library/Preferences/Doomseeker";
216 const QString legacyPrefDirectory =
".doomseeker";
219 if (dataDirError.isError())
220 failedDirs << dataDirError;
221 else if (appDataDir.exists(legacyPrefDirectory))
224 const QDir oldConfigDir(appDataDir.absolutePath() + QDir::separator() + legacyPrefDirectory);
225 gLog << QString(
"Migrating user data from '%1'\n\tto '%2'.")
226 .arg(oldConfigDir.absolutePath())
227 .arg(d->dataDirectory.absolutePath());
229 for (QFileInfo fileinfo : oldConfigDir.entryInfoList(QDir::Dirs))
231 const QString origPath = fileinfo.absoluteFilePath();
232 QFile file(origPath);
233 if (file.rename(d->dataDirectory.absoluteFilePath(fileinfo.fileName())))
237 #if !defined(Q_OS_WIN32)
246 if (demosDirError.isError())
247 failedDirs << demosDirError;
249 return uniqueErrnosByDir(failedDirs);
254 return staticDefaultInstance;
260 QStringList filePaths;
267 if (progBinDirName !=
"bin" && progBinDirName !=
"MacOS")
273 QString DataPaths::demosDirectoryPath()
const
275 return d->dataDirectory.absoluteFilePath(DEMOS_DIR_NAME);
281 if (!isPortableModeOn())
283 rootPath = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first();
291 QString DataPaths::env(
const QString &key)
293 return QProcessEnvironment::systemEnvironment().value(key);
296 void DataPaths::initDefault(
bool bPortableModeOn)
298 assert(staticDefaultInstance ==
nullptr &&
"DataPaths can have only one default.");
299 if (staticDefaultInstance ==
nullptr)
300 staticDefaultInstance =
new DataPaths(bPortableModeOn);
303 bool DataPaths::isPortableModeOn()
const
305 return d->bIsPortableModeOn;
331 #if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN32)
335 const QString installDir = INSTALL_PREFIX
"/" INSTALL_LIBDIR
"/doomseeker/";
337 paths = QStringList(installDir);
339 paths.append(installDir);
342 paths = uniquePaths(paths);
349 QString envVarName =
"";
354 envVarName =
"ProgramFiles(x86)";
358 envVarName =
"ProgramW6432";
362 envVarName =
"ProgramFiles";
369 QString path = env(envVarName);
370 if (path.isEmpty() && machineType != Preferred)
383 Q_UNUSED(machineType);
390 return d->configDirectory.absolutePath();
401 paths.append(QDir::currentPath());
402 paths.append(QCoreApplication::applicationDirPath());
404 paths.append(INSTALL_PREFIX
"/share/doomseeker");
406 paths = uniquePaths(paths);
407 QString subdirFiltered = subdir.trimmed();
408 if (!subdirFiltered.isEmpty())
410 for (
int i = 0; i < paths.size(); ++i)
418 Strings::triml(append,
"/\\");
420 if (isPortableModeOn())
422 QString path = d->workingDirectory +
"/" + append;
423 return QDir(path).absolutePath();
432 QString envVar = env(
"APPDATA");
440 dir = QDir::homePath();
445 Strings::trimr(dir,
"/\\");
447 dir += QDir::separator() + append;
449 return QDir(dir).absolutePath();
458 if (!rootDir.mkpath(dirToCreate))
460 int errnoval = errno;
462 return DirErrno(fullDirPath, errnoval, strerror(errnoval));
470 if (!pathToBottomMostExisting.isEmpty())
472 QFileInfo parentDir(pathToBottomMostExisting);
473 if (parentDir.exists() && !parentDir.isDir())
475 return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR,
476 QObject::tr(
"parent node is not a directory: %1")
477 .arg(parentDir.filePath()));
481 ++qt_ntfs_permission_lookup;
482 bool permissions = parentDir.isReadable()
483 && parentDir.isWritable()
484 && parentDir.isExecutable();
485 --qt_ntfs_permission_lookup;
489 return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR,
490 QObject::tr(
"lack of necessary permissions to the parent directory: %1")
491 .arg(parentDir.filePath()));
495 return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR, QObject::tr(
"cannot create directory"));
508 QFileInfo fileInfo(path);
510 bool bCondition1 = !path.isEmpty();
511 bool bCondition2 = fileInfo.exists();
512 bool bCondition3 = fileInfo.isDir();
514 return bCondition1 && bCondition2 && bCondition3;
519 return d->workingDirectory;