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