diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index d3134199..5fe1c71a 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -445,11 +445,21 @@ void Game::updatecustomlevelstats(std::string clevel, int cscore) #define LOAD_ARRAY_RENAME(ARRAY_NAME, DEST) \ if (pKey == #ARRAY_NAME && pText[0] != '\0') \ { \ - std::string TextString = pText; \ - std::vector values = split(TextString, ','); \ - for (int i = 0; i < VVV_min(SDL_arraysize(DEST), values.size()); i++) \ + /* We're loading in 32-bit integers. If we need more than 16 chars, + * something is seriously wrong */ \ + char buffer[16]; \ + size_t start = 0; \ + size_t i = 0; \ + \ + while (next_split_s(buffer, sizeof(buffer), &start, pText, ',')) \ { \ - DEST[i] = help.Int(values[i].c_str()); \ + if (i >= SDL_arraysize(DEST)) \ + { \ + break; \ + } \ + \ + DEST[i] = help.Int(buffer); \ + ++i; \ } \ } @@ -541,11 +551,15 @@ void Game::loadcustomlevelstats() if (pKey == "customlevelstats" && pText[0] != '\0') { - std::string TextString = (pText); - std::vector values = split(TextString,'|'); - for(size_t i = 0; i < values.size(); i++) + size_t start = 0; + size_t len = 0; + size_t prev_start = 0; + + while (next_split(&start, &len, &pText[start], '|')) { - customlevelnames.push_back(values[i]); + customlevelnames.push_back(std::string(&pText[prev_start], len)); + + prev_start = start; } } } diff --git a/desktop_version/src/UtilityClass.cpp b/desktop_version/src/UtilityClass.cpp index 2a7b928f..0331c2c2 100644 --- a/desktop_version/src/UtilityClass.cpp +++ b/desktop_version/src/UtilityClass.cpp @@ -4,6 +4,8 @@ #include #include +#include "Maths.h" + static const char* GCChar(const SDL_GameControllerButton button) { switch (button) @@ -71,21 +73,61 @@ int ss_toi(const std::string& str) return retval; } -std::vector split( const std::string &s, char delim, std::vector &elems ) -{ - std::stringstream ss(s); - std::string item; - while(std::getline(ss, item, delim)) +bool next_split( + size_t* start, + size_t* len, + const char* str, + const char delim +) { + size_t idx = 0; + *len = 0; + + if (str[idx] == '\0') { - elems.push_back(item); + return false; + } + + while (true) + { + if (str[idx] == delim) + { + *start += 1; + return true; + } + else if (str[idx] == '\0') + { + return true; + } + + idx += 1; + *start += 1; + *len += 1; } - return elems; } -std::vector split( const std::string &s, char delim ) -{ - std::vector elems; - return split(s, delim, elems); +bool next_split_s( + char buffer[], + const size_t buffer_size, + size_t* start, + const char* str, + const char delim +) { + size_t len = 0; + const size_t prev_start = *start; + + const bool retval = next_split(start, &len, &str[*start], delim); + + if (retval) + { + /* Using SDL_strlcpy() here results in calling SDL_strlen() */ + /* on the whole string, which results in a visible freeze */ + /* if it's a very large string */ + const size_t length = VVV_min(buffer_size, len); + SDL_memcpy(buffer, &str[prev_start], length); + buffer[length] = '\0'; + } + + return retval; } UtilityClass::UtilityClass() : diff --git a/desktop_version/src/UtilityClass.h b/desktop_version/src/UtilityClass.h index d93e5a54..26901310 100644 --- a/desktop_version/src/UtilityClass.h +++ b/desktop_version/src/UtilityClass.h @@ -7,9 +7,20 @@ int ss_toi(const std::string& str); -std::vector split(const std::string &s, char delim, std::vector &elems); +bool next_split( + size_t* start, + size_t* len, + const char* str, + const char delim +); -std::vector split(const std::string &s, char delim); +bool next_split_s( + char buffer[], + const size_t buffer_size, + size_t* start, + const char* str, + const char delim +); bool is_number(const char* str); diff --git a/desktop_version/src/editor.cpp b/desktop_version/src/editor.cpp index ec1a9c9a..393fa644 100644 --- a/desktop_version/src/editor.cpp +++ b/desktop_version/src/editor.cpp @@ -1748,21 +1748,29 @@ bool editorclass::load(std::string& _path) if (pKey == "contents" && pText[0] != '\0') { - std::string TextString = (pText); - std::vector values = split(TextString,','); - int x =0; - int y =0; - for(size_t i = 0; i < values.size(); i++) + int x = 0; + int y = 0; + + char buffer[16]; + size_t start = 0; + + while (next_split_s(buffer, sizeof(buffer), &start, pText, ',')) { - contents[x + (maxwidth*40*y)] = help.Int(values[i].c_str()); - x++; - if(x == mapwidth*40) + const int idx = x + maxwidth*40*y; + + if (INBOUNDS_ARR(idx, contents)) { - x=0; - y++; + contents[idx] = help.Int(buffer); } - } + ++x; + + if (x == mapwidth*40) + { + x = 0; + ++y; + } + } } @@ -1865,30 +1873,36 @@ bool editorclass::load(std::string& _path) if (pKey == "script" && pText[0] != '\0') { - std::string TextString = (pText); - std::vector values = split(TextString,'|'); Script script_; bool headerfound = false; - for(size_t i = 0; i < values.size(); i++) - { - std::string& line = values[i]; - if (line.length() && line[line.length() - 1] == ':') + size_t start = 0; + size_t len = 0; + size_t prev_start = 0; + + while (next_split(&start, &len, &pText[start], '|')) + { + if (len > 0 && pText[prev_start + len - 1] == ':') { if (headerfound) { script.customscripts.push_back(script_); } - script_.name = line.substr(0, line.length()-1); + + script_.name = std::string(&pText[prev_start], len - 1); script_.contents.clear(); headerfound = true; - continue; + + goto next; } if (headerfound) { - script_.contents.push_back(line); + script_.contents.push_back(std::string(&pText[prev_start], len)); } + +next: + prev_start = start; } /* Add the last script */