text: // Copyright (c) 2012-2016, The CryptoNote developers, The Bytecoin developers
  //
  // This file is part of DCRS.
  //
  // DCRS is free software: you can redistribute it and/or modify
  // it under the terms of the GNU Lesser General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // DCRS is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU Lesser General Public License for more details.
  //
  // You should have received a copy of the GNU Lesser General Public License
  // along with DCRS.  If not, see <http://www.gnu.org/licenses/>.
  
  #include "Util.h"
  #include <cstdio>
  
  #include <boost/filesystem.hpp>
  #include <boost/algorithm/string.hpp>
  
  #include "CryptoNoteConfig.h"
  
  #ifdef _WIN32
  #include <windows.h>
  #include <shlobj.h>
  #include <strsafe.h>
  #else 
  #include <sys/utsname.h>
  #endif
  
  
  namespace Tools
  {
  #ifdef WIN32
    std::string get_windows_version_display_string()
    {
      typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
      typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
  #define BUFSIZE 10000
  
      char pszOS[BUFSIZE] = {0};
      OSVERSIONINFOEX osvi;
      SYSTEM_INFO si;
      PGNSI pGNSI;
      PGPI pGPI;
      BOOL bOsVersionInfoEx;
      DWORD dwType;
  
      ZeroMemory(&si, sizeof(SYSTEM_INFO));
      ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
  
      osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
      bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi);
  
      if(!bOsVersionInfoEx) return pszOS;
  
      // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
  
      pGNSI = (PGNSI) GetProcAddress(
        GetModuleHandle(TEXT("kernel32.dll")), 
        "GetNativeSystemInfo");
      if(NULL != pGNSI)
        pGNSI(&si);
      else GetSystemInfo(&si);
  
      if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId && 
        osvi.dwMajorVersion > 4 )
      {
        StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft "));
  
        // Test for the specific product.
  
        if ( osvi.dwMajorVersion == 6 )
        {
          if( osvi.dwMinorVersion == 0 )
          {
            if( osvi.wProductType == VER_NT_WORKSTATION )
              StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista "));
            else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 " ));
          }
  
          if ( osvi.dwMinorVersion == 1 )
          {
            if( osvi.wProductType == VER_NT_WORKSTATION )
              StringCchCat(pszOS, BUFSIZE, TEXT("Windows 7 "));
            else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 " ));
          }
  
          pGPI = (PGPI) GetProcAddress(
            GetModuleHandle(TEXT("kernel32.dll")), 
            "GetProductInfo");
  
          pGPI( osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
  
          switch( dwType )
          {
          case PRODUCT_ULTIMATE:
            StringCchCat(pszOS, BUFSIZE, TEXT("Ultimate Edition" ));
            break;
          case PRODUCT_PROFESSIONAL:
            StringCchCat(pszOS, BUFSIZE, TEXT("Professional" ));
            break;
          case PRODUCT_HOME_PREMIUM:
            StringCchCat(pszOS, BUFSIZE, TEXT("Home Premium Edition" ));
            break;
          case PRODUCT_HOME_BASIC:
            StringCchCat(pszOS, BUFSIZE, TEXT("Home Basic Edition" ));
            break;
          case PRODUCT_ENTERPRISE:
            StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
            break;
          case PRODUCT_BUSINESS:
            StringCchCat(pszOS, BUFSIZE, TEXT("Business Edition" ));
            break;
          case PRODUCT_STARTER:
            StringCchCat(pszOS, BUFSIZE, TEXT("Starter Edition" ));
            break;
          case PRODUCT_CLUSTER_SERVER:
            StringCchCat(pszOS, BUFSIZE, TEXT("Cluster Server Edition" ));
            break;
          case PRODUCT_DATACENTER_SERVER:
            StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition" ));
            break;
          case PRODUCT_DATACENTER_SERVER_CORE:
            StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition (core installation)" ));
            break;
          case PRODUCT_ENTERPRISE_SERVER:
            StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
            break;
          case PRODUCT_ENTERPRISE_SERVER_CORE:
            StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition (core installation)" ));
            break;
          case PRODUCT_ENTERPRISE_SERVER_IA64:
            StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition for Itanium-based Systems" ));
            break;
          case PRODUCT_SMALLBUSINESS_SERVER:
            StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server" ));
            break;
          case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
            StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server Premium Edition" ));
            break;
          case PRODUCT_STANDARD_SERVER:
            StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition" ));
            break;
          case PRODUCT_STANDARD_SERVER_CORE:
            StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition (core installation)" ));
            break;
          case PRODUCT_WEB_SERVER:
            StringCchCat(pszOS, BUFSIZE, TEXT("Web Server Edition" ));
            break;
          }
        }
  
        if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
        {
          if( GetSystemMetrics(SM_SERVERR2) )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Server 2003 R2, "));
          else if ( osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Storage Server 2003"));
          else if ( osvi.wSuiteMask & VER_SUITE_WH_SERVER )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Home Server"));
          else if( osvi.wProductType == VER_NT_WORKSTATION &&
            si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
          {
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows XP Professional x64 Edition"));
          }
          else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2003, "));
  
          // Test for the server type.
          if ( osvi.wProductType != VER_NT_WORKSTATION )
          {
            if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 )
            {
              if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
                StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition for Itanium-based Systems" ));
              else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
                StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition for Itanium-based Systems" ));
            }
  
            else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
            {
              if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
                StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter x64 Edition" ));
              else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
                StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise x64 Edition" ));
              else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard x64 Edition" ));
            }
  
            else
            {
              if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER )
                StringCchCat(pszOS, BUFSIZE, TEXT( "Compute Cluster Edition" ));
              else if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
                StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition" ));
              else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
                StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition" ));
              else if ( osvi.wSuiteMask & VER_SUITE_BLADE )
                StringCchCat(pszOS, BUFSIZE, TEXT( "Web Edition" ));
              else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard Edition" ));
            }
          }
        }
  
        if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
        {
          StringCchCat(pszOS, BUFSIZE, TEXT("Windows XP "));
          if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Home Edition" ));
          else StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
        }
  
        if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
        {
          StringCchCat(pszOS, BUFSIZE, TEXT("Windows 2000 "));
  
          if ( osvi.wProductType == VER_NT_WORKSTATION )
          {
            StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
          }
          else 
          {
            if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
              StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Server" ));
            else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
              StringCchCat(pszOS, BUFSIZE, TEXT( "Advanced Server" ));
            else StringCchCat(pszOS, BUFSIZE, TEXT( "Server" ));
          }
        }
  
        // Include service pack (if any) and build number.
  
        if( strlen(osvi.szCSDVersion) > 0 )
        {
          StringCchCat(pszOS, BUFSIZE, TEXT(" ") );
          StringCchCat(pszOS, BUFSIZE, osvi.szCSDVersion);
        }
  
        TCHAR buf[80];
  
        StringCchPrintf( buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber);
        StringCchCat(pszOS, BUFSIZE, buf);
  
        if ( osvi.dwMajorVersion >= 6 )
        {
          if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
            StringCchCat(pszOS, BUFSIZE, TEXT( ", 64-bit" ));
          else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
            StringCchCat(pszOS, BUFSIZE, TEXT(", 32-bit"));
        }
  
        return pszOS; 
      }
      else
      {  
        printf( "This sample does not support this version of Windows.\n");
        return pszOS;
      }
    }
  #else
  std::string get_nix_version_display_string()
  {
    utsname un;
  
    if(uname(&un) < 0)
      return std::string("*nix: failed to get os version");
    return std::string() + un.sysname + " " + un.version + " " + un.release;
  }
  #endif
  
  
  
    std::string get_os_version_string()
    {
  #ifdef WIN32
      return get_windows_version_display_string();
  #else
      return get_nix_version_display_string();
  #endif
    }
  
  
  
  #ifdef WIN32
    std::string get_special_folder_path(int nfolder, bool iscreate)
    {
      namespace fs = boost::filesystem;
      char psz_path[MAX_PATH] = "";
  
      if(SHGetSpecialFolderPathA(NULL, psz_path, nfolder, iscreate)) {
        return psz_path;
      }
  
      return "";
    }
  #endif
  
    std::string getDefaultDataDirectory()
    {
      //namespace fs = boost::filesystem;
      // Windows < Vista: C:\Documents and Settings\Username\Application Data\CRYPTONOTE_NAME
      // Windows >= Vista: C:\Users\Username\AppData\Roaming\CRYPTONOTE_NAME
      // Mac: ~/Library/Application Support/CRYPTONOTE_NAME
      // Unix: ~/.CRYPTONOTE_NAME
      std::string config_folder;
  
  #ifdef _WIN32
      // Windows
      config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "/" + CryptoNote::CRYPTONOTE_NAME;
  #ifdef USE_LITE_WALLET
      config_folder = "./";
  #endif
  #else
      std::string pathRet;
      char* pszHome = getenv("HOME");
      if (pszHome == NULL || strlen(pszHome) == 0)
        pathRet = "/";
      else
        pathRet = pszHome;
  #ifdef __APPLE__
      // Mac
      std::string old_config_folder = (pathRet + "/." + CryptoNote::CRYPTONOTE_NAME);
      std::string pathRet2 = (pathRet + "/" + "Library/Application Support");
      config_folder =  (pathRet2 + "/" + CryptoNote::CRYPTONOTE_NAME);
      // move to correct location
      boost::filesystem::path old_path(old_config_folder);
      if (!boost::filesystem::exists(config_folder) && boost::filesystem::is_directory(old_path)) {
        if (boost::filesystem::create_directory(config_folder)) {
          for (const auto& entry : boost::filesystem::recursive_directory_iterator{old_path}) {
            const auto& path = entry.path();
            auto rel_path_str = path.string();
            boost::replace_first(rel_path_str, old_path.string(), "");
            boost::filesystem::copy(path, config_folder + boost::filesystem::path::preferred_separator + rel_path_str);
          }
          boost::filesystem::remove_all(old_path);
        }
      }
  #else
      // Unix
      config_folder = (pathRet + "/." + CryptoNote::CRYPTONOTE_NAME);
  #endif
  #endif
      return config_folder;
    }
  
    bool create_directories_if_necessary(const std::string& path)
    {
      namespace fs = boost::filesystem;
      boost::system::error_code ec;
      fs::path fs_path(path);
      if (fs::is_directory(fs_path, ec)) {
        return true;
      }
  
      return fs::create_directories(fs_path, ec);
    }
  
    std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name)
    {
      int code;
  #if defined(WIN32)
      // Maximizing chances for success
      DWORD attributes = ::GetFileAttributes(replaced_name.c_str());
      if (INVALID_FILE_ATTRIBUTES != attributes)
      {
        ::SetFileAttributes(replaced_name.c_str(), attributes & (~FILE_ATTRIBUTE_READONLY));
      }
  
      bool ok = 0 != ::MoveFileEx(replacement_name.c_str(), replaced_name.c_str(), MOVEFILE_REPLACE_EXISTING);
      code = ok ? 0 : static_cast<int>(::GetLastError());
  #else
      bool ok = 0 == std::rename(replacement_name.c_str(), replaced_name.c_str());
      code = ok ? 0 : errno;
  #endif
      return std::error_code(code, std::system_category());
    }
  
    bool directoryExists(const std::string& path) {
      boost::system::error_code ec;
      return boost::filesystem::is_directory(path, ec);
    }
  
  }
  