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 if (!uniqueMarkers.contains(path))
82 uniqueMarkers << path;
92 static const QString PLUGINS_DIR_NAME;
98 QString workingDirectory;
100 bool bIsPortableModeOn;
107 static const QString LEGACY_APPDATA_DIR_NAME = ".doomseeker";
108 static const QString DEMOS_DIR_NAME = "demos";
110 const QString
DataPaths::CHATLOGS_DIR_NAME = "chatlogs";
112 const QString
DataPaths::TRANSLATIONS_DIR_NAME = "translations";
113 const QString
DataPaths::UPDATE_PACKAGES_DIR_NAME = "updates";
114 const QString
DataPaths::UPDATE_PACKAGE_FILENAME_PREFIX = "doomseeker-update-pkg-";
118 d->bIsPortableModeOn = bPortableModeOn;
126 d->cacheDirectory.setPath(systemAppDataDirectory(
".cache"));
127 d->configDirectory.setPath(systemAppDataDirectory(LEGACY_APPDATA_DIR_NAME));
128 d->dataDirectory.setPath(systemAppDataDirectory(
".static"));
132 d->cacheDirectory.setPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
133 #if QT_VERSION >= 0x050500
135 d->configDirectory.setPath(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation));
139 QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation),
142 d->dataDirectory.setPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
145 gLog << QString(
"Cache directory: %1").arg(d->cacheDirectory.absolutePath());
146 gLog << QString(
"Config directory: %1").arg(d->configDirectory.absolutePath());
147 gLog << QString(
"Data directory: %1").arg(d->dataDirectory.absolutePath());
150 DataPaths::~DataPaths()
156 return d->cacheDirectory.absolutePath();
161 QStringList failedList;
165 failedList.append(dataDirectory);
172 QList<DirErrno> failedDirs;
177 if (cacheDirError.isError())
178 failedDirs << cacheDirError;
184 if (!d->configDirectory.exists(DoomseekerFilePaths::INI_FILENAME))
187 if (configDirError.isError())
188 failedDirs << configDirError;
190 #if !defined(Q_OS_DARWIN)
191 else if (appDataDir.exists(
".doomseeker"))
194 const QDir oldConfigDir(appDataDir.absolutePath() + QDir::separator() +
".doomseeker");
195 gLog << QString(
"Migrating configuration data from '%1'\n\tto '%2'.")
196 .arg(oldConfigDir.absolutePath())
197 .arg(d->configDirectory.absolutePath());
199 for (QFileInfo fileinfo : oldConfigDir.entryInfoList(QStringList(
"*.ini"), QDir::Files))
201 QFile(fileinfo.absoluteFilePath()).copy(d->configDirectory.absoluteFilePath(fileinfo.fileName()));
210 if (!d->dataDirectory.exists(DEMOS_DIR_NAME))
213 const QString legacyPrefDirectory =
"Library/Preferences/Doomseeker";
215 const QString legacyPrefDirectory =
".doomseeker";
218 if (dataDirError.isError())
219 failedDirs << dataDirError;
220 else if (appDataDir.exists(legacyPrefDirectory))
223 const QDir oldConfigDir(appDataDir.absolutePath() + QDir::separator() + legacyPrefDirectory);
224 gLog << QString(
"Migrating user data from '%1'\n\tto '%2'.")
225 .arg(oldConfigDir.absolutePath())
226 .arg(d->dataDirectory.absolutePath());
228 for (QFileInfo fileinfo : oldConfigDir.entryInfoList(QDir::Dirs))
230 const QString origPath = fileinfo.absoluteFilePath();
231 QFile file(origPath);
232 if (file.rename(d->dataDirectory.absoluteFilePath(fileinfo.fileName())))
236 #if !defined(Q_OS_WIN32)
245 if (demosDirError.isError())
246 failedDirs << demosDirError;
248 return uniqueErrnosByDir(failedDirs);
253 return staticDefaultInstance;
259 QStringList filePaths;
266 if (progBinDirName !=
"bin" && progBinDirName !=
"MacOS")
272 QString DataPaths::demosDirectoryPath()
const
274 return d->dataDirectory.absoluteFilePath(DEMOS_DIR_NAME);
280 if (!isPortableModeOn())
282 rootPath = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first();
290 QString DataPaths::env(
const QString &key)
292 return QProcessEnvironment::systemEnvironment().value(key);
295 void DataPaths::initDefault(
bool bPortableModeOn)
297 assert(staticDefaultInstance ==
nullptr &&
"DataPaths can have only one default.");
298 if (staticDefaultInstance ==
nullptr)
299 staticDefaultInstance =
new DataPaths(bPortableModeOn);
302 bool DataPaths::isPortableModeOn()
const
304 return d->bIsPortableModeOn;
330 #if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN32)
334 const QString installDir = INSTALL_PREFIX
"/" INSTALL_LIBDIR
"/doomseeker/";
336 paths = QStringList(installDir);
338 paths.append(installDir);
341 paths = uniquePaths(paths);
348 QString envVarName =
"";
353 envVarName =
"ProgramFiles(x86)";
357 envVarName =
"ProgramW6432";
361 envVarName =
"ProgramFiles";
368 QString path = env(envVarName);
369 if (path.isEmpty() && machineType != Preferred)
382 Q_UNUSED(machineType);
389 return d->configDirectory.absolutePath();
400 paths.append(QDir::currentPath());
401 paths.append(QCoreApplication::applicationDirPath());
403 paths.append(INSTALL_PREFIX
"/share/doomseeker");
405 paths = uniquePaths(paths);
406 QString subdirFiltered = subdir.trimmed();
407 if (!subdirFiltered.isEmpty())
409 for (
int i = 0; i < paths.size(); ++i)
417 Strings::triml(append,
"/\\");
419 if (isPortableModeOn())
421 QString path = d->workingDirectory +
"/" + append;
422 return QDir(path).absolutePath();
431 QString envVar = env(
"APPDATA");
439 dir = QDir::homePath();
444 Strings::trimr(dir,
"/\\");
446 dir += QDir::separator() + append;
448 return QDir(dir).absolutePath();
457 if (!rootDir.mkpath(dirToCreate))
459 int errnoval = errno;
461 return DirErrno(fullDirPath, errnoval, strerror(errnoval));
469 if (!pathToBottomMostExisting.isEmpty())
471 QFileInfo parentDir(pathToBottomMostExisting);
472 if (parentDir.exists() && !parentDir.isDir())
474 return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR,
475 QObject::tr(
"parent node is not a directory: %1")
476 .arg(parentDir.filePath()));
480 ++qt_ntfs_permission_lookup;
481 bool permissions = parentDir.isReadable()
482 && parentDir.isWritable()
483 && parentDir.isExecutable();
484 --qt_ntfs_permission_lookup;
488 return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR,
489 QObject::tr(
"lack of necessary permissions to the parent directory: %1")
490 .arg(parentDir.filePath()));
494 return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR, QObject::tr(
"cannot create directory"));
507 QFileInfo fileInfo(path);
509 bool bCondition1 = !path.isEmpty();
510 bool bCondition2 = fileInfo.exists();
511 bool bCondition3 = fileInfo.isDir();
513 return bCondition1 && bCondition2 && bCondition3;
518 return d->workingDirectory;