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