mirror of https://github.com/OpenRCT2/OpenRCT2.git
262 lines
8.1 KiB
C++
262 lines
8.1 KiB
C++
/*****************************************************************************
|
|
* Copyright (c) 2014-2020 OpenRCT2 developers
|
|
*
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
|
*
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
|
*****************************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include "../common.h"
|
|
|
|
#include <cstdarg>
|
|
#include <cstddef>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
namespace CODE_PAGE
|
|
{
|
|
// windows.h defines CP_UTF8
|
|
#undef CP_UTF8
|
|
|
|
constexpr int32_t CP_932 = 932; // ANSI/OEM Japanese; Japanese (Shift-JIS)
|
|
constexpr int32_t CP_936 = 936; // ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
|
|
constexpr int32_t CP_949 = 949; // ANSI/OEM Korean (Unified Hangul Code)
|
|
constexpr int32_t CP_950 = 950; // ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
|
|
constexpr int32_t CP_1252 = 1252; // ANSI Latin 1; Western European (Windows)
|
|
constexpr int32_t CP_UTF8 = 65001; // Unicode (UTF-8)
|
|
} // namespace CODE_PAGE
|
|
|
|
namespace String
|
|
{
|
|
constexpr const utf8* Empty = "";
|
|
|
|
std::string ToStd(const utf8* str);
|
|
std::string StdFormat_VA(const utf8* format, va_list args);
|
|
std::string StdFormat(const utf8* format, ...);
|
|
std::string ToUtf8(std::wstring_view src);
|
|
std::wstring ToWideChar(std::string_view src);
|
|
|
|
/**
|
|
* Creates a string_view from a char pointer with a length up to either the
|
|
* first null terminator or a given maximum length, whatever is smallest.
|
|
*/
|
|
std::string_view ToStringView(const char* ch, size_t maxLen);
|
|
|
|
bool IsNullOrEmpty(const utf8* str);
|
|
int32_t Compare(const std::string& a, const std::string& b, bool ignoreCase = false);
|
|
int32_t Compare(const utf8* a, const utf8* b, bool ignoreCase = false);
|
|
bool Equals(std::string_view a, std::string_view b, bool ignoreCase = false);
|
|
bool Equals(const std::string& a, const std::string& b, bool ignoreCase = false);
|
|
bool Equals(const utf8* a, const utf8* b, bool ignoreCase = false);
|
|
bool StartsWith(std::string_view str, std::string_view match, bool ignoreCase = false);
|
|
bool EndsWith(std::string_view str, std::string_view match, bool ignoreCase = false);
|
|
size_t IndexOf(const utf8* str, utf8 match, size_t startIndex = 0);
|
|
ptrdiff_t LastIndexOf(const utf8* str, utf8 match);
|
|
|
|
/**
|
|
* Gets the length of the given string in codepoints.
|
|
*/
|
|
size_t LengthOf(const utf8* str);
|
|
|
|
/**
|
|
* Gets the size of the given string in bytes excluding the null terminator.
|
|
*/
|
|
size_t SizeOf(const utf8* str);
|
|
|
|
utf8* Set(utf8* buffer, size_t bufferSize, const utf8* src);
|
|
utf8* Set(utf8* buffer, size_t bufferSize, const utf8* src, size_t srcSize);
|
|
utf8* Append(utf8* buffer, size_t bufferSize, const utf8* src);
|
|
utf8* Format(utf8* buffer, size_t bufferSize, const utf8* format, ...);
|
|
utf8* Format(const utf8* format, ...);
|
|
utf8* Format_VA(const utf8* format, va_list args);
|
|
utf8* AppendFormat(utf8* buffer, size_t bufferSize, const utf8* format, ...);
|
|
utf8* Duplicate(const std::string& src);
|
|
utf8* Duplicate(const utf8* src);
|
|
|
|
/**
|
|
* Helper method to free the string a string pointer points to and set it to a replacement string.
|
|
*/
|
|
utf8* DiscardUse(utf8** ptr, utf8* replacement);
|
|
|
|
/**
|
|
* Helper method to free the string a string pointer points to and set it to a copy of a replacement string.
|
|
*/
|
|
utf8* DiscardDuplicate(utf8** ptr, const utf8* replacement);
|
|
|
|
/**
|
|
* Splits the given string by a delimiter and returns the values as a new string array.
|
|
* @returns the number of values.
|
|
*/
|
|
std::vector<std::string> Split(std::string_view s, std::string_view delimiter);
|
|
|
|
utf8* SkipBOM(utf8* buffer);
|
|
const utf8* SkipBOM(const utf8* buffer);
|
|
|
|
size_t GetCodepointLength(codepoint_t codepoint);
|
|
codepoint_t GetNextCodepoint(utf8* ptr, utf8** nextPtr = nullptr);
|
|
codepoint_t GetNextCodepoint(const utf8* ptr, const utf8** nextPtr = nullptr);
|
|
utf8* WriteCodepoint(utf8* dst, codepoint_t codepoint);
|
|
void AppendCodepoint(std::string& str, codepoint_t codepoint);
|
|
|
|
bool IsWhiteSpace(codepoint_t codepoint);
|
|
utf8* Trim(utf8* str);
|
|
const utf8* TrimStart(const utf8* str);
|
|
utf8* TrimStart(utf8* buffer, size_t bufferSize, const utf8* src);
|
|
std::string TrimStart(const std::string& s);
|
|
std::string Trim(const std::string& s);
|
|
|
|
/**
|
|
* Converts a multi-byte string from one code page to another.
|
|
*/
|
|
std::string Convert(std::string_view src, int32_t srcCodePage, int32_t dstCodePage);
|
|
|
|
/**
|
|
* Returns an uppercased version of a UTF-8 string.
|
|
*/
|
|
std::string ToUpper(std::string_view src);
|
|
|
|
template<typename T> std::optional<T> Parse(std::string_view input)
|
|
{
|
|
if (input.size() == 0)
|
|
return std::nullopt;
|
|
|
|
T result = 0;
|
|
for (size_t i = 0; i < input.size(); i++)
|
|
{
|
|
auto chr = input[i];
|
|
if (chr >= '0' && chr <= '9')
|
|
{
|
|
auto digit = chr - '0';
|
|
auto last = result;
|
|
result = static_cast<T>((result * 10) + digit);
|
|
if (result <= last)
|
|
{
|
|
// Overflow, number too large for type
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Bad character
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns codepoint size or no value if not valid
|
|
*/
|
|
constexpr std::optional<int> UTF8GetCodePointSize(std::string_view v)
|
|
{
|
|
if (v.size() >= 1 && !(v[0] & 0x80))
|
|
{
|
|
return { 1 };
|
|
}
|
|
if (v.size() >= 2 && ((v[0] & 0xE0) == 0xC0))
|
|
{
|
|
return { 2 };
|
|
}
|
|
if (v.size() >= 3 && ((v[0] & 0xF0) == 0xE0))
|
|
{
|
|
return { 3 };
|
|
}
|
|
if (v.size() >= 4 && ((v[0] & 0xF8) == 0xF0))
|
|
{
|
|
return { 4 };
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* Truncates a string to at most `size` bytes,
|
|
* making sure not to cut in the middle of a sequence.
|
|
*/
|
|
std::string_view UTF8Truncate(std::string_view v, size_t size);
|
|
|
|
// Escapes special characters in a string to the percentage equivalent that can be used in URLs.
|
|
std::string URLEncode(std::string_view value);
|
|
} // namespace String
|
|
|
|
class CodepointView
|
|
{
|
|
private:
|
|
std::string_view _str;
|
|
|
|
public:
|
|
class iterator
|
|
{
|
|
private:
|
|
std::string_view _str;
|
|
size_t _index;
|
|
|
|
public:
|
|
iterator(std::string_view str, size_t index)
|
|
: _str(str)
|
|
, _index(index)
|
|
{
|
|
}
|
|
|
|
bool operator==(const iterator& rhs) const
|
|
{
|
|
return _index == rhs._index;
|
|
}
|
|
bool operator!=(const iterator& rhs) const
|
|
{
|
|
return _index != rhs._index;
|
|
}
|
|
char32_t operator*() const
|
|
{
|
|
return GetNextCodepoint(&_str[_index], nullptr);
|
|
}
|
|
iterator& operator++()
|
|
{
|
|
if (_index < _str.size())
|
|
{
|
|
const utf8* nextch;
|
|
GetNextCodepoint(&_str[_index], &nextch);
|
|
_index = nextch - _str.data();
|
|
}
|
|
return *this;
|
|
}
|
|
iterator operator++(int)
|
|
{
|
|
auto result = *this;
|
|
if (_index < _str.size())
|
|
{
|
|
const utf8* nextch;
|
|
GetNextCodepoint(&_str[_index], &nextch);
|
|
_index = nextch - _str.data();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
size_t GetIndex() const
|
|
{
|
|
return _index;
|
|
}
|
|
|
|
static char32_t GetNextCodepoint(const char* ch, const char** next);
|
|
};
|
|
|
|
CodepointView(std::string_view str)
|
|
: _str(str)
|
|
{
|
|
}
|
|
|
|
iterator begin() const
|
|
{
|
|
return iterator(_str, 0);
|
|
}
|
|
|
|
iterator end() const
|
|
{
|
|
return iterator(_str, _str.size());
|
|
}
|
|
};
|