summaryrefslogtreecommitdiffstats
path: root/xbmc/addons/interfaces/Filesystem.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--xbmc/addons/interfaces/Filesystem.cpp1181
1 files changed, 1181 insertions, 0 deletions
diff --git a/xbmc/addons/interfaces/Filesystem.cpp b/xbmc/addons/interfaces/Filesystem.cpp
new file mode 100644
index 0000000..c063b48
--- /dev/null
+++ b/xbmc/addons/interfaces/Filesystem.cpp
@@ -0,0 +1,1181 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "Filesystem.h"
+
+#include "FileItem.h"
+#include "Util.h"
+#include "addons/binary-addons/AddonDll.h"
+#include "filesystem/CurlFile.h"
+#include "filesystem/Directory.h"
+#include "filesystem/File.h"
+#include "filesystem/SpecialProtocol.h"
+#include "platform/Filesystem.h"
+#include "utils/Crc32.h"
+#include "utils/HttpHeader.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+#include "utils/log.h"
+
+#include <vector>
+
+#if defined(TARGET_WINDOWS)
+#ifndef S_IFLNK
+#define S_IFLNK 0120000
+#endif
+#ifndef S_ISBLK
+#define S_ISBLK(m) (0)
+#endif
+#ifndef S_ISSOCK
+#define S_ISSOCK(m) (0)
+#endif
+#ifndef S_ISLNK
+#define S_ISLNK(m) ((m & S_IFLNK) != 0)
+#endif
+#ifndef S_ISCHR
+#define S_ISCHR(m) ((m & _S_IFCHR) != 0)
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(m) ((m & _S_IFDIR) != 0)
+#endif
+#ifndef S_ISFIFO
+#define S_ISFIFO(m) ((m & _S_IFIFO) != 0)
+#endif
+#ifndef S_ISREG
+#define S_ISREG(m) ((m & _S_IFREG) != 0)
+#endif
+#endif
+
+using namespace kodi; // addon-dev-kit namespace
+using namespace XFILE;
+
+extern "C"
+{
+namespace ADDON
+{
+
+void Interface_Filesystem::Init(AddonGlobalInterface* addonInterface)
+{
+ addonInterface->toKodi->kodi_filesystem = new 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->remove_directory_recursive = remove_directory_recursive;
+ 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->get_disk_space = get_disk_space;
+ addonInterface->toKodi->kodi_filesystem->is_internet_stream = is_internet_stream;
+ addonInterface->toKodi->kodi_filesystem->is_on_lan = is_on_lan;
+ addonInterface->toKodi->kodi_filesystem->is_remote = is_remote;
+ addonInterface->toKodi->kodi_filesystem->is_local = is_local;
+ addonInterface->toKodi->kodi_filesystem->is_url = is_url;
+ addonInterface->toKodi->kodi_filesystem->get_http_header = get_http_header;
+ addonInterface->toKodi->kodi_filesystem->get_mime_type = get_mime_type;
+ addonInterface->toKodi->kodi_filesystem->get_content_type = get_content_type;
+ addonInterface->toKodi->kodi_filesystem->get_cookies = get_cookies;
+
+ addonInterface->toKodi->kodi_filesystem->http_header_create = http_header_create;
+ addonInterface->toKodi->kodi_filesystem->http_header_free = http_header_free;
+
+ 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->io_control_get_seek_possible =
+ io_control_get_seek_possible;
+ addonInterface->toKodi->kodi_filesystem->io_control_get_cache_status =
+ io_control_get_cache_status;
+ addonInterface->toKodi->kodi_filesystem->io_control_set_cache_rate = io_control_set_cache_rate;
+ addonInterface->toKodi->kodi_filesystem->io_control_set_retry = io_control_set_retry;
+ addonInterface->toKodi->kodi_filesystem->get_property_values = get_property_values;
+
+ 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) /* <-- Safe check, needed so long old addon way is present */
+ {
+ delete addonInterface->toKodi->kodi_filesystem;
+ addonInterface->toKodi->kodi_filesystem = nullptr;
+ }
+}
+
+unsigned int Interface_Filesystem::TranslateFileReadBitsToKodi(unsigned int addonFlags)
+{
+ unsigned int kodiFlags = 0;
+
+ if (addonFlags & ADDON_READ_TRUNCATED)
+ kodiFlags |= READ_TRUNCATED;
+ if (addonFlags & ADDON_READ_CHUNKED)
+ kodiFlags |= READ_CHUNKED;
+ if (addonFlags & ADDON_READ_CACHED)
+ kodiFlags |= READ_CACHED;
+ if (addonFlags & ADDON_READ_NO_CACHE)
+ kodiFlags |= READ_NO_CACHE;
+ if (addonFlags & ADDON_READ_BITRATE)
+ kodiFlags |= READ_BITRATE;
+ if (addonFlags & ADDON_READ_MULTI_STREAM)
+ kodiFlags |= READ_MULTI_STREAM;
+ if (addonFlags & ADDON_READ_AUDIO_VIDEO)
+ kodiFlags |= READ_AUDIO_VIDEO;
+ if (addonFlags & ADDON_READ_AFTER_WRITE)
+ kodiFlags |= READ_AFTER_WRITE;
+ if (addonFlags & READ_REOPEN)
+ kodiFlags |= READ_REOPEN;
+
+ return kodiFlags;
+}
+
+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::{} - invalid data (addon='{}', url='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(url));
+ return false;
+ }
+
+ CFileItemList items;
+ return CDirectory::GetDirectory(url, items, "", DIR_FLAG_DEFAULTS | DIR_FLAG_BYPASS_CACHE);
+}
+
+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::{} - invalid data (addon='{}', path='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(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::{} - invalid data (addon='{}', path='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(path));
+ return false;
+ }
+
+ return CDirectory::Exists(path, false);
+}
+
+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::{} - invalid data (addon='{}', path='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(path));
+ return false;
+ }
+
+ // Empty directory
+ CFileItemList fileItems;
+ CDirectory::GetDirectory(path, fileItems, "", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_BYPASS_CACHE);
+ for (int i = 0; i < fileItems.Size(); ++i)
+ CFile::Delete(fileItems.Get(i)->GetPath());
+
+ return CDirectory::Remove(path);
+}
+
+bool Interface_Filesystem::remove_directory_recursive(void* kodiBase, const char* path)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || path == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(path));
+ return false;
+ }
+
+ return CDirectory::RemoveRecursive(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,
+ struct 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::{} - invalid data (addon='{}', path='{}', mask='{}', "
+ "items='{}', num_items='{}'",
+ __FUNCTION__, kodiBase, static_cast<const void*>(path),
+ static_cast<const void*>(mask), static_cast<void*>(items),
+ static_cast<void*>(num_items));
+ return false;
+ }
+
+ CFileItemList fileItems;
+ if (!CDirectory::GetDirectory(path, fileItems, mask,
+ DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_BYPASS_CACHE))
+ 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,
+ struct VFSDirEntry* items,
+ unsigned int num_items)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || items == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', items='{}')",
+ __FUNCTION__, kodiBase, static_cast<void*>(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::{} - invalid data (addon='{}', filename='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(filename));
+ return false;
+ }
+
+ return CFile::Exists(filename, useCache);
+}
+
+bool Interface_Filesystem::stat_file(void* kodiBase,
+ const char* filename,
+ struct STAT_STRUCTURE* buffer)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || filename == nullptr || buffer == nullptr)
+ {
+ CLog::Log(LOGERROR,
+ "Interface_Filesystem::{} - invalid data (addon='{}', filename='{}', buffer='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(filename),
+ static_cast<void*>(buffer));
+ return false;
+ }
+
+ struct __stat64 statBuffer;
+ if (CFile::Stat(filename, &statBuffer) != 0)
+ return false;
+
+ buffer->deviceId = statBuffer.st_dev;
+ buffer->fileSerialNumber = statBuffer.st_ino;
+ buffer->size = statBuffer.st_size;
+ buffer->accessTime = statBuffer.st_atime;
+ buffer->modificationTime = statBuffer.st_mtime;
+ buffer->statusTime = statBuffer.st_ctime;
+ buffer->isDirectory = S_ISDIR(statBuffer.st_mode);
+ buffer->isSymLink = S_ISLNK(statBuffer.st_mode);
+ buffer->isBlock = S_ISBLK(statBuffer.st_mode);
+ buffer->isCharacter = S_ISCHR(statBuffer.st_mode);
+ buffer->isFifo = S_ISFIFO(statBuffer.st_mode);
+ buffer->isRegular = S_ISREG(statBuffer.st_mode);
+ buffer->isSocket = S_ISSOCK(statBuffer.st_mode);
+
+ return true;
+}
+
+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::{} - invalid data (addon='{}', filename='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(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::{} - invalid data (addon='{}', filename='{}', newFileName='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(filename),
+ static_cast<const void*>(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::{} - invalid data (addon='{}', filename='{}', dest='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(filename), static_cast<const void*>(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::{} - invalid data (addon='{}', filename='{})",
+ __FUNCTION__, kodiBase, static_cast<const void*>(filename));
+ return nullptr;
+ }
+
+ std::string string = CUtil::GetFileDigest(filename, KODI::UTILITY::CDigest::Type::MD5);
+ 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::{} - invalid data (addon='{}', filename='{})",
+ __FUNCTION__, kodiBase, static_cast<const void*>(filename));
+ return nullptr;
+ }
+
+ const auto crc = Crc32::ComputeFromLowerCase(filename);
+ const auto hex = StringUtils::Format("{:08x}.tbn", crc);
+ char* buffer = strdup(hex.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::{} - invalid data (addon='{}', filename='{})",
+ __FUNCTION__, kodiBase, static_cast<const void*>(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::{} - invalid data (addon='{}', path='{})",
+ __FUNCTION__, kodiBase, static_cast<const void*>(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::{} - invalid data (addon='{}', strSource='{})",
+ __FUNCTION__, kodiBase, static_cast<const void*>(strSource));
+ return nullptr;
+ }
+
+ return strdup(CSpecialProtocol::TranslatePath(strSource).c_str());
+}
+
+bool Interface_Filesystem::get_disk_space(
+ void* kodiBase, const char* path, uint64_t* capacity, uint64_t* free, uint64_t* available)
+{
+ using namespace KODI::PLATFORM::FILESYSTEM;
+
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || path == nullptr || capacity == nullptr || free == nullptr ||
+ available == nullptr)
+ {
+ CLog::Log(
+ LOGERROR,
+ "Interface_Filesystem::{} - invalid data (addon='{}', path='{}, capacity='{}, free='{}, "
+ "available='{})",
+ __FUNCTION__, kodiBase, static_cast<const void*>(path), static_cast<void*>(capacity),
+ static_cast<void*>(free), static_cast<void*>(available));
+ return false;
+ }
+
+ std::error_code ec;
+ auto freeSpace = space(CSpecialProtocol::TranslatePath(path), ec);
+ if (ec.value() != 0)
+ return false;
+
+ *capacity = freeSpace.capacity;
+ *free = freeSpace.free;
+ *available = freeSpace.available;
+ return true;
+}
+
+bool Interface_Filesystem::is_internet_stream(void* kodiBase, const char* path, bool strictCheck)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || path == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{})",
+ __FUNCTION__, kodiBase, static_cast<const void*>(path));
+ return false;
+ }
+
+ return URIUtils::IsInternetStream(path, strictCheck);
+}
+
+bool Interface_Filesystem::is_on_lan(void* kodiBase, const char* path)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || path == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{})",
+ __FUNCTION__, kodiBase, static_cast<const void*>(path));
+ return false;
+ }
+
+ return URIUtils::IsOnLAN(path);
+}
+
+bool Interface_Filesystem::is_remote(void* kodiBase, const char* path)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || path == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{})",
+ __FUNCTION__, kodiBase, static_cast<const void*>(path));
+ return false;
+ }
+
+ return URIUtils::IsRemote(path);
+}
+
+bool Interface_Filesystem::is_local(void* kodiBase, const char* path)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || path == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{})",
+ __FUNCTION__, kodiBase, static_cast<const void*>(path));
+ return false;
+ }
+
+ return CURL(path).IsLocal();
+}
+
+bool Interface_Filesystem::is_url(void* kodiBase, const char* path)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || path == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{})",
+ __FUNCTION__, kodiBase, static_cast<const void*>(path));
+ return false;
+ }
+
+ return URIUtils::IsURL(path);
+}
+
+bool Interface_Filesystem::get_mime_type(void* kodiBase,
+ const char* url,
+ char** content,
+ const char* useragent)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || url == nullptr || content == nullptr || useragent == nullptr)
+ {
+ CLog::Log(LOGERROR,
+ "Interface_Filesystem::{} - invalid data (addon='{}', url='{}', content='{}', "
+ "useragent='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(url),
+ static_cast<const void*>(content), static_cast<const void*>(useragent));
+ return false;
+ }
+
+ std::string kodiContent;
+ bool ret = XFILE::CCurlFile::GetMimeType(CURL(url), kodiContent, useragent);
+ if (ret && !kodiContent.empty())
+ {
+ *content = strdup(kodiContent.c_str());
+ }
+ return ret;
+}
+
+bool Interface_Filesystem::get_content_type(void* kodiBase,
+ const char* url,
+ char** content,
+ const char* useragent)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || url == nullptr || content == nullptr || useragent == nullptr)
+ {
+ CLog::Log(LOGERROR,
+ "Interface_Filesystem::{} - invalid data (addon='{}', url='{}', content='{}', "
+ "useragent='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(url),
+ static_cast<const void*>(content), static_cast<const void*>(useragent));
+ return false;
+ }
+
+ std::string kodiContent;
+ bool ret = XFILE::CCurlFile::GetContentType(CURL(url), kodiContent, useragent);
+ if (ret && !kodiContent.empty())
+ {
+ *content = strdup(kodiContent.c_str());
+ }
+ return ret;
+}
+
+bool Interface_Filesystem::get_cookies(void* kodiBase, const char* url, char** cookies)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || url == nullptr || cookies == nullptr)
+ {
+ CLog::Log(
+ LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', url='{}', cookies='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(url), static_cast<const void*>(cookies));
+ return false;
+ }
+
+ std::string kodiCookies;
+ bool ret = XFILE::CCurlFile::GetCookies(CURL(url), kodiCookies);
+ if (ret && !kodiCookies.empty())
+ {
+ *cookies = strdup(kodiCookies.c_str());
+ }
+ return ret;
+}
+
+bool Interface_Filesystem::get_http_header(void* kodiBase,
+ const char* url,
+ struct KODI_HTTP_HEADER* headers)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || url == nullptr || headers == nullptr || headers->handle == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data pointer given", __func__);
+ return false;
+ }
+
+ CHttpHeader* httpHeader = static_cast<CHttpHeader*>(headers->handle);
+ return XFILE::CCurlFile::GetHttpHeader(CURL(url), *httpHeader);
+}
+
+//------------------------------------------------------------------------------
+
+bool Interface_Filesystem::http_header_create(void* kodiBase, struct KODI_HTTP_HEADER* headers)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || headers == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', headers='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(headers));
+ return false;
+ }
+
+ headers->handle = new CHttpHeader;
+ headers->get_value = http_header_get_value;
+ headers->get_values = http_header_get_values;
+ headers->get_header = http_header_get_header;
+ headers->get_mime_type = http_header_get_mime_type;
+ headers->get_charset = http_header_get_charset;
+ headers->get_proto_line = http_header_get_proto_line;
+
+ return true;
+}
+
+void Interface_Filesystem::http_header_free(void* kodiBase, struct KODI_HTTP_HEADER* headers)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || headers == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', headers='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(headers));
+ return;
+ }
+
+ delete static_cast<CHttpHeader*>(headers->handle);
+ headers->handle = nullptr;
+}
+
+char* Interface_Filesystem::http_header_get_value(void* kodiBase, void* handle, const char* param)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || handle == nullptr || param == nullptr)
+ {
+ CLog::Log(LOGERROR,
+ "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}', param='{}')",
+ __FUNCTION__, kodiBase, handle, static_cast<const void*>(param));
+ return nullptr;
+ }
+
+ std::string string = static_cast<CHttpHeader*>(handle)->GetValue(param);
+
+ char* buffer = nullptr;
+ if (!string.empty())
+ buffer = strdup(string.c_str());
+ return buffer;
+}
+
+char** Interface_Filesystem::http_header_get_values(void* kodiBase,
+ void* handle,
+ const char* param,
+ int* length)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || handle == nullptr || param == nullptr || length == nullptr)
+ {
+ CLog::Log(LOGERROR,
+ "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}', param='{}', "
+ "length='{}')",
+ __FUNCTION__, kodiBase, handle, static_cast<const void*>(param),
+ static_cast<const void*>(length));
+ return nullptr;
+ }
+
+
+ std::vector<std::string> values = static_cast<CHttpHeader*>(handle)->GetValues(param);
+ *length = values.size();
+ char** ret = static_cast<char**>(malloc(sizeof(char*) * values.size()));
+ for (int i = 0; i < *length; ++i)
+ {
+ ret[i] = strdup(values[i].c_str());
+ }
+ return ret;
+}
+
+char* Interface_Filesystem::http_header_get_header(void* kodiBase, void* handle)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || handle == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}')",
+ __FUNCTION__, kodiBase, handle);
+ return nullptr;
+ }
+
+ std::string string = static_cast<CHttpHeader*>(handle)->GetHeader();
+
+ char* buffer = nullptr;
+ if (!string.empty())
+ buffer = strdup(string.c_str());
+ return buffer;
+}
+
+char* Interface_Filesystem::http_header_get_mime_type(void* kodiBase, void* handle)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || handle == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}')",
+ __FUNCTION__, kodiBase, handle);
+ return nullptr;
+ }
+
+ std::string string = static_cast<CHttpHeader*>(handle)->GetMimeType();
+
+ char* buffer = nullptr;
+ if (!string.empty())
+ buffer = strdup(string.c_str());
+ return buffer;
+}
+
+char* Interface_Filesystem::http_header_get_charset(void* kodiBase, void* handle)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || handle == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}')",
+ __FUNCTION__, kodiBase, handle);
+ return nullptr;
+ }
+
+ std::string string = static_cast<CHttpHeader*>(handle)->GetCharset();
+
+ char* buffer = nullptr;
+ if (!string.empty())
+ buffer = strdup(string.c_str());
+ return buffer;
+}
+
+char* Interface_Filesystem::http_header_get_proto_line(void* kodiBase, void* handle)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || handle == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}')",
+ __FUNCTION__, kodiBase, handle);
+ return nullptr;
+ }
+
+ std::string string = static_cast<CHttpHeader*>(handle)->GetProtoLine();
+
+ char* buffer = nullptr;
+ if (!string.empty())
+ buffer = strdup(string.c_str());
+ return buffer;
+}
+
+//------------------------------------------------------------------------------
+
+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::{} - invalid data (addon='{}', filename='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(filename));
+ return nullptr;
+ }
+
+ CFile* file = new CFile;
+ if (file->Open(filename, TranslateFileReadBitsToKodi(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::{} - invalid data (addon='{}', filename='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(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::{} - invalid data (addon='{}', file='{}', ptr='{}')",
+ __FUNCTION__, kodiBase, 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 || szLine == nullptr)
+ {
+ CLog::Log(LOGERROR,
+ "Interface_Filesystem::{} - invalid data (addon='{}', file='{}', szLine=='{}')",
+ __FUNCTION__, kodiBase, file, static_cast<void*>(szLine));
+ 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::{} - invalid data (addon='{}', file='{}', ptr='{}')",
+ __FUNCTION__, kodiBase, 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::{} - invalid data (addon='{}', file='{}')",
+ __FUNCTION__, kodiBase, 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::{} - invalid data (addon='{}', file='{}')",
+ __FUNCTION__, kodiBase, 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::{} - invalid data (addon='{}', file='{}')",
+ __FUNCTION__, kodiBase, 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::{} - invalid data (addon='{}', file='{}')",
+ __FUNCTION__, kodiBase, 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::{} - invalid data (addon='{}', file='{}')",
+ __FUNCTION__, kodiBase, 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::{} - invalid data (addon='{}', file='{}')",
+ __FUNCTION__, kodiBase, file);
+ return 0.0;
+ }
+
+ 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::{} - invalid data (addon='{}', file='{}')",
+ __FUNCTION__, kodiBase, 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::{} - invalid data (addon='{}', file='{}')", __FUNCTION__,
+ kodiBase, file);
+ return -1;
+ }
+
+ return static_cast<CFile*>(file)->GetChunkSize();
+}
+
+bool Interface_Filesystem::io_control_get_seek_possible(void* kodiBase, void* file)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || file == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_VFS::{} - invalid data (addon='{}', file='{}')", __FUNCTION__,
+ kodiBase, file);
+ return false;
+ }
+
+ return static_cast<CFile*>(file)->IoControl(EIoControl::IOCTRL_SEEK_POSSIBLE, nullptr) != 0
+ ? true
+ : false;
+}
+
+bool Interface_Filesystem::io_control_get_cache_status(void* kodiBase,
+ void* file,
+ struct VFS_CACHE_STATUS_DATA* status)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || file == nullptr || status == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_VFS::{} - invalid data (addon='{}', file='{}, status='{}')",
+ __FUNCTION__, kodiBase, file, static_cast<const void*>(status));
+ return false;
+ }
+
+ SCacheStatus data = {};
+ int ret = static_cast<CFile*>(file)->IoControl(EIoControl::IOCTRL_CACHE_STATUS, &data);
+ if (ret >= 0)
+ {
+ status->forward = data.forward;
+ status->maxrate = data.maxrate;
+ status->currate = data.currate;
+ status->lowrate = data.lowrate;
+ return true;
+ }
+ return false;
+}
+
+bool Interface_Filesystem::io_control_set_cache_rate(void* kodiBase, void* file, uint32_t rate)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || file == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_VFS::{} - invalid data (addon='{}', file='{}')", __FUNCTION__,
+ kodiBase, file);
+ return false;
+ }
+
+ return static_cast<CFile*>(file)->IoControl(EIoControl::IOCTRL_CACHE_SETRATE, &rate) >= 0 ? true
+ : false;
+}
+
+bool Interface_Filesystem::io_control_set_retry(void* kodiBase, void* file, bool retry)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || file == nullptr)
+ {
+ CLog::Log(LOGERROR, "Interface_VFS::{} - invalid data (addon='{}', file='{}')", __FUNCTION__,
+ kodiBase, file);
+ return false;
+ }
+
+ return static_cast<CFile*>(file)->IoControl(EIoControl::IOCTRL_SET_RETRY, &retry) >= 0 ? true
+ : false;
+}
+
+char** Interface_Filesystem::get_property_values(
+ void* kodiBase, void* file, int type, const char* name, int* numValues)
+{
+ CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
+ if (addon == nullptr || file == nullptr || name == nullptr || numValues == nullptr)
+ {
+ CLog::Log(LOGERROR,
+ "Interface_Filesystem::{} - invalid data (addon='{}', file='{}', name='{}', "
+ "numValues='{}')",
+ __FUNCTION__, kodiBase, file, static_cast<const void*>(name),
+ static_cast<void*>(numValues));
+ return nullptr;
+ }
+
+ XFILE::FileProperty internalType;
+ switch (type)
+ {
+ case ADDON_FILE_PROPERTY_RESPONSE_PROTOCOL:
+ internalType = XFILE::FILE_PROPERTY_RESPONSE_PROTOCOL;
+ break;
+ case ADDON_FILE_PROPERTY_RESPONSE_HEADER:
+ internalType = XFILE::FILE_PROPERTY_RESPONSE_HEADER;
+ break;
+ case ADDON_FILE_PROPERTY_CONTENT_TYPE:
+ internalType = XFILE::FILE_PROPERTY_CONTENT_TYPE;
+ break;
+ case ADDON_FILE_PROPERTY_CONTENT_CHARSET:
+ internalType = XFILE::FILE_PROPERTY_CONTENT_CHARSET;
+ break;
+ case ADDON_FILE_PROPERTY_MIME_TYPE:
+ internalType = XFILE::FILE_PROPERTY_MIME_TYPE;
+ break;
+ case ADDON_FILE_PROPERTY_EFFECTIVE_URL:
+ internalType = XFILE::FILE_PROPERTY_EFFECTIVE_URL;
+ break;
+ default:
+ CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}')",
+ __FUNCTION__, kodiBase, file);
+ return nullptr;
+ };
+ std::vector<std::string> values =
+ static_cast<CFile*>(file)->GetPropertyValues(internalType, name);
+ *numValues = values.size();
+ char** ret = static_cast<char**>(malloc(sizeof(char*) * values.size()));
+ for (int i = 0; i < *numValues; ++i)
+ {
+ ret[i] = strdup(values[i].c_str());
+ }
+ return ret;
+}
+
+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::{} - invalid data (addon='{}', url='{}')",
+ __FUNCTION__, kodiBase, static_cast<const void*>(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::{} - invalid data (addon='{}', file='{}', name='{}', value='{}')",
+ __FUNCTION__, kodiBase, file, static_cast<const void*>(name),
+ static_cast<const void*>(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;
+ };
+
+ return static_cast<CFile*>(file)->CURLAddOption(internalType, name, value);
+}
+
+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::{} - invalid data (addon='{}', file='{}')",
+ __FUNCTION__, kodiBase, file);
+ return false;
+ }
+
+ return static_cast<CFile*>(file)->CURLOpen(TranslateFileReadBitsToKodi(flags));
+}
+
+} /* namespace ADDON */
+} /* extern "C" */