SystemCFG.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // Description : handles system cfg
  9. #include "CrySystem_precompiled.h"
  10. #include "System.h"
  11. #include <time.h>
  12. #include "XConsole.h"
  13. #include "CryFile.h"
  14. #include "CryPath.h"
  15. #include <AzCore/Console/IConsole.h>
  16. #include <AzCore/Interface/Interface.h>
  17. #include <AzCore/Utils/Utils.h>
  18. #include <AzFramework/StringFunc/StringFunc.h>
  19. #if defined(AZ_RESTRICTED_PLATFORM)
  20. #undef AZ_RESTRICTED_SECTION
  21. #define SYSTEMCFG_CPP_SECTION_1 1
  22. #define SYSTEMCFG_CPP_SECTION_2 2
  23. #define SYSTEMCFG_CPP_SECTION_3 3
  24. #endif
  25. #if defined(LINUX) || defined(APPLE)
  26. #include "ILog.h"
  27. #endif
  28. #ifndef EXE_VERSION_INFO_0
  29. #define EXE_VERSION_INFO_0 1
  30. #endif
  31. #ifndef EXE_VERSION_INFO_1
  32. #define EXE_VERSION_INFO_1 0
  33. #endif
  34. #ifndef EXE_VERSION_INFO_2
  35. #define EXE_VERSION_INFO_2 0
  36. #endif
  37. #ifndef EXE_VERSION_INFO_3
  38. #define EXE_VERSION_INFO_3 1
  39. #endif
  40. #if defined(AZ_RESTRICTED_PLATFORM)
  41. #define AZ_RESTRICTED_SECTION SYSTEMCFG_CPP_SECTION_1
  42. #include AZ_RESTRICTED_FILE(SystemCFG_cpp)
  43. #endif
  44. //////////////////////////////////////////////////////////////////////////
  45. const SFileVersion& CSystem::GetFileVersion()
  46. {
  47. return m_fileVersion;
  48. }
  49. //////////////////////////////////////////////////////////////////////////
  50. const SFileVersion& CSystem::GetProductVersion()
  51. {
  52. return m_productVersion;
  53. }
  54. //////////////////////////////////////////////////////////////////////////
  55. const SFileVersion& CSystem::GetBuildVersion()
  56. {
  57. return m_buildVersion;
  58. }
  59. //////////////////////////////////////////////////////////////////////////
  60. #ifndef _RELEASE
  61. void CSystem::SystemVersionChanged(ICVar* pCVar)
  62. {
  63. if (CSystem* pThis = static_cast<CSystem*>(gEnv->pSystem))
  64. {
  65. pThis->SetVersionInfo(pCVar->GetString());
  66. }
  67. }
  68. void CSystem::SetVersionInfo(const char* const szVersion)
  69. {
  70. m_fileVersion.Set(szVersion);
  71. m_productVersion.Set(szVersion);
  72. m_buildVersion.Set(szVersion);
  73. CryLog("SetVersionInfo '%s'", szVersion);
  74. CryLog("FileVersion: %d.%d.%d.%d", m_fileVersion.v[3], m_fileVersion.v[2], m_fileVersion.v[1], m_fileVersion.v[0]);
  75. CryLog("ProductVersion: %d.%d.%d.%d", m_productVersion.v[3], m_productVersion.v[2], m_productVersion.v[1], m_productVersion.v[0]);
  76. CryLog("BuildVersion: %d.%d.%d.%d", m_buildVersion.v[3], m_buildVersion.v[2], m_buildVersion.v[1], m_buildVersion.v[0]);
  77. }
  78. #endif // #ifndef _RELEASE
  79. //////////////////////////////////////////////////////////////////////////
  80. void CSystem::QueryVersionInfo()
  81. {
  82. #ifndef WIN32
  83. //do we need some other values here?
  84. m_fileVersion.v[0] = m_productVersion.v[0] = EXE_VERSION_INFO_3;
  85. m_fileVersion.v[1] = m_productVersion.v[1] = EXE_VERSION_INFO_2;
  86. m_fileVersion.v[2] = m_productVersion.v[2] = EXE_VERSION_INFO_1;
  87. m_fileVersion.v[3] = m_productVersion.v[3] = EXE_VERSION_INFO_0;
  88. m_buildVersion = m_fileVersion;
  89. #else //WIN32
  90. char moduleName[_MAX_PATH];
  91. DWORD dwHandle;
  92. UINT len;
  93. char ver[1024 * 8];
  94. AZ::Utils::GetExecutablePath(moduleName, _MAX_PATH); //retrieves the PATH for the current module
  95. #ifdef AZ_MONOLITHIC_BUILD
  96. AZ::Utils::GetExecutablePath(moduleName, _MAX_PATH); //retrieves the PATH for the current module
  97. #else // AZ_MONOLITHIC_BUILD
  98. azstrcpy(moduleName, AZ_ARRAY_SIZE(moduleName), "CrySystem.dll"); // we want to version from the system dll
  99. #endif // AZ_MONOLITHIC_BUILD
  100. AZStd::wstring moduleNameW;
  101. AZStd::to_wstring(moduleNameW, moduleName);
  102. int verSize = GetFileVersionInfoSizeW(moduleNameW.c_str(), &dwHandle);
  103. if (verSize > 0)
  104. {
  105. GetFileVersionInfoW(moduleNameW.c_str(), dwHandle, 1024 * 8, ver);
  106. VS_FIXEDFILEINFO* vinfo;
  107. VerQueryValueW(ver, L"\\", (void**)&vinfo, &len);
  108. const uint32 verIndices[4] = {0, 1, 2, 3};
  109. m_fileVersion.v[verIndices[0]] = m_productVersion.v[verIndices[0]] = vinfo->dwFileVersionLS & 0xFFFF;
  110. m_fileVersion.v[verIndices[1]] = m_productVersion.v[verIndices[1]] = vinfo->dwFileVersionLS >> 16;
  111. m_fileVersion.v[verIndices[2]] = m_productVersion.v[verIndices[2]] = vinfo->dwFileVersionMS & 0xFFFF;
  112. m_fileVersion.v[verIndices[3]] = m_productVersion.v[verIndices[3]] = vinfo->dwFileVersionMS >> 16;
  113. m_buildVersion = m_fileVersion;
  114. struct LANGANDCODEPAGE
  115. {
  116. WORD wLanguage;
  117. WORD wCodePage;
  118. }* lpTranslate;
  119. UINT count = 0;
  120. wchar_t path[256];
  121. char* version = NULL;
  122. VerQueryValueW(ver, L"\\VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &count);
  123. if (lpTranslate != NULL)
  124. {
  125. azsnwprintf(path, sizeof(path), L"\\StringFileInfo\\%04x%04x\\InternalName", lpTranslate[0].wLanguage, lpTranslate[0].wCodePage);
  126. VerQueryValueW(ver, path, (LPVOID*)&version, &count);
  127. if (version)
  128. {
  129. m_buildVersion.Set(version);
  130. }
  131. }
  132. }
  133. #endif //WIN32
  134. }
  135. //////////////////////////////////////////////////////////////////////////
  136. void CSystem::LogVersion()
  137. {
  138. // Get time.
  139. time_t ltime;
  140. time(&ltime);
  141. #ifdef AZ_COMPILER_MSVC
  142. tm today;
  143. localtime_s(&today, &ltime);
  144. char s[1024];
  145. strftime(s, 128, "%d %b %y (%H %M %S)", &today);
  146. #else
  147. char s[1024];
  148. auto today = localtime(&ltime);
  149. strftime(s, 128, "%d %b %y (%H %M %S)", today);
  150. #endif
  151. [[maybe_unused]] const SFileVersion& ver = GetFileVersion();
  152. CryLogAlways("BackupNameAttachment=\" Build(%d) %s\" -- used by backup system\n", ver.v[0], s); // read by CreateBackupFile()
  153. // Use strftime to build a customized time string.
  154. #ifdef AZ_COMPILER_MSVC
  155. strftime(s, 128, "Log Started at %c", &today);
  156. #else
  157. strftime(s, 128, "Log Started at %c", today);
  158. #endif
  159. CryLogAlways("%s", s);
  160. CryLogAlways("Built on " __DATE__ " " __TIME__);
  161. #if defined(AZ_RESTRICTED_PLATFORM)
  162. #define AZ_RESTRICTED_SECTION SYSTEMCFG_CPP_SECTION_2
  163. #include AZ_RESTRICTED_FILE(SystemCFG_cpp)
  164. #elif defined(ANDROID)
  165. CryLogAlways("Running 32 bit Android version API VER:%d", __ANDROID_API__);
  166. #elif defined(IOS)
  167. CryLogAlways("Running 64 bit iOS version");
  168. #elif defined(WIN64)
  169. CryLogAlways("Running 64 bit Windows version");
  170. #elif defined(WIN32)
  171. CryLogAlways("Running 32 bit Windows version");
  172. #elif defined(LINUX64)
  173. CryLogAlways("Running 64 bit Linux version");
  174. #elif defined(LINUX32)
  175. CryLogAlways("Running 32 bit Linux version");
  176. #elif defined(MAC)
  177. CryLogAlways("Running 64 bit Mac version");
  178. #endif
  179. #if AZ_LEGACY_CRYSYSTEM_TRAIT_SYSTEMCFG_MODULENAME
  180. AZ::Utils::GetExecutablePath(s, sizeof(s));
  181. // Log EXE filename only if possible (not full EXE path which could contain sensitive info)
  182. AZStd::string exeName;
  183. if (AzFramework::StringFunc::Path::GetFullFileName(s, exeName)) {
  184. CryLogAlways("Executable: %s", exeName.c_str());
  185. }
  186. #endif
  187. CryLogAlways("FileVersion: %d.%d.%d.%d", m_fileVersion.v[3], m_fileVersion.v[2], m_fileVersion.v[1], m_fileVersion.v[0]);
  188. #if defined(LY_BUILD)
  189. CryLogAlways("ProductVersion: %d.%d.%d.%d - Build %d", m_productVersion.v[3], m_productVersion.v[2], m_productVersion.v[1], m_productVersion.v[0], LY_BUILD);
  190. #else // defined(LY_BUILD)
  191. CryLogAlways("ProductVersion: %d.%d.%d.%d", m_productVersion.v[3], m_productVersion.v[2], m_productVersion.v[1], m_productVersion.v[0]);
  192. #endif // defined(LY_BUILD)
  193. #if defined(AZ_RESTRICTED_PLATFORM)
  194. #define AZ_RESTRICTED_SECTION SYSTEMCFG_CPP_SECTION_3
  195. #include AZ_RESTRICTED_FILE(SystemCFG_cpp)
  196. #endif
  197. #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
  198. #undef AZ_RESTRICTED_SECTION_IMPLEMENTED
  199. #elif defined(_MSC_VER)
  200. CryLogAlways("Using Microsoft (tm) C++ Standard Library implementation\n");
  201. #elif defined(__clang__)
  202. CryLogAlways("Using CLANG C++ Standard Library implementation\n");
  203. #elif defined(__GNUC__)
  204. CryLogAlways("Using GNU C++ Standard Library implementation\n");
  205. #else
  206. #error "Please specify C++ STL library"
  207. #endif
  208. }
  209. //////////////////////////////////////////////////////////////////////////
  210. void CSystem::LogBuildInfo()
  211. {
  212. [[maybe_unused]] auto projectName = AZ::Utils::GetProjectName();
  213. CryLogAlways("GameName: %s", projectName.c_str());
  214. CryLogAlways("BuildTime: " __DATE__ " " __TIME__);
  215. }
  216. //////////////////////////////////////////////////////////////////////////
  217. void CSystem::SaveConfiguration()
  218. {
  219. }
  220. //////////////////////////////////////////////////////////////////////////
  221. static bool ParseSystemConfig(const AZStd::string& strSysConfigFilePath, ILoadConfigurationEntrySink* pSink, bool warnIfMissing)
  222. {
  223. assert(pSink);
  224. AZStd::string filename = strSysConfigFilePath;
  225. if (strlen(PathUtil::GetExt(filename.c_str())) == 0)
  226. {
  227. filename = PathUtil::ReplaceExtension(filename, "cfg");
  228. }
  229. CCryFile file;
  230. AZStd::string filenameLog;
  231. {
  232. if (filename[0] == '@')
  233. {
  234. // this is used when theres a very specific file to read, like @user@/game.cfg which is read
  235. // IN ADDITION to the one in the game folder, and afterwards to override values in it.
  236. // if the file is missing and its already prefixed with an alias, there is no need to look any further.
  237. if (!(file.Open(filename.c_str(), "rb")))
  238. {
  239. if (warnIfMissing)
  240. {
  241. CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Config file %s not found!", filename.c_str());
  242. }
  243. return false;
  244. }
  245. }
  246. else
  247. {
  248. // otherwise, if the file isn't prefixed with an alias, then its likely one of the convenience mappings
  249. // to either root or assets/config. this is done so that code can just request a simple file name and get its data
  250. if (
  251. !(file.Open(filename.c_str(), "rb")) &&
  252. !(file.Open((AZStd::string("@products@/") + filename).c_str(), "rb")) &&
  253. !(file.Open((AZStd::string("@products@/") + filename).c_str(), "rb")) &&
  254. !(file.Open((AZStd::string("@products@/config/") + filename).c_str(), "rb")) &&
  255. !(file.Open((AZStd::string("@products@/config/spec/") + filename).c_str(), "rb"))
  256. )
  257. {
  258. if (warnIfMissing)
  259. {
  260. CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Config file %s not found!", filename.c_str());
  261. }
  262. return false;
  263. }
  264. }
  265. AZ::IO::FixedMaxPath resolvedFilePath;
  266. AZ::IO::FileIOBase::GetInstance()->ResolvePath(resolvedFilePath, file.GetFilename());
  267. filenameLog = resolvedFilePath.String();
  268. }
  269. INDENT_LOG_DURING_SCOPE();
  270. int nLen = static_cast<int>(file.GetLength());
  271. if (nLen == 0)
  272. {
  273. CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Couldn't get length for Config file %s", filename.c_str());
  274. return false;
  275. }
  276. char* sAllText = new char [nLen + 16];
  277. if (file.ReadRaw(sAllText, nLen) < (size_t)nLen)
  278. {
  279. CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Couldn't read Config file %s", filename.c_str());
  280. return false;
  281. }
  282. sAllText[nLen] = '\0';
  283. sAllText[nLen + 1] = '\0';
  284. AZStd::string strGroup; // current group e.g. "[General]"
  285. char* strLast = sAllText + nLen;
  286. char* str = sAllText;
  287. while (str < strLast)
  288. {
  289. char* s = str;
  290. while (str < strLast && *str != '\n' && *str != '\r')
  291. {
  292. str++;
  293. }
  294. *str = '\0';
  295. str++;
  296. while (str < strLast && (*str == '\n' || *str == '\r'))
  297. {
  298. str++;
  299. }
  300. AZStd::string strLine = s;
  301. AZ::StringFunc::TrimWhiteSpace(strLine, true, true);
  302. // detect groups e.g. "[General]" should set strGroup="General"
  303. {
  304. size_t size = strLine.size();
  305. if (size >= 3)
  306. {
  307. if (strLine[0] == '[' && strLine[size - 1] == ']') // currently no comments are allowed to be behind groups
  308. {
  309. strGroup = &strLine[1];
  310. strGroup.resize(size - 2); // remove [ and ]
  311. continue; // next line
  312. }
  313. }
  314. }
  315. //trim all whitespace characters at the beginning and the end of the current line and store its size
  316. size_t strLineSize = strLine.size();
  317. //skip comments, comments start with ";" or "--" but may have preceding whitespace characters
  318. if (strLineSize > 0)
  319. {
  320. if (strLine[0] == ';')
  321. {
  322. continue;
  323. }
  324. else if (strLine.find("--") == 0)
  325. {
  326. continue;
  327. }
  328. }
  329. //skip empty lines
  330. else
  331. {
  332. continue;
  333. }
  334. //if line contains a '=' try to read and assign console variable
  335. AZStd::string::size_type posEq(strLine.find("=", 0));
  336. if (AZStd::string::npos != posEq)
  337. {
  338. AZStd::string stemp;
  339. AZStd::string strKey(strLine, 0, posEq);
  340. AZ::StringFunc::TrimWhiteSpace(strKey, true, true);
  341. {
  342. // extract value
  343. AZStd::string::size_type posValueStart(strLine.find("\"", posEq + 1) + 1);
  344. AZStd::string::size_type posValueEnd(strLine.rfind('\"'));
  345. AZStd::string strValue;
  346. if (AZStd::string::npos != posValueStart && AZStd::string::npos != posValueEnd)
  347. {
  348. strValue = AZStd::string(strLine, posValueStart, posValueEnd - posValueStart);
  349. }
  350. else
  351. {
  352. strValue = AZStd::string(strLine, posEq + 1, strLine.size() - (posEq + 1));
  353. AZ::StringFunc::TrimWhiteSpace(strValue, true, true);
  354. }
  355. {
  356. // replace '\\\\' with '\\' and '\\\"' with '\"'
  357. AZ::StringFunc::Replace(strValue, "\\\\", "\\");
  358. AZ::StringFunc::Replace(strValue, "\\\"", "\"");
  359. pSink->OnLoadConfigurationEntry(strKey.c_str(), strValue.c_str(), strGroup.c_str());
  360. }
  361. }
  362. }
  363. else
  364. {
  365. gEnv->pLog->LogWithType(ILog::eWarning, "%s -> invalid configuration line: %s", filename.c_str(), strLine.c_str());
  366. }
  367. }
  368. delete []sAllText;
  369. CryLog("Loading Config file %s (%s)", filename.c_str(), filenameLog.c_str());
  370. pSink->OnLoadConfigurationEntry_End();
  371. return true;
  372. }
  373. //////////////////////////////////////////////////////////////////////////
  374. void CSystem::OnLoadConfigurationEntry(const char* szKey, const char* szValue, [[maybe_unused]] const char* szGroup)
  375. {
  376. bool azConsoleProcessed = false;
  377. auto console = AZ::Interface<AZ::IConsole>::Get();
  378. if (console)
  379. {
  380. AZStd::string command(AZStd::string::format("%s %s", szKey, szValue));
  381. azConsoleProcessed = static_cast<bool>(console->PerformCommand(command.c_str()));
  382. }
  383. if (!azConsoleProcessed)
  384. {
  385. if (!gEnv->pConsole)
  386. {
  387. return;
  388. }
  389. if (*szKey != 0)
  390. {
  391. gEnv->pConsole->LoadConfigVar(szKey, szValue);
  392. }
  393. }
  394. }
  395. //////////////////////////////////////////////////////////////////////////
  396. void CSystem::LoadConfiguration(const char* sFilename, ILoadConfigurationEntrySink* pSink, bool warnIfMissing)
  397. {
  398. if (sFilename && strlen(sFilename) > 0)
  399. {
  400. if (!pSink)
  401. {
  402. pSink = this;
  403. }
  404. ParseSystemConfig(sFilename, pSink, warnIfMissing);
  405. }
  406. }