/* * Copyright (C) 2015-2018 Team Kodi * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #pragma once #include "../AddonBase.h" #include "../Filesystem.h" #if !defined(_WIN32) #include #if !defined(__stat64) #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) #define __stat64 stat #else #define __stat64 stat64 #endif #endif #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ //============================================================================ /// @ingroup cpp_kodi_addon_vfs_Defs /// @brief **VFS add-on URL data**\n /// This class is used to inform the addon of the desired wanted connection. /// /// Used on mostly all addon functions to identify related target. /// struct VFSURL { /// @brief Desired URL of the file system to be edited /// /// This includes all available parts of the access and is structured as /// follows: /// - ``://``:```@```:``/``?`` const char* url; /// @brief The associated domain name, which is optional and not available /// in all cases. const char* domain; /// @brief This includes the network address (e.g. `192.168.0.123`) or if /// the addon refers to file packages the path to it /// (e.g. `/home/by_me/MyPacket.rar`). const char* hostname; /// @brief With this variable the desired path to a folder or file within /// the hostname is given (e.g. `storage/videos/00001.ts`). const char* filename; /// @brief [Networking port](https://en.wikipedia.org/wiki/Port_(computer_networking)) /// to use for protocol. unsigned int port; /// @brief Special options on opened URL, this can e.g. on RAR packages /// `?flags=8&nextvalue=123` to inform about to not cache a read. /// /// Available options from Kodi: /// | Value: | Description: /// |-----------|------------------- /// | flags=8 | Used on RAR packages so that no data is cached from the requested source. /// | cache=no | Used on ZIP packages so that no data from the requested source is stored in the cache. However, this is currently not available from addons! /// /// In addition, other addons can use the URLs given by them to give options /// that fit the respective VFS addon and allow special operations. /// /// @note This procedure is not yet standardized and is currently not /// exactly available which are handed over. const char* options; /// @brief Desired username. const char* username; /// @brief Desired password. const char* password; /// @brief The complete URL is passed on here, but the user name and /// password are not shown and only appear to there as `USERNAME:PASSWORD`. /// /// As example `sftp://USERNAME:PASSWORD@192.168.178.123/storage/videos/00001.ts`. const char* redacted; /// @brief The name which is taken as the basis by source and would be first /// in folder view. /// /// As example on `sftp://dudu:isprivate@192.168.178.123/storage/videos/00001.ts` /// becomes then `storage` used here. const char* sharename; /// @brief Protocol name used on this stream, e.g. `sftp`. const char* protocol; }; //---------------------------------------------------------------------------- //============================================================================ /// @ingroup cpp_kodi_addon_vfs_Defs /// @brief In/out value which is queried at @ref kodi::addon::CInstanceVFS::IoControl.\n /// This declares the requested value on the addon, this gets or has to /// transfer data depending on the value. enum VFS_IOCTRL { /// @brief For cases where not supported control becomes asked. /// /// @note Should normally not given to addon. VFS_IOCTRL_INVALID = 0, /// @brief @ref VFS_IOCTRL_NATIVE_DATA structure, containing what should be /// passed to native ioctrl. VFS_IOCTRL_NATIVE = 1, /// @brief To check seek is possible. /// //// Return 0 if known not to work, 1 if it should work on related calls. VFS_IOCTRL_SEEK_POSSIBLE = 2, /// @brief @ref VFS_IOCTRL_CACHE_STATUS_DATA structure structure on related call VFS_IOCTRL_CACHE_STATUS = 3, /// @brief Unsigned int with speed limit for caching in bytes per second VFS_IOCTRL_CACHE_SETRATE = 4, /// @brief Enable/disable retry within the protocol handler (if supported) VFS_IOCTRL_SET_RETRY = 16, }; //---------------------------------------------------------------------------- //============================================================================ /// @ingroup cpp_kodi_addon_vfs_Defs /// @brief Structure used in @ref kodi::addon::CInstanceVFS::IoControl /// if question value for @ref VFS_IOCTRL_NATIVE is set\n /// With this structure, data is transmitted to the Kodi addon. /// /// This corresponds to POSIX systems with regard to [ioctl](https://en.wikipedia.org/wiki/Ioctl) /// data (emulated with Windows). struct VFS_IOCTRL_NATIVE_DATA { unsigned long int request; void* param; }; //---------------------------------------------------------------------------- //============================================================================ /// @ingroup cpp_kodi_addon_vfs_Defs /// @brief Structure used in @ref kodi::addon::CInstanceVFS::IoControl /// if question value for @ref VFS_IOCTRL_CACHE_STATUS is set\n /// This data is filled by the addon and returned to Kodi struct VFS_IOCTRL_CACHE_STATUS_DATA { /// @brief Number of bytes cached forward of current position. uint64_t forward; /// @brief Maximum number of bytes per second cache is allowed to fill. unsigned int maxrate; /// @brief Average read rate from source file since last position change. unsigned int currate; /// @brief Cache low speed condition detected? bool lowspeed; }; //---------------------------------------------------------------------------- typedef struct VFSGetDirectoryCallbacks /* internal */ { bool (__cdecl* get_keyboard_input)(void* ctx, const char* heading, char** input, bool hidden_input); void (__cdecl* set_error_dialog)(void* ctx, const char* heading, const char* line1, const char* line2, const char* line3); void (__cdecl* require_authentication)(void* ctx, const char* url); void* ctx; } VFSGetDirectoryCallbacks; typedef struct AddonProps_VFSEntry /* internal */ { int dummy; } AddonProps_VFSEntry; typedef struct AddonToKodiFuncTable_VFSEntry /* internal */ { KODI_HANDLE kodiInstance; } AddonToKodiFuncTable_VFSEntry; struct AddonInstance_VFSEntry; typedef struct KodiToAddonFuncTable_VFSEntry /* internal */ { KODI_HANDLE addonInstance; void*(__cdecl* open)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url); void*(__cdecl* open_for_write)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url, bool overwrite); ssize_t(__cdecl* read)(const struct AddonInstance_VFSEntry* instance, void* context, void* buffer, size_t buf_size); ssize_t(__cdecl* write)(const struct AddonInstance_VFSEntry* instance, void* context, const void* buffer, size_t buf_size); int64_t(__cdecl* seek)(const struct AddonInstance_VFSEntry* instance, void* context, int64_t position, int whence); int(__cdecl* truncate)(const struct AddonInstance_VFSEntry* instance, void* context, int64_t size); int64_t(__cdecl* get_length)(const struct AddonInstance_VFSEntry* instance, void* context); int64_t(__cdecl* get_position)(const struct AddonInstance_VFSEntry* instance, void* context); int(__cdecl* get_chunk_size)(const struct AddonInstance_VFSEntry* instance, void* context); int(__cdecl* io_control)(const struct AddonInstance_VFSEntry* instance, void* context, enum VFS_IOCTRL request, void* param); int(__cdecl* stat)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url, struct __stat64* buffer); bool(__cdecl* close)(const struct AddonInstance_VFSEntry* instance, void* context); bool(__cdecl* exists)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url); void(__cdecl* clear_out_idle)(const struct AddonInstance_VFSEntry* instance); void(__cdecl* disconnect_all)(const struct AddonInstance_VFSEntry* instance); bool(__cdecl* delete_it)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url); bool(__cdecl* rename)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url, const struct VFSURL* url2); bool(__cdecl* directory_exists)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url); bool(__cdecl* remove_directory)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url); bool(__cdecl* create_directory)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url); bool(__cdecl* get_directory)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url, struct VFSDirEntry** entries, int* num_entries, VFSGetDirectoryCallbacks* callbacks); bool(__cdecl* contains_files)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url, struct VFSDirEntry** entries, int* num_entries, char* rootpath); void(__cdecl* free_directory)(const struct AddonInstance_VFSEntry* instance, struct VFSDirEntry* entries, int num_entries); } KodiToAddonFuncTable_VFSEntry; typedef struct AddonInstance_VFSEntry /* internal */ { AddonProps_VFSEntry* props; AddonToKodiFuncTable_VFSEntry* toKodi; KodiToAddonFuncTable_VFSEntry* toAddon; } AddonInstance_VFSEntry; #ifdef __cplusplus } /* extern "C" */ namespace kodi { namespace addon { //############################################################################## /// @defgroup cpp_kodi_addon_vfs_Defs Definitions, structures and enumerators /// \ingroup cpp_kodi_addon_vfs /// @brief **VFS add-on general variables** /// /// Used to exchange the available options between Kodi and addon. /// /// //============================================================================== /// /// \addtogroup cpp_kodi_addon_vfs /// @brief \cpp_class{ kodi::addon::CInstanceVFS } /// **Virtual Filesystem (VFS) add-on instance** /// /// This instance type is used to allow Kodi various additional file system /// types. Be it a special file system, a compressed package or a system /// available over the network, everything is possible with it. /// /// This usage can be requested under various conditions, for example explicitly /// by another addon, by a Mimetype protocol defined in `addon.xml` or supported /// file extensions. /// /// Include the header @ref VFS.h "#include " /// to use this class. /// /// ---------------------------------------------------------------------------- /// /// Here is an example of what the `addon.xml.in` would look like for an VFS addon: /// /// ~~~~~~~~~~~~~{.xml} /// /// /// @ADDON_DEPENDS@ /// /// /// My VFS addon summary /// My VFS description /// @PLATFORM@ /// /// /// ~~~~~~~~~~~~~ /// /// @note Regarding boolean values with "false", these can also be omitted, /// since this would be the default. /// /// /// ### Standard values that can be declared for processing in `addon.xml`. /// /// These values are used by Kodi to identify associated streams and file /// extensions and then to select the associated addon. /// /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ `point`, /// \anchor cpp_kodi_addon_vfs_point /// string, /// The identification of the addon instance to VFS is mandatory `kodi.vfs`. /// In addition\, the instance declared in the first `` is also the main type of addon. /// } /// \table_row3{ `defaultPort`, /// \anchor cpp_kodi_addon_vfs_defaultPort /// integer, /// Default [networking port](https://en.wikipedia.org/wiki/Port_(computer_networking)) /// to use for protocol. /// } /// \table_row3{ `directories`, /// \anchor cpp_kodi_addon_vfs_directories /// boolean, /// VFS entry can list directories. /// } /// \table_row3{ `extensions`, /// \anchor cpp_kodi_addon_vfs_extensions /// string, /// Extensions for VFS entry.\n /// It is possible to declare several using `|`\, e.g. `.abc|.def|.ghi`. /// } /// \table_row3{ `encodedhostname`, /// \anchor cpp_kodi_addon_vfs_encodedhostname /// boolean, /// URL protocol from add-ons use encoded hostnames. /// } /// \table_row3{ `filedirectories`, /// \anchor cpp_kodi_addon_vfs_filedirectories /// boolean, /// VFS entry contains file directories. /// } /// \table_row3{ `files`, /// \anchor cpp_kodi_addon_vfs_directories /// boolean, /// Set to declare that VFS provides files. /// } /// \table_row3{ `protocols`, /// \anchor cpp_kodi_addon_vfs_protocols /// boolean, /// Protocols for VFS entry.\n /// It is possible to declare several using `|`\, e.g. `myprot1|myprot2`.\n /// @note This field also used to show on GUI\, see `supportBrowsing` below about *2:. /// When used there\, however\, only a **single** protocol is possible! /// } /// \table_row3{ `supportWrite`, /// \anchor cpp_kodi_addon_vfs_supportWrite /// boolean, /// Protocol supports write operations. /// } /// \table_row3{ `zeroconf`, /// \anchor cpp_kodi_addon_vfs_zeroconf /// string, /// [Zero conf](https://en.wikipedia.org/wiki/Zero-configuration_networking) announce string for VFS protocol. /// } /// \table_row3{ `library_@PLATFORM@`, /// \anchor cpp_kodi_addon_vfs_library /// string, /// The runtime library used for the addon. This is usually declared by `cmake` and correctly displayed in the translated `addon.xml`. /// } /// \table_end /// /// /// ### User selectable parts of the addon. /// /// The following table describes the values that can be defined by `addon.xml` /// and which part they relate to for user input. /// /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ `supportBrowsing`, /// \anchor cpp_kodi_addon_vfs_protocol_supportBrowsing /// boolean, /// Protocol supports server browsing. Used to open related sources by users in the window.\n\n /// | Associated places in Kodi: | /// | :---- | /// | \image html cpp_kodi_addon_vfs_protocol_1.png | ///
/// *1: The entry in the menu represented by this option corresponds to the text given with `label`. /// When the button is pressed\, @ref CInstanceVFS::GetDirectory is called on the add-on to get its content.\n /// *2: Protocol name of the stream defined with `protocols` in xml.\n /// @remark See also `supportDialog` about *3:. /// } /// \table_row3{ `supportDialog`, /// \anchor cpp_kodi_addon_vfs_protocol_supportDialog /// boolean, /// To point out that Kodi assigns a dialog to this VFS in order to compare it with other values e.g. query supportPassword in it.\n /// This will be available when adding sources in Kodi under "Add network location...".\n\n /// | Associated places in Kodi: | /// | :---- | /// | \image html cpp_kodi_addon_vfs_protocol_2.png | ///
/// *1: Field for selecting the VFS handler\, the addon will be available if `supportDialog` is set to `true`.\n /// *2: To set the associated server address. **Note:** *This field is always activated and cannot be changed by the addon.*\n /// *3: If `supportBrowsing` is set to `true`\, the button for opening a file selection dialog is given here too\, as in the file window.\n /// *4: This field is available if `supportPath` is set to `true`.\n /// *5: To edit the connection port. This field is available if `supportPort` is set to `true`.\n /// *6: This sets the required username and is available when `supportUsername` is set to `true`.\n /// *7: This sets the required password and is available when `supportPassword` is set to `true`. /// } /// \table_row3{ `supportPath`, /// \anchor cpp_kodi_addon_vfs_protocol_supportPath /// boolean, /// Protocol has path in addition to server name (see `supportDialog` about *4:). /// } /// \table_row3{ `supportPort`, /// \anchor cpp_kodi_addon_vfs_protocol_supportPort /// boolean, /// Protocol supports port customization (see `supportDialog` about *5:). /// } /// \table_row3{ `supportUsername`, /// \anchor cpp_kodi_addon_vfs_protocol_supportUsername /// boolean, /// Protocol uses logins (see `supportDialog` about *6:). /// } /// \table_row3{ `supportPassword`, /// \anchor cpp_kodi_addon_vfs_protocol_supportPassword /// boolean, /// Protocol supports passwords (see `supportDialog` about *7:). /// } /// \table_row3{ `protocols`, /// \anchor cpp_kodi_addon_vfs_protocol_protocols /// string, /// Protocols for VFS entry. /// @note This field is not editable and only used on GUI to show his name\, see `supportBrowsing` about *2: /// } /// \table_row3{ `label`, /// \anchor cpp_kodi_addon_vfs_protocol_label /// integer, /// The text identification number used in Kodi for display in the menu at `supportDialog` /// as a selection option and at `supportBrowsing` (see his image reference *1) as a menu entry.\n /// This can be a text identifier in Kodi or from addon.\n /// @remark For addon within 30000-30999 or 32000-32999. /// } /// \table_end /// /// @remark For more detailed description of the `addon.xml`, see also https://kodi.wiki/view/Addon.xml. /// /// /// -------------------------------------------------------------------------- /// /// /// **Example:** /// /// ~~~~~~~~~~~~~{.cpp} /// #include /// /// class CMyVFS : public kodi::addon::CInstanceVFS /// { /// public: /// CMyVFS(KODI_HANDLE instance, const std::string& kodiVersion); /// /// // Add all your required functions, the most CInstanceVFS functions of /// // must be included to have addon working correctly. /// ... /// }; /// /// CMyVFS::CMyVFS(KODI_HANDLE instance, const std::string& kodiVersion) /// : CInstanceVFS(instance, kodiVersion) /// { /// ... /// } /// /// ... /// /// /*----------------------------------------------------------------------*/ /// /// class CMyAddon : public kodi::addon::CAddonBase /// { /// public: /// CMyAddon() { } /// ADDON_STATUS CreateInstance(int instanceType, /// const std::string& instanceID, /// KODI_HANDLE instance, /// const std::string& version, /// KODI_HANDLE& addonInstance) override; /// }; /// /// // If you use only one instance in your add-on, can be instanceType and /// // instanceID ignored /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, /// const std::string& instanceID, /// KODI_HANDLE instance, /// const std::string& version, /// KODI_HANDLE& addonInstance) /// { /// if (instanceType == ADDON_INSTANCE_VFS) /// { /// kodi::Log(ADDON_LOG_NOTICE, "Creating my VFS instance"); /// addonInstance = new CMyVFS(instance, version); /// return ADDON_STATUS_OK; /// } /// else if (...) /// { /// ... /// } /// return ADDON_STATUS_UNKNOWN; /// } /// /// ADDONCREATOR(CMyAddon) /// ~~~~~~~~~~~~~ /// /// The destruction of the example class `CMyVFS` is called from /// Kodi's header. Manually deleting the add-on instance is not required. /// //---------------------------------------------------------------------------- class ATTRIBUTE_HIDDEN CInstanceVFS : public IAddonInstance { public: //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs /// @brief VFS class constructor used to support multiple instance /// types /// /// @param[in] instance The instance value given to /// `kodi::addon::CAddonBase::CreateInstance(...)`. /// @param[in] kodiVersion [opt] given from Kodi by @ref CAddonBase::CreateInstance /// to identify his instance API version /// /// @note Instance path as a single is not supported by this type. It must /// ensure that it can be called up several times. /// /// @warning Only use `instance` from the @ref CAddonBase::CreateInstance or /// @ref CAddonBase::CreateInstance call. /// explicit CInstanceVFS(KODI_HANDLE instance, const std::string& kodiVersion = "") : IAddonInstance(ADDON_INSTANCE_VFS, !kodiVersion.empty() ? kodiVersion : GetKodiTypeVersion(ADDON_INSTANCE_VFS)) { if (CAddonBase::m_interface->globalSingleInstance != nullptr) throw std::logic_error("kodi::addon::CInstanceVFS: Creation of multiple together with single " "instance way is not allowed!"); SetAddonStruct(instance); } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs /// @brief Destructor /// ~CInstanceVFS() override = default; //-------------------------------------------------------------------------- //========================================================================== /// /// @defgroup cpp_kodi_addon_vfs_general 1. General access functions /// @ingroup cpp_kodi_addon_vfs /// @brief **General access functions** /// /// This functions which are intended for getting folders, editing storage /// locations and file system queries. /// //========================================================================== /// /// @defgroup cpp_kodi_addon_vfs_filecontrol 2. File editing functions /// @ingroup cpp_kodi_addon_vfs /// @brief **File editing functions.** /// /// This value represents the addon-side handlers and to be able to identify /// his own parts in the event of further access. /// //@{ //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_filecontrol /// @brief Open a file for input /// /// @param[in] url The URL of the file /// @return Context for the opened file virtual void* Open(const VFSURL& url) { return nullptr; } //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_filecontrol /// @brief Open a file for output /// /// @param[in] url The URL of the file /// @param[in] overWrite Whether or not to overwrite an existing file /// @return Context for the opened file /// virtual void* OpenForWrite(const VFSURL& url, bool overWrite) { return nullptr; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_filecontrol /// @brief Close a file /// /// @param[in] context The context of the file /// @return True on success, false on failure /// virtual bool Close(void* context) { return false; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_filecontrol /// @brief Read from a file /// /// @param[in] context The context of the file /// @param[out] buffer The buffer to read data into /// @param[in] uiBufSize Number of bytes to read /// @return Number of bytes read /// virtual ssize_t Read(void* context, void* buffer, size_t uiBufSize) { return -1; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_filecontrol /// @brief Write to a file /// /// @param[in] context The context of the file /// @param[in] buffer The buffer to read data from /// @param[in] uiBufSize Number of bytes to write /// @return Number of bytes written /// virtual ssize_t Write(void* context, const void* buffer, size_t uiBufSize) { return -1; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_filecontrol /// @brief Seek in a file /// /// @param[in] context The context of the file /// @param[in] position The position to seek to /// @param[in] whence Position in file 'position' is relative to (SEEK_CUR, SEEK_SET, SEEK_END) /// @return Offset in file after seek /// virtual int64_t Seek(void* context, int64_t position, int whence) { return -1; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_filecontrol /// @brief Truncate a file /// /// @param[in] context The context of the file /// @param[in] size The size to truncate the file to /// @return 0 on success, -1 on error /// virtual int Truncate(void* context, int64_t size) { return -1; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_filecontrol /// @brief Get total size of a file /// /// @param[in] context The context of the file /// @return Total file size /// virtual int64_t GetLength(void* context) { return 0; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_filecontrol /// @brief Get current position in a file /// /// @param[in] context The context of the file /// @return Current position /// virtual int64_t GetPosition(void* context) { return 0; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_filecontrol /// @brief Get chunk size of a file /// /// @param[in] context The context of the file /// @return Chunk size /// virtual int GetChunkSize(void* context) { return 1; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_filecontrol /// @brief Perform an IO-control on the file /// /// @param[in] context The context of the file /// @param[in] request The requested IO-control /// @param[in] param Parameter attached to the IO-control /// @return -1 on error, >= 0 on success /// virtual int IoControl(void* context, VFS_IOCTRL request, void* param) { return -1; } //-------------------------------------------------------------------------- //@} //@{ //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_general /// @brief Stat a file /// /// @param[in] url The URL of the file /// @param[in] buffer The buffer to store results in /// @return -1 on error, 0 otherwise /// virtual int Stat(const VFSURL& url, struct __stat64* buffer) { return 0; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_general /// @brief Check for file existence /// /// @param[in] url The URL of the file /// @return True if file exists, false otherwise /// virtual bool Exists(const VFSURL& url) { return false; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_general /// @brief Clear out any idle connections /// virtual void ClearOutIdle() {} //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_general /// @brief Disconnect all connections /// virtual void DisconnectAll() {} //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_general /// @brief Delete a file /// /// @param[in] url The URL of the file /// @return True if deletion was successful, false otherwise /// virtual bool Delete(const VFSURL& url) { return false; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_general /// @brief Rename a file /// /// @param[in] url The URL of the source file /// @param[in] url2 The URL of the destination file /// @return True if deletion was successful, false otherwise /// virtual bool Rename(const VFSURL& url, const VFSURL& url2) { return false; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_general /// @brief Check for directory existence /// /// @param[in] url The URL of the file /// @return True if directory exists, false otherwise /// virtual bool DirectoryExists(const VFSURL& url) { return false; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_general /// @brief Remove a directory /// /// @param[in] url The URL of the directory /// @return True if removal was successful, false otherwise /// virtual bool RemoveDirectory(const VFSURL& url) { return false; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_general /// @brief Create a directory /// /// @param[in] url The URL of the file /// @return True if creation was successful, false otherwise /// virtual bool CreateDirectory(const VFSURL& url) { return false; } //-------------------------------------------------------------------------- //========================================================================== /// /// @defgroup cpp_kodi_addon_vfs_general_cb_GetDirectory **Callbacks GetDirectory()** /// @ingroup cpp_kodi_addon_vfs_general /// @brief Callback functions on GetDirectory() /// /// This functions becomes available during call of GetDirectory() from /// Kodi. /// /// If GetDirectory() returns false becomes the parts from here used on /// next call of the function. /// /// **Example:** /// ~~~~~~~~~~~~~{.cpp} /// /// #include /// /// ... /// /// bool CMyVFS::GetDirectory(const VFSURL& url, std::vector& items, CVFSCallbacks callbacks) /// { /// std::string neededString; /// callbacks.GetKeyboardInput("Test", neededString, true); /// if (neededString.empty()) /// return false; /// /// // Do the work /// ... /// return true; /// } /// ~~~~~~~~~~~~~ /// class CVFSCallbacks { public: /// @ingroup cpp_kodi_addon_vfs_general_cb_GetDirectory /// @brief Require keyboard input /// /// Becomes called if GetDirectory() returns false and GetDirectory() /// becomes after entry called again. /// /// @param[in] heading The heading of the keyboard dialog /// @param[out] input The resulting string. Returns string after /// second call! /// @param[in] hiddenInput To show input only as "*" on dialog /// @return True if input was received, false otherwise /// bool GetKeyboardInput(const std::string& heading, std::string& input, bool hiddenInput = false) { char* cInput = nullptr; bool ret = m_cb->get_keyboard_input(m_cb->ctx, heading.c_str(), &cInput, hiddenInput); if (cInput) { input = cInput; ::kodi::addon::CAddonBase::m_interface->toKodi->free_string( ::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, cInput); } return ret; } /// @ingroup cpp_kodi_addon_vfs_general_cb_GetDirectory /// @brief Display an error dialog /// /// @param[in] heading The heading of the error dialog /// @param[in] line1 The first line of the error dialog /// @param[in] line2 [opt] The second line of the error dialog /// @param[in] line3 [opt] The third line of the error dialog /// void SetErrorDialog(const std::string& heading, const std::string& line1, const std::string& line2 = "", const std::string& line3 = "") { m_cb->set_error_dialog(m_cb->ctx, heading.c_str(), line1.c_str(), line2.c_str(), line3.c_str()); } /// @ingroup cpp_kodi_addon_vfs_general_cb_GetDirectory /// @brief Prompt the user for authentication of a URL /// /// @param[in] url The URL void RequireAuthentication(const std::string& url) { m_cb->require_authentication(m_cb->ctx, url.c_str()); } explicit CVFSCallbacks(const VFSGetDirectoryCallbacks* cb) : m_cb(cb) {} private: const VFSGetDirectoryCallbacks* m_cb; }; //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_general /// @brief List a directory /// /// @param[in] url The URL of the directory /// @param[out] entries The entries in the directory, see /// @ref cpp_kodi_vfs_CDirEntry "kodi::vfs::CDirEntry" /// about his content /// @param[in] callbacks A callback structure /// @return Context for the directory listing /// /// /// -------------------------------------------------------------------------- /// /// ### Callbacks: /// @copydetails cpp_kodi_addon_vfs_general_cb_GetDirectory /// /// **Available callback functions** /// | Function: | Description /// |--|-- /// | CVFSCallbacks::GetKeyboardInput | @copybrief CVFSCallbacks::GetKeyboardInput @copydetails CVFSCallbacks::GetKeyboardInput /// | CVFSCallbacks::SetErrorDialog | @copybrief CVFSCallbacks::SetErrorDialog @copydetails CVFSCallbacks::SetErrorDialog /// | CVFSCallbacks::RequireAuthentication | @copybrief CVFSCallbacks::RequireAuthentication @copydetails CVFSCallbacks::RequireAuthentication /// virtual bool GetDirectory(const VFSURL& url, std::vector& entries, CVFSCallbacks callbacks) { return false; } //-------------------------------------------------------------------------- //========================================================================== /// /// @ingroup cpp_kodi_addon_vfs_general /// @brief Check if file should be presented as a directory (multiple streams) /// /// @param[in] url The URL of the file /// @param[out] entries The entries in the directory, see /// @ref cpp_kodi_vfs_CDirEntry "kodi::vfs::CDirEntry" /// about his content /// @param[out] rootPath Path to root directory if multiple entries /// @return Context for the directory listing /// virtual bool ContainsFiles(const VFSURL& url, std::vector& entries, std::string& rootPath) { return false; } //-------------------------------------------------------------------------- //@} private: void SetAddonStruct(KODI_HANDLE instance) { if (instance == nullptr) throw std::logic_error("kodi::addon::CInstanceVFS: Creation with empty addon structure not " "allowed, table must be given from Kodi!"); m_instanceData = static_cast(instance); m_instanceData->toAddon->addonInstance = this; m_instanceData->toAddon->open = ADDON_Open; m_instanceData->toAddon->open_for_write = ADDON_OpenForWrite; m_instanceData->toAddon->read = ADDON_Read; m_instanceData->toAddon->write = ADDON_Write; m_instanceData->toAddon->seek = ADDON_Seek; m_instanceData->toAddon->truncate = ADDON_Truncate; m_instanceData->toAddon->get_length = ADDON_GetLength; m_instanceData->toAddon->get_position = ADDON_GetPosition; m_instanceData->toAddon->get_chunk_size = ADDON_GetChunkSize; m_instanceData->toAddon->io_control = ADDON_IoControl; m_instanceData->toAddon->stat = ADDON_Stat; m_instanceData->toAddon->close = ADDON_Close; m_instanceData->toAddon->exists = ADDON_Exists; m_instanceData->toAddon->clear_out_idle = ADDON_ClearOutIdle; m_instanceData->toAddon->disconnect_all = ADDON_DisconnectAll; m_instanceData->toAddon->delete_it = ADDON_Delete; m_instanceData->toAddon->rename = ADDON_Rename; m_instanceData->toAddon->directory_exists = ADDON_DirectoryExists; m_instanceData->toAddon->remove_directory = ADDON_RemoveDirectory; m_instanceData->toAddon->create_directory = ADDON_CreateDirectory; m_instanceData->toAddon->get_directory = ADDON_GetDirectory; m_instanceData->toAddon->free_directory = ADDON_FreeDirectory; m_instanceData->toAddon->contains_files = ADDON_ContainsFiles; } inline static void* ADDON_Open(const AddonInstance_VFSEntry* instance, const VFSURL* url) { return static_cast(instance->toAddon->addonInstance)->Open(*url); } inline static void* ADDON_OpenForWrite(const AddonInstance_VFSEntry* instance, const VFSURL* url, bool overWrite) { return static_cast(instance->toAddon->addonInstance) ->OpenForWrite(*url, overWrite); } inline static ssize_t ADDON_Read(const AddonInstance_VFSEntry* instance, void* context, void* buffer, size_t uiBufSize) { return static_cast(instance->toAddon->addonInstance) ->Read(context, buffer, uiBufSize); } inline static ssize_t ADDON_Write(const AddonInstance_VFSEntry* instance, void* context, const void* buffer, size_t uiBufSize) { return static_cast(instance->toAddon->addonInstance) ->Write(context, buffer, uiBufSize); } inline static int64_t ADDON_Seek(const AddonInstance_VFSEntry* instance, void* context, int64_t position, int whence) { return static_cast(instance->toAddon->addonInstance) ->Seek(context, position, whence); } inline static int ADDON_Truncate(const AddonInstance_VFSEntry* instance, void* context, int64_t size) { return static_cast(instance->toAddon->addonInstance)->Truncate(context, size); } inline static int64_t ADDON_GetLength(const AddonInstance_VFSEntry* instance, void* context) { return static_cast(instance->toAddon->addonInstance)->GetLength(context); } inline static int64_t ADDON_GetPosition(const AddonInstance_VFSEntry* instance, void* context) { return static_cast(instance->toAddon->addonInstance)->GetPosition(context); } inline static int ADDON_GetChunkSize(const AddonInstance_VFSEntry* instance, void* context) { return static_cast(instance->toAddon->addonInstance)->GetChunkSize(context); } inline static int ADDON_IoControl(const AddonInstance_VFSEntry* instance, void* context, enum VFS_IOCTRL request, void* param) { return static_cast(instance->toAddon->addonInstance) ->IoControl(context, request, param); } inline static int ADDON_Stat(const AddonInstance_VFSEntry* instance, const VFSURL* url, struct __stat64* buffer) { return static_cast(instance->toAddon->addonInstance)->Stat(*url, buffer); } inline static bool ADDON_Close(const AddonInstance_VFSEntry* instance, void* context) { return static_cast(instance->toAddon->addonInstance)->Close(context); } inline static bool ADDON_Exists(const AddonInstance_VFSEntry* instance, const VFSURL* url) { return static_cast(instance->toAddon->addonInstance)->Exists(*url); } inline static void ADDON_ClearOutIdle(const AddonInstance_VFSEntry* instance) { return static_cast(instance->toAddon->addonInstance)->ClearOutIdle(); } inline static void ADDON_DisconnectAll(const AddonInstance_VFSEntry* instance) { return static_cast(instance->toAddon->addonInstance)->DisconnectAll(); } inline static bool ADDON_Delete(const AddonInstance_VFSEntry* instance, const VFSURL* url) { return static_cast(instance->toAddon->addonInstance)->Delete(*url); } inline static bool ADDON_Rename(const AddonInstance_VFSEntry* instance, const VFSURL* url, const VFSURL* url2) { return static_cast(instance->toAddon->addonInstance)->Rename(*url, *url2); } inline static bool ADDON_DirectoryExists(const AddonInstance_VFSEntry* instance, const VFSURL* url) { return static_cast(instance->toAddon->addonInstance)->DirectoryExists(*url); } inline static bool ADDON_RemoveDirectory(const AddonInstance_VFSEntry* instance, const VFSURL* url) { return static_cast(instance->toAddon->addonInstance)->RemoveDirectory(*url); } inline static bool ADDON_CreateDirectory(const AddonInstance_VFSEntry* instance, const VFSURL* url) { return static_cast(instance->toAddon->addonInstance)->CreateDirectory(*url); } inline static bool ADDON_GetDirectory(const AddonInstance_VFSEntry* instance, const VFSURL* url, VFSDirEntry** retEntries, int* num_entries, VFSGetDirectoryCallbacks* callbacks) { std::vector addonEntries; bool ret = static_cast(instance->toAddon->addonInstance) ->GetDirectory(*url, addonEntries, CVFSCallbacks(callbacks)); if (ret) { VFSDirEntry* entries = static_cast(malloc(sizeof(VFSDirEntry) * addonEntries.size())); for (unsigned int i = 0; i < addonEntries.size(); ++i) { entries[i].label = strdup(addonEntries[i].Label().c_str()); entries[i].title = strdup(addonEntries[i].Title().c_str()); entries[i].path = strdup(addonEntries[i].Path().c_str()); entries[i].folder = addonEntries[i].IsFolder(); entries[i].size = addonEntries[i].Size(); entries[i].date_time = addonEntries[i].DateTime(); entries[i].num_props = 0; const std::map& props = addonEntries[i].GetProperties(); if (!props.empty()) { entries[i].properties = static_cast(malloc(sizeof(VFSProperty) * props.size())); for (const auto& prop : props) { entries[i].properties[entries[i].num_props].name = strdup(prop.first.c_str()); entries[i].properties[entries[i].num_props].val = strdup(prop.second.c_str()); ++entries[i].num_props; } } else entries[i].properties = nullptr; } *retEntries = entries; *num_entries = static_cast(addonEntries.size()); } return ret; } inline static void ADDON_FreeDirectory(const AddonInstance_VFSEntry* instance, VFSDirEntry* entries, int num_entries) { for (int i = 0; i < num_entries; ++i) { if (entries[i].properties) { for (unsigned int j = 0; j < entries[i].num_props; ++j) { free(entries[i].properties[j].name); free(entries[i].properties[j].val); } free(entries[i].properties); } free(entries[i].label); free(entries[i].title); free(entries[i].path); } free(entries); } inline static bool ADDON_ContainsFiles(const AddonInstance_VFSEntry* instance, const VFSURL* url, VFSDirEntry** retEntries, int* num_entries, char* rootpath) { std::string cppRootPath; std::vector addonEntries; bool ret = static_cast(instance->toAddon->addonInstance) ->ContainsFiles(*url, addonEntries, cppRootPath); if (ret) { strncpy(rootpath, cppRootPath.c_str(), ADDON_STANDARD_STRING_LENGTH); VFSDirEntry* entries = static_cast(malloc(sizeof(VFSDirEntry) * addonEntries.size())); for (size_t i = 0; i < addonEntries.size(); ++i) { entries[i].label = strdup(addonEntries[i].Label().c_str()); entries[i].title = strdup(addonEntries[i].Title().c_str()); entries[i].path = strdup(addonEntries[i].Path().c_str()); entries[i].folder = addonEntries[i].IsFolder(); entries[i].size = addonEntries[i].Size(); entries[i].date_time = addonEntries[i].DateTime(); entries[i].num_props = 0; const std::map& props = addonEntries[i].GetProperties(); if (!props.empty()) { entries[i].properties = static_cast(malloc(sizeof(VFSProperty) * props.size())); for (const auto& prop : props) { entries[i].properties[entries[i].num_props].name = strdup(prop.first.c_str()); entries[i].properties[entries[i].num_props].val = strdup(prop.second.c_str()); ++entries[i].num_props; } } else entries[i].properties = nullptr; } *retEntries = entries; *num_entries = static_cast(addonEntries.size()); } return ret; } AddonInstance_VFSEntry* m_instanceData; }; } /* namespace addon */ } /* namespace kodi */ #endif /* __cplusplus */