1 /*
2  *  Copyright (C) 2013 Arne Morten Kvarving
3  *
4  *  SPDX-License-Identifier: GPL-2.0-or-later
5  *  See LICENSES/README.md for more information.
6  */
7 
8 #include "VFSEntry.h"
9 
10 #include "ServiceBroker.h"
11 #include "URL.h"
12 #include "addons/interfaces/Filesystem.h"
13 #include "network/ZeroconfBrowser.h"
14 #include "utils/StringUtils.h"
15 #include "utils/log.h"
16 
17 #include <utility>
18 
19 #if defined(TARGET_WINDOWS)
20 #ifndef S_IFLNK
21 #define S_IFLNK 0120000
22 #endif
23 #ifndef S_IFBLK
24 #define S_IFBLK 0
25 #endif
26 #ifndef S_IFSOCK
27 #define S_IFSOCK 0
28 #endif
29 #ifndef S_IFREG
30 #define S_IFREG _S_IFREG
31 #endif
32 #ifndef S_IFCHR
33 #define S_IFCHR _S_IFCHR
34 #endif
35 #ifndef S_IFDIR
36 #define S_IFDIR _S_IFDIR
37 #endif
38 #ifndef S_IFIFO
39 #define S_IFIFO _S_IFIFO
40 #endif
41 #endif
42 
43 namespace ADDON
44 {
45 
~CVFSAddonCache()46 CVFSAddonCache::~CVFSAddonCache()
47 {
48   Deinit();
49 }
50 
Init()51 void CVFSAddonCache::Init()
52 {
53   CServiceBroker::GetAddonMgr().Events().Subscribe(this, &CVFSAddonCache::OnEvent);
54 
55   // Load all available VFS addons during Kodi start
56   std::vector<AddonInfoPtr> addonInfos;
57   CServiceBroker::GetAddonMgr().GetAddonInfos(addonInfos, true, ADDON_VFS);
58 
59   CSingleLock lock(m_critSection);
60   for (const auto& addonInfo : addonInfos)
61   {
62     VFSEntryPtr vfs = std::make_shared<CVFSEntry>(addonInfo);
63     vfs->Addon()->RegisterInformer(this);
64 
65     m_addonsInstances.emplace_back(vfs);
66 
67     if (!vfs->GetZeroconfType().empty())
68       CZeroconfBrowser::GetInstance()->AddServiceType(vfs->GetZeroconfType());
69   }
70 }
71 
Deinit()72 void CVFSAddonCache::Deinit()
73 {
74   CServiceBroker::GetAddonMgr().Events().Unsubscribe(this);
75 }
76 
GetAddonInstances()77 const std::vector<VFSEntryPtr> CVFSAddonCache::GetAddonInstances()
78 {
79   CSingleLock lock(m_critSection);
80   return m_addonsInstances;
81 }
82 
GetAddonInstance(const std::string & strId)83 VFSEntryPtr CVFSAddonCache::GetAddonInstance(const std::string& strId)
84 {
85   VFSEntryPtr addon;
86 
87   CSingleLock lock(m_critSection);
88 
89   const auto& itAddon = std::find_if(m_addonsInstances.begin(), m_addonsInstances.end(),
90     [&strId](const VFSEntryPtr& addon)
91     {
92       return addon->ID() == strId;
93     });
94 
95   if (itAddon != m_addonsInstances.end())
96     addon = *itAddon;
97 
98   return addon;
99 }
100 
OnEvent(const AddonEvent & event)101 void CVFSAddonCache::OnEvent(const AddonEvent& event)
102 {
103   if (typeid(event) == typeid(AddonEvents::Disabled))
104   {
105     for (const auto& vfs : m_addonsInstances)
106     {
107       if (vfs->ID() == event.id && !vfs->GetZeroconfType().empty())
108         CZeroconfBrowser::GetInstance()->RemoveServiceType(vfs->GetZeroconfType());
109     }
110   }
111 
112   if (typeid(event) == typeid(AddonEvents::Enabled) ||
113       typeid(event) == typeid(AddonEvents::Disabled) ||
114       typeid(event) == typeid(AddonEvents::ReInstalled))
115   {
116     if (CServiceBroker::GetAddonMgr().HasType(event.id, ADDON_VFS))
117       Update(event.id);
118   }
119   else if (typeid(event) == typeid(AddonEvents::UnInstalled))
120   {
121     Update(event.id);
122   }
123 }
124 
IsInUse(const std::string & id)125 bool CVFSAddonCache::IsInUse(const std::string& id)
126 {
127   CSingleLock lock(m_critSection);
128 
129   const auto& itAddon = std::find_if(m_addonsInstances.begin(), m_addonsInstances.end(),
130                                      [&id](const VFSEntryPtr& addon) { return addon->ID() == id; });
131   if (itAddon != m_addonsInstances.end() && (*itAddon).use_count() > 1)
132     return true;
133   return false;
134 }
135 
Update(const std::string & id)136 void CVFSAddonCache::Update(const std::string& id)
137 {
138   std::vector<VFSEntryPtr> addonmap;
139 
140   // Stop used instance if present, otherwise the new becomes created on already created addon base one.
141   {
142     CSingleLock lock(m_critSection);
143 
144     const auto& itAddon =
145         std::find_if(m_addonsInstances.begin(), m_addonsInstances.end(),
146                      [&id](const VFSEntryPtr& addon) { return addon->ID() == id; });
147 
148     if (itAddon != m_addonsInstances.end())
149     {
150       (*itAddon)->Addon()->RegisterInformer(nullptr);
151       m_addonsInstances.erase(itAddon);
152     }
153   }
154 
155   // Create and init the new VFS addon instance
156   AddonInfoPtr addonInfo = CServiceBroker::GetAddonMgr().GetAddonInfo(id, ADDON_VFS);
157   if (addonInfo && !CServiceBroker::GetAddonMgr().IsAddonDisabled(id))
158   {
159     VFSEntryPtr vfs = std::make_shared<CVFSEntry>(addonInfo);
160 
161     if (!vfs->GetZeroconfType().empty())
162       CZeroconfBrowser::GetInstance()->AddServiceType(vfs->GetZeroconfType());
163 
164     CSingleLock lock(m_critSection);
165     m_addonsInstances.emplace_back(vfs);
166   }
167 }
168 
169 class CVFSURLWrapper
170 {
171   public:
CVFSURLWrapper(const CURL & url2)172     explicit CVFSURLWrapper(const CURL& url2)
173     {
174       m_strings.push_back(url2.Get());
175       m_strings.push_back(url2.GetDomain());
176       m_strings.push_back(url2.GetHostName());
177       m_strings.push_back(url2.GetFileName());
178       m_strings.push_back(url2.GetOptions());
179       m_strings.push_back(url2.GetUserName());
180       m_strings.push_back(url2.GetPassWord());
181       m_strings.push_back(url2.GetRedacted());
182       m_strings.push_back(url2.GetShareName());
183       m_strings.push_back(url2.GetProtocol());
184 
185       url.url = m_strings[0].c_str();
186       url.domain = m_strings[1].c_str();
187       url.hostname = m_strings[2].c_str();
188       url.filename = m_strings[3].c_str();
189       url.port = url2.GetPort();
190       url.options = m_strings[4].c_str();
191       url.username = m_strings[5].c_str();
192       url.password = m_strings[6].c_str();
193       url.redacted = m_strings[7].c_str();
194       url.sharename = m_strings[8].c_str();
195       url.protocol = m_strings[9].c_str();
196     }
197 
198     VFSURL url;
199   protected:
200     std::vector<std::string> m_strings;
201 };
202 
ProtocolInfo(const AddonInfoPtr & addonInfo)203 CVFSEntry::ProtocolInfo::ProtocolInfo(const AddonInfoPtr& addonInfo)
204   : supportPath(addonInfo->Type(ADDON_VFS)->GetValue("@supportPath").asBoolean()),
205     supportUsername(addonInfo->Type(ADDON_VFS)->GetValue("@supportUsername").asBoolean()),
206     supportPassword(addonInfo->Type(ADDON_VFS)->GetValue("@supportPassword").asBoolean()),
207     supportPort(addonInfo->Type(ADDON_VFS)->GetValue("@supportPort").asBoolean()),
208     supportBrowsing(addonInfo->Type(ADDON_VFS)->GetValue("@supportBrowsing").asBoolean()),
209     supportWrite(addonInfo->Type(ADDON_VFS)->GetValue("@supportWrite").asBoolean()),
210     defaultPort(addonInfo->Type(ADDON_VFS)->GetValue("@defaultPort").asInteger()),
211     type(addonInfo->Type(ADDON_VFS)->GetValue("@protocols").asString()),
212     label(addonInfo->Type(ADDON_VFS)->GetValue("@label").asInteger())
213 {
214 }
215 
CVFSEntry(const AddonInfoPtr & addonInfo)216 CVFSEntry::CVFSEntry(const AddonInfoPtr& addonInfo)
217   : IAddonInstanceHandler(ADDON_INSTANCE_VFS, addonInfo),
218     m_protocols(addonInfo->Type(ADDON_VFS)->GetValue("@protocols").asString()),
219     m_extensions(addonInfo->Type(ADDON_VFS)->GetValue("@extensions").asString()),
220     m_zeroconf(addonInfo->Type(ADDON_VFS)->GetValue("@zeroconf").asString()),
221     m_files(addonInfo->Type(ADDON_VFS)->GetValue("@files").asBoolean()),
222     m_directories(addonInfo->Type(ADDON_VFS)->GetValue("@directories").asBoolean()),
223     m_filedirectories(addonInfo->Type(ADDON_VFS)->GetValue("@filedirectories").asBoolean()),
224     m_protocolInfo(addonInfo)
225 {
226   if (!addonInfo->Type(ADDON_VFS)->GetValue("@supportDialog").asBoolean())
227     m_protocolInfo.type.clear();
228 
229   // Create "C" interface structures, used as own parts to prevent API problems on update
230   m_struct.props = new AddonProps_VFSEntry();
231   m_struct.toAddon = new KodiToAddonFuncTable_VFSEntry();
232   m_struct.toKodi = new AddonToKodiFuncTable_VFSEntry();
233 
234   m_struct.toKodi->kodiInstance = this;
235   if (CreateInstance(&m_struct) != ADDON_STATUS_OK)
236     CLog::Log(LOGFATAL, "CVFSEntry - Couldn't create instance on add-on '%s'", addonInfo->Name().c_str());
237 }
238 
~CVFSEntry()239 CVFSEntry::~CVFSEntry()
240 {
241   DestroyInstance();
242 
243   // Delete "C" interface structures
244   delete m_struct.toAddon;
245   delete m_struct.toKodi;
246   delete m_struct.props;
247 }
248 
Open(const CURL & url)249 void* CVFSEntry::Open(const CURL& url)
250 {
251   if (!m_struct.toAddon->open)
252     return nullptr;
253 
254   CVFSURLWrapper url2(url);
255   return m_struct.toAddon->open(&m_struct, &url2.url);
256 }
257 
OpenForWrite(const CURL & url,bool bOverWrite)258 void* CVFSEntry::OpenForWrite(const CURL& url, bool bOverWrite)
259 {
260   if (!m_struct.toAddon->open_for_write)
261     return nullptr;
262 
263   CVFSURLWrapper url2(url);
264   return m_struct.toAddon->open_for_write(&m_struct, &url2.url, bOverWrite);
265 }
266 
Exists(const CURL & url)267 bool CVFSEntry::Exists(const CURL& url)
268 {
269   if (!m_struct.toAddon->exists)
270     return false;
271 
272   CVFSURLWrapper url2(url);
273   return m_struct.toAddon->exists(&m_struct, &url2.url);
274 }
275 
Stat(const CURL & url,struct __stat64 * buffer)276 int CVFSEntry::Stat(const CURL& url, struct __stat64* buffer)
277 {
278   int ret = -1;
279   if (!m_struct.toAddon->stat)
280     return ret;
281 
282   CVFSURLWrapper url2(url);
283   STAT_STRUCTURE statBuffer = {};
284   ret = m_struct.toAddon->stat(&m_struct, &url2.url, &statBuffer);
285 
286   buffer->st_dev = statBuffer.deviceId;
287   buffer->st_ino = statBuffer.fileSerialNumber;
288   buffer->st_size = statBuffer.size;
289   buffer->st_atime = statBuffer.accessTime;
290   buffer->st_mtime = statBuffer.modificationTime;
291   buffer->st_ctime = statBuffer.statusTime;
292   buffer->st_mode = 0;
293   if (statBuffer.isDirectory)
294     buffer->st_mode |= S_IFDIR;
295   if (statBuffer.isSymLink)
296     buffer->st_mode |= S_IFLNK;
297   if (statBuffer.isBlock)
298     buffer->st_mode |= S_IFBLK;
299   if (statBuffer.isCharacter)
300     buffer->st_mode |= S_IFCHR;
301   if (statBuffer.isFifo)
302     buffer->st_mode |= S_IFIFO;
303   if (statBuffer.isRegular)
304     buffer->st_mode |= S_IFREG;
305   if (statBuffer.isSocket)
306     buffer->st_mode |= S_IFSOCK;
307 
308   return ret;
309 }
310 
Read(void * ctx,void * lpBuf,size_t uiBufSize)311 ssize_t CVFSEntry::Read(void* ctx, void* lpBuf, size_t uiBufSize)
312 {
313   if (!m_struct.toAddon->read)
314     return 0;
315 
316   return m_struct.toAddon->read(&m_struct, ctx, static_cast<uint8_t*>(lpBuf), uiBufSize);
317 }
318 
Write(void * ctx,const void * lpBuf,size_t uiBufSize)319 ssize_t CVFSEntry::Write(void* ctx, const void* lpBuf, size_t uiBufSize)
320 {
321   if (!m_struct.toAddon->write)
322     return 0;
323 
324   return m_struct.toAddon->write(&m_struct, ctx, static_cast<const uint8_t*>(lpBuf), uiBufSize);
325 }
326 
Seek(void * ctx,int64_t position,int whence)327 int64_t CVFSEntry::Seek(void* ctx, int64_t position, int whence)
328 {
329   if (!m_struct.toAddon->seek)
330     return 0;
331 
332   return m_struct.toAddon->seek(&m_struct, ctx, position, whence);
333 }
334 
Truncate(void * ctx,int64_t size)335 int CVFSEntry::Truncate(void* ctx, int64_t size)
336 {
337   if (!m_struct.toAddon->truncate)
338     return 0;
339 
340   return m_struct.toAddon->truncate(&m_struct, ctx, size);
341 }
342 
Close(void * ctx)343 void CVFSEntry::Close(void* ctx)
344 {
345   if (m_struct.toAddon->close)
346     m_struct.toAddon->close(&m_struct, ctx);
347 }
348 
GetPosition(void * ctx)349 int64_t CVFSEntry::GetPosition(void* ctx)
350 {
351   if (!m_struct.toAddon->get_position)
352     return 0;
353 
354   return m_struct.toAddon->get_position(&m_struct, ctx);
355 }
356 
GetChunkSize(void * ctx)357 int CVFSEntry::GetChunkSize(void* ctx)
358 {
359   if (!m_struct.toAddon->get_chunk_size)
360     return 0;
361 
362   return m_struct.toAddon->get_chunk_size(&m_struct, ctx);
363 }
364 
GetLength(void * ctx)365 int64_t CVFSEntry::GetLength(void* ctx)
366 {
367   if (!m_struct.toAddon->get_length)
368     return 0;
369 
370   return m_struct.toAddon->get_length(&m_struct, ctx);
371 }
372 
IoControl(void * ctx,XFILE::EIoControl request,void * param)373 int CVFSEntry::IoControl(void* ctx, XFILE::EIoControl request, void* param)
374 {
375   switch (request)
376   {
377     case XFILE::EIoControl::IOCTRL_SEEK_POSSIBLE:
378     {
379       if (!m_struct.toAddon->io_control_get_seek_possible)
380         return -1;
381       return m_struct.toAddon->io_control_get_seek_possible(&m_struct, ctx) ? 1 : 0;
382     }
383     case XFILE::EIoControl::IOCTRL_CACHE_STATUS:
384     {
385       if (!m_struct.toAddon->io_control_get_cache_status)
386         return -1;
387 
388       XFILE::SCacheStatus* kodiData = static_cast<XFILE::SCacheStatus*>(param);
389       if (!kodiData)
390         return -1;
391 
392       VFS_CACHE_STATUS_DATA status;
393       int ret = m_struct.toAddon->io_control_get_cache_status(&m_struct, ctx, &status) ? 0 : -1;
394       if (ret >= 0)
395       {
396         kodiData->forward = status.forward;
397         kodiData->maxrate = status.maxrate;
398         kodiData->currate = status.currate;
399         kodiData->lowspeed = status.lowspeed;
400       }
401       return ret;
402     }
403     case XFILE::EIoControl::IOCTRL_CACHE_SETRATE:
404     {
405       if (!m_struct.toAddon->io_control_set_cache_rate)
406         return -1;
407 
408       unsigned int& iParam = *static_cast<unsigned int*>(param);
409       return m_struct.toAddon->io_control_set_cache_rate(&m_struct, ctx, iParam) ? 1 : 0;
410     }
411     case XFILE::EIoControl::IOCTRL_SET_RETRY:
412     {
413       if (!m_struct.toAddon->io_control_set_retry)
414         return -1;
415 
416       bool& bParam = *static_cast<bool*>(param);
417       return m_struct.toAddon->io_control_set_retry(&m_struct, ctx, bParam) ? 0 : -1;
418     }
419 
420     // Not by addon supported io's
421     case XFILE::EIoControl::IOCTRL_SET_CACHE:
422     case XFILE::EIoControl::IOCTRL_NATIVE:
423     default:
424       break;
425   }
426 
427   return -1;
428 }
429 
Delete(const CURL & url)430 bool CVFSEntry::Delete(const CURL& url)
431 {
432   if (!m_struct.toAddon->delete_it)
433     return false;
434 
435   CVFSURLWrapper url2(url);
436   return m_struct.toAddon->delete_it(&m_struct, &url2.url);
437 }
438 
Rename(const CURL & url,const CURL & url2)439 bool CVFSEntry::Rename(const CURL& url, const CURL& url2)
440 {
441   if (!m_struct.toAddon->rename)
442     return false;
443 
444   CVFSURLWrapper url3(url);
445   CVFSURLWrapper url4(url2);
446   return m_struct.toAddon->rename(&m_struct, &url3.url, &url4.url);
447 }
448 
ClearOutIdle()449 void CVFSEntry::ClearOutIdle()
450 {
451   if (m_struct.toAddon->clear_out_idle)
452     m_struct.toAddon->clear_out_idle(&m_struct);
453 }
454 
DisconnectAll()455 void CVFSEntry::DisconnectAll()
456 {
457   if (m_struct.toAddon->disconnect_all)
458     m_struct.toAddon->disconnect_all(&m_struct);
459 }
460 
DirectoryExists(const CURL & url)461 bool CVFSEntry::DirectoryExists(const CURL& url)
462 {
463   if (!m_struct.toAddon->directory_exists)
464     return false;
465 
466   CVFSURLWrapper url2(url);
467   return m_struct.toAddon->directory_exists(&m_struct, &url2.url);
468 }
469 
RemoveDirectory(const CURL & url)470 bool CVFSEntry::RemoveDirectory(const CURL& url)
471 {
472   if (!m_struct.toAddon->remove_directory)
473     return false;
474 
475   CVFSURLWrapper url2(url);
476   return m_struct.toAddon->remove_directory(&m_struct, &url2.url);
477 }
478 
CreateDirectory(const CURL & url)479 bool CVFSEntry::CreateDirectory(const CURL& url)
480 {
481   if (!m_struct.toAddon->create_directory)
482     return false;
483 
484   CVFSURLWrapper url2(url);
485   return m_struct.toAddon->create_directory(&m_struct, &url2.url);
486 }
487 
VFSDirEntriesToCFileItemList(int num_entries,VFSDirEntry * entries,CFileItemList & items)488 static void VFSDirEntriesToCFileItemList(int num_entries,
489                                          VFSDirEntry* entries,
490                                          CFileItemList& items)
491 {
492   for (int i=0;i<num_entries;++i)
493   {
494     CFileItemPtr item(new CFileItem());
495     item->SetLabel(entries[i].label);
496     item->SetPath(entries[i].path);
497     item->m_dwSize = entries[i].size;
498     item->m_dateTime = entries[i].date_time;
499     item->m_bIsFolder = entries[i].folder;
500     if (entries[i].title)
501       item->m_strTitle = entries[i].title;
502     for (unsigned int j=0;j<entries[i].num_props;++j)
503     {
504       if (StringUtils::CompareNoCase(entries[i].properties[j].name, "propmisusepreformatted") == 0)
505       {
506         if (StringUtils::CompareNoCase(entries[i].properties[j].name, "true") == 0)
507           item->SetLabelPreformatted(true);
508         else
509           item->SetLabelPreformatted(false);
510       } else
511         item->SetProperty(entries[i].properties[j].name,
512                           entries[i].properties[j].val);
513     }
514     items.Add(item);
515   }
516 }
517 
GetDirectory(const CURL & url,CFileItemList & items,void * ctx)518 bool CVFSEntry::GetDirectory(const CURL& url, CFileItemList& items,
519                              void* ctx)
520 {
521   if (!m_struct.toAddon->get_directory || !m_struct.toAddon->free_directory)
522     return false;
523 
524   VFSGetDirectoryCallbacks callbacks;
525   callbacks.ctx = ctx;
526   callbacks.get_keyboard_input = CVFSEntryIDirectoryWrapper::DoGetKeyboardInput;
527   callbacks.set_error_dialog = CVFSEntryIDirectoryWrapper::DoSetErrorDialog;
528   callbacks.require_authentication = CVFSEntryIDirectoryWrapper::DoRequireAuthentication;
529 
530   VFSDirEntry* entries = nullptr;
531   int num_entries = 0;
532   CVFSURLWrapper url2(url);
533   bool ret =
534       m_struct.toAddon->get_directory(&m_struct, &url2.url, &entries, &num_entries, &callbacks);
535   if (ret)
536   {
537     VFSDirEntriesToCFileItemList(num_entries, entries, items);
538     m_struct.toAddon->free_directory(&m_struct, entries, num_entries);
539   }
540 
541   return ret;
542 }
543 
ContainsFiles(const CURL & url,CFileItemList & items)544 bool CVFSEntry::ContainsFiles(const CURL& url, CFileItemList& items)
545 {
546   if (!m_struct.toAddon->contains_files || !m_struct.toAddon->free_directory)
547     return false;
548 
549   VFSDirEntry* entries = nullptr;
550   int num_entries = 0;
551 
552   CVFSURLWrapper url2(url);
553   char rootpath[ADDON_STANDARD_STRING_LENGTH];
554   rootpath[0] = 0;
555   bool ret =
556       m_struct.toAddon->contains_files(&m_struct, &url2.url, &entries, &num_entries, rootpath);
557   if (!ret)
558     return false;
559 
560   VFSDirEntriesToCFileItemList(num_entries, entries, items);
561   m_struct.toAddon->free_directory(&m_struct, entries, num_entries);
562   if (strlen(rootpath))
563     items.SetPath(rootpath);
564 
565   return true;
566 }
567 
CVFSEntryIFileWrapper(VFSEntryPtr ptr)568 CVFSEntryIFileWrapper::CVFSEntryIFileWrapper(VFSEntryPtr ptr)
569   : m_context(nullptr), m_addon(std::move(ptr))
570 {
571 }
572 
~CVFSEntryIFileWrapper()573 CVFSEntryIFileWrapper::~CVFSEntryIFileWrapper()
574 {
575   Close();
576 }
577 
Open(const CURL & url)578 bool CVFSEntryIFileWrapper::Open(const CURL& url)
579 {
580   m_context = m_addon->Open(url);
581   return m_context != NULL;
582 }
583 
OpenForWrite(const CURL & url,bool bOverWrite)584 bool CVFSEntryIFileWrapper::OpenForWrite(const CURL& url, bool bOverWrite)
585 {
586   m_context = m_addon->OpenForWrite(url, bOverWrite);
587   return m_context != NULL;
588 }
589 
Exists(const CURL & url)590 bool CVFSEntryIFileWrapper::Exists(const CURL& url)
591 {
592   return m_addon->Exists(url);
593 }
594 
Stat(const CURL & url,struct __stat64 * buffer)595 int CVFSEntryIFileWrapper::Stat(const CURL& url, struct __stat64* buffer)
596 {
597   return m_addon->Stat(url, buffer);
598 }
599 
Truncate(int64_t size)600 int CVFSEntryIFileWrapper::Truncate(int64_t size)
601 {
602   return m_addon->Truncate(m_context, size);
603 }
604 
Read(void * lpBuf,size_t uiBufSize)605 ssize_t CVFSEntryIFileWrapper::Read(void* lpBuf, size_t uiBufSize)
606 {
607   if (!m_context)
608     return 0;
609 
610   return m_addon->Read(m_context, lpBuf, uiBufSize);
611 }
612 
Write(const void * lpBuf,size_t uiBufSize)613 ssize_t CVFSEntryIFileWrapper::Write(const void* lpBuf, size_t uiBufSize)
614 {
615   if (!m_context)
616     return 0;
617 
618   return m_addon->Write(m_context, lpBuf, uiBufSize);
619 }
620 
Seek(int64_t iFilePosition,int whence)621 int64_t CVFSEntryIFileWrapper::Seek(int64_t iFilePosition, int whence)
622 {
623   if (!m_context)
624     return 0;
625 
626   return m_addon->Seek(m_context, iFilePosition, whence);
627 }
628 
Close()629 void CVFSEntryIFileWrapper::Close()
630 {
631   if (m_context)
632   {
633     m_addon->Close(m_context);
634     m_context = NULL;
635   }
636 }
637 
GetPosition()638 int64_t CVFSEntryIFileWrapper::GetPosition()
639 {
640   if (!m_context)
641     return 0;
642 
643   return m_addon->GetPosition(m_context);
644 }
645 
GetChunkSize()646 int CVFSEntryIFileWrapper::GetChunkSize()
647 {
648   if (!m_context)
649     return 0;
650 
651   return m_addon->GetChunkSize(m_context);
652 }
653 
GetLength()654 int64_t CVFSEntryIFileWrapper::GetLength()
655 {
656   if (!m_context)
657     return 0;
658 
659   return m_addon->GetLength(m_context);
660 }
661 
IoControl(XFILE::EIoControl request,void * param)662 int CVFSEntryIFileWrapper::IoControl(XFILE::EIoControl request, void* param)
663 {
664   if (!m_context)
665     return 0;
666 
667   return m_addon->IoControl(m_context, request, param);
668 }
669 
Delete(const CURL & url)670 bool CVFSEntryIFileWrapper::Delete(const CURL& url)
671 {
672   return m_addon->Delete(url);
673 }
674 
Rename(const CURL & url,const CURL & url2)675 bool CVFSEntryIFileWrapper::Rename(const CURL& url, const CURL& url2)
676 {
677   return m_addon->Rename(url, url2);
678 }
679 
CVFSEntryIDirectoryWrapper(VFSEntryPtr ptr)680 CVFSEntryIDirectoryWrapper::CVFSEntryIDirectoryWrapper(VFSEntryPtr ptr) : m_addon(std::move(ptr))
681 {
682 }
683 
Exists(const CURL & url)684 bool CVFSEntryIDirectoryWrapper::Exists(const CURL& url)
685 {
686   return m_addon->DirectoryExists(url);
687 }
688 
Remove(const CURL & url)689 bool CVFSEntryIDirectoryWrapper::Remove(const CURL& url)
690 {
691   return m_addon->RemoveDirectory(url);
692 }
693 
Create(const CURL & url)694 bool CVFSEntryIDirectoryWrapper::Create(const CURL& url)
695 {
696   return m_addon->CreateDirectory(url);
697 }
698 
GetDirectory(const CURL & url,CFileItemList & items)699 bool CVFSEntryIDirectoryWrapper::GetDirectory(const CURL& url,
700                                               CFileItemList& items)
701 {
702   return m_addon->GetDirectory(url, items, this);
703 }
704 
DoGetKeyboardInput(void * ctx,const char * heading,char ** input,bool hidden_input)705 bool CVFSEntryIDirectoryWrapper::DoGetKeyboardInput(void* ctx,
706                                                     const char* heading,
707                                                     char** input,
708                                                     bool hidden_input)
709 {
710   return static_cast<CVFSEntryIDirectoryWrapper*>(ctx)->GetKeyboardInput2(heading, input, hidden_input);
711 }
712 
GetKeyboardInput2(const char * heading,char ** input,bool hidden_input)713 bool CVFSEntryIDirectoryWrapper::GetKeyboardInput2(const char* heading,
714                                                    char** input,
715                                                    bool hidden_input)
716 {
717   std::string inp;
718   bool result;
719   if ((result=GetKeyboardInput(CVariant(std::string(heading)), inp, hidden_input)))
720     *input = strdup(inp.c_str());
721 
722   return result;
723 }
724 
DoSetErrorDialog(void * ctx,const char * heading,const char * line1,const char * line2,const char * line3)725 void CVFSEntryIDirectoryWrapper::DoSetErrorDialog(void* ctx, const char* heading,
726                                                   const char* line1,
727                                                   const char* line2,
728                                                   const char* line3)
729 {
730   static_cast<CVFSEntryIDirectoryWrapper*>(ctx)->SetErrorDialog2(heading, line1,
731                                                                  line2, line3);
732 }
733 
SetErrorDialog2(const char * heading,const char * line1,const char * line2,const char * line3)734 void CVFSEntryIDirectoryWrapper::SetErrorDialog2(const char* heading,
735                                                  const char* line1,
736                                                  const char* line2,
737                                                  const char* line3)
738 {
739   CVariant l2=0, l3=0;
740   if (line2)
741     l2 = std::string(line2);
742   if (line3)
743     l3 = std::string(line3);
744   if (m_flags & XFILE::DIR_FLAG_ALLOW_PROMPT)
745     SetErrorDialog(CVariant(std::string(heading)),
746                    CVariant(std::string(line1)), l2, l3);
747 }
748 
DoRequireAuthentication(void * ctx,const char * url)749 void CVFSEntryIDirectoryWrapper::DoRequireAuthentication(void* ctx,
750                                                          const char* url)
751 {
752   static_cast<CVFSEntryIDirectoryWrapper*>(ctx)->RequireAuthentication2(CURL(url));
753 }
754 
RequireAuthentication2(const CURL & url)755 void CVFSEntryIDirectoryWrapper::RequireAuthentication2(const CURL& url)
756 {
757   if (m_flags & XFILE::DIR_FLAG_ALLOW_PROMPT)
758     RequireAuthentication(url);
759 }
760 
761 } /*namespace ADDON*/
762 
763