Utilities.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. #include <AzCore/Serialization/SerializeContext.h> // Needs to be on top due to missing include in AssetSerializer.h
  9. #include <AzCore/Asset/AssetSerializer.h>
  10. #include <AzCore/Casting/numeric_cast.h>
  11. #include <AzCore/Debug/Trace.h>
  12. #include <AzCore/IO/FileIO.h>
  13. #include <AzCore/IO/SystemFile.h>
  14. #include <AzCore/Module/Module.h>
  15. #include <AzCore/Module/ModuleManagerBus.h>
  16. #include <AzCore/Serialization/Json/JsonSerialization.h>
  17. #include <AzCore/Serialization/Json/RegistrationContext.h>
  18. #include <AzCore/Settings/CommandLine.h>
  19. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  20. #include <AzCore/std/algorithm.h>
  21. #include <AzCore/std/containers/queue.h>
  22. #include <AzCore/std/functional.h>
  23. #include <AzCore/std/string/conversions.h>
  24. #include <AzCore/std/string/wildcard.h>
  25. #include <AzCore/StringFunc/StringFunc.h>
  26. #include <Application.h>
  27. #include <Utilities.h>
  28. namespace AZ::SerializeContextTools
  29. {
  30. AZStd::string Utilities::ReadOutputTargetFromCommandLine(Application& application, const char* defaultFileOrFolder)
  31. {
  32. AZ::IO::Path outputPath;
  33. if (application.GetAzCommandLine()->HasSwitch("output"))
  34. {
  35. outputPath.Native() = application.GetAzCommandLine()->GetSwitchValue("output", 0);
  36. }
  37. else
  38. {
  39. outputPath = defaultFileOrFolder;
  40. }
  41. return AZStd::move(outputPath.Native());
  42. }
  43. AZStd::vector<AZStd::string> Utilities::ReadFileListFromCommandLine(Application& application, AZStd::string_view switchName)
  44. {
  45. AZStd::vector<AZStd::string> result;
  46. const AZ::CommandLine* commandLine = application.GetAzCommandLine();
  47. if (!commandLine)
  48. {
  49. AZ_Error("SerializeContextTools", false, "Command line not available.");
  50. return result;
  51. }
  52. if (!commandLine->HasSwitch(switchName))
  53. {
  54. AZ_Error("SerializeContextTools", false, "Missing command line argument '-%*s' which should contain the requested files.",
  55. aznumeric_cast<int>(switchName.size()), switchName.data());
  56. return result;
  57. }
  58. AZStd::vector<AZStd::string_view> fileList;
  59. auto AppendFileList = [&fileList](AZStd::string_view filename)
  60. {
  61. fileList.emplace_back(filename);
  62. };
  63. for (size_t switchIndex{}; switchIndex < commandLine->GetNumSwitchValues(switchName); ++switchIndex)
  64. {
  65. AZ::StringFunc::TokenizeVisitor(commandLine->GetSwitchValue(switchName, switchIndex), AppendFileList, ";");
  66. }
  67. return Utilities::ExpandFileList(".", fileList);
  68. }
  69. AZStd::vector<AZStd::string> Utilities::ExpandFileList(const char* root, const AZStd::vector<AZStd::string_view>& fileList)
  70. {
  71. AZStd::vector<AZStd::string> result;
  72. result.reserve(fileList.size());
  73. for (const AZStd::string_view& file : fileList)
  74. {
  75. if (HasWildCard(file))
  76. {
  77. AZ::IO::FixedMaxPath filterPath{ file };
  78. AZ::IO::FixedMaxPath parentPath{ filterPath.ParentPath() };
  79. if (filterPath.IsRelative())
  80. {
  81. parentPath = AZ::IO::FixedMaxPath(root) / parentPath;
  82. }
  83. AZ::IO::PathView filterFilename = filterPath.Filename();
  84. if (filterFilename.empty())
  85. {
  86. AZ_Error("SerializeContextTools", false, "Unable to get folder path for '%.*s'.",
  87. aznumeric_cast<int>(filterFilename.Native().size()), filterFilename.Native().data());
  88. continue;
  89. }
  90. AZStd::queue<AZ::IO::FixedMaxPath> pendingFolders;
  91. pendingFolders.push(AZStd::move(parentPath));
  92. while (!pendingFolders.empty())
  93. {
  94. const AZ::IO::FixedMaxPath& filterFolder = pendingFolders.front();
  95. auto callback = [&pendingFolders, &filterFolder, &filterFilename, &result](AZ::IO::PathView item, bool isFile) -> bool
  96. {
  97. if (item == "." || item == "..")
  98. {
  99. return true;
  100. }
  101. AZ::IO::FixedMaxPath fullPath = filterFolder / item;
  102. if (isFile)
  103. {
  104. if (AZStd::wildcard_match(filterFilename.Native(), item.Native()))
  105. {
  106. result.emplace_back(fullPath.c_str(), fullPath.Native().size());
  107. }
  108. }
  109. else
  110. {
  111. pendingFolders.push(AZStd::move(fullPath));
  112. }
  113. return true;
  114. };
  115. AZ::IO::SystemFile::FindFiles((filterFolder / "*").c_str(), callback);
  116. pendingFolders.pop();
  117. }
  118. }
  119. else
  120. {
  121. AZ::IO::FixedMaxPath filePath{ file };
  122. if (filePath.IsRelative())
  123. {
  124. filePath = AZ::IO::FixedMaxPath(root) / filePath;
  125. }
  126. result.emplace_back(filePath.c_str(), filePath.Native().size());
  127. }
  128. }
  129. return result;
  130. }
  131. bool Utilities::HasWildCard(AZStd::string_view string)
  132. {
  133. // Wild cards vary between platforms, but these are the most common ones.
  134. return string.find_first_of("*?[]!@#", 0) != AZStd::string_view::npos;
  135. }
  136. void Utilities::SanitizeFilePath(AZStd::string& filePath)
  137. {
  138. auto invalidCharacters = [](char letter)
  139. {
  140. return
  141. letter == ':' || letter == '"' || letter == '\'' ||
  142. letter == '{' || letter == '}' ||
  143. letter == '<' || letter == '>';
  144. };
  145. AZStd::replace_if(filePath.begin(), filePath.end(), invalidCharacters, '_');
  146. }
  147. bool Utilities::IsSerializationPrimitive(const AZ::Uuid& classId)
  148. {
  149. JsonRegistrationContext* registrationContext;
  150. AZ::ComponentApplicationBus::BroadcastResult(registrationContext, &AZ::ComponentApplicationBus::Events::GetJsonRegistrationContext);
  151. if (!registrationContext)
  152. {
  153. AZ_Error("SerializeContextTools", false, "Failed to retrieve json registration context.");
  154. return false;
  155. }
  156. return registrationContext->GetSerializerForType(classId) != nullptr;
  157. }
  158. AZStd::vector<AZ::Uuid> Utilities::GetSystemComponents(const Application& application)
  159. {
  160. AZStd::vector<AZ::Uuid> result = application.GetRequiredSystemComponents();
  161. auto getModuleSystemComponentsCB = [&result](const ModuleData& moduleData) -> bool
  162. {
  163. if (AZ::Module* module = moduleData.GetModule())
  164. {
  165. AZ::ComponentTypeList moduleRequiredComponents = module->GetRequiredSystemComponents();
  166. result.reserve(result.size() + moduleRequiredComponents.size());
  167. result.insert(result.end(), moduleRequiredComponents.begin(), moduleRequiredComponents.end());
  168. }
  169. return true;
  170. };
  171. ModuleManagerRequestBus::Broadcast(&ModuleManagerRequests::EnumerateModules, getModuleSystemComponentsCB);
  172. return result;
  173. }
  174. AZStd::string Utilities::GenerateRelativePosixPath(const AZ::IO::PathView& projectPath, const AZ::IO::PathView& absolutePath)
  175. {
  176. AZ::IO::FixedMaxPath projectRelativeFilePath = absolutePath.LexicallyProximate(projectPath);
  177. AZStd::to_lower(projectRelativeFilePath.Native().begin(), projectRelativeFilePath.Native().end());
  178. AZStd::string result = projectRelativeFilePath.StringAsPosix();
  179. const bool isOutsideProjectFolder = result.starts_with("..");
  180. if (isOutsideProjectFolder)
  181. {
  182. result = GetStringAfterFirstOccurenceOf("assets/", result);
  183. }
  184. return result;
  185. }
  186. AZStd::string_view Utilities::GetStringAfterFirstOccurenceOf(const AZStd::string_view& toFind, const AZStd::string_view& string)
  187. {
  188. const auto startIndex = string.find(toFind);
  189. return startIndex == AZStd::string::npos ? string : string.substr(startIndex + toFind.length());
  190. }
  191. } // namespace AZ::SerializeContextTools