[windows] Fix MAC Address Discovery
[xbmc.git] / xbmc / filesystem / File.cpp
blobfe1e60c090692478c24ffd43cd100dd0cdb31837
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/Settings.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 auto settings = CServiceBroker::GetSettingsComponent()->GetSettings();
292 const int cacheBufferMode = (settings)
293 ? settings->GetInt(CSettings::SETTING_FILECACHE_BUFFERMODE)
294 : CACHE_BUFFER_MODE_NETWORK;
296 if ((cacheBufferMode == CACHE_BUFFER_MODE_INTERNET &&
297 URIUtils::IsInternetStream(pathToUrl, true)) ||
298 (cacheBufferMode == CACHE_BUFFER_MODE_TRUE_INTERNET &&
299 URIUtils::IsInternetStream(pathToUrl, false)) ||
300 (cacheBufferMode == CACHE_BUFFER_MODE_NETWORK &&
301 URIUtils::IsNetworkFilesystem(pathToUrl)) ||
302 (cacheBufferMode == CACHE_BUFFER_MODE_ALL &&
303 (URIUtils::IsNetworkFilesystem(pathToUrl) || URIUtils::IsHD(pathToUrl))))
305 m_flags |= READ_CACHED;
309 if (m_flags & READ_CACHED)
311 m_pFile = std::make_unique<CFileCache>(m_flags);
313 if (!m_pFile)
314 return false;
316 return m_pFile->Open(url);
320 m_pFile.reset(CFileFactory::CreateLoader(url));
322 if (!m_pFile)
323 return false;
325 CURL authUrl(url);
326 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
327 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
331 if (!m_pFile->Open(authUrl))
332 return false;
334 catch (CRedirectException *pRedirectEx)
336 // the file implementation decided this item should use a different implementation.
337 // the exception will contain the new implementation.
338 CLog::Log(LOGDEBUG, "File::Open - redirecting implementation for {}", file.GetRedacted());
339 if (pRedirectEx && pRedirectEx->m_pNewFileImp)
341 std::unique_ptr<CURL> pNewUrl(pRedirectEx->m_pNewUrl);
342 m_pFile.reset(pRedirectEx->m_pNewFileImp);
343 delete pRedirectEx;
345 if (pNewUrl)
347 CURL newAuthUrl(*pNewUrl);
348 if (CPasswordManager::GetInstance().IsURLSupported(newAuthUrl) && newAuthUrl.GetUserName().empty())
349 CPasswordManager::GetInstance().AuthenticateURL(newAuthUrl);
351 if (!m_pFile->Open(newAuthUrl))
352 return false;
354 else
356 if (!m_pFile->Open(authUrl))
357 return false;
361 catch (...)
363 CLog::Log(LOGERROR, "File::Open - unknown exception when opening {}", file.GetRedacted());
364 return false;
367 if (ShouldUseStreamBuffer(url))
369 m_pBuffer = std::make_unique<CFileStreamBuffer>(0);
370 m_pBuffer->Attach(m_pFile.get());
373 if (m_flags & READ_BITRATE)
375 m_bitStreamStats = std::make_unique<BitstreamStats>();
376 m_bitStreamStats->Start();
379 return true;
381 XBMCCOMMONS_HANDLE_UNCHECKED
382 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
383 CLog::Log(LOGERROR, "{} - Error opening {}", __FUNCTION__, file.GetRedacted());
384 return false;
387 bool CFile::ShouldUseStreamBuffer(const CURL& url)
389 if (m_flags & READ_CHUNKED || m_pFile->GetChunkSize() > 0)
390 return true;
392 // file size > 200 MB but not in optical disk
393 if (m_pFile->GetLength() > 200 * 1024 * 1024 && !URIUtils::IsDVD(url.GetShareName()))
394 return true;
396 return false;
399 bool CFile::OpenForWrite(const std::string& strFileName, bool bOverWrite)
401 const CURL pathToUrl(strFileName);
402 return OpenForWrite(pathToUrl, bOverWrite);
405 bool CFile::OpenForWrite(const CURL& file, bool bOverWrite)
409 CURL url = URIUtils::SubstitutePath(file);
410 CURL authUrl = url;
411 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
412 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
414 m_pFile.reset(CFileFactory::CreateLoader(url));
416 if (m_pFile && m_pFile->OpenForWrite(authUrl, bOverWrite))
418 // add this file to our directory cache (if it's stored)
419 g_directoryCache.AddFile(url.Get());
420 return true;
422 return false;
424 XBMCCOMMONS_HANDLE_UNCHECKED
425 catch(...)
427 CLog::Log(LOGERROR, "{} - Unhandled exception opening {}", __FUNCTION__, file.GetRedacted());
429 CLog::Log(LOGERROR, "{} - Error opening {}", __FUNCTION__, file.GetRedacted());
430 return false;
433 int CFile::DetermineChunkSize(const int srcChunkSize, const int reqChunkSize)
435 // Determine cache chunk size: if source chunk size is bigger than 1
436 // use source chunk size else use requested chunk size
437 return (srcChunkSize > 1 ? srcChunkSize : reqChunkSize);
440 bool CFile::Exists(const std::string& strFileName, bool bUseCache /* = true */)
442 const CURL pathToUrl(strFileName);
443 return Exists(pathToUrl, bUseCache);
446 bool CFile::Exists(const CURL& file, bool bUseCache /* = true */)
448 CURL url(URIUtils::SubstitutePath(file));
449 CURL authUrl = url;
450 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
451 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
455 if (bUseCache)
457 bool bPathInCache;
458 if (g_directoryCache.FileExists(url.Get(), bPathInCache))
459 return true;
460 if (bPathInCache)
461 return false;
464 std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url));
465 if (!pFile)
466 return false;
468 return pFile->Exists(authUrl);
470 XBMCCOMMONS_HANDLE_UNCHECKED
471 catch (CRedirectException *pRedirectEx)
473 // the file implementation decided this item should use a different implementation.
474 // the exception will contain the new implementation and optional a redirected URL.
475 CLog::Log(LOGDEBUG, "File::Exists - redirecting implementation for {}", file.GetRedacted());
476 if (pRedirectEx && pRedirectEx->m_pNewFileImp)
478 std::unique_ptr<IFile> pImp(pRedirectEx->m_pNewFileImp);
479 std::unique_ptr<CURL> pNewUrl(pRedirectEx->m_pNewUrl);
480 delete pRedirectEx;
482 if (pImp)
484 if (pNewUrl)
486 if (bUseCache)
488 bool bPathInCache;
489 if (g_directoryCache.FileExists(pNewUrl->Get(), bPathInCache))
490 return true;
491 if (bPathInCache)
492 return false;
494 CURL newAuthUrl = *pNewUrl;
495 if (CPasswordManager::GetInstance().IsURLSupported(newAuthUrl) && newAuthUrl.GetUserName().empty())
496 CPasswordManager::GetInstance().AuthenticateURL(newAuthUrl);
498 return pImp->Exists(newAuthUrl);
500 else
502 return pImp->Exists(authUrl);
507 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
508 CLog::Log(LOGERROR, "{} - Error checking for {}", __FUNCTION__, file.GetRedacted());
509 return false;
512 int CFile::Stat(struct __stat64 *buffer)
514 if (!buffer)
515 return -1;
517 if (!m_pFile)
519 *buffer = {};
520 errno = ENOENT;
521 return -1;
524 return m_pFile->Stat(buffer);
527 int CFile::Stat(const std::string& strFileName, struct __stat64* buffer)
529 const CURL pathToUrl(strFileName);
530 return Stat(pathToUrl, buffer);
533 int CFile::Stat(const CURL& file, struct __stat64* buffer)
535 if (!buffer)
536 return -1;
538 CURL url(URIUtils::SubstitutePath(file));
539 CURL authUrl = url;
540 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
541 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
545 std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url));
546 if (!pFile)
547 return -1;
548 return pFile->Stat(authUrl, buffer);
550 XBMCCOMMONS_HANDLE_UNCHECKED
551 catch (CRedirectException *pRedirectEx)
553 // the file implementation decided this item should use a different implementation.
554 // the exception will contain the new implementation and optional a redirected URL.
555 CLog::Log(LOGDEBUG, "File::Stat - redirecting implementation for {}", file.GetRedacted());
556 if (pRedirectEx && pRedirectEx->m_pNewFileImp)
558 std::unique_ptr<IFile> pImp(pRedirectEx->m_pNewFileImp);
559 std::unique_ptr<CURL> pNewUrl(pRedirectEx->m_pNewUrl);
560 delete pRedirectEx;
562 if (pNewUrl)
564 if (pImp)
566 CURL newAuthUrl = *pNewUrl;
567 if (CPasswordManager::GetInstance().IsURLSupported(newAuthUrl) && newAuthUrl.GetUserName().empty())
568 CPasswordManager::GetInstance().AuthenticateURL(newAuthUrl);
570 if (!pImp->Stat(newAuthUrl, buffer))
572 return 0;
576 else
578 if (pImp.get() && !pImp->Stat(authUrl, buffer))
580 return 0;
585 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
586 CLog::Log(LOGERROR, "{} - Error statting {}", __FUNCTION__, file.GetRedacted());
587 return -1;
590 ssize_t CFile::Read(void *lpBuf, size_t uiBufSize)
592 if (!m_pFile)
593 return -1;
594 if (lpBuf == NULL && uiBufSize != 0)
595 return -1;
597 if (uiBufSize > SSIZE_MAX)
598 uiBufSize = SSIZE_MAX;
600 if (uiBufSize == 0)
602 // "test" read with zero size
603 // some VFSs don't handle correctly null buffer pointer
604 // provide valid buffer pointer for them
605 char dummy;
606 return m_pFile->Read(&dummy, 0);
609 if(m_pBuffer)
611 if(m_flags & READ_TRUNCATED)
613 const ssize_t nBytes = m_pBuffer->sgetn(
614 (char *)lpBuf, std::min<std::streamsize>((std::streamsize)uiBufSize,
615 m_pBuffer->in_avail()));
616 if (m_bitStreamStats && nBytes>0)
617 m_bitStreamStats->AddSampleBytes(nBytes);
618 return nBytes;
620 else
622 const ssize_t nBytes = m_pBuffer->sgetn((char*)lpBuf, uiBufSize);
623 if (m_bitStreamStats && nBytes>0)
624 m_bitStreamStats->AddSampleBytes(nBytes);
625 return nBytes;
631 if(m_flags & READ_TRUNCATED)
633 const ssize_t nBytes = m_pFile->Read(lpBuf, uiBufSize);
634 if (m_bitStreamStats && nBytes>0)
635 m_bitStreamStats->AddSampleBytes(nBytes);
636 return nBytes;
638 else
640 ssize_t done = 0;
641 while((uiBufSize-done) > 0)
643 const ssize_t curr = m_pFile->Read((char*)lpBuf+done, uiBufSize-done);
644 if (curr <= 0)
646 if (curr < 0 && done == 0)
647 return -1;
649 break;
651 done+=curr;
653 if (m_bitStreamStats && done > 0)
654 m_bitStreamStats->AddSampleBytes(done);
655 return done;
658 XBMCCOMMONS_HANDLE_UNCHECKED
659 catch(...)
661 CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__);
662 return -1;
664 return 0;
667 //*********************************************************************************************
668 void CFile::Close()
672 if (m_pFile)
673 m_pFile->Close();
675 m_pBuffer.reset();
676 m_pFile.reset();
678 XBMCCOMMONS_HANDLE_UNCHECKED
679 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
682 void CFile::Flush()
686 if (m_pFile)
687 m_pFile->Flush();
689 XBMCCOMMONS_HANDLE_UNCHECKED
690 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
693 //*********************************************************************************************
694 int64_t CFile::Seek(int64_t iFilePosition, int iWhence)
696 if (!m_pFile)
697 return -1;
699 if (m_pBuffer)
701 if(iWhence == SEEK_CUR)
702 return m_pBuffer->pubseekoff(iFilePosition, std::ios_base::cur);
703 else if(iWhence == SEEK_END)
704 return m_pBuffer->pubseekoff(iFilePosition, std::ios_base::end);
705 else if(iWhence == SEEK_SET)
706 return m_pBuffer->pubseekoff(iFilePosition, std::ios_base::beg);
711 return m_pFile->Seek(iFilePosition, iWhence);
713 XBMCCOMMONS_HANDLE_UNCHECKED
714 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
715 return -1;
718 //*********************************************************************************************
719 int CFile::Truncate(int64_t iSize)
721 if (!m_pFile)
722 return -1;
726 return m_pFile->Truncate(iSize);
728 XBMCCOMMONS_HANDLE_UNCHECKED
729 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
730 return -1;
733 //*********************************************************************************************
734 int64_t CFile::GetLength()
738 if (m_pFile)
739 return m_pFile->GetLength();
740 return 0;
742 XBMCCOMMONS_HANDLE_UNCHECKED
743 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
744 return 0;
747 //*********************************************************************************************
748 int64_t CFile::GetPosition() const
750 if (!m_pFile)
751 return -1;
753 if (m_pBuffer)
754 return m_pBuffer->pubseekoff(0, std::ios_base::cur);
758 return m_pFile->GetPosition();
760 XBMCCOMMONS_HANDLE_UNCHECKED
761 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
762 return -1;
766 //*********************************************************************************************
767 bool CFile::ReadString(char *szLine, int iLineLength)
769 if (!m_pFile || !szLine)
770 return false;
772 if (m_pBuffer)
774 typedef CFileStreamBuffer::traits_type traits;
775 CFileStreamBuffer::int_type aByte = m_pBuffer->sgetc();
777 if(aByte == traits::eof())
778 return false;
780 while(iLineLength>0)
782 aByte = m_pBuffer->sbumpc();
784 if(aByte == traits::eof())
785 break;
787 if(aByte == traits::to_int_type('\n'))
789 if(m_pBuffer->sgetc() == traits::to_int_type('\r'))
790 m_pBuffer->sbumpc();
791 break;
794 if(aByte == traits::to_int_type('\r'))
796 if(m_pBuffer->sgetc() == traits::to_int_type('\n'))
797 m_pBuffer->sbumpc();
798 break;
801 *szLine = traits::to_char_type(aByte);
802 szLine++;
803 iLineLength--;
806 // if we have no space for terminating character we failed
807 if(iLineLength==0)
808 return false;
810 *szLine = 0;
812 return true;
817 return m_pFile->ReadString(szLine, iLineLength);
819 XBMCCOMMONS_HANDLE_UNCHECKED
820 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
821 return false;
824 ssize_t CFile::Write(const void* lpBuf, size_t uiBufSize)
826 if (!m_pFile)
827 return -1;
828 if (lpBuf == NULL && uiBufSize != 0)
829 return -1;
833 if (uiBufSize == 0 && lpBuf == NULL)
834 { // "test" write with zero size
835 // some VFSs don't handle correctly null buffer pointer
836 // provide valid buffer pointer for them
837 const char dummyBuf = 0;
838 return m_pFile->Write(&dummyBuf, 0);
841 return m_pFile->Write(lpBuf, uiBufSize);
843 XBMCCOMMONS_HANDLE_UNCHECKED
844 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
845 return -1;
848 bool CFile::Delete(const std::string& strFileName)
850 const CURL pathToUrl(strFileName);
851 return Delete(pathToUrl);
854 bool CFile::Delete(const CURL& file)
858 CURL url(URIUtils::SubstitutePath(file));
859 CURL authUrl = url;
860 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
861 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
863 std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url));
864 if (!pFile)
865 return false;
867 if(pFile->Delete(authUrl))
869 g_directoryCache.ClearFile(url.Get());
870 return true;
873 XBMCCOMMONS_HANDLE_UNCHECKED
874 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
875 if (Exists(file))
876 CLog::Log(LOGERROR, "{} - Error deleting file {}", __FUNCTION__, file.GetRedacted());
877 return false;
880 bool CFile::Rename(const std::string& strFileName, const std::string& strNewFileName)
882 const CURL pathToUrl(strFileName);
883 const CURL pathToUrlNew(strNewFileName);
884 return Rename(pathToUrl, pathToUrlNew);
887 bool CFile::Rename(const CURL& file, const CURL& newFile)
891 CURL url(URIUtils::SubstitutePath(file));
892 CURL urlnew(URIUtils::SubstitutePath(newFile));
894 CURL authUrl = url;
895 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
896 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
897 CURL authUrlNew = urlnew;
898 if (CPasswordManager::GetInstance().IsURLSupported(authUrlNew) && authUrlNew.GetUserName().empty())
899 CPasswordManager::GetInstance().AuthenticateURL(authUrlNew);
901 std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url));
902 if (!pFile)
903 return false;
905 if(pFile->Rename(authUrl, authUrlNew))
907 g_directoryCache.ClearFile(url.Get());
908 g_directoryCache.AddFile(urlnew.Get());
909 return true;
912 XBMCCOMMONS_HANDLE_UNCHECKED
913 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception ", __FUNCTION__); }
914 CLog::Log(LOGERROR, "{} - Error renaming file {}", __FUNCTION__, file.GetRedacted());
915 return false;
918 bool CFile::SetHidden(const std::string& fileName, bool hidden)
920 const CURL pathToUrl(fileName);
921 return SetHidden(pathToUrl, hidden);
924 bool CFile::SetHidden(const CURL& file, bool hidden)
928 CURL url(URIUtils::SubstitutePath(file));
929 CURL authUrl = url;
930 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
931 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
933 std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url));
934 if (!pFile)
935 return false;
937 return pFile->SetHidden(authUrl, hidden);
939 catch(...)
941 CLog::Log(LOGERROR, "{}({}) - Unhandled exception", __FUNCTION__, file.GetRedacted());
943 return false;
946 int CFile::IoControl(EIoControl request, void* param)
948 int result = -1;
949 if (!m_pFile)
950 return -1;
951 result = m_pFile->IoControl(request, param);
953 if(result == -1 && request == IOCTRL_SEEK_POSSIBLE)
955 if(m_pFile->GetLength() >= 0 && m_pFile->Seek(0, SEEK_CUR) >= 0)
956 return 1;
957 else
958 return 0;
961 return result;
964 int CFile::GetChunkSize()
966 if (m_pFile)
967 return m_pFile->GetChunkSize();
968 return 0;
971 const std::string CFile::GetProperty(XFILE::FileProperty type, const std::string &name) const
973 if (!m_pFile)
974 return "";
975 return m_pFile->GetProperty(type, name);
978 const std::vector<std::string> CFile::GetPropertyValues(XFILE::FileProperty type, const std::string &name) const
980 if (!m_pFile)
982 return std::vector<std::string>();
984 return m_pFile->GetPropertyValues(type, name);
987 ssize_t CFile::LoadFile(const std::string& filename, std::vector<uint8_t>& outputBuffer)
989 const CURL pathToUrl(filename);
990 return LoadFile(pathToUrl, outputBuffer);
993 ssize_t CFile::LoadFile(const CURL& file, std::vector<uint8_t>& outputBuffer)
995 static const size_t max_file_size = 0x7FFFFFFF;
996 static const size_t min_chunk_size = 64 * 1024U;
997 static const size_t max_chunk_size = 2048 * 1024U;
999 outputBuffer.clear();
1001 if (!Open(file, READ_TRUNCATED))
1002 return 0;
1005 GetLength() will typically return values that fall into three cases:
1006 1. The real filesize. This is the typical case.
1007 2. Zero. This is the case for some http:// streams for example.
1008 3. Some value smaller than the real filesize. This is the case for an expanding file.
1010 In order to handle all three cases, we read the file in chunks, relying on Read()
1011 returning 0 at EOF. To minimize (re)allocation of the buffer, the chunksize in
1012 cases 1 and 3 is set to one byte larger than the value returned by GetLength().
1013 The chunksize in case 2 is set to the lowest value larger than min_chunk_size aligned
1014 to GetChunkSize().
1016 We fill the buffer entirely before reallocation. Thus, reallocation never occurs in case 1
1017 as the buffer is larger than the file, so we hit EOF before we hit the end of buffer.
1019 To minimize reallocation, we double the chunksize each read while chunksize is lower
1020 than max_chunk_size.
1022 int64_t filesize = GetLength();
1023 if (filesize > (int64_t)max_file_size)
1024 return 0; /* file is too large for this function */
1026 size_t chunksize = (filesize > 0) ? static_cast<size_t>(filesize + 1)
1027 : static_cast<size_t>(DetermineChunkSize(GetChunkSize(),
1028 min_chunk_size));
1029 size_t total_read = 0;
1030 while (true)
1032 if (total_read == outputBuffer.size())
1033 { // (re)alloc
1034 if (outputBuffer.size() + chunksize > max_file_size)
1036 outputBuffer.clear();
1037 return -1;
1039 outputBuffer.resize(outputBuffer.size() + chunksize);
1040 if (chunksize < max_chunk_size)
1041 chunksize *= 2;
1043 ssize_t read = Read(outputBuffer.data() + total_read, outputBuffer.size() - total_read);
1044 if (read < 0)
1046 outputBuffer.clear();
1047 return -1;
1049 total_read += read;
1050 if (!read)
1051 break;
1054 outputBuffer.resize(total_read);
1056 return total_read;
1059 double CFile::GetDownloadSpeed()
1061 if (m_pFile)
1062 return m_pFile->GetDownloadSpeed();
1063 return 0.0;
1066 //*********************************************************************************************
1067 //*************** Stream IO for CFile objects *************************************************
1068 //*********************************************************************************************
1069 CFileStreamBuffer::~CFileStreamBuffer()
1071 sync();
1072 Detach();
1075 CFileStreamBuffer::CFileStreamBuffer(int backsize)
1076 : std::streambuf()
1077 , m_file(NULL)
1078 , m_buffer(NULL)
1079 , m_backsize(backsize)
1083 void CFileStreamBuffer::Attach(IFile *file)
1085 m_file = file;
1087 m_frontsize = CFile::DetermineChunkSize(m_file->GetChunkSize(), 64 * 1024);
1089 m_buffer = new char[m_frontsize+m_backsize];
1090 setg(0,0,0);
1091 setp(0,0);
1094 void CFileStreamBuffer::Detach()
1096 setg(0,0,0);
1097 setp(0,0);
1098 delete[] m_buffer;
1099 m_buffer = NULL;
1102 CFileStreamBuffer::int_type CFileStreamBuffer::underflow()
1104 if(gptr() < egptr())
1105 return traits_type::to_int_type(*gptr());
1107 if(!m_file)
1108 return traits_type::eof();
1110 size_t backsize = 0;
1111 if(m_backsize)
1113 backsize = (size_t)std::min<ptrdiff_t>((ptrdiff_t)m_backsize, egptr()-eback());
1114 memmove(m_buffer, egptr()-backsize, backsize);
1117 ssize_t size = m_file->Read(m_buffer+backsize, m_frontsize);
1119 if (size == 0)
1120 return traits_type::eof();
1121 else if (size < 0)
1123 CLog::LogF(LOGWARNING, "Error reading file - assuming eof");
1124 return traits_type::eof();
1127 setg(m_buffer, m_buffer+backsize, m_buffer+backsize+size);
1128 return traits_type::to_int_type(*gptr());
1131 CFileStreamBuffer::pos_type CFileStreamBuffer::seekoff(
1132 off_type offset,
1133 std::ios_base::seekdir way,
1134 std::ios_base::openmode mode)
1136 // calculate relative offset
1137 off_type aheadbytes = (egptr() - gptr());
1138 off_type pos = m_file->GetPosition() - aheadbytes;
1139 off_type offset2;
1140 if(way == std::ios_base::cur)
1141 offset2 = offset;
1142 else if(way == std::ios_base::beg)
1143 offset2 = offset - pos;
1144 else if(way == std::ios_base::end)
1145 offset2 = offset + m_file->GetLength() - pos;
1146 else
1147 return std::streampos(-1);
1149 // a non seek shouldn't modify our buffer
1150 if(offset2 == 0)
1151 return pos;
1153 // try to seek within buffer
1154 if(gptr()+offset2 >= eback() && gptr()+offset2 < egptr())
1156 gbump(offset2);
1157 return pos + offset2;
1160 // reset our buffer pointer, will
1161 // start buffering on next read
1162 setg(0,0,0);
1163 setp(0,0);
1165 int64_t position = -1;
1166 if(way == std::ios_base::cur)
1167 position = m_file->Seek(offset - aheadbytes, SEEK_CUR);
1168 else if(way == std::ios_base::end)
1169 position = m_file->Seek(offset, SEEK_END);
1170 else
1171 position = m_file->Seek(offset, SEEK_SET);
1173 if(position<0)
1174 return std::streampos(-1);
1176 return position;
1179 CFileStreamBuffer::pos_type CFileStreamBuffer::seekpos(
1180 pos_type pos,
1181 std::ios_base::openmode mode)
1183 return seekoff(pos, std::ios_base::beg, mode);
1186 std::streamsize CFileStreamBuffer::showmanyc()
1188 underflow();
1189 return egptr() - gptr();
1192 CFileStream::CFileStream(int backsize /*= 0*/) : std::istream(&m_buffer), m_buffer(backsize)
1196 CFileStream::~CFileStream()
1198 Close();
1202 bool CFileStream::Open(const CURL& filename)
1204 Close();
1206 CURL url(URIUtils::SubstitutePath(filename));
1207 m_file.reset(CFileFactory::CreateLoader(url));
1209 CURL authUrl = url;
1210 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
1211 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
1213 if(m_file && m_file->Open(authUrl))
1215 m_buffer.Attach(m_file.get());
1216 return true;
1219 setstate(failbit);
1220 return false;
1223 int64_t CFileStream::GetLength()
1225 return m_file->GetLength();
1228 void CFileStream::Close()
1230 if(!m_file)
1231 return;
1233 m_buffer.Detach();
1236 bool CFileStream::Open(const std::string& filename)
1238 const CURL pathToUrl(filename);
1239 return Open(pathToUrl);