From 4c3251ec645c8b71820dab7e51e612e5919d4e75 Mon Sep 17 00:00:00 2001 From: manuel Date: Sun, 23 Jul 2017 16:59:43 +0200 Subject: sync with upstream --- .../include/kodi/addon-instance/VFS.h | 622 +++++++++++++++++++++ 1 file changed, 622 insertions(+) create mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VFS.h (limited to 'xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VFS.h') diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VFS.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VFS.h new file mode 100644 index 0000000..4bb3e69 --- /dev/null +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VFS.h @@ -0,0 +1,622 @@ +#pragma once +/* + * Copyright (C) 2015 Team Kodi + * + * 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 "../AddonBase.h" +#include "../Filesystem.h" + +#ifdef BUILD_KODI_ADDON +#include "../IFileTypes.h" +#else +#include "filesystem/IFileTypes.h" +#include "PlatformDefs.h" +#endif + +namespace kodi { namespace addon { class CInstanceVFS; }} + +extern "C" +{ + + struct VFSURL + { + const char* url; + const char* domain; + const char* hostname; + const char* filename; + unsigned int port; + const char* options; + const char* username; + const char* password; + const char* redacted; + const char* sharename; + }; + + 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::addon::CInstanceVFS* addonInstance; + + void* (__cdecl* open) (const AddonInstance_VFSEntry* instance, const VFSURL* url); + void* (__cdecl* open_for_write) (const AddonInstance_VFSEntry* instance, const VFSURL* url, bool overwrite); + ssize_t (__cdecl* read) (const AddonInstance_VFSEntry* instance, void* context, void* buffer, size_t buf_size); + ssize_t (__cdecl* write) (const AddonInstance_VFSEntry* instance, void* context, const void* buffer, size_t buf_size); + int64_t (__cdecl* seek) (const AddonInstance_VFSEntry* instance, void* context, int64_t position, int whence); + int (__cdecl* truncate) (const AddonInstance_VFSEntry* instance, void* context, int64_t size); + int64_t (__cdecl* get_length) (const AddonInstance_VFSEntry* instance, void* context); + int64_t (__cdecl* get_position) (const AddonInstance_VFSEntry* instance, void* context); + int (__cdecl* get_chunk_size) (const AddonInstance_VFSEntry* instance, void* context); + int (__cdecl* io_control) (const AddonInstance_VFSEntry* instance, void* context, XFILE::EIoControl request, void* param); + int (__cdecl* stat) (const AddonInstance_VFSEntry* instance, const VFSURL* url, struct __stat64* buffer); + bool (__cdecl* close) (const AddonInstance_VFSEntry* instance, void* context); + bool (__cdecl* exists) (const AddonInstance_VFSEntry* instance, const VFSURL* url); + void (__cdecl* clear_out_idle) (const AddonInstance_VFSEntry* instance); + void (__cdecl* disconnect_all) (const AddonInstance_VFSEntry* instance); + bool (__cdecl* delete_it) (const AddonInstance_VFSEntry* instance, const VFSURL* url); + bool (__cdecl* rename) (const AddonInstance_VFSEntry* instance, const VFSURL* url, const VFSURL* url2); + bool (__cdecl* directory_exists) (const AddonInstance_VFSEntry* instance, const VFSURL* url); + bool (__cdecl* remove_directory) (const AddonInstance_VFSEntry* instance, const VFSURL* url); + bool (__cdecl* create_directory) (const AddonInstance_VFSEntry* instance, const VFSURL* url); + bool (__cdecl* get_directory) (const AddonInstance_VFSEntry* instance, + const VFSURL* url, + VFSDirEntry** entries, + int* num_entries, + VFSGetDirectoryCallbacks* callbacks); + bool (__cdecl* contains_files) (const AddonInstance_VFSEntry* instance, + const VFSURL* url, + VFSDirEntry** entries, + int* num_entries, + char* rootpath); + void (__cdecl* free_directory) (const AddonInstance_VFSEntry* instance, VFSDirEntry* entries, int num_entries); + } KodiToAddonFuncTable_VFSEntry; + + typedef struct AddonInstance_VFSEntry /* internal */ + { + AddonProps_VFSEntry props; + AddonToKodiFuncTable_VFSEntry toKodi; + KodiToAddonFuncTable_VFSEntry toAddon; + } AddonInstance_VFSEntry; + +} /* extern "C" */ + +namespace kodi +{ +namespace addon +{ + class CInstanceVFS : public IAddonInstance + { + public: + CInstanceVFS(KODI_HANDLE instance) + : IAddonInstance(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); + } + + ~CInstanceVFS() override = default; + + /// @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; } + + /// @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; } + + /// @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; } + + /// @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; } + + /// @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; } + + /// @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; } + + /// @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; } + + /// @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; } + + /// @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; } + + /// @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, XFILE::EIoControl request, void* param) { return -1; } + + /// @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; } + + /// @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; } + + /// @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; } + + /// @brief Clear out any idle connections + /// + virtual void ClearOutIdle() { } + + /// @brief Disconnect all connections + /// + virtual void DisconnectAll() { } + + /// @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; } + + /// @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; } + + /// @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; } + + /// @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; } + + /// @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; } + + /// @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 CMyFile::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: + /// @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; + } + + /// @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()); + } + + /// @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()); + } + + CVFSCallbacks(const VFSGetDirectoryCallbacks* cb) : m_cb(cb) { } + + private: + const VFSGetDirectoryCallbacks* m_cb; + }; + //@} + + /// @brief List a directory + /// + /// @param[in] url The URL of the directory + /// @param[out] entries The entries in the directory + /// @param[in] callbacks A callback structure + /// @return Context for the directory listing + /// + virtual bool GetDirectory(const VFSURL& url, + std::vector& entries, + CVFSCallbacks callbacks) { return false; } + + /// @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 + /// @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 instance->toAddon.addonInstance->Open(*url); + } + + inline static void* ADDON_OpenForWrite(const AddonInstance_VFSEntry* instance, const VFSURL* url, bool overWrite) + { + return instance->toAddon.addonInstance->OpenForWrite(*url, overWrite); + } + + inline static ssize_t ADDON_Read(const AddonInstance_VFSEntry* instance, void* context, void* buffer, size_t uiBufSize) + { + return 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 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 instance->toAddon.addonInstance->Seek(context, position, whence); + } + + inline static int ADDON_Truncate(const AddonInstance_VFSEntry* instance, void* context, int64_t size) + { + return instance->toAddon.addonInstance->Truncate(context, size); + } + + inline static int64_t ADDON_GetLength(const AddonInstance_VFSEntry* instance, void* context) + { + return instance->toAddon.addonInstance->GetLength(context); + } + + inline static int64_t ADDON_GetPosition(const AddonInstance_VFSEntry* instance, void* context) + { + return instance->toAddon.addonInstance->GetPosition(context); + } + + inline static int ADDON_GetChunkSize(const AddonInstance_VFSEntry* instance, void* context) + { + return instance->toAddon.addonInstance->GetChunkSize(context); + } + + inline static int ADDON_IoControl(const AddonInstance_VFSEntry* instance, void* context, XFILE::EIoControl request, void* param) + { + return instance->toAddon.addonInstance->IoControl(context, request, param); + } + + inline static int ADDON_Stat(const AddonInstance_VFSEntry* instance, const VFSURL* url, struct __stat64* buffer) + { + return instance->toAddon.addonInstance->Stat(*url, buffer); + } + + inline static bool ADDON_Close(const AddonInstance_VFSEntry* instance, void* context) + { + return instance->toAddon.addonInstance->Close(context); + } + + inline static bool ADDON_Exists(const AddonInstance_VFSEntry* instance, const VFSURL* url) + { + return instance->toAddon.addonInstance->Exists(*url); + } + + inline static void ADDON_ClearOutIdle(const AddonInstance_VFSEntry* instance) + { + return instance->toAddon.addonInstance->ClearOutIdle(); + } + + inline static void ADDON_DisconnectAll(const AddonInstance_VFSEntry* instance) + { + return instance->toAddon.addonInstance->DisconnectAll(); + } + + inline static bool ADDON_Delete(const AddonInstance_VFSEntry* instance, const VFSURL* url) + { + return instance->toAddon.addonInstance->Delete(*url); + } + + inline static bool ADDON_Rename(const AddonInstance_VFSEntry* instance, const VFSURL* url, const VFSURL* url2) + { + return instance->toAddon.addonInstance->Rename(*url, *url2); + } + + inline static bool ADDON_DirectoryExists(const AddonInstance_VFSEntry* instance, const VFSURL* url) + { + return instance->toAddon.addonInstance->DirectoryExists(*url); + } + + inline static bool ADDON_RemoveDirectory(const AddonInstance_VFSEntry* instance, const VFSURL* url) + { + return instance->toAddon.addonInstance->RemoveDirectory(*url); + } + + inline static bool ADDON_CreateDirectory(const AddonInstance_VFSEntry* instance, const VFSURL* url) + { + return 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 = instance->toAddon.addonInstance->GetDirectory(*url, addonEntries, 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].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 = 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 = 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 (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].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 = addonEntries.size(); + } + return ret; + } + + AddonInstance_VFSEntry* m_instanceData; + }; + +} /* namespace addon */ +} /* namespace kodi */ -- cgit v1.2.3