OpenTTD Source 20250529-master-g10c159a79f
string_consumer.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "../stdafx.h"
11#include "string_consumer.hpp"
12
13#include "bitmath_func.hpp"
14#include "utf8.hpp"
15#include "string_builder.hpp"
16
17#include "../string_func.h"
18
19#if defined(STRGEN) || defined(SETTINGSGEN)
20#include "../error_func.h"
21#else
22#include "../debug.h"
23#endif
24
25#include "../safeguards.h"
26
27/* static */ const std::string_view StringConsumer::WHITESPACE_NO_NEWLINE = "\t\v\f\r ";
28/* static */ const std::string_view StringConsumer::WHITESPACE_OR_NEWLINE = "\t\n\v\f\r ";
29
30/* static */ void StringConsumer::LogError(std::string &&msg)
31{
32#if defined(STRGEN) || defined(SETTINGSGEN)
33 FatalErrorI(std::move(msg));
34#else
35 DebugPrint("misc", 0, std::move(msg));
36#endif
37}
38
39std::optional<uint8_t> StringConsumer::PeekUint8() const
40{
41 if (this->GetBytesLeft() < 1) return std::nullopt;
42 return static_cast<uint8_t>(this->src[this->position]);
43}
44
45std::optional<uint16_t> StringConsumer::PeekUint16LE() const
46{
47 if (this->GetBytesLeft() < 2) return std::nullopt;
48 return static_cast<uint8_t>(this->src[this->position]) |
49 static_cast<uint8_t>(this->src[this->position + 1]) << 8;
50}
51
52std::optional<uint32_t> StringConsumer::PeekUint32LE() const
53{
54 if (this->GetBytesLeft() < 4) return std::nullopt;
55 return static_cast<uint8_t>(this->src[this->position]) |
56 static_cast<uint8_t>(this->src[this->position + 1]) << 8 |
57 static_cast<uint8_t>(this->src[this->position + 2]) << 16 |
58 static_cast<uint8_t>(this->src[this->position + 3]) << 24;
59}
60
61std::optional<uint64_t> StringConsumer::PeekUint64LE() const
62{
63 if (this->GetBytesLeft() < 8) return std::nullopt;
64 return static_cast<uint64_t>(static_cast<uint8_t>(this->src[this->position])) |
65 static_cast<uint64_t>(static_cast<uint8_t>(this->src[this->position + 1])) << 8 |
66 static_cast<uint64_t>(static_cast<uint8_t>(this->src[this->position + 2])) << 16 |
67 static_cast<uint64_t>(static_cast<uint8_t>(this->src[this->position + 3])) << 24 |
68 static_cast<uint64_t>(static_cast<uint8_t>(this->src[this->position + 4])) << 32 |
69 static_cast<uint64_t>(static_cast<uint8_t>(this->src[this->position + 5])) << 40 |
70 static_cast<uint64_t>(static_cast<uint8_t>(this->src[this->position + 6])) << 48 |
71 static_cast<uint64_t>(static_cast<uint8_t>(this->src[this->position + 7])) << 56;
72}
73
74std::optional<char> StringConsumer::PeekChar() const
75{
76 auto result = this->PeekUint8();
77 if (!result.has_value()) return {};
78 return static_cast<char>(*result);
79}
80
81std::pair<StringConsumer::size_type, char32_t> StringConsumer::PeekUtf8() const
82{
83 auto buf = this->src.substr(this->position);
84 return DecodeUtf8(buf);
85}
86
87std::string_view StringConsumer::Peek(size_type len) const
88{
89 auto buf = this->src.substr(this->position);
90 if (len == std::string_view::npos) {
91 len = buf.size();
92 } else if (len > buf.size()) {
93 len = buf.size();
94 }
95 return buf.substr(0, len);
96}
97
98void StringConsumer::Skip(size_type len)
99{
100 if (len == std::string_view::npos) {
101 this->position = this->src.size();
102 } else if (size_type max_len = GetBytesLeft(); len > max_len) {
103 LogError(fmt::format("Source buffer too short: {} > {}", len, max_len));
104 this->position = this->src.size();
105 } else {
106 this->position += len;
107 }
108}
109
110StringConsumer::size_type StringConsumer::Find(std::string_view str) const
111{
112 assert(!str.empty());
113 auto buf = this->src.substr(this->position);
114 return buf.find(str);
115}
116
117StringConsumer::size_type StringConsumer::FindUtf8(char32_t c) const
118{
119 auto [data, len] = EncodeUtf8(c);
120 return this->Find({data, len});
121}
122
123StringConsumer::size_type StringConsumer::FindCharIn(std::string_view chars) const
124{
125 assert(!chars.empty());
126 auto buf = this->src.substr(this->position);
127 return buf.find_first_of(chars);
128}
129
130StringConsumer::size_type StringConsumer::FindCharNotIn(std::string_view chars) const
131{
132 assert(!chars.empty());
133 auto buf = this->src.substr(this->position);
134 return buf.find_first_not_of(chars);
135}
136
137std::string_view StringConsumer::PeekUntil(std::string_view str, SeparatorUsage sep) const
138{
139 assert(!str.empty());
140 auto buf = this->src.substr(this->position);
141 auto len = buf.find(str);
142 if (len != std::string_view::npos) {
143 switch (sep) {
145 if (buf.compare(len, str.size(), str) == 0) len += str.size();
146 break;
148 while (buf.compare(len, str.size(), str) == 0) len += str.size();
149 break;
150 default:
151 break;
152 }
153 }
154 return buf.substr(0, len);
155}
156
157std::string_view StringConsumer::PeekUntilUtf8(char32_t c, SeparatorUsage sep) const
158{
159 auto [data, len] = EncodeUtf8(c);
160 return PeekUntil({data, len}, sep);
161}
162
163std::string_view StringConsumer::ReadUntilUtf8(char32_t c, SeparatorUsage sep)
164{
165 auto [data, len] = EncodeUtf8(c);
166 return ReadUntil({data, len}, sep);
167}
168
170{
171 auto [data, len] = EncodeUtf8(c);
172 return SkipUntil({data, len}, sep);
173}
174
176{
177 this->SkipIf("-");
178 if (base == 0) {
179 if (this->ReadIf("0x") || this->ReadIf("0X")) { // boolean short-circuit ensures only one prefix is read
180 base = 16;
181 } else {
182 base = 10;
183 }
184 }
185 switch (base) {
186 default:
187 assert(false);
188 break;
189 case 8:
190 this->SkipUntilCharNotIn("01234567");
191 break;
192 case 10:
193 this->SkipUntilCharNotIn("0123456789");
194 break;
195 case 16:
196 this->SkipUntilCharNotIn("0123456789abcdefABCDEF");
197 break;
198 }
199}
Functions related to bit mathematics.
std::string_view Peek(size_type len) const
Peek the next 'len' bytes.
SeparatorUsage
Treatment of separator characters.
@ READ_ALL_SEPARATORS
Read all consecutive separators, and include them all in the result.
@ READ_ONE_SEPARATOR
Read one separator, and include it in the result.
std::optional< uint32_t > PeekUint32LE() const
Peek binary uint32 using little endian.
size_type GetBytesLeft() const noexcept
Get number of bytes left to read.
std::string_view PeekUntil(std::string_view str, SeparatorUsage sep) const
Peek data until the first occurrence of 'str'.
static const std::string_view WHITESPACE_OR_NEWLINE
ASCII whitespace characters, including new-line.
std::string_view ReadUntil(std::string_view str, SeparatorUsage sep)
Read data until the first occurrence of 'str', and advance reader.
void SkipUntil(std::string_view str, SeparatorUsage sep)
Skip data until the first occurrence of 'str'.
static const std::string_view WHITESPACE_NO_NEWLINE
ASCII whitespace characters, excluding new-line.
std::optional< char > PeekChar() const
Peek 8-bit character.
bool ReadIf(std::string_view str)
Check whether the next data matches 'str', and skip it.
std::string_view PeekUntilUtf8(char32_t c, SeparatorUsage sep) const
Peek data until the first occurrence of UTF-8 char 'c'.
std::optional< uint64_t > PeekUint64LE() const
Peek binary uint64 using little endian.
void SkipUntilCharNotIn(std::string_view chars)
Skip 8-bit chars, while they are in 'chars', until they are not.
size_type FindCharNotIn(std::string_view chars) const
Find first occurence of any 8-bit char not in 'chars'.
void SkipIf(std::string_view str)
If the next data matches 'str', then skip it.
std::optional< uint16_t > PeekUint16LE() const
Peek binary uint16 using little endian.
void SkipIntegerBase(int base)
Skip an integer in number 'base'.
void Skip(size_type len)
Discard some bytes.
size_type Find(std::string_view str) const
Find first occurence of 'str'.
std::optional< uint8_t > PeekUint8() const
Peek binary uint8.
void SkipUntilUtf8(char32_t c, SeparatorUsage sep)
Skip data until the first occurrence of UTF-8 char 'c'.
std::string_view ReadUntilUtf8(char32_t c, SeparatorUsage sep)
Read data until the first occurrence of UTF-8 char 'c', and advance reader.
std::pair< size_type, char32_t > PeekUtf8() const
Peek UTF-8 character.
size_type FindCharIn(std::string_view chars) const
Find first occurence of any 8-bit char in 'chars'.
size_type FindUtf8(char32_t c) const
Find first occurence of UTF-8 char 'c'.
std::pair< size_t, char32_t > DecodeUtf8(std::string_view buf)
Decode a character from UTF-8.
Definition utf8.cpp:48
std::pair< char[4], size_t > EncodeUtf8(char32_t c)
Encode a character to UTF-8.
Definition utf8.cpp:21
void DebugPrint(std::string_view category, int level, std::string &&message)
Internal function for outputting the debug line.
Definition debug.cpp:110
void FatalErrorI(const std::string &str)
Error handling for fatal non-user errors.
Definition openttd.cpp:140
Compose strings from textual and binary data.
Parse strings.
Handling of UTF-8 encoded data.