diff options
author | notspiff <cptspiff@gmail.com> | 2016-08-19 13:33:02 +0200 |
---|---|---|
committer | notspiff <cptspiff@gmail.com> | 2017-01-09 14:45:40 +0100 |
commit | db313a1567ffd81bf2cc95752d68152db8dc75ce (patch) | |
tree | 84215746473c6b2c86c371afc948569d3df74e47 | |
parent | b7f0f4be0ac5850fb72ceabfa7d7e6fd6cd52eaf (diff) |
add support for vfs add-ons
-rw-r--r-- | addons/kodi.vfs/addon.xml | 7 | ||||
-rw-r--r-- | addons/resource.language.en_gb/resources/strings.po | 5 | ||||
-rw-r--r-- | cmake/cpack/deb/packages/kodi-vfs-dev.txt.in | 25 | ||||
-rw-r--r-- | cmake/installdata/common/addons.txt | 1 | ||||
-rw-r--r-- | cmake/scripts/linux/Install.cmake | 7 | ||||
-rw-r--r-- | system/addon-manifest.xml | 1 | ||||
-rw-r--r-- | xbmc/Application.cpp | 28 | ||||
-rw-r--r-- | xbmc/addons/Addon.cpp | 1 | ||||
-rw-r--r-- | xbmc/addons/AddonBuilder.cpp | 4 | ||||
-rw-r--r-- | xbmc/addons/AddonManager.cpp | 1 | ||||
-rw-r--r-- | xbmc/addons/BinaryAddonCache.cpp | 3 | ||||
-rw-r--r-- | xbmc/addons/CMakeLists.txt | 2 | ||||
-rw-r--r-- | xbmc/addons/IAddon.h | 1 | ||||
-rw-r--r-- | xbmc/addons/VFSEntry.cpp | 537 | ||||
-rw-r--r-- | xbmc/addons/VFSEntry.h | 289 | ||||
-rw-r--r-- | xbmc/addons/addon-bindings.mk | 1 | ||||
-rw-r--r-- | xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_dll.h | 126 | ||||
-rw-r--r-- | xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_types.h | 226 | ||||
-rw-r--r-- | xbmc/filesystem/AddonsDirectory.cpp | 2 | ||||
-rw-r--r-- | xbmc/filesystem/DirectoryFactory.cpp | 18 | ||||
-rw-r--r-- | xbmc/filesystem/FileDirectoryFactory.cpp | 40 | ||||
-rw-r--r-- | xbmc/filesystem/FileFactory.cpp | 21 |
22 files changed, 1341 insertions, 5 deletions
diff --git a/addons/kodi.vfs/addon.xml b/addons/kodi.vfs/addon.xml new file mode 100644 index 0000000000..4535e332e9 --- /dev/null +++ b/addons/kodi.vfs/addon.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<addon id="kodi.vfs" version="1.0.0" provider-name="Team-Kodi"> + <backwards-compatibility abi="1.0.0"/> + <requires> + <import addon="xbmc.core" version="0.1.0"/> + </requires> +</addon> diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index a4cc34078d..eec9e8636a 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -20405,3 +20405,8 @@ msgstr "" msgctxt "#39012" msgid "Set the maximum time to wait for the network to come up after starting or waking up. When time has passed before network is up startup will continue." msgstr "" + +#: xbmc/addons/Addon.cpp +msgctxt "#39013" +msgid "Virtual filesystems" +msgstr "" diff --git a/cmake/cpack/deb/packages/kodi-vfs-dev.txt.in b/cmake/cpack/deb/packages/kodi-vfs-dev.txt.in new file mode 100644 index 0000000000..091193e413 --- /dev/null +++ b/cmake/cpack/deb/packages/kodi-vfs-dev.txt.in @@ -0,0 +1,25 @@ +# kodi-vfs-dev debian package metadata +# +# Setting PACKAGE_SHLIBDEPS to 'ON' will cause CPack to use dpkg-shlibdeps to +# automatically generate the package dependency list and append its output to +# PACKAGE_DEPENDS list. Only useful for packages that contain binaries. +# +# PACKAGE_ARCHITECTURE should be set to 'all' only if package contains +# architecture agnostic data. CPack will set proper architecture (amd64/i386/etc) +# based on build options. +# +# Remaining settings are (hopefully) self-explanatory. + +PACKAGE_NAME @APP_NAME_LC@-vfs-dev +PACKAGE_ARCHITECTURE all +PACKAGE_SECTION libdevel +PACKAGE_PRIORITY optional +PACKAGE_SHLIBDEPS +PACKAGE_DEPENDS @APP_NAME_LC@-addon-dev +PACKAGE_RECOMMENDS +PACKAGE_SUGGESTS +PACKAGE_BREAKS +PACKAGE_REPLACES +PACKAGE_PROVIDES xbmc-vfs-dev +PACKAGE_DESCRIPTION_HEADER @APP_NAME@ Media Center (vfs add-ons dev package) +PACKAGE_DESCRIPTION_FOOTER This is the development package for @APP_NAME@'s vfs add-ons. diff --git a/cmake/installdata/common/addons.txt b/cmake/installdata/common/addons.txt index cd434515fd..99857a7699 100644 --- a/cmake/installdata/common/addons.txt +++ b/cmake/installdata/common/addons.txt @@ -40,3 +40,4 @@ addons/metadata.common.theaudiodb.com/* addons/metadata.common.themoviedb.org/* addons/metadata.themoviedb.org/* addons/metadata.tvdb.com/* +addons/kodi.vfs/* diff --git a/cmake/scripts/linux/Install.cmake b/cmake/scripts/linux/Install.cmake index f15267b397..e2baab09f0 100644 --- a/cmake/scripts/linux/Install.cmake +++ b/cmake/scripts/linux/Install.cmake @@ -318,6 +318,13 @@ install(FILES ${CMAKE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/ko DESTINATION ${includedir}/${APP_NAME_LC} COMPONENT kodi-game-dev) +# Install kodi-vfs-dev +install(FILES ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_dll.h + ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_types.h + ${CORE_SOURCE_DIR}/xbmc/filesystem/IFileTypes.h + DESTINATION include/${APP_NAME_LC} + COMPONENT kodi-vfs-dev) + # Install XBT skin files foreach(texture ${XBT_FILES}) string(REPLACE "${CMAKE_BINARY_DIR}/" "" dir ${texture}) diff --git a/system/addon-manifest.xml b/system/addon-manifest.xml index 04cce30856..0df3df682e 100644 --- a/system/addon-manifest.xml +++ b/system/addon-manifest.xml @@ -9,6 +9,7 @@ <addon>kodi.inputstream</addon> <addon>kodi.peripheral</addon> <addon>kodi.resource</addon> + <addon>kodi.vfs</addon> <addon>metadata.album.universal</addon> <addon>metadata.artists.universal</addon> <addon>metadata.common.allmusic.com</addon> diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp index 6d9f3eddd2..e793ddbd2d 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -53,6 +53,7 @@ #include "addons/BinaryAddonCache.h" #include "addons/LanguageResource.h" #include "addons/Skin.h" +#include "addons/VFSEntry.h" #include "interfaces/generic/ScriptInvocationManager.h" #ifdef HAS_PYTHON #include "interfaces/python/XBPython.h" @@ -204,6 +205,7 @@ #ifdef TARGET_POSIX #include "XHandle.h" #include "XTimeUtils.h" +#include "filesystem/posix/PosixDirectory.h" #endif #if defined(TARGET_ANDROID) @@ -2944,6 +2946,14 @@ void CApplication::Stop(int exitCode) #ifdef HAS_FILESYSTEM_SFTP CSFTPSessionManager::DisconnectAllSessions(); #endif + VECADDONS addons; + CServiceBroker::GetBinaryAddonCache().GetAddons(addons, ADDON_VFS); + for (auto& it : addons) + { + AddonPtr addon = CServiceBroker::GetBinaryAddonCache().GetAddonInstance(it->ID(), ADDON_VFS); + VFSEntryPtr vfs = std::static_pointer_cast<CVFSEntry>(addon); + vfs->DisconnectAll(); + } #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB) smb.Deinit(); @@ -4582,6 +4592,15 @@ void CApplication::ProcessSlow() CSFTPSessionManager::ClearOutIdleSessions(); #endif + VECADDONS addons; + CServiceBroker::GetBinaryAddonCache().GetAddons(addons, ADDON_VFS); + for (auto& it : addons) + { + AddonPtr addon = CServiceBroker::GetBinaryAddonCache().GetAddonInstance(it->ID(), ADDON_VFS); + VFSEntryPtr vfs = std::static_pointer_cast<CVFSEntry>(addon); + vfs->ClearOutIdle(); + } + g_mediaManager.ProcessEvents(); CAEFactory::GarbageCollect(); @@ -5203,6 +5222,15 @@ void CApplication::CloseNetworkShares() #ifdef HAS_FILESYSTEM_SFTP CSFTPSessionManager::DisconnectAllSessions(); #endif + + VECADDONS addons; + CServiceBroker::GetBinaryAddonCache().GetAddons(addons, ADDON_VFS); + for (auto& it : addons) + { + AddonPtr addon = CServiceBroker::GetBinaryAddonCache().GetAddonInstance(it->ID(), ADDON_VFS); + VFSEntryPtr vfs = std::static_pointer_cast<CVFSEntry>(addon); + vfs->DisconnectAll(); + } } void CApplication::RegisterActionListener(IActionListener *listener) diff --git a/xbmc/addons/Addon.cpp b/xbmc/addons/Addon.cpp index c24396f955..3b94e5aa49 100644 --- a/xbmc/addons/Addon.cpp +++ b/xbmc/addons/Addon.cpp @@ -109,6 +109,7 @@ static const TypeMapping types[] = {"kodi.resource.games", ADDON_RESOURCE_GAMES, 35209, "DefaultAddonGame.png" }, {"kodi.adsp", ADDON_ADSPDLL, 24135, "DefaultAddonAudioDSP.png" }, {"kodi.inputstream", ADDON_INPUTSTREAM, 24048, "DefaultAddonInputstream.png" }, + {"kodi.vfs", ADDON_VFS, 39013, "DefaultAddonVfs.png" }, }; std::string TranslateType(ADDON::TYPE type, bool pretty/*=false*/) diff --git a/xbmc/addons/AddonBuilder.cpp b/xbmc/addons/AddonBuilder.cpp index f7b9f68372..2df8abcd3f 100644 --- a/xbmc/addons/AddonBuilder.cpp +++ b/xbmc/addons/AddonBuilder.cpp @@ -33,6 +33,7 @@ #include "addons/Service.h" #include "addons/Skin.h" #include "addons/UISoundsResource.h" +#include "addons/VFSEntry.h" #include "addons/Visualisation.h" #include "addons/Webinterface.h" #include "cores/AudioEngine/Engines/ActiveAE/AudioDSPAddons/ActiveAEDSP.h" @@ -89,6 +90,7 @@ std::shared_ptr<IAddon> CAddonBuilder::Build() type == ADDON_ADSPDLL || type == ADDON_AUDIOENCODER || type == ADDON_AUDIODECODER || + type == ADDON_VFS || type == ADDON_INPUTSTREAM || type == ADDON_PERIPHERALDLL || type == ADDON_GAMEDLL) @@ -142,6 +144,8 @@ std::shared_ptr<IAddon> CAddonBuilder::Build() return PERIPHERALS::CPeripheralAddon::FromExtension(std::move(m_props), m_extPoint); case ADDON_GAMEDLL: return GAME::CGameClient::FromExtension(std::move(m_props), m_extPoint); + case ADDON_VFS: + return CVFSEntry::FromExtension(std::move(m_props), m_extPoint); case ADDON_SKIN: return CSkinInfo::FromExtension(std::move(m_props), m_extPoint); case ADDON_RESOURCE_IMAGES: diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp index d0300fad4d..4c7c1cd5a3 100644 --- a/xbmc/addons/AddonManager.cpp +++ b/xbmc/addons/AddonManager.cpp @@ -40,6 +40,7 @@ #include "events/AddonManagementEvent.h" #include "events/EventLog.h" #include "filesystem/SpecialProtocol.h" +#include "VFSEntry.h" #include "LangInfo.h" #include "PluginSource.h" #include "Repository.h" diff --git a/xbmc/addons/BinaryAddonCache.cpp b/xbmc/addons/BinaryAddonCache.cpp index a09a4b55a9..41f08ff6a5 100644 --- a/xbmc/addons/BinaryAddonCache.cpp +++ b/xbmc/addons/BinaryAddonCache.cpp @@ -37,6 +37,7 @@ void CBinaryAddonCache::Init() ADDON_INPUTSTREAM, ADDON_PVRDLL, ADDON_GAMEDLL, + ADDON_VFS }; CAddonMgr::GetInstance().Events().Subscribe(this, &CBinaryAddonCache::OnEvent); Update(); @@ -111,4 +112,4 @@ void CBinaryAddonCache::Update() } } -}
\ No newline at end of file +} diff --git a/xbmc/addons/CMakeLists.txt b/xbmc/addons/CMakeLists.txt index f026e604d0..b6d26bcb5a 100644 --- a/xbmc/addons/CMakeLists.txt +++ b/xbmc/addons/CMakeLists.txt @@ -30,6 +30,7 @@ set(SOURCES Addon.cpp Service.cpp Skin.cpp UISoundsResource.cpp + VFSEntry.cpp Visualisation.cpp Webinterface.cpp) @@ -70,6 +71,7 @@ set(HEADERS Addon.h Service.h Skin.h UISoundsResource.h + VFSEntry.h Visualisation.h Webinterface.h) diff --git a/xbmc/addons/IAddon.h b/xbmc/addons/IAddon.h index 0a19579760..b58e19e752 100644 --- a/xbmc/addons/IAddon.h +++ b/xbmc/addons/IAddon.h @@ -64,6 +64,7 @@ namespace ADDON ADDON_RESOURCE_LANGUAGE, ADDON_RESOURCE_UISOUNDS, ADDON_RESOURCE_GAMES, + ADDON_VFS, ADDON_VIDEO, // virtual addon types ADDON_AUDIO, ADDON_IMAGE, diff --git a/xbmc/addons/VFSEntry.cpp b/xbmc/addons/VFSEntry.cpp new file mode 100644 index 0000000000..d056c838ef --- /dev/null +++ b/xbmc/addons/VFSEntry.cpp @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2013 Arne Morten Kvarving + * + * 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#include "VFSEntry.h" +#include "AddonManager.h" +#include "utils/StringUtils.h" +#include "URL.h" + +namespace ADDON +{ + +class CVFSURLWrapper +{ + public: + CVFSURLWrapper(const CURL& url2) + { + m_strings.push_back(url2.Get()); + m_strings.push_back(url2.GetDomain()); + m_strings.push_back(url2.GetHostName()); + m_strings.push_back(url2.GetFileName()); + m_strings.push_back(url2.GetOptions()); + m_strings.push_back(url2.GetUserName()); + m_strings.push_back(url2.GetPassWord()); + m_strings.push_back(url2.GetRedacted()); + m_strings.push_back(url2.GetShareName()); + + url.url = m_strings[0].c_str(); + url.domain = m_strings[1].c_str(); + url.hostname = m_strings[2].c_str(); + url.filename = m_strings[3].c_str(); + url.port = url2.GetPort(); + url.options = m_strings[4].c_str(); + url.username = m_strings[5].c_str(); + url.password = m_strings[6].c_str(); + url.redacted = m_strings[7].c_str(); + url.sharename = m_strings[8].c_str(); + } + + VFSURL url; + protected: + std::vector<std::string> m_strings; +}; + +std::unique_ptr<CVFSEntry> CVFSEntry::FromExtension(AddonProps props, + const cp_extension_t* ext) +{ + std::string protocols = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@protocols"); + std::string extensions = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@extensions"); + bool files = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@files") == "true"; + bool directories = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@directories") == "true"; + bool filedirectories = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@filedirectories") == "true"; + + return std::unique_ptr<CVFSEntry>(new CVFSEntry(std::move(props), + protocols, + extensions, + files, directories, + filedirectories)); +} + + +CVFSEntry::CVFSEntry(AddonProps props, + const std::string& protocols, + const std::string& extensions, + bool files, bool directories, bool filedirectories) + : CAddonDll(std::move(props)), + m_protocols(protocols), + m_extensions(extensions), + m_files(files), + m_directories(directories), + m_filedirectories(filedirectories) +{ +} + +bool CVFSEntry::Create() +{ + return CAddonDll::Create(&m_struct, &m_info) == ADDON_STATUS_OK; +} + +void* CVFSEntry::Open(const CURL& url) +{ + if (!Initialized()) + return NULL; + + CVFSURLWrapper url2(url); + return m_struct.Open(&url2.url); +} + +void* CVFSEntry::OpenForWrite(const CURL& url, bool bOverWrite) +{ + if (!Initialized()) + return NULL; + + CVFSURLWrapper url2(url); + return m_struct.OpenForWrite(&url2.url, bOverWrite); +} + +bool CVFSEntry::Exists(const CURL& url) +{ + if (!Initialized()) + return false; + + CVFSURLWrapper url2(url); + return m_struct.Exists(&url2.url); +} + +int CVFSEntry::Stat(const CURL& url, struct __stat64* buffer) +{ + if (!Initialized()) + return -1; + + CVFSURLWrapper url2(url); + return m_struct.Stat(&url2.url, buffer); +} + +ssize_t CVFSEntry::Read(void* ctx, void* lpBuf, size_t uiBufSize) +{ + if (!Initialized()) + return 0; + + return m_struct.Read(ctx, lpBuf, uiBufSize); +} + +ssize_t CVFSEntry::Write(void* ctx, void* lpBuf, size_t uiBufSize) +{ + if (!Initialized()) + return 0; + + return m_struct.Write(ctx, lpBuf, uiBufSize); +} + +int64_t CVFSEntry::Seek(void* ctx, int64_t position, int whence) +{ + if (!Initialized()) + return 0; + + return m_struct.Seek(ctx, position, whence); +} + +int CVFSEntry::Truncate(void* ctx, int64_t size) +{ + if (!Initialized()) + return 0; + + return m_struct.Truncate(ctx, size); +} + +void CVFSEntry::Close(void* ctx) +{ + if (!Initialized()) + return; + + m_struct.Close(ctx); +} + +int64_t CVFSEntry::GetPosition(void* ctx) +{ + if (!Initialized()) + return 0; + + return m_struct.GetPosition(ctx); +} + +int CVFSEntry::GetChunkSize(void* ctx) +{ + if (!Initialized()) + return 0; + + return m_struct.GetChunkSize(ctx); +} + +int64_t CVFSEntry::GetLength(void* ctx) +{ + if (!Initialized()) + return 0; + + return m_struct.GetLength(ctx); +} + +int CVFSEntry::IoControl(void* ctx, XFILE::EIoControl request, void* param) +{ + if (!Initialized()) + return -1; + + return m_struct.IoControl(ctx, request, param); +} + +bool CVFSEntry::Delete(const CURL& url) +{ + if (!Initialized()) + return false; + + CVFSURLWrapper url2(url); + return m_struct.Delete(&url2.url); +} + +bool CVFSEntry::Rename(const CURL& url, const CURL& url2) +{ + if (!Initialized()) + return false; + + CVFSURLWrapper url3(url); + CVFSURLWrapper url4(url2); + return m_struct.Rename(&url3.url, &url4.url); +} + +void CVFSEntry::ClearOutIdle() +{ + if (!Initialized()) + return; + + m_struct.ClearOutIdle(); +} + +void CVFSEntry::DisconnectAll() +{ + if (!Initialized()) + return; + + m_struct.DisconnectAll(); +} + +bool CVFSEntry::DirectoryExists(const CURL& url) +{ + if (!Initialized()) + return false; + + CVFSURLWrapper url2(url); + return m_struct.DirectoryExists(&url2.url); +} + +bool CVFSEntry::RemoveDirectory(const CURL& url) +{ + if (!Initialized()) + return false; + + CVFSURLWrapper url2(url); + return m_struct.RemoveDirectory(&url2.url); +} + +bool CVFSEntry::CreateDirectory(const CURL& url) +{ + if (!Initialized()) + return false; + + CVFSURLWrapper url2(url); + return m_struct.CreateDirectory(&url2.url); +} + +static void VFSDirEntriesToCFileItemList(int num_entries, + VFSDirEntry* entries, + CFileItemList& items) +{ + for (int i=0;i<num_entries;++i) + { + CFileItemPtr item(new CFileItem()); + item->SetLabel(entries[i].label); + item->SetPath(entries[i].path); + item->m_dwSize = entries[i].size; + item->m_dateTime = entries[i].mtime; + item->m_bIsFolder = entries[i].folder; + if (entries[i].title) + item->m_strTitle = entries[i].title; + for (int j=0;j<entries[i].num_props;++j) + { + if (strcasecmp(entries[i].properties[j].name, "propmisusepreformatted") == 0) + { + if (strcasecmp(entries[i].properties[j].name, "true") == 0) + item->SetLabelPreformated(true); + else + item->SetLabelPreformated(false); + } else + item->SetProperty(entries[i].properties[j].name, + entries[i].properties[j].val); + } + items.Add(item); + } +} + +bool CVFSEntry::GetDirectory(const CURL& url, CFileItemList& items, + void* ctx) +{ + if (!Initialized() && !Create()) + return false; + + VFSCallbacks callbacks; + callbacks.ctx = ctx; + callbacks.GetKeyboardInput = CVFSEntryIDirectoryWrapper::DoGetKeyboardInput; + callbacks.SetErrorDialog = CVFSEntryIDirectoryWrapper::DoSetErrorDialog; + callbacks.RequireAuthentication = CVFSEntryIDirectoryWrapper::DoRequireAuthentication; + + VFSDirEntry* entries; + int num_entries; + CVFSURLWrapper url2(url); + void* ctx2 = m_struct.GetDirectory(&url2.url, &entries, &num_entries, &callbacks); + if (ctx2) + { + VFSDirEntriesToCFileItemList(num_entries, entries, items); + m_struct.FreeDirectory(ctx2); + + return true; + } + + return false; +} + +bool CVFSEntry::ContainsFiles(const CURL& url, CFileItemList& items) +{ + if (!Initialized() && !Create()) + return false; + + VFSDirEntry* entries; + int num_entries; + + CVFSURLWrapper url2(url); + char rootpath[1024]; + rootpath[0] = 0; + void* ctx = m_struct.ContainsFiles(&url2.url, &entries, &num_entries, rootpath); + if (!ctx) + return false; + + VFSDirEntriesToCFileItemList(num_entries, entries, items); + m_struct.FreeDirectory(ctx); + if (strlen(rootpath)) + items.SetPath(rootpath); + + return true; +} + +CVFSEntryIFileWrapper::CVFSEntryIFileWrapper(VFSEntryPtr ptr) : + m_context(NULL), m_addon(ptr) +{ +} + +CVFSEntryIFileWrapper::~CVFSEntryIFileWrapper() +{ + Close(); +} + +bool CVFSEntryIFileWrapper::Open(const CURL& url) +{ + m_context = m_addon->Open(url); + return m_context != NULL; +} + +bool CVFSEntryIFileWrapper::OpenForWrite(const CURL& url, bool bOverWrite) +{ + m_context = m_addon->OpenForWrite(url, bOverWrite); + return m_context != NULL; +} + +bool CVFSEntryIFileWrapper::Exists(const CURL& url) +{ + return m_addon->Exists(url); +} + +int CVFSEntryIFileWrapper::Stat(const CURL& url, struct __stat64* buffer) +{ + return m_addon->Stat(url, buffer); +} + +int CVFSEntryIFileWrapper::Truncate(int64_t size) +{ + return m_addon->Truncate(m_context, size); +} + +ssize_t CVFSEntryIFileWrapper::Read(void* lpBuf, size_t uiBufSize) +{ + if (!m_context) + return 0; + + return m_addon->Read(m_context, lpBuf, uiBufSize); +} + +ssize_t CVFSEntryIFileWrapper::Write(void* lpBuf, size_t uiBufSize) +{ + if (!m_context) + return 0; + + return m_addon->Write(m_context, lpBuf, uiBufSize); +} + +int64_t CVFSEntryIFileWrapper::Seek(int64_t iFilePosition, int iWhence) +{ + if (!m_context) + return 0; + + return m_addon->Seek(m_context, iFilePosition, iWhence); +} + +void CVFSEntryIFileWrapper::Close() +{ + if (m_context) + { + m_addon->Close(m_context); + m_context = NULL; + } +} + +int64_t CVFSEntryIFileWrapper::GetPosition() +{ + if (!m_context) + return 0; + + return m_addon->GetPosition(m_context); +} + +int CVFSEntryIFileWrapper::GetChunkSize() +{ + if (!m_context) + return 0; + + return m_addon->GetChunkSize(m_context); +} + +int64_t CVFSEntryIFileWrapper::GetLength() +{ + if (!m_context) + return 0; + + return m_addon->GetLength(m_context); +} + +int CVFSEntryIFileWrapper::IoControl(XFILE::EIoControl request, void* param) +{ + if (!m_context) + return 0; + + return m_addon->IoControl(m_context, request, param); +} + +bool CVFSEntryIFileWrapper::Delete(const CURL& url) +{ + return m_addon->Delete(url); +} + +bool CVFSEntryIFileWrapper::Rename(const CURL& url, const CURL& url2) +{ + return m_addon->Rename(url, url2); +} + +CVFSEntryIDirectoryWrapper::CVFSEntryIDirectoryWrapper(VFSEntryPtr ptr) : + m_addon(ptr) +{ +} + +bool CVFSEntryIDirectoryWrapper::Exists(const CURL& url) +{ + return m_addon->DirectoryExists(url); +} + +bool CVFSEntryIDirectoryWrapper::Remove(const CURL& url) +{ + return m_addon->RemoveDirectory(url); +} + +bool CVFSEntryIDirectoryWrapper::Create(const CURL& url) +{ + return m_addon->CreateDirectory(url); +} + +bool CVFSEntryIDirectoryWrapper::GetDirectory(const CURL& url, + CFileItemList& items) +{ + return m_addon->GetDirectory(url, items, this); +} + +bool CVFSEntryIDirectoryWrapper::DoGetKeyboardInput(void* ctx, + const char* heading, + char** input) +{ + return ((CVFSEntryIDirectoryWrapper*)ctx)->GetKeyboardInput2(heading, input); +} + +bool CVFSEntryIDirectoryWrapper::GetKeyboardInput2(const char* heading, + char** input) +{ + std::string inp; + bool result; + if ((result=GetKeyboardInput(CVariant(std::string(heading)), inp))) + *input = strdup(inp.c_str()); + + return result; +} + +void CVFSEntryIDirectoryWrapper::DoSetErrorDialog(void* ctx, const char* heading, + const char* line1, + const char* line2, + const char* line3) +{ + ((CVFSEntryIDirectoryWrapper*)ctx)->SetErrorDialog2(heading, line1, + line2, line3); +} + +void CVFSEntryIDirectoryWrapper::SetErrorDialog2(const char* heading, + const char* line1, + const char* line2, + const char* line3) +{ + CVariant l2=0, l3=0; + if (line2) + l2 = std::string(line2); + if (line3) + l3 = std::string(line3); + if (m_flags & XFILE::DIR_FLAG_ALLOW_PROMPT) + SetErrorDialog(CVariant(std::string(heading)), + CVariant(std::string(line1)), l2, l3); +} + +void CVFSEntryIDirectoryWrapper::DoRequireAuthentication(void* ctx, + const char* url) +{ + ((CVFSEntryIDirectoryWrapper*)ctx)->RequireAuthentication2(CURL(url)); +} + +void CVFSEntryIDirectoryWrapper::RequireAuthentication2(const CURL& url) +{ + if (m_flags & XFILE::DIR_FLAG_ALLOW_PROMPT) + RequireAuthentication(url); +} + +} /*namespace ADDON*/ + diff --git a/xbmc/addons/VFSEntry.h b/xbmc/addons/VFSEntry.h new file mode 100644 index 0000000000..3b486b7aca --- /dev/null +++ b/xbmc/addons/VFSEntry.h @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2013 Arne Morten Kvarving + * + * 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "AddonDll.h" +#include "addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_types.h" +#include "filesystem/IFile.h" +#include "filesystem/IDirectory.h" +#include "filesystem/IFileDirectory.h" + +namespace ADDON +{ + //! \brief A virtual filesystem entry add-on. + class CVFSEntry : public CAddonDll + { + public: + static std::unique_ptr<CVFSEntry> FromExtension(AddonProps props, + const cp_extension_t* ext); + + //! \brief Construct from add-on properties. + //! \param props General addon properties + //! \param protocols Protocols associated with add-on + //! \param extensions File extensions associated with add-on (filedirectories) + //! \param files If true, add-on provides files + //! \param directories If true, add-on provides directory listings + //! \param filedirectories If true, add-on provides filedirectories + explicit CVFSEntry(AddonProps props, + const std::string& protocols, + const std::string& extensions, + bool files, bool directories, bool filedirectories); + + //! \brief Empty destructor. + virtual ~CVFSEntry() {} + + // Things that MUST be supplied by the child classes + bool Create(); + void* Open(const CURL& url); + void* OpenForWrite(const CURL& url, bool bOverWrite); + bool Exists(const CURL& url); + int Stat(const CURL& url, struct __stat64* buffer); + ssize_t Read(void* ctx, void* lpBuf, size_t uiBufSize); + ssize_t Write(void* ctx, void* lpBuf, size_t uiBufSize); + int64_t Seek(void* ctx, int64_t iFilePosition, int iWhence = SEEK_SET); + int Truncate(void* ctx, int64_t size); + void Close(void* ctx); + int64_t GetPosition(void* ctx); + int64_t GetLength(void* ctx); + int GetChunkSize(void* ctx); + int IoControl(void* ctx, XFILE::EIoControl request, void* param); + bool Delete(const CURL& url); + bool Rename(const CURL& url, const CURL& url2); + + bool GetDirectory(const CURL& url, CFileItemList& items, void* ctx); + bool DirectoryExists(const CURL& url); + bool RemoveDirectory(const CURL& url); + bool CreateDirectory(const CURL& url); + void ClearOutIdle(); + void DisconnectAll(); + + bool ContainsFiles(const CURL& path, CFileItemList& items); + + const std::string& GetProtocols() const { return m_protocols; } + const std::string& GetExtensions() const { return m_extensions; } + bool HasFiles() const { return m_files; } + bool HasDirectories() const { return m_directories; } + bool HasFileDirectories() const { return m_filedirectories; } + protected: + std::string m_protocols; //!< Protocols for VFS entry. + std::string m_extensions; //!< Extensions for VFS entry. + bool m_files; //!< Vfs entry can read files. + bool m_directories; //!< VFS entry can list directories. + bool m_filedirectories; //!< VFS entry contains file directories. + KodiToAddonFuncTable_VFSEntry m_struct; //!< VFS callback table + VFS_PROPS m_info; //!< (Dummy) properties + }; + + typedef std::shared_ptr<CVFSEntry> VFSEntryPtr; //!< Convenience typedef. + + //! \brief Wrapper equpping a CVFSEntry with an IFile interface. + //! \details Needed as CVFSEntry implements several VFS interfaces + //! with overlapping methods. + class CVFSEntryIFileWrapper : public XFILE::IFile + { + public: + //! \brief The constructor initializes the reference to the wrapped CVFSEntry. + //! \param ptr The CVFSEntry to wrap. + CVFSEntryIFileWrapper(VFSEntryPtr ptr); + + //! \brief Empty destructor. + virtual ~CVFSEntryIFileWrapper(); + + //! \brief Open a file. + //! \param[in] url URL to open. + //! \returns True if file was opened, false otherwise. + virtual bool Open(const CURL& url); + + //! \brief Open a file for writing. + //! \param[in] url URL to open. + //! \param[in] bOverWrite If true, overwrite an existing file. + //! \returns True if file was opened, false otherwise. + virtual bool OpenForWrite(const CURL& url, bool bOverWrite); + + //! \brief Check for file existence. + //! \param[in] url URL of file. + virtual bool Exists(const CURL& url); + + //! \brief Stat a file. + //! \param[in] url URL of file. + //! \param[out] buffer The stat info. + //! \details Returns 0 on success, non-zero otherwise (see fstat() return values). + virtual int Stat(const CURL& url, struct __stat64* buffer); + + //! \brief Read data from file: + //! \param lpBuf Buffer to read data into. + //! \param[in] uiBufSize Number of bytes to read. + //! \returns Number of bytes read. + virtual ssize_t Read(void* lpBuf, size_t uiBufSize); + + //! \brief Write data to file. + //! \param[in] lpBuf Data to write. + //! \param[in] uiBufSize Number of bytes to write. + //! \returns Number of bytes written. + virtual ssize_t Write(void* lpBuf, size_t uiBufSize); + + //! \brief Seek in file. + //! \param[in] iFilePosition Position to seek to. + //! \param[in] whence Origin for position. + //! \returns New file position. + virtual int64_t Seek(int64_t iFilePosition, int iWhence = SEEK_SET); + + //! \brief Truncate a file. + //! \param[in] size Size of new file. + virtual int Truncate(int64_t size); + + //! \brief Close file. + virtual void Close(); + + //! \brief Obtain current file position. + virtual int64_t GetPosition(); + + //! \brief Obtain file size. + virtual int64_t GetLength(); + + //! \brief Obtain chunksize of file. + virtual int GetChunkSize(); + + //! \brief Perform I/O controls for file. + virtual int IoControl(XFILE::EIoControl request, void* param); + + //! \brief Delete a file. + //! \param[in] url URL of file to delete. + virtual bool Delete(const CURL& url); + + //! \brief Rename a file. + //! \param[in] url URL of file to rename. + //! \param[in] url2 New URL of file. + virtual bool Rename(const CURL& url, const CURL& url2); + protected: + void* m_context; //!< Opaque add-on specific context for opened file. + VFSEntryPtr m_addon; //!< Pointer to wrapped CVFSEntry. + }; + + //! \brief Wrapper equpping a CVFSEntry with an IDirectory interface. + //! \details Needed as CVFSEntry implements several VFS interfaces + //! with overlapping methods. + class CVFSEntryIDirectoryWrapper : public XFILE::IDirectory + { + public: + //! \brief The constructor initializes the reference to the wrapped CVFSEntry. + //! \param ptr The CVFSEntry to wrap. + CVFSEntryIDirectoryWrapper(VFSEntryPtr ptr); + + //! \brief Empty destructor. + virtual ~CVFSEntryIDirectoryWrapper() {} + + //! \brief Return directory listing. + //! \param[in] url URL to file to list. + //! \param items List of items in file. + //! \return True if listing succeeded, false otherwise. + virtual bool GetDirectory(const CURL& strPath, CFileItemList& items); + + //! \brief Check if directory exists. + //! \param[in] url URL to check. + virtual bool Exists(const CURL& strPath); + + //! \brief Delete directory. + //! \param[in] url URL to delete. + virtual bool Remove(const CURL& strPath); + + //! \brief Create directory. + //! \param[in] url URL to delete. + virtual bool Create(const CURL& strPath); + + //! \brief Static helper for doing a keyboard callback. + static bool DoGetKeyboardInput(void* context, const char* heading, + char** input); + + //! \brief Get keyboard input. + bool GetKeyboardInput2(const char* heading, char** input); + + //! \brief Static helper for displaying an error dialog. + static void DoSetErrorDialog(void* ctx, const char* heading, + const char* line1, const char* line2, + const char* line3); + + //! \brief Show an error dialog. + void SetErrorDialog2(const char* heading, const char* line1, + const char* line2, const char* line3); + + //! \brief Static helper for requiring authentication. + static void DoRequireAuthentication(void* ctx, const char* url); + + //! \brief Require authentication. + void RequireAuthentication2(const CURL& url); + protected: + VFSEntryPtr m_addon; //!< Pointer to wrapper CVFSEntry. + }; + + //! \brief Wrapper equpping a CVFSEntry with an IFileDirectory interface. + //! \details Needed as CVFSEntry implements several VFS interfaces + //! with overlapping methods. + class CVFSEntryIFileDirectoryWrapper : public XFILE::IFileDirectory, + public CVFSEntryIDirectoryWrapper + { + public: + //! \brief The constructor initializes the reference to the wrapped CVFSEntry. + //! \param ptr The CVFSEntry to wrap. + CVFSEntryIFileDirectoryWrapper(VFSEntryPtr ptr) : CVFSEntryIDirectoryWrapper(ptr) {} + + //! \brief Empty destructor. + virtual ~CVFSEntryIFileDirectoryWrapper() {} + + //! \brief Check if the given file should be treated as a directory. + //! \param[in] URL URL for file to probe. + bool ContainsFiles(const CURL& url) + { + return m_addon->ContainsFiles(url, m_items); + } + + //! \brief Return directory listing. + //! \param[in] url URL to file to list. + //! \param items List of items in file. + //! \return True if listing succeeded, false otherwise. + bool GetDirectory(const CURL& url, CFileItemList& items) + { + return CVFSEntryIDirectoryWrapper::GetDirectory(url, items); + } + + //! \brief Check if directory exists. + //! \param[in] url URL to check. + bool Exists(const CURL& url) + { + return CVFSEntryIDirectoryWrapper::Exists(url); + } + + //! \brief Delete directory. + //! \param[in] url URL to delete. + bool Remove(const CURL& url) + { + return CVFSEntryIDirectoryWrapper::Remove(url); + } + + //! \brief Create directory. + //! \param[in] url URL to delete. + bool Create(const CURL& url) + { + return CVFSEntryIDirectoryWrapper::Create(url); + } + + CFileItemList m_items; //!< Internal list of items, used for cache purposes. + }; + +} /*namespace ADDON*/ diff --git a/xbmc/addons/addon-bindings.mk b/xbmc/addons/addon-bindings.mk index 0144a5b2a9..6bbfe69dbe 100644 --- a/xbmc/addons/addon-bindings.mk +++ b/xbmc/addons/addon-bindings.mk @@ -20,6 +20,7 @@ BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_types.h BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_dll.h BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_types.h BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_utils.hpp +BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_dll.h BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_types.h BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_utils.hpp BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_dll.h diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_dll.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_dll.h new file mode 100644 index 0000000000..0d7a13538d --- /dev/null +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_dll.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2013 Arne Morten Kvarving + * + * 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include <stdint.h> +#include "xbmc_addon_dll.h" +#include "kodi_vfs_types.h" + +extern "C" +{ + //! \copydoc KodiToAddonFuncTable_VFSEntry::Open + void* Open(VFSURL* url); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::OpenForWrite + void* OpenForWrite(VFSURL* url, bool bOverWrite); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::Read + ssize_t Read(void* context, void* buffer, size_t size); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::Write + ssize_t Write(void* context, const void* buffer, size_t size); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::Seek + int64_t Seek(void* context, int64_t position, int whence); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::Truncate + int Truncate(void* context, int64_t size); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::GetLength + int64_t GetLength(void* context); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::GetPosition + int64_t GetPosition(void* context); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::GetChunkSize + int GetChunkSize(void* context); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::IoControl + int IoControl(void* context, XFILE::EIoControl request, void* param); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::Stat + int Stat(VFSURL* url, struct __stat64* buffer); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::Close + bool Close(void* context); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::Exists + bool Exists(VFSURL* url); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::ContainsFiles + void* ContainsFiles(VFSURL* url, VFSDirEntry** entries, int* num_entries, + char* rootpath); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::ClearOutIdle + void ClearOutIdle(); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::DisconnectAll + void DisconnectAll(); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::DirectoryExists + bool DirectoryExists(VFSURL* url); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::RemoveDirectory + bool RemoveDirectory(VFSURL* url); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::CreateDirectory + bool CreateDirectory(VFSURL* url); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::GetDirectory + void* GetDirectory(VFSURL* url, VFSDirEntry** entries, int* num_entries, + VFSCallbacks* callbacks); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::FreeDirectory + void FreeDirectory(void* ctx); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::Delete + bool Delete(VFSURL* url); + + //! \copydoc KodiToAddonFuncTable_VFSEntry::Rename + bool Rename(VFSURL* url, VFSURL* url2); + + //! \brief Function to export the above structure to Kodi + void __declspec(dllexport) get_addon(void* ptr) + { + KodiToAddonFuncTable_VFSEntry* vfs = static_cast<KodiToAddonFuncTable_VFSEntry*>(ptr); + vfs->Open = Open; + vfs->OpenForWrite = OpenForWrite; + vfs->Read = Read; + vfs->Write = Write; + vfs->Seek = Seek; + vfs->GetLength = GetLength; + vfs->GetPosition = GetPosition; + vfs->IoControl = IoControl; + vfs->Stat = Stat; + vfs->Close = Close; + vfs->Exists = Exists; + vfs->ClearOutIdle = ClearOutIdle; + vfs->DisconnectAll = DisconnectAll; + vfs->DirectoryExists = DirectoryExists; + vfs->GetDirectory = GetDirectory; + vfs->FreeDirectory = FreeDirectory; + vfs->Truncate = Truncate; + vfs->Delete = Delete; + vfs->Rename = Rename; + vfs->RemoveDirectory = RemoveDirectory; + vfs->CreateDirectory = CreateDirectory; + vfs->ContainsFiles = ContainsFiles; + vfs->GetChunkSize = GetChunkSize; + }; +}; diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_types.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_types.h index b62c7b0c7f..b315ed2eb6 100644 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_types.h +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_types.h @@ -18,15 +18,241 @@ */ #pragma once +#ifdef TARGET_WINDOWS +#include <windows.h> +#else +#ifndef __cdecl +#define __cdecl +#endif +#ifndef __declspec +#define __declspec(X) +#endif +#endif + #include <stdint.h> +#include "xbmc_addon_types.h" +#ifdef BUILD_KODI_ADDON +#include "IFileTypes.h" +#else +#include "filesystem/IFileTypes.h" +#include "PlatformDefs.h" +#endif extern "C" { + struct VFS_PROPS + { + int dummy; + }; + + struct VFSProperty + { + char* name; + char* val; + }; + struct VFSDirEntry { char* label; //!< item label + char* title; //!< item title char* path; //!< item path + int num_props; //!< Number of properties attached to item + VFSProperty* properties; //!< Properties + FILETIME mtime; //!< Mtime for file represented by item bool folder; //!< Item is a folder uint64_t size; //!< Size of file represented by item }; + + struct VFSURL + { + const char* url; + const char* domain; + const char* hostname; + const char* filename; + unsigned int port; + const char* options; + const char* username; + const char* password; + const char* redacted; + const char* sharename; + }; + + struct VFSCallbacks + { + //! \brief Require keyboard input + //! \param heading The heading of the keyboard dialog + //! \param input A pointer to the resulting string. Must be free'd by caller. + //! \return True if input was received, false otherwise + bool (__cdecl* GetKeyboardInput)(void* ctx, const char* heading, char** input); + + //! \brief Display an error dialog + //! \param heading The heading of the error dialog + //! \param line1 The first line of the error dialog + //! \param line2 The second line of the error dialog. Can be NULL + //! \param line3 The third line of the error dialog. Can be NULL + void (__cdecl* SetErrorDialog)(void* ctx, const char* heading, const char* line1, const char* line2, const char* line3); + + //! \brief Prompt the user for authentication of a URL + //! \param url The URL + void (__cdecl* RequireAuthentication)(void* ctx, const char* url); + + //! \brief The context to be passed to the callbacks + void* ctx; + }; + + typedef struct KodiToAddonFuncTable_VFSEntry + { + //! \brief Open a file for input + //! \param url The URL of the file + //! \return Context for the opened file + //! \sa IFile::Open + void* (__cdecl* Open) (VFSURL* url); + + //! \brief Open a file for output + //! \param url The URL of the file + //! \param bOverwrite Whether or not to overwrite an existing file + //! \return Context for the opened file + //! \sa IFile::OpenForWrite + void* (__cdecl* OpenForWrite) (VFSURL* url, bool bOverWrite); + + //! \brief Read from a file + //! \param context The context of the file + //! \param buffer The buffer to read data into + //! \param uiBufSize Number of bytes to read + //! \return Number of bytes read + //! \sa IFile::Read + ssize_t (__cdecl* Read) (void* context, void* buffer, size_t uiBufSize); + + //! \brief Write to a file + //! \param context The context of the file + //! \param buffer The buffer to read data from + //! \param uiBufSize Number of bytes to write + //! \return Number of bytes written + //! \sa IFile::Write + ssize_t (__cdecl* Write) (void* context, const void* buffer, size_t uiBufSize); + + //! \brief Seek in a file + //! \param context The context of the file + //! \param position The position to seek to + //! \param whence Position in file 'position' is relative to (SEEK_CUR, SEEK_SET, SEEK_END) + //! \return Offset in file after seek + //! \sa IFile::Seek + int64_t (__cdecl* Seek) (void* context, int64_t position, int whence); + + //! \brief Truncate a file + //! \param context The context of the file + //! \param size The size to truncate the file to + //! \return 0 on success, -1 on error + //! \sa IFile::Truncate + int (__cdecl* Truncate) (void* context, int64_t size); + + //! \brief Get total size of a file + //! \param context The context of the file + //! \return Total file size + //! \sa IFile::GetLength + int64_t (__cdecl* GetLength) (void* context); + + //! \brief Get current position in a file + //! \param context The context of the file + //! \return Current position + //! \sa IFile::GetPosition + int64_t (__cdecl* GetPosition) (void* context); + + //! \brief Get chunk size of a file + //! \param context The context of the file + //! \return Chunk size + //! \sa IFile::GetChunkSize() + int (__cdecl* GetChunkSize)(void* context); + + //! \brief Perform an IO-control on the file + //! \param context The context of the file + //! \param request The requested IO-control + //! \param param Parameter attached to the IO-control + //! \return -1 on error, >= 0 on success + //! \sa IFile::IoControl + int (__cdecl* IoControl) (void* context, XFILE::EIoControl request, void* param); + + //! \brief Stat a file + //! \param url The URL of the file + //! \param buffer The buffer to store results in + //! \return -1 on error, 0 otherwise + //! \sa IFile::Stat + int (__cdecl* Stat) (VFSURL* url, struct __stat64* buffer); + //! \brief Close a file + //! \param context The context of the file + //! \return True on success, false on failure + //! \sa IFile::Close + + bool (__cdecl* Close) (void* context); + + //! \brief Check for file existence + //! \param url The URL of the file + //! \return True if file exists, false otherwise + //! \sa IFile::Exists + bool (__cdecl* Exists) (VFSURL* url); + + //! \brief Clear out any idle connections + void (__cdecl* ClearOutIdle) (); + + //! \brief Disconnect all connections + void (__cdecl* DisconnectAll) (); + + //! \brief Delete a file + //! \param url The URL of the file + //! \return True if deletion was successful, false otherwise + //! \sa IFile::Delete + bool (__cdecl* Delete) (VFSURL* url); + + //! \brief Rename a file + //! \param url The URL of the source file + //! \param url2 The URL of the destination file + //! \return True if deletion was successful, false otherwise + //! \sa IFile::Rename + bool (__cdecl* Rename) (VFSURL* url, VFSURL* url2); + + //! \brief Check for directory existence + //! \param url The URL of the file + //! \return True if directory exists, false otherwise + //! \sa IDirectory::Exists + bool (__cdecl* DirectoryExists) (VFSURL* url); + + //! \brief Remove a directory + //! \param url The URL of the directory + //! \return True if removal was successful, false otherwise + //! \sa IDirectory::Remove + bool (__cdecl* RemoveDirectory) (VFSURL* url); + + //! \brief Create a directory + //! \param url The URL of the file + //! \return True if creation was successful, false otherwise + //! \sa IDirectory::Create + bool (__cdecl* CreateDirectory) (VFSURL* url); + + //! \brief List a directory + //! \param url The URL of the directory + //! \param entries The entries in the directory + //! \param num_entries Number of entries in the directory + //! \param callbacks A callback structure + //! \return Context for the directory listing + //! \sa IDirectory::GetDirectory + void* (__cdecl* GetDirectory) (VFSURL* url, + VFSDirEntry** entries, + int* num_entries, + VFSCallbacks* callbacks); + + //! \brief Free up resources after listing a directory + void (__cdecl* FreeDirectory) (void* ctx); + + //! \brief Check if file should be presented as a directory (multiple streams) + //! \param url The URL of the file + //! \param entries The entries in the directory + //! \param num_entries Number of entries in the directory + //! \param rootpath Path to root directory if multiple entries + //! \return Context for the directory listing + //! \sa IFileDirectory::ContainsFiles, FreeDirectory + void* (__cdecl* ContainsFiles) (VFSURL* url, + VFSDirEntry** entries, + int* num_entries, + char* rootpath); + } KodiToAddonFuncTable_VFSEntry; } diff --git a/xbmc/filesystem/AddonsDirectory.cpp b/xbmc/filesystem/AddonsDirectory.cpp index 65efada472..94dfa65502 100644 --- a/xbmc/filesystem/AddonsDirectory.cpp +++ b/xbmc/filesystem/AddonsDirectory.cpp @@ -704,6 +704,8 @@ bool CAddonsDirectory::GetDirectory(const CURL& url, CFileItemList &items) type = ADDON_PVRDLL; else if (path.GetFileName() == "kodi.adsp") type = ADDON_ADSPDLL; + else if (path.GetFileName() == "kodi.vfs") + type = ADDON_VFS; else type = ADDON_UNKNOWN; diff --git a/xbmc/filesystem/DirectoryFactory.cpp b/xbmc/filesystem/DirectoryFactory.cpp index 47d172faeb..c63fa24575 100644 --- a/xbmc/filesystem/DirectoryFactory.cpp +++ b/xbmc/filesystem/DirectoryFactory.cpp @@ -95,6 +95,11 @@ #include "AndroidAppDirectory.h" #endif #include "ResourceDirectory.h" +#include "ServiceBroker.h" +#include "addons/VFSEntry.h" +#include "addons/BinaryAddonCache.h" + +using namespace ADDON; using namespace XFILE; @@ -196,6 +201,19 @@ IDirectory* CDirectoryFactory::Create(const CURL& url) #endif } + if (!url.GetProtocol().empty() && CServiceBroker::IsBinaryAddonCacheUp()) + { + VECADDONS addons; + ADDON::CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); + addonCache.GetAddons(addons, ADDON::ADDON_VFS); + for (size_t i=0;i<addons.size();++i) + { + VFSEntryPtr vfs(std::static_pointer_cast<CVFSEntry>(addons[i])); + if (vfs->HasDirectories() && vfs->GetProtocols().find(url.GetProtocol()) != std::string::npos) + return new CVFSEntryIDirectoryWrapper(vfs); + } + } + CLog::Log(LOGWARNING, "%s - %sunsupported protocol(%s) in %s", __FUNCTION__, networkAvailable ? "" : "Network down or ", url.GetProtocol().c_str(), url.GetRedacted().c_str() ); return NULL; } diff --git a/xbmc/filesystem/FileDirectoryFactory.cpp b/xbmc/filesystem/FileDirectoryFactory.cpp index a483d3dc60..626a9f6d12 100644 --- a/xbmc/filesystem/FileDirectoryFactory.cpp +++ b/xbmc/filesystem/FileDirectoryFactory.cpp @@ -44,8 +44,9 @@ #include "utils/StringUtils.h" #include "URL.h" #include "ServiceBroker.h" -#include "addons/BinaryAddonCache.h" #include "addons/AudioDecoder.h" +#include "addons/VFSEntry.h" +#include "addons/BinaryAddonCache.h" using namespace ADDON; using namespace XFILE; @@ -85,15 +86,46 @@ IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem, } } -#ifdef HAS_FILESYSTEM - + if (CServiceBroker::IsBinaryAddonCacheUp()) + { + VECADDONS vfs; + CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); + addonCache.GetAddons(vfs, ADDON_VFS); + for (size_t i=0;i<vfs.size();++i) + { + std::shared_ptr<CVFSEntry> dec(std::static_pointer_cast<CVFSEntry>(vfs[i])); + if (!strExtension.empty() && dec->HasFileDirectories() && + dec->GetExtensions().find(strExtension) != std::string::npos) + { + CVFSEntryIFileDirectoryWrapper* wrap = new CVFSEntryIFileDirectoryWrapper(dec); + if (wrap->ContainsFiles(url)) + { + if (wrap->m_items.Size() == 1) + { + // one STORED file - collapse it down + *pItem = *wrap->m_items[0]; + } + else + { // compressed or more than one file -> create a dir + pItem->SetPath(wrap->m_items.GetPath()); + return wrap; + } + } + else + pItem->m_bIsFolder = true; + + delete wrap; + return NULL; + } + } + } + if (pItem->IsRSS()) return new CRSSDirectory(); if (pItem->IsDiscImage()) return new CUDFDirectory(); -#endif #if defined(TARGET_ANDROID) if (url.IsFileType("apk")) { diff --git a/xbmc/filesystem/FileFactory.cpp b/xbmc/filesystem/FileFactory.cpp index e9d8740779..dc8ea151d3 100644 --- a/xbmc/filesystem/FileFactory.cpp +++ b/xbmc/filesystem/FileFactory.cpp @@ -76,7 +76,12 @@ #include "URL.h" #include "utils/log.h" #include "network/WakeOnAccess.h" +#include "utils/StringUtils.h" +#include "ServiceBroker.h" +#include "addons/VFSEntry.h" +#include "addons/BinaryAddonCache.h" +using namespace ADDON; using namespace XFILE; CFileFactory::CFileFactory() @@ -98,6 +103,22 @@ IFile* CFileFactory::CreateLoader(const CURL& url) if (!CWakeOnAccess::GetInstance().WakeUpHost(url)) return NULL; + std::string strProtocol = url.GetProtocol(); + StringUtils::ToLower(strProtocol); + + if (!strProtocol.empty() && CServiceBroker::IsBinaryAddonCacheUp()) + { + VECADDONS addons; + ADDON::CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); + addonCache.GetAddons(addons, ADDON::ADDON_VFS); + for (size_t i=0;i<addons.size();++i) + { + VFSEntryPtr vfs(std::static_pointer_cast<CVFSEntry>(addons[i])); + if (vfs->HasFiles() && vfs->GetProtocols().find(strProtocol) != std::string::npos) + return new CVFSEntryIFileWrapper(vfs); + } + } + #if defined(TARGET_ANDROID) if (url.IsProtocol("apk")) return new CAPKFile(); #endif |