From 1025e3ecea67b90232cfdc9590a7ee8887efdcc8 Mon Sep 17 00:00:00 2001 From: lupoDharkael Date: Tue, 20 Nov 2018 18:00:58 +0100 Subject: Node: make _generate_serial_child_name manipulate numbers as String The conversion from an String to int can overflow int and int64 so it is safer to manipulate strings when we try to find the next available name for a Node. --- scene/main/node.cpp | 80 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 29 deletions(-) (limited to 'scene/main') diff --git a/scene/main/node.cpp b/scene/main/node.cpp index ae2ab2af80..ea50e7289d 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1008,6 +1008,32 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) { } } +// Return s + 1 as if it were an integer +String increase_numeric_string(const String &s) { + + String res = s; + bool carry = res.length() > 0; + + for (int i = res.length() - 1; i >= 0; i--) { + if (!carry) { + break; + } + CharType n = s[i]; + if (n == '9') { // keep carry as true: 9 + 1 + res[i] = '0'; + } else { + res[i] = s[i] + 1; + carry = false; + } + } + + if (carry) { + res = "1" + res; + } + + return res; +} + String Node::_generate_serial_child_name(Node *p_child) { String name = p_child->data.name; @@ -1040,42 +1066,38 @@ String Node::_generate_serial_child_name(Node *p_child) { } String nnsep = _get_name_num_separator(); - int num = 0; - bool explicit_zero = false; - if (nums.length() > 0 && name.substr(name.length() - nnsep.length() - nums.length(), nnsep.length()) == nnsep) { - // Base name + Separator + Number - num = nums.to_int(); - name = name.substr(0, name.length() - nnsep.length() - nums.length()); // Keep base name - if (num == 0) { - explicit_zero = true; + int name_last_index = name.length() - nnsep.length() - nums.length(); + + // Assign the base name + separator to name if we have numbers preceded by a separator + if (nums.length() > 0 && name.substr(name_last_index, nnsep.length()) == nnsep) { + name = name.substr(0, name_last_index + nnsep.length()).strip_edges(); + } else { + nums = ""; + } + + Vector children_names; + + for (int i = 0; i < data.children.size(); i++) { + String child_name = data.children[i]->data.name; + if (data.children[i] == p_child) + continue; + if (child_name.begins_with(name)) { + children_names.push_back(child_name); } } - int num_places = nums.length(); for (;;) { - String attempt = (name + (num > 0 || explicit_zero ? nnsep + itos(num).pad_zeros(num_places) : "")).strip_edges(); - bool found = false; - for (int i = 0; i < data.children.size(); i++) { - if (data.children[i] == p_child) - continue; - if (data.children[i]->data.name == attempt) { - found = true; - break; - } - } - if (!found) { + String attempt = name + nums; + + if (children_names.find(attempt) == -1) { return attempt; } else { - if (num == 0) { - if (explicit_zero) { - // Name ended in separator + 0; user expects to get to separator + 1 - num = 1; - } else { - // Name was undecorated so skip to 2 for a more natural result - num = 2; - } + if (nums.length() == 0) { + // Name was undecorated so skip to 2 for a more natural result + nums = "2"; + name += nnsep; // Add separator because nums.length() > 0 was false } else { - num++; + nums = increase_numeric_string(nums); } } } -- cgit v1.2.3