XacroUtils.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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 "XacroUtils.h"
  9. #include <AzCore/IO/FileIO.h>
  10. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  11. #include <AzCore/XML/rapidxml.h>
  12. #include <AzFramework/Process/ProcessCommunicator.h>
  13. #include <AzFramework/Process/ProcessWatcher.h>
  14. #include <QString>
  15. namespace ROS2::Utils::xacro
  16. {
  17. ExecutionOutcome ParseXacro(const AZStd::string& filename, const Params& params)
  18. {
  19. ExecutionOutcome outcome;
  20. // test if xacro exists
  21. AZStd::string xacroPath = "xacro";
  22. auto settingsRegistry = AZ::SettingsRegistry::Get();
  23. AZStd::string xacroExecutablePath;
  24. if (settingsRegistry && settingsRegistry->Get(xacroExecutablePath, "/O3DE/ROS2/xacro_executable_path"))
  25. {
  26. // Validate the path using AZ::IO::SystemFile:Exists
  27. const bool pathExists = AZ::IO::SystemFile::Exists(xacroExecutablePath.c_str());
  28. // Use the AzProcessWatcher to launch the executable.
  29. if (pathExists)
  30. {
  31. xacroPath = xacroExecutablePath;
  32. }
  33. }
  34. AZ_Warning("ParseXacro", !xacroPath.empty(), "There is xacro executable in your path");
  35. if (xacroPath.empty())
  36. {
  37. return ExecutionOutcome{};
  38. }
  39. AZ_Printf("ParseXacro", "xacro executable : %s \n", xacroPath.c_str());
  40. AZ_Printf("ParseXacro", "Convert xacro file : %s \n", filename.c_str());
  41. const QString program = QString::fromUtf8(xacroPath.data(), xacroPath.size());
  42. AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
  43. processLaunchInfo.m_processExecutableString = xacroPath;
  44. processLaunchInfo.m_commandlineParameters.emplace<AZStd::vector<AZStd::string>>({ filename });
  45. for (const auto& param : params)
  46. {
  47. const AZStd::string& name{ param.first };
  48. const AZStd::string& value{ param.second };
  49. AZStd::string command_line_parameter{ name + ":=" + value };
  50. AZStd::get<AZStd::vector<AZStd::string>>(processLaunchInfo.m_commandlineParameters).emplace_back(command_line_parameter);
  51. }
  52. outcome.m_called = processLaunchInfo.m_processExecutableString + " " + processLaunchInfo.GetCommandLineParametersAsString();
  53. AZ_Printf("ParseXacro", "calling file : %s \n", outcome.m_called.c_str());
  54. AzFramework::ProcessOutput process_output;
  55. const bool succeed = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(
  56. processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, process_output);
  57. if (succeed && process_output.HasOutput() && !process_output.HasError())
  58. {
  59. AZ_Printf("ParseXacro", "xacro finished with success \n");
  60. const auto& output = process_output.outputResult;
  61. outcome.m_urdfHandle = UrdfParser::Parse(output.data());
  62. outcome.m_succeed = true;
  63. }
  64. else
  65. {
  66. AZ_Printf("ParseXacro", "xacro finished with error \n");
  67. const auto& stdStream = process_output.outputResult;
  68. const auto& cerrStream = process_output.errorResult;
  69. outcome.m_logStandardOutput = AZStd::string(stdStream.data(), stdStream.size());
  70. outcome.m_logErrorOutput = AZStd::string(cerrStream.data(), cerrStream.size());
  71. outcome.m_succeed = false;
  72. }
  73. return outcome;
  74. }
  75. AZStd::unordered_map<AZStd::string, AZStd::string> GetParameterFromXacroData(const AZStd::string& data)
  76. {
  77. AZStd::vector<char> dataArray;
  78. dataArray.resize_no_construct(data.size() + 1);
  79. AZStd::copy(data.data(), data.end(), dataArray.begin());
  80. dataArray.back() = '\0';
  81. constexpr char argNameTag[]{ "xacro:arg" };
  82. constexpr char nameTag[]{ "name" };
  83. constexpr char defaultTag[]{ "default" };
  84. AZStd::unordered_map<AZStd::string, AZStd::string> params;
  85. AZ::rapidxml::xml_document<char> doc;
  86. doc.parse<AZ::rapidxml::parse_full>(dataArray.data());
  87. if (doc.first_node() == nullptr)
  88. {
  89. return params;
  90. }
  91. AZ::rapidxml::xml_node<char>* xmlRootNode = doc.first_node("robot");
  92. if (xmlRootNode == nullptr)
  93. {
  94. return params;
  95. }
  96. for (AZ::rapidxml::xml_node<>* child_node = xmlRootNode->first_node(); child_node; child_node = child_node->next_sibling())
  97. {
  98. if (strcmp(argNameTag, child_node->name()) == 0)
  99. {
  100. const auto* attributeName = child_node->first_attribute(nameTag);
  101. const auto* attributeDefault = child_node->first_attribute(defaultTag);
  102. if (attributeName)
  103. {
  104. AZStd::string name{ attributeName->value() };
  105. AZStd::string value;
  106. if (attributeDefault)
  107. {
  108. value = AZStd::string{ attributeDefault->value() };
  109. }
  110. params.emplace(AZStd::make_pair(AZStd::move(name), AZStd::move(value)));
  111. }
  112. }
  113. }
  114. return params;
  115. }
  116. AZStd::unordered_map<AZStd::string, AZStd::string> GetParameterFromXacroFile(const AZStd::string& filename)
  117. {
  118. AZ::IO::FileIOStream fileStream;
  119. if (!fileStream.Open(filename.c_str(), AZ::IO::OpenMode::ModeRead | AZ::IO::OpenMode::ModeBinary))
  120. {
  121. return xacro::Params();
  122. }
  123. AZ::IO::SizeType length = fileStream.GetLength();
  124. if (length == 0)
  125. {
  126. return xacro::Params();
  127. }
  128. AZStd::string charBuffer;
  129. auto ReadFile = [&fileStream](char* buffer, size_t size)
  130. {
  131. return fileStream.Read(size, buffer);
  132. };
  133. charBuffer.resize_and_overwrite(length, ReadFile);
  134. return GetParameterFromXacroData(charBuffer);
  135. }
  136. } // namespace ROS2::Utils::xacro