[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / addons / addoninfo / AddonInfo.cpp
blob0f2f7fba5f77f57d9a9d714315969db068678509
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "AddonInfo.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "LangInfo.h"
14 #include "ServiceBroker.h"
15 #include "addons/AddonManager.h"
16 #include "addons/IAddon.h"
17 #include "addons/addoninfo/AddonType.h"
18 #include "filesystem/Directory.h"
19 #include "guilib/LocalizeStrings.h"
20 #include "utils/StringUtils.h"
21 #include "utils/URIUtils.h"
23 #include <algorithm>
24 #include <array>
25 #include <string_view>
27 namespace ADDON
30 typedef struct
32 std::string_view name;
33 std::string_view old_name;
34 AddonType type;
35 int pretty;
36 AddonInstanceSupport instance_support;
37 std::string_view icon;
38 } TypeMapping;
40 // clang-format off
41 static constexpr const std::array<TypeMapping, 40> types =
43 {"unknown", "", AddonType::UNKNOWN, 0, AddonInstanceSupport::SUPPORT_NONE, "" },
44 {"xbmc.metadata.scraper.albums", "", AddonType::SCRAPER_ALBUMS, 24016, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonAlbumInfo.png" },
45 {"xbmc.metadata.scraper.artists", "", AddonType::SCRAPER_ARTISTS, 24017, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonArtistInfo.png" },
46 {"xbmc.metadata.scraper.movies", "", AddonType::SCRAPER_MOVIES, 24007, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonMovieInfo.png" },
47 {"xbmc.metadata.scraper.musicvideos", "", AddonType::SCRAPER_MUSICVIDEOS, 24015, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonMusicVideoInfo.png" },
48 {"xbmc.metadata.scraper.tvshows", "", AddonType::SCRAPER_TVSHOWS, 24014, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonTvInfo.png" },
49 {"xbmc.metadata.scraper.library", "", AddonType::SCRAPER_LIBRARY, 24083, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonInfoLibrary.png" },
50 {"xbmc.ui.screensaver", "", AddonType::SCREENSAVER, 24008, AddonInstanceSupport::SUPPORT_OPTIONAL, "DefaultAddonScreensaver.png" },
51 {"xbmc.player.musicviz", "", AddonType::VISUALIZATION, 24010, AddonInstanceSupport::SUPPORT_OPTIONAL, "DefaultAddonVisualization.png" },
52 {"xbmc.python.pluginsource", "", AddonType::PLUGIN, 24005, AddonInstanceSupport::SUPPORT_NONE, "" },
53 {"xbmc.python.script", "", AddonType::SCRIPT, 24009, AddonInstanceSupport::SUPPORT_NONE, "" },
54 {"xbmc.python.weather", "", AddonType::SCRIPT_WEATHER, 24027, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonWeather.png" },
55 {"xbmc.python.lyrics", "", AddonType::SCRIPT_LYRICS, 24013, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonLyrics.png" },
56 {"xbmc.python.library", "", AddonType::SCRIPT_LIBRARY, 24081, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonHelper.png" },
57 {"xbmc.python.module", "", AddonType::SCRIPT_MODULE, 24082, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonLibrary.png" },
58 {"xbmc.subtitle.module", "", AddonType::SUBTITLE_MODULE, 24012, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonSubtitles.png" },
59 {"kodi.context.item", "", AddonType::CONTEXTMENU_ITEM, 24025, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonContextItem.png" },
60 {"kodi.game.controller", "", AddonType::GAME_CONTROLLER, 35050, AddonInstanceSupport::SUPPORT_OPTIONAL, "DefaultAddonGame.png" },
61 {"xbmc.gui.skin", "", AddonType::SKIN, 166, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonSkin.png" },
62 {"xbmc.webinterface", "", AddonType::WEB_INTERFACE, 199, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonWebSkin.png" },
63 {"xbmc.addon.repository", "", AddonType::REPOSITORY, 24011, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonRepository.png" },
64 {"kodi.pvrclient", "xbmc.pvrclient", AddonType::PVRDLL, 24019, AddonInstanceSupport::SUPPORT_SETTINGS, "DefaultAddonPVRClient.png" },
65 {"kodi.gameclient", "", AddonType::GAMEDLL, 35049, AddonInstanceSupport::SUPPORT_OPTIONAL, "DefaultAddonGame.png" },
66 {"kodi.peripheral", "", AddonType::PERIPHERALDLL, 35010, AddonInstanceSupport::SUPPORT_MANDATORY, "DefaultAddonPeripheral.png" },
67 {"xbmc.addon.video", "", AddonType::VIDEO, 1037, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonVideo.png" },
68 {"xbmc.addon.audio", "", AddonType::AUDIO, 1038, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonMusic.png" },
69 {"xbmc.addon.image", "", AddonType::IMAGE, 1039, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonPicture.png" },
70 {"xbmc.addon.executable", "", AddonType::EXECUTABLE, 1043, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonProgram.png" },
71 {"kodi.addon.game", "", AddonType::GAME, 35049, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonGame.png" },
72 {"kodi.audioencoder", "", AddonType::AUDIOENCODER, 200, AddonInstanceSupport::SUPPORT_MANDATORY, "DefaultAddonAudioEncoder.png" },
73 {"kodi.audiodecoder", "", AddonType::AUDIODECODER, 201, AddonInstanceSupport::SUPPORT_MANDATORY, "DefaultAddonAudioDecoder.png" },
74 {"xbmc.service", "", AddonType::SERVICE, 24018, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonService.png" },
75 {"kodi.resource.images", "", AddonType::RESOURCE_IMAGES, 24035, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonImages.png" },
76 {"kodi.resource.language", "", AddonType::RESOURCE_LANGUAGE, 24026, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonLanguage.png" },
77 {"kodi.resource.uisounds", "", AddonType::RESOURCE_UISOUNDS, 24006, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonUISounds.png" },
78 {"kodi.resource.games", "", AddonType::RESOURCE_GAMES, 35209, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonGame.png" },
79 {"kodi.resource.font", "", AddonType::RESOURCE_FONT, 13303, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonFont.png" },
80 {"kodi.inputstream", "", AddonType::INPUTSTREAM, 24048, AddonInstanceSupport::SUPPORT_MANDATORY, "DefaultAddonInputstream.png" },
81 {"kodi.vfs", "", AddonType::VFS, 39013, AddonInstanceSupport::SUPPORT_MANDATORY, "DefaultAddonVfs.png" },
82 {"kodi.imagedecoder", "", AddonType::IMAGEDECODER, 39015, AddonInstanceSupport::SUPPORT_MANDATORY, "DefaultAddonImageDecoder.png" },
83 }};
84 // clang-format on
86 const std::string& CAddonInfo::OriginName() const
88 if (!m_originName)
90 ADDON::AddonPtr origin;
91 if (CServiceBroker::GetAddonMgr().GetAddon(m_origin, origin, ADDON::OnlyEnabled::CHOICE_NO))
92 m_originName = std::make_unique<std::string>(origin->Name());
93 else
94 m_originName = std::make_unique<std::string>(); // remember we tried to fetch the name
96 return *m_originName;
99 /**
100 * static public helper functions
104 std::string CAddonInfo::TranslateType(AddonType type, bool pretty /*= false*/)
106 for (const TypeMapping& map : types)
108 if (type == map.type)
110 if (pretty && map.pretty)
111 return g_localizeStrings.Get(map.pretty);
112 else
113 return std::string(map.name.data(), map.name.size());
116 return "";
119 AddonType CAddonInfo::TranslateType(const std::string& string)
121 for (const TypeMapping& map : types)
123 if (string == map.name || (!map.old_name.empty() && string == map.old_name))
124 return map.type;
127 return AddonType::UNKNOWN;
130 std::string CAddonInfo::TranslateIconType(AddonType type)
132 for (const TypeMapping& map : types)
134 if (type == map.type)
135 return std::string(map.icon.data(), map.icon.size());
137 return "";
140 AddonType CAddonInfo::TranslateSubContent(const std::string& content)
142 if (content == "audio")
143 return AddonType::AUDIO;
144 else if (content == "image")
145 return AddonType::IMAGE;
146 else if (content == "executable")
147 return AddonType::EXECUTABLE;
148 else if (content == "video")
149 return AddonType::VIDEO;
150 else if (content == "game")
151 return AddonType::GAME;
152 else
153 return AddonType::UNKNOWN;
156 AddonInstanceSupport CAddonInfo::InstanceSupportType(AddonType type)
158 const auto it = std::find_if(types.begin(), types.end(),
159 [type](const TypeMapping& entry) { return entry.type == type; });
160 if (it != types.end())
161 return it->instance_support;
163 return AddonInstanceSupport::SUPPORT_NONE;
166 CAddonInfo::CAddonInfo(std::string id, AddonType type) : m_id(std::move(id)), m_mainType(type)
171 const CAddonType* CAddonInfo::Type(AddonType type) const
173 static CAddonType dummy;
175 if (!m_types.empty())
177 if (type == AddonType::UNKNOWN)
178 return &m_types[0];
180 for (auto& addonType : m_types)
182 if (addonType.Type() == type)
183 return &addonType;
187 return &dummy;
190 bool CAddonInfo::HasType(AddonType type, bool mainOnly /*= false*/) const
192 return (m_mainType == type ||
193 ProvidesSubContent(type, mainOnly ? m_mainType : AddonType::UNKNOWN));
196 bool CAddonInfo::ProvidesSubContent(AddonType content, AddonType mainType) const
198 if (content == AddonType::UNKNOWN)
199 return false;
201 for (const auto& addonType : m_types)
203 if ((mainType == AddonType::UNKNOWN || addonType.Type() == mainType) &&
204 addonType.ProvidesSubContent(content))
205 return true;
208 return false;
211 bool CAddonInfo::ProvidesSeveralSubContents() const
213 int contents = 0;
214 for (const auto& addonType : m_types)
215 contents += addonType.ProvidedSubContents();
216 return contents > 0 ? true : false;
219 bool CAddonInfo::MeetsVersion(const CAddonVersion& versionMin, const CAddonVersion& version) const
221 return !(versionMin > m_version || version < m_minversion);
224 const CAddonVersion& CAddonInfo::DependencyMinVersion(const std::string& dependencyID) const
226 auto it = std::find_if(m_dependencies.begin(), m_dependencies.end(),
227 [&](const DependencyInfo& other) { return other.id == dependencyID; });
229 if (it != m_dependencies.end())
230 return it->versionMin;
232 static CAddonVersion emptyVersion;
233 return emptyVersion;
236 const CAddonVersion& CAddonInfo::DependencyVersion(const std::string& dependencyID) const
238 auto it = std::find_if(m_dependencies.begin(), m_dependencies.end(), [&](const DependencyInfo& other) { return other.id == dependencyID; });
240 if (it != m_dependencies.end())
241 return it->version;
243 static CAddonVersion emptyVersion;
244 return emptyVersion;
247 const std::string& CAddonInfo::GetTranslatedText(const std::unordered_map<std::string, std::string>& locales) const
249 if (locales.size() == 1)
250 return locales.begin()->second;
251 else if (locales.empty())
252 return StringUtils::Empty;
254 // find the language from the list that matches the current locale best
255 std::string matchingLanguage = g_langInfo.GetLocale().FindBestMatch(locales);
256 if (matchingLanguage.empty())
257 matchingLanguage = KODI_ADDON_DEFAULT_LANGUAGE_CODE;
259 auto const& translatedValue = locales.find(matchingLanguage);
260 if (translatedValue != locales.end())
261 return translatedValue->second;
262 return StringUtils::Empty;
265 bool CAddonInfo::SupportsMultipleInstances() const
267 switch (m_addonInstanceSupportType)
269 case AddonInstanceSupport::SUPPORT_MANDATORY:
270 case AddonInstanceSupport::SUPPORT_OPTIONAL:
271 return true;
272 case AddonInstanceSupport::SUPPORT_SETTINGS:
273 return m_supportsInstanceSettings;
274 case AddonInstanceSupport::SUPPORT_NONE:
275 default:
276 return false;
280 std::vector<AddonInstanceId> CAddonInfo::GetKnownInstanceIds() const
282 static const std::vector<AddonInstanceId> singletonInstance = {ADDON_SINGLETON_INSTANCE_ID};
284 if (!m_supportsInstanceSettings)
285 return singletonInstance;
287 std::vector<AddonInstanceId> ret;
288 const std::string searchPath = StringUtils::Format("special://profile/addon_data/{}/", m_id);
290 if (XFILE::CDirectory::Exists(searchPath))
292 CFileItemList items;
293 XFILE::CDirectory::GetDirectory(searchPath, items, ".xml", XFILE::DIR_FLAG_NO_FILE_DIRS);
295 static const std::string startName = "instance-settings-";
297 for (const auto& item : items)
299 std::string filename = URIUtils::GetFileName(item->GetPath());
300 if (StringUtils::StartsWithNoCase(filename, startName))
302 URIUtils::RemoveExtension(filename);
303 const std::string_view uid(filename.data() + startName.length());
304 if (!uid.empty() && StringUtils::IsInteger(uid.data()))
305 ret.emplace_back(std::atoi(uid.data()));
310 // If no instances are used, create first as default.
311 if (ret.empty())
312 ret.emplace_back(ADDON_FIRST_INSTANCE_ID);
314 return ret;
317 } /* namespace ADDON */