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 #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]
104 static const int64_t SECS_BETWEEN_EPOCHS = 11644473600LL;
105 static const int64_t SECS_TO_100NS = 10000000;
107 using namespace XFILE;
108 using namespace PLAYLIST;
111 static D3DGAMMARAMP oldramp, flashramp;
112 #elif defined(HAS_SDL_2D)
113 static uint16_t oldrampRed[256];
114 static uint16_t oldrampGreen[256];
115 static uint16_t oldrampBlue[256];
116 static uint16_t flashrampRed[256];
117 static uint16_t flashrampGreen[256];
118 static uint16_t flashrampBlue[256];
121 #if !defined(TARGET_WINDOWS)
122 unsigned int CUtil::s_randomSeed = time(NULL);
132 CStdString CUtil::GetTitleFromPath(const CStdString& strFileNameAndPath, bool bIsFolder /* = false */)
134 // use above to get the filename
135 CStdString path(strFileNameAndPath);
136 URIUtils::RemoveSlashAtEnd(path);
137 CStdString strFilename = URIUtils::GetFileName(path);
139 CURL url(strFileNameAndPath);
140 CStdString strHostname = url.GetHostName();
144 if (url.GetProtocol() == "upnp")
145 strFilename = CUPnPDirectory::GetFriendlyName(strFileNameAndPath.c_str());
148 if (url.GetProtocol() == "rss")
152 if(dir.GetDirectory(strFileNameAndPath, items) && !items.m_strTitle.IsEmpty())
153 return items.m_strTitle;
157 else if (url.GetProtocol() == "shout")
159 const int genre = strFileNameAndPath.find_first_of('=');
161 strFilename = g_localizeStrings.Get(260);
163 strFilename = g_localizeStrings.Get(260) + " - " + strFileNameAndPath.substr(genre+1).c_str();
166 // Windows SMB Network (SMB)
167 else if (url.GetProtocol() == "smb" && strFilename.IsEmpty())
169 if (url.GetHostName().IsEmpty())
171 strFilename = g_localizeStrings.Get(20171);
175 strFilename = url.GetHostName();
178 // iTunes music share (DAAP)
179 else if (url.GetProtocol() == "daap" && strFilename.IsEmpty())
180 strFilename = g_localizeStrings.Get(20174);
183 else if (url.GetProtocol() == "hdhomerun" && strFilename.IsEmpty())
184 strFilename = "HDHomerun Devices";
187 else if (url.GetProtocol() == "sling")
188 strFilename = "Slingbox";
191 else if (url.GetProtocol() == "rtv")
192 strFilename = "ReplayTV Devices";
194 // HTS Tvheadend client
195 else if (url.GetProtocol() == "htsp")
196 strFilename = g_localizeStrings.Get(20256);
198 // VDR Streamdev client
199 else if (url.GetProtocol() == "vtp")
200 strFilename = g_localizeStrings.Get(20257);
203 else if (url.GetProtocol() == "myth")
204 strFilename = g_localizeStrings.Get(20258);
207 else if (url.GetProtocol() == "sap" && strFilename.IsEmpty())
208 strFilename = "SAP Streams";
211 else if (url.GetProtocol() == "sources")
212 strFilename = g_localizeStrings.Get(744);
215 else if (StringUtils::StartsWithNoCase(path, "special://musicplaylists"))
216 strFilename = g_localizeStrings.Get(136);
219 else if (StringUtils::StartsWithNoCase(path, "special://videoplaylists"))
220 strFilename = g_localizeStrings.Get(136);
222 else if (URIUtils::ProtocolHasParentInHostname(url.GetProtocol()) && strFilename.IsEmpty())
223 strFilename = URIUtils::GetFileName(url.GetHostName());
225 // now remove the extension if needed
226 if (!CSettings::Get().GetBool("filelists.showextensions") && !bIsFolder)
228 URIUtils::RemoveExtension(strFilename);
232 // URLDecode since the original path may be an URL
233 CURL::Decode(strFilename);
237 void CUtil::CleanString(const CStdString& strFileName, CStdString& strTitle, CStdString& strTitleAndYear, CStdString& strYear, bool bRemoveExtension /* = false */, bool bCleanChars /* = true */)
239 strTitleAndYear = strFileName;
241 if (strFileName.Equals(".."))
244 const CStdStringArray ®exps = g_advancedSettings.m_videoCleanStringRegExps;
246 CRegExp reTags(true, true);
247 CRegExp reYear(false, true);
249 if (!reYear.RegComp(g_advancedSettings.m_videoCleanDateTimeRegExp))
251 CLog::Log(LOGERROR, "%s: Invalid datetime clean RegExp:'%s'", __FUNCTION__, g_advancedSettings.m_videoCleanDateTimeRegExp.c_str());
255 if (reYear.RegFind(strTitleAndYear.c_str()) >= 0)
257 strTitleAndYear = reYear.GetMatch(1);
258 strYear = reYear.GetMatch(2);
262 URIUtils::RemoveExtension(strTitleAndYear);
264 for (unsigned int i = 0; i < regexps.size(); i++)
266 if (!reTags.RegComp(regexps[i].c_str()))
267 { // invalid regexp - complain in logs
268 CLog::Log(LOGERROR, "%s: Invalid string clean RegExp:'%s'", __FUNCTION__, regexps[i].c_str());
272 if ((j=reTags.RegFind(strTitleAndYear.c_str())) > 0)
273 strTitleAndYear = strTitleAndYear.Mid(0, j);
276 // final cleanup - special characters used instead of spaces:
277 // all '_' tokens should be replaced by spaces
278 // if the file contains no spaces, all '.' tokens should be replaced by
279 // spaces - one possibility of a mistake here could be something like:
280 // "Dr..StrangeLove" - hopefully no one would have anything like this.
283 bool initialDots = true;
284 bool alreadyContainsSpace = (strTitleAndYear.Find(' ') >= 0);
286 for (int i = 0; i < (int)strTitleAndYear.size(); i++)
288 char c = strTitleAndYear.GetAt(i);
293 if ((c == '_') || ((!alreadyContainsSpace) && !initialDots && (c == '.')))
295 strTitleAndYear.SetAt(i, ' ');
300 strTitle = strTitleAndYear.Trim();
303 if (!strYear.IsEmpty())
304 strTitleAndYear = strTitle + " (" + strYear + ")";
306 // restore extension if needed
307 if (!bRemoveExtension)
308 strTitleAndYear += URIUtils::GetExtension(strFileName);
311 void CUtil::GetQualifiedFilename(const CStdString &strBasePath, CStdString &strFilename)
313 // Check if the filename is a fully qualified URL such as protocol://path/to/file
314 CURL plItemUrl(strFilename);
315 if (!plItemUrl.GetProtocol().IsEmpty())
318 // If the filename starts "x:", "\\" or "/" it's already fully qualified so return
319 if (strFilename.size() > 1)
321 if ( (strFilename[1] == ':') || (strFilename[0] == '/') )
323 if ( strFilename[1] == ':' || (strFilename[0] == '\\' && strFilename[1] == '\\'))
327 // add to base path and then clean
328 strFilename = URIUtils::AddFileToFolder(strBasePath, strFilename);
330 // get rid of any /./ or \.\ that happen to be there
331 strFilename.Replace("\\.\\", "\\");
332 strFilename.Replace("/./", "/");
334 // now find any "\\..\\" and remove them via GetParentPath
336 while ((pos = strFilename.Find("/../")) > 0)
338 CStdString basePath = strFilename.Left(pos+1);
339 strFilename = strFilename.Mid(pos+4);
340 basePath = URIUtils::GetParentPath(basePath);
341 strFilename = URIUtils::AddFileToFolder(basePath, strFilename);
343 while ((pos = strFilename.Find("\\..\\")) > 0)
345 CStdString basePath = strFilename.Left(pos+1);
346 strFilename = strFilename.Mid(pos+4);
347 basePath = URIUtils::GetParentPath(basePath);
348 strFilename = URIUtils::AddFileToFolder(basePath, strFilename);
353 bool CUtil::TestGetQualifiedFilename()
355 CStdString file = "../foo"; GetQualifiedFilename("smb://", file);
356 if (file != "foo") return false;
357 file = "C:\\foo\\bar"; GetQualifiedFilename("smb://", file);
358 if (file != "C:\\foo\\bar") return false;
359 file = "../foo/./bar"; GetQualifiedFilename("smb://my/path", file);
360 if (file != "smb://my/foo/bar") return false;
361 file = "smb://foo/bar/"; GetQualifiedFilename("upnp://", file);
362 if (file != "smb://foo/bar/") return false;
366 bool CUtil::TestMakeLegalPath()
369 #ifdef TARGET_WINDOWS
370 path = "C:\\foo\\bar"; path = MakeLegalPath(path);
371 if (path != "C:\\foo\\bar") return false;
372 path = "C:\\foo:\\bar\\"; path = MakeLegalPath(path);
373 if (path != "C:\\foo_\\bar\\") return false;
375 path = "/foo/bar/"; path = MakeLegalPath(path);
376 if (path != "/foo/bar/") return false;
377 path = "/foo?/bar"; path = MakeLegalPath(path);
378 if (path != "/foo_/bar") return false;
380 path = "smb://foo/bar"; path = MakeLegalPath(path);
381 if (path != "smb://foo/bar") return false;
382 path = "smb://foo/bar?/"; path = MakeLegalPath(path);
383 if (path != "smb://foo/bar_/") return false;
388 void CUtil::RunShortcut(const char* szShortcutPath)
392 void CUtil::GetHomePath(CStdString& strPath, const CStdString& strTarget)
394 strPath = CEnvironment::getenv(strTarget);
396 #ifdef TARGET_WINDOWS
397 if (strPath.find("..") != std::string::npos)
399 //expand potential relative path to full path
400 CStdStringW strPathW;
401 g_charsetConverter.utf8ToW(strPath, strPathW, false);
402 CWIN32Util::AddExtraLongPathPrefix(strPathW);
403 const unsigned int bufSize = GetFullPathNameW(strPathW, 0, NULL, NULL);
406 wchar_t * buf = new wchar_t[bufSize];
407 if (GetFullPathNameW(strPathW, bufSize, buf, NULL) <= bufSize-1)
409 std::wstring expandedPathW(buf);
410 CWIN32Util::RemoveExtraLongPathPrefix(expandedPathW);
411 g_charsetConverter.wToUTF8(expandedPathW, strPath);
419 if (strPath.IsEmpty())
421 CStdString strHomePath = ResolveExecutablePath();
422 #if defined(TARGET_DARWIN)
424 char given_path[2*MAXPATHLEN];
425 uint32_t path_size =2*MAXPATHLEN;
427 result = GetDarwinExecutablePath(given_path, &path_size);
430 // Move backwards to last /.
431 for (int n=strlen(given_path)-1; given_path[n] != '/'; n--)
432 given_path[n] = '\0';
434 #if defined(TARGET_DARWIN_IOS)
435 strcat(given_path, "/XBMCData/XBMCHome/");
437 // Assume local path inside application bundle.
438 strcat(given_path, "../Resources/XBMC/");
441 // Convert to real path.
442 char real_path[2*MAXPATHLEN];
443 if (realpath(given_path, real_path) != NULL)
450 size_t last_sep = strHomePath.find_last_of(PATH_SEPARATOR_CHAR);
451 if (last_sep != string::npos)
452 strPath = strHomePath.Left(last_sep);
454 strPath = strHomePath;
457 #if defined(TARGET_POSIX) && !defined(TARGET_DARWIN)
458 /* Change strPath accordingly when target is XBMC_HOME and when INSTALL_PATH
459 * and BIN_INSTALL_PATH differ
461 CStdString installPath = INSTALL_PATH;
462 CStdString binInstallPath = BIN_INSTALL_PATH;
463 if (!strTarget.compare("XBMC_HOME") && installPath.compare(binInstallPath))
465 int pos = strPath.length() - binInstallPath.length();
466 CStdString tmp = strPath;
468 if (!tmp.compare(binInstallPath))
470 strPath.erase(pos, strPath.length());
471 strPath.append(installPath);
477 bool CUtil::IsPVR(const CStdString& strFile)
479 return StringUtils::StartsWithNoCase(strFile, "pvr:");
482 bool CUtil::IsHTSP(const CStdString& strFile)
484 return StringUtils::StartsWithNoCase(strFile, "htsp:");
487 bool CUtil::IsLiveTV(const CStdString& strFile)
489 if (StringUtils::StartsWithNoCase(strFile, "pvr://channels"))
492 if(URIUtils::IsTuxBox(strFile)
493 || URIUtils::IsVTP(strFile)
494 || URIUtils::IsHDHomeRun(strFile)
495 || URIUtils::IsHTSP(strFile)
496 || StringUtils::StartsWithNoCase(strFile, "sap:"))
499 if (URIUtils::IsMythTV(strFile) && CMythDirectory::IsLiveTV(strFile))
505 bool CUtil::IsTVRecording(const CStdString& strFile)
507 return StringUtils::StartsWithNoCase(strFile, "pvr://recording");
510 bool CUtil::IsPicture(const CStdString& strFile)
512 return URIUtils::HasExtension(strFile,
513 g_advancedSettings.m_pictureExtensions + "|.tbn|.dds");
516 bool CUtil::ExcludeFileOrFolder(const CStdString& strFileOrFolder, const CStdStringArray& regexps)
518 if (strFileOrFolder.IsEmpty())
521 CRegExp regExExcludes(true, true); // case insensitive regex
523 for (unsigned int i = 0; i < regexps.size(); i++)
525 if (!regExExcludes.RegComp(regexps[i].c_str()))
526 { // invalid regexp - complain in logs
527 CLog::Log(LOGERROR, "%s: Invalid exclude RegExp:'%s'", __FUNCTION__, regexps[i].c_str());
530 if (regExExcludes.RegFind(strFileOrFolder) > -1)
532 CLog::Log(LOGDEBUG, "%s: File '%s' excluded. (Matches exclude rule RegExp:'%s')", __FUNCTION__, strFileOrFolder.c_str(), regexps[i].c_str());
539 void CUtil::GetFileAndProtocol(const CStdString& strURL, CStdString& strDir)
542 if (!URIUtils::IsRemote(strURL)) return ;
543 if (URIUtils::IsDVD(strURL)) return ;
546 strDir = StringUtils::Format("%s://%s", url.GetProtocol().c_str(), url.GetFileName().c_str());
549 int CUtil::GetDVDIfoTitle(const CStdString& strFile)
551 CStdString strFilename = URIUtils::GetFileName(strFile);
552 if (strFilename.Equals("video_ts.ifo")) return 0;
554 return atoi(strFilename.Mid(4, 2).c_str());
557 CStdString CUtil::GetFileMD5(const CStdString& strPath)
561 if (file.Open(strPath))
569 read = file.Read(temp,1024);
571 md5.append(temp,read);
573 md5.getDigest(result);
580 bool CUtil::GetDirectoryName(const CStdString& strFileName, CStdString& strDescription)
582 CStdString strFName = URIUtils::GetFileName(strFileName);
583 strDescription = strFileName.Left(strFileName.size() - strFName.size());
584 URIUtils::RemoveSlashAtEnd(strDescription);
586 int iPos = strDescription.ReverseFind("\\");
588 iPos = strDescription.ReverseFind("/");
591 CStdString strTmp = strDescription.Right(strDescription.size()-iPos-1);
592 strDescription = strTmp;//strDescription.Right(strDescription.size() - iPos - 1);
594 else if (strDescription.size() <= 0)
595 strDescription = strFName;
599 void CUtil::GetDVDDriveIcon( const CStdString& strPath, CStdString& strIcon )
601 if ( !g_mediaManager.IsDiscInDrive() )
603 strIcon = "DefaultDVDEmpty.png";
607 if ( URIUtils::IsDVD(strPath) )
610 CCdInfo* pInfo = g_mediaManager.GetCdInfo();
612 if ( pInfo != NULL && pInfo->IsUDFX( 1 ) )
614 strIcon = "DefaultXboxDVD.png";
618 strIcon = "DefaultDVDRom.png";
622 if ( URIUtils::IsISO9660(strPath) )
625 CCdInfo* pInfo = g_mediaManager.GetCdInfo();
626 if ( pInfo != NULL && pInfo->IsVideoCd( 1 ) )
628 strIcon = "DefaultVCD.png";
632 strIcon = "DefaultDVDRom.png";
636 if ( URIUtils::IsCDDA(strPath) )
638 strIcon = "DefaultCDDA.png";
643 void CUtil::RemoveTempFiles()
645 CStdString searchPath = CProfilesManager::Get().GetDatabaseFolder();
647 if (!XFILE::CDirectory::GetDirectory(searchPath, items, ".tmp", DIR_FLAG_NO_FILE_DIRS))
650 for (int i = 0; i < items.Size(); ++i)
652 if (items[i]->m_bIsFolder)
654 XFILE::CFile::Delete(items[i]->GetPath());
658 void CUtil::ClearSubtitles()
662 CDirectory::GetDirectory("special://temp/",items);
663 for( int i=0;i<items.Size();++i)
665 if (!items[i]->m_bIsFolder)
667 if ( items[i]->GetPath().Find("subtitle") >= 0 || items[i]->GetPath().Find("vobsub_queue") >= 0 )
669 CLog::Log(LOGDEBUG, "%s - Deleting temporary subtitle %s", __FUNCTION__, items[i]->GetPath().c_str());
670 CFile::Delete(items[i]->GetPath());
676 void CUtil::ClearTempFonts()
678 CStdString searchPath = "special://temp/fonts/";
680 if (!CFile::Exists(searchPath))
684 CDirectory::GetDirectory(searchPath, items, "", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_BYPASS_CACHE);
686 for (int i=0; i<items.Size(); ++i)
688 if (items[i]->m_bIsFolder)
690 CFile::Delete(items[i]->GetPath());
694 static const char * sub_exts[] = { ".utf", ".utf8", ".utf-8", ".sub", ".srt", ".smi", ".rt", ".txt", ".ssa", ".aqt", ".jss", ".ass", ".idx", NULL};
696 int64_t CUtil::ToInt64(uint32_t high, uint32_t low)
705 CStdString CUtil::GetNextFilename(const CStdString &fn_template, int max)
707 if (!fn_template.Find("%03d"))
710 CStdString searchPath = URIUtils::GetDirectory(fn_template);
711 CStdString mask = URIUtils::GetExtension(fn_template);
712 CStdString name = StringUtils::Format(fn_template.c_str(), 0);
715 if (!CDirectory::GetDirectory(searchPath, items, mask, DIR_FLAG_NO_FILE_DIRS))
718 items.SetFastLookup(true);
719 for (int i = 0; i <= max; i++)
721 CStdString name = StringUtils::Format(fn_template.c_str(), i);
722 if (!items.Get(name))
728 CStdString CUtil::GetNextPathname(const CStdString &path_template, int max)
730 if (!path_template.Find("%04d"))
733 for (int i = 0; i <= max; i++)
735 CStdString name = StringUtils::Format(path_template.c_str(), i);
736 if (!CFile::Exists(name))
742 void CUtil::StatToStatI64(struct _stati64 *result, struct stat *stat)
744 result->st_dev = stat->st_dev;
745 result->st_ino = stat->st_ino;
746 result->st_mode = stat->st_mode;
747 result->st_nlink = stat->st_nlink;
748 result->st_uid = stat->st_uid;
749 result->st_gid = stat->st_gid;
750 result->st_rdev = stat->st_rdev;
751 result->st_size = (int64_t)stat->st_size;
754 result->st_atime = (long)(stat->st_atime & 0xFFFFFFFF);
755 result->st_mtime = (long)(stat->st_mtime & 0xFFFFFFFF);
756 result->st_ctime = (long)(stat->st_ctime & 0xFFFFFFFF);
758 result->_st_atime = (long)(stat->st_atime & 0xFFFFFFFF);
759 result->_st_mtime = (long)(stat->st_mtime & 0xFFFFFFFF);
760 result->_st_ctime = (long)(stat->st_ctime & 0xFFFFFFFF);
764 void CUtil::Stat64ToStatI64(struct _stati64 *result, struct __stat64 *stat)
766 result->st_dev = stat->st_dev;
767 result->st_ino = stat->st_ino;
768 result->st_mode = stat->st_mode;
769 result->st_nlink = stat->st_nlink;
770 result->st_uid = stat->st_uid;
771 result->st_gid = stat->st_gid;
772 result->st_rdev = stat->st_rdev;
773 result->st_size = stat->st_size;
775 result->st_atime = (long)(stat->st_atime & 0xFFFFFFFF);
776 result->st_mtime = (long)(stat->st_mtime & 0xFFFFFFFF);
777 result->st_ctime = (long)(stat->st_ctime & 0xFFFFFFFF);
779 result->_st_atime = (long)(stat->st_atime & 0xFFFFFFFF);
780 result->_st_mtime = (long)(stat->st_mtime & 0xFFFFFFFF);
781 result->_st_ctime = (long)(stat->st_ctime & 0xFFFFFFFF);
785 void CUtil::StatI64ToStat64(struct __stat64 *result, struct _stati64 *stat)
787 result->st_dev = stat->st_dev;
788 result->st_ino = stat->st_ino;
789 result->st_mode = stat->st_mode;
790 result->st_nlink = stat->st_nlink;
791 result->st_uid = stat->st_uid;
792 result->st_gid = stat->st_gid;
793 result->st_rdev = stat->st_rdev;
794 result->st_size = stat->st_size;
796 result->st_atime = stat->st_atime;
797 result->st_mtime = stat->st_mtime;
798 result->st_ctime = stat->st_ctime;
800 result->st_atime = stat->_st_atime;
801 result->st_mtime = stat->_st_mtime;
802 result->st_ctime = stat->_st_ctime;
806 void CUtil::Stat64ToStat(struct stat *result, struct __stat64 *stat)
808 result->st_dev = stat->st_dev;
809 result->st_ino = stat->st_ino;
810 result->st_mode = stat->st_mode;
811 result->st_nlink = stat->st_nlink;
812 result->st_uid = stat->st_uid;
813 result->st_gid = stat->st_gid;
814 result->st_rdev = stat->st_rdev;
816 if (stat->st_size <= LONG_MAX)
817 result->st_size = (_off_t)stat->st_size;
819 if (sizeof(stat->st_size) <= sizeof(result->st_size) )
820 result->st_size = stat->st_size;
825 CLog::Log(LOGWARNING, "WARNING: File is larger than 32bit stat can handle, file size will be reported as 0 bytes");
827 result->st_atime = (time_t)(stat->st_atime & 0xFFFFFFFF);
828 result->st_mtime = (time_t)(stat->st_mtime & 0xFFFFFFFF);
829 result->st_ctime = (time_t)(stat->st_ctime & 0xFFFFFFFF);
832 #ifdef TARGET_WINDOWS
833 void CUtil::Stat64ToStat64i32(struct _stat64i32 *result, struct __stat64 *stat)
835 result->st_dev = stat->st_dev;
836 result->st_ino = stat->st_ino;
837 result->st_mode = stat->st_mode;
838 result->st_nlink = stat->st_nlink;
839 result->st_uid = stat->st_uid;
840 result->st_gid = stat->st_gid;
841 result->st_rdev = stat->st_rdev;
843 if (stat->st_size <= LONG_MAX)
844 result->st_size = (_off_t)stat->st_size;
846 if (sizeof(stat->st_size) <= sizeof(result->st_size) )
847 result->st_size = stat->st_size;
852 CLog::Log(LOGWARNING, "WARNING: File is larger than 32bit stat can handle, file size will be reported as 0 bytes");
855 result->st_atime = stat->st_atime;
856 result->st_mtime = stat->st_mtime;
857 result->st_ctime = stat->st_ctime;
859 result->st_atime = stat->_st_atime;
860 result->st_mtime = stat->_st_mtime;
861 result->st_ctime = stat->_st_ctime;
866 bool CUtil::CreateDirectoryEx(const CStdString& strPath)
868 // Function to create all directories at once instead
869 // of calling CreateDirectory for every subdir.
870 // Creates the directory and subdirectories if needed.
872 // return true if directory already exist
873 if (CDirectory::Exists(strPath)) return true;
875 // we currently only allow HD and smb, nfs and afp paths
876 if (!URIUtils::IsHD(strPath) && !URIUtils::IsSmb(strPath) && !URIUtils::IsNfs(strPath) && !URIUtils::IsAfp(strPath))
878 CLog::Log(LOGERROR,"%s called with an unsupported path: %s", __FUNCTION__, strPath.c_str());
882 CStdStringArray dirs = URIUtils::SplitPath(strPath);
883 CStdString dir(dirs.front());
884 URIUtils::AddSlashAtEnd(dir);
885 for (CStdStringArray::iterator it = dirs.begin() + 1; it != dirs.end(); it ++)
887 dir = URIUtils::AddFileToFolder(dir, *it);
888 CDirectory::Create(dir);
891 // was the final destination directory successfully created ?
892 if (!CDirectory::Exists(strPath)) return false;
896 CStdString CUtil::MakeLegalFileName(const CStdString &strFile, int LegalType)
898 CStdString result = strFile;
900 result.Replace('/', '_');
901 result.Replace('\\', '_');
902 result.Replace('?', '_');
904 if (LegalType == LEGAL_WIN32_COMPAT)
906 // just filter out some illegal characters on windows
907 result.Replace(':', '_');
908 result.Replace('*', '_');
909 result.Replace('?', '_');
910 result.Replace('\"', '_');
911 result.Replace('<', '_');
912 result.Replace('>', '_');
913 result.Replace('|', '_');
914 result.TrimRight(".");
915 result.TrimRight(" ");
920 // legalize entire path
921 CStdString CUtil::MakeLegalPath(const CStdString &strPathAndFile, int LegalType)
923 if (URIUtils::IsStack(strPathAndFile))
924 return MakeLegalPath(CStackDirectory::GetFirstStackedFile(strPathAndFile));
925 if (URIUtils::IsMultiPath(strPathAndFile))
926 return MakeLegalPath(CMultiPathDirectory::GetFirstPath(strPathAndFile));
927 if (!URIUtils::IsHD(strPathAndFile) && !URIUtils::IsSmb(strPathAndFile) && !URIUtils::IsNfs(strPathAndFile) && !URIUtils::IsAfp(strPathAndFile))
928 return strPathAndFile; // we don't support writing anywhere except HD, SMB, NFS and AFP - no need to legalize path
930 bool trailingSlash = URIUtils::HasSlashAtEnd(strPathAndFile);
931 CStdStringArray dirs = URIUtils::SplitPath(strPathAndFile);
932 // we just add first token to path and don't legalize it - possible values:
933 // "X:" (local win32), "" (local unix - empty string before '/') or
934 // "protocol://domain"
935 CStdString dir(dirs.front());
936 URIUtils::AddSlashAtEnd(dir);
937 for (CStdStringArray::iterator it = dirs.begin() + 1; it != dirs.end(); it ++)
938 dir = URIUtils::AddFileToFolder(dir, MakeLegalFileName(*it, LegalType));
939 if (trailingSlash) URIUtils::AddSlashAtEnd(dir);
943 CStdString CUtil::ValidatePath(const CStdString &path, bool bFixDoubleSlashes /* = false */)
945 CStdString result = path;
947 // Don't do any stuff on URLs containing %-characters or protocols that embed
948 // filenames. NOTE: Don't use IsInZip or IsInRar here since it will infinitely
949 // recurse and crash XBMC
950 if (URIUtils::IsURL(path) &&
951 (path.Find('%') >= 0 ||
952 StringUtils::StartsWithNoCase(path, "apk:") ||
953 StringUtils::StartsWithNoCase(path, "zip:") ||
954 StringUtils::StartsWithNoCase(path, "rar:") ||
955 StringUtils::StartsWithNoCase(path, "stack:") ||
956 StringUtils::StartsWithNoCase(path, "bluray:") ||
957 StringUtils::StartsWithNoCase(path, "multipath:") ))
960 // check the path for incorrect slashes
961 #ifdef TARGET_WINDOWS
962 if (URIUtils::IsDOSPath(path))
964 result.Replace('/', '\\');
965 /* The double slash correction should only be used when *absolutely*
966 necessary! This applies to certain DLLs or use from Python DLLs/scripts
967 that incorrectly generate double (back) slashes.
969 if (bFixDoubleSlashes)
971 // Fixup for double back slashes (but ignore the \\ of unc-paths)
972 for (int x = 1; x < result.GetLength() - 1; x++)
974 if (result[x] == '\\' && result[x+1] == '\\')
979 else if (path.Find("://") >= 0 || path.Find(":\\\\") >= 0)
982 result.Replace('\\', '/');
983 /* The double slash correction should only be used when *absolutely*
984 necessary! This applies to certain DLLs or use from Python DLLs/scripts
985 that incorrectly generate double (back) slashes.
987 if (bFixDoubleSlashes)
989 // Fixup for double forward slashes(/) but don't touch the :// of URLs
990 for (int x = 2; x < result.GetLength() - 1; x++)
992 if ( result[x] == '/' && result[x + 1] == '/' && !(result[x - 1] == ':' || (result[x - 1] == '/' && result[x - 2] == ':')) )
1000 bool CUtil::IsUsingTTFSubtitles()
1002 return URIUtils::HasExtension(CSettings::Get().GetString("subtitles.font"), ".ttf");
1006 bool CUtil::TestSplitExec()
1008 CStdString function;
1009 vector<CStdString> params;
1010 CUtil::SplitExecFunction("ActivateWindow(Video, \"C:\\test\\foo\")", function, params);
1011 if (function != "ActivateWindow" || params.size() != 2 || params[0] != "Video" || params[1] != "C:\\test\\foo")
1014 CUtil::SplitExecFunction("ActivateWindow(Video, \"C:\\test\\foo\\\")", function, params);
1015 if (function != "ActivateWindow" || params.size() != 2 || params[0] != "Video" || params[1] != "C:\\test\\foo\"")
1017 CUtil::SplitExecFunction("ActivateWindow(Video, \"C:\\\\test\\\\foo\\\\\")", function, params);
1018 if (function != "ActivateWindow" || params.size() != 2 || params[0] != "Video" || params[1] != "C:\\test\\foo\\")
1020 CUtil::SplitExecFunction("ActivateWindow(Video, \"C:\\\\\\\\test\\\\\\foo\\\\\")", function, params);
1021 if (function != "ActivateWindow" || params.size() != 2 || params[0] != "Video" || params[1] != "C:\\\\test\\\\foo\\")
1023 CUtil::SplitExecFunction("SetProperty(Foo,\"\")", function, params);
1024 if (function != "SetProperty" || params.size() != 2 || params[0] != "Foo" || params[1] != "")
1026 CUtil::SplitExecFunction("SetProperty(foo,ba(\"ba black )\",sheep))", function, params);
1027 if (function != "SetProperty" || params.size() != 2 || params[0] != "foo" || params[1] != "ba(\"ba black )\",sheep)")
1033 void CUtil::SplitExecFunction(const CStdString &execString, CStdString &function, vector<CStdString> ¶meters)
1035 CStdString paramString;
1037 int iPos = execString.Find("(");
1038 int iPos2 = execString.ReverseFind(")");
1039 if (iPos > 0 && iPos2 > 0)
1041 paramString = execString.Mid(iPos + 1, iPos2 - iPos - 1);
1042 function = execString.Left(iPos);
1045 function = execString;
1047 // remove any whitespace, and the standard prefix (if it exists)
1049 if( StringUtils::StartsWithNoCase(function, "xbmc.") )
1050 function.Delete(0, 5);
1052 SplitParams(paramString, parameters);
1055 void CUtil::SplitParams(const CStdString ¶mString, std::vector<CStdString> ¶meters)
1057 bool inQuotes = false;
1058 bool lastEscaped = false; // only every second character can be escaped
1060 size_t whiteSpacePos = 0;
1061 CStdString parameter;
1063 for (size_t pos = 0; pos < paramString.size(); pos++)
1065 char ch = paramString[pos];
1066 bool escaped = (pos > 0 && paramString[pos - 1] == '\\' && !lastEscaped);
1067 lastEscaped = escaped;
1069 { // if we're in a quote, we accept everything until the closing quote
1070 if (ch == '"' && !escaped)
1071 { // finished a quote - no need to add the end quote to our string
1076 { // not in a quote, so check if we should be starting one
1077 if (ch == '"' && !escaped)
1078 { // start of quote - no need to add the quote to our string
1081 if (inFunction && ch == ')')
1082 { // end of a function
1086 { // start of function
1089 if (!inFunction && ch == ',')
1090 { // not in a function, so a comma signfies the end of this parameter
1092 parameter = parameter.Left(whiteSpacePos);
1093 // trim off start and end quotes
1094 if (parameter.GetLength() > 1 && parameter[0] == '"' && parameter[parameter.GetLength() - 1] == '"')
1095 parameter = parameter.Mid(1,parameter.GetLength() - 2);
1096 else if (parameter.GetLength() > 3 && parameter[parameter.GetLength() - 1] == '"')
1098 // check name="value" style param.
1099 int quotaPos = parameter.Find('"');
1100 if (quotaPos > 1 && quotaPos < parameter.GetLength() - 1 && parameter[quotaPos - 1] == '=')
1102 parameter.Delete(parameter.GetLength() - 1);
1103 parameter.Delete(quotaPos);
1106 parameters.push_back(parameter);
1112 if ((ch == '"' || ch == '\\') && escaped)
1113 { // escaped quote or backslash
1114 parameter[parameter.size()-1] = ch;
1117 // whitespace handling - we skip any whitespace at the left or right of an unquoted parameter
1118 if (ch == ' ' && !inQuotes)
1120 if (parameter.IsEmpty()) // skip whitespace on left
1122 if (!whiteSpacePos) // make a note of where whitespace starts on the right
1123 whiteSpacePos = parameter.size();
1129 if (inFunction || inQuotes)
1130 CLog::Log(LOGWARNING, "%s(%s) - end of string while searching for ) or \"", __FUNCTION__, paramString.c_str());
1132 parameter = parameter.Left(whiteSpacePos);
1133 // trim off start and end quotes
1134 if (parameter.GetLength() > 1 && parameter[0] == '"' && parameter[parameter.GetLength() - 1] == '"')
1135 parameter = parameter.Mid(1,parameter.GetLength() - 2);
1136 else if (parameter.GetLength() > 3 && parameter[parameter.GetLength() - 1] == '"')
1138 // check name="value" style param.
1139 int quotaPos = parameter.Find('"');
1140 if (quotaPos > 1 && quotaPos < parameter.GetLength() - 1 && parameter[quotaPos - 1] == '=')
1142 parameter.Delete(parameter.GetLength() - 1);
1143 parameter.Delete(quotaPos);
1146 if (!parameter.IsEmpty() || parameters.size())
1147 parameters.push_back(parameter);
1150 int CUtil::GetMatchingSource(const CStdString& strPath1, VECSOURCES& VECSOURCES, bool& bIsSourceName)
1152 if (strPath1.IsEmpty())
1155 // copy as we may change strPath
1156 CStdString strPath = strPath1;
1158 // Check for special protocols
1159 CURL checkURL(strPath);
1162 if (checkURL.GetProtocol() == "stack")
1163 strPath.Delete(0, 8); // remove the stack protocol
1165 if (checkURL.GetProtocol() == "shout")
1166 strPath = checkURL.GetHostName();
1167 if (checkURL.GetProtocol() == "tuxbox")
1169 if (checkURL.GetProtocol() == "plugin")
1171 if (checkURL.GetProtocol() == "multipath")
1172 strPath = CMultiPathDirectory::GetFirstPath(strPath);
1174 bIsSourceName = false;
1177 // we first test the NAME of a source
1178 for (int i = 0; i < (int)VECSOURCES.size(); ++i)
1180 CMediaSource share = VECSOURCES.at(i);
1181 CStdString strName = share.strName;
1183 // special cases for dvds
1184 if (URIUtils::IsOnDVD(share.strPath))
1186 if (URIUtils::IsOnDVD(strPath))
1189 // not a path, so we need to modify the source name
1190 // since we add the drive status and disc name to the source
1191 // "Name (Drive Status/Disc Name)"
1192 int iPos = strName.ReverseFind('(');
1194 strName = strName.Mid(0, iPos - 1);
1196 if (strPath.Equals(strName))
1198 bIsSourceName = true;
1203 // now test the paths
1205 // remove user details, and ensure path only uses forward slashes
1206 // and ends with a trailing slash so as not to match a substring
1207 CURL urlDest(strPath);
1208 urlDest.SetOptions("");
1209 CStdString strDest = urlDest.GetWithoutUserDetails();
1210 ForceForwardSlashes(strDest);
1211 if (!URIUtils::HasSlashAtEnd(strDest))
1213 int iLenPath = strDest.size();
1215 for (int i = 0; i < (int)VECSOURCES.size(); ++i)
1217 CMediaSource share = VECSOURCES.at(i);
1219 // does it match a source name?
1220 if (share.strPath.substr(0,8) == "shout://")
1222 CURL url(share.strPath);
1223 if (strPath.Equals(url.GetHostName()))
1227 // doesnt match a name, so try the source path
1228 vector<CStdString> vecPaths;
1230 // add any concatenated paths if they exist
1231 if (share.vecPaths.size() > 0)
1232 vecPaths = share.vecPaths;
1234 // add the actual share path at the front of the vector
1235 vecPaths.insert(vecPaths.begin(), share.strPath);
1238 for (int j = 0; j < (int)vecPaths.size(); ++j)
1240 // remove user details, and ensure path only uses forward slashes
1241 // and ends with a trailing slash so as not to match a substring
1242 CURL urlShare(vecPaths[j]);
1243 urlShare.SetOptions("");
1244 CStdString strShare = urlShare.GetWithoutUserDetails();
1245 ForceForwardSlashes(strShare);
1246 if (!URIUtils::HasSlashAtEnd(strShare))
1248 int iLenShare = strShare.size();
1250 if ((iLenPath >= iLenShare) && StringUtils::StartsWithNoCase(strDest, strShare) && (iLenShare > iLength))
1252 // if exact match, return it immediately
1253 if (iLenPath == iLenShare)
1255 // if the path EXACTLY matches an item in a concatentated path
1256 // set source name to true to load the full virtualpath
1257 bIsSourceName = false;
1258 if (vecPaths.size() > 1)
1259 bIsSourceName = true;
1263 iLength = iLenShare;
1268 // return the index of the share with the longest match
1272 // rar:// and zip://
1273 // if archive wasn't mounted, look for a matching share for the archive instead
1274 if( StringUtils::StartsWithNoCase(strPath, "rar://") || StringUtils::StartsWithNoCase(strPath, "zip://") )
1276 // get the hostname portion of the url since it contains the archive file
1277 strPath = checkURL.GetHostName();
1279 bIsSourceName = false;
1281 return GetMatchingSource(strPath, VECSOURCES, bDummy);
1284 CLog::Log(LOGDEBUG,"CUtil::GetMatchingSource: no matching source found for [%s]", strPath1.c_str());
1289 CStdString CUtil::TranslateSpecialSource(const CStdString &strSpecial)
1291 if (!strSpecial.IsEmpty() && strSpecial[0] == '$')
1293 if (StringUtils::StartsWithNoCase(strSpecial, "$home"))
1294 return URIUtils::AddFileToFolder("special://home/", strSpecial.Mid(5));
1295 else if (StringUtils::StartsWithNoCase(strSpecial, "$subtitles"))
1296 return URIUtils::AddFileToFolder("special://subtitles/", strSpecial.Mid(10));
1297 else if (StringUtils::StartsWithNoCase(strSpecial, "$userdata"))
1298 return URIUtils::AddFileToFolder("special://userdata/", strSpecial.Mid(9));
1299 else if (StringUtils::StartsWithNoCase(strSpecial, "$database"))
1300 return URIUtils::AddFileToFolder("special://database/", strSpecial.Mid(9));
1301 else if (StringUtils::StartsWithNoCase(strSpecial, "$thumbnails"))
1302 return URIUtils::AddFileToFolder("special://thumbnails/", strSpecial.Mid(11));
1303 else if (StringUtils::StartsWithNoCase(strSpecial, "$recordings"))
1304 return URIUtils::AddFileToFolder("special://recordings/", strSpecial.Mid(11));
1305 else if (StringUtils::StartsWithNoCase(strSpecial, "$screenshots"))
1306 return URIUtils::AddFileToFolder("special://screenshots/", strSpecial.Mid(12));
1307 else if (StringUtils::StartsWithNoCase(strSpecial, "$musicplaylists"))
1308 return URIUtils::AddFileToFolder("special://musicplaylists/", strSpecial.Mid(15));
1309 else if (StringUtils::StartsWithNoCase(strSpecial, "$videoplaylists"))
1310 return URIUtils::AddFileToFolder("special://videoplaylists/", strSpecial.Mid(15));
1311 else if (StringUtils::StartsWithNoCase(strSpecial, "$cdrips"))
1312 return URIUtils::AddFileToFolder("special://cdrips/", strSpecial.Mid(7));
1313 // this one will be removed post 2.0
1314 else if (StringUtils::StartsWithNoCase(strSpecial, "$playlists"))
1315 return URIUtils::AddFileToFolder(CSettings::Get().GetString("system.playlistspath"), strSpecial.Mid(10));
1320 CStdString CUtil::MusicPlaylistsLocation()
1322 vector<CStdString> vec;
1323 vec.push_back(URIUtils::AddFileToFolder(CSettings::Get().GetString("system.playlistspath"), "music"));
1324 vec.push_back(URIUtils::AddFileToFolder(CSettings::Get().GetString("system.playlistspath"), "mixed"));
1325 return XFILE::CMultiPathDirectory::ConstructMultiPath(vec);
1328 CStdString CUtil::VideoPlaylistsLocation()
1330 vector<CStdString> vec;
1331 vec.push_back(URIUtils::AddFileToFolder(CSettings::Get().GetString("system.playlistspath"), "video"));
1332 vec.push_back(URIUtils::AddFileToFolder(CSettings::Get().GetString("system.playlistspath"), "mixed"));
1333 return XFILE::CMultiPathDirectory::ConstructMultiPath(vec);
1336 void CUtil::DeleteMusicDatabaseDirectoryCache()
1338 CUtil::DeleteDirectoryCache("mdb-");
1339 CUtil::DeleteDirectoryCache("sp-"); // overkill as it will delete video smartplaylists, but as we can't differentiate based on URL...
1342 void CUtil::DeleteVideoDatabaseDirectoryCache()
1344 CUtil::DeleteDirectoryCache("vdb-");
1345 CUtil::DeleteDirectoryCache("sp-"); // overkill as it will delete music smartplaylists, but as we can't differentiate based on URL...
1348 void CUtil::DeleteDirectoryCache(const CStdString &prefix)
1350 CStdString searchPath = "special://temp/";
1351 CFileItemList items;
1352 if (!XFILE::CDirectory::GetDirectory(searchPath, items, ".fi", DIR_FLAG_NO_FILE_DIRS))
1355 for (int i = 0; i < items.Size(); ++i)
1357 if (items[i]->m_bIsFolder)
1359 CStdString fileName = URIUtils::GetFileName(items[i]->GetPath());
1360 if (fileName.Left(prefix.GetLength()) == prefix)
1361 XFILE::CFile::Delete(items[i]->GetPath());
1366 void CUtil::GetRecursiveListing(const CStdString& strPath, CFileItemList& items, const CStdString& strMask, bool bUseFileDirectories)
1368 CFileItemList myItems;
1369 int flags = DIR_FLAG_DEFAULTS;
1370 if (!bUseFileDirectories)
1371 flags |= DIR_FLAG_NO_FILE_DIRS;
1372 CDirectory::GetDirectory(strPath,myItems,strMask,flags);
1373 for (int i=0;i<myItems.Size();++i)
1375 if (myItems[i]->m_bIsFolder)
1376 CUtil::GetRecursiveListing(myItems[i]->GetPath(),items,strMask,bUseFileDirectories);
1378 items.Add(myItems[i]);
1382 void CUtil::GetRecursiveDirsListing(const CStdString& strPath, CFileItemList& item)
1384 CFileItemList myItems;
1385 CDirectory::GetDirectory(strPath,myItems,"",DIR_FLAG_NO_FILE_DIRS);
1386 for (int i=0;i<myItems.Size();++i)
1388 if (myItems[i]->m_bIsFolder && !myItems[i]->GetPath().Equals(".."))
1390 item.Add(myItems[i]);
1391 CUtil::GetRecursiveDirsListing(myItems[i]->GetPath(),item);
1396 void CUtil::ForceForwardSlashes(CStdString& strPath)
1398 int iPos = strPath.ReverseFind('\\');
1401 strPath.at(iPos) = '/';
1402 iPos = strPath.ReverseFind('\\');
1406 double CUtil::AlbumRelevance(const CStdString& strAlbumTemp1, const CStdString& strAlbum1, const CStdString& strArtistTemp1, const CStdString& strArtist1)
1408 // case-insensitive fuzzy string comparison on the album and artist for relevance
1409 // weighting is identical, both album and artist are 50% of the total relevance
1410 // a missing artist means the maximum relevance can only be 0.50
1411 CStdString strAlbumTemp = strAlbumTemp1;
1412 strAlbumTemp.MakeLower();
1413 CStdString strAlbum = strAlbum1;
1414 strAlbum.MakeLower();
1415 double fAlbumPercentage = fstrcmp(strAlbumTemp, strAlbum, 0.0f);
1416 double fArtistPercentage = 0.0f;
1417 if (!strArtist1.IsEmpty())
1419 CStdString strArtistTemp = strArtistTemp1;
1420 strArtistTemp.MakeLower();
1421 CStdString strArtist = strArtist1;
1422 strArtist.MakeLower();
1423 fArtistPercentage = fstrcmp(strArtistTemp, strArtist, 0.0f);
1425 double fRelevance = fAlbumPercentage * 0.5f + fArtistPercentage * 0.5f;
1429 bool CUtil::MakeShortenPath(CStdString StrInput, CStdString& StrOutput, int iTextMaxLength)
1431 int iStrInputSize = StrInput.size();
1432 if((iStrInputSize <= 0) || (iTextMaxLength >= iStrInputSize))
1436 size_t nGreaterDelim, nPos;
1438 nPos = StrInput.find_last_of( '\\' );
1439 if ( nPos != CStdString::npos )
1443 nPos = StrInput.find_last_of( '/' );
1444 if ( nPos != CStdString::npos )
1447 if ( cDelim == '\0' )
1450 if (nPos == StrInput.size() - 1)
1452 StrInput.erase(StrInput.size() - 1);
1453 nPos = StrInput.find_last_of( cDelim );
1455 while( iTextMaxLength < iStrInputSize )
1457 nPos = StrInput.find_last_of( cDelim, nPos );
1458 nGreaterDelim = nPos;
1459 if ( nPos != CStdString::npos )
1460 nPos = StrInput.find_last_of( cDelim, nPos - 1 );
1461 if ( nPos == CStdString::npos ) break;
1462 if ( nGreaterDelim > nPos ) StrInput.replace( nPos + 1, nGreaterDelim - nPos - 1, ".." );
1463 iStrInputSize = StrInput.size();
1465 // replace any additional /../../ with just /../ if necessary
1466 CStdString replaceDots = StringUtils::Format("..%c..", cDelim);
1467 while (StrInput.size() > (unsigned int)iTextMaxLength)
1468 if (!StrInput.Replace(replaceDots, ".."))
1470 // finally, truncate our string to force inside our max text length,
1471 // replacing the last 2 characters with ".."
1474 // "smb://../Playboy Swimsuit Cal.."
1475 if (iTextMaxLength > 2 && StrInput.size() > (unsigned int)iTextMaxLength)
1477 StrInput = StrInput.Left(iTextMaxLength - 2);
1480 StrOutput = StrInput;
1484 bool CUtil::SupportsWriteFileOperations(const CStdString& strPath)
1486 // currently only hd, smb, nfs, afp and dav support delete and rename
1487 if (URIUtils::IsHD(strPath))
1489 if (URIUtils::IsSmb(strPath))
1491 if (CUtil::IsTVRecording(strPath))
1492 return CPVRDirectory::SupportsWriteFileOperations(strPath);
1493 if (URIUtils::IsNfs(strPath))
1495 if (URIUtils::IsAfp(strPath))
1497 if (URIUtils::IsDAV(strPath))
1499 if (URIUtils::IsMythTV(strPath))
1502 * Can't use CFile::Exists() to check whether the myth:// path supports file operations because
1503 * it hits the directory cache on the way through, which has the Live Channels and Guide
1506 return CMythDirectory::SupportsWriteFileOperations(strPath);
1508 if (URIUtils::IsStack(strPath))
1509 return SupportsWriteFileOperations(CStackDirectory::GetFirstStackedFile(strPath));
1510 if (URIUtils::IsMultiPath(strPath))
1511 return CMultiPathDirectory::SupportsWriteFileOperations(strPath);
1516 bool CUtil::SupportsReadFileOperations(const CStdString& strPath)
1518 if (URIUtils::IsVideoDb(strPath))
1524 CStdString CUtil::GetDefaultFolderThumb(const CStdString &folderThumb)
1526 if (g_TextureManager.HasTexture(folderThumb))
1531 void CUtil::GetSkinThemes(vector<CStdString>& vecTheme)
1533 CStdString strPath = URIUtils::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media");
1534 CFileItemList items;
1535 CDirectory::GetDirectory(strPath, items);
1536 // Search for Themes in the Current skin!
1537 for (int i = 0; i < items.Size(); ++i)
1539 CFileItemPtr pItem = items[i];
1540 if (!pItem->m_bIsFolder)
1542 CStdString strExtension = URIUtils::GetExtension(pItem->GetPath());
1543 if ((strExtension == ".xpr" && pItem->GetLabel().CompareNoCase("Textures.xpr")) ||
1544 (strExtension == ".xbt" && pItem->GetLabel().CompareNoCase("Textures.xbt")))
1546 CStdString strLabel = pItem->GetLabel();
1547 vecTheme.push_back(strLabel.Mid(0, strLabel.size() - 4));
1551 sort(vecTheme.begin(), vecTheme.end(), sortstringbyname());
1554 void CUtil::InitRandomSeed()
1558 now = CurrentHostCounter();
1559 unsigned int seed = (unsigned int)now;
1560 // CLog::Log(LOGDEBUG, "%s - Initializing random seed with %u", __FUNCTION__, seed);
1565 bool CUtil::RunCommandLine(const CStdString& cmdLine, bool waitExit)
1567 CStdStringArray args;
1569 StringUtils::SplitString(cmdLine, ",", args);
1571 // Strip quotes and whitespace around the arguments, or exec will fail.
1572 // This allows the python invocation to be written more naturally with any amount of whitespace around the args.
1573 // But it's still limited, for example quotes inside the strings are not expanded, etc.
1574 // TODO: Maybe some python library routine can parse this more properly ?
1575 for (size_t i=0; i<args.size(); i++)
1577 CStdString &s = args[i];
1578 CStdString stripd = s.Trim();
1579 if (stripd[0] == '"' || stripd[0] == '\'')
1582 s = s.Right(s.size() - 1);
1584 if (stripd[stripd.size() - 1] == '"' || stripd[stripd.size() - 1] == '\'')
1587 s = s.Left(s.size() - 1);
1591 return Command(args, waitExit);
1595 // FIXME, this should be merged with the function below.
1597 bool CUtil::Command(const CStdStringArray& arrArgs, bool waitExit)
1600 printf("Executing: ");
1601 for (size_t i=0; i<arrArgs.size(); i++)
1602 printf("%s ", arrArgs[i].c_str());
1606 pid_t child = fork();
1612 // fork again in order not to leave a zombie process
1616 else if (child != 0)
1622 if (arrArgs.size() > 0)
1624 char **args = (char **)alloca(sizeof(char *) * (arrArgs.size() + 3));
1625 memset(args, 0, (sizeof(char *) * (arrArgs.size() + 3)));
1626 for (size_t i=0; i<arrArgs.size(); i++)
1627 args[i] = (char *)arrArgs[i].c_str();
1628 execvp(args[0], args);
1633 waitpid(child, &n, 0);
1636 return (waitExit) ? (WEXITSTATUS(n) == 0) : true;
1639 bool CUtil::SudoCommand(const CStdString &strCommand)
1641 CLog::Log(LOGDEBUG, "Executing sudo command: <%s>", strCommand.c_str());
1642 pid_t child = fork();
1646 close(0); // close stdin to avoid sudo request password
1649 CStdStringArray arrArgs;
1650 StringUtils::SplitString(strCommand, " ", arrArgs);
1651 if (arrArgs.size() > 0)
1653 char **args = (char **)alloca(sizeof(char *) * (arrArgs.size() + 3));
1654 memset(args, 0, (sizeof(char *) * (arrArgs.size() + 3)));
1655 args[0] = (char *)"/usr/bin/sudo";
1656 args[1] = (char *)"-S";
1657 for (size_t i=0; i<arrArgs.size(); i++)
1659 args[i+2] = (char *)arrArgs[i].c_str();
1661 execvp("/usr/bin/sudo", args);
1665 waitpid(child, &n, 0);
1667 return WEXITSTATUS(n) == 0;
1671 int CUtil::LookupRomanDigit(char roman_digit)
1673 switch (roman_digit)
1701 int CUtil::TranslateRomanNumeral(const char* roman_numeral)
1706 if (roman_numeral && roman_numeral[0])
1713 while (*roman_numeral)
1715 int digit = CUtil::LookupRomanDigit(*roman_numeral);
1718 // General sanity checks
1720 // numeral not in LUT
1727 // N = 10^n may not precede (N+1) > 10^(N+1)
1728 if (test == 1 && digit > last * 10)
1731 // N = 5*10^n may not precede (N+1) >= N
1732 if (test == 5 && digit >= last)
1735 // End general sanity checks
1739 // smaller numerals may not repeat before a larger one
1748 else if (last == digit)
1757 decimal += 2 * last - temp_sum;
1759 decimal += temp_sum;
1766 // Post general sanity checks
1768 // numerals may not repeat more than thrice
1777 decimal += temp_sum;
1779 decimal += 2 * last - temp_sum;
1784 CStdString CUtil::ResolveExecutablePath()
1786 CStdString strExecutablePath;
1787 #ifdef TARGET_WINDOWS
1788 static const size_t bufSize = MAX_PATH * 2;
1789 wchar_t* buf = new wchar_t[bufSize];
1791 ::GetModuleFileNameW(0, buf, bufSize);
1793 g_charsetConverter.wToUTF8(buf,strExecutablePath);
1795 #elif defined(TARGET_DARWIN)
1796 char given_path[2*MAXPATHLEN];
1797 uint32_t path_size =2*MAXPATHLEN;
1799 GetDarwinExecutablePath(given_path, &path_size);
1800 strExecutablePath = given_path;
1801 #elif defined(TARGET_FREEBSD)
1808 mib[2] = KERN_PROC_PATHNAME;
1811 buflen = sizeof(buf) - 1;
1812 if(sysctl(mib, 4, buf, &buflen, NULL, 0) < 0)
1813 strExecutablePath = "";
1815 strExecutablePath = buf;
1817 /* Get our PID and build the name of the link in /proc */
1818 pid_t pid = getpid();
1819 char linkname[64]; /* /proc/<pid>/exe */
1820 snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid);
1822 /* Now read the symbolic link */
1823 char buf[PATH_MAX + 1];
1826 int ret = readlink(linkname, buf, sizeof(buf) - 1);
1830 strExecutablePath = buf;
1832 return strExecutablePath;
1835 CStdString CUtil::GetFrameworksPath(bool forPython)
1837 CStdString strFrameworksPath;
1838 #if defined(TARGET_DARWIN)
1839 char given_path[2*MAXPATHLEN];
1840 uint32_t path_size =2*MAXPATHLEN;
1842 GetDarwinFrameworkPath(forPython, given_path, &path_size);
1843 strFrameworksPath = given_path;
1845 return strFrameworksPath;
1848 void CUtil::ScanForExternalSubtitles(const CStdString& strMovie, std::vector<CStdString>& vecSubtitles )
1850 unsigned int startTimer = XbmcThreads::SystemClockMillis();
1852 // new array for commons sub dirs
1853 const char * common_sub_dirs[] = {"subs",
1867 vector<CStdString> vecExtensionsCached;
1869 CFileItem item(strMovie, false);
1870 if ( item.IsInternetStream()
1871 || item.IsHDHomeRun()
1872 || item.IsSlingbox()
1873 || item.IsPlayList()
1878 vector<CStdString> strLookInPaths;
1880 CStdString strMovieFileName;
1883 URIUtils::Split(strMovie, strPath, strMovieFileName);
1884 CStdString strMovieFileNameNoExt(URIUtils::ReplaceExtension(strMovieFileName, ""));
1885 strLookInPaths.push_back(strPath);
1887 if (!CMediaSettings::Get().GetAdditionalSubtitleDirectoryChecked() && !CSettings::Get().GetString("subtitles.custompath").empty()) // to avoid checking non-existent directories (network) every time..
1889 if (!g_application.getNetwork().IsAvailable() && !URIUtils::IsHD(CSettings::Get().GetString("subtitles.custompath")))
1891 CLog::Log(LOGINFO,"CUtil::CacheSubtitles: disabling alternate subtitle directory for this session, it's nonaccessible");
1892 CMediaSettings::Get().SetAdditionalSubtitleDirectoryChecked(-1); // disabled
1894 else if (!CDirectory::Exists(CSettings::Get().GetString("subtitles.custompath")))
1896 CLog::Log(LOGINFO,"CUtil::CacheSubtitles: disabling alternate subtitle directory for this session, it's nonexistant");
1897 CMediaSettings::Get().SetAdditionalSubtitleDirectoryChecked(-1); // disabled
1900 CMediaSettings::Get().SetAdditionalSubtitleDirectoryChecked(1);
1903 if (strMovie.Left(6) == "rar://") // <--- if this is found in main path then ignore it!
1906 CStdString strArchive = url.GetHostName();
1907 URIUtils::Split(strArchive, strPath, strMovieFileName);
1908 strLookInPaths.push_back(strPath);
1911 int iSize = strLookInPaths.size();
1912 for (int i=0; i<iSize; ++i)
1914 CStdStringArray directories;
1915 int nTokens = StringUtils::SplitString( strLookInPaths[i], "/", directories );
1917 StringUtils::SplitString( strLookInPaths[i], "\\", directories );
1919 // if it's inside a cdX dir, add parent path
1920 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
1922 CStdString strPath2;
1923 URIUtils::GetParentPath(strLookInPaths[i], strPath2);
1924 strLookInPaths.push_back(strPath2);
1928 // checking if any of the common subdirs exist ..
1929 iSize = strLookInPaths.size();
1930 for (int i=0;i<iSize;++i)
1932 for (int j=0; common_sub_dirs[j]; j++)
1934 CStdString strPath2 = URIUtils::AddFileToFolder(strLookInPaths[i],common_sub_dirs[j]);
1935 URIUtils::AddSlashAtEnd(strPath2);
1936 if (CDirectory::Exists(strPath2))
1937 strLookInPaths.push_back(strPath2);
1940 // .. done checking for common subdirs
1942 // check if there any cd-directories in the paths we have added so far
1943 iSize = strLookInPaths.size();
1944 for (int i=0;i<9;++i) // 9 cd's
1946 CStdString cdDir = StringUtils::Format("cd%i",i+1);
1947 for (int i=0;i<iSize;++i)
1949 CStdString strPath2 = URIUtils::AddFileToFolder(strLookInPaths[i],cdDir);
1950 URIUtils::AddSlashAtEnd(strPath2);
1951 bool pathAlreadyAdded = false;
1952 for (unsigned int i=0; i<strLookInPaths.size(); i++)
1954 // if movie file is inside cd-dir, this directory can exist in vector already
1955 if (strLookInPaths[i].Equals( strPath2 ) )
1956 pathAlreadyAdded = true;
1958 if (CDirectory::Exists(strPath2) && !pathAlreadyAdded)
1959 strLookInPaths.push_back(strPath2);
1962 // .. done checking for cd-dirs
1964 // this is last because we dont want to check any common subdirs or cd-dirs in the alternate <subtitles> dir.
1965 if (CMediaSettings::Get().GetAdditionalSubtitleDirectoryChecked() == 1)
1967 strPath = CSettings::Get().GetString("subtitles.custompath");
1968 URIUtils::AddSlashAtEnd(strPath);
1969 strLookInPaths.push_back(strPath);
1976 // 2 steps for movie directory and alternate subtitles directory
1977 CLog::Log(LOGDEBUG,"%s: Searching for subtitles...", __FUNCTION__);
1978 for (unsigned int step = 0; step < strLookInPaths.size(); step++)
1980 if (strLookInPaths[step].length() != 0)
1982 CFileItemList items;
1984 CDirectory::GetDirectory(strLookInPaths[step], items, g_advancedSettings.m_subtitlesExtensions, DIR_FLAG_NO_FILE_DIRS);
1986 for (int j = 0; j < items.Size(); j++)
1988 URIUtils::Split(items[j]->GetPath(), strPath, strItem);
1990 if (StringUtils::StartsWithNoCase(strItem, strMovieFileNameNoExt))
1992 // is this a rar or zip-file
1993 if (URIUtils::IsRAR(strItem) || URIUtils::IsZIP(strItem))
1995 // zip-file name equals strMovieFileNameNoExt, don't check in zip-file
1996 ScanArchiveForSubtitles( items[j]->GetPath(), "", vecSubtitles );
1998 else // not a rar/zip file
2000 for (int i = 0; sub_exts[i]; i++)
2002 //Cache subtitle with same name as movie
2003 if (URIUtils::HasExtension(strItem, sub_exts[i]))
2005 vecSubtitles.push_back( items[j]->GetPath() );
2006 CLog::Log(LOGINFO, "%s: found subtitle file %s\n", __FUNCTION__, items[j]->GetPath().c_str() );
2013 // is this a rar or zip-file
2014 if (URIUtils::IsRAR(strItem) || URIUtils::IsZIP(strItem))
2016 // check strMovieFileNameNoExt in zip-file
2017 ScanArchiveForSubtitles( items[j]->GetPath(), strMovieFileNameNoExt, vecSubtitles );
2024 iSize = vecSubtitles.size();
2025 for (int i = 0; i < iSize; i++)
2027 if (URIUtils::HasExtension(vecSubtitles[i], ".smi"))
2029 //Cache multi-language sami subtitle
2030 CDVDSubtitleStream* pStream = new CDVDSubtitleStream();
2031 if(pStream->Open(vecSubtitles[i]))
2033 CDVDSubtitleTagSami TagConv;
2034 TagConv.LoadHead(pStream);
2035 if (TagConv.m_Langclass.size() >= 2)
2037 for (unsigned int k = 0; k < TagConv.m_Langclass.size(); k++)
2039 strDest = StringUtils::Format("special://temp/subtitle.%s.%d.smi", TagConv.m_Langclass[k].Name.c_str(), i);
2040 if (CFile::Cache(vecSubtitles[i], strDest))
2042 CLog::Log(LOGINFO, " cached subtitle %s->%s\n", vecSubtitles[i].c_str(), strDest.c_str());
2043 vecSubtitles.push_back(strDest);
2051 CLog::Log(LOGDEBUG,"%s: END (total time: %i ms)", __FUNCTION__, (int)(XbmcThreads::SystemClockMillis() - startTimer));
2054 int CUtil::ScanArchiveForSubtitles( const CStdString& strArchivePath, const CStdString& strMovieFileNameNoExt, std::vector<CStdString>& vecSubtitles )
2056 int nSubtitlesAdded = 0;
2057 CFileItemList ItemList;
2059 // zip only gets the root dir
2060 if (URIUtils::HasExtension(strArchivePath, ".zip"))
2062 CStdString strZipPath;
2063 URIUtils::CreateArchivePath(strZipPath,"zip",strArchivePath,"");
2064 if (!CDirectory::GetDirectory(strZipPath,ItemList,"",DIR_FLAG_NO_FILE_DIRS))
2069 #ifdef HAS_FILESYSTEM_RAR
2070 // get _ALL_files in the rar, even those located in subdirectories because we set the bMask to false.
2071 // so now we dont have to find any subdirs anymore, all files in the rar is checked.
2072 if( !g_RarManager.GetFilesInRar(ItemList, strArchivePath, false, "") )
2078 for (int it= 0 ; it <ItemList.Size();++it)
2080 CStdString strPathInRar = ItemList[it]->GetPath();
2081 CStdString strExt = URIUtils::GetExtension(strPathInRar);
2083 CLog::Log(LOGDEBUG, "ScanArchiveForSubtitles:: Found file %s", strPathInRar.c_str());
2084 // always check any embedded rar archives
2085 // checking for embedded rars, I moved this outside the sub_ext[] loop. We only need to check this once for each file.
2086 if (URIUtils::IsRAR(strPathInRar) || URIUtils::IsZIP(strPathInRar))
2088 CStdString strRarInRar;
2089 if (strExt == ".rar")
2090 URIUtils::CreateArchivePath(strRarInRar, "rar", strArchivePath, strPathInRar);
2092 URIUtils::CreateArchivePath(strRarInRar, "zip", strArchivePath, strPathInRar);
2093 ScanArchiveForSubtitles(strRarInRar,strMovieFileNameNoExt,vecSubtitles);
2095 // done checking if this is a rar-in-rar
2097 // check that the found filename matches the movie filename
2098 int fnl = strMovieFileNameNoExt.size();
2099 if (fnl && !StringUtils::StartsWithNoCase(URIUtils::GetFileName(strPathInRar), strMovieFileNameNoExt))
2103 while (sub_exts[iPos])
2105 if (strExt.CompareNoCase(sub_exts[iPos]) == 0)
2107 CStdString strSourceUrl;
2108 if (URIUtils::HasExtension(strArchivePath, ".rar"))
2109 URIUtils::CreateArchivePath(strSourceUrl, "rar", strArchivePath, strPathInRar);
2111 strSourceUrl = strPathInRar;
2113 CLog::Log(LOGINFO, "%s: found subtitle file %s\n", __FUNCTION__, strSourceUrl.c_str() );
2114 vecSubtitles.push_back( strSourceUrl );
2122 return nSubtitlesAdded;
2125 void CUtil::GetExternalStreamDetailsFromFilename(const CStdString& strVideo, const CStdString& strStream, ExternalStreamInfo& info)
2127 CStdString videoBaseName = URIUtils::GetFileName(strVideo);
2128 URIUtils::RemoveExtension(videoBaseName);
2130 CStdString toParse = URIUtils::GetFileName(strStream);
2131 URIUtils::RemoveExtension(toParse);
2133 // we check left part - if it's same as video base name - strip it
2134 if (toParse.Left(videoBaseName.length()).Equals(videoBaseName))
2135 toParse = toParse.Mid(videoBaseName.length());
2137 // trim any non-alphanumeric char in the begining
2138 std::string::iterator result = std::find_if(toParse.begin(), toParse.end(), ::isalnum);
2141 if (result != toParse.end()) // if we have anything to parse
2143 std::string inputString(result, toParse.end());
2144 std::string delimiters(" .-");
2145 std::vector<std::string> tokens;
2146 StringUtils::Tokenize(inputString, tokens, delimiters);
2148 for (std::vector<std::string>::iterator it = tokens.begin(); it != tokens.end(); ++it)
2150 if (info.language.empty())
2152 CStdString langTmp(*it);
2153 CStdString langCode;
2154 // try to recognize language
2155 if (g_LangCodeExpander.ConvertToThreeCharCode(langCode, langTmp))
2157 info.language = langCode;
2161 if (info.flag == 0x1111)
2163 std::string flag_tmp(*it);
2164 StringUtils::ToLower(flag_tmp);
2165 if (!flag_tmp.compare("none"))
2167 info.flag = CDemuxStream::FLAG_NONE;
2170 else if (!flag_tmp.compare("default"))
2172 info.flag = CDemuxStream::FLAG_DEFAULT;
2175 else if (!flag_tmp.compare("forced"))
2177 info.flag = CDemuxStream::FLAG_FORCED;
2181 name += " " + (*it);
2185 name += g_localizeStrings.Get(21602); // External
2186 StringUtils::Trim(name);
2187 info.name = StringUtils::RemoveDuplicatedSpacesAndTabs(name);
2188 if (info.flag == 0x1111)
2189 info.flag = CDemuxStream::FLAG_NONE;
2191 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());
2194 /*! \brief in a vector of subtitles finds the corresponding .sub file for a given .idx file
2196 bool CUtil::FindVobSubPair( const std::vector<CStdString>& vecSubtitles, const CStdString& strIdxPath, CStdString& strSubPath )
2198 if (URIUtils::HasExtension(strIdxPath, ".idx"))
2200 CStdString strIdxFile;
2201 CStdString strIdxDirectory;
2202 URIUtils::Split(strIdxPath, strIdxDirectory, strIdxFile);
2203 for (unsigned int j=0; j < vecSubtitles.size(); j++)
2205 CStdString strSubFile;
2206 CStdString strSubDirectory;
2207 URIUtils::Split(vecSubtitles[j], strSubDirectory, strSubFile);
2208 if (URIUtils::IsInArchive(vecSubtitles[j]))
2209 CURL::Decode(strSubDirectory);
2210 if (URIUtils::HasExtension(strSubFile, ".sub") &&
2211 (URIUtils::ReplaceExtension(strIdxFile,"").Equals(URIUtils::ReplaceExtension(strSubFile,"")) ||
2212 strSubDirectory.Mid(6, strSubDirectory.length()-11).Equals(URIUtils::ReplaceExtension(strIdxPath,""))))
2214 strSubPath = vecSubtitles[j];
2222 /*! \brief checks if in the vector of subtitles the given .sub file has a corresponding idx and hence is a vobsub file
2224 bool CUtil::IsVobSub( const std::vector<CStdString>& vecSubtitles, const CStdString& strSubPath )
2226 if (URIUtils::HasExtension(strSubPath, ".sub"))
2228 CStdString strSubFile;
2229 CStdString strSubDirectory;
2230 URIUtils::Split(strSubPath, strSubDirectory, strSubFile);
2231 if (URIUtils::IsInArchive(strSubPath))
2232 CURL::Decode(strSubDirectory);
2233 for (unsigned int j=0; j < vecSubtitles.size(); j++)
2235 CStdString strIdxFile;
2236 CStdString strIdxDirectory;
2237 URIUtils::Split(vecSubtitles[j], strIdxDirectory, strIdxFile);
2238 if (URIUtils::HasExtension(strIdxFile, ".idx") &&
2239 (URIUtils::ReplaceExtension(strIdxFile,"").Equals(URIUtils::ReplaceExtension(strSubFile,"")) ||
2240 strSubDirectory.Mid(6, strSubDirectory.length()-11).Equals(URIUtils::ReplaceExtension(vecSubtitles[j],""))))
2247 bool CUtil::CanBindPrivileged()
2252 return true; //root user can always bind to privileged ports
2256 //check if CAP_NET_BIND_SERVICE is enabled, this allows non-root users to bind to privileged ports
2257 bool canbind = false;
2258 cap_t capabilities = cap_get_proc();
2261 cap_flag_value_t value;
2262 if (cap_get_flag(capabilities, CAP_NET_BIND_SERVICE, CAP_EFFECTIVE, &value) == 0)
2265 cap_free(capabilities);
2274 #endif //HAVE_LIBCAP
2276 #else //TARGET_POSIX
2280 #endif //TARGET_POSIX
2283 bool CUtil::ValidatePort(int port)
2285 // check that it's a valid port
2287 if (!CUtil::CanBindPrivileged() && (port < 1024 || port > 65535))
2291 if (port <= 0 || port > 65535)
2297 int CUtil::GetRandomNumber()
2299 #ifdef TARGET_WINDOWS
2300 unsigned int number;
2301 if (rand_s(&number) == 0)
2304 return rand_r(&s_randomSeed);