svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 00008 This program is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU General Public License as 00010 published by the Free Software Foundation; either version 2 of the 00011 License, or (at your option) any later version. See the file 00012 COPYING included with this distribution for more information. 00013 */ 00014 00015 /* 00016 This is a modified version of a source file from the 00017 Rosegarden MIDI and audio sequencer and notation editor. 00018 This file copyright 2005-2011 Chris Cannam and the Rosegarden 00019 development team. 00020 */ 00021 00022 #include "ResourceFinder.h" 00023 00024 #include <QDir> 00025 #include <QFileInfo> 00026 #include <QStringList> 00027 #include <QProcess> 00028 #include <QCoreApplication> 00029 00030 #if QT_VERSION >= 0x050000 00031 #include <QStandardPaths> 00032 #endif 00033 00034 #include <cstdlib> 00035 #include <iostream> 00036 00061 QStringList 00062 ResourceFinder::getSystemResourcePrefixList() 00063 { 00064 // returned in order of priority 00065 00066 QStringList list; 00067 00068 #ifdef Q_OS_WIN32 00069 char *programFiles = getenv("ProgramFiles"); 00070 if (programFiles && programFiles[0]) { 00071 list << QString("%1/%2/%3") 00072 .arg(programFiles) 00073 .arg(qApp->organizationName()) 00074 .arg(qApp->applicationName()); 00075 } else { 00076 list << QString("C:/Program Files/%1/%2") 00077 .arg(qApp->organizationName()) 00078 .arg(qApp->applicationName()); 00079 } 00080 #else 00081 #ifdef Q_OS_MAC 00082 list << QString("/Library/Application Support/%1") 00083 .arg(qApp->applicationName()); 00084 #else 00085 list << QString("/usr/local/share/%1") 00086 .arg(qApp->applicationName()); 00087 list << QString("/usr/share/%1") 00088 .arg(qApp->applicationName()); 00089 #endif 00090 #endif 00091 00092 return list; 00093 } 00094 00095 static QString 00096 getOldStyleUserResourcePrefix() 00097 { 00098 #ifdef Q_OS_WIN32 00099 // This is awkward and does not work correctly for non-ASCII home 00100 // directory names, hence getNewStyleUserResourcePrefix() below 00101 char *homedrive = getenv("HOMEDRIVE"); 00102 char *homepath = getenv("HOMEPATH"); 00103 QString home; 00104 if (homedrive && homepath) { 00105 home = QString("%1%2").arg(homedrive).arg(homepath); 00106 } else { 00107 home = QDir::home().absolutePath(); 00108 } 00109 if (home == "") return ""; 00110 return QString("%1/.%2").arg(home).arg(qApp->applicationName()); 00111 #else 00112 char *home = getenv("HOME"); 00113 if (!home || !home[0]) return ""; 00114 #ifdef Q_OS_MAC 00115 return QString("%1/Library/Application Support/%2") 00116 .arg(home) 00117 .arg(qApp->applicationName()); 00118 #else 00119 return QString("%1/.local/share/%2") 00120 .arg(home) 00121 .arg(qApp->applicationName()); 00122 #endif 00123 #endif 00124 } 00125 00126 static QString 00127 getNewStyleUserResourcePrefix() 00128 { 00129 #if QT_VERSION >= 0x050000 00130 // This is expected to be much more reliable than 00131 // getOldStyleUserResourcePrefix(), but it returns a different 00132 // directory because it includes the organisation name (which is 00133 // fair enough). Hence migrateOldStyleResources() which moves 00134 // across any resources found in the old-style path the first time 00135 // we look for the new-style one 00136 return QStandardPaths::writableLocation(QStandardPaths::DataLocation); 00137 #else 00138 return getOldStyleUserResourcePrefix(); 00139 #endif 00140 } 00141 00142 static void 00143 migrateOldStyleResources() 00144 { 00145 QString oldPath = getOldStyleUserResourcePrefix(); 00146 QString newPath = getNewStyleUserResourcePrefix(); 00147 00148 if (oldPath != newPath && 00149 QDir(oldPath).exists() && 00150 !QDir(newPath).exists()) { 00151 00152 QDir d(oldPath); 00153 00154 if (!d.mkpath(newPath)) { 00155 cerr << "WARNING: Failed to create new-style resource path \"" 00156 << newPath << "\" to migrate old resources to" << endl; 00157 return; 00158 } 00159 00160 QDir target(newPath); 00161 00162 bool success = true; 00163 00164 QStringList entries 00165 (d.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)); 00166 00167 foreach (QString entry, entries) { 00168 if (d.rename(entry, target.filePath(entry))) { 00169 cerr << "NOTE: Successfully moved resource \"" 00170 << entry << "\" from old resource path to new" << endl; 00171 } else { 00172 cerr << "WARNING: Failed to move old resource \"" 00173 << entry << "\" from old location \"" 00174 << oldPath << "\" to new location \"" 00175 << newPath << "\"" << endl; 00176 success = false; 00177 } 00178 } 00179 00180 if (success) { 00181 if (!d.rmdir(oldPath)) { 00182 cerr << "WARNING: Failed to remove old resource path \"" 00183 << oldPath << "\" after migrating " << entries.size() 00184 << " resource(s) to new path \"" << newPath 00185 << "\" (directory not empty?)" << endl; 00186 } else { 00187 cerr << "NOTE: Successfully moved " << entries.size() 00188 << " resource(s) from old resource " 00189 << "path \"" << oldPath << "\" to new path \"" 00190 << newPath << "\"" << endl; 00191 } 00192 } 00193 } 00194 } 00195 00196 QString 00197 ResourceFinder::getUserResourcePrefix() 00198 { 00199 migrateOldStyleResources(); 00200 return getNewStyleUserResourcePrefix(); 00201 } 00202 00203 QStringList 00204 ResourceFinder::getResourcePrefixList() 00205 { 00206 // returned in order of priority 00207 00208 QStringList list; 00209 00210 QString user = getUserResourcePrefix(); 00211 if (user != "") list << user; 00212 00213 list << getSystemResourcePrefixList(); 00214 00215 list << ":"; // bundled resource location 00216 00217 return list; 00218 } 00219 00220 QString 00221 ResourceFinder::getResourcePath(QString resourceCat, QString fileName) 00222 { 00223 // We don't simply call getResourceDir here, because that returns 00224 // only the "installed file" location. We also want to search the 00225 // bundled resources and user-saved files. 00226 00227 QStringList prefixes = getResourcePrefixList(); 00228 00229 if (resourceCat != "") resourceCat = "/" + resourceCat; 00230 00231 for (QStringList::const_iterator i = prefixes.begin(); 00232 i != prefixes.end(); ++i) { 00233 00234 QString prefix = *i; 00235 00236 SVDEBUG << "ResourceFinder::getResourcePath: Looking up file \"" << fileName << "\" for category \"" << resourceCat << "\" in prefix \"" << prefix << "\"" << endl; 00237 00238 QString path = 00239 QString("%1%2/%3").arg(prefix).arg(resourceCat).arg(fileName); 00240 if (QFileInfo(path).exists() && QFileInfo(path).isReadable()) { 00241 cerr << "Found it!" << endl; 00242 return path; 00243 } 00244 } 00245 00246 return ""; 00247 } 00248 00249 QString 00250 ResourceFinder::getResourceDir(QString resourceCat) 00251 { 00252 // Returns only the "installed file" location 00253 00254 QStringList prefixes = getSystemResourcePrefixList(); 00255 00256 if (resourceCat != "") resourceCat = "/" + resourceCat; 00257 00258 for (QStringList::const_iterator i = prefixes.begin(); 00259 i != prefixes.end(); ++i) { 00260 00261 QString prefix = *i; 00262 QString path = QString("%1%2").arg(prefix).arg(resourceCat); 00263 if (QFileInfo(path).exists() && 00264 QFileInfo(path).isDir() && 00265 QFileInfo(path).isReadable()) { 00266 return path; 00267 } 00268 } 00269 00270 return ""; 00271 } 00272 00273 QString 00274 ResourceFinder::getResourceSavePath(QString resourceCat, QString fileName) 00275 { 00276 QString dir = getResourceSaveDir(resourceCat); 00277 if (dir == "") return ""; 00278 00279 return dir + "/" + fileName; 00280 } 00281 00282 QString 00283 ResourceFinder::getResourceSaveDir(QString resourceCat) 00284 { 00285 // Returns the "user" location 00286 00287 QString user = getUserResourcePrefix(); 00288 if (user == "") return ""; 00289 00290 if (resourceCat != "") resourceCat = "/" + resourceCat; 00291 00292 QDir userDir(user); 00293 if (!userDir.exists()) { 00294 if (!userDir.mkpath(user)) { 00295 cerr << "ResourceFinder::getResourceSaveDir: ERROR: Failed to create user resource path \"" << user << "\"" << endl; 00296 return ""; 00297 } 00298 } 00299 00300 if (resourceCat != "") { 00301 QString save = QString("%1%2").arg(user).arg(resourceCat); 00302 QDir saveDir(save); 00303 if (!saveDir.exists()) { 00304 if (!saveDir.mkpath(save)) { 00305 cerr << "ResourceFinder::getResourceSaveDir: ERROR: Failed to create user resource path \"" << save << "\"" << endl; 00306 return ""; 00307 } 00308 } 00309 return save; 00310 } else { 00311 return user; 00312 } 00313 } 00314 00315 QStringList 00316 ResourceFinder::getResourceFiles(QString resourceCat, QString fileExt) 00317 { 00318 QStringList results; 00319 QStringList prefixes = getResourcePrefixList(); 00320 00321 QStringList filters; 00322 filters << QString("*.%1").arg(fileExt); 00323 00324 for (QStringList::const_iterator i = prefixes.begin(); 00325 i != prefixes.end(); ++i) { 00326 00327 QString prefix = *i; 00328 QString path; 00329 00330 if (resourceCat != "") { 00331 path = QString("%1/%2").arg(prefix).arg(resourceCat); 00332 } else { 00333 path = prefix; 00334 } 00335 00336 QDir dir(path); 00337 if (!dir.exists()) continue; 00338 00339 dir.setNameFilters(filters); 00340 QStringList entries = dir.entryList 00341 (QDir::Files | QDir::Readable, QDir::Name); 00342 00343 for (QStringList::const_iterator j = entries.begin(); 00344 j != entries.end(); ++j) { 00345 results << QString("%1/%2").arg(path).arg(*j); 00346 } 00347 } 00348 00349 return results; 00350 } 00351 00352 bool 00353 ResourceFinder::unbundleResource(QString resourceCat, QString fileName) 00354 { 00355 QString path = getResourcePath(resourceCat, fileName); 00356 00357 if (!path.startsWith(':')) return true; 00358 00359 // This is the lowest-priority alternative path for this 00360 // resource, so we know that there must be no installed copy. 00361 // Install one to the user location. 00362 SVDEBUG << "ResourceFinder::unbundleResource: File " << fileName << " is bundled, un-bundling it" << endl; 00363 QString target = getResourceSavePath(resourceCat, fileName); 00364 QFile file(path); 00365 if (!file.copy(target)) { 00366 cerr << "ResourceFinder::unbundleResource: ERROR: Failed to un-bundle resource file \"" << fileName << "\" to user location \"" << target << "\"" << endl; 00367 return false; 00368 } 00369 00370 QFile chmod(target); 00371 chmod.setPermissions(QFile::ReadOwner | 00372 QFile::ReadUser | /* for potential platform-independence */ 00373 QFile::ReadGroup | 00374 QFile::ReadOther | 00375 QFile::WriteOwner| 00376 QFile::WriteUser); /* for potential platform-independence */ 00377 00378 return true; 00379 } 00380