diff options
Diffstat (limited to 'xbmc/filesystem/SpecialProtocol.cpp')
-rw-r--r-- | xbmc/filesystem/SpecialProtocol.cpp | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/xbmc/filesystem/SpecialProtocol.cpp b/xbmc/filesystem/SpecialProtocol.cpp new file mode 100644 index 0000000..1828773 --- /dev/null +++ b/xbmc/filesystem/SpecialProtocol.cpp @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "SpecialProtocol.h" + +#include "ServiceBroker.h" +#include "URL.h" +#include "Util.h" +#include "profiles/ProfileManager.h" +#include "settings/AdvancedSettings.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/URIUtils.h" +#include "utils/log.h" +#include "windowing/GraphicContext.h" + +#include <cassert> + +#include "PlatformDefs.h" +#ifdef TARGET_POSIX +#include <dirent.h> +#include "utils/StringUtils.h" +#endif + +const CProfileManager *CSpecialProtocol::m_profileManager = nullptr; + +void CSpecialProtocol::RegisterProfileManager(const CProfileManager &profileManager) +{ + m_profileManager = &profileManager; +} + +void CSpecialProtocol::UnregisterProfileManager() +{ + m_profileManager = nullptr; +} + +void CSpecialProtocol::SetProfilePath(const std::string &dir) +{ + SetPath("profile", dir); + CLog::Log(LOGINFO, "special://profile/ is mapped to: {}", GetPath("profile")); +} + +void CSpecialProtocol::SetXBMCPath(const std::string &dir) +{ + SetPath("xbmc", dir); +} + +void CSpecialProtocol::SetXBMCBinPath(const std::string &dir) +{ + SetPath("xbmcbin", dir); +} + +void CSpecialProtocol::SetXBMCBinAddonPath(const std::string &dir) +{ + SetPath("xbmcbinaddons", dir); +} + +void CSpecialProtocol::SetXBMCAltBinAddonPath(const std::string &dir) +{ + SetPath("xbmcaltbinaddons", dir); +} + +void CSpecialProtocol::SetXBMCFrameworksPath(const std::string &dir) +{ + SetPath("frameworks", dir); +} + +void CSpecialProtocol::SetHomePath(const std::string &dir) +{ + SetPath("home", dir); +} + +void CSpecialProtocol::SetUserHomePath(const std::string &dir) +{ + SetPath("userhome", dir); +} + +void CSpecialProtocol::SetEnvHomePath(const std::string &dir) +{ + SetPath("envhome", dir); +} + +void CSpecialProtocol::SetMasterProfilePath(const std::string &dir) +{ + SetPath("masterprofile", dir); +} + +void CSpecialProtocol::SetTempPath(const std::string &dir) +{ + SetPath("temp", dir); +} + +void CSpecialProtocol::SetLogPath(const std::string &dir) +{ + SetPath("logpath", dir); +} + +bool CSpecialProtocol::ComparePath(const std::string &path1, const std::string &path2) +{ + return TranslatePath(path1) == TranslatePath(path2); +} + +std::string CSpecialProtocol::TranslatePath(const std::string &path) +{ + CURL url(path); + // check for special-protocol, if not, return + if (!url.IsProtocol("special")) + { + return path; + } + return TranslatePath(url); +} + +std::string CSpecialProtocol::TranslatePath(const CURL &url) +{ + // check for special-protocol, if not, return + if (!url.IsProtocol("special")) + { +#if defined(TARGET_POSIX) && defined(_DEBUG) + std::string path(url.Get()); + if (path.length() >= 2 && path[1] == ':') + { + CLog::Log(LOGWARNING, "Trying to access old style dir: {}", path); + // printf("Trying to access old style dir: %s\n", path.c_str()); + } +#endif + + return url.Get(); + } + + const std::string& FullFileName = url.GetFileName(); + + std::string translatedPath; + std::string FileName; + std::string RootDir; + + // Split up into the special://root and the rest of the filename + size_t pos = FullFileName.find('/'); + if (pos != std::string::npos && pos > 1) + { + RootDir = FullFileName.substr(0, pos); + + if (pos < FullFileName.size()) + FileName = FullFileName.substr(pos + 1); + } + else + RootDir = FullFileName; + + if (RootDir == "subtitles") + translatedPath = URIUtils::AddFileToFolder(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SUBTITLES_CUSTOMPATH), FileName); + else if (RootDir == "userdata" && m_profileManager) + translatedPath = URIUtils::AddFileToFolder(m_profileManager->GetUserDataFolder(), FileName); + else if (RootDir == "database" && m_profileManager) + translatedPath = URIUtils::AddFileToFolder(m_profileManager->GetDatabaseFolder(), FileName); + else if (RootDir == "thumbnails" && m_profileManager) + translatedPath = URIUtils::AddFileToFolder(m_profileManager->GetThumbnailsFolder(), FileName); + else if (RootDir == "recordings" || RootDir == "cdrips") + translatedPath = URIUtils::AddFileToFolder(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_AUDIOCDS_RECORDINGPATH), FileName); + else if (RootDir == "screenshots") + translatedPath = URIUtils::AddFileToFolder(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_DEBUG_SCREENSHOTPATH), FileName); + else if (RootDir == "musicartistsinfo") + translatedPath = URIUtils::AddFileToFolder(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_MUSICLIBRARY_ARTISTSFOLDER), FileName); + else if (RootDir == "musicplaylists") + translatedPath = URIUtils::AddFileToFolder(CUtil::MusicPlaylistsLocation(), FileName); + else if (RootDir == "videoplaylists") + translatedPath = URIUtils::AddFileToFolder(CUtil::VideoPlaylistsLocation(), FileName); + else if (RootDir == "skin") + { + auto winSystem = CServiceBroker::GetWinSystem(); + // windowing may not have been initialized yet + if (winSystem) + translatedPath = URIUtils::AddFileToFolder(winSystem->GetGfxContext().GetMediaDir(), FileName); + } + // from here on, we have our "real" special paths + else if (RootDir == "xbmc" || + RootDir == "xbmcbin" || + RootDir == "xbmcbinaddons" || + RootDir == "xbmcaltbinaddons" || + RootDir == "home" || + RootDir == "envhome" || + RootDir == "userhome" || + RootDir == "temp" || + RootDir == "profile" || + RootDir == "masterprofile" || + RootDir == "frameworks" || + RootDir == "logpath") + { + std::string basePath = GetPath(RootDir); + if (!basePath.empty()) + translatedPath = URIUtils::AddFileToFolder(basePath, FileName); + else + translatedPath.clear(); + } + + // check if we need to recurse in + if (URIUtils::IsSpecial(translatedPath)) + { // we need to recurse in, as there may be multiple translations required + return TranslatePath(translatedPath); + } + + // Validate the final path, just in case + return CUtil::ValidatePath(translatedPath); +} + +std::string CSpecialProtocol::TranslatePathConvertCase(const std::string& path) +{ + std::string translatedPath = TranslatePath(path); + +#ifdef TARGET_POSIX + if (translatedPath.find("://") != std::string::npos) + return translatedPath; + + // If the file exists with the requested name, simply return it + struct stat stat_buf; + if (stat(translatedPath.c_str(), &stat_buf) == 0) + return translatedPath; + + std::string result; + std::vector<std::string> tokens; + StringUtils::Tokenize(translatedPath, tokens, "/"); + std::string file; + DIR* dir; + struct dirent* de; + + for (unsigned int i = 0; i < tokens.size(); i++) + { + file = result + "/"; + file += tokens[i]; + if (stat(file.c_str(), &stat_buf) == 0) + { + result += "/" + tokens[i]; + } + else + { + dir = opendir(result.c_str()); + if (dir) + { + while ((de = readdir(dir)) != NULL) + { + // check if there's a file with same name but different case + if (StringUtils::CompareNoCase(de->d_name, tokens[i]) == 0) + { + result += "/"; + result += de->d_name; + break; + } + } + + // if we did not find any file that somewhat matches, just + // fallback but we know it's not gonna be a good ending + if (de == NULL) + result += "/" + tokens[i]; + + closedir(dir); + } + else + { // this is just fallback, we won't succeed anyway... + result += "/" + tokens[i]; + } + } + } + + return result; +#else + return translatedPath; +#endif +} + +void CSpecialProtocol::LogPaths() +{ + CLog::Log(LOGINFO, "special://xbmc/ is mapped to: {}", GetPath("xbmc")); + CLog::Log(LOGINFO, "special://xbmcbin/ is mapped to: {}", GetPath("xbmcbin")); + CLog::Log(LOGINFO, "special://xbmcbinaddons/ is mapped to: {}", GetPath("xbmcbinaddons")); + CLog::Log(LOGINFO, "special://masterprofile/ is mapped to: {}", GetPath("masterprofile")); +#if defined(TARGET_POSIX) + CLog::Log(LOGINFO, "special://envhome/ is mapped to: {}", GetPath("envhome")); +#endif + CLog::Log(LOGINFO, "special://home/ is mapped to: {}", GetPath("home")); + CLog::Log(LOGINFO, "special://temp/ is mapped to: {}", GetPath("temp")); + CLog::Log(LOGINFO, "special://logpath/ is mapped to: {}", GetPath("logpath")); + //CLog::Log(LOGINFO, "special://userhome/ is mapped to: {}", GetPath("userhome")); + if (!CUtil::GetFrameworksPath().empty()) + CLog::Log(LOGINFO, "special://frameworks/ is mapped to: {}", GetPath("frameworks")); +} + +// private routines, to ensure we only set/get an appropriate path +void CSpecialProtocol::SetPath(const std::string &key, const std::string &path) +{ + m_pathMap[key] = path; +} + +std::string CSpecialProtocol::GetPath(const std::string &key) +{ + std::map<std::string, std::string>::iterator it = m_pathMap.find(key); + if (it != m_pathMap.end()) + return it->second; + assert(false); + return ""; +} |