[PVR][Estuary] Timer settings dialog: Show client name in timer type selection dialog...
[xbmc.git] / xbmc / filesystem / File.cpp
blob9e8a2668dece8eea722c866ebcbc83112fd42ae3
1 /*
2 * Copyright (c) 2002 Frodo
3 * Portions Copyright (c) by the authors of ffmpeg and xvid
4 * Copyright (C) 2002-2018 Team Kodi
5 * This file is part of Kodi - https://kodi.tv
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 * See LICENSES/README.md for more information.
9 */
11 #include "File.h"
13 #include "Directory.h"
14 #include "DirectoryCache.h"
15 #include "FileCache.h"
16 #include "FileFactory.h"
17 #include "IFile.h"
18 #include "PasswordManager.h"
19 #include "ServiceBroker.h"
20 #include "application/ApplicationComponents.h"
21 #include "application/ApplicationPowerHandling.h"
22 #include "commons/Exception.h"
23 #include "settings/AdvancedSettings.h"
24 #include "settings/SettingsComponent.h"
25 #include "utils/BitstreamStats.h"
26 #include "utils/StringUtils.h"
27 #include "utils/URIUtils.h"
28 #include "utils/log.h"
30 using namespace XFILE;
32 //////////////////////////////////////////////////////////////////////
33 // Construction/Destruction
34 //////////////////////////////////////////////////////////////////////
35 #ifndef __GNUC__
36 #pragma warning (disable:4244)
37 #endif
39 //*********************************************************************************************
40 CFile::CFile() = default;
42 //*********************************************************************************************
43 CFile::~CFile()
45 Close();
48 //*********************************************************************************************
50 bool CFile::Copy(const std::string& strFileName, const std::string& strDest, XFILE::IFileCallback* pCallback, void* pContext)
52 const CURL pathToUrl(strFileName);
53 const CURL pathToUrlDest(strDest);
54 return Copy(pathToUrl, pathToUrlDest, pCallback, pContext);
57 bool CFile::Copy(const CURL& url2, const CURL& dest, XFILE::IFileCallback* pCallback, void* pContext)
59 CFile file;
61 const std::string pathToUrl(dest.Get());
62 if (pathToUrl.empty())
63 return false;
65 // special case for zips - ignore caching
66 CURL url(url2);
67 if (StringUtils::StartsWith(url.Get(), "zip://") || URIUtils::IsInAPK(url.Get()))
68 url.SetOptions("?cache=no");
69 if (file.Open(url.Get(), READ_TRUNCATED | READ_CHUNKED))
72 CFile newFile;
73 if (URIUtils::IsHD(pathToUrl)) // create possible missing dirs
75 std::vector<std::string> tokens;
76 std::string strDirectory = URIUtils::GetDirectory(pathToUrl);
77 URIUtils::RemoveSlashAtEnd(strDirectory); // for the test below
78 if (!(strDirectory.size() == 2 && strDirectory[1] == ':'))
80 CURL url(strDirectory);
81 std::string pathsep;
82 #ifndef TARGET_POSIX
83 pathsep = "\\";
84 #else
85 pathsep = "/";
86 #endif
87 // Try to use the recursive creation first, if it fails
88 // it might not be implemented for that subsystem so let's
89 // fall back to the old method in that case
90 if (!CDirectory::Create(url))
92 StringUtils::Tokenize(url.GetFileName(), tokens, pathsep);
93 std::string strCurrPath;
94 // Handle special
95 if (!url.GetProtocol().empty())
97 pathsep = "/";
98 strCurrPath += url.GetProtocol() + "://";
99 } // If the directory has a / at the beginning, don't forget it
100 else if (strDirectory[0] == pathsep[0])
101 strCurrPath += pathsep;
103 for (const std::string& iter : tokens)
105 strCurrPath += iter + pathsep;
106 CDirectory::Create(strCurrPath);
111 if (CFile::Exists(dest))
112 CFile::Delete(dest);
113 if (!newFile.OpenForWrite(dest, true)) // overwrite always
115 file.Close();
116 return false;
119 int iBufferSize = DetermineChunkSize(file.GetChunkSize(), 128 * 1024);
121 std::vector<char> buffer(iBufferSize);
122 ssize_t iRead, iWrite;
124 unsigned long long llFileSize = file.GetLength();
125 unsigned long long llPos = 0;
127 CStopWatch timer;
128 timer.StartZero();
129 float start = 0.0f;
130 auto& components = CServiceBroker::GetAppComponents();
131 const auto appPower = components.GetComponent<CApplicationPowerHandling>();
132 while (true)
134 appPower->ResetScreenSaver();
136 iRead = file.Read(buffer.data(), buffer.size());
137 if (iRead == 0) break;
138 else if (iRead < 0)
140 CLog::Log(LOGERROR, "{} - Failed read from file {}", __FUNCTION__, url.GetRedacted());
141 llFileSize = (uint64_t)-1;
142 break;
145 /* write data and make sure we managed to write it all */
146 iWrite = 0;
147 while(iWrite < iRead)
149 ssize_t iWrite2 = newFile.Write(buffer.data() + iWrite, iRead - iWrite);
150 if(iWrite2 <=0)
151 break;
152 iWrite+=iWrite2;
155 if (iWrite != iRead)
157 CLog::Log(LOGERROR, "{} - Failed write to file {}", __FUNCTION__, dest.GetRedacted());
158 llFileSize = (uint64_t)-1;
159 break;
162 llPos += iRead;
164 // calculate the current and average speeds
165 float end = timer.GetElapsedSeconds();
167 if (pCallback && end - start > 0.5f && end)
169 start = end;
171 float averageSpeed = llPos / end;
172 int ipercent = 0;
173 if(llFileSize)
174 ipercent = 100 * llPos / llFileSize;
176 if(!pCallback->OnFileCallback(pContext, ipercent, averageSpeed))
178 CLog::Log(LOGERROR, "{} - User aborted copy", __FUNCTION__);
179 llFileSize = (uint64_t)-1;
180 break;
185 /* close both files */
186 newFile.Close();
187 file.Close();
189 /* verify that we managed to completed the file */
190 if (llFileSize && llPos != llFileSize)
192 CFile::Delete(dest);
193 return false;
195 return true;
197 return false;
200 //*********************************************************************************************
202 bool CFile::CURLCreate(const std::string &url)
204 m_curl.Parse(url);
205 return true;
208 bool CFile::CURLAddOption(XFILE::CURLOPTIONTYPE type, const char* name, const char * value)
210 switch (type){
211 case XFILE::CURL_OPTION_CREDENTIALS:
213 m_curl.SetUserName(name);
214 m_curl.SetPassword(value);
215 break;
217 case XFILE::CURL_OPTION_PROTOCOL:
218 case XFILE::CURL_OPTION_HEADER:
220 m_curl.SetProtocolOption(name, value);
221 break;
223 case XFILE::CURL_OPTION_OPTION:
225 m_curl.SetOption(name, value);
226 break;
228 default:
229 return false;
231 return true;
234 bool CFile::CURLOpen(unsigned int flags)
236 return Open(m_curl, flags);
239 bool CFile::Open(const std::string& strFileName, const unsigned int flags)
241 const CURL pathToUrl(strFileName);
242 return Open(pathToUrl, flags);
245 bool CFile::Open(const CURL& file, const unsigned int flags)
247 if (m_pFile)
249 if ((flags & READ_REOPEN) == 0)
251 CLog::Log(LOGERROR, "File::Open - already open: {}", file.GetRedacted());
252 return false;
254 else
256 return m_pFile->ReOpen(URIUtils::SubstitutePath(file));
260 m_flags = flags;
263 bool bPathInCache;
265 CURL url(URIUtils::SubstitutePath(file)), url2(url);
267 if (url2.IsProtocol("apk") || url2.IsProtocol("zip") )
268 url2.SetOptions("");
270 if (!g_directoryCache.FileExists(url2.Get(), bPathInCache) )
272 if (bPathInCache)
273 return false;
277 * There are 5 buffer modes available (configurable in as.xml)
278 * 0) Buffer all internet filesystems (like 2 but additionally also ftp, webdav, etc.)
279 * 1) Buffer all filesystems (including local)
280 * 2) Only buffer true internet filesystems (streams) (http, etc.)
281 * 3) No buffer
282 * 4) Buffer all remote (non-local) filesystems
284 if (!(m_flags & READ_NO_CACHE))
286 const std::string pathToUrl(url.Get());
287 if (URIUtils::IsDVD(pathToUrl) || URIUtils::IsBluray(pathToUrl) ||
288 (m_flags & READ_AUDIO_VIDEO))
290 const unsigned int iCacheBufferMode =
291 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_cacheBufferMode;
292 if ((iCacheBufferMode == CACHE_BUFFER_MODE_INTERNET &&
293 URIUtils::IsInternetStream(pathToUrl, true)) ||
294 (iCacheBufferMode == CACHE_BUFFER_MODE_TRUE_INTERNET &&
295 URIUtils::IsInternetStream(pathToUrl, false)) ||
296 (iCacheBufferMode == CACHE_BUFFER_MODE_NETWORK &&
297 URIUtils::IsNetworkFilesystem(pathToUrl)) ||
298 (iCacheBufferMode == CACHE_BUFFER_MODE_ALL &&
299 (URIUtils::IsNetworkFilesystem(pathToUrl) || URIUtils::IsHD(pathToUrl))))
301 m_flags |= READ_CACHED;
305 if (m_flags & READ_CACHED)
307 m_pFile = std::make_unique<CFileCache>(m_flags);
309 if (!m_pFile)
310 return false;
312 return m_pFile->Open(url);
316 m_pFile.reset(CFileFactory::CreateLoader(url));
318 if (!m_pFile)
319 return false;
321 CURL authUrl(url);
322 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
323 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
327 if (!m_pFile->Open(authUrl))
328 return false;
330 catch (CRedirectException *pRedirectEx)
332 // the file implementation decided this item should use a different implementation.
333 // the exception will contain the new implementation.
334 CLog::Log(LOGDEBUG, "File::Open - redirecting implementation for {}", file.GetRedacted());
335 if (pRedirectEx && pRedirectEx->m_pNewFileImp)
337 std::unique_ptr<CURL> pNewUrl(pRedirectEx->m_pNewUrl);
338 m_pFile.reset(pRedirectEx->m_pNewFileImp);
339 delete pRedirectEx;
341 if (pNewUrl)
343 CURL newAuthUrl(*pNewUrl);
344 if (CPasswordManager::GetInstance().IsURLSupported(newAuthUrl) && newAuthUrl.GetUserName().empty())
345 CPasswordManager::GetInstance().AuthenticateURL(newAuthUrl);
347 if (!m_pFile->Open(newAuthUrl))
348 return false;
350 else
352 if (!m_pFile->Open(authUrl))
353 return false;
357 catch (...)
359 CLog::Log(LOGERROR, "File::Open - unknown exception when opening {}", file.GetRedacted());
360 return false;
363 if (m_pFile->GetChunkSize() && !(m_flags & READ_CHUNKED))
365 m_pBuffer = std::make_unique<CFileStreamBuffer>(0);
366 m_pBuffer->Attach(m_pFile.get());
369 if (m_flags & READ_BITRATE)
371 m_bitStreamStats = std::make_unique<BitstreamStats>();
372 m_bitStreamStats->Start();
375 return true;
377 XBMCCOMMONS_HANDLE_UNCHECKED
378 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
379 CLog::Log(LOGERROR, "{} - Error opening {}", __FUNCTION__, file.GetRedacted());
380 return false;
383 bool CFile::OpenForWrite(const std::string& strFileName, bool bOverWrite)
385 const CURL pathToUrl(strFileName);
386 return OpenForWrite(pathToUrl, bOverWrite);
389 bool CFile::OpenForWrite(const CURL& file, bool bOverWrite)
393 CURL url = URIUtils::SubstitutePath(file);
394 CURL authUrl = url;
395 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
396 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
398 m_pFile.reset(CFileFactory::CreateLoader(url));
400 if (m_pFile && m_pFile->OpenForWrite(authUrl, bOverWrite))
402 // add this file to our directory cache (if it's stored)
403 g_directoryCache.AddFile(url.Get());
404 return true;
406 return false;
408 XBMCCOMMONS_HANDLE_UNCHECKED
409 catch(...)
411 CLog::Log(LOGERROR, "{} - Unhandled exception opening {}", __FUNCTION__, file.GetRedacted());
413 CLog::Log(LOGERROR, "{} - Error opening {}", __FUNCTION__, file.GetRedacted());
414 return false;
417 int CFile::DetermineChunkSize(const int srcChunkSize, const int reqChunkSize)
419 // Determine cache chunk size: if source chunk size is bigger than 1
420 // use source chunk size else use requested chunk size
421 return (srcChunkSize > 1 ? srcChunkSize : reqChunkSize);
424 bool CFile::Exists(const std::string& strFileName, bool bUseCache /* = true */)
426 const CURL pathToUrl(strFileName);
427 return Exists(pathToUrl, bUseCache);
430 bool CFile::Exists(const CURL& file, bool bUseCache /* = true */)
432 CURL url(URIUtils::SubstitutePath(file));
433 CURL authUrl = url;
434 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
435 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
439 if (bUseCache)
441 bool bPathInCache;
442 if (g_directoryCache.FileExists(url.Get(), bPathInCache))
443 return true;
444 if (bPathInCache)
445 return false;
448 std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url));
449 if (!pFile)
450 return false;
452 return pFile->Exists(authUrl);
454 XBMCCOMMONS_HANDLE_UNCHECKED
455 catch (CRedirectException *pRedirectEx)
457 // the file implementation decided this item should use a different implementation.
458 // the exception will contain the new implementation and optional a redirected URL.
459 CLog::Log(LOGDEBUG, "File::Exists - redirecting implementation for {}", file.GetRedacted());
460 if (pRedirectEx && pRedirectEx->m_pNewFileImp)
462 std::unique_ptr<IFile> pImp(pRedirectEx->m_pNewFileImp);
463 std::unique_ptr<CURL> pNewUrl(pRedirectEx->m_pNewUrl);
464 delete pRedirectEx;
466 if (pImp)
468 if (pNewUrl)
470 if (bUseCache)
472 bool bPathInCache;
473 if (g_directoryCache.FileExists(pNewUrl->Get(), bPathInCache))
474 return true;
475 if (bPathInCache)
476 return false;
478 CURL newAuthUrl = *pNewUrl;
479 if (CPasswordManager::GetInstance().IsURLSupported(newAuthUrl) && newAuthUrl.GetUserName().empty())
480 CPasswordManager::GetInstance().AuthenticateURL(newAuthUrl);
482 return pImp->Exists(newAuthUrl);
484 else
486 return pImp->Exists(authUrl);
491 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
492 CLog::Log(LOGERROR, "{} - Error checking for {}", __FUNCTION__, file.GetRedacted());
493 return false;
496 int CFile::Stat(struct __stat64 *buffer)
498 if (!buffer)
499 return -1;
501 if (!m_pFile)
503 *buffer = {};
504 errno = ENOENT;
505 return -1;
508 return m_pFile->Stat(buffer);
511 int CFile::Stat(const std::string& strFileName, struct __stat64* buffer)
513 const CURL pathToUrl(strFileName);
514 return Stat(pathToUrl, buffer);
517 int CFile::Stat(const CURL& file, struct __stat64* buffer)
519 if (!buffer)
520 return -1;
522 CURL url(URIUtils::SubstitutePath(file));
523 CURL authUrl = url;
524 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
525 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
529 std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url));
530 if (!pFile)
531 return -1;
532 return pFile->Stat(authUrl, buffer);
534 XBMCCOMMONS_HANDLE_UNCHECKED
535 catch (CRedirectException *pRedirectEx)
537 // the file implementation decided this item should use a different implementation.
538 // the exception will contain the new implementation and optional a redirected URL.
539 CLog::Log(LOGDEBUG, "File::Stat - redirecting implementation for {}", file.GetRedacted());
540 if (pRedirectEx && pRedirectEx->m_pNewFileImp)
542 std::unique_ptr<IFile> pImp(pRedirectEx->m_pNewFileImp);
543 std::unique_ptr<CURL> pNewUrl(pRedirectEx->m_pNewUrl);
544 delete pRedirectEx;
546 if (pNewUrl)
548 if (pImp)
550 CURL newAuthUrl = *pNewUrl;
551 if (CPasswordManager::GetInstance().IsURLSupported(newAuthUrl) && newAuthUrl.GetUserName().empty())
552 CPasswordManager::GetInstance().AuthenticateURL(newAuthUrl);
554 if (!pImp->Stat(newAuthUrl, buffer))
556 return 0;
560 else
562 if (pImp.get() && !pImp->Stat(authUrl, buffer))
564 return 0;
569 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
570 CLog::Log(LOGERROR, "{} - Error statting {}", __FUNCTION__, file.GetRedacted());
571 return -1;
574 ssize_t CFile::Read(void *lpBuf, size_t uiBufSize)
576 if (!m_pFile)
577 return -1;
578 if (lpBuf == NULL && uiBufSize != 0)
579 return -1;
581 if (uiBufSize > SSIZE_MAX)
582 uiBufSize = SSIZE_MAX;
584 if (uiBufSize == 0)
586 // "test" read with zero size
587 // some VFSs don't handle correctly null buffer pointer
588 // provide valid buffer pointer for them
589 char dummy;
590 return m_pFile->Read(&dummy, 0);
593 if(m_pBuffer)
595 if(m_flags & READ_TRUNCATED)
597 const ssize_t nBytes = m_pBuffer->sgetn(
598 (char *)lpBuf, std::min<std::streamsize>((std::streamsize)uiBufSize,
599 m_pBuffer->in_avail()));
600 if (m_bitStreamStats && nBytes>0)
601 m_bitStreamStats->AddSampleBytes(nBytes);
602 return nBytes;
604 else
606 const ssize_t nBytes = m_pBuffer->sgetn((char*)lpBuf, uiBufSize);
607 if (m_bitStreamStats && nBytes>0)
608 m_bitStreamStats->AddSampleBytes(nBytes);
609 return nBytes;
615 if(m_flags & READ_TRUNCATED)
617 const ssize_t nBytes = m_pFile->Read(lpBuf, uiBufSize);
618 if (m_bitStreamStats && nBytes>0)
619 m_bitStreamStats->AddSampleBytes(nBytes);
620 return nBytes;
622 else
624 ssize_t done = 0;
625 while((uiBufSize-done) > 0)
627 const ssize_t curr = m_pFile->Read((char*)lpBuf+done, uiBufSize-done);
628 if (curr <= 0)
630 if (curr < 0 && done == 0)
631 return -1;
633 break;
635 done+=curr;
637 if (m_bitStreamStats && done > 0)
638 m_bitStreamStats->AddSampleBytes(done);
639 return done;
642 XBMCCOMMONS_HANDLE_UNCHECKED
643 catch(...)
645 CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__);
646 return -1;
648 return 0;
651 //*********************************************************************************************
652 void CFile::Close()
656 if (m_pFile)
657 m_pFile->Close();
659 m_pBuffer.reset();
660 m_pFile.reset();
662 XBMCCOMMONS_HANDLE_UNCHECKED
663 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
666 void CFile::Flush()
670 if (m_pFile)
671 m_pFile->Flush();
673 XBMCCOMMONS_HANDLE_UNCHECKED
674 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
677 //*********************************************************************************************
678 int64_t CFile::Seek(int64_t iFilePosition, int iWhence)
680 if (!m_pFile)
681 return -1;
683 if (m_pBuffer)
685 if(iWhence == SEEK_CUR)
686 return m_pBuffer->pubseekoff(iFilePosition, std::ios_base::cur);
687 else if(iWhence == SEEK_END)
688 return m_pBuffer->pubseekoff(iFilePosition, std::ios_base::end);
689 else if(iWhence == SEEK_SET)
690 return m_pBuffer->pubseekoff(iFilePosition, std::ios_base::beg);
695 return m_pFile->Seek(iFilePosition, iWhence);
697 XBMCCOMMONS_HANDLE_UNCHECKED
698 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
699 return -1;
702 //*********************************************************************************************
703 int CFile::Truncate(int64_t iSize)
705 if (!m_pFile)
706 return -1;
710 return m_pFile->Truncate(iSize);
712 XBMCCOMMONS_HANDLE_UNCHECKED
713 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
714 return -1;
717 //*********************************************************************************************
718 int64_t CFile::GetLength()
722 if (m_pFile)
723 return m_pFile->GetLength();
724 return 0;
726 XBMCCOMMONS_HANDLE_UNCHECKED
727 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
728 return 0;
731 //*********************************************************************************************
732 int64_t CFile::GetPosition() const
734 if (!m_pFile)
735 return -1;
737 if (m_pBuffer)
738 return m_pBuffer->pubseekoff(0, std::ios_base::cur);
742 return m_pFile->GetPosition();
744 XBMCCOMMONS_HANDLE_UNCHECKED
745 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
746 return -1;
750 //*********************************************************************************************
751 bool CFile::ReadString(char *szLine, int iLineLength)
753 if (!m_pFile || !szLine)
754 return false;
756 if (m_pBuffer)
758 typedef CFileStreamBuffer::traits_type traits;
759 CFileStreamBuffer::int_type aByte = m_pBuffer->sgetc();
761 if(aByte == traits::eof())
762 return false;
764 while(iLineLength>0)
766 aByte = m_pBuffer->sbumpc();
768 if(aByte == traits::eof())
769 break;
771 if(aByte == traits::to_int_type('\n'))
773 if(m_pBuffer->sgetc() == traits::to_int_type('\r'))
774 m_pBuffer->sbumpc();
775 break;
778 if(aByte == traits::to_int_type('\r'))
780 if(m_pBuffer->sgetc() == traits::to_int_type('\n'))
781 m_pBuffer->sbumpc();
782 break;
785 *szLine = traits::to_char_type(aByte);
786 szLine++;
787 iLineLength--;
790 // if we have no space for terminating character we failed
791 if(iLineLength==0)
792 return false;
794 *szLine = 0;
796 return true;
801 return m_pFile->ReadString(szLine, iLineLength);
803 XBMCCOMMONS_HANDLE_UNCHECKED
804 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
805 return false;
808 ssize_t CFile::Write(const void* lpBuf, size_t uiBufSize)
810 if (!m_pFile)
811 return -1;
812 if (lpBuf == NULL && uiBufSize != 0)
813 return -1;
817 if (uiBufSize == 0 && lpBuf == NULL)
818 { // "test" write with zero size
819 // some VFSs don't handle correctly null buffer pointer
820 // provide valid buffer pointer for them
821 const char dummyBuf = 0;
822 return m_pFile->Write(&dummyBuf, 0);
825 return m_pFile->Write(lpBuf, uiBufSize);
827 XBMCCOMMONS_HANDLE_UNCHECKED
828 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
829 return -1;
832 bool CFile::Delete(const std::string& strFileName)
834 const CURL pathToUrl(strFileName);
835 return Delete(pathToUrl);
838 bool CFile::Delete(const CURL& file)
842 CURL url(URIUtils::SubstitutePath(file));
843 CURL authUrl = url;
844 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
845 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
847 std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url));
848 if (!pFile)
849 return false;
851 if(pFile->Delete(authUrl))
853 g_directoryCache.ClearFile(url.Get());
854 return true;
857 XBMCCOMMONS_HANDLE_UNCHECKED
858 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
859 if (Exists(file))
860 CLog::Log(LOGERROR, "{} - Error deleting file {}", __FUNCTION__, file.GetRedacted());
861 return false;
864 bool CFile::Rename(const std::string& strFileName, const std::string& strNewFileName)
866 const CURL pathToUrl(strFileName);
867 const CURL pathToUrlNew(strNewFileName);
868 return Rename(pathToUrl, pathToUrlNew);
871 bool CFile::Rename(const CURL& file, const CURL& newFile)
875 CURL url(URIUtils::SubstitutePath(file));
876 CURL urlnew(URIUtils::SubstitutePath(newFile));
878 CURL authUrl = url;
879 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
880 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
881 CURL authUrlNew = urlnew;
882 if (CPasswordManager::GetInstance().IsURLSupported(authUrlNew) && authUrlNew.GetUserName().empty())
883 CPasswordManager::GetInstance().AuthenticateURL(authUrlNew);
885 std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url));
886 if (!pFile)
887 return false;
889 if(pFile->Rename(authUrl, authUrlNew))
891 g_directoryCache.ClearFile(url.Get());
892 g_directoryCache.AddFile(urlnew.Get());
893 return true;
896 XBMCCOMMONS_HANDLE_UNCHECKED
897 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception ", __FUNCTION__); }
898 CLog::Log(LOGERROR, "{} - Error renaming file {}", __FUNCTION__, file.GetRedacted());
899 return false;
902 bool CFile::SetHidden(const std::string& fileName, bool hidden)
904 const CURL pathToUrl(fileName);
905 return SetHidden(pathToUrl, hidden);
908 bool CFile::SetHidden(const CURL& file, bool hidden)
912 CURL url(URIUtils::SubstitutePath(file));
913 CURL authUrl = url;
914 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
915 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
917 std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url));
918 if (!pFile)
919 return false;
921 return pFile->SetHidden(authUrl, hidden);
923 catch(...)
925 CLog::Log(LOGERROR, "{}({}) - Unhandled exception", __FUNCTION__, file.GetRedacted());
927 return false;
930 int CFile::IoControl(EIoControl request, void* param)
932 int result = -1;
933 if (!m_pFile)
934 return -1;
935 result = m_pFile->IoControl(request, param);
937 if(result == -1 && request == IOCTRL_SEEK_POSSIBLE)
939 if(m_pFile->GetLength() >= 0 && m_pFile->Seek(0, SEEK_CUR) >= 0)
940 return 1;
941 else
942 return 0;
945 return result;
948 int CFile::GetChunkSize()
950 if (m_pFile)
951 return m_pFile->GetChunkSize();
952 return 0;
955 const std::string CFile::GetProperty(XFILE::FileProperty type, const std::string &name) const
957 if (!m_pFile)
958 return "";
959 return m_pFile->GetProperty(type, name);
962 const std::vector<std::string> CFile::GetPropertyValues(XFILE::FileProperty type, const std::string &name) const
964 if (!m_pFile)
966 return std::vector<std::string>();
968 return m_pFile->GetPropertyValues(type, name);
971 ssize_t CFile::LoadFile(const std::string& filename, std::vector<uint8_t>& outputBuffer)
973 const CURL pathToUrl(filename);
974 return LoadFile(pathToUrl, outputBuffer);
977 ssize_t CFile::LoadFile(const CURL& file, std::vector<uint8_t>& outputBuffer)
979 static const size_t max_file_size = 0x7FFFFFFF;
980 static const size_t min_chunk_size = 64 * 1024U;
981 static const size_t max_chunk_size = 2048 * 1024U;
983 outputBuffer.clear();
985 if (!Open(file, READ_TRUNCATED))
986 return 0;
989 GetLength() will typically return values that fall into three cases:
990 1. The real filesize. This is the typical case.
991 2. Zero. This is the case for some http:// streams for example.
992 3. Some value smaller than the real filesize. This is the case for an expanding file.
994 In order to handle all three cases, we read the file in chunks, relying on Read()
995 returning 0 at EOF. To minimize (re)allocation of the buffer, the chunksize in
996 cases 1 and 3 is set to one byte larger than the value returned by GetLength().
997 The chunksize in case 2 is set to the lowest value larger than min_chunk_size aligned
998 to GetChunkSize().
1000 We fill the buffer entirely before reallocation. Thus, reallocation never occurs in case 1
1001 as the buffer is larger than the file, so we hit EOF before we hit the end of buffer.
1003 To minimize reallocation, we double the chunksize each read while chunksize is lower
1004 than max_chunk_size.
1006 int64_t filesize = GetLength();
1007 if (filesize > (int64_t)max_file_size)
1008 return 0; /* file is too large for this function */
1010 size_t chunksize = (filesize > 0) ? static_cast<size_t>(filesize + 1)
1011 : static_cast<size_t>(DetermineChunkSize(GetChunkSize(),
1012 min_chunk_size));
1013 size_t total_read = 0;
1014 while (true)
1016 if (total_read == outputBuffer.size())
1017 { // (re)alloc
1018 if (outputBuffer.size() + chunksize > max_file_size)
1020 outputBuffer.clear();
1021 return -1;
1023 outputBuffer.resize(outputBuffer.size() + chunksize);
1024 if (chunksize < max_chunk_size)
1025 chunksize *= 2;
1027 ssize_t read = Read(outputBuffer.data() + total_read, outputBuffer.size() - total_read);
1028 if (read < 0)
1030 outputBuffer.clear();
1031 return -1;
1033 total_read += read;
1034 if (!read)
1035 break;
1038 outputBuffer.resize(total_read);
1040 return total_read;
1043 double CFile::GetDownloadSpeed()
1045 if (m_pFile)
1046 return m_pFile->GetDownloadSpeed();
1047 return 0.0;
1050 //*********************************************************************************************
1051 //*************** Stream IO for CFile objects *************************************************
1052 //*********************************************************************************************
1053 CFileStreamBuffer::~CFileStreamBuffer()
1055 sync();
1056 Detach();
1059 CFileStreamBuffer::CFileStreamBuffer(int backsize)
1060 : std::streambuf()
1061 , m_file(NULL)
1062 , m_buffer(NULL)
1063 , m_backsize(backsize)
1067 void CFileStreamBuffer::Attach(IFile *file)
1069 m_file = file;
1071 m_frontsize = CFile::DetermineChunkSize(m_file->GetChunkSize(), 64 * 1024);
1073 m_buffer = new char[m_frontsize+m_backsize];
1074 setg(0,0,0);
1075 setp(0,0);
1078 void CFileStreamBuffer::Detach()
1080 setg(0,0,0);
1081 setp(0,0);
1082 delete[] m_buffer;
1083 m_buffer = NULL;
1086 CFileStreamBuffer::int_type CFileStreamBuffer::underflow()
1088 if(gptr() < egptr())
1089 return traits_type::to_int_type(*gptr());
1091 if(!m_file)
1092 return traits_type::eof();
1094 size_t backsize = 0;
1095 if(m_backsize)
1097 backsize = (size_t)std::min<ptrdiff_t>((ptrdiff_t)m_backsize, egptr()-eback());
1098 memmove(m_buffer, egptr()-backsize, backsize);
1101 ssize_t size = m_file->Read(m_buffer+backsize, m_frontsize);
1103 if (size == 0)
1104 return traits_type::eof();
1105 else if (size < 0)
1107 CLog::LogF(LOGWARNING, "Error reading file - assuming eof");
1108 return traits_type::eof();
1111 setg(m_buffer, m_buffer+backsize, m_buffer+backsize+size);
1112 return traits_type::to_int_type(*gptr());
1115 CFileStreamBuffer::pos_type CFileStreamBuffer::seekoff(
1116 off_type offset,
1117 std::ios_base::seekdir way,
1118 std::ios_base::openmode mode)
1120 // calculate relative offset
1121 off_type aheadbytes = (egptr() - gptr());
1122 off_type pos = m_file->GetPosition() - aheadbytes;
1123 off_type offset2;
1124 if(way == std::ios_base::cur)
1125 offset2 = offset;
1126 else if(way == std::ios_base::beg)
1127 offset2 = offset - pos;
1128 else if(way == std::ios_base::end)
1129 offset2 = offset + m_file->GetLength() - pos;
1130 else
1131 return std::streampos(-1);
1133 // a non seek shouldn't modify our buffer
1134 if(offset2 == 0)
1135 return pos;
1137 // try to seek within buffer
1138 if(gptr()+offset2 >= eback() && gptr()+offset2 < egptr())
1140 gbump(offset2);
1141 return pos + offset2;
1144 // reset our buffer pointer, will
1145 // start buffering on next read
1146 setg(0,0,0);
1147 setp(0,0);
1149 int64_t position = -1;
1150 if(way == std::ios_base::cur)
1151 position = m_file->Seek(offset - aheadbytes, SEEK_CUR);
1152 else if(way == std::ios_base::end)
1153 position = m_file->Seek(offset, SEEK_END);
1154 else
1155 position = m_file->Seek(offset, SEEK_SET);
1157 if(position<0)
1158 return std::streampos(-1);
1160 return position;
1163 CFileStreamBuffer::pos_type CFileStreamBuffer::seekpos(
1164 pos_type pos,
1165 std::ios_base::openmode mode)
1167 return seekoff(pos, std::ios_base::beg, mode);
1170 std::streamsize CFileStreamBuffer::showmanyc()
1172 underflow();
1173 return egptr() - gptr();
1176 CFileStream::CFileStream(int backsize /*= 0*/) : std::istream(&m_buffer), m_buffer(backsize)
1180 CFileStream::~CFileStream()
1182 Close();
1186 bool CFileStream::Open(const CURL& filename)
1188 Close();
1190 CURL url(URIUtils::SubstitutePath(filename));
1191 m_file.reset(CFileFactory::CreateLoader(url));
1193 CURL authUrl = url;
1194 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
1195 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
1197 if(m_file && m_file->Open(authUrl))
1199 m_buffer.Attach(m_file.get());
1200 return true;
1203 setstate(failbit);
1204 return false;
1207 int64_t CFileStream::GetLength()
1209 return m_file->GetLength();
1212 void CFileStream::Close()
1214 if(!m_file)
1215 return;
1217 m_buffer.Detach();
1220 bool CFileStream::Open(const std::string& filename)
1222 const CURL pathToUrl(filename);
1223 return Open(pathToUrl);