#pragma once
/*
* Copyright (C) 2005-2017 Team Kodi
* http://kodi.tv
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kodi; see the file COPYING. If not, see
* .
*
*/
#include /* va_list, va_start, va_arg, va_end */
#include
#include
#include
#include
#include
#ifndef TARGET_WINDOWS
#ifndef __cdecl
#define __cdecl
#endif
#ifndef __declspec
#define __declspec(X)
#endif
#endif
#undef ATTRIBUTE_PACKED
#undef PRAGMA_PACK_BEGIN
#undef PRAGMA_PACK_END
#if defined(__GNUC__)
#define ATTRIBUTE_PACKED __attribute__ ((packed))
#define PRAGMA_PACK 0
#define ATTRIBUTE_HIDDEN __attribute__ ((visibility ("hidden")))
#endif
#if !defined(ATTRIBUTE_PACKED)
#define ATTRIBUTE_PACKED
#define PRAGMA_PACK 1
#endif
#if !defined(ATTRIBUTE_HIDDEN)
#define ATTRIBUTE_HIDDEN
#endif
#include "versions.h"
namespace kodi { namespace addon { class CAddonBase; }}
namespace kodi { namespace addon { class IAddonInstance; }}
extern "C" {
//==============================================================================
/// Standard undefined pointer handle
typedef void* KODI_HANDLE;
//------------------------------------------------------------------------------
//==============================================================================
///
typedef enum ADDON_STATUS
{
///
ADDON_STATUS_OK,
///
ADDON_STATUS_LOST_CONNECTION,
///
ADDON_STATUS_NEED_RESTART,
///
ADDON_STATUS_NEED_SETTINGS,
///
ADDON_STATUS_UNKNOWN,
/// permanent failure, like failing to resolve methods
ADDON_STATUS_PERMANENT_FAILURE,
/* internal used return error if function becomes not used from child on
* addon */
ADDON_STATUS_NOT_IMPLEMENTED
} ADDON_STATUS;
//------------------------------------------------------------------------------
//==============================================================================
/// @todo remove start with ADDON_* after old way on libXBMC_addon.h is removed
///
typedef enum AddonLog
{
///
ADDON_LOG_DEBUG = 0,
///
ADDON_LOG_INFO = 1,
///
ADDON_LOG_NOTICE = 2,
///
ADDON_LOG_WARNING = 3,
///
ADDON_LOG_ERROR = 4,
///
ADDON_LOG_SEVERE = 5,
///
ADDON_LOG_FATAL = 6
} AddonLog;
//------------------------------------------------------------------------------
/*!
* @brief Handle used to return data from the PVR add-on to CPVRClient
*/
struct ADDON_HANDLE_STRUCT
{
void *callerAddress; /*!< address of the caller */
void *dataAddress; /*!< address to store data in */
int dataIdentifier; /*!< parameter to pass back when calling the callback */
};
typedef ADDON_HANDLE_STRUCT *ADDON_HANDLE;
/*
* To have a on add-on and kodi itself handled string always on known size!
*/
#define ADDON_STANDARD_STRING_LENGTH 1024
#define ADDON_STANDARD_STRING_LENGTH_SMALL 256
/*
* Callback function tables from addon to Kodi
* Set complete from Kodi!
*/
struct AddonToKodiFuncTable_kodi;
struct AddonToKodiFuncTable_kodi_audioengine;
struct AddonToKodiFuncTable_kodi_filesystem;
struct AddonToKodiFuncTable_kodi_network;
struct AddonToKodiFuncTable_kodi_gui;
typedef struct AddonToKodiFuncTable_Addon
{
// Pointer inside Kodi, used on callback functions to give related handle
// class, for this ADDON::CAddonDll inside Kodi.
KODI_HANDLE kodiBase;
// Function addresses used for callbacks from addon to Kodi
void (*free_string)(void* kodiBase, char* str);
void (*free_string_array)(void* kodiBase, char** arr, int numElements);
char* (*get_addon_path)(void* kodiBase);
char* (*get_base_user_path)(void* kodiBase);
void (*addon_log_msg)(void* kodiBase, const int loglevel, const char *msg);
bool (*get_setting_bool)(void* kodiBase, const char* id, bool* value);
bool (*get_setting_int)(void* kodiBase, const char* id, int* value);
bool (*get_setting_float)(void* kodiBase, const char* id, float* value);
bool (*get_setting_string)(void* kodiBase, const char* id, char** value);
bool (*set_setting_bool)(void* kodiBase, const char* id, bool value);
bool (*set_setting_int)(void* kodiBase, const char* id, int value);
bool (*set_setting_float)(void* kodiBase, const char* id, float value);
bool (*set_setting_string)(void* kodiBase, const char* id, const char* value);
AddonToKodiFuncTable_kodi* kodi;
AddonToKodiFuncTable_kodi_audioengine* kodi_audioengine;
AddonToKodiFuncTable_kodi_filesystem* kodi_filesystem;
AddonToKodiFuncTable_kodi_gui* kodi_gui;
AddonToKodiFuncTable_kodi_network *kodi_network;
void* (*get_interface)(void* kodiBase, const char *name, const char *version);
} AddonToKodiFuncTable_Addon;
/*
* Function tables from Kodi to addon
*/
typedef struct KodiToAddonFuncTable_Addon
{
void (*destroy)();
ADDON_STATUS (*get_status)();
ADDON_STATUS (*create_instance)(int instanceType, const char* instanceID, KODI_HANDLE instance, KODI_HANDLE* addonInstance, KODI_HANDLE parent);
void (*destroy_instance)(int instanceType, KODI_HANDLE instance);
ADDON_STATUS (*set_setting)(const char *settingName, const void *settingValue);
} KodiToAddonFuncTable_Addon;
/*
* Main structure passed from kodi to addon with basic information needed to
* create add-on.
*/
typedef struct AddonGlobalInterface
{
// String with full path where add-on is installed (without his name on end)
// Set from Kodi!
const char* libBasePath;
// Pointer of first created instance, used in case this add-on goes with single way
// Set from Kodi!
KODI_HANDLE firstKodiInstance;
// Pointer to master base class inside add-on
// Set from addon header!
kodi::addon::CAddonBase* addonBase;
// Pointer to a instance used on single way (together with this class)
// Set from addon header!
kodi::addon::IAddonInstance* globalSingleInstance;
// Callback function tables from addon to Kodi
// Set from Kodi!
AddonToKodiFuncTable_Addon* toKodi;
// Function tables from Kodi to addon
// Set from addon header!
KodiToAddonFuncTable_Addon* toAddon;
} AddonGlobalInterface;
} /* extern "C" */
//==============================================================================
namespace kodi {
namespace addon {
/*
* Internal class to control various instance types with general parts defined
* here.
*
* Mainly is this currently used to identify requested instance types.
*
* @note This class is not need to know during add-on development thats why
* commented with "*".
*/
class IAddonInstance
{
public:
explicit IAddonInstance(ADDON_TYPE type) : m_type(type) { }
virtual ~IAddonInstance() = default;
virtual ADDON_STATUS CreateInstance(int instanceType, std::string instanceID, KODI_HANDLE instance, KODI_HANDLE& addonInstance)
{
return ADDON_STATUS_NOT_IMPLEMENTED;
}
const ADDON_TYPE m_type;
};
} /* namespace addon */
} /* namespace kodi */
//------------------------------------------------------------------------------
//==============================================================================
namespace kodi {
///
class CSettingValue
{
public:
explicit CSettingValue(const void *settingValue) : m_settingValue(settingValue) {}
bool empty() const { return (m_settingValue == nullptr) ? true : false; }
std::string GetString() const { return (char*)m_settingValue; }
int GetInt() const { return *(int*)m_settingValue; }
unsigned int GetUInt() const { return *(unsigned int*)m_settingValue; }
bool GetBoolean() const { return *(bool*)m_settingValue; }
float GetFloat() const { return *(float*)m_settingValue; }
private:
const void *m_settingValue;
};
} /* namespace kodi */
//------------------------------------------------------------------------------
//==============================================================================
namespace kodi {
namespace addon {
/// Add-on main instance class.
class ATTRIBUTE_HIDDEN CAddonBase
{
public:
CAddonBase()
{
CAddonBase::m_interface->toAddon->destroy = ADDONBASE_Destroy;
CAddonBase::m_interface->toAddon->get_status = ADDONBASE_GetStatus;
CAddonBase::m_interface->toAddon->create_instance = ADDONBASE_CreateInstance;
CAddonBase::m_interface->toAddon->destroy_instance = ADDONBASE_DestroyInstance;
CAddonBase::m_interface->toAddon->set_setting = ADDONBASE_SetSetting;
}
virtual ~CAddonBase() = default;
virtual ADDON_STATUS Create() { return ADDON_STATUS_OK; }
virtual ADDON_STATUS GetStatus() { return ADDON_STATUS_OK; }
virtual ADDON_STATUS SetSetting(const std::string& settingName, const CSettingValue& settingValue) { return ADDON_STATUS_UNKNOWN; }
virtual ADDON_STATUS CreateInstance(int instanceType, std::string instanceID, KODI_HANDLE instance, KODI_HANDLE& addonInstance)
{
/* The handling below is intended for the case of the add-on only one
* instance and this is integrated in the add-on base class.
*/
/* Check about single instance usage */
if (CAddonBase::m_interface->firstKodiInstance == instance && // the kodi side instance pointer must be equal to first one
CAddonBase::m_interface->globalSingleInstance && // the addon side instance pointer must be set
CAddonBase::m_interface->globalSingleInstance->m_type == instanceType) // and the requested type must be equal with used add-on class
{
addonInstance = CAddonBase::m_interface->globalSingleInstance;
return ADDON_STATUS_OK;
}
return ADDON_STATUS_UNKNOWN;
}
/* Global variables of class */
static AddonGlobalInterface* m_interface; // Interface function table to hold addresses on add-on and from kodi
/*private:*/ /* Needed public as long the old call functions becomes used! */
static inline void ADDONBASE_Destroy()
{
delete CAddonBase::m_interface->addonBase;
CAddonBase::m_interface->addonBase = nullptr;
}
static inline ADDON_STATUS ADDONBASE_GetStatus() { return CAddonBase::m_interface->addonBase->GetStatus(); }
static inline ADDON_STATUS ADDONBASE_SetSetting(const char *settingName, const void *settingValue)
{
return CAddonBase::m_interface->addonBase->SetSetting(settingName, CSettingValue(settingValue));
}
static inline ADDON_STATUS ADDONBASE_CreateInstance(int instanceType, const char* instanceID, KODI_HANDLE instance, KODI_HANDLE* addonInstance, KODI_HANDLE parent)
{
ADDON_STATUS status = ADDON_STATUS_NOT_IMPLEMENTED;
if (parent != nullptr)
status = static_cast(parent)->CreateInstance(instanceType, instanceID, instance, *addonInstance);
if (status == ADDON_STATUS_NOT_IMPLEMENTED)
status = CAddonBase::m_interface->addonBase->CreateInstance(instanceType, instanceID, instance, *addonInstance);
if (*addonInstance == nullptr)
throw std::logic_error("kodi::addon::CAddonBase CreateInstance returns a empty instance pointer!");
if (static_cast<::kodi::addon::IAddonInstance*>(*addonInstance)->m_type != instanceType)
throw std::logic_error("kodi::addon::CAddonBase CreateInstance with difference on given and returned instance type!");
return status;
}
static inline void ADDONBASE_DestroyInstance(int instanceType, KODI_HANDLE instance)
{
if (CAddonBase::m_interface->globalSingleInstance == nullptr && instance != CAddonBase::m_interface->addonBase)
{
if (static_cast<::kodi::addon::IAddonInstance*>(instance)->m_type == instanceType)
delete static_cast<::kodi::addon::IAddonInstance*>(instance);
else
throw std::logic_error("kodi::addon::CAddonBase DestroyInstance called with difference on given and present instance type!");
}
}
};
} /* namespace addon */
} /* namespace kodi */
//------------------------------------------------------------------------------
//==============================================================================
namespace kodi {
///
inline std::string GetAddonPath(const std::string& append = "")
{
char* str = ::kodi::addon::CAddonBase::m_interface->toKodi->get_addon_path(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase);
std::string ret = str;
::kodi::addon::CAddonBase::m_interface->toKodi->free_string(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, str);
if (!append.empty())
{
if (append.at(0) != '\\' &&
append.at(0) != '/')
#ifdef TARGET_WINDOWS
ret.append("\\");
#else
ret.append("/");
#endif
ret.append(append);
}
return ret;
}
} /* namespace kodi */
//------------------------------------------------------------------------------
//==============================================================================
namespace kodi {
///
inline std::string GetBaseUserPath(const std::string& append = "")
{
char* str = ::kodi::addon::CAddonBase::m_interface->toKodi->get_base_user_path(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase);
std::string ret = str;
::kodi::addon::CAddonBase::m_interface->toKodi->free_string(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, str);
if (!append.empty())
{
if (append.at(0) != '\\' &&
append.at(0) != '/')
#ifdef TARGET_WINDOWS
ret.append("\\");
#else
ret.append("/");
#endif
ret.append(append);
}
return ret;
}
} /* namespace kodi */
//------------------------------------------------------------------------------
//==============================================================================
namespace kodi {
///
inline std::string GetLibPath()
{
return ::kodi::addon::CAddonBase::m_interface->libBasePath;
}
} /* namespace kodi */
//------------------------------------------------------------------------------
//==============================================================================
namespace kodi {
///
inline void Log(const AddonLog loglevel, const char* format, ...)
{
char buffer[16384];
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
va_end(args);
::kodi::addon::CAddonBase::m_interface->toKodi->addon_log_msg(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, loglevel, buffer);
}
} /* namespace kodi */
//------------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline bool CheckSettingString(const std::string& settingName, std::string& settingValue)
{
char* buffer = nullptr;
bool ret = ::kodi::addon::CAddonBase::m_interface->toKodi->get_setting_string(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &buffer);
if (buffer)
{
if (ret)
settingValue = buffer;
::kodi::addon::CAddonBase::m_interface->toKodi->free_string(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, buffer);
}
return ret;
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline std::string GetSettingString(const std::string& settingName)
{
std::string settingValue;
CheckSettingString(settingName, settingValue);
return settingValue;
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline void SetSettingString(const std::string& settingName, const std::string& settingValue)
{
::kodi::addon::CAddonBase::m_interface->toKodi->set_setting_string(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), settingValue.c_str());
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline bool CheckSettingInt(const std::string& settingName, int& settingValue)
{
return ::kodi::addon::CAddonBase::m_interface->toKodi->get_setting_int(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &settingValue);
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline int GetSettingInt(const std::string& settingName)
{
int settingValue = 0;
CheckSettingInt(settingName, settingValue);
return settingValue;
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline void SetSettingInt(const std::string& settingName, int settingValue)
{
::kodi::addon::CAddonBase::m_interface->toKodi->set_setting_int(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), settingValue);
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline bool CheckSettingBoolean(const std::string& settingName, bool& settingValue)
{
return ::kodi::addon::CAddonBase::m_interface->toKodi->get_setting_bool(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &settingValue);
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline bool GetSettingBoolean(const std::string& settingName)
{
bool settingValue = false;
CheckSettingBoolean(settingName, settingValue);
return settingValue;
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline void SetSettingBoolean(const std::string& settingName, bool settingValue)
{
::kodi::addon::CAddonBase::m_interface->toKodi->set_setting_bool(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), settingValue);
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline bool CheckSettingFloat(const std::string& settingName, float& settingValue)
{
return ::kodi::addon::CAddonBase::m_interface->toKodi->get_setting_float(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &settingValue);
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline float GetSettingFloat(const std::string& settingName)
{
float settingValue = 0.0f;
CheckSettingFloat(settingName, settingValue);
return settingValue;
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline void SetSettingFloat(const std::string& settingName, float settingValue)
{
::kodi::addon::CAddonBase::m_interface->toKodi->set_setting_float(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), settingValue);
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//============================================================================
namespace kodi {
///
inline std::string TranslateAddonStatus(ADDON_STATUS status)
{
switch (status)
{
case ADDON_STATUS_OK:
return "OK";
case ADDON_STATUS_LOST_CONNECTION:
return "Lost Connection";
case ADDON_STATUS_NEED_RESTART:
return "Need Restart";
case ADDON_STATUS_NEED_SETTINGS:
return "Need Settings";
case ADDON_STATUS_UNKNOWN:
return "Unknown error";
case ADDON_STATUS_PERMANENT_FAILURE:
return "Permanent failure";
case ADDON_STATUS_NOT_IMPLEMENTED:
return "Not implemented";
default:
break;
}
return "Unknown";
}
} /* namespace kodi */
//----------------------------------------------------------------------------
//==============================================================================
namespace kodi {
///
/// \ingroup cpp_kodi
/// @brief Returns a function table to a named interface
///
/// @return pointer to struct containing interface functions
///
///
/// ------------------------------------------------------------------------
///
/// **Example:**
/// ~~~~~~~~~~~~~{.cpp}
/// #include
/// #include
/// ...
/// FuncTable_foo *table = kodi::GetPlatformInfo(foo_name, foo_version);
/// ...
/// ~~~~~~~~~~~~~
///
inline void* GetInterface(const std::string &name, const std::string &version)
{
AddonToKodiFuncTable_Addon* toKodi = ::kodi::addon::CAddonBase::m_interface->toKodi;
return toKodi->get_interface(toKodi->kodiBase, name.c_str(), version.c_str());
}
} /* namespace kodi */
/*! addon creation macro
* @todo cleanup this stupid big macro
* This macro includes now all for add-on's needed functions. This becomes a bigger
* rework after everything is done on Kodi itself, currently is this way needed
* to have compatibility with not reworked interfaces.
*
* Becomes really cleaned up soon :D
*/
#define ADDONCREATOR(AddonClass) \
extern "C" __declspec(dllexport) void get_addon(void* pAddon) {} \
extern "C" __declspec(dllexport) ADDON_STATUS ADDON_Create(KODI_HANDLE addonInterface, void *unused) \
{ \
kodi::addon::CAddonBase::m_interface = static_cast(addonInterface); \
kodi::addon::CAddonBase::m_interface->addonBase = new AddonClass; \
return kodi::addon::CAddonBase::m_interface->addonBase->Create(); \
} \
extern "C" __declspec(dllexport) void ADDON_Destroy() \
{ \
kodi::addon::CAddonBase::ADDONBASE_Destroy(); \
} \
extern "C" __declspec(dllexport) ADDON_STATUS ADDON_GetStatus() \
{ \
return kodi::addon::CAddonBase::ADDONBASE_GetStatus(); \
} \
extern "C" __declspec(dllexport) ADDON_STATUS ADDON_SetSetting(const char *settingName, const void *settingValue) \
{ \
return kodi::addon::CAddonBase::ADDONBASE_SetSetting(settingName, settingValue); \
} \
extern "C" __declspec(dllexport) const char* ADDON_GetTypeVersion(int type) \
{ \
return kodi::addon::GetTypeVersion(type); \
} \
AddonGlobalInterface* kodi::addon::CAddonBase::m_interface = nullptr;