BibleTime
directory.cpp
Go to the documentation of this file.
1/*********
2*
3* In the name of the Father, and of the Son, and of the Holy Spirit.
4*
5* This file is part of BibleTime's source code, https://bibletime.info/
6*
7* Copyright 1999-2025 by the BibleTime developers.
8* The BibleTime source code is licensed under the GNU General Public License
9* version 2.0.
10*
11**********/
12
13#include "directory.h"
14
15#include <optional>
16#include <QByteArray>
17#include <QCoreApplication>
18#include <QDebug>
19#include <QDir>
20#if (QT_VERSION < QT_VERSION_CHECK(6, 8, 0))
21#include <QDirIterator>
22#else
23#include <QDirListing>
24#endif
25#include <QFlags>
26#include <QLocale>
27#include <QStringList>
28#include <QtGlobal>
29
30
31namespace util {
32namespace directory {
33
34namespace {
35
36std::optional<QDir> cachedPrefix;
37std::optional<QDir> cachedPicsDir;
38std::optional<QDir> cachedLocaleDir;
39std::optional<QDir> cachedDisplayTemplatesDir;
41std::optional<QDir> cachedUserBaseDir;
42std::optional<QDir> cachedUserHomeDir;
43std::optional<QDir> cachedUserHomeSwordDir;
44std::optional<QDir> cachedUserCacheDir;
45std::optional<QDir> cachedUserIndexDir;
46#ifdef Q_OS_WIN
47// Only Windows installs the sword directory which contains locales.d:
48std::optional<QDir> cachedApplicationSwordDir;
49std::optional<QDir> cachedSharedSwordDir;
50#endif
51
52#ifdef Q_OS_WIN
53QString const BIBLETIME = QStringLiteral("Bibletime");
54QString const SWORD_DIR = QStringLiteral("Sword");
55#else
56QString const BIBLETIME = QStringLiteral(".bibletime");
57QString const SWORD_DIR = QStringLiteral(".sword");
58#endif
59} // anonymous namespace
60
62 QDir wDir(QCoreApplication::applicationDirPath());
63 wDir.makeAbsolute();
64 if (!wDir.cdUp()) { // Installation prefix
65 qWarning() << "Unable to use prefix one level up from " << wDir.path();
66 return false;
67 }
68 cachedPrefix.emplace(wDir);
69
70#ifdef Q_OS_WIN
71 // application sword dir for Windows only:
72 cachedApplicationSwordDir.emplace(wDir);
73 if (!cachedApplicationSwordDir->cd(QStringLiteral("share/sword"))) {
74 qWarning() << "Cannot find sword directory relative to"
75 << QCoreApplication::applicationDirPath();
76 return false;
77 }
78 // Sword dir for Windows only:
79 cachedSharedSwordDir.emplace(qEnvironmentVariable("ProgramData"));
80 if (!cachedSharedSwordDir->cd(SWORD_DIR)) {
81 if (!cachedSharedSwordDir->mkdir(SWORD_DIR)
82 || !cachedSharedSwordDir->cd(SWORD_DIR))
83 {
84 qWarning() << "Cannot find " << cachedSharedSwordDir->absolutePath() << " \\Sword";
85 return false;
86 }
87 }
88#endif
89
90 // We unset the SWORD_PATH so libsword finds paths correctly:
91 ::qunsetenv("SWORD_PATH");
92
93 cachedPicsDir.emplace(wDir);
94 if (!cachedPicsDir->cd(QStringLiteral("share/bibletime/pics"))) {
95 qWarning() << "Cannot find pics directory relative to"
96 << wDir.absolutePath();
97 return false;
98 }
99
100 cachedLocaleDir.emplace(wDir);
101 if (!cachedLocaleDir->cd(QStringLiteral("share/bibletime/locale"))) {
102 qWarning() << "Cannot find locale directory relative to"
103 << wDir.absolutePath();
104 return false;
105 }
106
107 cachedDisplayTemplatesDir.emplace(wDir); //display templates dir
108 if (!cachedDisplayTemplatesDir->cd(
109 QStringLiteral("share/bibletime/display-templates/")))
110 {
111 qWarning() << "Cannot find display template directory relative to"
112 << wDir.absolutePath();
113 return false;
114 }
115
116#ifdef Q_OS_WINRT
117 cachedUserHomeDir.emplace();
118#elif defined (Q_OS_WIN) && !defined(Q_OS_WIN32)
119 cachedUserHomeDir.emplace(QCoreApplication::applicationDirPath());
120#elif defined Q_OS_WIN32
121 cachedUserHomeDir.emplace(qEnvironmentVariable("APPDATA"));
122#else
123 cachedUserHomeDir.emplace(qgetenv("HOME"));
124#endif
125
126 cachedUserBaseDir.emplace(*cachedUserHomeDir);
127 if (!cachedUserBaseDir->cd(BIBLETIME)) {
128 if (!cachedUserBaseDir->mkpath(BIBLETIME)
129 || !cachedUserBaseDir->cd(BIBLETIME))
130 {
131 qWarning() << "Could not create user settings directory relative to"
132 << cachedUserHomeDir->absolutePath();
133 return false;
134 }
135 }
136
137 cachedUserHomeSwordDir.emplace(*cachedUserHomeDir);
138#if !defined(Q_OS_WIN) || defined(Q_OS_WIN32)
139 if (!cachedUserHomeSwordDir->cd(SWORD_DIR)) {
140 if (!cachedUserHomeSwordDir->mkpath(SWORD_DIR)
141 || !cachedUserHomeSwordDir->cd(SWORD_DIR))
142 {
143 qWarning() << "Could not create user home " << SWORD_DIR
144 << " directory.";
145 return false;
146 }
147 }
148#endif
149
150 { /// \todo Check and comment whether this is needed:
151 auto userHomeSwordModsDir = *cachedUserHomeSwordDir;
152 static auto const modsDir = QStringLiteral("mods.d");
153 if (!userHomeSwordModsDir.cd(modsDir)) {
154 if (!userHomeSwordModsDir.mkdir(modsDir)
155 || !userHomeSwordModsDir.cd(modsDir))
156 {
157 qWarning() << "Could not create user home " << SWORD_DIR
158 << " mods.d directory.";
159 return false;
160 }
161 }
162 }
163
164 cachedUserCacheDir.emplace(*cachedUserBaseDir);
165 {
166 static auto const cacheDir = QStringLiteral("cache");
167 if (!cachedUserCacheDir->cd(cacheDir)) {
168 if (!cachedUserCacheDir->mkdir(cacheDir)
169 || !cachedUserCacheDir->cd(cacheDir))
170 {
171 qWarning() << "Could not create user cache directory.";
172 return false;
173 }
174 }
175 }
176
177 cachedUserIndexDir.emplace(*cachedUserBaseDir);
178 {
179 static auto const indicesDir = QStringLiteral("indices");
180 if (!cachedUserIndexDir->cd(indicesDir)) {
181 if (!cachedUserIndexDir->mkdir(indicesDir)
182 || !cachedUserIndexDir->cd(indicesDir))
183 {
184 qWarning() << "Could not create user indices directory.";
185 return false;
186 }
187 }
188 }
189
190 cachedUserDisplayTemplatesDir.emplace(*cachedUserBaseDir);
191 {
192 static auto const displayTemplatesDir =
193 QStringLiteral("display-templates");
194 if (!cachedUserDisplayTemplatesDir->cd(displayTemplatesDir)) {
195 if (!cachedUserDisplayTemplatesDir->mkdir(displayTemplatesDir)
196 || !cachedUserDisplayTemplatesDir->cd(displayTemplatesDir))
197 {
198 qWarning() << "Could not create user display templates "
199 "directory.";
200 return false;
201 }
202 }
203 }
204
205 return true;
206} // bool initDirectoryCache();
207
208::qint64 getDirSizeRecursive(QString const & dir) {
209 ::qint64 size = 0u;
210 #if (QT_VERSION < QT_VERSION_CHECK(6, 8, 0))
211 QDirIterator it(dir, QDir::Files, QDirIterator::Subdirectories);
212 while (it.hasNext())
213 size += it.nextFileInfo().size();
214 #else
215 using F = QDirListing::IteratorFlag;
216 for (auto const & fileEntry : QDirListing(dir, F::FilesOnly | F::Recursive))
217 size += fileEntry.size();
218 #endif
219 return size;
220}
221
222#ifdef Q_OS_WIN
223const QDir &getApplicationSwordDir() {
224 return *cachedApplicationSwordDir;
225}
226
227const QDir &getSharedSwordDir() {
228 return *cachedSharedSwordDir;
229}
230#endif
231
232QDir const & getIconDir() {
233 static const QDir cachedIconDir(
234 cachedPrefix->filePath(
235 QStringLiteral("share/bibletime/icons")));
236 return cachedIconDir;
237}
238
239QString const & getLicensePath() {
240 static auto const cachedLicensePath(
241 cachedPrefix->filePath(
242 QStringLiteral("share/bibletime/license/LICENSE")));
243 return cachedLicensePath;
244}
245
246const QDir &getPicsDir() {
247 return *cachedPicsDir;
248}
249
250const QDir &getLocaleDir() {
251 return *cachedLocaleDir;
252}
253
254namespace {
255
256QString getDocFile(QString docName) {
257 static QDir const cachedDocDir(cachedPrefix->filePath(BT_RUNTIME_DOCDIR));
258 QString r;
259 if (auto dir = cachedDocDir; dir.cd(docName)) {
260 QStringList tryLanguages;
261 tryLanguages.append(QLocale().name());
262 {
263 auto const & localeName = tryLanguages.back();
264 if (localeName.contains('_'))
265 tryLanguages.append(localeName.section('_', 0, 0));
266 }
267 tryLanguages.append(QStringLiteral("en"));
268 auto const tryDoc =
269 [&dir,&tryLanguages](QString const & type,
270 QString const & filename) -> QString
271 {
272 if (dir.cd(type)) {
273 for (auto const & tryLanguage : tryLanguages) {
274 if (dir.cd(tryLanguage)) {
275 if (dir.exists(filename))
276 return dir.absoluteFilePath(filename);
277 dir.cdUp();
278 }
279 }
280 dir.cdUp();
281 }
282 return {};
283 };
284 r = tryDoc(QStringLiteral("html"), QStringLiteral("index.html"));
285 if (r.isEmpty())
286 r = tryDoc(QStringLiteral("pdf"), docName + QStringLiteral(".pdf"));
287 }
288 return r;
289}
290
291} // anonymous namespace
292
293QString getHandbook() { return getDocFile(QStringLiteral("handbook")); }
294
295QString getHowto() { return getDocFile(QStringLiteral("howto")); }
296
298 return *cachedDisplayTemplatesDir;
299}
300
301const QDir &getUserBaseDir() {
302 return *cachedUserBaseDir;
303}
304
305const QDir &getUserHomeDir() {
306 return *cachedUserHomeDir;
307}
308
309const QDir &getUserHomeSwordDir() {
310 return *cachedUserHomeSwordDir;
311}
312
313const QDir &getUserCacheDir() {
314 return *cachedUserCacheDir;
315}
316
317const QDir &getUserIndexDir() {
318 return *cachedUserIndexDir;
319}
320
322 return *cachedUserDisplayTemplatesDir;
323}
324
325} // namespace directory
326} // namespace util
QStringList r(content.left(bodyIndex))
const QDir & getLocaleDir()
const QDir & getUserCacheDir()
QString getHandbook()
const QDir & getUserHomeSwordDir()
QString const & getLicensePath()
QDir const & getIconDir()
const QDir & getDisplayTemplatesDir()
const QDir & getUserHomeDir()
const QDir & getUserIndexDir()
::qint64 getDirSizeRecursive(QString const &dir)
bool initDirectoryCache()
Initializes the directory cache and returns whether it was successful.
Definition directory.cpp:61
const QDir & getUserBaseDir()
const QDir & getUserDisplayTemplatesDir()
const QDir & getPicsDir()
QString getHowto()