summaryrefslogtreecommitdiffstats
path: root/xbmc/addons/binary-addons
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
commitc04dcc2e7d834218ef2d4194331e383402495ae1 (patch)
tree7333e38d10d75386e60f336b80c2443c1166031d /xbmc/addons/binary-addons
parentInitial commit. (diff)
downloadkodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz
kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/addons/binary-addons')
-rw-r--r--xbmc/addons/binary-addons/AddonDll.cpp553
-rw-r--r--xbmc/addons/binary-addons/AddonDll.h163
-rw-r--r--xbmc/addons/binary-addons/AddonInstanceHandler.cpp386
-rw-r--r--xbmc/addons/binary-addons/AddonInstanceHandler.h135
-rw-r--r--xbmc/addons/binary-addons/BinaryAddonBase.cpp108
-rw-r--r--xbmc/addons/binary-addons/BinaryAddonBase.h54
-rw-r--r--xbmc/addons/binary-addons/BinaryAddonManager.cpp88
-rw-r--r--xbmc/addons/binary-addons/BinaryAddonManager.h95
-rw-r--r--xbmc/addons/binary-addons/CMakeLists.txt12
-rw-r--r--xbmc/addons/binary-addons/DllAddon.h35
10 files changed, 1629 insertions, 0 deletions
diff --git a/xbmc/addons/binary-addons/AddonDll.cpp b/xbmc/addons/binary-addons/AddonDll.cpp
new file mode 100644
index 0000000..4ff5254
--- /dev/null
+++ b/xbmc/addons/binary-addons/AddonDll.cpp
@@ -0,0 +1,553 @@
+/*
+ * 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 "AddonDll.h"
+
+#include "ServiceBroker.h"
+#include "addons/AddonStatusHandler.h"
+#include "addons/addoninfo/AddonInfo.h"
+#include "addons/binary-addons/BinaryAddonBase.h"
+#include "addons/binary-addons/BinaryAddonManager.h"
+#include "addons/binary-addons/DllAddon.h"
+#include "addons/interfaces/AddonBase.h"
+#include "addons/kodi-dev-kit/include/kodi/versions.h"
+#include "addons/settings/AddonSettings.h"
+#include "events/EventLog.h"
+#include "events/NotificationEvent.h"
+#include "filesystem/File.h"
+#include "filesystem/SpecialProtocol.h"
+#include "messaging/helpers/DialogOKHelper.h"
+#include "settings/lib/SettingSection.h"
+#include "utils/URIUtils.h"
+#include "utils/Variant.h"
+#include "utils/log.h"
+
+#include <utility>
+
+using namespace KODI::MESSAGING;
+
+namespace ADDON
+{
+
+CAddonDll::CAddonDll(const AddonInfoPtr& addonInfo, BinaryAddonBasePtr addonBase)
+ : CAddon(addonInfo, addonInfo->MainType()), m_binaryAddonBase(std::move(addonBase))
+{
+}
+
+CAddonDll::CAddonDll(const AddonInfoPtr& addonInfo, AddonType addonType)
+ : CAddon(addonInfo, addonType),
+ m_binaryAddonBase(CServiceBroker::GetBinaryAddonManager().GetRunningAddonBase(addonInfo->ID()))
+{
+}
+
+CAddonDll::~CAddonDll()
+{
+ if (m_initialized)
+ Destroy();
+}
+
+std::string CAddonDll::GetDllPath(const std::string &libPath)
+{
+ std::string strFileName = libPath;
+ std::string strLibName = URIUtils::GetFileName(strFileName);
+
+ if (strLibName.empty())
+ return "";
+
+ /* Check if lib being loaded exists, else check in XBMC binary location */
+#if defined(TARGET_ANDROID)
+ if (XFILE::CFile::Exists(strFileName))
+ {
+ bool doCopy = true;
+ std::string dstfile = URIUtils::AddFileToFolder(CSpecialProtocol::TranslatePath("special://xbmcaltbinaddons/"), strLibName);
+
+ struct __stat64 dstFileStat;
+ if (XFILE::CFile::Stat(dstfile, &dstFileStat) == 0)
+ {
+ struct __stat64 srcFileStat;
+ if (XFILE::CFile::Stat(strFileName, &srcFileStat) == 0)
+ {
+ if (dstFileStat.st_size == srcFileStat.st_size && dstFileStat.st_mtime > srcFileStat.st_mtime)
+ doCopy = false;
+ }
+ }
+
+ if (doCopy)
+ {
+ CLog::Log(LOGDEBUG, "ADDON: caching {} to {}", strFileName, dstfile);
+ XFILE::CFile::Copy(strFileName, dstfile);
+ }
+
+ strFileName = dstfile;
+ }
+ if (!XFILE::CFile::Exists(strFileName))
+ {
+ std::string tempbin = getenv("KODI_ANDROID_LIBS");
+ strFileName = tempbin + "/" + strLibName;
+ }
+#endif
+
+ if (!XFILE::CFile::Exists(strFileName))
+ {
+ std::string strAltFileName;
+
+ std::string altbin = CSpecialProtocol::TranslatePath("special://xbmcaltbinaddons/");
+ if (!altbin.empty())
+ {
+ strAltFileName = altbin + strLibName;
+ if (!XFILE::CFile::Exists(strAltFileName))
+ {
+ std::string temp = CSpecialProtocol::TranslatePath("special://xbmc/addons/");
+ strAltFileName = strFileName;
+ strAltFileName.erase(0, temp.size());
+ strAltFileName = altbin + strAltFileName;
+ }
+ CLog::Log(LOGDEBUG, "ADDON: Trying to load {}", strAltFileName);
+ }
+
+ if (XFILE::CFile::Exists(strAltFileName))
+ strFileName = strAltFileName;
+ else
+ {
+ std::string temp = CSpecialProtocol::TranslatePath("special://xbmc/");
+ std::string tempbin = CSpecialProtocol::TranslatePath("special://xbmcbin/");
+ strFileName.erase(0, temp.size());
+ strFileName = tempbin + strFileName;
+ if (!XFILE::CFile::Exists(strFileName))
+ {
+ CLog::Log(LOGERROR, "ADDON: Could not locate {}", strLibName);
+ strFileName.clear();
+ }
+ }
+ }
+
+ return strFileName;
+}
+
+std::string CAddonDll::LibPath() const
+{
+ return GetDllPath(CAddon::LibPath());
+}
+
+bool CAddonDll::LoadDll()
+{
+ if (m_pDll)
+ return true;
+
+ std::string strFileName = LibPath();
+ if (strFileName.empty())
+ return false;
+
+ /* Load the Dll */
+ m_pDll = new DllAddon;
+ m_pDll->SetFile(strFileName);
+ m_pDll->EnableDelayedUnload(false);
+ if (!m_pDll->Load())
+ {
+ delete m_pDll;
+ m_pDll = nullptr;
+
+ std::string heading =
+ StringUtils::Format("{}: {}", CAddonInfo::TranslateType(Type(), true), Name());
+ HELPERS::ShowOKDialogLines(CVariant{heading}, CVariant{24070}, CVariant{24071});
+
+ return false;
+ }
+
+ return true;
+}
+
+ADDON_STATUS CAddonDll::Create(KODI_ADDON_INSTANCE_STRUCT* firstKodiInstance)
+{
+ CLog::Log(LOGDEBUG, "ADDON: Dll Initializing - {}", Name());
+ m_initialized = false;
+
+ if (!LoadDll())
+ {
+ return ADDON_STATUS_PERMANENT_FAILURE;
+ }
+
+ /* Check versions about global parts on add-on (parts used on all types) */
+ for (unsigned int id = ADDON_GLOBAL_MAIN; id <= ADDON_GLOBAL_MAX; ++id)
+ {
+ if (!CheckAPIVersion(id))
+ return ADDON_STATUS_PERMANENT_FAILURE;
+ }
+
+ /* Allocate the helper function class to allow crosstalk over
+ helper add-on headers */
+ if (!Interface_Base::InitInterface(this, m_interface, firstKodiInstance))
+ return ADDON_STATUS_PERMANENT_FAILURE;
+
+ /* Call Create to make connections, initializing data or whatever is
+ needed to become the AddOn running */
+ ADDON_STATUS status = m_pDll->Create(&m_interface);
+
+ // "C" ABI related call, if on add-on used.
+ if (status == ADDON_STATUS_OK && m_interface.toAddon->create)
+ status = m_interface.toAddon->create(m_interface.firstKodiInstance, &m_interface.addonBase);
+
+ if (status == ADDON_STATUS_OK)
+ {
+ m_initialized = true;
+ }
+ else if (status == ADDON_STATUS_NEED_SETTINGS)
+ {
+ if ((status = TransferSettings(ADDON_SETTINGS_ID)) == ADDON_STATUS_OK)
+ m_initialized = true;
+ else
+ new CAddonStatusHandler(ID(), ADDON_SETTINGS_ID, status, false);
+ }
+ else
+ { // Addon failed initialization
+ CLog::Log(LOGERROR,
+ "ADDON: Dll {} - Client returned bad status ({}) from Create and is not usable",
+ Name(), status);
+
+ // @todo currently a copy and paste from other function and becomes improved.
+ std::string heading =
+ StringUtils::Format("{}: {}", CAddonInfo::TranslateType(Type(), true), Name());
+ HELPERS::ShowOKDialogLines(CVariant{ heading }, CVariant{ 24070 }, CVariant{ 24071 });
+ }
+
+ return status;
+}
+
+void CAddonDll::Destroy()
+{
+ /* Unload library file */
+ if (m_pDll)
+ {
+ if (m_interface.toAddon->destroy)
+ m_interface.toAddon->destroy(m_interface.addonBase);
+ m_pDll->Unload();
+ }
+
+ Interface_Base::DeInitInterface(m_interface);
+
+ if (m_pDll)
+ {
+ delete m_pDll;
+ m_pDll = nullptr;
+ CLog::Log(LOGINFO, "ADDON: Dll Destroyed - {}", Name());
+ }
+
+ ResetSettings(ADDON_SETTINGS_ID);
+
+ m_initialized = false;
+}
+
+ADDON_STATUS CAddonDll::CreateInstance(KODI_ADDON_INSTANCE_STRUCT* instance)
+{
+ assert(instance != nullptr);
+ assert(instance->functions != nullptr);
+ assert(instance->info != nullptr);
+ assert(instance->info->functions != nullptr);
+
+ ADDON_STATUS status = ADDON_STATUS_OK;
+
+ if (!m_initialized)
+ status = Create(instance);
+ if (status != ADDON_STATUS_OK)
+ return status;
+
+ /* Check version of requested instance type */
+ if (!CheckAPIVersion(instance->info->type))
+ return ADDON_STATUS_PERMANENT_FAILURE;
+
+ status = m_interface.toAddon->create_instance(m_interface.addonBase, instance);
+
+ if (instance->info)
+ {
+ m_usedInstances[instance->info->kodi] = instance;
+ }
+
+ return status;
+}
+
+void CAddonDll::DestroyInstance(KODI_ADDON_INSTANCE_STRUCT* instance)
+{
+ if (m_usedInstances.empty())
+ return;
+
+ auto it = m_usedInstances.find(instance->info->kodi);
+ if (it != m_usedInstances.end())
+ {
+ m_interface.toAddon->destroy_instance(m_interface.addonBase, it->second);
+ m_usedInstances.erase(it);
+ }
+
+ if (m_usedInstances.empty())
+ Destroy();
+}
+
+bool CAddonDll::IsInUse() const
+{
+ if (m_informer)
+ return m_informer->IsInUse(ID());
+ return false;
+}
+
+void CAddonDll::RegisterInformer(CAddonDllInformer* informer)
+{
+ m_informer = informer;
+}
+
+AddonPtr CAddonDll::GetRunningInstance() const
+{
+ if (CServiceBroker::IsAddonInterfaceUp())
+ return CServiceBroker::GetBinaryAddonManager().GetRunningAddon(ID());
+
+ return AddonPtr();
+}
+
+void CAddonDll::OnPreInstall()
+{
+ if (m_binaryAddonBase)
+ m_binaryAddonBase->OnPreInstall();
+}
+
+void CAddonDll::OnPostInstall(bool update, bool modal)
+{
+ if (m_binaryAddonBase)
+ m_binaryAddonBase->OnPostInstall(update, modal);
+}
+
+void CAddonDll::OnPreUnInstall()
+{
+ if (m_binaryAddonBase)
+ m_binaryAddonBase->OnPreUnInstall();
+}
+
+void CAddonDll::OnPostUnInstall()
+{
+ if (m_binaryAddonBase)
+ m_binaryAddonBase->OnPostUnInstall();
+}
+
+bool CAddonDll::DllLoaded(void) const
+{
+ return m_pDll != nullptr;
+}
+
+CAddonVersion CAddonDll::GetTypeVersionDll(int type) const
+{
+ return CAddonVersion(m_pDll ? m_pDll->GetAddonTypeVersion(type) : nullptr);
+}
+
+CAddonVersion CAddonDll::GetTypeMinVersionDll(int type) const
+{
+ return CAddonVersion(m_pDll ? m_pDll->GetAddonTypeMinVersion(type) : nullptr);
+}
+
+void CAddonDll::SaveSettings(AddonInstanceId id /* = ADDON_SETTINGS_ID */)
+{
+ // must save first, as TransferSettings() reloads saved settings!
+ CAddon::SaveSettings(id);
+ if (m_initialized)
+ TransferSettings(id);
+}
+
+ADDON_STATUS CAddonDll::TransferSettings(AddonInstanceId instanceId)
+{
+ bool restart = false;
+ ADDON_STATUS reportStatus = ADDON_STATUS_OK;
+
+ CLog::Log(LOGDEBUG, "Calling TransferSettings for: {}", Name());
+
+ LoadSettings(false, true, instanceId);
+
+ auto settings = GetSettings(instanceId);
+ if (settings != nullptr)
+ {
+ KODI_ADDON_INSTANCE_FUNC* instanceTarget{nullptr};
+ KODI_ADDON_INSTANCE_HDL instanceHandle{nullptr};
+ if (instanceId != ADDON_SETTINGS_ID)
+ {
+ const auto it = std::find_if(
+ m_usedInstances.begin(), m_usedInstances.end(),
+ [instanceId](const auto& data) { return data.second->info->number == instanceId; });
+ if (it == m_usedInstances.end())
+ return ADDON_STATUS_UNKNOWN;
+
+ instanceTarget = it->second->functions;
+ instanceHandle = it->second->hdl;
+ }
+
+ for (const auto& section : settings->GetSections())
+ {
+ for (const auto& category : section->GetCategories())
+ {
+ for (const auto& group : category->GetGroups())
+ {
+ for (const auto& setting : group->GetSettings())
+ {
+ if (StringUtils::StartsWith(setting->GetId(), ADDON_SETTING_INSTANCE_GROUP))
+ continue; // skip internal settings
+
+ ADDON_STATUS status = ADDON_STATUS_OK;
+ const char* id = setting->GetId().c_str();
+
+ switch (setting->GetType())
+ {
+ case SettingType::Boolean:
+ {
+ bool tmp = std::static_pointer_cast<CSettingBool>(setting)->GetValue();
+ if (instanceId == ADDON_SETTINGS_ID)
+ {
+ if (m_interface.toAddon->setting_change_boolean)
+ status =
+ m_interface.toAddon->setting_change_boolean(m_interface.addonBase, id, tmp);
+ }
+ else if (instanceTarget && instanceHandle)
+ {
+ if (instanceTarget->instance_setting_change_boolean)
+ status =
+ instanceTarget->instance_setting_change_boolean(instanceHandle, id, tmp);
+ }
+ break;
+ }
+
+ case SettingType::Integer:
+ {
+ int tmp = std::static_pointer_cast<CSettingInt>(setting)->GetValue();
+ if (instanceId == ADDON_SETTINGS_ID)
+ {
+ if (m_interface.toAddon->setting_change_integer)
+ status =
+ m_interface.toAddon->setting_change_integer(m_interface.addonBase, id, tmp);
+ }
+ else if (instanceTarget && instanceHandle)
+ {
+ if (instanceTarget->instance_setting_change_integer)
+ status =
+ instanceTarget->instance_setting_change_integer(instanceHandle, id, tmp);
+ }
+ break;
+ }
+
+ case SettingType::Number:
+ {
+ float tmpf = static_cast<float>(std::static_pointer_cast<CSettingNumber>(setting)->GetValue());
+ if (instanceId == ADDON_SETTINGS_ID)
+ {
+ if (m_interface.toAddon->setting_change_float)
+ status =
+ m_interface.toAddon->setting_change_float(m_interface.addonBase, id, tmpf);
+ }
+ else if (instanceTarget && instanceHandle)
+ {
+ if (instanceTarget->instance_setting_change_float)
+ status =
+ instanceTarget->instance_setting_change_float(instanceHandle, id, tmpf);
+ }
+ break;
+ }
+
+ case SettingType::String:
+ {
+ if (instanceId == ADDON_SETTINGS_ID)
+ {
+ if (m_interface.toAddon->setting_change_string)
+ status = m_interface.toAddon->setting_change_string(
+ m_interface.addonBase, id,
+ std::static_pointer_cast<CSettingString>(setting)->GetValue().c_str());
+ }
+ else if (instanceTarget && instanceHandle)
+ {
+ if (instanceTarget->instance_setting_change_string)
+ status = instanceTarget->instance_setting_change_string(
+ instanceHandle, id,
+ std::static_pointer_cast<CSettingString>(setting)->GetValue().c_str());
+ }
+ break;
+ }
+
+ default:
+ {
+ // log unknowns as an error, but go ahead and transfer the string
+ CLog::Log(LOGERROR, "Unknown setting type of '{}' for {}", id, Name());
+ if (instanceId == ADDON_SETTINGS_ID)
+ {
+ if (m_interface.toAddon->setting_change_string)
+ status = m_interface.toAddon->setting_change_string(
+ m_interface.addonBase, id, setting->ToString().c_str());
+ }
+ else if (instanceTarget && instanceHandle)
+ {
+ if (instanceTarget->instance_setting_change_string)
+ status = instanceTarget->instance_setting_change_string(
+ instanceHandle, id, setting->ToString().c_str());
+ }
+ break;
+ }
+ }
+
+ if (status == ADDON_STATUS_NEED_RESTART)
+ restart = true;
+ else if (status != ADDON_STATUS_OK)
+ reportStatus = status;
+ }
+ }
+ }
+ }
+ }
+
+ if (restart || reportStatus != ADDON_STATUS_OK)
+ {
+ new CAddonStatusHandler(ID(), instanceId, restart ? ADDON_STATUS_NEED_RESTART : reportStatus,
+ true);
+ }
+
+ return ADDON_STATUS_OK;
+}
+
+bool CAddonDll::CheckAPIVersion(int type)
+{
+ /* check the API version */
+ CAddonVersion kodiMinVersion(kodi::addon::GetTypeMinVersion(type));
+ CAddonVersion addonVersion(m_pDll->GetAddonTypeVersion(type));
+ CAddonVersion addonMinVersion = m_pDll->GetAddonTypeMinVersion_available()
+ ? CAddonVersion(m_pDll->GetAddonTypeMinVersion(type))
+ : addonVersion;
+
+ /* Check the global usage from addon
+ * if not used from addon, empty version is returned
+ */
+ if (type <= ADDON_GLOBAL_MAX && addonVersion.empty())
+ return true;
+
+ /* If a instance (not global) version becomes checked must be the version
+ * present.
+ */
+ if (kodiMinVersion > addonVersion ||
+ addonMinVersion > CAddonVersion(kodi::addon::GetTypeVersion(type)))
+ {
+ CLog::Log(LOGERROR, "Add-on '{}' is using an incompatible API version for type '{}'. Kodi API min version = '{}/{}', add-on API version '{}/{}'",
+ Name(),
+ kodi::addon::GetTypeName(type),
+ kodi::addon::GetTypeVersion(type),
+ kodiMinVersion.asString(),
+ addonMinVersion.asString(),
+ addonVersion.asString());
+
+ if (CServiceBroker::GetGUI())
+ {
+ CEventLog* eventLog = CServiceBroker::GetEventLog();
+ if (eventLog)
+ eventLog->AddWithNotification(
+ EventPtr(new CNotificationEvent(Name(), 24152, EventLevel::Error)));
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+} /* namespace ADDON */
diff --git a/xbmc/addons/binary-addons/AddonDll.h b/xbmc/addons/binary-addons/AddonDll.h
new file mode 100644
index 0000000..5f17a04
--- /dev/null
+++ b/xbmc/addons/binary-addons/AddonDll.h
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "addons/Addon.h"
+#include "addons/kodi-dev-kit/include/kodi/c-api/addon_base.h"
+
+#include <map>
+#include <memory>
+#include <string>
+
+class DllAddon;
+
+namespace ADDON
+{
+
+class CBinaryAddonBase;
+using BinaryAddonBasePtr = std::shared_ptr<CBinaryAddonBase>;
+
+/*!
+ * Addon instance handler, used as identify for std::map to find related
+ * addon instance. This class itself not accessed here.
+ *
+ * @todo As long game addon system use CAddonDll itself and not
+ * IAddonInstanceHandler as parent, is the set of this as "void*" needed.
+ * After game system is changed should by this also changed to
+ * "const IAddonInstanceHandler*" or direct in map below.
+ */
+using ADDON_INSTANCE_HANDLER = void*;
+
+/*!
+ * @brief Information class for use on addon type managers.
+ *
+ * This to query via @ref CAddonDll the manager so that work can be performed.
+ * If there are multiple instances it be harder to be informed about any changes.
+ */
+class CAddonDllInformer
+{
+public:
+ virtual ~CAddonDllInformer() = default;
+
+ virtual bool IsInUse(const std::string& id) = 0;
+};
+
+class CAddonDll : public CAddon
+{
+public:
+ CAddonDll(const AddonInfoPtr& addonInfo, BinaryAddonBasePtr addonBase);
+ CAddonDll(const AddonInfoPtr& addonInfo, AddonType addonType);
+ ~CAddonDll() override;
+
+ // Implementation of IAddon via CAddon
+ std::string LibPath() const override;
+
+ // addon settings
+ void SaveSettings(AddonInstanceId id = ADDON_SETTINGS_ID) override;
+
+ bool DllLoaded(void) const;
+
+ /*!
+ * @brief Get api version of moduleType type
+ *
+ * @return The version of requested type, if dll is loaded and supported by addon.
+ * If one of both do not match, an empty version is returned.
+ *
+ * @note This should only be called if the associated dll is loaded.
+ * Otherwise use @ref CAddonInfo::DependencyVersion(...)
+ */
+ CAddonVersion GetTypeVersionDll(int type) const;
+
+ /*!
+ * @brief Get api min version of moduleType type
+ *
+ * @return The version of requested type, if dll is loaded and supported by addon.
+ * If one of both do not match, an empty version is returned.
+ *
+ * @note This should only be called if the associated dll is loaded.
+ * Otherwise use @ref CAddonInfo::DependencyMinVersion(...)
+ */
+ CAddonVersion GetTypeMinVersionDll(int type) const;
+
+ /*!
+ * @brief Function to create a addon instance class
+ *
+ * @param[in,out] instance The for addon used data structure for active instance
+ * @return The status of addon after the creation.
+ */
+ ADDON_STATUS CreateInstance(KODI_ADDON_INSTANCE_STRUCT* instance);
+
+ /*!
+ * @brief Function to destroy a on addon created instance class
+ *
+ * @param[in] instance The for addon used data structure for active instance
+ */
+ void DestroyInstance(KODI_ADDON_INSTANCE_STRUCT* instance);
+
+ bool IsInUse() const override;
+ void RegisterInformer(CAddonDllInformer* informer);
+ AddonPtr GetRunningInstance() const override;
+
+ void OnPreInstall() override;
+ void OnPostInstall(bool update, bool modal) override;
+ void OnPreUnInstall() override;
+ void OnPostUnInstall() override;
+
+ bool Initialized() const { return m_initialized; }
+
+protected:
+ static std::string GetDllPath(const std::string& strFileName);
+
+ std::string m_parentLib;
+
+private:
+ /*!
+ * @brief Main addon creation call function
+ *
+ * This becomes called only one time before a addon instance becomes created.
+ * If another instance becomes requested is this Create no more used. To see
+ * like a "int main()" on exe.
+ *
+ * @param[in] firstKodiInstance The first instance who becomes used.
+ * In case addon supports only one instance
+ * and not multiple together can addon use
+ * only one complete class for everything.
+ * This is used then to interact on interface.
+ * @return The status of addon after the creation.
+ */
+ ADDON_STATUS Create(KODI_ADDON_INSTANCE_STRUCT* firstKodiInstance);
+
+ /*!
+ * @brief Main addon destroying call function
+ *
+ * This becomes called only one time after the last addon instance becomes destroyed.
+ */
+ void Destroy();
+
+ bool CheckAPIVersion(int type);
+
+ BinaryAddonBasePtr m_binaryAddonBase = nullptr;
+ DllAddon* m_pDll = nullptr;
+ bool m_initialized = false;
+ bool LoadDll();
+ std::map<ADDON_INSTANCE_HANDLER, KODI_ADDON_INSTANCE_STRUCT*> m_usedInstances;
+ CAddonDllInformer* m_informer = nullptr;
+
+ virtual ADDON_STATUS TransferSettings(AddonInstanceId instanceId);
+
+ /*!
+ * This structure, which is fixed to the addon headers, makes use of the at
+ * least supposed parts for the interface.
+ * This structure is defined in:
+ * /xbmc/addons/kodi-dev-kit/include/kodi/AddonBase.h
+ */
+ AddonGlobalInterface m_interface = {};
+};
+
+} /* namespace ADDON */
diff --git a/xbmc/addons/binary-addons/AddonInstanceHandler.cpp b/xbmc/addons/binary-addons/AddonInstanceHandler.cpp
new file mode 100644
index 0000000..34c303b
--- /dev/null
+++ b/xbmc/addons/binary-addons/AddonInstanceHandler.cpp
@@ -0,0 +1,386 @@
+/*
+ * 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 "AddonInstanceHandler.h"
+
+#include "ServiceBroker.h"
+#include "addons/AddonVersion.h"
+#include "addons/binary-addons/AddonDll.h"
+#include "addons/binary-addons/BinaryAddonManager.h"
+#include "addons/interfaces/AddonBase.h"
+#include "addons/kodi-dev-kit/include/kodi/AddonBase.h"
+#include "addons/settings/AddonSettings.h"
+#include "filesystem/Directory.h"
+#include "filesystem/SpecialProtocol.h"
+#include "settings/lib/Setting.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+#include <mutex>
+
+namespace ADDON
+{
+
+CCriticalSection IAddonInstanceHandler::m_cdSec;
+
+IAddonInstanceHandler::IAddonInstanceHandler(
+ ADDON_TYPE type,
+ const AddonInfoPtr& addonInfo,
+ AddonInstanceId instanceId /* = ADDON_INSTANCE_ID_UNUSED */,
+ KODI_HANDLE parentInstance /* = nullptr*/,
+ const std::string& uniqueWorkID /* = ""*/)
+ : m_type(type), m_instanceId(instanceId), m_parentInstance(parentInstance), m_addonInfo(addonInfo)
+{
+ // if no special instance ID is given generate one from class pointer (is
+ // faster as unique id and also safe enough for them).
+ m_uniqueWorkID = !uniqueWorkID.empty() ? uniqueWorkID : StringUtils::Format("{}", fmt::ptr(this));
+ m_addonBase = CServiceBroker::GetBinaryAddonManager().GetAddonBase(addonInfo, this, m_addon);
+
+ KODI_ADDON_INSTANCE_INFO* info = new KODI_ADDON_INSTANCE_INFO();
+ info->number = m_instanceId; // @todo change within next big API change to "instance_id"
+ info->id = m_uniqueWorkID.c_str(); // @todo change within next big API change to "unique_work_id"
+ info->version = kodi::addon::GetTypeVersion(m_type);
+ info->type = m_type;
+ info->kodi = this;
+ info->parent = m_parentInstance;
+ info->first_instance = m_addon && !m_addon->Initialized();
+ info->functions = new KODI_ADDON_INSTANCE_FUNC_CB();
+ info->functions->get_instance_user_path = get_instance_user_path;
+ info->functions->is_instance_setting_using_default = is_instance_setting_using_default;
+ info->functions->get_instance_setting_bool = get_instance_setting_bool;
+ info->functions->get_instance_setting_int = get_instance_setting_int;
+ info->functions->get_instance_setting_float = get_instance_setting_float;
+ info->functions->get_instance_setting_string = get_instance_setting_string;
+ info->functions->set_instance_setting_bool = set_instance_setting_bool;
+ info->functions->set_instance_setting_int = set_instance_setting_int;
+ info->functions->set_instance_setting_float = set_instance_setting_float;
+ info->functions->set_instance_setting_string = set_instance_setting_string;
+ m_ifc.info = info;
+ m_ifc.functions = new KODI_ADDON_INSTANCE_FUNC();
+}
+
+IAddonInstanceHandler::~IAddonInstanceHandler()
+{
+ CServiceBroker::GetBinaryAddonManager().ReleaseAddonBase(m_addonBase, this);
+
+ delete m_ifc.functions;
+ if (m_ifc.info)
+ delete m_ifc.info->functions;
+ delete m_ifc.info;
+}
+
+std::string IAddonInstanceHandler::ID() const
+{
+ return m_addon ? m_addon->ID() : "";
+}
+
+std::string IAddonInstanceHandler::Name() const
+{
+ return m_addon ? m_addon->Name() : "";
+}
+
+std::string IAddonInstanceHandler::Author() const
+{
+ return m_addon ? m_addon->Author() : "";
+}
+
+std::string IAddonInstanceHandler::Icon() const
+{
+ return m_addon ? m_addon->Icon() : "";
+}
+
+std::string IAddonInstanceHandler::Path() const
+{
+ return m_addon ? m_addon->Path() : "";
+}
+
+std::string IAddonInstanceHandler::Profile() const
+{
+ return m_addon ? m_addon->Profile() : "";
+}
+
+CAddonVersion IAddonInstanceHandler::Version() const
+{
+ return m_addon ? m_addon->Version() : CAddonVersion();
+}
+
+ADDON_STATUS IAddonInstanceHandler::CreateInstance()
+{
+ if (!m_addon)
+ return ADDON_STATUS_UNKNOWN;
+
+ std::unique_lock<CCriticalSection> lock(m_cdSec);
+
+ ADDON_STATUS status = m_addon->CreateInstance(&m_ifc);
+ if (status != ADDON_STATUS_OK)
+ {
+ CLog::Log(LOGERROR,
+ "IAddonInstanceHandler::{}: {} returned bad status \"{}\" during instance creation",
+ __func__, m_addon->ID(), kodi::addon::TranslateAddonStatus(status));
+ }
+ return status;
+}
+
+void IAddonInstanceHandler::DestroyInstance()
+{
+ std::unique_lock<CCriticalSection> lock(m_cdSec);
+ if (m_addon)
+ m_addon->DestroyInstance(&m_ifc);
+}
+
+std::shared_ptr<CSetting> IAddonInstanceHandler::GetSetting(const std::string& setting)
+{
+ if (!m_addon->HasSettings(m_instanceId))
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - couldn't get settings for add-on '{}'",
+ __func__, Name());
+ return nullptr;
+ }
+
+ auto value = m_addon->GetSettings(m_instanceId)->GetSetting(setting);
+ if (value == nullptr)
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - can't find setting '{}' in '{}'", __func__,
+ setting, Name());
+ return nullptr;
+ }
+
+ return value;
+}
+
+char* IAddonInstanceHandler::get_instance_user_path(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl)
+{
+ IAddonInstanceHandler* instance = static_cast<IAddonInstanceHandler*>(hdl);
+ if (!instance)
+ return nullptr;
+
+ const std::string path = CSpecialProtocol::TranslatePath(instance->m_addon->Profile());
+
+ XFILE::CDirectory::Create(path);
+ return strdup(path.c_str());
+}
+
+bool IAddonInstanceHandler::is_instance_setting_using_default(
+ const KODI_ADDON_INSTANCE_BACKEND_HDL hdl, const char* id)
+{
+ IAddonInstanceHandler* instance = static_cast<IAddonInstanceHandler*>(hdl);
+ if (!instance || !id)
+ return false;
+
+ auto setting = instance->GetSetting(id);
+ if (setting == nullptr)
+ return false;
+
+ return setting->IsDefault();
+}
+
+bool IAddonInstanceHandler::get_instance_setting_bool(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ bool* value)
+{
+ IAddonInstanceHandler* instance = static_cast<IAddonInstanceHandler*>(hdl);
+ if (!instance || !id || !value)
+ return false;
+
+ auto setting = instance->GetSetting(id);
+ if (setting == nullptr)
+ return false;
+
+ if (setting->GetType() != SettingType::Boolean)
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - setting '{}' is not a boolean in '{}'",
+ __func__, id, instance->Name());
+ return false;
+ }
+
+ *value = std::static_pointer_cast<CSettingBool>(setting)->GetValue();
+ return true;
+}
+
+bool IAddonInstanceHandler::get_instance_setting_int(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ int* value)
+{
+ IAddonInstanceHandler* instance = static_cast<IAddonInstanceHandler*>(hdl);
+ if (!instance || !id || !value)
+ return false;
+
+ auto setting = instance->GetSetting(id);
+ if (setting == nullptr)
+ return false;
+
+ if (setting->GetType() != SettingType::Integer && setting->GetType() != SettingType::Number)
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - setting '{}' is not a integer in '{}'",
+ __func__, id, instance->Name());
+ return false;
+ }
+
+ if (setting->GetType() == SettingType::Integer)
+ *value = std::static_pointer_cast<CSettingInt>(setting)->GetValue();
+ else
+ *value = static_cast<int>(std::static_pointer_cast<CSettingNumber>(setting)->GetValue());
+ return true;
+}
+
+bool IAddonInstanceHandler::get_instance_setting_float(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ float* value)
+{
+ IAddonInstanceHandler* instance = static_cast<IAddonInstanceHandler*>(hdl);
+ if (!instance || !id || !value)
+ return false;
+
+ auto setting = instance->GetSetting(id);
+ if (setting == nullptr)
+ return false;
+
+ if (setting->GetType() != SettingType::Number)
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - setting '{}' is not a number in '{}'",
+ __func__, id, instance->Name());
+ return false;
+ }
+
+ *value = static_cast<float>(std::static_pointer_cast<CSettingNumber>(setting)->GetValue());
+ return true;
+}
+
+bool IAddonInstanceHandler::get_instance_setting_string(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ char** value)
+{
+ IAddonInstanceHandler* instance = static_cast<IAddonInstanceHandler*>(hdl);
+ if (!instance || !id || !value)
+ return false;
+
+ auto setting = instance->GetSetting(id);
+ if (setting == nullptr)
+ return false;
+
+ if (setting->GetType() != SettingType::String)
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - setting '{}' is not a string in '{}'",
+ __func__, id, instance->Name());
+ return false;
+ }
+
+ *value = strdup(std::static_pointer_cast<CSettingString>(setting)->GetValue().c_str());
+ return true;
+}
+
+bool IAddonInstanceHandler::set_instance_setting_bool(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ bool value)
+{
+ IAddonInstanceHandler* instance = static_cast<IAddonInstanceHandler*>(hdl);
+ if (!instance || !id)
+ return false;
+
+ if (Interface_Base::UpdateSettingInActiveDialog(instance->m_addon.get(), instance->m_instanceId,
+ id, value ? "true" : "false"))
+ return true;
+
+ if (!instance->m_addon->UpdateSettingBool(id, value, instance->m_instanceId))
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - invalid setting type", __func__);
+ return false;
+ }
+
+ instance->m_addon->SaveSettings(instance->m_instanceId);
+
+ return true;
+}
+
+bool IAddonInstanceHandler::set_instance_setting_int(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ int value)
+{
+ IAddonInstanceHandler* instance = static_cast<IAddonInstanceHandler*>(hdl);
+ if (!instance || !id)
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - invalid data (instance='{}', id='{}')",
+ __func__, hdl, static_cast<const void*>(id));
+
+ return false;
+ }
+
+ if (Interface_Base::UpdateSettingInActiveDialog(instance->m_addon.get(), instance->m_instanceId,
+ id, std::to_string(value)))
+ return true;
+
+ if (!instance->m_addon->UpdateSettingInt(id, value, instance->m_instanceId))
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - invalid setting type", __func__);
+ return false;
+ }
+
+ instance->m_addon->SaveSettings(instance->m_instanceId);
+
+ return true;
+}
+
+bool IAddonInstanceHandler::set_instance_setting_float(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ float value)
+{
+ IAddonInstanceHandler* instance = static_cast<IAddonInstanceHandler*>(hdl);
+ if (!instance || !id)
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - invalid data (instance='{}', id='{}')",
+ __func__, hdl, static_cast<const void*>(id));
+
+ return false;
+ }
+
+ if (Interface_Base::UpdateSettingInActiveDialog(instance->m_addon.get(), instance->m_instanceId,
+ id, StringUtils::Format("{:f}", value)))
+ return true;
+
+ if (!instance->m_addon->UpdateSettingNumber(id, static_cast<double>(value),
+ instance->m_instanceId))
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - invalid setting type", __func__);
+ return false;
+ }
+
+ instance->m_addon->SaveSettings(instance->m_instanceId);
+
+ return true;
+}
+
+bool IAddonInstanceHandler::set_instance_setting_string(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ const char* value)
+{
+ IAddonInstanceHandler* instance = static_cast<IAddonInstanceHandler*>(hdl);
+ if (!instance || !id || !value)
+ {
+ CLog::Log(LOGERROR,
+ "IAddonInstanceHandler::{} - invalid data (instance='{}', id='{}', value='{}')",
+ __func__, hdl, static_cast<const void*>(id), static_cast<const void*>(value));
+
+ return false;
+ }
+
+ if (Interface_Base::UpdateSettingInActiveDialog(instance->m_addon.get(), instance->m_instanceId,
+ id, value))
+ return true;
+
+ if (!instance->m_addon->UpdateSettingString(id, value, instance->m_instanceId))
+ {
+ CLog::Log(LOGERROR, "IAddonInstanceHandler::{} - invalid setting type", __func__);
+ return false;
+ }
+
+ instance->m_addon->SaveSettings(instance->m_instanceId);
+
+ return true;
+}
+
+} /* namespace ADDON */
diff --git a/xbmc/addons/binary-addons/AddonInstanceHandler.h b/xbmc/addons/binary-addons/AddonInstanceHandler.h
new file mode 100644
index 0000000..27ba95b
--- /dev/null
+++ b/xbmc/addons/binary-addons/AddonInstanceHandler.h
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "addons/IAddon.h"
+#include "addons/kodi-dev-kit/include/kodi/c-api/addon_base.h"
+#include "addons/kodi-dev-kit/include/kodi/versions.h"
+#include "threads/CriticalSection.h"
+
+#include <memory>
+#include <string>
+
+class CSetting;
+
+namespace ADDON
+{
+
+class CAddonDll;
+using AddonDllPtr = std::shared_ptr<CAddonDll>;
+
+class CAddonInfo;
+using AddonInfoPtr = std::shared_ptr<CAddonInfo>;
+
+class CBinaryAddonBase;
+using BinaryAddonBasePtr = std::shared_ptr<CBinaryAddonBase>;
+
+class IAddonInstanceHandler
+{
+public:
+ /**
+ * @brief Class constructor for handling add-on instance processes, allowing
+ * an add-on to handle multiple work simultaneously and independently.
+ *
+ * @param[in] type The associated add-on type which is processed in the running
+ * instance.
+ * @param[in] addonInfo Class for querying available add-on information (e.g.
+ * content declared in addon.xml).
+ * @param[in] parentInstance *[opt]* Above running add-on instance which starts this
+ * instance. Used to have the associated class for
+ * work to open in the add-on.\n\n
+ * **Currently used values:**
+ * | Parent | Target | Description
+ * |--------|--------|-------------
+ * | @ref kodi::addon::CInstanceInputStream | @ref kodi::addon::CInstanceVideoCodec | In order to be able to access the overlying input stream instance in the video codec created by Kodi on the add-on.
+ * @param[in] uniqueWorkID *[opt]* Identification value intended to pass any special
+ * values to the instance to be opened.
+ * If not used, the IAddonInstanceHandler class pointer
+ * is used as a string.\n\n
+ * **Currently used values:**
+ * | Add-on instance type | Description
+ * |----------------------|---------------------
+ * | @ref kodi::addon::CInstanceInputStream "Inputstream" | To transfer special values to inputstream using the property @ref STREAM_PROPERTY_INPUTSTREAM_INSTANCE_ID from external space, for example PVR add-on which also supports inputstream can exchange special values with it, e.g. select the necessary add-on processing class, since it is not known at the start what is being executed ( live TV, radio, recordings...) and add-on may use different classes.
+ * | All other | The used class pointer of Kodi's @ref IAddonInstanceHandler is used as a value to have an individually different value.
+ */
+ IAddonInstanceHandler(ADDON_TYPE type,
+ const AddonInfoPtr& addonInfo,
+ AddonInstanceId instanceId = ADDON_INSTANCE_ID_UNUSED,
+ KODI_HANDLE parentInstance = nullptr,
+ const std::string& uniqueWorkID = "");
+ virtual ~IAddonInstanceHandler();
+
+ ADDON_TYPE UsedType() const { return m_type; }
+ AddonInstanceId InstanceId() const { return m_instanceId; }
+ const std::string& UniqueWorkID() { return m_uniqueWorkID; }
+
+ std::string ID() const;
+ std::string Name() const;
+ std::string Author() const;
+ std::string Icon() const;
+ std::string Path() const;
+ std::string Profile() const;
+ CAddonVersion Version() const;
+
+ ADDON_STATUS CreateInstance();
+ void DestroyInstance();
+ const AddonDllPtr& Addon() const { return m_addon; }
+ AddonInfoPtr GetAddonInfo() const { return m_addonInfo; }
+
+ virtual void OnPreInstall() {}
+ virtual void OnPostInstall(bool update, bool modal) {}
+ virtual void OnPreUnInstall() {}
+ virtual void OnPostUnInstall() {}
+
+protected:
+ KODI_ADDON_INSTANCE_INFO m_info{};
+ KODI_ADDON_INSTANCE_STRUCT m_ifc{};
+
+private:
+ std::shared_ptr<CSetting> GetSetting(const std::string& setting);
+
+ static char* get_instance_user_path(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl);
+ static bool is_instance_setting_using_default(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id);
+ static bool get_instance_setting_bool(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ bool* value);
+ static bool get_instance_setting_int(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ int* value);
+ static bool get_instance_setting_float(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ float* value);
+ static bool get_instance_setting_string(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ char** value);
+ static bool set_instance_setting_bool(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ bool value);
+ static bool set_instance_setting_int(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ int value);
+ static bool set_instance_setting_float(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ float value);
+ static bool set_instance_setting_string(const KODI_ADDON_INSTANCE_BACKEND_HDL hdl,
+ const char* id,
+ const char* value);
+
+ const ADDON_TYPE m_type;
+ const AddonInstanceId m_instanceId;
+ std::string m_uniqueWorkID;
+ KODI_HANDLE m_parentInstance;
+ AddonInfoPtr m_addonInfo;
+ BinaryAddonBasePtr m_addonBase;
+ AddonDllPtr m_addon;
+ static CCriticalSection m_cdSec;
+};
+
+} /* namespace ADDON */
diff --git a/xbmc/addons/binary-addons/BinaryAddonBase.cpp b/xbmc/addons/binary-addons/BinaryAddonBase.cpp
new file mode 100644
index 0000000..cea1586
--- /dev/null
+++ b/xbmc/addons/binary-addons/BinaryAddonBase.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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 "BinaryAddonBase.h"
+
+#include "addons/addoninfo/AddonInfo.h"
+#include "addons/binary-addons/AddonDll.h"
+#include "addons/binary-addons/AddonInstanceHandler.h"
+#include "utils/log.h"
+
+#include <mutex>
+
+using namespace ADDON;
+
+const std::string& CBinaryAddonBase::ID() const
+{
+ return m_addonInfo->ID();
+}
+
+AddonDllPtr CBinaryAddonBase::GetAddon(IAddonInstanceHandler* handler)
+{
+ if (handler == nullptr)
+ {
+ CLog::Log(LOGERROR, "CBinaryAddonBase::{}: for Id '{}' called with empty instance handler",
+ __FUNCTION__, ID());
+ return nullptr;
+ }
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ // If no 'm_activeAddon' is defined create it new.
+ if (m_activeAddon == nullptr)
+ m_activeAddon = std::make_shared<CAddonDll>(m_addonInfo, shared_from_this());
+
+ // add the instance handler to the info to know used amount on addon
+ m_activeAddonHandlers.insert(handler);
+
+ return m_activeAddon;
+}
+
+void CBinaryAddonBase::ReleaseAddon(IAddonInstanceHandler* handler)
+{
+ if (handler == nullptr)
+ {
+ CLog::Log(LOGERROR, "CBinaryAddonBase::{}: for Id '{}' called with empty instance handler",
+ __FUNCTION__, ID());
+ return;
+ }
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ auto presentHandler = m_activeAddonHandlers.find(handler);
+ if (presentHandler == m_activeAddonHandlers.end())
+ return;
+
+ m_activeAddonHandlers.erase(presentHandler);
+
+ // if no handler is present anymore reset and delete the add-on class on information
+ if (m_activeAddonHandlers.empty())
+ {
+ m_activeAddon.reset();
+ }
+}
+
+size_t CBinaryAddonBase::UsedInstanceCount() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return m_activeAddonHandlers.size();
+}
+
+AddonDllPtr CBinaryAddonBase::GetActiveAddon()
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return m_activeAddon;
+}
+
+void CBinaryAddonBase::OnPreInstall()
+{
+ const std::unordered_set<IAddonInstanceHandler*> activeAddonHandlers = m_activeAddonHandlers;
+ for (const auto& instance : activeAddonHandlers)
+ instance->OnPreInstall();
+}
+
+void CBinaryAddonBase::OnPostInstall(bool update, bool modal)
+{
+ const std::unordered_set<IAddonInstanceHandler*> activeAddonHandlers = m_activeAddonHandlers;
+ for (const auto& instance : activeAddonHandlers)
+ instance->OnPostInstall(update, modal);
+}
+
+void CBinaryAddonBase::OnPreUnInstall()
+{
+ const std::unordered_set<IAddonInstanceHandler*> activeAddonHandlers = m_activeAddonHandlers;
+ for (const auto& instance : activeAddonHandlers)
+ instance->OnPreUnInstall();
+}
+
+void CBinaryAddonBase::OnPostUnInstall()
+{
+ const std::unordered_set<IAddonInstanceHandler*> activeAddonHandlers = m_activeAddonHandlers;
+ for (const auto& instance : activeAddonHandlers)
+ instance->OnPostUnInstall();
+}
diff --git a/xbmc/addons/binary-addons/BinaryAddonBase.h b/xbmc/addons/binary-addons/BinaryAddonBase.h
new file mode 100644
index 0000000..789b35a
--- /dev/null
+++ b/xbmc/addons/binary-addons/BinaryAddonBase.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "threads/CriticalSection.h"
+
+#include <memory>
+#include <string>
+#include <unordered_set>
+
+namespace ADDON
+{
+
+ class IAddonInstanceHandler;
+
+ class CAddonInfo;
+ using AddonInfoPtr = std::shared_ptr<CAddonInfo>;
+
+ class CAddonDll;
+ typedef std::shared_ptr<CAddonDll> AddonDllPtr;
+
+ class CBinaryAddonBase : public std::enable_shared_from_this<CBinaryAddonBase>
+ {
+ public:
+ explicit CBinaryAddonBase(const AddonInfoPtr& addonInfo) : m_addonInfo(addonInfo) { }
+
+ const std::string& ID() const;
+
+ AddonDllPtr GetAddon(IAddonInstanceHandler* handler);
+ void ReleaseAddon(IAddonInstanceHandler* handler);
+ size_t UsedInstanceCount() const;
+
+ AddonDllPtr GetActiveAddon();
+
+ void OnPreInstall();
+ void OnPostInstall(bool update, bool modal);
+ void OnPreUnInstall();
+ void OnPostUnInstall();
+
+ private:
+ AddonInfoPtr m_addonInfo;
+
+ mutable CCriticalSection m_critSection;
+ AddonDllPtr m_activeAddon;
+ std::unordered_set<IAddonInstanceHandler*> m_activeAddonHandlers;
+ };
+
+} /* namespace ADDON */
diff --git a/xbmc/addons/binary-addons/BinaryAddonManager.cpp b/xbmc/addons/binary-addons/BinaryAddonManager.cpp
new file mode 100644
index 0000000..699fc09
--- /dev/null
+++ b/xbmc/addons/binary-addons/BinaryAddonManager.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 "BinaryAddonManager.h"
+
+#include "addons/addoninfo/AddonInfo.h"
+#include "addons/binary-addons/AddonDll.h"
+#include "addons/binary-addons/BinaryAddonBase.h"
+#include "utils/log.h"
+
+#include <mutex>
+
+using namespace ADDON;
+
+BinaryAddonBasePtr CBinaryAddonManager::GetAddonBase(const AddonInfoPtr& addonInfo,
+ IAddonInstanceHandler* handler,
+ AddonDllPtr& addon)
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ BinaryAddonBasePtr addonBase;
+
+ const auto& addonInstances = m_runningAddons.find(addonInfo->ID());
+ if (addonInstances != m_runningAddons.end())
+ {
+ addonBase = addonInstances->second;
+ }
+ else
+ {
+ addonBase = std::make_shared<CBinaryAddonBase>(addonInfo);
+
+ m_runningAddons.emplace(addonInfo->ID(), addonBase);
+ }
+
+ if (addonBase)
+ {
+ addon = addonBase->GetAddon(handler);
+ }
+ if (!addon)
+ {
+ CLog::Log(LOGFATAL, "CBinaryAddonManager::{}: Tried to get add-on '{}' who not available!",
+ __func__, addonInfo->ID());
+ }
+
+ return addonBase;
+}
+
+void CBinaryAddonManager::ReleaseAddonBase(const BinaryAddonBasePtr& addonBase,
+ IAddonInstanceHandler* handler)
+{
+ const auto& addon = m_runningAddons.find(addonBase->ID());
+ if (addon == m_runningAddons.end())
+ return;
+
+ addonBase->ReleaseAddon(handler);
+
+ if (addonBase->UsedInstanceCount() > 0)
+ return;
+
+ m_runningAddons.erase(addon);
+}
+
+BinaryAddonBasePtr CBinaryAddonManager::GetRunningAddonBase(const std::string& addonId) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ const auto& addonInstances = m_runningAddons.find(addonId);
+ if (addonInstances != m_runningAddons.end())
+ return addonInstances->second;
+
+ return nullptr;
+}
+
+AddonPtr CBinaryAddonManager::GetRunningAddon(const std::string& addonId) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ const BinaryAddonBasePtr base = GetRunningAddonBase(addonId);
+ if (base)
+ return base->GetActiveAddon();
+
+ return nullptr;
+}
diff --git a/xbmc/addons/binary-addons/BinaryAddonManager.h b/xbmc/addons/binary-addons/BinaryAddonManager.h
new file mode 100644
index 0000000..d7f4a9f
--- /dev/null
+++ b/xbmc/addons/binary-addons/BinaryAddonManager.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "threads/CriticalSection.h"
+
+#include <map>
+#include <memory>
+
+namespace ADDON
+{
+
+ class IAddonInstanceHandler;
+
+ class IAddon;
+ using AddonPtr = std::shared_ptr<IAddon>;
+
+ class CAddonInfo;
+ using AddonInfoPtr = std::shared_ptr<CAddonInfo>;
+
+ class CAddonDll;
+ typedef std::shared_ptr<CAddonDll> AddonDllPtr;
+
+ class CBinaryAddonBase;
+ typedef std::shared_ptr<CBinaryAddonBase> BinaryAddonBasePtr;
+
+ class CBinaryAddonManager
+ {
+ public:
+ CBinaryAddonManager() = default;
+ CBinaryAddonManager(const CBinaryAddonManager&) = delete;
+ ~CBinaryAddonManager() = default;
+
+ /*!
+ * @brief Create or get available addon instance handle base.
+ *
+ * On first call the binary addon base class becomes created, on every next
+ * call of addon id, this becomes given again and a counter about in
+ * @ref CBinaryAddonBase increased.
+ *
+ * @param[in] addonBase related addon base to release
+ * @param[in] handler related instance handle class
+ *
+ * @warning This and @ref ReleaseAddonBase are only be called from
+ * @ref IAddonInstanceHandler, use nowhere else allowed!
+ *
+ */
+ BinaryAddonBasePtr GetAddonBase(const AddonInfoPtr& addonInfo,
+ IAddonInstanceHandler* handler,
+ AddonDllPtr& addon);
+
+ /*!
+ * @brief Release a running addon instance handle base.
+ *
+ * On last release call the here on map stored entry becomes
+ * removed and the dll unloaded.
+ *
+ * @param[in] addonBase related addon base to release
+ * @param[in] handler related instance handle class
+ *
+ */
+ void ReleaseAddonBase(const BinaryAddonBasePtr& addonBase, IAddonInstanceHandler* handler);
+
+ /*!
+ * @brief Get running addon base class for a given addon id.
+ *
+ * @param[in] addonId the addon id
+ * @return running addon base class if found, nullptr otherwise.
+ *
+ */
+ BinaryAddonBasePtr GetRunningAddonBase(const std::string& addonId) const;
+
+ /*!
+ * @brief Used from other addon manager to get active addon over a from him
+ * created CAddonDll.
+ *
+ * @param[in] addonId related addon id string
+ * @return if present the pointer to active one or nullptr if not present
+ *
+ */
+ AddonPtr GetRunningAddon(const std::string& addonId) const;
+
+ private:
+ mutable CCriticalSection m_critSection;
+
+ std::map<std::string, BinaryAddonBasePtr> m_runningAddons;
+ };
+
+} /* namespace ADDON */
diff --git a/xbmc/addons/binary-addons/CMakeLists.txt b/xbmc/addons/binary-addons/CMakeLists.txt
new file mode 100644
index 0000000..33a72ce
--- /dev/null
+++ b/xbmc/addons/binary-addons/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(SOURCES BinaryAddonManager.cpp
+ AddonDll.cpp
+ AddonInstanceHandler.cpp
+ BinaryAddonBase.cpp)
+
+set(HEADERS BinaryAddonManager.h
+ AddonDll.h
+ AddonInstanceHandler.h
+ BinaryAddonBase.h
+ DllAddon.h)
+
+core_add_library(addons_binary-addons)
diff --git a/xbmc/addons/binary-addons/DllAddon.h b/xbmc/addons/binary-addons/DllAddon.h
new file mode 100644
index 0000000..c0399f7
--- /dev/null
+++ b/xbmc/addons/binary-addons/DllAddon.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "DynamicDll.h"
+
+class DllAddonInterface
+{
+public:
+ virtual ~DllAddonInterface() = default;
+ virtual ADDON_STATUS Create(void* cb) = 0;
+ virtual const char* GetAddonTypeVersion(int type)=0;
+ virtual const char* GetAddonTypeMinVersion(int type) = 0;
+};
+
+class DllAddon : public DllDynamic, public DllAddonInterface
+{
+public:
+ DECLARE_DLL_WRAPPER_TEMPLATE(DllAddon)
+ DEFINE_METHOD1(ADDON_STATUS, Create, (void* p1))
+ DEFINE_METHOD1(const char*, GetAddonTypeVersion, (int p1))
+ DEFINE_METHOD1(const char*, GetAddonTypeMinVersion, (int p1))
+ bool GetAddonTypeMinVersion_available() { return m_GetAddonTypeMinVersion != nullptr; }
+ BEGIN_METHOD_RESOLVE()
+ RESOLVE_METHOD_RENAME(ADDON_Create, Create)
+ RESOLVE_METHOD_RENAME(ADDON_GetTypeVersion, GetAddonTypeVersion)
+ RESOLVE_METHOD_RENAME_OPTIONAL(ADDON_GetTypeMinVersion, GetAddonTypeMinVersion)
+ END_METHOD_RESOLVE()
+};