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