Merge pull request #4676 from jmarshallnz/dont_set_scraper_on_tvshow_on_nfo
[vuplus_xbmc] / xbmc / utils / SystemInfo.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include <limits.h>
22
23 #include "threads/SystemClock.h"
24 #include "system.h"
25 #include "SystemInfo.h"
26 #ifndef TARGET_POSIX
27 #include <conio.h>
28 #else
29 #include <sys/utsname.h>
30 #endif
31 #include "GUIInfoManager.h"
32 #include "filesystem/CurlFile.h"
33 #include "network/Network.h"
34 #include "Application.h"
35 #include "windowing/WindowingFactory.h"
36 #include "guilib/LocalizeStrings.h"
37 #include "CPUInfo.h"
38 #include "utils/TimeUtils.h"
39 #include "utils/log.h"
40 #ifdef TARGET_WINDOWS
41 #include "dwmapi.h"
42 #endif
43 #if defined(TARGET_DARWIN)
44 #include "osx/DarwinUtils.h"
45 #include "osx/CocoaInterface.h"
46 #endif
47 #include "powermanagement/PowerManager.h"
48 #include "utils/StringUtils.h"
49 #include "utils/XMLUtils.h"
50 #if defined(TARGET_ANDROID)
51 #include "android/jni/Build.h"
52 #include "utils/AMLUtils.h"
53 #endif
54
55 /* Target identification */
56 #if defined(TARGET_DARWIN)
57 #include <Availability.h>
58 #elif defined(TARGET_ANDROID)
59 #include <android/api-level.h>
60 #elif defined(TARGET_FREEBSD)
61 #include <sys/param.h>
62 #elif defined(TARGET_LINUX)
63 #include <linux/version.h>
64 #endif
65
66 CSysInfo g_sysinfo;
67
68 CSysInfoJob::CSysInfoJob()
69 {
70 }
71
72 bool CSysInfoJob::DoWork()
73 {
74   m_info.systemUptime      = GetSystemUpTime(false);
75   m_info.systemTotalUptime = GetSystemUpTime(true);
76   m_info.internetState     = GetInternetState();
77   m_info.videoEncoder      = GetVideoEncoder();
78   m_info.cpuFrequency      = GetCPUFreqInfo();
79   m_info.kernelVersion     = CSysInfo::GetKernelVersion();
80   m_info.macAddress        = GetMACAddress();
81   m_info.batteryLevel      = GetBatteryLevel();
82   return true;
83 }
84
85 const CSysData &CSysInfoJob::GetData() const
86 {
87   return m_info;
88 }
89
90 CStdString CSysInfoJob::GetCPUFreqInfo()
91 {
92   double CPUFreq = GetCPUFrequency();
93   return StringUtils::Format("%4.2fMHz", CPUFreq);;
94 }
95
96 CSysData::INTERNET_STATE CSysInfoJob::GetInternetState()
97 {
98   // Internet connection state!
99   XFILE::CCurlFile http;
100   if (http.IsInternet())
101     return CSysData::CONNECTED;
102   return CSysData::DISCONNECTED;
103 }
104
105 CStdString CSysInfoJob::GetMACAddress()
106 {
107 #if defined(HAS_LINUX_NETWORK) || defined(HAS_WIN32_NETWORK)
108   CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
109   if (iface)
110     return iface->GetMacAddress();
111 #endif
112   return "";
113 }
114
115 CStdString CSysInfoJob::GetVideoEncoder()
116 {
117   return "GPU: " + g_Windowing.GetRenderRenderer();
118 }
119
120 CStdString CSysInfoJob::GetBatteryLevel()
121 {
122   return StringUtils::Format("%d%%", g_powerManager.BatteryLevel());
123 }
124
125 double CSysInfoJob::GetCPUFrequency()
126 {
127 #if defined (TARGET_POSIX) || defined(TARGET_WINDOWS)
128   return double (g_cpuInfo.getCPUFrequency());
129 #else
130   return 0;
131 #endif
132 }
133
134 bool CSysInfoJob::SystemUpTime(int iInputMinutes, int &iMinutes, int &iHours, int &iDays)
135 {
136   iMinutes=0;iHours=0;iDays=0;
137   iMinutes = iInputMinutes;
138   if (iMinutes >= 60) // Hour's
139   {
140     iHours = iMinutes / 60;
141     iMinutes = iMinutes - (iHours *60);
142   }
143   if (iHours >= 24) // Days
144   {
145     iDays = iHours / 24;
146     iHours = iHours - (iDays * 24);
147   }
148   return true;
149 }
150
151 CStdString CSysInfoJob::GetSystemUpTime(bool bTotalUptime)
152 {
153   CStdString strSystemUptime;
154   int iInputMinutes, iMinutes,iHours,iDays;
155
156   if(bTotalUptime)
157   {
158     //Total Uptime
159     iInputMinutes = g_sysinfo.GetTotalUptime() + ((int)(XbmcThreads::SystemClockMillis() / 60000));
160   }
161   else
162   {
163     //Current UpTime
164     iInputMinutes = (int)(XbmcThreads::SystemClockMillis() / 60000);
165   }
166
167   SystemUpTime(iInputMinutes,iMinutes, iHours, iDays);
168   if (iDays > 0)
169   {
170     strSystemUptime = StringUtils::Format("%i %s, %i %s, %i %s",
171                                           iDays, g_localizeStrings.Get(12393).c_str(),
172                                           iHours, g_localizeStrings.Get(12392).c_str(),
173                                           iMinutes, g_localizeStrings.Get(12391).c_str());
174   }
175   else if (iDays == 0 && iHours >= 1 )
176   {
177     strSystemUptime = StringUtils::Format("%i %s, %i %s",
178                                           iHours, g_localizeStrings.Get(12392).c_str(),
179                                           iMinutes, g_localizeStrings.Get(12391).c_str());
180   }
181   else if (iDays == 0 && iHours == 0 &&  iMinutes >= 0)
182   {
183     strSystemUptime = StringUtils::Format("%i %s",
184                                           iMinutes, g_localizeStrings.Get(12391).c_str());
185   }
186   return strSystemUptime;
187 }
188
189 CStdString CSysInfo::TranslateInfo(int info) const
190 {
191   switch(info)
192   {
193   case SYSTEM_VIDEO_ENCODER_INFO:
194     return m_info.videoEncoder;
195   case NETWORK_MAC_ADDRESS:
196     return m_info.macAddress;
197   case SYSTEM_KERNEL_VERSION:
198     return m_info.kernelVersion;
199   case SYSTEM_CPUFREQUENCY:
200     return m_info.cpuFrequency;
201   case SYSTEM_UPTIME:
202     return m_info.systemUptime;
203   case SYSTEM_TOTALUPTIME:
204     return m_info.systemTotalUptime;
205   case SYSTEM_INTERNET_STATE:
206     if (m_info.internetState == CSysData::CONNECTED)
207       return g_localizeStrings.Get(13296);
208     else
209       return g_localizeStrings.Get(13297);
210   case SYSTEM_BATTERY_LEVEL:
211     return m_info.batteryLevel;
212   default:
213     return "";
214   }
215 }
216
217 void CSysInfo::Reset()
218 {
219   m_info.Reset();
220 }
221
222 CSysInfo::CSysInfo(void) : CInfoLoader(15 * 1000)
223 {
224   memset(MD5_Sign, 0, sizeof(MD5_Sign));
225   m_iSystemTimeTotalUp = 0;
226 }
227
228 CSysInfo::~CSysInfo()
229 {
230 }
231
232 bool CSysInfo::Load(const TiXmlNode *settings)
233 {
234   if (settings == NULL)
235     return false;
236   
237   const TiXmlElement *pElement = settings->FirstChildElement("general");
238   if (pElement)
239     XMLUtils::GetInt(pElement, "systemtotaluptime", m_iSystemTimeTotalUp, 0, INT_MAX);
240
241   return true;
242 }
243
244 bool CSysInfo::Save(TiXmlNode *settings) const
245 {
246   if (settings == NULL)
247     return false;
248
249   TiXmlNode *generalNode = settings->FirstChild("general");
250   if (generalNode == NULL)
251   {
252     TiXmlElement generalNodeNew("general");
253     generalNode = settings->InsertEndChild(generalNodeNew);
254     if (generalNode == NULL)
255       return false;
256   }
257   XMLUtils::SetInt(generalNode, "systemtotaluptime", m_iSystemTimeTotalUp);
258
259   return true;
260 }
261
262 bool CSysInfo::GetDiskSpace(const CStdString& drive,int& iTotal, int& iTotalFree, int& iTotalUsed, int& iPercentFree, int& iPercentUsed)
263 {
264   bool bRet= false;
265   ULARGE_INTEGER ULTotal= { { 0 } };
266   ULARGE_INTEGER ULTotalFree= { { 0 } };
267
268   if( !drive.empty() && !drive.Equals("*") )
269   {
270 #ifdef TARGET_WINDOWS
271     UINT uidriveType = GetDriveType(( drive + ":\\" ));
272     if(uidriveType != DRIVE_UNKNOWN && uidriveType != DRIVE_NO_ROOT_DIR)
273 #endif
274       bRet= ( 0 != GetDiskFreeSpaceEx( ( drive + ":\\" ), NULL, &ULTotal, &ULTotalFree) );
275   }
276   else
277   {
278     ULARGE_INTEGER ULTotalTmp= { { 0 } };
279     ULARGE_INTEGER ULTotalFreeTmp= { { 0 } };
280 #ifdef TARGET_WINDOWS
281     char* pcBuffer= NULL;
282     DWORD dwStrLength= GetLogicalDriveStrings( 0, pcBuffer );
283     if( dwStrLength != 0 )
284     {
285       dwStrLength+= 1;
286       pcBuffer= new char [dwStrLength];
287       GetLogicalDriveStrings( dwStrLength, pcBuffer );
288       int iPos= 0;
289       do {
290         if( DRIVE_FIXED == GetDriveType( pcBuffer + iPos  ) &&
291             GetDiskFreeSpaceEx( ( pcBuffer + iPos ), NULL, &ULTotal, &ULTotalFree ) )
292         {
293           ULTotalTmp.QuadPart+= ULTotal.QuadPart;
294           ULTotalFreeTmp.QuadPart+= ULTotalFree.QuadPart;
295         }
296         iPos += (strlen( pcBuffer + iPos) + 1 );
297       }while( strlen( pcBuffer + iPos ) > 0 );
298     }
299     delete[] pcBuffer;
300 #else // for linux and osx
301     static const char *drv_letter[] = { "C:\\", "E:\\", "F:\\", "G:\\", "X:\\", "Y:\\", "Z:\\", NULL };
302     for( int i = 0; drv_letter[i]; i++)
303     {
304       if( GetDiskFreeSpaceEx( drv_letter[i], NULL, &ULTotal, &ULTotalFree ) )
305       {
306         ULTotalTmp.QuadPart+= ULTotal.QuadPart;
307         ULTotalFreeTmp.QuadPart+= ULTotalFree.QuadPart;
308       }
309     }
310 #endif
311     if( ULTotalTmp.QuadPart || ULTotalFreeTmp.QuadPart )
312     {
313       ULTotal.QuadPart= ULTotalTmp.QuadPart;
314       ULTotalFree.QuadPart= ULTotalFreeTmp.QuadPart;
315       bRet= true;
316     }
317   }
318
319   if( bRet )
320   {
321     iTotal = (int)( ULTotal.QuadPart / MB );
322     iTotalFree = (int)( ULTotalFree.QuadPart / MB );
323     iTotalUsed = iTotal - iTotalFree;
324     if( ULTotal.QuadPart > 0 )
325     {
326       iPercentUsed = (int)( 100.0f * ( ULTotal.QuadPart - ULTotalFree.QuadPart ) / ULTotal.QuadPart + 0.5f );
327     }
328     else
329     {
330       iPercentUsed = 0;
331     }
332     iPercentFree = 100 - iPercentUsed;
333   }
334
335   return bRet;
336 }
337
338 CStdString CSysInfo::GetCPUModel()
339 {
340   return "CPU: " + g_cpuInfo.getCPUModel();
341 }
342
343 CStdString CSysInfo::GetCPUBogoMips()
344 {
345   return "BogoMips: " + g_cpuInfo.getCPUBogoMips();
346 }
347
348 CStdString CSysInfo::GetCPUHardware()
349 {
350   return "Hardware: " + g_cpuInfo.getCPUHardware();
351 }
352
353 CStdString CSysInfo::GetCPURevision()
354 {
355   return "Revision: " + g_cpuInfo.getCPURevision();
356 }
357
358 CStdString CSysInfo::GetCPUSerial()
359 {
360   return "Serial: " + g_cpuInfo.getCPUSerial();
361 }
362
363 CStdString CSysInfo::GetManufacturer()
364 {
365   CStdString manufacturer = "";
366 #if defined(TARGET_ANDROID)
367   manufacturer = CJNIBuild::MANUFACTURER;
368 #endif
369   return manufacturer;
370 }
371
372 CStdString CSysInfo::GetModel()
373 {
374   CStdString model = "";
375 #if defined(TARGET_ANDROID)
376   model = CJNIBuild::MODEL;
377 #endif
378   return model;
379 }
380
381 CStdString CSysInfo::GetProduct()
382 {
383   CStdString product = "";
384 #if defined(TARGET_ANDROID)
385   product = CJNIBuild::PRODUCT;
386 #endif
387   return product;
388 }
389
390 bool CSysInfo::IsAeroDisabled()
391 {
392 #ifdef TARGET_WINDOWS
393   BOOL aeroEnabled = FALSE;
394   HRESULT res = DwmIsCompositionEnabled(&aeroEnabled);
395   if (SUCCEEDED(res))
396     return !aeroEnabled;
397 #endif
398   return false;
399 }
400
401 bool CSysInfo::HasHW3DInterlaced()
402 {
403 #if defined(TARGET_ANDROID)
404   if (aml_hw3d_present())
405     return true;
406 #endif
407   return false;
408 }
409
410 CSysInfo::WindowsVersion CSysInfo::m_WinVer = WindowsVersionUnknown;
411
412 bool CSysInfo::IsWindowsVersion(WindowsVersion ver)
413 {
414   if (ver == WindowsVersionUnknown)
415     return false;
416   return GetWindowsVersion() == ver;
417 }
418
419 bool CSysInfo::IsWindowsVersionAtLeast(WindowsVersion ver)
420 {
421   if (ver == WindowsVersionUnknown)
422     return false;
423   return GetWindowsVersion() >= ver;
424 }
425
426 CSysInfo::WindowsVersion CSysInfo::GetWindowsVersion()
427 {
428 #ifdef TARGET_WINDOWS
429   if (m_WinVer == WindowsVersionUnknown)
430   {
431     OSVERSIONINFOEX osvi;
432     ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
433     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
434     if (GetVersionEx((OSVERSIONINFO *)&osvi))
435     {
436       if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
437         m_WinVer = WindowsVersionVista;
438       else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)
439         m_WinVer = WindowsVersionWin7;
440       else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2)
441         m_WinVer = WindowsVersionWin8;
442       else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) 
443         m_WinVer = WindowsVersionWin8_1;
444       /* Insert checks for new Windows versions here */
445       else if ( (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion > 3) || osvi.dwMajorVersion > 6)
446         m_WinVer = WindowsVersionFuture;
447     }
448   }
449 #endif // TARGET_WINDOWS
450   return m_WinVer;
451 }
452
453 int CSysInfo::GetKernelBitness(void)
454 {
455 #ifdef TARGET_WINDOWS
456   SYSTEM_INFO si;
457   GetSystemInfo(&si);
458   if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
459     return 64;
460   
461   BOOL (WINAPI *ptrIsWow64) (HANDLE, PBOOL);
462   HMODULE hKernel32 = GetModuleHandleA("kernel32");
463   if (hKernel32 == NULL)
464     return 0; // Can't detect OS
465   ptrIsWow64 = (BOOL (WINAPI *) (HANDLE, PBOOL)) GetProcAddress(hKernel32, "IsWow64Process");
466   BOOL wow64proc = FALSE;
467   if (ptrIsWow64 == NULL || ptrIsWow64(GetCurrentProcess(), &wow64proc) == FALSE)
468     return 0; // Can't detect OS
469   return (wow64proc == FALSE) ? 32 : 64;
470 #elif defined(TARGET_POSIX)
471   struct utsname un;
472   if (uname(&un) == 0)
473   {
474     std::string machine(un.machine);
475     if (machine == "x86_64" || machine == "amd64" || machine == "arm64" || machine == "aarch64" || machine == "ppc64" || machine == "ia64")
476       return 64;
477     return 32;
478   }
479   return 0; // can't detect
480 #else
481   return 0; // unknown
482 #endif
483 }
484
485 int CSysInfo::GetXbmcBitness(void)
486 {
487 #if defined (__aarch64__) || defined(__arm64__) || defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) || defined(__ppc64__)
488   return 64;
489 #elif defined(__thumb__) || defined(_M_ARMT) || defined(__arm__) || defined(_M_ARM) || defined(__mips__) || defined(mips) || defined(__mips) || defined(i386) || \
490   defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(_X86_) || defined(__powerpc) || \
491   defined(__powerpc__) || defined(__ppc__) || defined(_M_PPC)
492   return 32;
493 #else
494   return 0; // Unknown
495 #endif
496 }
497
498 CStdString CSysInfo::GetKernelVersion()
499 {
500 #if defined(TARGET_DARWIN)
501   return g_sysinfo.GetUnameVersion();
502 #elif defined (TARGET_POSIX)
503   struct utsname un;
504   if (uname(&un)==0)
505   {
506     return StringUtils::Format("%s %s %s %s", un.sysname, un.release, un.version, un.machine);;
507   }
508
509   return "";
510 #else
511   OSVERSIONINFOEX osvi;
512   ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
513   osvi.dwOSVersionInfoSize = sizeof(osvi);
514
515   std::string strKernel = "Windows";
516   if (GetVersionEx((OSVERSIONINFO *)&osvi))
517   {
518     switch (GetWindowsVersion())
519     {
520     case WindowsVersionVista:
521       if (osvi.wProductType == VER_NT_WORKSTATION)
522         strKernel.append(" Vista");
523       else
524         strKernel.append(" Server 2008");
525       break;
526     case WindowsVersionWin7:
527       if (osvi.wProductType == VER_NT_WORKSTATION)
528         strKernel.append(" 7");
529       else
530         strKernel.append(" Server 2008 R2");
531       break;
532     case WindowsVersionWin8:
533       if (osvi.wProductType == VER_NT_WORKSTATION)
534         strKernel.append(" 8");
535       else
536         strKernel.append(" Server 2012");
537       break;
538     case WindowsVersionWin8_1:
539       if (osvi.wProductType == VER_NT_WORKSTATION)
540         strKernel.append(" 8.1");
541       else
542         strKernel.append(" Server 2012 R2");
543       break;
544     case WindowsVersionFuture:
545       strKernel.append(" Unknown Future Version");
546       break;
547     default:
548       strKernel.append(" Unknown version");
549       break;
550     }
551
552     // Append Service Pack version if any
553     if (osvi.wServicePackMajor > 0)
554     {
555       strKernel.append(StringUtils::Format(" SP%d", osvi.wServicePackMajor));
556       if (osvi.wServicePackMinor > 0)
557       {
558         strKernel.append(StringUtils::Format(".%d", osvi.wServicePackMinor));
559       }
560     }
561
562     strKernel.append(StringUtils::Format(" %d-bit", GetKernelBitness()));
563
564     strKernel.append(StringUtils::Format(", build %d", osvi.dwBuildNumber));
565   }
566   else
567   {
568     strKernel.append(" unknown");
569     strKernel.append(StringUtils::Format(" %d-bit", GetKernelBitness()));
570   }
571
572   return strKernel;
573 #endif
574 }
575
576 bool CSysInfo::HasInternet()
577 {
578   if (m_info.internetState != CSysData::UNKNOWN)
579     return m_info.internetState == CSysData::CONNECTED;
580   return (m_info.internetState = CSysInfoJob::GetInternetState()) == CSysData::CONNECTED;
581 }
582
583 CStdString CSysInfo::GetHddSpaceInfo(int drive, bool shortText)
584 {
585  int percent;
586  return GetHddSpaceInfo( percent, drive, shortText);
587 }
588
589 CStdString CSysInfo::GetHddSpaceInfo(int& percent, int drive, bool shortText)
590 {
591   int total, totalFree, totalUsed, percentFree, percentused;
592   CStdString strRet;
593   percent = 0;
594   if (g_sysinfo.GetDiskSpace("", total, totalFree, totalUsed, percentFree, percentused))
595   {
596     if (shortText)
597     {
598       switch(drive)
599       {
600         case SYSTEM_FREE_SPACE:
601           percent = percentFree;
602           break;
603         case SYSTEM_USED_SPACE:
604           percent = percentused;
605           break;
606       }
607     }
608     else
609     {
610       switch(drive)
611       {
612       case SYSTEM_FREE_SPACE:
613         strRet = StringUtils::Format("%i MB %s", totalFree, g_localizeStrings.Get(160).c_str());
614         break;
615       case SYSTEM_USED_SPACE:
616         strRet = StringUtils::Format("%i MB %s", totalUsed, g_localizeStrings.Get(20162).c_str());
617         break;
618       case SYSTEM_TOTAL_SPACE:
619         strRet = StringUtils::Format("%i MB %s", total, g_localizeStrings.Get(20161).c_str());
620         break;
621       case SYSTEM_FREE_SPACE_PERCENT:
622         strRet = StringUtils::Format("%i %% %s", percentFree, g_localizeStrings.Get(160).c_str());
623         break;
624       case SYSTEM_USED_SPACE_PERCENT:
625         strRet = StringUtils::Format("%i %% %s", percentused, g_localizeStrings.Get(20162).c_str());
626         break;
627       }
628     }
629   }
630   else
631   {
632     if (shortText)
633       strRet = "N/A";
634     else
635       strRet = g_localizeStrings.Get(161);
636   }
637   return strRet;
638 }
639
640 #if defined(TARGET_LINUX)
641 CStdString CSysInfo::GetLinuxDistro()
642 {
643 #if defined(TARGET_ANDROID)
644   return "Android";
645 #endif
646   static const char* release_file[] = { "/etc/debian_version",
647                                         "/etc/SuSE-release",
648                                         "/etc/mandrake-release",
649                                         "/etc/fedora-release",
650                                         "/etc/redhat-release",
651                                         "/etc/gentoo-release",
652                                         "/etc/slackware-version",
653                                         "/etc/arch-release",
654                                         "/etc/buildroot-release",
655                                         NULL };
656   CStdString result("");
657   char buffer[256] = {'\0'};
658
659   /* Try reading PRETTY_NAME from /etc/os-release first.
660    * If this fails, fall back to lsb_release or distro-specific release-file. */
661
662   FILE *os_release = fopen("/etc/os-release", "r");
663
664   if (os_release)
665   {
666     char *key = NULL;
667     char *val = NULL;
668
669     while (fgets(buffer, sizeof(buffer), os_release))
670     {
671       key = val = buffer;
672       strsep(&val, "=");
673
674       if (strcmp(key, "PRETTY_NAME") == 0)
675       {
676         char *pretty_name = val;
677
678         // remove newline and enclosing quotes
679         if (pretty_name[strlen(pretty_name) - 1] == '\n')
680           pretty_name[strlen(pretty_name) - 1] = '\0';
681
682         if (pretty_name[0] == '\'' || pretty_name[0] == '\"')
683         {
684           pretty_name++;
685           pretty_name[strlen(pretty_name) - 1] = '\0';
686         }
687
688         // unescape quotes and backslashes
689         char *p = pretty_name;
690         while (*p)
691         {
692           char *this_char = p;
693           char *next_char = p + 1;
694
695           if (*this_char == '\\' &&
696               (*next_char == '\'' || *next_char == '\"' || *next_char == '\\'))
697           {
698             while (*this_char)
699             {
700               *this_char = *next_char;
701               this_char++;
702               next_char++;
703             }
704           }
705
706           p++;
707         }
708
709         result = pretty_name;
710         break;
711       }
712     }
713
714     fclose(os_release);
715
716     if (!result.empty())
717       return result;
718   }
719
720   FILE* pipe = popen("unset PYTHONHOME; unset PYTHONPATH; lsb_release -d  2>/dev/null | cut -f2", "r");
721   if (pipe)
722   {
723     if (fread(buffer, sizeof(char), sizeof(buffer), pipe) > 0 && !ferror(pipe))
724       result = buffer;
725     pclose(pipe);
726     if (!result.empty())
727       return StringUtils::Trim(result);
728   }
729
730   FILE* file = NULL;
731   for (int i = 0; result.empty() && release_file[i]; i++)
732   {
733     file = fopen(release_file[i], "r");
734     if (file)
735     {
736       if (fgets(buffer, sizeof(buffer), file))
737       {
738         result = buffer;
739         if (!result.empty())
740           return StringUtils::Trim(result);
741       }
742       fclose(file);
743     }
744   }
745
746   CLog::Log(LOGWARNING, "Unable to determine Linux distribution");
747   return "Unknown";
748 }
749 #endif
750
751 #ifdef TARGET_POSIX
752 CStdString CSysInfo::GetUnameVersion()
753 {
754   CStdString result = "";
755
756 #if defined(TARGET_ANDROID)
757   struct utsname name;
758   if (uname(&name) == -1)
759     result = "Android";
760   result += name.release;
761   result += " ";
762   result += name.machine;
763 #elif defined(TARGET_DARWIN_IOS)
764   result = GetDarwinOSReleaseString();
765   result += ", ";
766   result += GetDarwinVersionString();
767 #else
768   FILE* pipe = popen("uname -rm", "r");
769   if (pipe)
770   {
771     char buffer[256];
772     if (fgets(buffer, sizeof(buffer), pipe))
773     {
774       result = buffer;
775 #if defined(TARGET_DARWIN)
776       StringUtils::Trim(result);
777       result += ", "; 
778       result += GetDarwinVersionString();
779 #endif
780     }
781     else
782       CLog::Log(LOGWARNING, "Unable to determine Uname version");
783     pclose(pipe);
784   }
785 #endif//else !TARGET_ANDROID
786
787   return StringUtils::Trim(result);
788 }
789 #endif
790
791 #if defined(TARGET_WINDOWS)
792 CStdString CSysInfo::GetUAWindowsVersion()
793 {
794   OSVERSIONINFOEX osvi = {};
795
796   osvi.dwOSVersionInfoSize = sizeof(osvi);
797   CStdString strVersion = "Windows NT";
798
799   if (GetVersionEx((OSVERSIONINFO *)&osvi))
800   {
801     strVersion += StringUtils::Format(" %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion);
802   }
803
804   SYSTEM_INFO si = {};
805   GetSystemInfo(&si);
806
807   BOOL bIsWow = FALSE;
808   if (IsWow64Process(GetCurrentProcess(), &bIsWow))
809   {
810     if (bIsWow)
811     {
812       strVersion.append(";WOW64");
813       GetNativeSystemInfo(&si);     // different function to read the info under Wow
814     }
815   }
816
817   if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
818     strVersion.append(";Win64;x64");
819   else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64)
820     strVersion.append(";Win64;IA64");
821
822   return strVersion;
823 }
824 #endif
825
826
827 CStdString CSysInfo::GetUserAgent()
828 {
829   CStdString result;
830   result = "XBMC/" + g_infoManager.GetLabel(SYSTEM_BUILD_VERSION) + " (";
831 #if defined(TARGET_WINDOWS)
832   result += GetUAWindowsVersion();
833 #elif defined(TARGET_DARWIN)
834 #if defined(TARGET_DARWIN_IOS)
835   result += "iOS; ";
836 #else
837   result += "Mac OS X; ";
838 #endif
839   result += GetUnameVersion();
840 #elif defined(TARGET_FREEBSD)
841   result += "FreeBSD; ";
842   result += GetUnameVersion();
843 #elif defined(TARGET_POSIX)
844   result += "Linux; ";
845   result += GetLinuxDistro();
846   result += "; ";
847   result += GetUnameVersion();
848 #endif
849   result += "; http://xbmc.org)";
850
851   return result;
852 }
853
854 bool CSysInfo::IsAppleTV2()
855 {
856 #if defined(TARGET_DARWIN)
857   return DarwinIsAppleTV2();
858 #else
859   return false;
860 #endif
861 }
862
863 bool CSysInfo::HasVideoToolBoxDecoder()
864 {
865   bool        result = false;
866
867 #if defined(HAVE_VIDEOTOOLBOXDECODER)
868   result = DarwinHasVideoToolboxDecoder();
869 #endif
870   return result;
871 }
872
873 std::string CSysInfo::GetBuildTargetPlatformName(void)
874 {
875 #if defined(TARGET_DARWIN_OSX)
876   return "Darwin OSX";
877 #elif defined(TARGET_DARWIN_IOS_ATV2)
878   return "Darwin iOS ATV2";
879 #elif defined(TARGET_DARWIN_IOS)
880   return "Darwin iOS";
881 #elif defined(TARGET_FREEBSD)
882   return "FreeBSD";
883 #elif defined(TARGET_ANDROID)
884   return "Android";
885 #elif defined(TARGET_LINUX)
886   return "Linux";
887 #elif defined(TARGET_WINDOWS)
888   return "Win32";
889 #else
890   return "unknown platform";
891 #endif
892 }
893
894 std::string CSysInfo::GetBuildTargetPlatformVersion(void)
895 {
896 /* Expand macro before stringify */
897 #define STR_MACRO(x) #x
898 #define XSTR_MACRO(x) STR_MACRO(x)
899
900 #if defined(TARGET_DARWIN_OSX)
901   return "version " XSTR_MACRO(__MAC_OS_X_VERSION_MIN_REQUIRED);
902 #elif defined(TARGET_DARWIN_IOS)
903   return "version " XSTR_MACRO(__IPHONE_OS_VERSION_MIN_REQUIRED);
904 #elif defined(TARGET_FREEBSD)
905   return "version " XSTR_MACRO(__FreeBSD_version);
906 #elif defined(TARGET_ANDROID)
907   return "API level " XSTR_MACRO(__ANDROID_API__);
908 #elif defined(TARGET_LINUX)
909   std::string ver = StringUtils::Format("%i.%i.%i", LINUX_VERSION_CODE >> 16, (LINUX_VERSION_CODE >> 8) & 0xff, LINUX_VERSION_CODE & 0xff);
910   return ver;
911 #elif defined(TARGET_WINDOWS)
912   return "version " XSTR_MACRO(NTDDI_VERSION);
913 #else
914   return "(unknown platform)";
915 #endif
916 }
917
918 std::string CSysInfo::GetBuildTargetCpuFamily(void)
919 {
920 #if defined(__thumb__) || defined(_M_ARMT) 
921   return "ARM (Thumb)";
922 #elif defined(__arm__) || defined(_M_ARM) || defined (__aarch64__)
923   return "ARM";
924 #elif defined(__mips__) || defined(mips) || defined(__mips)
925   return "MIPS";
926 #elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) || \
927    defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(_X86_)
928   return "x86";
929 #elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC)
930   return "PowerPC";
931 #else
932   return "unknown CPU family";
933 #endif
934 }
935
936
937 CJob *CSysInfo::GetJob() const
938 {
939   return new CSysInfoJob();
940 }
941
942 void CSysInfo::OnJobComplete(unsigned int jobID, bool success, CJob *job)
943 {
944   m_info = ((CSysInfoJob *)job)->GetData();
945   CInfoLoader::OnJobComplete(jobID, success, job);
946 }