diff options
-rw-r--r-- | addons/kodi.binary.global.filesystem/addon.xml.in | 7 | ||||
-rw-r--r-- | system/addon-manifest.xml | 1 | ||||
-rw-r--r-- | xbmc/addons/AddonDll.cpp | 3 | ||||
-rw-r--r-- | xbmc/addons/interfaces/CMakeLists.txt | 2 | ||||
-rw-r--r-- | xbmc/addons/interfaces/Filesystem.cpp | 576 | ||||
-rw-r--r-- | xbmc/addons/interfaces/Filesystem.h | 88 | ||||
-rw-r--r-- | xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h | 2 | ||||
-rw-r--r-- | xbmc/addons/kodi-addon-dev-kit/include/kodi/Filesystem.h | 1490 | ||||
-rw-r--r-- | xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h | 20 |
9 files changed, 2187 insertions, 2 deletions
diff --git a/addons/kodi.binary.global.filesystem/addon.xml.in b/addons/kodi.binary.global.filesystem/addon.xml.in new file mode 100644 index 0000000000..71955fb741 --- /dev/null +++ b/addons/kodi.binary.global.filesystem/addon.xml.in @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<addon id="kodi.binary.global.filesystem" version="@ADDON_GLOBAL_VERSION_FILESYSTEM@" provider-name="Team Kodi"> + <backwards-compatibility abi="@ADDON_GLOBAL_VERSION_FILESYSTEM_MIN@"/> + <requires> + <import addon="xbmc.core" version="0.1.0"/> + </requires> +</addon> diff --git a/system/addon-manifest.xml b/system/addon-manifest.xml index 727d1742fb..be65220b50 100644 --- a/system/addon-manifest.xml +++ b/system/addon-manifest.xml @@ -7,6 +7,7 @@ <addon>kodi.binary.global.general</addon> <addon>kodi.binary.global.network</addon> <addon>kodi.binary.global.gui</addon> + <addon>kodi.binary.global.filesystem</addon> <addon>kodi.binary.instance.adsp</addon> <addon>kodi.binary.instance.audiodecoder</addon> <addon>kodi.binary.instance.audioencoder</addon> diff --git a/xbmc/addons/AddonDll.cpp b/xbmc/addons/AddonDll.cpp index f21ae294b3..871cd53d4e 100644 --- a/xbmc/addons/AddonDll.cpp +++ b/xbmc/addons/AddonDll.cpp @@ -38,6 +38,7 @@ // Global addon callback handle classes #include "addons/interfaces/AudioEngine.h" +#include "addons/interfaces/Filesystem.h" #include "addons/interfaces/General.h" #include "addons/interfaces/Network.h" @@ -567,6 +568,7 @@ bool CAddonDll::InitInterface(KODI_HANDLE firstKodiInstance) Interface_General::Init(&m_interface); Interface_AudioEngine::Init(&m_interface); + Interface_Filesystem::Init(&m_interface); Interface_Network::Init(&m_interface); return true; @@ -575,6 +577,7 @@ bool CAddonDll::InitInterface(KODI_HANDLE firstKodiInstance) void CAddonDll::DeInitInterface() { Interface_Network::DeInit(&m_interface); + Interface_Filesystem::DeInit(&m_interface); Interface_AudioEngine::DeInit(&m_interface); Interface_General::DeInit(&m_interface); diff --git a/xbmc/addons/interfaces/CMakeLists.txt b/xbmc/addons/interfaces/CMakeLists.txt index efc0075633..33a52a13db 100644 --- a/xbmc/addons/interfaces/CMakeLists.txt +++ b/xbmc/addons/interfaces/CMakeLists.txt @@ -1,11 +1,13 @@ set(SOURCES AddonInterfaces.cpp AudioEngine.cpp General.cpp + Filesystem.cpp Network.cpp) set(HEADERS AddonInterfaces.h AudioEngine.h General.h + Filesystem.h Network.h) core_add_library(addonsBinaryInterfaces) diff --git a/xbmc/addons/interfaces/Filesystem.cpp b/xbmc/addons/interfaces/Filesystem.cpp new file mode 100644 index 0000000000..902f34886d --- /dev/null +++ b/xbmc/addons/interfaces/Filesystem.cpp @@ -0,0 +1,576 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + */ + +#include "Filesystem.h" +#include "addons/kodi-addon-dev-kit/include/kodi/Filesystem.h" + +#include "Util.h" +#include "addons/AddonDll.h" +#include "filesystem/File.h" +#include "filesystem/Directory.h" +#include "filesystem/SpecialProtocol.h" +#include "utils/Crc32.h" +#include "utils/log.h" +#include "utils/StringUtils.h" + +using namespace kodi; // addon-dev-kit namespace +using namespace XFILE; + +extern "C" +{ +namespace ADDON +{ + +void Interface_Filesystem::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_filesystem = static_cast<AddonToKodiFuncTable_kodi_filesystem*>(malloc(sizeof(AddonToKodiFuncTable_kodi_filesystem))); + + addonInterface->toKodi->kodi_filesystem->can_open_directory = can_open_directory; + addonInterface->toKodi->kodi_filesystem->create_directory = create_directory; + addonInterface->toKodi->kodi_filesystem->directory_exists = directory_exists; + addonInterface->toKodi->kodi_filesystem->remove_directory = remove_directory; + addonInterface->toKodi->kodi_filesystem->get_directory = get_directory; + addonInterface->toKodi->kodi_filesystem->free_directory = free_directory; + + addonInterface->toKodi->kodi_filesystem->file_exists = file_exists; + addonInterface->toKodi->kodi_filesystem->stat_file = stat_file; + addonInterface->toKodi->kodi_filesystem->delete_file = delete_file; + addonInterface->toKodi->kodi_filesystem->rename_file = rename_file; + addonInterface->toKodi->kodi_filesystem->copy_file = copy_file; + addonInterface->toKodi->kodi_filesystem->get_file_md5 = get_file_md5; + addonInterface->toKodi->kodi_filesystem->get_cache_thumb_name = get_cache_thumb_name; + addonInterface->toKodi->kodi_filesystem->make_legal_filename = make_legal_filename; + addonInterface->toKodi->kodi_filesystem->make_legal_path = make_legal_path; + addonInterface->toKodi->kodi_filesystem->translate_special_protocol = translate_special_protocol; + + addonInterface->toKodi->kodi_filesystem->open_file = open_file; + addonInterface->toKodi->kodi_filesystem->open_file_for_write = open_file_for_write; + addonInterface->toKodi->kodi_filesystem->read_file = read_file; + addonInterface->toKodi->kodi_filesystem->read_file_string = read_file_string; + addonInterface->toKodi->kodi_filesystem->write_file = write_file; + addonInterface->toKodi->kodi_filesystem->flush_file = flush_file; + addonInterface->toKodi->kodi_filesystem->seek_file = seek_file; + addonInterface->toKodi->kodi_filesystem->truncate_file = truncate_file; + addonInterface->toKodi->kodi_filesystem->get_file_position = get_file_position; + addonInterface->toKodi->kodi_filesystem->get_file_length = get_file_length; + addonInterface->toKodi->kodi_filesystem->get_file_download_speed = get_file_download_speed; + addonInterface->toKodi->kodi_filesystem->close_file = close_file; + addonInterface->toKodi->kodi_filesystem->get_file_chunk_size = get_file_chunk_size; + + addonInterface->toKodi->kodi_filesystem->curl_create = curl_create; + addonInterface->toKodi->kodi_filesystem->curl_add_option = curl_add_option; + addonInterface->toKodi->kodi_filesystem->curl_open = curl_open; +} + +void Interface_Filesystem::DeInit(AddonGlobalInterface* addonInterface) +{ + if (addonInterface->toKodi && /* <-- needed as long as the old addon way is used */ + addonInterface->toKodi->kodi_filesystem) + { + free(addonInterface->toKodi->kodi_filesystem); + addonInterface->toKodi->kodi_filesystem = nullptr; + } +} + +bool Interface_Filesystem::can_open_directory(void* kodiBase, const char* url) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || url == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', url='%p')", __FUNCTION__, addon, url); + return false; + } + + CFileItemList items; + return CDirectory::GetDirectory(url, items); +} + +bool Interface_Filesystem::create_directory(void* kodiBase, const char *path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', path='%p')", __FUNCTION__, addon, path); + return false; + } + + return CDirectory::Create(path); +} + +bool Interface_Filesystem::directory_exists(void* kodiBase, const char *path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', path='%p')", __FUNCTION__, addon, path); + return false; + } + + return CDirectory::Exists(path); +} + +bool Interface_Filesystem::remove_directory(void* kodiBase, const char *path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', path='%p')", __FUNCTION__, addon, path); + return false; + } + + // Empty directory + CFileItemList fileItems; + CDirectory::GetDirectory(path, fileItems); + for (int i = 0; i < fileItems.Size(); ++i) + CFile::Delete(fileItems.Get(i)->GetPath()); + + return CDirectory::Remove(path); +} + +static void CFileItemListToVFSDirEntries(VFSDirEntry* entries, + const CFileItemList& items) +{ + for (unsigned int i = 0; i < static_cast<unsigned int>(items.Size()); ++i) + { + entries[i].label = strdup(items[i]->GetLabel().c_str()); + entries[i].path = strdup(items[i]->GetPath().c_str()); + entries[i].size = items[i]->m_dwSize; + entries[i].folder = items[i]->m_bIsFolder; + items[i]->m_dateTime.GetAsTime(entries[i].date_time); + } +} + +bool Interface_Filesystem::get_directory(void* kodiBase, const char *path, const char* mask, VFSDirEntry** items, unsigned int* num_items) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr || mask == nullptr|| items == nullptr || num_items == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', path='%p', mask='%p', items='%p', num_items='%p'", __FUNCTION__, addon, path, mask, items, num_items); + return false; + } + + CFileItemList fileItems; + if (!CDirectory::GetDirectory(path, fileItems, mask, DIR_FLAG_NO_FILE_DIRS)) + return false; + + if (fileItems.Size() > 0) + { + *num_items = static_cast<unsigned int>(fileItems.Size()); + *items = new VFSDirEntry[fileItems.Size()]; + CFileItemListToVFSDirEntries(*items, fileItems); + } + else + { + *num_items = 0; + *items = nullptr; + } + + return true; +} + +void Interface_Filesystem::free_directory(void* kodiBase, VFSDirEntry* items, unsigned int num_items) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || items == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', items='%p')", __FUNCTION__, addon, items); + return; + } + + for (unsigned int i = 0; i < num_items; ++i) + { + free(items[i].label); + free(items[i].path); + } + delete[] items; +} + +//------------------------------------------------------------------------------ + +bool Interface_Filesystem::file_exists(void* kodiBase, const char *filename, bool useCache) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', filename='%p')", __FUNCTION__, addon, filename); + return false; + } + + return CFile::Exists(filename, useCache); +} + +int Interface_Filesystem::stat_file(void* kodiBase, const char *filename, struct __stat64* buffer) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr || buffer == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', filename='%p', buffer='%p')", __FUNCTION__, addon, filename, buffer); + return false; + } + + return CFile::Stat(filename, buffer); +} + +bool Interface_Filesystem::delete_file(void* kodiBase, const char *filename) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', filename='%p')", __FUNCTION__, addon, filename); + return false; + } + + return CFile::Delete(filename); +} + +bool Interface_Filesystem::rename_file(void* kodiBase, const char *filename, const char *newFileName) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr || newFileName == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', filename='%p', newFileName='%p')", __FUNCTION__, addon, filename, newFileName); + return false; + } + + return CFile::Rename(filename, newFileName); +} + +bool Interface_Filesystem::copy_file(void* kodiBase, const char *filename, const char *dest) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr || dest == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', filename='%p', dest='%p')", __FUNCTION__, addon, filename, dest); + return false; + } + + return CFile::Copy(filename, dest); +} + +char* Interface_Filesystem::get_file_md5(void* kodiBase, const char* filename) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', filename='%p)", __FUNCTION__, addon, filename); + return nullptr; + } + + std::string string = CUtil::GetFileMD5(filename); + char* buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_Filesystem::get_cache_thumb_name(void* kodiBase, const char* filename) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', filename='%p)", __FUNCTION__, addon, filename); + return nullptr; + } + + Crc32 crc; + crc.ComputeFromLowerCase(filename); + std::string string = StringUtils::Format("%08x.tbn", (unsigned __int32)crc); + char* buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_Filesystem::make_legal_filename(void* kodiBase, const char* filename) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', filename='%p)", __FUNCTION__, addon, filename); + return nullptr; + } + + std::string string = CUtil::MakeLegalFileName(filename);; + char* buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_Filesystem::make_legal_path(void* kodiBase, const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', path='%p)", __FUNCTION__, addon, path); + return nullptr; + } + + std::string string = CUtil::MakeLegalPath(path);; + char* buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_Filesystem::translate_special_protocol(void* kodiBase, const char *strSource) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || strSource == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', strSource='%p)", __FUNCTION__, addon, strSource); + return nullptr; + } + + return strdup(CSpecialProtocol::TranslatePath(strSource).c_str()); +} + +//------------------------------------------------------------------------------ + +void* Interface_Filesystem::open_file(void* kodiBase, const char* filename, unsigned int flags) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', filename='%p')", __FUNCTION__, addon, filename); + return nullptr; + } + + CFile* file = new CFile; + if (file->Open(filename, flags)) + return static_cast<void*>(file); + + delete file; + return nullptr; +} + +void* Interface_Filesystem::open_file_for_write(void* kodiBase, const char* filename, bool overwrite) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', filename='%p')", __FUNCTION__, addon, filename); + return nullptr; + } + + CFile* file = new CFile; + if (file->OpenForWrite(filename, overwrite)) + return static_cast<void*>(file); + + delete file; + return nullptr; +} + +ssize_t Interface_Filesystem::read_file(void* kodiBase, void* file, void* ptr, size_t size) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr || ptr == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p', ptr='%p')", __FUNCTION__, addon, file, ptr); + return -1; + } + + return static_cast<CFile*>(file)->Read(ptr, size); +} + +bool Interface_Filesystem::read_file_string(void* kodiBase, void* file, char *szLine, int lineLength) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p')", __FUNCTION__, addon, file); + return false; + } + + return static_cast<CFile*>(file)->ReadString(szLine, lineLength); +} + +ssize_t Interface_Filesystem::write_file(void* kodiBase, void* file, const void* ptr, size_t size) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr || ptr == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p', ptr='%p')", __FUNCTION__, addon, file, ptr); + return -1; + } + + return static_cast<CFile*>(file)->Write(ptr, size); +} + +void Interface_Filesystem::flush_file(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p')", __FUNCTION__, addon, file); + return; + } + + static_cast<CFile*>(file)->Flush(); +} + +int64_t Interface_Filesystem::seek_file(void* kodiBase, void* file, int64_t position, int whence) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p')", __FUNCTION__, addon, file); + return -1; + } + + return static_cast<CFile*>(file)->Seek(position, whence); +} + +int Interface_Filesystem::truncate_file(void* kodiBase, void* file, int64_t size) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p')", __FUNCTION__, addon, file); + return -1; + } + + return static_cast<CFile*>(file)->Truncate(size); +} + +int64_t Interface_Filesystem::get_file_position(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p')", __FUNCTION__, addon, file); + return -1; + } + + return static_cast<CFile*>(file)->GetPosition(); +} + +int64_t Interface_Filesystem::get_file_length(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p')", __FUNCTION__, addon, file); + return -1; + } + + return static_cast<CFile*>(file)->GetLength(); +} + +double Interface_Filesystem::get_file_download_speed(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p')", __FUNCTION__, addon, file); + return 0.0f; + } + + return static_cast<CFile*>(file)->GetDownloadSpeed(); +} + +void Interface_Filesystem::close_file(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p')", __FUNCTION__, addon, file); + return; + } + + static_cast<CFile*>(file)->Close(); + delete static_cast<CFile*>(file); +} + +int Interface_Filesystem::get_file_chunk_size(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_VFS::%s - invalid data (addon='%p', file='%p)", __FUNCTION__, addon, file); + return -1; + } + + return static_cast<CFile*>(file)->GetChunkSize(); +} + +void* Interface_Filesystem::curl_create(void* kodiBase, const char* url) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || url == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', url='%p')", __FUNCTION__, addon, url); + return nullptr; + } + + CFile* file = new CFile; + if (file->CURLCreate(url)) + return static_cast<void*>(file); + + delete file; + return nullptr; +} + +bool Interface_Filesystem::curl_add_option(void* kodiBase, void* file, int type, const char* name, const char* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr || name == nullptr || value == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p', name='%p', value='%p')", __FUNCTION__, addon, file, name, value); + return false; + } + + XFILE::CURLOPTIONTYPE internalType; + switch (type) + { + case ADDON_CURL_OPTION_OPTION: + internalType = XFILE::CURL_OPTION_OPTION; + break; + case ADDON_CURL_OPTION_PROTOCOL: + internalType = XFILE::CURL_OPTION_PROTOCOL; + break; + case ADDON_CURL_OPTION_CREDENTIALS: + internalType = XFILE::CURL_OPTION_CREDENTIALS; + break; + case ADDON_CURL_OPTION_HEADER: + internalType = XFILE::CURL_OPTION_HEADER; + break; + default: + throw std::logic_error("Interface_Filesystem::curl_add_option - invalid curl option type"); + return false; + }; + + CFile* cfile = static_cast<CFile*>(file); + if (cfile) + return cfile->CURLAddOption(internalType, name, value); + + return false; +} + +bool Interface_Filesystem::curl_open(void* kodiBase, void* file, unsigned int flags) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::%s - invalid data (addon='%p', file='%p')", __FUNCTION__, addon, file); + return false; + } + + CFile* cfile = static_cast<CFile*>(file); + if (cfile) + return cfile->CURLOpen(flags); + + return false; +} + +} /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/Filesystem.h b/xbmc/addons/interfaces/Filesystem.h new file mode 100644 index 0000000000..7ef9a0401b --- /dev/null +++ b/xbmc/addons/interfaces/Filesystem.h @@ -0,0 +1,88 @@ +#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 + * <http://www.gnu.org/licenses/>. + * + */ + +#include "FileItem.h" + +extern "C" +{ + +struct VFSDirEntry; +struct AddonGlobalInterface; + +namespace ADDON +{ + + struct Interface_Filesystem + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note For add of new functions use the "_" style to identify direct a + * add-on callback function. Everything with CamelCase is only for the + * usage in Kodi only. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static bool can_open_directory(void* kodiBase, const char* url); + static bool create_directory(void* kodiBase, const char *path); + static bool directory_exists(void* kodiBase, const char *path); + static bool remove_directory(void* kodiBase, const char *path); + static bool get_directory(void* kodiBase, const char* path, const char* mask, VFSDirEntry** items, unsigned int* num_items); + static void free_directory(void* kodiBase, VFSDirEntry* items, unsigned int num_items); + + static bool file_exists(void* kodiBase, const char *filename, bool useCache); + static int stat_file(void* kodiBase, const char *filename, struct __stat64* buffer); + static bool delete_file(void* kodiBase, const char *filename); + static bool rename_file(void* kodiBase, const char *filename, const char *newFileName); + static bool copy_file(void* kodiBase, const char *filename, const char *dest); + static char* get_file_md5(void* kodiBase, const char* filename); + static char* get_cache_thumb_name(void* kodiBase, const char* filename); + static char* make_legal_filename(void* kodiBase, const char* filename); + static char* make_legal_path(void* kodiBase, const char* path); + static char* translate_special_protocol(void* kodiBase, const char *strSource); + + static void* open_file(void* kodiBase, const char* filename, unsigned int flags); + static void* open_file_for_write(void* kodiBase, const char* filename, bool overwrite); + static ssize_t read_file(void* kodiBase, void* file, void* ptr, size_t size); + static bool read_file_string(void* kodiBase, void* file, char *szLine, int lineLength); + static ssize_t write_file(void* kodiBase, void* file, const void* ptr, size_t size); + static void flush_file(void* kodiBase, void* file); + static int64_t seek_file(void* kodiBase, void* file, int64_t position, int whence); + static int truncate_file(void* kodiBase, void* file, int64_t size); + static int64_t get_file_position(void* kodiBase, void* file); + static int64_t get_file_length(void* kodiBase, void* file); + static double get_file_download_speed(void* kodiBase, void* file); + static void close_file(void* kodiBase, void* file); + static int get_file_chunk_size(void* kodiBase, void* file); + + static void* curl_create(void* kodiBase, const char* url); + static bool curl_add_option(void* kodiBase, void* file, int type, const char* name, const char* value); + static bool curl_open(void* kodiBase, void* file, unsigned int flags); + //@} + }; + +} /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h index 6f2de58fab..ea4184d059 100644 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h @@ -145,6 +145,7 @@ typedef ADDON_HANDLE_STRUCT *ADDON_HANDLE; */ struct AddonToKodiFuncTable_kodi; struct AddonToKodiFuncTable_kodi_audioengine; +struct AddonToKodiFuncTable_kodi_filesystem; struct AddonToKodiFuncTable_kodi_network; typedef struct AddonToKodiFuncTable_Addon { @@ -162,6 +163,7 @@ typedef struct AddonToKodiFuncTable_Addon AddonToKodiFuncTable_kodi* kodi; AddonToKodiFuncTable_kodi_audioengine* kodi_audioengine; + AddonToKodiFuncTable_kodi_filesystem* kodi_filesystem; AddonToKodiFuncTable_kodi_network *kodi_network; } AddonToKodiFuncTable_Addon; diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/Filesystem.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/Filesystem.h new file mode 100644 index 0000000000..3222e8b19e --- /dev/null +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/Filesystem.h @@ -0,0 +1,1490 @@ +#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 + * <http://www.gnu.org/licenses/>. + * + */ + +#include "AddonBase.h" + +#include <map> + +#if !defined(_WIN32) + #include <sys/stat.h> + #if !defined(__stat64) + #define __stat64 stat64 + #endif +#endif +#ifdef _WIN32 // windows +#ifndef _SSIZE_T_DEFINED + typedef intptr_t ssize_t; + #define _SSIZE_T_DEFINED +#endif // !_SSIZE_T_DEFINED +#endif + +#ifndef S_ISDIR + #define S_ISDIR(mode) ((((mode)) & 0170000) == (0040000)) +#endif + +#ifndef S_ISLNK + #define S_ISLNK(mode) ((((mode)) & 0170000) == (0120000)) +#endif + +/* + * For interface between add-on and kodi. + * + * This structure defines the addresses of functions stored inside Kodi which + * are then available for the add-on to call + * + * All function pointers there are used by the C++ interface functions below. + * You find the set of them on xbmc/addons/interfaces/General.cpp + * + * Note: For add-on development itself this is not needed + */ +extern "C" +{ + + struct VFSProperty + { + char* name; + char* val; + }; + + struct VFSDirEntry + { + char* label; //!< item label + char* title; //!< item title + char* path; //!< item path + unsigned int num_props; //!< Number of properties attached to item + VFSProperty* properties; //!< Properties + time_t date_time; //!< file creation date & time + bool folder; //!< Item is a folder + uint64_t size; //!< Size of file represented by item + }; + + typedef struct AddonToKodiFuncTable_kodi_filesystem + { + bool (*can_open_directory)(void* kodiBase, const char* url); + bool (*create_directory)(void* kodiBase, const char* path); + bool (*remove_directory)(void* kodiBase, const char* path); + bool (*directory_exists)(void* kodiBase, const char* path); + bool (*get_directory)(void* kodiBase, const char* path, const char* mask, VFSDirEntry** items, unsigned int* num_items); + void (*free_directory)(void* kodiBase, VFSDirEntry* items, unsigned int num_items); + + bool (*file_exists)(void* kodiBase, const char *filename, bool useCache); + int (*stat_file)(void* kodiBase, const char *filename, struct __stat64* buffer); + bool (*delete_file)(void* kodiBase, const char *filename); + bool (*rename_file)(void* kodiBase, const char *filename, const char *newFileName); + bool (*copy_file)(void* kodiBase, const char *filename, const char *dest); + + char* (*get_file_md5)(void* kodiBase, const char* filename); + char* (*get_cache_thumb_name)(void* kodiBase, const char* filename); + char* (*make_legal_filename)(void* kodiBase, const char* filename); + char* (*make_legal_path)(void* kodiBase, const char* path); + char* (*translate_special_protocol)(void* kodiBase, const char *strSource); + + void* (*open_file)(void* kodiBase, const char* filename, unsigned int flags); + void* (*open_file_for_write)(void* kodiBase, const char* filename, bool overwrite); + ssize_t (*read_file)(void* kodiBase, void* file, void* ptr, size_t size); + bool (*read_file_string)(void* kodiBase, void* file, char *szLine, int iLineLength); + ssize_t (*write_file)(void* kodiBase, void* file, const void* ptr, size_t size); + void (*flush_file)(void* kodiBase, void* file); + int64_t (*seek_file)(void* kodiBase, void* file, int64_t position, int whence); + int (*truncate_file)(void* kodiBase, void* file, int64_t size); + int64_t (*get_file_position)(void* kodiBase, void* file); + int64_t (*get_file_length)(void* kodiBase, void* file); + double (*get_file_download_speed)(void* kodiBase, void* file); + void (*close_file)(void* kodiBase, void* file); + int (*get_file_chunk_size)(void* kodiBase, void* file); + + void* (*curl_create)(void* kodiBase, const char* url); + bool (*curl_add_option)(void* kodiBase, void* file, int type, const char* name, const char* value); + bool (*curl_open)(void* kodiBase, void* file, unsigned int flags); + } AddonToKodiFuncTable_kodi_filesystem; + +} /* extern "C" */ + +//============================================================================== +/// \defgroup cpp_kodi_vfs_CFile_Defs Definitions, structures and enumerators +/// \ingroup cpp_kodi_vfs_CFile +/// @brief **Virtual file Server definition values** +//------------------------------------------------------------------------------ + +//============================================================================== +/// +/// @ingroup cpp_kodi_vfs_CFile_Defs +/// Flags to define way how file becomes opened with kodi::vfs::CFile::OpenFile() +/// +/// The values can be used together, e.g. <b>`file.Open("myfile", READ_TRUNCATED | READ_CHUNKED);`</b> +/// +typedef enum OpenFileFlags +{ + /// indicate that caller can handle truncated reads, where function returns + /// before entire buffer has been filled + READ_TRUNCATED = 0x01, + + /// indicate that that caller support read in the minimum defined chunk size, + /// this disables internal cache then + READ_CHUNKED = 0x02, + + /// use cache to access this file + READ_CACHED = 0x04, + + /// open without caching. regardless to file type + READ_NO_CACHE = 0x08, + + /// calcuate bitrate for file while reading + READ_BITRATE = 0x10, + + /// indicate to the caller we will seek between multiple streams in the file + /// frequently + READ_MULTI_STREAM = 0x20, + + /// indicate to the caller file is audio and/or video (and e.g. may grow) + READ_AUDIO_VIDEO = 0x40, + + /// indicate that caller will do write operations before reading + READ_AFTER_WRITE = 0x80, + + /// indicate that caller want to reopen a file if its already open + READ_REOPEN = 0x100 +} OpenFileFlags; +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi_vfs_CFile_Defs +/// @brief Used CURL message types +/// +typedef enum CURLOptiontype +{ + /// Set a general option + ADDON_CURL_OPTION_OPTION, + /// Set a protocol option + ADDON_CURL_OPTION_PROTOCOL, + /// Set User and password + ADDON_CURL_OPTION_CREDENTIALS, + /// Add a Header + ADDON_CURL_OPTION_HEADER +} CURLOptiontype; +//------------------------------------------------------------------------------ + +//============================================================================ +/// +/// \ingroup cpp_kodi_vfs_CFile_Defs +/// @brief Information about a file +/// +struct STAT_STRUCTURE +{ + /// ID of device containing file + uint32_t deviceId; + /// Total size, in bytes + uint64_t size; +#ifdef TARGET_WINDOWS + /// Time of last access + __time64_t accessTime; + /// Time of last modification + __time64_t modificationTime; + /// Time of last status change + __time64_t statusTime; +#else + /// Time of last access + timespec accessTime; + /// Time of last modification + timespec modificationTime; + /// Time of last status change + timespec statusTime; +#endif + /// The stat url is a directory + bool isDirectory; + /// The stat url is a symbolic link + bool isSymLink; +}; +//------------------------------------------------------------------------------ + +namespace kodi +{ +namespace vfs +{ + + //============================================================================ + /// + /// \defgroup cpp_kodi_vfs_CDirEntry class CDirEntry + /// \ingroup cpp_kodi_vfs + /// + /// @brief **Virtual file server directory entry** + /// + /// This class is used as an entry for files and folders in + /// kodi::vfs::GetDirectory(). + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// + /// ... + /// + /// std::vector<kodi::vfs::CDirEntry> items; + /// kodi::vfs::GetDirectory("special://temp", "", items); + /// + /// fprintf(stderr, "Directory have %lu entries\n", items.size()); + /// for (unsigned long i = 0; i < items.size(); i++) + /// { + /// char buff[20]; + /// time_t now = items[i].DateTime(); + /// strftime(buff, 20, "%Y-%m-%d %H:%M:%S", gmtime(&now)); + /// fprintf(stderr, " - %04lu -- Folder: %s -- Name: %s -- Path: %s -- Time: %s\n", + /// i+1, + /// items[i].IsFolder() ? "yes" : "no ", + /// items[i].Label().c_str(), + /// items[i].Path().c_str(), + /// buff); + /// } + /// ~~~~~~~~~~~~~ + /// + /// It has the header \ref Filesystem.h "#include <kodi/Filesystem.h>" be included + /// to enjoy it. + /// + //@{ + class CDirEntry + { + public: + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Constructor for VFS directory entry + /// + /// @param[in] label [opt] Name to use for entry + /// @param[in] path [opt] Used path of the entry + /// @param[in] folder [opt] If set entry used as folder + /// @param[in] size [opt] If used as file, his size defined there + /// + CDirEntry(const std::string& label = "", + const std::string& path = "", + bool folder = false, + int64_t size = -1) : + m_label(label), + m_path(path), + m_folder(folder), + m_size(size) + { + } + //---------------------------------------------------------------------------- + + //============================================================================ + // @note Not for addon development itself needed, thats why below is + // disabled for doxygen! + // + // @ingroup cpp_kodi_vfs_CDirEntry + // @brief Constructor to create own copy + // + // @param[in] dirEntry pointer to own class type + // + CDirEntry(const VFSDirEntry& dirEntry) : + m_label(dirEntry.label ? dirEntry.label : ""), + m_path(dirEntry.path ? dirEntry.path : ""), + m_folder(dirEntry.folder), + m_size(dirEntry.size), + m_dateTime(dirEntry.date_time) + { + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Get the directory entry name + /// + /// @return Name of the entry + /// + const std::string& Label(void) const { return m_label; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Get the optional title of entry + /// + /// @return Title of the entry, if exists + /// + const std::string& Title(void) const { return m_title; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Get the path of the entry + /// + /// @return File system path of the entry + /// + const std::string& Path(void) const { return m_path; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Used to check entry is folder + /// + /// @return true if entry is a folder + /// + bool IsFolder(void) const { return m_folder; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief If file, the size of the file + /// + /// @return Defined file size + /// + int64_t Size(void) const { return m_size; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Get file time and date for a new entry + /// + /// @return The with time_t defined date and time of file + /// + time_t DateTime() { return m_dateTime; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Set the label name + /// + /// @param[in] label name of entry + /// + void SetLabel(const std::string& label) { m_label = label; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Set the title name + /// + /// @param[in] title title name of entry + /// + void SetTitle(const std::string& title) { m_title = title; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Set the path of the entry + /// + /// @param[in] path path of entry + /// + void SetPath(const std::string& path) { m_path = path; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Set the entry defined as folder + /// + /// @param[in] folder If true becomes entry defined as folder + /// + void SetFolder(bool folder) { m_folder = folder; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Set a file size for a new entry + /// + /// @param[in] size Size to set for dir entry + /// + void SetSize(int64_t size) { m_size = size; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Set file time and date for a new entry + /// + /// @param[in] dateTime The with time_t defined date and time of file + /// + void SetDateTime(time_t dateTime) { m_dateTime = dateTime; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Add a by string defined property entry to directory entry + /// + /// @note A property can be used to add some special information about a file + /// or directory entry, this can be used on other places to do the right work + /// of them. + /// + /// @param[in] id Identification name of property + /// @param[in] value The property value to add by given id + /// + void AddProperty(const std::string& id, const std::string& value) { m_properties[id] = value; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Clear all present properties + /// + void ClearProperties() { m_properties.clear(); } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Get the present properties list on directory entry + /// + /// @return map with all present properties + /// + const std::map<std::string, std::string>& GetProperties() const { return m_properties; } + //---------------------------------------------------------------------------- + + private: + std::string m_label; + std::string m_title; + std::string m_path; + std::map<std::string, std::string> m_properties; + bool m_folder; + int64_t m_size; + time_t m_dateTime; + }; + //@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Make a directory + /// + /// The kodi::vfs::CreateDirectory() function shall create a + /// new directory with name path. + /// + /// The newly created directory shall be an empty directory. + /// + /// @param[in] path Path to the directory. + /// @return Upon successful completion, CreateDirectory() shall return true. + /// Otherwise false shall be returned, no directory shall be created. + /// + /// + /// ------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// ... + /// std::string directory = "C:\\my_dir"; + /// bool ret = kodi::vfs::CreateDirectory(directory); + /// fprintf(stderr, "Directory '%s' successfull created: %s\n", directory.c_str(), ret ? "yes" : "no"); + /// ... + /// ~~~~~~~~~~~~~ + /// + inline bool CreateDirectory(const std::string& path) + { + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->create_directory(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Verifying the Existence of a Directory + /// + /// The kodi::vfs::DirectoryExists() method determines whether + /// a specified folder exists. + /// + /// @param[in] path Path to the directory. + /// @return True when it exists, false otherwise. + /// + /// + /// ------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// ... + /// std::string directory = "C:\\my_dir"; + /// bool ret = kodi::vfs::DirectoryExists(directory); + /// fprintf(stderr, "Directory '%s' present: %s\n", directory.c_str(), ret ? "yes" : "no"); + /// ... + /// ~~~~~~~~~~~~~ + /// + inline bool DirectoryExists(const std::string& path) + { + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->directory_exists(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Removes a directory. + /// + /// The kodi::vfs::RemoveDirectory() function shall remove a + /// directory whose name is given by path. + /// + /// @param[in] path Path to the directory. + /// @return Upon successful completion, the function RemoveDirectory() shall + /// return true. Otherwise, false shall be returned, and errno set + /// to indicate the error. If false is returned, the named directory + /// shall not be changed. + /// + /// + /// ------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// ... + /// bool ret = kodi::vfs::RemoveDirectory("C:\\my_dir"); + /// ... + /// ~~~~~~~~~~~~~ + /// + inline bool RemoveDirectory(const std::string& path) + { + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->remove_directory(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Lists a directory. + /// + /// Return the list of files and directories which have been found in the + /// specified directory and which respect the given constraint. + /// + /// It can handle the normal OS dependent paths and also the special virtual + /// filesystem from Kodi what starts with \b special://. + /// + /// @param[in] path The path in which the files and directories are located. + /// @param[in] mask Mask to filter out requested files, e.g. "*.avi|*.mpg" to + /// files with this ending. + /// @param[out] items The returned list directory entries. + /// @return True if listing was successful, false otherwise. + /// + /// + /// ------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// + /// std::vector<kodi::vfs::CDirEntry> items; + /// kodi::vfs::GetDirectory("special://temp", "", items); + /// + /// fprintf(stderr, "Directory have %lu entries\n", items.size()); + /// for (unsigned long i = 0; i < items.size(); i++) + /// { + /// fprintf(stderr, " - %04lu -- Folder: %s -- Name: %s -- Path: %s\n", + /// i+1, + /// items[i].IsFolder() ? "yes" : "no ", + /// items[i].Label().c_str(), + /// items[i].Path().c_str()); + /// } + /// ~~~~~~~~~~~~~ + inline bool GetDirectory(const std::string& path, const std::string& mask, std::vector<CDirEntry>& items) + { + VFSDirEntry* dir_list = nullptr; + unsigned int num_items = 0; + if (::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->get_directory(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, path.c_str(), mask.c_str(), &dir_list, &num_items)) + { + if (dir_list) + { + for (unsigned int i = 0; i < num_items; ++i) + items.push_back(CDirEntry(dir_list[i])); + + ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->free_directory(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, dir_list, num_items); + } + + return true; + } + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Retrieve MD5sum of a file + /// + /// @param[in] path path to the file to MD5sum + /// @return md5 sum of the file + /// + /// + /// ------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// #include <kodi/gui/DialogFileBrowser.h> + /// ... + /// std::string md5; + /// std::string filename; + /// if (kodi::gui::DialogFileBrowser::ShowAndGetFile("local", "*.avi|*.mpg|*.mp4", + /// "Test File selection to get MD5", + /// filename)) + /// { + /// md5 = kodi::vfs::GetFileMD5(filename); + /// fprintf(stderr, "MD5 of file '%s' is %s\n", md5.c_str(), filename.c_str()); + /// } + /// ~~~~~~~~~~~~~ + /// + inline std::string GetFileMD5(const std::string& path) + { + std::string strReturn; + char* strMd5 = ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_md5(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); + if (strMd5 != nullptr) + { + if (std::strlen(strMd5)) + strReturn = strMd5; + ::kodi::addon::CAddonBase::m_interface->toKodi->free_string(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, strMd5); + } + return strReturn; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Returns a thumb cache filename + /// + /// @param[in] filename path to file + /// @return cache filename + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// #include <kodi/gui/DialogFileBrowser.h> + /// ... + /// std::string thumb; + /// std::string filename; + /// if (kodi::gui::DialogFileBrowser::ShowAndGetFile("local", "*.avi|*.mpg|*.mp4", + /// "Test File selection to get Thumnail", + /// filename)) + /// { + /// thumb = kodi::vfs::GetCacheThumbName(filename); + /// fprintf(stderr, "Thumb name of file '%s' is %s\n", thumb.c_str(), filename.c_str()); + /// } + /// ~~~~~~~~~~~~~ + /// + inline std::string GetCacheThumbName(const std::string& filename) + { + std::string strReturn; + char* strThumbName = ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->get_cache_thumb_name(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, filename.c_str()); + if (strThumbName != nullptr) + { + if (std::strlen(strThumbName)) + strReturn = strThumbName; + ::kodi::addon::CAddonBase::m_interface->toKodi->free_string(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, strThumbName); + } + return strReturn; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Make filename valid + /// + /// Function to replace not valid characters with '_'. It can be also + /// compared with original before in a own loop until it is equal + /// (no invalid characters). + /// + /// @param[in] filename Filename to check and fix + /// @return The legal filename + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// ... + /// std::string fileName = "///\\jk???lj????.mpg"; + /// std::string legalName = kodi::vfs::MakeLegalFileName(fileName); + /// fprintf(stderr, "Legal name of '%s' is '%s'\n", fileName.c_str(), legalName.c_str()); + /// + /// /* Returns as legal: 'jk___lj____.mpg' */ + /// ~~~~~~~~~~~~~ + /// + inline std::string MakeLegalFileName(const std::string& filename) + { + std::string strReturn; + char* strLegalFileName = ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->make_legal_filename(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, filename.c_str()); + if (strLegalFileName != nullptr) + { + if (std::strlen(strLegalFileName)) + strReturn = strLegalFileName; + ::kodi::addon::CAddonBase::m_interface->toKodi->free_string(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, strLegalFileName); + } + return strReturn; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Make directory name valid + /// + /// Function to replace not valid characters with '_'. It can be also + /// compared with original before in a own loop until it is equal + /// (no invalid characters). + /// + /// @param[in] path Directory name to check and fix + /// @return The legal directory name + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// ... + /// std::string path = "///\\jk???lj????\\hgjkg"; + /// std::string legalPath = kodi::vfs::MakeLegalPath(path); + /// fprintf(stderr, "Legal name of '%s' is '%s'\n", path.c_str(), legalPath.c_str()); + /// + /// /* Returns as legal: '/jk___lj____/hgjkg' */ + /// ~~~~~~~~~~~~~ + /// + inline std::string MakeLegalPath(const std::string& path) + { + std::string strReturn; + char* strLegalPath = ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->make_legal_path(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); + if (strLegalPath != nullptr) + { + if (std::strlen(strLegalPath)) + strReturn = strLegalPath; + ::kodi::addon::CAddonBase::m_interface->toKodi->free_string(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, strLegalPath); + } + return strReturn; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// \ingroup cpp_kodi + /// @brief Returns the translated path + /// + /// @param[in] source string or unicode - Path to format + /// @return A human-readable string suitable for logging + /// + /// @note Only useful if you are coding for both Linux and Windows. + /// e.g. Converts 'special://masterprofile/script_data' -> '/home/user/.kodi/UserData/script_data' + /// on Linux. + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// ... + /// std::string path = kodi::vfs::TranslateSpecialProtocol("special://masterprofile/script_data"); + /// fprintf(stderr, "Translated path is: %s\n", path.c_str()); + /// ... + /// ~~~~~~~~~~~~~ + /// or + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// ... + /// fprintf(stderr, "Directory 'special://temp' is '%s'\n", kodi::vfs::TranslateSpecialProtocol("special://temp").c_str()); + /// ... + /// ~~~~~~~~~~~~~ + /// + inline std::string TranslateSpecialProtocol(const std::string& source) + { + std::string strReturn; + char* protocol = ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->translate_special_protocol(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, source.c_str()); + if (protocol != nullptr) + { + if (std::strlen(protocol)) + strReturn = protocol; + ::kodi::addon::CAddonBase::m_interface->toKodi->free_string(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, protocol); + } + return strReturn; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Return the file name from given complate path string + /// + /// @param[in] path The complete path include file and directory + /// @return Filename from path + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// ... + /// std::string fileName = kodi::vfs::GetFileName("special://temp/kodi.log"); + /// fprintf(stderr, "File name is '%s'\n", fileName.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline std::string GetFileName(const std::string& path) + { + /* find the last slash */ + const size_t slash = path.find_last_of("/\\"); + return path.substr(slash+1); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Return the directory name from given complate path string + /// + /// @param[in] path The complete path include file and directory + /// @return Directory name from path + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// ... + /// std::string dirName = kodi::vfs::GetDirectoryName("special://temp/kodi.log"); + /// fprintf(stderr, "Directory name is '%s'\n", dirName.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline std::string GetDirectoryName(const std::string& path) + { + // Will from a full filename return the directory the file resides in. + // Keeps the final slash at end and possible |option=foo options. + + size_t iPosSlash = path.find_last_of("/\\"); + if (iPosSlash == std::string::npos) + return ""; // No slash, so no path (ignore any options) + + size_t iPosBar = path.rfind('|'); + if (iPosBar == std::string::npos) + return path.substr(0, iPosSlash + 1); // Only path + + return path.substr(0, iPosSlash + 1) + path.substr(iPosBar); // Path + options + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Return a size aligned to the chunk size at least as large as the chunk size. + /// + /// @param[in] chunk The chunk size + /// @param[in] minimum The minimum size (or maybe the minimum number of chunks?) + /// @return The aligned size + /// + inline unsigned int GetChunkSize(unsigned int chunk, unsigned int minimum) + { + if (chunk) + return chunk * ((minimum + chunk - 1) / chunk); + else + return minimum; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Check if a file exists. + /// + /// @param[in] filename The filename to check. + /// @param[in] usecache Check in file cache. + /// @return true if the file exists false otherwise. + /// + /// + /// ------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// ... + /// bool exists = kodi::vfs::FileExists("special://temp/kodi.log"); + /// fprintf(stderr, "Log file should be always present, is it present? %s\n", exists ? "yes" : "no"); + /// ~~~~~~~~~~~~~ + /// + static inline bool FileExists(const std::string& filename, bool usecache = false) + { + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->file_exists(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), usecache); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Get file status. + /// + /// These function return information about a file. Execute (search) + /// permission is required on all of the directories in path that + /// lead to the file. + /// + /// The call return a stat structure, which contains the on \ref STAT_STRUCTURE + /// defined values. + /// + /// @warning Not all of the OS file systems implement all of the time fields. + /// + /// @param[in] filename The filename to read the status from. + /// @param[out] buffer The file status is written into this buffer. + /// @return On success, tru is returned. On error, fale is returned + /// + /// + /// ------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// ... + /// STAT_STRUCTURE statFile; + /// int ret = kodi::vfs::StatFile("special://temp/kodi.log", &statFile); + /// fprintf(stderr, "deviceId (ID of device containing file) = %u\n" + /// "size (total size, in bytes) = %lu\n" + /// "accessTime (time of last access) = %lu\n" + /// "modificationTime (time of last modification) = %lu\n" + /// "statusTime (time of last status change) = %lu\n" + /// "isDirectory (The stat url is a directory) = %s\n" + /// "isSymLink (The stat url is a symbolic link) = %s\n" + /// "Return value = %i\n", + /// statFile.deviceId, + /// statFile.size, + /// statFile.accessTime, + /// statFile.modificationTime, + /// statFile.statusTime, + /// statFile.isDirectory ? "true" : "false", + /// statFile.isSymLink ? "true" : "false", + /// ret); + /// ~~~~~~~~~~~~~ + /// + static inline bool StatFile(const std::string& filename, STAT_STRUCTURE& buffer) + { + struct __stat64 frontendBuffer = { }; + if (::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->stat_file(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), &frontendBuffer)) + { + buffer.deviceId = frontendBuffer.st_dev; + buffer.size = frontendBuffer.st_size; +#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) + buffer.accessTime = frontendBuffer.st_atimespec; + buffer.modificationTime = frontendBuffer.st_mtimespec; + buffer.statusTime = frontendBuffer.st_ctimespec; +#elif defined(TARGET_WINDOWS) + buffer.accessTime = frontendBuffer.st_atime; + buffer.modificationTime = frontendBuffer.st_mtime; + buffer.statusTime = frontendBuffer.st_ctime; +#elif defined(TARGET_ANDROID) + buffer.accessTime.tv_sec = frontendBuffer.st_atime; + buffer.accessTime.tv_nsec = frontendBuffer.st_atime_nsec; + buffer.modificationTime.tv_sec = frontendBuffer.st_mtime; + buffer.modificationTime.tv_nsec = frontendBuffer.st_mtime_nsec; + buffer.statusTime.tv_sec = frontendBuffer.st_ctime; + buffer.statusTime.tv_nsec = frontendBuffer.st_ctime_nsec; +#else + buffer.accessTime = frontendBuffer.st_atim; + buffer.modificationTime = frontendBuffer.st_mtim; + buffer.statusTime = frontendBuffer.st_ctim; +#endif + buffer.isDirectory = S_ISDIR(frontendBuffer.st_mode); + buffer.isSymLink = S_ISLNK(frontendBuffer.st_mode); + return true; + } + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Deletes a file. + /// + /// @param[in] filename The filename to delete. + /// @return The file was successfully deleted. + /// + /// + /// ------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// #include <kodi/gui/DialogFileBrowser.h> + /// #include <kodi/gui/DialogOK.h> + /// ... + /// std::string filename; + /// if (kodi::gui::DialogFileBrowser::ShowAndGetFile("local", "", + /// "Test File selection and delete of them!", + /// filename)) + /// { + /// bool successed = kodi::vfs::DeleteFile(filename); + /// if (!successed) + /// kodi::gui::DialogOK::ShowAndGetInput("Error", "Delete of File", filename, "failed!"); + /// else + /// kodi::gui::DialogOK::ShowAndGetInput("Information", "Delete of File", filename, "successfull done."); + /// } + /// ~~~~~~~~~~~~~ + /// + static inline bool DeleteFile(const std::string& filename) + { + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->delete_file(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, filename.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Rename a file name + /// + /// @param[in] filename The filename to copy. + /// @param[in] newFileName The new filename + /// @return true if successfully renamed + /// + /// + static inline bool RenameFile(const std::string& filename, const std::string& newFileName) + { + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->rename_file(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), newFileName.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_vfs + /// @brief Copy a file from source to destination + /// + /// @param[in] filename The filename to copy. + /// @param[in] destination The destination to copy file to + /// @return true if successfully copied + /// + /// + static inline bool CopyFile(const std::string& filename, const std::string& destination) + { + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->copy_file(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), destination.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// \defgroup cpp_kodi_vfs_CFile class CFile + /// \ingroup cpp_kodi_vfs + /// + /// @brief **Virtual file server control** + /// + /// CFile is the class used for handling Files in Kodi. This class can be used + /// for creating, reading, writing and modifying files. It directly provides unbuffered, binary disk input/output services + /// + /// It has the header \ref Filesystem.h "#include <kodi/Filesystem.h>" be included + /// to enjoy it. + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include <kodi/Filesystem.h> + /// + /// ... + /// + /// /* Create the needed file handle class */ + /// kodi::vfs::CFile myFile(); + /// + /// /* In this example we use the user path for the add-on */ + /// std::string file = kodi::GetUserPath() + "/myFile.txt"; + /// + /// /* Now create and open the file or overwrite if present */ + /// myFile.OpenFileForWrite(file, true); + /// + /// const char* str = "I love Kodi!"; + /// + /// /* write string */ + /// myFile.Write(str, sizeof(str)); + /// + /// /* On this way the Close() is not needed to call, becomes done from destructor */ + /// + /// ~~~~~~~~~~~~~ + /// + //@{ + class CFile + { + public: + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Construct a new, unopened file + /// + CFile() : m_file(nullptr) { } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Close() is called from the destructor, so explicitly closing the + /// file isn't required + /// + virtual ~CFile() { Close(); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Open the file with filename via Kodi's \ref cpp_kodi_vfs_CFile + /// "CFile". Needs to be closed by calling Close() when done. + /// + /// @param[in] filename The filename to open. + /// @param[in] flags [opt] The flags to pass, see \ref OpenFileFlags + /// @return True on success or false on failure + /// + bool OpenFile(const std::string& filename, unsigned int flags = 0) + { + Close(); + m_file = ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->open_file(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), flags); + return m_file != nullptr; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Open the file with filename via Kodi's \ref cpp_kodi_vfs_CFile + /// "CFile" in write mode. Needs to be closed by calling Close() when + /// done. + /// + /// @note Related folders becomes created if not present. + /// + /// @param[in] filename The filename to open. + /// @param[in] overwrite True to overwrite, false otherwise. + /// @return True on success or false on failure + /// + bool OpenFileForWrite(const std::string& filename, bool overwrite = false) + { + Close(); + + // Try to open the file. If it fails, check if we need to create the directory first + // This way we avoid checking if the directory exists every time + m_file = ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->open_file_for_write(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), overwrite); + if (!m_file) + { + std::string cacheDirectory = kodi::vfs::GetDirectoryName(filename); + if (::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->directory_exists(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, cacheDirectory.c_str()) || + ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->create_directory(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, cacheDirectory.c_str())) + m_file = ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->open_file_for_write(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), overwrite); + } + return m_file != nullptr; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Create a Curl representation + /// + /// @param[in] url the URL of the Type. + /// @return True on success or false on failure + /// + bool CURLCreate(const std::string& url) + { + m_file = ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->curl_create(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, url.c_str()); + return m_file != nullptr; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Add options to the curl file created with CURLCreate + /// + /// @param[in] type option type to set, see \ref CURLOptiontype + /// @param[in] name name of the option + /// @param[in] value value of the option + /// @return True on success or false on failure + /// + bool CURLAddOption(CURLOptiontype type, const std::string& name, const std::string& value) + { + if (!m_file) + { + kodi::Log(ADDON_LOG_ERROR, "kodi::vfs::CURLCreate(...) needed to call before!"); + return false; + } + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->curl_add_option(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file, type, name.c_str(), value.c_str()); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Open the curl file created with CURLCreate + /// + /// @param[in] flags [opt] The flags to pass, see \ref OpenFileFlags + /// @return True on success or false on failure + /// + bool CURLOpen(unsigned int flags = 0) + { + if (!m_file) + { + kodi::Log(ADDON_LOG_ERROR, "kodi::vfs::CURLCreate(...) needed to call before!"); + return false; + } + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->curl_open(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file, flags); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Read from an open file. + /// + /// @param[in] ptr The buffer to store the data in. + /// @param[in] size The size of the buffer. + /// @return number of successfully read bytes if any bytes + /// were read and stored in buffer, zero if no bytes + /// are available to read (end of file was reached) + /// or undetectable error occur, -1 in case of any + /// explicit error + /// + ssize_t Read(void* ptr, size_t size) + { + if (!m_file) + return -1; + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->read_file(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file, ptr, size); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Read a string from an open file. + /// + /// @param[out] line The buffer to store the data in. + /// @return True when a line was read, false otherwise. + /// + bool ReadLine(std::string &line) + { + line.clear(); + if (!m_file) + return false; + // TODO: Read 1024 chars into buffer. If file position advanced that many + // chars, we didn't hit a newline. Otherwise, if file position is 1 or 2 + // past the number of bytes read, we read (and skipped) a newline sequence. + char buffer[1025]; + if (::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->read_file_string(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file, buffer, sizeof(buffer))) + { + line = buffer; + return !line.empty(); + } + return false; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Write to a file opened in write mode. + /// + /// @param[in] ptr Pointer to the data to write, converted to a + /// const void*. + /// @param[in] size Size of the data to write. + /// @return number of successfully written bytes if any + /// bytes were written, zero if no bytes were + /// written and no detectable error occur,-1 in case + /// of any explicit error + /// + ssize_t Write(const void* ptr, size_t size) + { + if (!m_file) + return -1; + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->write_file(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file, ptr, size); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Flush buffered data. + /// + /// If the given stream was open for writing (or if it was open for updating + /// and the last i/o operation was an output operation) any unwritten data + /// in its output buffer is written to the file. + /// + /// The stream remains open after this call. + /// + /// When a file is closed, either because of a call to close or because the + /// class is destructed, all the buffers associated with it are + /// automatically flushed. + /// + void Flush() + { + if (!m_file) + return; + ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->flush_file(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Set the file's current position. + /// + /// The whence argument is optional and defaults to SEEK_SET (0) + /// + /// @param[in] position the position that you want to seek to + /// @param[in] whence [optional] offset relative to + /// You can set the value of whence to one. + /// of three things: + /// | Value | int | Description | + /// |:--------:|:---:|:----------------------------------------------------| + /// | SEEK_SET | 0 | position is relative to the beginning of the file. This is probably what you had in mind anyway, and is the most commonly used value for whence. + /// | SEEK_CUR | 1 | position is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes." + /// | SEEK_END | 2 | position is relative to the end of the file. Just like SEEK_SET except from the other end of the file. Be sure to use negative values for offset if you want to back up from the end of the file, instead of going past the end into oblivion. + /// + /// @return Returns the resulting offset location as + /// measured in bytes from the beginning of + /// the file. On error, the value -1 is + /// returned. + /// + int64_t Seek(int64_t position, int whence = SEEK_SET) + { + if (!m_file) + return -1; + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->seek_file(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file, position, whence); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Truncate a file to the requested size. + /// + /// @param[in] size The new max size. + /// @return New size? On error, the value -1 is + /// returned. + /// + int Truncate(int64_t size) + { + if (!m_file) + return -1; + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->truncate_file(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file, size); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief The current offset in an open file. + /// + /// @return The requested offset. On error, the value -1 is + /// returned. + /// + int64_t GetPosition() + { + if (!m_file) + return -1; + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_position(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Get the file size of an open file. + /// + /// @return The requested size. On error, the value -1 is + /// returned. + /// + int64_t GetLength() + { + if (!m_file) + return -1; + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_length(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Checks the file access is on end position. + /// + /// @return If you've reached the end of the file, AtEnd() returns true. + /// + bool AtEnd() + { + if (!m_file) + return true; + int64_t length = ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_length(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file); + int64_t position = ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_position(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file); + return position >= length; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Close an open file. + /// + void Close() + { + if (!m_file) + return; + ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->close_file(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file); + m_file = nullptr; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Get the chunk size for an open file. + /// + /// @return The requested size. On error, the value -1 is + /// returned. + /// + int GetChunkSize() + { + if (!m_file) + return -1; + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_chunk_size(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Get the current download speed of file if loaded from web. + /// + /// @return The current download speed. + /// + double GetFileDownloadSpeed() + { + if (!m_file) + return 0.0; + return ::kodi::addon::CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_download_speed(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, m_file); + } + //-------------------------------------------------------------------------- + + private: + void* m_file; + }; + //@} + //---------------------------------------------------------------------------- + +} /* namespace vfs */ +} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h index 2d197f2924..fa90f77094 100644 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h @@ -41,7 +41,7 @@ * overview. */ -#define ADDON_GLOBAL_VERSION_MAIN "1.0.6" +#define ADDON_GLOBAL_VERSION_MAIN "1.0.7" #define ADDON_GLOBAL_VERSION_MAIN_MIN "1.0.2" #define ADDON_GLOBAL_VERSION_MAIN_XML_ID "kodi.binary.global.main" #define ADDON_GLOBAL_VERSION_MAIN_DEPENDS "AddonBase.h" \ @@ -65,6 +65,11 @@ #define ADDON_GLOBAL_VERSION_AUDIOENGINE_XML_ID "kodi.binary.global.audioengine" #define ADDON_GLOBAL_VERSION_AUDIOENGINE_DEPENDS "AudioEngine.h" +#define ADDON_GLOBAL_VERSION_FILESYSTEM "1.0.0" +#define ADDON_GLOBAL_VERSION_FILESYSTEM_MIN "1.0.0" +#define ADDON_GLOBAL_VERSION_FILESYSTEM_XML_ID "kodi.binary.global.filesystem" +#define ADDON_GLOBAL_VERSION_FILESYSTEM_DEPENDS "Filesystem.h" + #define ADDON_GLOBAL_VERSION_NETWORK "1.0.0" #define ADDON_GLOBAL_VERSION_NETWORK_MIN "1.0.0" #define ADDON_GLOBAL_VERSION_NETWORK_XML_ID "kodi.binary.global.network" @@ -159,7 +164,8 @@ typedef enum ADDON_TYPE ADDON_GLOBAL_AUDIOENGINE = 2, ADDON_GLOBAL_GENERAL = 3, ADDON_GLOBAL_NETWORK = 4, - ADDON_GLOBAL_MAX = 4, // Last used global id, used in loops to check versions. Need to change if new global type becomes added. + ADDON_GLOBAL_FILESYSTEM = 5, + ADDON_GLOBAL_MAX = 5, // Last used global id, used in loops to check versions. Need to change if new global type becomes added. /* addon type instances */ ADDON_INSTANCE_ADSP = 101, @@ -211,6 +217,10 @@ inline const char* GetTypeVersion(int type) case ADDON_GLOBAL_AUDIOENGINE: return ADDON_GLOBAL_VERSION_AUDIOENGINE; #endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_FILESYSTEM_USED) + case ADDON_GLOBAL_FILESYSTEM: + return ADDON_GLOBAL_VERSION_FILESYSTEM; +#endif #if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_NETWORK_USED) case ADDON_GLOBAL_NETWORK: return ADDON_GLOBAL_VERSION_NETWORK; @@ -286,6 +296,8 @@ inline const char* GetTypeMinVersion(int type) return ADDON_GLOBAL_VERSION_GENERAL_MIN; case ADDON_GLOBAL_AUDIOENGINE: return ADDON_GLOBAL_VERSION_AUDIOENGINE_MIN; + case ADDON_GLOBAL_FILESYSTEM: + return ADDON_GLOBAL_VERSION_FILESYSTEM_MIN; case ADDON_GLOBAL_NETWORK: return ADDON_GLOBAL_VERSION_NETWORK_MIN; @@ -336,6 +348,8 @@ inline const char* GetTypeName(int type) return "General"; case ADDON_GLOBAL_AUDIOENGINE: return "AudioEngine"; + case ADDON_GLOBAL_FILESYSTEM: + return "Filesystem"; case ADDON_GLOBAL_NETWORK: return "Network"; @@ -385,6 +399,8 @@ inline int GetTypeId(const char* name) return ADDON_GLOBAL_GUI; else if (strcmp(name, "audioengine") == 0) return ADDON_GLOBAL_AUDIOENGINE; + else if (strcmp(name, "filesystem") == 0) + return ADDON_GLOBAL_FILESYSTEM; else if (strcmp(name, "network") == 0) return ADDON_GLOBAL_NETWORK; else if (strcmp(name, "adsp") == 0) |