File indexing completed on 2024-04-28 07:37:57

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2004-2007 Torsten Rahn <tackat@kde.org>
0004 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
0005 //
0006 
0007 
0008 #include "MarbleDirs.h"
0009 #include "MarbleDebug.h"
0010 
0011 #include <QFile>
0012 #include <QString>
0013 #include <QStringList>
0014 #include <QCoreApplication>
0015 
0016 #include <cstdlib>
0017 
0018 #include <QStandardPaths>
0019 
0020 #ifdef Q_OS_WIN
0021 //for getting appdata path
0022 //mingw-w64 Internet Explorer 5.01
0023 #define _WIN32_IE 0x0501
0024 #include <shlobj.h>
0025 #endif
0026 
0027 #ifdef Q_OS_MACX
0028 //for getting app bundle path
0029 #include <ApplicationServices/ApplicationServices.h>
0030 #endif
0031 
0032 #include <config-marble.h>
0033 
0034 using namespace Marble;
0035 
0036 namespace
0037 {
0038     QString runTimeMarbleDataPath;
0039 
0040     QString runTimeMarblePluginPath;
0041 }
0042 
0043 MarbleDirs::MarbleDirs()
0044     : d( nullptr )
0045 {
0046 }
0047 
0048 
0049 QString MarbleDirs::path( const QString& relativePath )
0050 { 
0051     QString  localpath = localPath() + QLatin1Char('/') + relativePath; // local path
0052     QString  systempath  = systemPath() + QLatin1Char('/') + relativePath;  // system path
0053 
0054 
0055     QString fullpath = systempath;
0056     if ( QFile::exists( localpath ) ) {
0057         fullpath = localpath;
0058     }
0059     return QDir( fullpath ).canonicalPath(); 
0060 }
0061 
0062 
0063 QString MarbleDirs::pluginPath( const QString& relativePath )
0064 { 
0065     const QString localpath = pluginLocalPath() + QDir::separator() + relativePath;    // local path
0066     const QString systempath  = pluginSystemPath() + QDir::separator() + relativePath; // system path
0067 
0068 
0069     QString fullpath = systempath;
0070     if ( QFile::exists( localpath ) ) {
0071         fullpath = localpath;
0072     }
0073 
0074     return QDir( fullpath ).canonicalPath(); 
0075 }
0076 
0077 QStringList MarbleDirs::entryList( const QString& relativePath, QDir::Filters filters )
0078 {
0079     QStringList filesLocal = QDir(MarbleDirs::localPath() + QLatin1Char('/') + relativePath).entryList(filters);
0080     QStringList filesSystem = QDir(MarbleDirs::systemPath() + QLatin1Char('/') + relativePath).entryList(filters);
0081     QStringList allFiles( filesLocal );
0082     allFiles << filesSystem;
0083 
0084     // remove duplicate entries
0085     allFiles.sort();
0086     for ( int i = 1; i < allFiles.size(); ++i ) {
0087         if ( allFiles.at(i) == allFiles.at( i - 1 ) ) {
0088             allFiles.removeAt(i);
0089             --i;
0090         }
0091     }
0092 
0093     return allFiles;
0094 }
0095 
0096 QStringList MarbleDirs::pluginEntryList( const QString& relativePath, QDir::Filters filters )
0097 {
0098     QStringList allFiles = QDir(MarbleDirs::pluginLocalPath() + QLatin1Char('/') + relativePath).entryList(filters);
0099     auto const pluginSystemPath = MarbleDirs::pluginSystemPath();
0100     if (!pluginSystemPath.isEmpty()) {
0101         allFiles << QDir(pluginSystemPath + QLatin1Char('/') + relativePath).entryList(filters);
0102     }
0103 
0104     // remove duplicate entries
0105     allFiles.sort();
0106     for ( int i = 1; i < allFiles.size(); ++i ) {
0107         if ( allFiles.at(i) == allFiles.at( i - 1 ) ) {
0108             allFiles.removeAt(i);
0109             --i;
0110         }
0111     }
0112 
0113     return allFiles;
0114 }
0115 
0116 QString MarbleDirs::systemPath()
0117 {
0118     if (!runTimeMarbleDataPath.isEmpty()) {
0119         return runTimeMarbleDataPath;
0120     }
0121 
0122     QString systempath;
0123 
0124 #ifdef MARBLE_DATA_PATH
0125     //MARBLE_DATA_PATH is a compiler define set by cmake
0126     QString compileTimeMarbleDataPath(MARBLE_DATA_PATH);
0127 
0128     if(QDir(compileTimeMarbleDataPath).exists())
0129         return compileTimeMarbleDataPath;
0130 #endif  // MARBLE_DATA_PATH
0131 
0132 
0133 #ifdef Q_OS_WIN
0134     return QCoreApplication::applicationDirPath() + QDir::separator() + QLatin1String("data");
0135 #endif
0136 
0137 #ifdef Q_OS_MACX
0138     //
0139     // On OSX lets try to find any file first in the bundle
0140     // before branching out to home and sys dirs
0141     //
0142     CFURLRef myBundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
0143     CFStringRef myMacPath = CFURLCopyFileSystemPath(myBundleRef, kCFURLPOSIXPathStyle);
0144     const char *mypPathPtr = CFStringGetCStringPtr(myMacPath,CFStringGetSystemEncoding());
0145     CFRelease(myBundleRef);
0146     QString myPath(mypPathPtr);
0147     CFRelease(myMacPath);
0148     //do some magick so that we can still find data dir if
0149     //marble was not built as a bundle
0150     if (myPath.contains(QLatin1String(".app"))) {  //its a bundle!
0151       systempath = myPath + QLatin1String("/Contents/Resources/data");
0152     }
0153 
0154     if ( QFile::exists( systempath ) ){ 
0155       return systempath;
0156     }
0157 #endif   // mac bundle
0158 
0159 #ifdef Q_OS_ANDROID
0160     systempath = "assets:/data";
0161     return systempath;
0162 #endif
0163 
0164     // This is the preferred fallback location if no marbleDataPath is set.
0165     systempath = QDir( QCoreApplication::applicationDirPath() + QLatin1String( "/data" ) ).canonicalPath();
0166 
0167     if ( QFile::exists( systempath ) ){
0168       return systempath;
0169     }
0170 
0171     // This fallback location is for compatibility with KDE installations.
0172     return QDir( QCoreApplication::applicationDirPath()
0173                  + QLatin1String( "/../share/apps/marble/data" )
0174                  ).canonicalPath();
0175 }
0176 
0177 QString MarbleDirs::pluginSystemPath()
0178 {
0179     if (!runTimeMarblePluginPath.isEmpty()) {
0180         return runTimeMarblePluginPath;
0181     }
0182 
0183     QString systempath;
0184 
0185 #ifdef MARBLE_PLUGIN_PATH
0186     //MARBLE_PLUGIN_PATH is a compiler define set by cmake
0187     QString compileTimeMarblePluginPath(MARBLE_PLUGIN_PATH);
0188 
0189     if(QDir(compileTimeMarblePluginPath).exists())
0190         return compileTimeMarblePluginPath;
0191 #endif  // MARBLE_PLUGIN_PATH
0192 
0193 #ifdef Q_OS_MACX
0194     //
0195     // On OSX lets try to find any file first in the bundle
0196     // before branching out to home and sys dirs
0197     //
0198     CFURLRef myBundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
0199     CFStringRef myMacPath = CFURLCopyFileSystemPath(myBundleRef, kCFURLPOSIXPathStyle);
0200     const char *mypPathPtr = CFStringGetCStringPtr(myMacPath,CFStringGetSystemEncoding());
0201     CFRelease(myBundleRef);
0202     CFRelease(myMacPath);
0203     QString myPath(mypPathPtr);
0204     //do some magick so that we can still find data dir if
0205     //marble was not built as a bundle
0206     if (myPath.contains(QLatin1String(".app"))) {  //its a bundle!
0207       systempath = myPath + QLatin1String("/Contents/Resources/plugins");
0208     }
0209 
0210     if ( QFile::exists( systempath ) ){ 
0211       return systempath;
0212     }
0213 #endif   // mac bundle
0214 
0215 #ifdef Q_OS_WIN
0216     return QCoreApplication::applicationDirPath() + QDir::separator() + QLatin1String("plugins");
0217 #endif
0218 
0219 #ifdef Q_OS_ANDROID
0220     return "assets:/plugins";
0221 #endif
0222 
0223     // This is the preferred fallback location if no marblePluginPath is set.
0224     systempath = QDir( QCoreApplication::applicationDirPath() + QLatin1String( "/plugins" ) ).canonicalPath();
0225 
0226     if ( QFile::exists( systempath ) ){
0227       return systempath;
0228     }
0229 
0230     // This ultimate fallback location is for compatibility with KDE installations.
0231     return QDir( QCoreApplication::applicationDirPath()
0232                  + QLatin1String( "/../lib/kde4/plugins/marble" )
0233                  ).canonicalPath();
0234 }
0235 
0236 QString MarbleDirs::localPath() 
0237 {
0238 #ifndef Q_OS_WIN
0239     QString dataHome = getenv( "XDG_DATA_HOME" );
0240     if( dataHome.isEmpty() )
0241         dataHome = QDir::homePath() + QLatin1String("/.local/share");
0242 
0243     return dataHome + QLatin1String("/marble"); // local path
0244 #else
0245     return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/.marble/data");
0246 #endif
0247 }
0248 
0249 QStringList MarbleDirs::oldLocalPaths()
0250 {
0251     QStringList possibleOldPaths;
0252 
0253 #ifndef Q_OS_WIN
0254     const QString oldDefault = QDir::homePath() + QLatin1String("/.marble/data");
0255     possibleOldPaths.append( oldDefault );
0256 
0257     const QString xdgDefault = QDir::homePath() + QLatin1String("/.local/share/marble");
0258     possibleOldPaths.append( xdgDefault );
0259 
0260     QString xdg = getenv( "XDG_DATA_HOME" );
0261     xdg += QLatin1String("/marble/");
0262     possibleOldPaths.append( xdg );
0263 #endif
0264 
0265 #ifdef Q_OS_WIN
0266     HWND hwnd = 0;
0267     WCHAR *appdata_path = new WCHAR[MAX_PATH + 1];
0268 
0269     SHGetSpecialFolderPathW(hwnd, appdata_path, CSIDL_APPDATA, 0);
0270     QString appdata = QString::fromUtf16(reinterpret_cast<ushort*>(appdata_path));
0271     delete[] appdata_path;
0272     possibleOldPaths << QString(QDir::fromNativeSeparators(appdata) + QLatin1String("/.marble/data")); // local path
0273 #endif
0274 
0275     QString currentLocalPath = QDir( MarbleDirs::localPath() ).canonicalPath();
0276     QStringList oldPaths;
0277     for( const QString& possibleOldPath: possibleOldPaths ) {
0278         if( !QDir().exists( possibleOldPath ) ) {
0279             continue;
0280         }
0281 
0282         QString canonicalPossibleOldPath = QDir( possibleOldPath ).canonicalPath();
0283         if( canonicalPossibleOldPath == currentLocalPath ) {
0284             continue;
0285         }
0286 
0287         oldPaths.append( canonicalPossibleOldPath );
0288     }
0289 
0290     return oldPaths;
0291 }
0292 
0293 QString MarbleDirs::pluginLocalPath() 
0294 {
0295 #ifndef Q_OS_WIN
0296     return QDir::homePath() + QLatin1String("/.marble/plugins"); // local path
0297 #else
0298     return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/.marble/plugins");
0299 #endif
0300 }
0301 
0302 QString MarbleDirs::marbleDataPath()
0303 {
0304     return runTimeMarbleDataPath;
0305 }
0306 
0307 QString MarbleDirs::marblePluginPath()
0308 {
0309     return runTimeMarblePluginPath;
0310 }
0311 
0312 void MarbleDirs::setMarbleDataPath( const QString& adaptedPath )
0313 {
0314     if ( !QDir::root().exists( adaptedPath ) )
0315     {
0316         qWarning() << QString( "Invalid MarbleDataPath \"%1\". Using \"%2\" instead." ).arg( adaptedPath, systemPath() );
0317         return;
0318     }
0319 
0320     runTimeMarbleDataPath = adaptedPath;
0321 }
0322 
0323 void MarbleDirs::setMarblePluginPath( const QString& adaptedPath )
0324 {
0325     if ( !QDir::root().exists( adaptedPath ) )
0326     {
0327         qWarning() << QString( "Invalid MarblePluginPath \"%1\". Using \"%2\" instead." ).arg( adaptedPath, pluginSystemPath() );
0328         return;
0329     }
0330 
0331     runTimeMarblePluginPath = adaptedPath;
0332 }
0333 
0334 
0335 void MarbleDirs::debug()
0336 {
0337     mDebug() << "=== MarbleDirs: ===";
0338     mDebug() << "Local Path:" << localPath();
0339     mDebug() << "Plugin Local Path:" << pluginLocalPath();
0340     mDebug() << "";
0341     mDebug() << "Marble Data Path (Run Time) :" << runTimeMarbleDataPath; 
0342     mDebug() << "Marble Data Path (Compile Time):" << QString(MARBLE_DATA_PATH); 
0343     mDebug() << "";
0344     mDebug() << "Marble Plugin Path (Run Time) :" << runTimeMarblePluginPath; 
0345     mDebug() << "Marble Plugin Path (Compile Time):" << QString(MARBLE_PLUGIN_PATH); 
0346     mDebug() << "";
0347     mDebug() << "System Path:" << systemPath();
0348     mDebug() << "Plugin System Path:" << pluginSystemPath();
0349     mDebug() << "===================";
0350 }