2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
20 #include "network/Network.h"
21 #include "threads/SystemClock.h"
23 #if defined(TARGET_DARWIN)
24 #include <sys/param.h>
25 #include <mach-o/dyld.h>
28 #if defined(TARGET_FREEBSD)
29 #include <sys/param.h>
30 #include <sys/sysctl.h>
34 #include <sys/types.h>
39 #if defined(TARGET_ANDROID)
40 #include "android/bionic_supplement/bionic_supplement.h"
44 #include "Application.h"
46 #include "addons/Addon.h"
47 #include "filesystem/PVRDirectory.h"
48 #include "filesystem/Directory.h"
49 #include "filesystem/StackDirectory.h"
50 #include "filesystem/MultiPathDirectory.h"
51 #include "filesystem/SpecialProtocol.h"
52 #include "filesystem/RSSDirectory.h"
53 #ifdef HAS_FILESYSTEM_RAR
54 #include "filesystem/RarManager.h"
56 #include "filesystem/MythDirectory.h"
58 #include "filesystem/UPnPDirectory.h"
60 #include "profiles/ProfilesManager.h"
61 #include "utils/RegExp.h"
62 #include "guilib/GraphicContext.h"
63 #include "guilib/TextureManager.h"
64 #include "utils/fstrcmp.h"
65 #include "storage/MediaManager.h"
67 #include "utils/CharsetConverter.h"
69 #include "WIN32Util.h"
71 #if defined(TARGET_DARWIN)
72 #include "osx/DarwinUtils.h"
74 #include "GUIUserMessages.h"
75 #include "filesystem/File.h"
76 #include "settings/MediaSettings.h"
77 #include "settings/Settings.h"
78 #include "utils/StringUtils.h"
79 #include "settings/AdvancedSettings.h"
80 #ifdef HAS_IRSERVERSUITE
81 #include "input/windows/IRServerSuite.h"
83 #include "guilib/LocalizeStrings.h"
84 #include "utils/md5.h"
85 #include "utils/TimeUtils.h"
86 #include "utils/URIUtils.h"
87 #include "utils/log.h"
88 #include "utils/Environment.h"
90 #include "cores/dvdplayer/DVDSubtitles/DVDSubtitleTagSami.h"
91 #include "cores/dvdplayer/DVDSubtitles/DVDSubtitleStream.h"
93 #include "utils/LangCodeExpander.h"
95 #include <sys/capability.h>
98 #include "cores/dvdplayer/DVDDemuxers/DVDDemux.h"
103 using namespace MEDIA_DETECT;
106 #define clamp(x) (x) > 255.f ? 255 : ((x) < 0 ? 0 : (BYTE)(x+0.5f)) // Valid ranges: brightness[-1 -> 1 (0 is default)] contrast[0 -> 2 (1 is default)] gamma[0.5 -> 3.5 (1 is default)] default[ramp is linear]
107 static const int64_t SECS_BETWEEN_EPOCHS = 11644473600LL;
108 static const int64_t SECS_TO_100NS = 10000000;
110 using namespace XFILE;
111 using namespace PLAYLIST;
114 static D3DGAMMARAMP oldramp, flashramp;
115 #elif defined(HAS_SDL_2D)
116 static uint16_t oldrampRed[256];
117 static uint16_t oldrampGreen[256];
118 static uint16_t oldrampBlue[256];
119 static uint16_t flashrampRed[256];
120 static uint16_t flashrampGreen[256];
121 static uint16_t flashrampBlue[256];
124 #if !defined(TARGET_WINDOWS)
125 unsigned int CUtil::s_randomSeed = time(NULL);
135 CStdString CUtil::GetTitleFromPath(const CStdString& strFileNameAndPath, bool bIsFolder /* = false */)
137 CURL pathToUrl(strFileNameAndPath);
138 return GetTitleFromPath(pathToUrl, bIsFolder);
141 CStdString CUtil::GetTitleFromPath(const CURL& url, bool bIsFolder /* = false */)
143 // use above to get the filename
144 CStdString path(url.Get());
145 URIUtils::RemoveSlashAtEnd(path);
146 CStdString strFilename = URIUtils::GetFileName(path);
148 CStdString strHostname = url.GetHostName();
152 if (url.IsProtocol("upnp"))
153 strFilename = CUPnPDirectory::GetFriendlyName(url);
156 if (url.IsProtocol("rss"))
160 if(dir.GetDirectory(url, items) && !items.m_strTitle.empty())
161 return items.m_strTitle;
165 else if (url.IsProtocol("shout"))
167 const CStdString strFileNameAndPath = url.Get();
168 const int genre = strFileNameAndPath.find_first_of('=');
170 strFilename = g_localizeStrings.Get(260);
172 strFilename = g_localizeStrings.Get(260) + " - " + strFileNameAndPath.substr(genre+1).c_str();
175 // Windows SMB Network (SMB)
176 else if (url.IsProtocol("smb") && strFilename.empty())
178 if (url.GetHostName().empty())
180 strFilename = g_localizeStrings.Get(20171);
184 strFilename = url.GetHostName();
187 // iTunes music share (DAAP)
188 else if (url.IsProtocol("daap") && strFilename.empty())
189 strFilename = g_localizeStrings.Get(20174);
192 else if (url.IsProtocol("hdhomerun") && strFilename.empty())
193 strFilename = "HDHomerun Devices";
196 else if (url.IsProtocol("sling"))
197 strFilename = "Slingbox";
200 else if (url.IsProtocol("rtv"))
201 strFilename = "ReplayTV Devices";
203 // HTS Tvheadend client
204 else if (url.IsProtocol("htsp"))
205 strFilename = g_localizeStrings.Get(20256);
207 // VDR Streamdev client
208 else if (url.IsProtocol("vtp"))
209 strFilename = g_localizeStrings.Get(20257);
212 else if (url.IsProtocol("myth"))
213 strFilename = g_localizeStrings.Get(20258);
216 else if (url.IsProtocol("sap") && strFilename.empty())
217 strFilename = "SAP Streams";
220 else if (url.IsProtocol("sources"))
221 strFilename = g_localizeStrings.Get(744);
224 else if (URIUtils::PathStarts(path, "special://musicplaylists"))
225 strFilename = g_localizeStrings.Get(136);
228 else if (URIUtils::PathStarts(path, "special://videoplaylists"))
229 strFilename = g_localizeStrings.Get(136);
231 else if (URIUtils::HasParentInHostname(url) && strFilename.empty())
232 strFilename = URIUtils::GetFileName(url.GetHostName());
234 // now remove the extension if needed
235 if (!CSettings::Get().GetBool("filelists.showextensions") && !bIsFolder)
237 URIUtils::RemoveExtension(strFilename);
241 // URLDecode since the original path may be an URL
242 strFilename = CURL::Decode(strFilename);
246 void CUtil::CleanString(const std::string& strFileName,
247 std::string& strTitle,
248 std::string& strTitleAndYear,
249 std::string& strYear,
250 bool bRemoveExtension /* = false */,
251 bool bCleanChars /* = true */)
253 strTitleAndYear = strFileName;
255 if (strFileName == "..")
258 const vector<string> ®exps = g_advancedSettings.m_videoCleanStringRegExps;
260 CRegExp reTags(true, CRegExp::autoUtf8);
261 CRegExp reYear(false, CRegExp::autoUtf8);
263 if (!reYear.RegComp(g_advancedSettings.m_videoCleanDateTimeRegExp))
265 CLog::Log(LOGERROR, "%s: Invalid datetime clean RegExp:'%s'", __FUNCTION__, g_advancedSettings.m_videoCleanDateTimeRegExp.c_str());
269 if (reYear.RegFind(strTitleAndYear.c_str()) >= 0)
271 strTitleAndYear = reYear.GetMatch(1);
272 strYear = reYear.GetMatch(2);
276 URIUtils::RemoveExtension(strTitleAndYear);
278 for (unsigned int i = 0; i < regexps.size(); i++)
280 if (!reTags.RegComp(regexps[i].c_str()))
281 { // invalid regexp - complain in logs
282 CLog::Log(LOGERROR, "%s: Invalid string clean RegExp:'%s'", __FUNCTION__, regexps[i].c_str());
286 if ((j=reTags.RegFind(strTitleAndYear.c_str())) > 0)
287 strTitleAndYear = strTitleAndYear.substr(0, j);
290 // final cleanup - special characters used instead of spaces:
291 // all '_' tokens should be replaced by spaces
292 // if the file contains no spaces, all '.' tokens should be replaced by
293 // spaces - one possibility of a mistake here could be something like:
294 // "Dr..StrangeLove" - hopefully no one would have anything like this.
297 bool initialDots = true;
298 bool alreadyContainsSpace = (strTitleAndYear.find(' ') != std::string::npos);
300 for (size_t i = 0; i < strTitleAndYear.size(); i++)
302 char c = strTitleAndYear[i];
307 if ((c == '_') || ((!alreadyContainsSpace) && !initialDots && (c == '.')))
309 strTitleAndYear[i] = ' ';
314 StringUtils::Trim(strTitleAndYear);
315 strTitle = strTitleAndYear;
318 if (!strYear.empty())
319 strTitleAndYear = strTitle + " (" + strYear + ")";
321 // restore extension if needed
322 if (!bRemoveExtension)
323 strTitleAndYear += URIUtils::GetExtension(strFileName);
326 void CUtil::GetQualifiedFilename(const std::string &strBasePath, std::string &strFilename)
328 // Check if the filename is a fully qualified URL such as protocol://path/to/file
329 CURL plItemUrl(strFilename);
330 if (!plItemUrl.GetProtocol().empty())
333 // If the filename starts "x:", "\\" or "/" it's already fully qualified so return
334 if (strFilename.size() > 1)
336 if ( (strFilename[1] == ':') || (strFilename[0] == '/') )
338 if ( strFilename[1] == ':' || (strFilename[0] == '\\' && strFilename[1] == '\\'))
342 // add to base path and then clean
343 strFilename = URIUtils::AddFileToFolder(strBasePath, strFilename);
345 // get rid of any /./ or \.\ that happen to be there
346 StringUtils::Replace(strFilename, "\\.\\", "\\");
347 StringUtils::Replace(strFilename, "/./", "/");
349 // now find any "\\..\\" and remove them via GetParentPath
351 while ((pos = strFilename.find("/../")) != std::string::npos)
353 CStdString basePath = strFilename.substr(0, pos + 1);
354 strFilename.erase(0, pos + 4);
355 basePath = URIUtils::GetParentPath(basePath);
356 strFilename = URIUtils::AddFileToFolder(basePath, strFilename);
358 while ((pos = strFilename.find("\\..\\")) != std::string::npos)
360 CStdString basePath = strFilename.substr(0, pos + 1);
361 strFilename.erase(0, pos + 4);
362 basePath = URIUtils::GetParentPath(basePath);
363 strFilename = URIUtils::AddFileToFolder(basePath, strFilename);
368 bool CUtil::TestGetQualifiedFilename()
370 CStdString file = "../foo"; GetQualifiedFilename("smb://", file);
371 if (file != "foo") return false;
372 file = "C:\\foo\\bar"; GetQualifiedFilename("smb://", file);
373 if (file != "C:\\foo\\bar") return false;
374 file = "../foo/./bar"; GetQualifiedFilename("smb://my/path", file);
375 if (file != "smb://my/foo/bar") return false;
376 file = "smb://foo/bar/"; GetQualifiedFilename("upnp://", file);
377 if (file != "smb://foo/bar/") return false;
381 bool CUtil::TestMakeLegalPath()
384 #ifdef TARGET_WINDOWS
385 path = "C:\\foo\\bar"; path = MakeLegalPath(path);
386 if (path != "C:\\foo\\bar") return false;
387 path = "C:\\foo:\\bar\\"; path = MakeLegalPath(path);
388 if (path != "C:\\foo_\\bar\\") return false;
390 path = "/foo/bar/"; path = MakeLegalPath(path);
391 if (path != "/foo/bar/") return false;
392 path = "/foo?/bar"; path = MakeLegalPath(path);
393 if (path != "/foo_/bar") return false;
395 path = "smb://foo/bar"; path = MakeLegalPath(path);
396 if (path != "smb://foo/bar") return false;
397 path = "smb://foo/bar?/"; path = MakeLegalPath(path);
398 if (path != "smb://foo/bar_/") return false;
403 void CUtil::RunShortcut(const char* szShortcutPath)
407 void CUtil::GetHomePath(std::string& strPath, const std::string& strTarget)
409 strPath = CEnvironment::getenv(strTarget);
411 #ifdef TARGET_WINDOWS
412 if (strPath.find("..") != std::string::npos)
414 //expand potential relative path to full path
415 CStdStringW strPathW;
416 g_charsetConverter.utf8ToW(strPath, strPathW, false);
417 CWIN32Util::AddExtraLongPathPrefix(strPathW);
418 const unsigned int bufSize = GetFullPathNameW(strPathW, 0, NULL, NULL);
421 wchar_t * buf = new wchar_t[bufSize];
422 if (GetFullPathNameW(strPathW, bufSize, buf, NULL) <= bufSize-1)
424 std::wstring expandedPathW(buf);
425 CWIN32Util::RemoveExtraLongPathPrefix(expandedPathW);
426 g_charsetConverter.wToUTF8(expandedPathW, strPath);
436 std::string strHomePath = ResolveExecutablePath();
437 #if defined(TARGET_DARWIN)
439 char given_path[2*MAXPATHLEN];
440 uint32_t path_size =2*MAXPATHLEN;
442 result = GetDarwinExecutablePath(given_path, &path_size);
445 // Move backwards to last /.
446 for (int n=strlen(given_path)-1; given_path[n] != '/'; n--)
447 given_path[n] = '\0';
449 #if defined(TARGET_DARWIN_IOS)
450 strcat(given_path, "/XBMCData/XBMCHome/");
452 // Assume local path inside application bundle.
453 strcat(given_path, "../Resources/XBMC/");
456 // Convert to real path.
457 char real_path[2*MAXPATHLEN];
458 if (realpath(given_path, real_path) != NULL)
465 size_t last_sep = strHomePath.find_last_of(PATH_SEPARATOR_CHAR);
466 if (last_sep != string::npos)
467 strPath = strHomePath.substr(0, last_sep);
469 strPath = strHomePath;
472 #if defined(TARGET_POSIX) && !defined(TARGET_DARWIN)
473 /* Change strPath accordingly when target is XBMC_HOME and when INSTALL_PATH
474 * and BIN_INSTALL_PATH differ
476 std::string installPath = INSTALL_PATH;
477 std::string binInstallPath = BIN_INSTALL_PATH;
478 if (!strTarget.compare("XBMC_HOME") && installPath.compare(binInstallPath))
480 int pos = strPath.length() - binInstallPath.length();
481 CStdString tmp = strPath;
483 if (!tmp.compare(binInstallPath))
485 strPath.erase(pos, strPath.length());
486 strPath.append(installPath);
492 bool CUtil::IsPVR(const CStdString& strFile)
494 return StringUtils::StartsWithNoCase(strFile, "pvr:");
497 bool CUtil::IsHTSP(const CStdString& strFile)
499 return StringUtils::StartsWithNoCase(strFile, "htsp:");
502 bool CUtil::IsLiveTV(const CStdString& strFile)
504 if (StringUtils::StartsWithNoCase(strFile, "pvr://channels"))
507 if(URIUtils::IsTuxBox(strFile)
508 || URIUtils::IsVTP(strFile)
509 || URIUtils::IsHDHomeRun(strFile)
510 || URIUtils::IsHTSP(strFile)
511 || StringUtils::StartsWithNoCase(strFile, "sap:"))
514 if (URIUtils::IsMythTV(strFile) && CMythDirectory::IsLiveTV(strFile))
520 bool CUtil::IsTVRecording(const CStdString& strFile)
522 return StringUtils::StartsWithNoCase(strFile, "pvr://recording");
525 bool CUtil::IsPicture(const CStdString& strFile)
527 return URIUtils::HasExtension(strFile,
528 g_advancedSettings.m_pictureExtensions + "|.tbn|.dds");
531 bool CUtil::ExcludeFileOrFolder(const CStdString& strFileOrFolder, const vector<string>& regexps)
533 if (strFileOrFolder.empty())
536 CRegExp regExExcludes(true, CRegExp::autoUtf8); // case insensitive regex
538 for (unsigned int i = 0; i < regexps.size(); i++)
540 if (!regExExcludes.RegComp(regexps[i].c_str()))
541 { // invalid regexp - complain in logs
542 CLog::Log(LOGERROR, "%s: Invalid exclude RegExp:'%s'", __FUNCTION__, regexps[i].c_str());
545 if (regExExcludes.RegFind(strFileOrFolder) > -1)
547 CLog::Log(LOGDEBUG, "%s: File '%s' excluded. (Matches exclude rule RegExp:'%s')", __FUNCTION__, strFileOrFolder.c_str(), regexps[i].c_str());
554 void CUtil::GetFileAndProtocol(const CStdString& strURL, CStdString& strDir)
557 if (!URIUtils::IsRemote(strURL)) return ;
558 if (URIUtils::IsDVD(strURL)) return ;
561 strDir = StringUtils::Format("%s://%s", url.GetProtocol().c_str(), url.GetFileName().c_str());
564 int CUtil::GetDVDIfoTitle(const CStdString& strFile)
566 CStdString strFilename = URIUtils::GetFileName(strFile);
567 if (strFilename.Equals("video_ts.ifo")) return 0;
569 return atoi(strFilename.substr(4, 2).c_str());
572 CStdString CUtil::GetFileMD5(const CStdString& strPath)
576 if (file.Open(strPath))
584 read = file.Read(temp,1024);
586 md5.append(temp,read);
588 result = md5.getDigest();
595 bool CUtil::GetDirectoryName(const CStdString& strFileName, CStdString& strDescription)
597 CStdString strFName = URIUtils::GetFileName(strFileName);
598 strDescription = URIUtils::GetDirectory(strFileName);
599 URIUtils::RemoveSlashAtEnd(strDescription);
601 size_t iPos = strDescription.find_last_of("/\\");
602 if (iPos != std::string::npos)
603 strDescription = strDescription.substr(iPos + 1);
604 else if (strDescription.size() <= 0)
605 strDescription = strFName;
609 void CUtil::GetDVDDriveIcon(const std::string& strPath, std::string& strIcon)
611 if ( !g_mediaManager.IsDiscInDrive() )
613 strIcon = "DefaultDVDEmpty.png";
617 if ( URIUtils::IsDVD(strPath) )
619 strIcon = "DefaultDVDRom.png";
623 if ( URIUtils::IsISO9660(strPath) )
626 CCdInfo* pInfo = g_mediaManager.GetCdInfo();
627 if ( pInfo != NULL && pInfo->IsVideoCd( 1 ) )
629 strIcon = "DefaultVCD.png";
633 strIcon = "DefaultDVDRom.png";
637 if ( URIUtils::IsCDDA(strPath) )
639 strIcon = "DefaultCDDA.png";
644 void CUtil::RemoveTempFiles()
646 CStdString searchPath = CProfilesManager::Get().GetDatabaseFolder();
648 if (!XFILE::CDirectory::GetDirectory(searchPath, items, ".tmp", DIR_FLAG_NO_FILE_DIRS))
651 for (int i = 0; i < items.Size(); ++i)
653 if (items[i]->m_bIsFolder)
655 XFILE::CFile::Delete(items[i]->GetPath());
659 void CUtil::ClearSubtitles()
663 CDirectory::GetDirectory("special://temp/",items);
664 for( int i=0;i<items.Size();++i)
666 if (!items[i]->m_bIsFolder)
668 if (items[i]->GetPath().find("subtitle") != std::string::npos ||
669 items[i]->GetPath().find("vobsub_queue") != std::string::npos)
671 CLog::Log(LOGDEBUG, "%s - Deleting temporary subtitle %s", __FUNCTION__, items[i]->GetPath().c_str());
672 CFile::Delete(items[i]->GetPath());
678 void CUtil::ClearTempFonts()
680 CStdString searchPath = "special://temp/fonts/";
682 if (!CFile::Exists(searchPath))
686 CDirectory::GetDirectory(searchPath, items, "", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_BYPASS_CACHE);
688 for (int i=0; i<items.Size(); ++i)
690 if (items[i]->m_bIsFolder)
692 CFile::Delete(items[i]->GetPath());
696 static const char * sub_exts[] = { ".utf", ".utf8", ".utf-8", ".sub", ".srt", ".smi", ".rt", ".txt", ".ssa", ".aqt", ".jss", ".ass", ".idx", NULL};
698 int64_t CUtil::ToInt64(uint32_t high, uint32_t low)
707 CStdString CUtil::GetNextFilename(const CStdString &fn_template, int max)
709 if (fn_template.find("%03d") == std::string::npos)
712 CStdString searchPath = URIUtils::GetDirectory(fn_template);
713 CStdString mask = URIUtils::GetExtension(fn_template);
714 CStdString name = StringUtils::Format(fn_template.c_str(), 0);
717 if (!CDirectory::GetDirectory(searchPath, items, mask, DIR_FLAG_NO_FILE_DIRS))
720 items.SetFastLookup(true);
721 for (int i = 0; i <= max; i++)
723 CStdString name = StringUtils::Format(fn_template.c_str(), i);
724 if (!items.Get(name))
730 CStdString CUtil::GetNextPathname(const CStdString &path_template, int max)
732 if (path_template.find("%04d") == std::string::npos)
735 for (int i = 0; i <= max; i++)
737 CStdString name = StringUtils::Format(path_template.c_str(), i);
738 if (!CFile::Exists(name))
744 void CUtil::StatToStatI64(struct _stati64 *result, struct stat *stat)
746 result->st_dev = stat->st_dev;
747 result->st_ino = stat->st_ino;
748 result->st_mode = stat->st_mode;
749 result->st_nlink = stat->st_nlink;
750 result->st_uid = stat->st_uid;
751 result->st_gid = stat->st_gid;
752 result->st_rdev = stat->st_rdev;
753 result->st_size = (int64_t)stat->st_size;
756 result->st_atime = (long)(stat->st_atime & 0xFFFFFFFF);
757 result->st_mtime = (long)(stat->st_mtime & 0xFFFFFFFF);
758 result->st_ctime = (long)(stat->st_ctime & 0xFFFFFFFF);
760 result->_st_atime = (long)(stat->st_atime & 0xFFFFFFFF);
761 result->_st_mtime = (long)(stat->st_mtime & 0xFFFFFFFF);
762 result->_st_ctime = (long)(stat->st_ctime & 0xFFFFFFFF);
766 void CUtil::Stat64ToStatI64(struct _stati64 *result, struct __stat64 *stat)
768 result->st_dev = stat->st_dev;
769 result->st_ino = stat->st_ino;
770 result->st_mode = stat->st_mode;
771 result->st_nlink = stat->st_nlink;
772 result->st_uid = stat->st_uid;
773 result->st_gid = stat->st_gid;
774 result->st_rdev = stat->st_rdev;
775 result->st_size = stat->st_size;
777 result->st_atime = (long)(stat->st_atime & 0xFFFFFFFF);
778 result->st_mtime = (long)(stat->st_mtime & 0xFFFFFFFF);
779 result->st_ctime = (long)(stat->st_ctime & 0xFFFFFFFF);
781 result->_st_atime = (long)(stat->st_atime & 0xFFFFFFFF);
782 result->_st_mtime = (long)(stat->st_mtime & 0xFFFFFFFF);
783 result->_st_ctime = (long)(stat->st_ctime & 0xFFFFFFFF);
787 void CUtil::StatI64ToStat64(struct __stat64 *result, struct _stati64 *stat)
789 result->st_dev = stat->st_dev;
790 result->st_ino = stat->st_ino;
791 result->st_mode = stat->st_mode;
792 result->st_nlink = stat->st_nlink;
793 result->st_uid = stat->st_uid;
794 result->st_gid = stat->st_gid;
795 result->st_rdev = stat->st_rdev;
796 result->st_size = stat->st_size;
798 result->st_atime = stat->st_atime;
799 result->st_mtime = stat->st_mtime;
800 result->st_ctime = stat->st_ctime;
802 result->st_atime = stat->_st_atime;
803 result->st_mtime = stat->_st_mtime;
804 result->st_ctime = stat->_st_ctime;
808 void CUtil::Stat64ToStat(struct stat *result, struct __stat64 *stat)
810 result->st_dev = stat->st_dev;
811 result->st_ino = stat->st_ino;
812 result->st_mode = stat->st_mode;
813 result->st_nlink = stat->st_nlink;
814 result->st_uid = stat->st_uid;
815 result->st_gid = stat->st_gid;
816 result->st_rdev = stat->st_rdev;
818 if (stat->st_size <= LONG_MAX)
819 result->st_size = (_off_t)stat->st_size;
821 if (sizeof(stat->st_size) <= sizeof(result->st_size) )
822 result->st_size = stat->st_size;
827 CLog::Log(LOGWARNING, "WARNING: File is larger than 32bit stat can handle, file size will be reported as 0 bytes");
829 result->st_atime = (time_t)(stat->st_atime & 0xFFFFFFFF);
830 result->st_mtime = (time_t)(stat->st_mtime & 0xFFFFFFFF);
831 result->st_ctime = (time_t)(stat->st_ctime & 0xFFFFFFFF);
834 #ifdef TARGET_WINDOWS
835 void CUtil::Stat64ToStat64i32(struct _stat64i32 *result, struct __stat64 *stat)
837 result->st_dev = stat->st_dev;
838 result->st_ino = stat->st_ino;
839 result->st_mode = stat->st_mode;
840 result->st_nlink = stat->st_nlink;
841 result->st_uid = stat->st_uid;
842 result->st_gid = stat->st_gid;
843 result->st_rdev = stat->st_rdev;
845 if (stat->st_size <= LONG_MAX)
846 result->st_size = (_off_t)stat->st_size;
848 if (sizeof(stat->st_size) <= sizeof(result->st_size) )
849 result->st_size = stat->st_size;
854 CLog::Log(LOGWARNING, "WARNING: File is larger than 32bit stat can handle, file size will be reported as 0 bytes");
857 result->st_atime = stat->st_atime;
858 result->st_mtime = stat->st_mtime;
859 result->st_ctime = stat->st_ctime;
861 result->st_atime = stat->_st_atime;
862 result->st_mtime = stat->_st_mtime;
863 result->st_ctime = stat->_st_ctime;
868 bool CUtil::CreateDirectoryEx(const CStdString& strPath)
870 // Function to create all directories at once instead
871 // of calling CreateDirectory for every subdir.
872 // Creates the directory and subdirectories if needed.
874 // return true if directory already exist
875 if (CDirectory::Exists(strPath)) return true;
877 // we currently only allow HD and smb, nfs and afp paths
878 if (!URIUtils::IsHD(strPath) && !URIUtils::IsSmb(strPath) && !URIUtils::IsNfs(strPath) && !URIUtils::IsAfp(strPath))
880 CLog::Log(LOGERROR,"%s called with an unsupported path: %s", __FUNCTION__, strPath.c_str());
884 vector<string> dirs = URIUtils::SplitPath(strPath);
887 CStdString dir(dirs.front());
888 URIUtils::AddSlashAtEnd(dir);
889 for (vector<string>::const_iterator it = dirs.begin() + 1; it != dirs.end(); it ++)
891 dir = URIUtils::AddFileToFolder(dir, *it);
892 CDirectory::Create(dir);
895 // was the final destination directory successfully created ?
896 if (!CDirectory::Exists(strPath)) return false;
900 CStdString CUtil::MakeLegalFileName(const CStdString &strFile, int LegalType)
902 CStdString result = strFile;
904 StringUtils::Replace(result, '/', '_');
905 StringUtils::Replace(result, '\\', '_');
906 StringUtils::Replace(result, '?', '_');
908 if (LegalType == LEGAL_WIN32_COMPAT)
910 // just filter out some illegal characters on windows
911 StringUtils::Replace(result, ':', '_');
912 StringUtils::Replace(result, '*', '_');
913 StringUtils::Replace(result, '?', '_');
914 StringUtils::Replace(result, '\"', '_');
915 StringUtils::Replace(result, '<', '_');
916 StringUtils::Replace(result, '>', '_');
917 StringUtils::Replace(result, '|', '_');
918 StringUtils::TrimRight(result, ". ");
923 // legalize entire path
924 CStdString CUtil::MakeLegalPath(const CStdString &strPathAndFile, int LegalType)
926 if (URIUtils::IsStack(strPathAndFile))
927 return MakeLegalPath(CStackDirectory::GetFirstStackedFile(strPathAndFile));
928 if (URIUtils::IsMultiPath(strPathAndFile))
929 return MakeLegalPath(CMultiPathDirectory::GetFirstPath(strPathAndFile));
930 if (!URIUtils::IsHD(strPathAndFile) && !URIUtils::IsSmb(strPathAndFile) && !URIUtils::IsNfs(strPathAndFile) && !URIUtils::IsAfp(strPathAndFile))
931 return strPathAndFile; // we don't support writing anywhere except HD, SMB, NFS and AFP - no need to legalize path
933 bool trailingSlash = URIUtils::HasSlashAtEnd(strPathAndFile);
934 vector<string> dirs = URIUtils::SplitPath(strPathAndFile);
936 return strPathAndFile;
937 // we just add first token to path and don't legalize it - possible values:
938 // "X:" (local win32), "" (local unix - empty string before '/') or
939 // "protocol://domain"
940 CStdString dir(dirs.front());
941 URIUtils::AddSlashAtEnd(dir);
942 for (vector<string>::const_iterator it = dirs.begin() + 1; it != dirs.end(); it ++)
943 dir = URIUtils::AddFileToFolder(dir, MakeLegalFileName(*it, LegalType));
944 if (trailingSlash) URIUtils::AddSlashAtEnd(dir);
948 CStdString CUtil::ValidatePath(const CStdString &path, bool bFixDoubleSlashes /* = false */)
950 CStdString result = path;
952 // Don't do any stuff on URLs containing %-characters or protocols that embed
953 // filenames. NOTE: Don't use IsInZip or IsInRar here since it will infinitely
954 // recurse and crash XBMC
955 if (URIUtils::IsURL(path) &&
956 (path.find('%') != std::string::npos ||
957 StringUtils::StartsWithNoCase(path, "apk:") ||
958 StringUtils::StartsWithNoCase(path, "zip:") ||
959 StringUtils::StartsWithNoCase(path, "rar:") ||
960 StringUtils::StartsWithNoCase(path, "stack:") ||
961 StringUtils::StartsWithNoCase(path, "bluray:") ||
962 StringUtils::StartsWithNoCase(path, "multipath:") ))
965 // check the path for incorrect slashes
966 #ifdef TARGET_WINDOWS
967 if (URIUtils::IsDOSPath(path))
969 StringUtils::Replace(result, '/', '\\');
970 /* The double slash correction should only be used when *absolutely*
971 necessary! This applies to certain DLLs or use from Python DLLs/scripts
972 that incorrectly generate double (back) slashes.
974 if (bFixDoubleSlashes && !result.empty())
976 // Fixup for double back slashes (but ignore the \\ of unc-paths)
977 for (size_t x = 1; x < result.size() - 1; x++)
979 if (result[x] == '\\' && result[x+1] == '\\')
984 else if (path.find("://") != std::string::npos || path.find(":\\\\") != std::string::npos)
987 StringUtils::Replace(result, '\\', '/');
988 /* The double slash correction should only be used when *absolutely*
989 necessary! This applies to certain DLLs or use from Python DLLs/scripts
990 that incorrectly generate double (back) slashes.
992 if (bFixDoubleSlashes && !result.empty())
994 // Fixup for double forward slashes(/) but don't touch the :// of URLs
995 for (size_t x = 2; x < result.size() - 1; x++)
997 if ( result[x] == '/' && result[x + 1] == '/' && !(result[x - 1] == ':' || (result[x - 1] == '/' && result[x - 2] == ':')) )
1005 bool CUtil::IsUsingTTFSubtitles()
1007 return URIUtils::HasExtension(CSettings::Get().GetString("subtitles.font"), ".ttf");
1011 bool CUtil::TestSplitExec()
1013 CStdString function;
1014 vector<CStdString> params;
1015 CUtil::SplitExecFunction("ActivateWindow(Video, \"C:\\test\\foo\")", function, params);
1016 if (function != "ActivateWindow" || params.size() != 2 || params[0] != "Video" || params[1] != "C:\\test\\foo")
1019 CUtil::SplitExecFunction("ActivateWindow(Video, \"C:\\test\\foo\\\")", function, params);
1020 if (function != "ActivateWindow" || params.size() != 2 || params[0] != "Video" || params[1] != "C:\\test\\foo\"")
1022 CUtil::SplitExecFunction("ActivateWindow(Video, \"C:\\\\test\\\\foo\\\\\")", function, params);
1023 if (function != "ActivateWindow" || params.size() != 2 || params[0] != "Video" || params[1] != "C:\\test\\foo\\")
1025 CUtil::SplitExecFunction("ActivateWindow(Video, \"C:\\\\\\\\test\\\\\\foo\\\\\")", function, params);
1026 if (function != "ActivateWindow" || params.size() != 2 || params[0] != "Video" || params[1] != "C:\\\\test\\\\foo\\")
1028 CUtil::SplitExecFunction("SetProperty(Foo,\"\")", function, params);
1029 if (function != "SetProperty" || params.size() != 2 || params[0] != "Foo" || params[1] != "")
1031 CUtil::SplitExecFunction("SetProperty(foo,ba(\"ba black )\",sheep))", function, params);
1032 if (function != "SetProperty" || params.size() != 2 || params[0] != "foo" || params[1] != "ba(\"ba black )\",sheep)")
1038 void CUtil::SplitExecFunction(const std::string &execString, std::string &function, vector<string> ¶meters)
1040 std::string paramString;
1042 size_t iPos = execString.find("(");
1043 size_t iPos2 = execString.rfind(")");
1044 if (iPos != std::string::npos && iPos2 != std::string::npos)
1046 paramString = execString.substr(iPos + 1, iPos2 - iPos - 1);
1047 function = execString.substr(0, iPos);
1050 function = execString;
1052 // remove any whitespace, and the standard prefix (if it exists)
1053 StringUtils::Trim(function);
1054 if( StringUtils::StartsWithNoCase(function, "xbmc.") )
1055 function.erase(0, 5);
1057 SplitParams(paramString, parameters);
1060 void CUtil::SplitParams(const CStdString ¶mString, std::vector<std::string> ¶meters)
1062 bool inQuotes = false;
1063 bool lastEscaped = false; // only every second character can be escaped
1065 size_t whiteSpacePos = 0;
1066 CStdString parameter;
1068 for (size_t pos = 0; pos < paramString.size(); pos++)
1070 char ch = paramString[pos];
1071 bool escaped = (pos > 0 && paramString[pos - 1] == '\\' && !lastEscaped);
1072 lastEscaped = escaped;
1074 { // if we're in a quote, we accept everything until the closing quote
1075 if (ch == '"' && !escaped)
1076 { // finished a quote - no need to add the end quote to our string
1081 { // not in a quote, so check if we should be starting one
1082 if (ch == '"' && !escaped)
1083 { // start of quote - no need to add the quote to our string
1086 if (inFunction && ch == ')')
1087 { // end of a function
1091 { // start of function
1094 if (!inFunction && ch == ',')
1095 { // not in a function, so a comma signfies the end of this parameter
1097 parameter = parameter.substr(0, whiteSpacePos);
1098 // trim off start and end quotes
1099 if (parameter.length() > 1 && parameter[0] == '"' && parameter[parameter.length() - 1] == '"')
1100 parameter = parameter.substr(1, parameter.length() - 2);
1101 else if (parameter.length() > 3 && parameter[parameter.length() - 1] == '"')
1103 // check name="value" style param.
1104 size_t quotaPos = parameter.find('"');
1105 if (quotaPos > 1 && quotaPos < parameter.length() - 1 && parameter[quotaPos - 1] == '=')
1107 parameter.erase(parameter.length() - 1);
1108 parameter.erase(quotaPos);
1111 parameters.push_back(parameter);
1117 if ((ch == '"' || ch == '\\') && escaped)
1118 { // escaped quote or backslash
1119 parameter[parameter.size()-1] = ch;
1122 // whitespace handling - we skip any whitespace at the left or right of an unquoted parameter
1123 if (ch == ' ' && !inQuotes)
1125 if (parameter.empty()) // skip whitespace on left
1127 if (!whiteSpacePos) // make a note of where whitespace starts on the right
1128 whiteSpacePos = parameter.size();
1134 if (inFunction || inQuotes)
1135 CLog::Log(LOGWARNING, "%s(%s) - end of string while searching for ) or \"", __FUNCTION__, paramString.c_str());
1137 parameter.erase(whiteSpacePos);
1138 // trim off start and end quotes
1139 if (parameter.size() > 1 && parameter[0] == '"' && parameter[parameter.size() - 1] == '"')
1140 parameter = parameter.substr(1,parameter.size() - 2);
1141 else if (parameter.size() > 3 && parameter[parameter.size() - 1] == '"')
1143 // check name="value" style param.
1144 size_t quotaPos = parameter.find('"');
1145 if (quotaPos > 1 && quotaPos < parameter.length() - 1 && parameter[quotaPos - 1] == '=')
1147 parameter.erase(parameter.length() - 1);
1148 parameter.erase(quotaPos);
1151 if (!parameter.empty() || parameters.size())
1152 parameters.push_back(parameter);
1155 int CUtil::GetMatchingSource(const CStdString& strPath1, VECSOURCES& VECSOURCES, bool& bIsSourceName)
1157 if (strPath1.empty())
1160 // copy as we may change strPath
1161 CStdString strPath = strPath1;
1163 // Check for special protocols
1164 CURL checkURL(strPath);
1166 if (StringUtils::StartsWith(strPath, "special://skin/"))
1170 if (checkURL.IsProtocol("stack"))
1171 strPath.erase(0, 8); // remove the stack protocol
1173 if (checkURL.IsProtocol("shout"))
1174 strPath = checkURL.GetHostName();
1175 if (checkURL.IsProtocol("tuxbox"))
1177 if (checkURL.IsProtocol("plugin"))
1179 if (checkURL.IsProtocol("multipath"))
1180 strPath = CMultiPathDirectory::GetFirstPath(strPath);
1182 bIsSourceName = false;
1185 // we first test the NAME of a source
1186 for (int i = 0; i < (int)VECSOURCES.size(); ++i)
1188 CMediaSource share = VECSOURCES.at(i);
1189 CStdString strName = share.strName;
1191 // special cases for dvds
1192 if (URIUtils::IsOnDVD(share.strPath))
1194 if (URIUtils::IsOnDVD(strPath))
1197 // not a path, so we need to modify the source name
1198 // since we add the drive status and disc name to the source
1199 // "Name (Drive Status/Disc Name)"
1200 size_t iPos = strName.rfind('(');
1201 if (iPos != std::string::npos && iPos > 1)
1202 strName = strName.substr(0, iPos - 1);
1204 if (strPath.Equals(strName))
1206 bIsSourceName = true;
1211 // now test the paths
1213 // remove user details, and ensure path only uses forward slashes
1214 // and ends with a trailing slash so as not to match a substring
1215 CURL urlDest(strPath);
1216 urlDest.SetOptions("");
1217 CStdString strDest = urlDest.GetWithoutUserDetails();
1218 ForceForwardSlashes(strDest);
1219 if (!URIUtils::HasSlashAtEnd(strDest))
1223 size_t iLenPath = strDest.size();
1224 for (int i = 0; i < (int)VECSOURCES.size(); ++i)
1226 CMediaSource share = VECSOURCES.at(i);
1228 // does it match a source name?
1229 if (share.strPath.substr(0,8) == "shout://")
1231 CURL url(share.strPath);
1232 if (strPath == url.GetHostName())
1236 // doesnt match a name, so try the source path
1237 vector<string> vecPaths;
1239 // add any concatenated paths if they exist
1240 if (share.vecPaths.size() > 0)
1241 vecPaths = share.vecPaths;
1243 // add the actual share path at the front of the vector
1244 vecPaths.insert(vecPaths.begin(), share.strPath);
1247 for (int j = 0; j < (int)vecPaths.size(); ++j)
1249 // remove user details, and ensure path only uses forward slashes
1250 // and ends with a trailing slash so as not to match a substring
1251 CURL urlShare(vecPaths[j]);
1252 urlShare.SetOptions("");
1253 CStdString strShare = urlShare.GetWithoutUserDetails();
1254 ForceForwardSlashes(strShare);
1255 if (!URIUtils::HasSlashAtEnd(strShare))
1257 size_t iLenShare = strShare.size();
1259 if ((iLenPath >= iLenShare) && StringUtils::StartsWithNoCase(strDest, strShare) && (iLenShare > iLength))
1261 // if exact match, return it immediately
1262 if (iLenPath == iLenShare)
1264 // if the path EXACTLY matches an item in a concatentated path
1265 // set source name to true to load the full virtualpath
1266 bIsSourceName = false;
1267 if (vecPaths.size() > 1)
1268 bIsSourceName = true;
1272 iLength = iLenShare;
1277 // return the index of the share with the longest match
1281 // rar:// and zip://
1282 // if archive wasn't mounted, look for a matching share for the archive instead
1283 if( StringUtils::StartsWithNoCase(strPath, "rar://") || StringUtils::StartsWithNoCase(strPath, "zip://") )
1285 // get the hostname portion of the url since it contains the archive file
1286 strPath = checkURL.GetHostName();
1288 bIsSourceName = false;
1290 return GetMatchingSource(strPath, VECSOURCES, bDummy);
1293 CLog::Log(LOGDEBUG,"CUtil::GetMatchingSource: no matching source found for [%s]", strPath1.c_str());
1298 CStdString CUtil::TranslateSpecialSource(const CStdString &strSpecial)
1300 if (!strSpecial.empty() && strSpecial[0] == '$')
1302 if (StringUtils::StartsWithNoCase(strSpecial, "$home"))
1303 return URIUtils::AddFileToFolder("special://home/", strSpecial.substr(5));
1304 else if (StringUtils::StartsWithNoCase(strSpecial, "$subtitles"))
1305 return URIUtils::AddFileToFolder("special://subtitles/", strSpecial.substr(10));
1306 else if (StringUtils::StartsWithNoCase(strSpecial, "$userdata"))
1307 return URIUtils::AddFileToFolder("special://userdata/", strSpecial.substr(9));
1308 else if (StringUtils::StartsWithNoCase(strSpecial, "$database"))
1309 return URIUtils::AddFileToFolder("special://database/", strSpecial.substr(9));
1310 else if (StringUtils::StartsWithNoCase(strSpecial, "$thumbnails"))
1311 return URIUtils::AddFileToFolder("special://thumbnails/", strSpecial.substr(11));
1312 else if (StringUtils::StartsWithNoCase(strSpecial, "$recordings"))
1313 return URIUtils::AddFileToFolder("special://recordings/", strSpecial.substr(11));
1314 else if (StringUtils::StartsWithNoCase(strSpecial, "$screenshots"))
1315 return URIUtils::AddFileToFolder("special://screenshots/", strSpecial.substr(12));
1316 else if (StringUtils::StartsWithNoCase(strSpecial, "$musicplaylists"))
1317 return URIUtils::AddFileToFolder("special://musicplaylists/", strSpecial.substr(15));
1318 else if (StringUtils::StartsWithNoCase(strSpecial, "$videoplaylists"))
1319 return URIUtils::AddFileToFolder("special://videoplaylists/", strSpecial.substr(15));
1320 else if (StringUtils::StartsWithNoCase(strSpecial, "$cdrips"))
1321 return URIUtils::AddFileToFolder("special://cdrips/", strSpecial.substr(7));
1322 // this one will be removed post 2.0
1323 else if (StringUtils::StartsWithNoCase(strSpecial, "$playlists"))
1324 return URIUtils::AddFileToFolder(CSettings::Get().GetString("system.playlistspath"), strSpecial.substr(10));
1329 CStdString CUtil::MusicPlaylistsLocation()
1332 vec.push_back(URIUtils::AddFileToFolder(CSettings::Get().GetString("system.playlistspath"), "music"));
1333 vec.push_back(URIUtils::AddFileToFolder(CSettings::Get().GetString("system.playlistspath"), "mixed"));
1334 return XFILE::CMultiPathDirectory::ConstructMultiPath(vec);
1337 CStdString CUtil::VideoPlaylistsLocation()
1340 vec.push_back(URIUtils::AddFileToFolder(CSettings::Get().GetString("system.playlistspath"), "video"));
1341 vec.push_back(URIUtils::AddFileToFolder(CSettings::Get().GetString("system.playlistspath"), "mixed"));
1342 return XFILE::CMultiPathDirectory::ConstructMultiPath(vec);
1345 void CUtil::DeleteMusicDatabaseDirectoryCache()
1347 CUtil::DeleteDirectoryCache("mdb-");
1348 CUtil::DeleteDirectoryCache("sp-"); // overkill as it will delete video smartplaylists, but as we can't differentiate based on URL...
1351 void CUtil::DeleteVideoDatabaseDirectoryCache()
1353 CUtil::DeleteDirectoryCache("vdb-");
1354 CUtil::DeleteDirectoryCache("sp-"); // overkill as it will delete music smartplaylists, but as we can't differentiate based on URL...
1357 void CUtil::DeleteDirectoryCache(const CStdString &prefix)
1359 CStdString searchPath = "special://temp/";
1360 CFileItemList items;
1361 if (!XFILE::CDirectory::GetDirectory(searchPath, items, ".fi", DIR_FLAG_NO_FILE_DIRS))
1364 for (int i = 0; i < items.Size(); ++i)
1366 if (items[i]->m_bIsFolder)
1368 CStdString fileName = URIUtils::GetFileName(items[i]->GetPath());
1369 if (StringUtils::StartsWith(fileName, prefix))
1370 XFILE::CFile::Delete(items[i]->GetPath());
1375 void CUtil::GetRecursiveListing(const CStdString& strPath, CFileItemList& items, const CStdString& strMask, unsigned int flags /* = DIR_FLAG_DEFAULTS */)
1377 CFileItemList myItems;
1378 CDirectory::GetDirectory(strPath,myItems,strMask,flags);
1379 for (int i=0;i<myItems.Size();++i)
1381 if (myItems[i]->m_bIsFolder)
1382 CUtil::GetRecursiveListing(myItems[i]->GetPath(),items,strMask,flags);
1384 items.Add(myItems[i]);
1388 void CUtil::GetRecursiveDirsListing(const CStdString& strPath, CFileItemList& item, unsigned int flags /* = DIR_FLAG_DEFAULTS */)
1390 CFileItemList myItems;
1391 CDirectory::GetDirectory(strPath,myItems,"",flags);
1392 for (int i=0;i<myItems.Size();++i)
1394 if (myItems[i]->m_bIsFolder && !myItems[i]->IsPath(".."))
1396 item.Add(myItems[i]);
1397 CUtil::GetRecursiveDirsListing(myItems[i]->GetPath(),item,flags);
1402 void CUtil::ForceForwardSlashes(CStdString& strPath)
1404 size_t iPos = strPath.rfind('\\');
1405 while (iPos != string::npos)
1407 strPath.at(iPos) = '/';
1408 iPos = strPath.rfind('\\');
1412 double CUtil::AlbumRelevance(const CStdString& strAlbumTemp1, const CStdString& strAlbum1, const CStdString& strArtistTemp1, const CStdString& strArtist1)
1414 // case-insensitive fuzzy string comparison on the album and artist for relevance
1415 // weighting is identical, both album and artist are 50% of the total relevance
1416 // a missing artist means the maximum relevance can only be 0.50
1417 CStdString strAlbumTemp = strAlbumTemp1;
1418 StringUtils::ToLower(strAlbumTemp);
1419 CStdString strAlbum = strAlbum1;
1420 StringUtils::ToLower(strAlbum);
1421 double fAlbumPercentage = fstrcmp(strAlbumTemp, strAlbum, 0.0f);
1422 double fArtistPercentage = 0.0f;
1423 if (!strArtist1.empty())
1425 CStdString strArtistTemp = strArtistTemp1;
1426 StringUtils::ToLower(strArtistTemp);
1427 CStdString strArtist = strArtist1;
1428 StringUtils::ToLower(strArtist);
1429 fArtistPercentage = fstrcmp(strArtistTemp, strArtist, 0.0f);
1431 double fRelevance = fAlbumPercentage * 0.5f + fArtistPercentage * 0.5f;
1435 bool CUtil::MakeShortenPath(std::string StrInput, std::string& StrOutput, size_t iTextMaxLength)
1437 size_t iStrInputSize = StrInput.size();
1438 if(iStrInputSize <= 0 || iTextMaxLength >= iStrInputSize)
1442 size_t nGreaterDelim, nPos;
1444 nPos = StrInput.find_last_of( '\\' );
1445 if (nPos != std::string::npos)
1449 nPos = StrInput.find_last_of( '/' );
1450 if (nPos != std::string::npos)
1453 if ( cDelim == '\0' )
1456 if (nPos == StrInput.size() - 1)
1458 StrInput.erase(StrInput.size() - 1);
1459 nPos = StrInput.find_last_of(cDelim);
1461 while( iTextMaxLength < iStrInputSize )
1463 nPos = StrInput.find_last_of( cDelim, nPos );
1464 nGreaterDelim = nPos;
1465 if ( nPos != std::string::npos )
1466 nPos = StrInput.find_last_of( cDelim, nPos - 1 );
1467 if ( nPos == CStdString::npos ) break;
1468 if ( nGreaterDelim > nPos ) StrInput.replace( nPos + 1, nGreaterDelim - nPos - 1, ".." );
1469 iStrInputSize = StrInput.size();
1471 // replace any additional /../../ with just /../ if necessary
1472 std::string replaceDots = StringUtils::Format("..%c..", cDelim);
1473 while (StrInput.size() > (unsigned int)iTextMaxLength)
1474 if (!StringUtils::Replace(StrInput, replaceDots, ".."))
1476 // finally, truncate our string to force inside our max text length,
1477 // replacing the last 2 characters with ".."
1480 // "smb://../Playboy Swimsuit Cal.."
1481 if (iTextMaxLength > 2 && StrInput.size() > (unsigned int)iTextMaxLength)
1483 StrInput.erase(iTextMaxLength - 2);
1486 StrOutput = StrInput;
1490 bool CUtil::SupportsWriteFileOperations(const CStdString& strPath)
1492 // currently only hd, smb, nfs, afp and dav support delete and rename
1493 if (URIUtils::IsHD(strPath))
1495 if (URIUtils::IsSmb(strPath))
1497 if (CUtil::IsTVRecording(strPath))
1498 return CPVRDirectory::SupportsWriteFileOperations(strPath);
1499 if (URIUtils::IsNfs(strPath))
1501 if (URIUtils::IsAfp(strPath))
1503 if (URIUtils::IsDAV(strPath))
1505 if (URIUtils::IsMythTV(strPath))
1508 * Can't use CFile::Exists() to check whether the myth:// path supports file operations because
1509 * it hits the directory cache on the way through, which has the Live Channels and Guide
1512 return CMythDirectory::SupportsWriteFileOperations(strPath);
1514 if (URIUtils::IsStack(strPath))
1515 return SupportsWriteFileOperations(CStackDirectory::GetFirstStackedFile(strPath));
1516 if (URIUtils::IsMultiPath(strPath))
1517 return CMultiPathDirectory::SupportsWriteFileOperations(strPath);
1522 bool CUtil::SupportsReadFileOperations(const CStdString& strPath)
1524 if (URIUtils::IsVideoDb(strPath))
1530 CStdString CUtil::GetDefaultFolderThumb(const CStdString &folderThumb)
1532 if (g_TextureManager.HasTexture(folderThumb))
1537 void CUtil::GetSkinThemes(vector<std::string>& vecTheme)
1539 std::string strPath = URIUtils::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media");
1540 CFileItemList items;
1541 CDirectory::GetDirectory(strPath, items);
1542 // Search for Themes in the Current skin!
1543 for (int i = 0; i < items.Size(); ++i)
1545 CFileItemPtr pItem = items[i];
1546 if (!pItem->m_bIsFolder)
1548 CStdString strExtension = URIUtils::GetExtension(pItem->GetPath());
1549 if ((strExtension == ".xpr" && !StringUtils::EqualsNoCase(pItem->GetLabel(), "Textures.xpr")) ||
1550 (strExtension == ".xbt" && !StringUtils::EqualsNoCase(pItem->GetLabel(), "Textures.xbt")))
1552 std::string strLabel = pItem->GetLabel();
1553 vecTheme.push_back(strLabel.substr(0, strLabel.size() - 4));
1557 sort(vecTheme.begin(), vecTheme.end(), sortstringbyname());
1560 void CUtil::InitRandomSeed()
1564 now = CurrentHostCounter();
1565 unsigned int seed = (unsigned int)now;
1566 // CLog::Log(LOGDEBUG, "%s - Initializing random seed with %u", __FUNCTION__, seed);
1571 bool CUtil::RunCommandLine(const CStdString& cmdLine, bool waitExit)
1573 vector<string> args = StringUtils::Split(cmdLine, ",");
1575 // Strip quotes and whitespace around the arguments, or exec will fail.
1576 // This allows the python invocation to be written more naturally with any amount of whitespace around the args.
1577 // But it's still limited, for example quotes inside the strings are not expanded, etc.
1578 // TODO: Maybe some python library routine can parse this more properly ?
1579 for (vector<string>::iterator it = args.begin(); it != args.end(); ++it)
1582 pos = it->find_first_not_of(" \t\n\"'");
1583 if (pos != std::string::npos)
1588 pos = it->find_last_not_of(" \t\n\"'"); // if it returns npos we'll end up with an empty string which is OK
1590 it->erase(++pos, it->size());
1594 return Command(args, waitExit);
1598 // FIXME, this should be merged with the function below.
1600 bool CUtil::Command(const std::vector<std::string>& arrArgs, bool waitExit)
1603 printf("Executing: ");
1604 for (size_t i=0; i<arrArgs.size(); i++)
1605 printf("%s ", arrArgs[i].c_str());
1609 pid_t child = fork();
1615 // fork again in order not to leave a zombie process
1619 else if (child != 0)
1625 if (arrArgs.size() > 0)
1627 char **args = (char **)alloca(sizeof(char *) * (arrArgs.size() + 3));
1628 memset(args, 0, (sizeof(char *) * (arrArgs.size() + 3)));
1629 for (size_t i=0; i<arrArgs.size(); i++)
1630 args[i] = (char *)arrArgs[i].c_str();
1631 execvp(args[0], args);
1636 waitpid(child, &n, 0);
1639 return (waitExit) ? (WEXITSTATUS(n) == 0) : true;
1642 bool CUtil::SudoCommand(const CStdString &strCommand)
1644 CLog::Log(LOGDEBUG, "Executing sudo command: <%s>", strCommand.c_str());
1645 pid_t child = fork();
1649 close(0); // close stdin to avoid sudo request password
1652 vector<string> arrArgs = StringUtils::Split(strCommand, " ");
1653 if (arrArgs.size() > 0)
1655 char **args = (char **)alloca(sizeof(char *) * (arrArgs.size() + 3));
1656 memset(args, 0, (sizeof(char *) * (arrArgs.size() + 3)));
1657 args[0] = (char *)"/usr/bin/sudo";
1658 args[1] = (char *)"-S";
1659 for (size_t i=0; i<arrArgs.size(); i++)
1661 args[i+2] = (char *)arrArgs[i].c_str();
1663 execvp("/usr/bin/sudo", args);
1667 waitpid(child, &n, 0);
1669 return WEXITSTATUS(n) == 0;
1673 int CUtil::LookupRomanDigit(char roman_digit)
1675 switch (roman_digit)
1703 int CUtil::TranslateRomanNumeral(const char* roman_numeral)
1708 if (roman_numeral && roman_numeral[0])
1715 while (*roman_numeral)
1717 int digit = CUtil::LookupRomanDigit(*roman_numeral);
1720 // General sanity checks
1722 // numeral not in LUT
1729 // N = 10^n may not precede (N+1) > 10^(N+1)
1730 if (test == 1 && digit > last * 10)
1733 // N = 5*10^n may not precede (N+1) >= N
1734 if (test == 5 && digit >= last)
1737 // End general sanity checks
1741 // smaller numerals may not repeat before a larger one
1750 else if (last == digit)
1759 decimal += 2 * last - temp_sum;
1761 decimal += temp_sum;
1768 // Post general sanity checks
1770 // numerals may not repeat more than thrice
1779 decimal += temp_sum;
1781 decimal += 2 * last - temp_sum;
1786 CStdString CUtil::ResolveExecutablePath()
1788 CStdString strExecutablePath;
1789 #ifdef TARGET_WINDOWS
1790 static const size_t bufSize = MAX_PATH * 2;
1791 wchar_t* buf = new wchar_t[bufSize];
1793 ::GetModuleFileNameW(0, buf, bufSize);
1795 g_charsetConverter.wToUTF8(buf,strExecutablePath);
1797 #elif defined(TARGET_DARWIN)
1798 char given_path[2*MAXPATHLEN];
1799 uint32_t path_size =2*MAXPATHLEN;
1801 GetDarwinExecutablePath(given_path, &path_size);
1802 strExecutablePath = given_path;
1803 #elif defined(TARGET_FREEBSD)
1810 mib[2] = KERN_PROC_PATHNAME;
1813 buflen = sizeof(buf) - 1;
1814 if(sysctl(mib, 4, buf, &buflen, NULL, 0) < 0)
1815 strExecutablePath = "";
1817 strExecutablePath = buf;
1819 /* Get our PID and build the name of the link in /proc */
1820 pid_t pid = getpid();
1821 char linkname[64]; /* /proc/<pid>/exe */
1822 snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid);
1824 /* Now read the symbolic link */
1825 char buf[PATH_MAX + 1];
1828 int ret = readlink(linkname, buf, sizeof(buf) - 1);
1832 strExecutablePath = buf;
1834 return strExecutablePath;
1837 CStdString CUtil::GetFrameworksPath(bool forPython)
1839 CStdString strFrameworksPath;
1840 #if defined(TARGET_DARWIN)
1841 char given_path[2*MAXPATHLEN];
1842 uint32_t path_size =2*MAXPATHLEN;
1844 GetDarwinFrameworkPath(forPython, given_path, &path_size);
1845 strFrameworksPath = given_path;
1847 return strFrameworksPath;
1850 void CUtil::ScanForExternalSubtitles(const std::string& strMovie, std::vector<std::string>& vecSubtitles )
1852 unsigned int startTimer = XbmcThreads::SystemClockMillis();
1854 // new array for commons sub dirs
1855 const char * common_sub_dirs[] = {"subs",
1869 vector<std::string> vecExtensionsCached;
1871 CFileItem item(strMovie, false);
1872 if ( item.IsInternetStream()
1873 || item.IsHDHomeRun()
1874 || item.IsSlingbox()
1875 || item.IsPlayList()
1880 vector<std::string> strLookInPaths;
1882 std::string strMovieFileName;
1883 std::string strPath;
1885 URIUtils::Split(strMovie, strPath, strMovieFileName);
1886 std::string strMovieFileNameNoExt(URIUtils::ReplaceExtension(strMovieFileName, ""));
1887 strLookInPaths.push_back(strPath);
1889 if (!CMediaSettings::Get().GetAdditionalSubtitleDirectoryChecked() && !CSettings::Get().GetString("subtitles.custompath").empty()) // to avoid checking non-existent directories (network) every time..
1891 if (!g_application.getNetwork().IsAvailable() && !URIUtils::IsHD(CSettings::Get().GetString("subtitles.custompath")))
1893 CLog::Log(LOGINFO,"CUtil::CacheSubtitles: disabling alternate subtitle directory for this session, it's nonaccessible");
1894 CMediaSettings::Get().SetAdditionalSubtitleDirectoryChecked(-1); // disabled
1896 else if (!CDirectory::Exists(CSettings::Get().GetString("subtitles.custompath")))
1898 CLog::Log(LOGINFO,"CUtil::CacheSubtitles: disabling alternate subtitle directory for this session, it's nonexistant");
1899 CMediaSettings::Get().SetAdditionalSubtitleDirectoryChecked(-1); // disabled
1902 CMediaSettings::Get().SetAdditionalSubtitleDirectoryChecked(1);
1905 if (StringUtils::StartsWith(strMovie, "rar://")) // <--- if this is found in main path then ignore it!
1908 std::string strArchive = url.GetHostName();
1909 URIUtils::Split(strArchive, strPath, strMovieFileName);
1910 strLookInPaths.push_back(strPath);
1913 int iSize = strLookInPaths.size();
1914 for (int i=0; i<iSize; ++i)
1916 vector<string> directories = StringUtils::Split( strLookInPaths[i], "/" );
1917 if (directories.size() == 1)
1918 directories = StringUtils::Split( strLookInPaths[i], "\\" );
1920 // if it's inside a cdX dir, add parent path
1921 if (directories.size() >= 2 && directories[directories.size()-2].size() == 3 && StringUtils::StartsWithNoCase(directories[directories.size()-2], "cd")) // SplitString returns empty token as last item, hence size-2
1923 std::string strPath2;
1924 URIUtils::GetParentPath(strLookInPaths[i], strPath2);
1925 strLookInPaths.push_back(strPath2);
1929 // checking if any of the common subdirs exist ..
1930 iSize = strLookInPaths.size();
1931 for (int i=0;i<iSize;++i)
1933 for (int j=0; common_sub_dirs[j]; j++)
1935 std::string strPath2 = URIUtils::AddFileToFolder(strLookInPaths[i],common_sub_dirs[j]);
1936 URIUtils::AddSlashAtEnd(strPath2);
1937 if (CDirectory::Exists(strPath2))
1938 strLookInPaths.push_back(strPath2);
1941 // .. done checking for common subdirs
1943 // check if there any cd-directories in the paths we have added so far
1944 iSize = strLookInPaths.size();
1945 for (int i=0;i<9;++i) // 9 cd's
1947 std::string cdDir = StringUtils::Format("cd%i",i+1);
1948 for (int i=0;i<iSize;++i)
1950 std::string strPath2 = URIUtils::AddFileToFolder(strLookInPaths[i],cdDir);
1951 URIUtils::AddSlashAtEnd(strPath2);
1952 bool pathAlreadyAdded = false;
1953 for (unsigned int i=0; i<strLookInPaths.size(); i++)
1955 // if movie file is inside cd-dir, this directory can exist in vector already
1956 if (StringUtils::EqualsNoCase(strLookInPaths[i], strPath2))
1957 pathAlreadyAdded = true;
1959 if (CDirectory::Exists(strPath2) && !pathAlreadyAdded)
1960 strLookInPaths.push_back(strPath2);
1963 // .. done checking for cd-dirs
1965 // this is last because we dont want to check any common subdirs or cd-dirs in the alternate <subtitles> dir.
1966 if (CMediaSettings::Get().GetAdditionalSubtitleDirectoryChecked() == 1)
1968 strPath = CSettings::Get().GetString("subtitles.custompath");
1969 URIUtils::AddSlashAtEnd(strPath);
1970 strLookInPaths.push_back(strPath);
1973 std::string strLExt;
1974 std::string strDest;
1975 std::string strItem;
1977 // 2 steps for movie directory and alternate subtitles directory
1978 CLog::Log(LOGDEBUG,"%s: Searching for subtitles...", __FUNCTION__);
1979 for (unsigned int step = 0; step < strLookInPaths.size(); step++)
1981 if (strLookInPaths[step].length() != 0)
1983 CFileItemList items;
1985 CDirectory::GetDirectory(strLookInPaths[step], items, g_advancedSettings.m_subtitlesExtensions, DIR_FLAG_NO_FILE_DIRS);
1987 for (int j = 0; j < items.Size(); j++)
1989 URIUtils::Split(items[j]->GetPath(), strPath, strItem);
1991 if (StringUtils::StartsWithNoCase(strItem, strMovieFileNameNoExt))
1993 // is this a rar or zip-file
1994 if (URIUtils::IsRAR(strItem) || URIUtils::IsZIP(strItem))
1996 // zip-file name equals strMovieFileNameNoExt, don't check in zip-file
1997 ScanArchiveForSubtitles( items[j]->GetPath(), "", vecSubtitles );
1999 else // not a rar/zip file
2001 for (int i = 0; sub_exts[i]; i++)
2003 //Cache subtitle with same name as movie
2004 if (URIUtils::HasExtension(strItem, sub_exts[i]))
2006 vecSubtitles.push_back( items[j]->GetPath() );
2007 CLog::Log(LOGINFO, "%s: found subtitle file %s\n", __FUNCTION__, items[j]->GetPath().c_str() );
2014 // is this a rar or zip-file
2015 if (URIUtils::IsRAR(strItem) || URIUtils::IsZIP(strItem))
2017 // check strMovieFileNameNoExt in zip-file
2018 ScanArchiveForSubtitles( items[j]->GetPath(), strMovieFileNameNoExt, vecSubtitles );
2025 iSize = vecSubtitles.size();
2026 for (int i = 0; i < iSize; i++)
2028 if (URIUtils::HasExtension(vecSubtitles[i], ".smi"))
2030 //Cache multi-language sami subtitle
2031 CDVDSubtitleStream* pStream = new CDVDSubtitleStream();
2032 if(pStream->Open(vecSubtitles[i]))
2034 CDVDSubtitleTagSami TagConv;
2035 TagConv.LoadHead(pStream);
2036 if (TagConv.m_Langclass.size() >= 2)
2038 for (unsigned int k = 0; k < TagConv.m_Langclass.size(); k++)
2040 strDest = StringUtils::Format("special://temp/subtitle.%s.%d.smi", TagConv.m_Langclass[k].Name.c_str(), i);
2041 if (CFile::Copy(vecSubtitles[i], strDest))
2043 CLog::Log(LOGINFO, " cached subtitle %s->%s\n", vecSubtitles[i].c_str(), strDest.c_str());
2044 vecSubtitles.push_back(strDest);
2052 CLog::Log(LOGDEBUG,"%s: END (total time: %i ms)", __FUNCTION__, (int)(XbmcThreads::SystemClockMillis() - startTimer));
2055 int CUtil::ScanArchiveForSubtitles( const std::string& strArchivePath, const std::string& strMovieFileNameNoExt, std::vector<std::string>& vecSubtitles )
2057 int nSubtitlesAdded = 0;
2058 CFileItemList ItemList;
2060 // zip only gets the root dir
2061 if (URIUtils::HasExtension(strArchivePath, ".zip"))
2063 CURL pathToUrl(strArchivePath);
2064 CURL zipURL = URIUtils::CreateArchivePath("zip", pathToUrl, "");
2065 if (!CDirectory::GetDirectory(zipURL, ItemList, "", DIR_FLAG_NO_FILE_DIRS))
2070 #ifdef HAS_FILESYSTEM_RAR
2071 // get _ALL_files in the rar, even those located in subdirectories because we set the bMask to false.
2072 // so now we dont have to find any subdirs anymore, all files in the rar is checked.
2073 if( !g_RarManager.GetFilesInRar(ItemList, strArchivePath, false, "") )
2079 for (int it= 0 ; it <ItemList.Size();++it)
2081 std::string strPathInRar = ItemList[it]->GetPath();
2082 std::string strExt = URIUtils::GetExtension(strPathInRar);
2084 CLog::Log(LOGDEBUG, "ScanArchiveForSubtitles:: Found file %s", strPathInRar.c_str());
2085 // always check any embedded rar archives
2086 // checking for embedded rars, I moved this outside the sub_ext[] loop. We only need to check this once for each file.
2087 if (URIUtils::IsRAR(strPathInRar) || URIUtils::IsZIP(strPathInRar))
2090 CURL pathToUrl(strArchivePath);
2091 if (strExt == ".rar")
2092 urlRar = URIUtils::CreateArchivePath("rar", pathToUrl, strPathInRar);
2094 urlRar = URIUtils::CreateArchivePath("zip", pathToUrl, strPathInRar);
2095 ScanArchiveForSubtitles(urlRar.Get(), strMovieFileNameNoExt, vecSubtitles);
2097 // done checking if this is a rar-in-rar
2099 // check that the found filename matches the movie filename
2100 int fnl = strMovieFileNameNoExt.size();
2101 if (fnl && !StringUtils::StartsWithNoCase(URIUtils::GetFileName(strPathInRar), strMovieFileNameNoExt))
2105 while (sub_exts[iPos])
2107 if (StringUtils::EqualsNoCase(strExt, sub_exts[iPos]))
2109 CURL pathToURL(strArchivePath);
2110 CStdString strSourceUrl;
2111 if (URIUtils::HasExtension(strArchivePath, ".rar"))
2112 strSourceUrl = URIUtils::CreateArchivePath("rar", pathToURL, strPathInRar).Get();
2114 strSourceUrl = strPathInRar;
2116 CLog::Log(LOGINFO, "%s: found subtitle file %s\n", __FUNCTION__, strSourceUrl.c_str() );
2117 vecSubtitles.push_back( strSourceUrl );
2125 return nSubtitlesAdded;
2128 void CUtil::GetExternalStreamDetailsFromFilename(const CStdString& strVideo, const CStdString& strStream, ExternalStreamInfo& info)
2130 CStdString videoBaseName = URIUtils::GetFileName(strVideo);
2131 URIUtils::RemoveExtension(videoBaseName);
2133 CStdString toParse = URIUtils::GetFileName(strStream);
2134 URIUtils::RemoveExtension(toParse);
2136 // we check left part - if it's same as video base name - strip it
2137 if (StringUtils::StartsWithNoCase(toParse, videoBaseName))
2138 toParse = toParse.substr(videoBaseName.length());
2140 // trim any non-alphanumeric char in the begining
2141 std::string::iterator result = std::find_if(toParse.begin(), toParse.end(), ::isalnum);
2144 if (result != toParse.end()) // if we have anything to parse
2146 std::string inputString(result, toParse.end());
2147 std::string delimiters(" .-");
2148 std::vector<std::string> tokens;
2149 StringUtils::Tokenize(inputString, tokens, delimiters);
2151 for (std::vector<std::string>::iterator it = tokens.begin(); it != tokens.end(); ++it)
2153 if (info.language.empty())
2155 CStdString langTmp(*it);
2156 CStdString langCode;
2157 // try to recognize language
2158 if (g_LangCodeExpander.ConvertToThreeCharCode(langCode, langTmp))
2160 info.language = langCode;
2165 // try to recognize a flag
2166 std::string flag_tmp(*it);
2167 StringUtils::ToLower(flag_tmp);
2168 if (!flag_tmp.compare("none"))
2170 info.flag |= CDemuxStream::FLAG_NONE;
2173 else if (!flag_tmp.compare("default"))
2175 info.flag |= CDemuxStream::FLAG_DEFAULT;
2178 else if (!flag_tmp.compare("forced"))
2180 info.flag |= CDemuxStream::FLAG_FORCED;
2184 name += " " + (*it);
2188 name += g_localizeStrings.Get(21602); // External
2189 StringUtils::Trim(name);
2190 info.name = StringUtils::RemoveDuplicatedSpacesAndTabs(name);
2192 info.flag = CDemuxStream::FLAG_NONE;
2194 CLog::Log(LOGDEBUG, "%s - Language = '%s' / Name = '%s' / Flag = '%u' from %s", __FUNCTION__, info.language.c_str(), info.name.c_str(), info.flag, strStream.c_str());
2197 /*! \brief in a vector of subtitles finds the corresponding .sub file for a given .idx file
2199 bool CUtil::FindVobSubPair(const std::vector<std::string>& vecSubtitles, const std::string& strIdxPath, std::string& strSubPath)
2201 if (URIUtils::HasExtension(strIdxPath, ".idx"))
2203 std::string strIdxFile;
2204 std::string strIdxDirectory;
2205 URIUtils::Split(strIdxPath, strIdxDirectory, strIdxFile);
2206 for (unsigned int j=0; j < vecSubtitles.size(); j++)
2208 std::string strSubFile;
2209 std::string strSubDirectory;
2210 URIUtils::Split(vecSubtitles[j], strSubDirectory, strSubFile);
2211 if (URIUtils::IsInArchive(vecSubtitles[j]))
2212 strSubDirectory = CURL::Decode(strSubDirectory);
2213 if (URIUtils::HasExtension(strSubFile, ".sub") &&
2214 (URIUtils::ReplaceExtension(strIdxPath,"").Equals(URIUtils::ReplaceExtension(vecSubtitles[j],"")) ||
2215 (strSubDirectory.size() >= 11 &&
2216 StringUtils::EqualsNoCase(strSubDirectory.substr(6, strSubDirectory.length()-11), URIUtils::ReplaceExtension(strIdxPath,"")))))
2218 strSubPath = vecSubtitles[j];
2226 /*! \brief checks if in the vector of subtitles the given .sub file has a corresponding idx and hence is a vobsub file
2228 bool CUtil::IsVobSub(const std::vector<std::string>& vecSubtitles, const std::string& strSubPath)
2230 if (URIUtils::HasExtension(strSubPath, ".sub"))
2232 std::string strSubFile;
2233 std::string strSubDirectory;
2234 URIUtils::Split(strSubPath, strSubDirectory, strSubFile);
2235 if (URIUtils::IsInArchive(strSubPath))
2236 strSubDirectory = CURL::Decode(strSubDirectory);
2237 for (unsigned int j=0; j < vecSubtitles.size(); j++)
2239 std::string strIdxFile;
2240 std::string strIdxDirectory;
2241 URIUtils::Split(vecSubtitles[j], strIdxDirectory, strIdxFile);
2242 if (URIUtils::HasExtension(strIdxFile, ".idx") &&
2243 (URIUtils::ReplaceExtension(vecSubtitles[j],"").Equals(URIUtils::ReplaceExtension(strSubPath,"")) ||
2244 (strSubDirectory.size() >= 11 &&
2245 StringUtils::EqualsNoCase(strSubDirectory.substr(6, strSubDirectory.length()-11), URIUtils::ReplaceExtension(vecSubtitles[j],"")))))
2252 /*! \brief find a plain or archived vobsub .sub file corresponding to an .idx file
2254 std::string CUtil::GetVobSubSubFromIdx(const std::string& vobSubIdx)
2256 std::string vobSub = URIUtils::ReplaceExtension(vobSubIdx, ".sub");
2258 // check if a .sub file exists in the same directory
2259 if (CFile::Exists(vobSub))
2264 // look inside a .rar or .zip in the same directory
2265 const std::string archTypes[] = { "rar", "zip" };
2266 std::string vobSubFilename = URIUtils::GetFileName(vobSub);
2267 for (unsigned int i = 0; i < sizeof(archTypes) / sizeof(archTypes[0]); i++)
2269 vobSub = URIUtils::CreateArchivePath(archTypes[i],
2270 CURL(URIUtils::ReplaceExtension(vobSubIdx, std::string(".") + archTypes[i])),
2271 vobSubFilename).Get();
2272 if (CFile::Exists(vobSub))
2276 return std::string();
2279 /*! \brief find a .idx file from a path of a plain or archived vobsub .sub file
2281 std::string CUtil::GetVobSubIdxFromSub(const std::string& vobSub)
2283 std::string vobSubIdx = URIUtils::ReplaceExtension(vobSub, ".idx");
2285 // check if a .idx file exists in the same directory
2286 if (CFile::Exists(vobSubIdx))
2291 // look outside archive (usually .rar) if the .sub is inside one
2292 if (URIUtils::IsInArchive(vobSub))
2295 std::string archiveFile = URIUtils::GetDirectory(vobSub);
2296 std::string vobSubIdxDir = URIUtils::GetParentPath(archiveFile);
2298 if (!vobSubIdxDir.empty())
2300 std::string vobSubIdxFilename = URIUtils::GetFileName(vobSubIdx);
2301 std::string vobSubIdx = URIUtils::AddFileToFolder(vobSubIdxDir, vobSubIdxFilename);
2303 if (CFile::Exists(vobSubIdx))
2308 return std::string();
2311 bool CUtil::CanBindPrivileged()
2316 return true; //root user can always bind to privileged ports
2320 //check if CAP_NET_BIND_SERVICE is enabled, this allows non-root users to bind to privileged ports
2321 bool canbind = false;
2322 cap_t capabilities = cap_get_proc();
2325 cap_flag_value_t value;
2326 if (cap_get_flag(capabilities, CAP_NET_BIND_SERVICE, CAP_EFFECTIVE, &value) == 0)
2329 cap_free(capabilities);
2338 #endif //HAVE_LIBCAP
2340 #else //TARGET_POSIX
2344 #endif //TARGET_POSIX
2347 bool CUtil::ValidatePort(int port)
2349 // check that it's a valid port
2351 if (!CUtil::CanBindPrivileged() && (port < 1024 || port > 65535))
2355 if (port <= 0 || port > 65535)
2361 int CUtil::GetRandomNumber()
2363 #ifdef TARGET_WINDOWS
2364 unsigned int number;
2365 if (rand_s(&number) == 0)
2368 return rand_r(&s_randomSeed);