mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Use StringConsumer for parsing more strings.
parent
e7d758c82a
commit
79b2202f2e
|
@ -12,6 +12,7 @@
|
||||||
#include "base_media_func.h"
|
#include "base_media_func.h"
|
||||||
#include "base_media_music.h"
|
#include "base_media_music.h"
|
||||||
#include "random_access_file_type.h"
|
#include "random_access_file_type.h"
|
||||||
|
#include "core/string_consumer.hpp"
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
|
@ -176,10 +177,13 @@ bool MusicSet::FillSetDetails(const IniFile &ini, const std::string &path, const
|
||||||
|
|
||||||
item = trimmed_filename != nullptr && timingtrim != nullptr ? timingtrim->GetItem(trimmed_filename) : nullptr;
|
item = trimmed_filename != nullptr && timingtrim != nullptr ? timingtrim->GetItem(trimmed_filename) : nullptr;
|
||||||
if (item != nullptr && item->value.has_value() && !item->value->empty()) {
|
if (item != nullptr && item->value.has_value() && !item->value->empty()) {
|
||||||
auto endpos = item->value->find(':');
|
StringConsumer consumer{*item->value};
|
||||||
if (endpos != std::string::npos) {
|
auto start = consumer.TryReadIntegerBase<uint>(10);
|
||||||
this->songinfo[i].override_start = atoi(item->value->c_str());
|
auto valid = consumer.ReadIf(":");
|
||||||
this->songinfo[i].override_end = atoi(item->value->c_str() + endpos + 1);
|
auto end = consumer.TryReadIntegerBase<uint>(10);
|
||||||
|
if (start.has_value() && valid && end.has_value() && !consumer.AnyBytesLeft()) {
|
||||||
|
this->songinfo[i].override_start = *start;
|
||||||
|
this->songinfo[i].override_end = *end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "../strings_func.h"
|
#include "../strings_func.h"
|
||||||
#include "../timer/timer.h"
|
#include "../timer/timer.h"
|
||||||
#include "../timer/timer_window.h"
|
#include "../timer/timer_window.h"
|
||||||
|
#include "../core/string_consumer.hpp"
|
||||||
#include "network_content.h"
|
#include "network_content.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
@ -628,78 +629,66 @@ void ClientNetworkContentSocketHandler::OnReceiveData(std::unique_ptr<char[]> da
|
||||||
/* When we haven't opened a file this must be our first packet with metadata. */
|
/* When we haven't opened a file this must be our first packet with metadata. */
|
||||||
this->cur_info = std::make_unique<ContentInfo>();
|
this->cur_info = std::make_unique<ContentInfo>();
|
||||||
|
|
||||||
/** Check p for not being null and return calling OnFailure if that's not the case. */
|
try {
|
||||||
#define check_not_null(p) { if ((p) == nullptr) { this->OnFailure(); return; } }
|
for (;;) {
|
||||||
/** Check p for not being null and then terminate, or return calling OnFailure. */
|
std::string_view buffer{this->http_response.data(), this->http_response.size()};
|
||||||
#define check_and_terminate(p) { check_not_null(p); *(p) = '\0'; }
|
buffer.remove_prefix(this->http_response_index);
|
||||||
|
auto len = buffer.find('\n');
|
||||||
|
if (len == std::string_view::npos) throw std::exception{};
|
||||||
|
/* Update the index for the next one */
|
||||||
|
this->http_response_index += static_cast<int>(len + 1);
|
||||||
|
|
||||||
for (;;) {
|
StringConsumer consumer{buffer.substr(0, len)};
|
||||||
char *str = this->http_response.data() + this->http_response_index;
|
|
||||||
char *p = strchr(str, '\n');
|
|
||||||
check_and_terminate(p);
|
|
||||||
|
|
||||||
/* Update the index for the next one */
|
/* Read the ID */
|
||||||
this->http_response_index += (int)strlen(str) + 1;
|
this->cur_info->id = static_cast<ContentID>(consumer.ReadIntegerBase<uint>(10));
|
||||||
|
if (!consumer.ReadIf(",")) throw std::exception{};
|
||||||
|
|
||||||
/* Read the ID */
|
/* Read the type */
|
||||||
p = strchr(str, ',');
|
this->cur_info->type = static_cast<ContentType>(consumer.ReadIntegerBase<uint>(10));
|
||||||
check_and_terminate(p);
|
if (!consumer.ReadIf(",")) throw std::exception{};
|
||||||
this->cur_info->id = (ContentID)atoi(str);
|
|
||||||
|
|
||||||
/* Read the type */
|
/* Read the file size */
|
||||||
str = p + 1;
|
this->cur_info->filesize = consumer.ReadIntegerBase<uint32_t>(10);
|
||||||
p = strchr(str, ',');
|
if (!consumer.ReadIf(",")) throw std::exception{};
|
||||||
check_and_terminate(p);
|
|
||||||
this->cur_info->type = (ContentType)atoi(str);
|
|
||||||
|
|
||||||
/* Read the file size */
|
/* Read the URL */
|
||||||
str = p + 1;
|
auto url = consumer.GetLeftData();
|
||||||
p = strchr(str, ',');
|
|
||||||
check_and_terminate(p);
|
|
||||||
this->cur_info->filesize = atoi(str);
|
|
||||||
|
|
||||||
/* Read the URL */
|
/* Is it a fallback URL? If so, just continue with the next one. */
|
||||||
str = p + 1;
|
if (consumer.ReadIf("ottd")) {
|
||||||
/* Is it a fallback URL? If so, just continue with the next one. */
|
|
||||||
if (strncmp(str, "ottd", 4) == 0) {
|
|
||||||
if ((uint)this->http_response_index >= this->http_response.size()) {
|
|
||||||
/* Have we gone through all lines? */
|
/* Have we gone through all lines? */
|
||||||
this->OnFailure();
|
if (static_cast<size_t>(this->http_response_index) >= this->http_response.size()) throw std::exception{};
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = strrchr(str, '/');
|
consumer.SkipUntilChar('/', StringConsumer::KEEP_SEPARATOR);
|
||||||
check_not_null(p);
|
std::string_view filename;
|
||||||
p++; // Start after the '/'
|
/* Skip all but the last part. There must be at least one / though */
|
||||||
|
do {
|
||||||
|
if (!consumer.ReadIf("/")) throw std::exception{};
|
||||||
|
filename = consumer.ReadUntilChar('/', StringConsumer::KEEP_SEPARATOR);
|
||||||
|
} while (consumer.AnyBytesLeft());
|
||||||
|
|
||||||
std::string filename = p;
|
/* Remove the extension from the string. */
|
||||||
/* Remove the extension from the string. */
|
for (uint i = 0; i < 2; i++) {
|
||||||
for (uint i = 0; i < 2; i++) {
|
auto pos = filename.find_last_of('.');
|
||||||
auto pos = filename.find_last_of('.');
|
if (pos == std::string::npos) throw std::exception{};
|
||||||
if (pos == std::string::npos) {
|
filename = filename.substr(0, pos);
|
||||||
this->OnFailure();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
filename.erase(pos);
|
|
||||||
|
/* Copy the string, without extension, to the filename. */
|
||||||
|
this->cur_info->filename = filename;
|
||||||
|
|
||||||
|
/* Request the next file. */
|
||||||
|
if (!this->BeforeDownload()) throw std::exception{};
|
||||||
|
|
||||||
|
NetworkHTTPSocketHandler::Connect(url, this);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
} catch (const std::exception&) {
|
||||||
/* Copy the string, without extension, to the filename. */
|
this->OnFailure();
|
||||||
this->cur_info->filename = std::move(filename);
|
|
||||||
|
|
||||||
/* Request the next file. */
|
|
||||||
if (!this->BeforeDownload()) {
|
|
||||||
this->OnFailure();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetworkHTTPSocketHandler::Connect(str, this);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef check
|
|
||||||
#undef check_and_terminate
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Connect to the content server. */
|
/** Connect to the content server. */
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
#include "timer/timer_game_realtime.h"
|
#include "timer/timer_game_realtime.h"
|
||||||
#include "timer/timer_game_tick.h"
|
#include "timer/timer_game_tick.h"
|
||||||
#include "social_integration.h"
|
#include "social_integration.h"
|
||||||
|
#include "core/string_consumer.hpp"
|
||||||
|
|
||||||
#include "linkgraph/linkgraphschedule.h"
|
#include "linkgraph/linkgraphschedule.h"
|
||||||
|
|
||||||
|
@ -272,14 +273,17 @@ static void WriteSavegameInfo(const std::string &name)
|
||||||
*/
|
*/
|
||||||
static void ParseResolution(Dimension *res, const char *s)
|
static void ParseResolution(Dimension *res, const char *s)
|
||||||
{
|
{
|
||||||
const char *t = strchr(s, 'x');
|
StringConsumer consumer(std::string_view{s});
|
||||||
if (t == nullptr) {
|
auto width = consumer.TryReadIntegerBase<uint>(10);
|
||||||
|
auto valid = consumer.ReadIf("x");
|
||||||
|
auto height = consumer.TryReadIntegerBase<uint>(10);
|
||||||
|
if (!width.has_value() || !valid || !height.has_value() || consumer.AnyBytesLeft()) {
|
||||||
ShowInfo("Invalid resolution '{}'", s);
|
ShowInfo("Invalid resolution '{}'", s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
res->width = std::max(std::strtoul(s, nullptr, 0), 64UL);
|
res->width = std::max<uint>(*width, 64);
|
||||||
res->height = std::max(std::strtoul(t + 1, nullptr, 0), 64UL);
|
res->height = std::max<uint>(*height, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -248,29 +248,19 @@ static std::optional<std::vector<uint32_t>> ParseIntList(const char *p)
|
||||||
bool comma = false; // do we accept comma?
|
bool comma = false; // do we accept comma?
|
||||||
std::vector<uint32_t> result;
|
std::vector<uint32_t> result;
|
||||||
|
|
||||||
while (*p != '\0') {
|
StringConsumer consumer{std::string_view{p}};
|
||||||
switch (*p) {
|
for (;;) {
|
||||||
case ',':
|
consumer.SkipUntilCharNotIn(StringConsumer::WHITESPACE_NO_NEWLINE);
|
||||||
/* Do not accept multiple commas between numbers */
|
if (!consumer.AnyBytesLeft()) break;
|
||||||
if (!comma) return std::nullopt;
|
if (comma && consumer.ReadIf(",")) {
|
||||||
comma = false;
|
/* commas are optional, but we only accept one between values */
|
||||||
[[fallthrough]];
|
comma = false;
|
||||||
|
continue;
|
||||||
case ' ':
|
|
||||||
p++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: {
|
|
||||||
char *end;
|
|
||||||
unsigned long v = std::strtoul(p, &end, 0);
|
|
||||||
if (p == end) return std::nullopt; // invalid character (not a number)
|
|
||||||
|
|
||||||
result.push_back(ClampTo<uint32_t>(v));
|
|
||||||
p = end; // first non-number
|
|
||||||
comma = true; // we accept comma now
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
auto v = consumer.TryReadIntegerBase<uint32_t>(10);
|
||||||
|
if (!v.has_value()) return std::nullopt;
|
||||||
|
result.push_back(*v);
|
||||||
|
comma = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have read comma but no number after it, fail.
|
/* If we have read comma but no number after it, fail.
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
#include "../blitter/factory.hpp"
|
#include "../blitter/factory.hpp"
|
||||||
#include "../zoom_func.h"
|
#include "../zoom_func.h"
|
||||||
|
#include "../core/string_consumer.hpp"
|
||||||
|
|
||||||
#include "../table/opengl_shader.h"
|
#include "../table/opengl_shader.h"
|
||||||
#include "../table/sprites.h"
|
#include "../table/sprites.h"
|
||||||
|
@ -539,9 +540,13 @@ std::optional<std::string_view> OpenGLBackend::Init(const Dimension &screen_res)
|
||||||
if (strncmp(renderer, "llvmpipe", 8) == 0 || strncmp(renderer, "softpipe", 8) == 0) return "Software renderer detected, not using OpenGL";
|
if (strncmp(renderer, "llvmpipe", 8) == 0 || strncmp(renderer, "softpipe", 8) == 0) return "Software renderer detected, not using OpenGL";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char *minor = strchr(ver, '.');
|
StringConsumer consumer{std::string_view{ver}};
|
||||||
_gl_major_ver = atoi(ver);
|
_gl_major_ver = consumer.ReadIntegerBase<uint8_t>(10);
|
||||||
_gl_minor_ver = minor != nullptr ? atoi(minor + 1) : 0;
|
if (consumer.ReadIf(".")) {
|
||||||
|
_gl_minor_ver = consumer.ReadIntegerBase<uint8_t>(10);
|
||||||
|
} else {
|
||||||
|
_gl_minor_ver = 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/* Old drivers on Windows (especially if made by Intel) seem to be
|
/* Old drivers on Windows (especially if made by Intel) seem to be
|
||||||
|
|
Loading…
Reference in New Issue