| 1040 | } |
| 1041 | |
| 1042 | void BT::XMLParser::PImpl::recursivelyCreateSubtree( |
| 1043 | const std::string& tree_ID, const std::string& tree_path, |
| 1044 | const std::string& prefix_path, Tree& output_tree, Blackboard::Ptr blackboard, |
| 1045 | const TreeNode::Ptr& root_node, std::unordered_set<std::string>& ancestors) |
| 1046 | { |
| 1047 | if(!ancestors.insert(tree_ID).second) |
| 1048 | { |
| 1049 | throw RuntimeError("Recursive behavior tree cycle detected: tree '", tree_ID, |
| 1050 | "' references itself (directly or indirectly)"); |
| 1051 | } |
| 1052 | constexpr int kMaxNestingDepth = 256; |
| 1053 | std::function<void(const TreeNode::Ptr&, Tree::Subtree::Ptr, std::string, |
| 1054 | const XMLElement*, int)> |
| 1055 | recursiveStep; |
| 1056 | |
| 1057 | recursiveStep = [&](TreeNode::Ptr parent_node, Tree::Subtree::Ptr subtree, |
| 1058 | std::string prefix, const XMLElement* element, int depth) { |
| 1059 | if(depth > kMaxNestingDepth) |
| 1060 | { |
| 1061 | throw RuntimeError("Maximum XML nesting depth exceeded during tree " |
| 1062 | "instantiation (limit: ", |
| 1063 | std::to_string(kMaxNestingDepth), |
| 1064 | "). The XML is too deeply nested."); |
| 1065 | } |
| 1066 | // create the node |
| 1067 | auto node = createNodeFromXML(element, blackboard, parent_node, prefix, output_tree); |
| 1068 | subtree->nodes.push_back(node); |
| 1069 | |
| 1070 | // common case: iterate through all children |
| 1071 | if(node->type() != NodeType::SUBTREE) |
| 1072 | { |
| 1073 | for(auto child_element = element->FirstChildElement(); child_element != nullptr; |
| 1074 | child_element = child_element->NextSiblingElement()) |
| 1075 | { |
| 1076 | recursiveStep(node, subtree, prefix, child_element, depth + 1); |
| 1077 | } |
| 1078 | } |
| 1079 | else // special case: SubTreeNode |
| 1080 | { |
| 1081 | auto new_bb = Blackboard::create(blackboard); |
| 1082 | // Inherit polymorphic cast registry from factory (Issue #943) |
| 1083 | new_bb->setPolymorphicCastRegistry(factory->polymorphicCastRegistryPtr()); |
| 1084 | const std::string subtree_ID = element->Attribute("ID"); |
| 1085 | std::unordered_map<std::string, std::string> subtree_remapping; |
| 1086 | bool do_autoremap = false; |
| 1087 | |
| 1088 | for(auto attr = element->FirstAttribute(); attr != nullptr; attr = attr->Next()) |
| 1089 | { |
| 1090 | const std::string attr_name = attr->Name(); |
| 1091 | std::string attr_value = attr->Value(); |
| 1092 | if(attr_value == "{=}") |
| 1093 | { |
| 1094 | attr_value = StrCat("{", attr_name, "}"); |
| 1095 | } |
| 1096 | |
| 1097 | if(attr_name == "_autoremap") |
| 1098 | { |
| 1099 | do_autoremap = convertFromString<bool>(attr_value); |
no test coverage detected