summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/Optional.h77
-rw-r--r--src/util/base64.cpp5
-rw-r--r--src/util/md32_common.h2
-rw-r--r--src/util/serialize.cpp412
-rw-r--r--src/util/serialize.h252
-rw-r--r--src/util/sha256.c6
-rw-r--r--src/util/srp.cpp4
-rw-r--r--src/util/string.cpp186
-rw-r--r--src/util/string.h42
9 files changed, 205 insertions, 781 deletions
diff --git a/src/util/Optional.h b/src/util/Optional.h
new file mode 100644
index 000000000..9c2842b43
--- /dev/null
+++ b/src/util/Optional.h
@@ -0,0 +1,77 @@
+/*
+Minetest
+Copyright (C) 2021 rubenwardy
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program 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. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#pragma once
+
+#include "debug.h"
+
+struct nullopt_t
+{
+};
+constexpr nullopt_t nullopt{};
+
+/**
+ * An implementation of optional for C++11, which aims to be
+ * compatible with a subset of std::optional features.
+ *
+ * Unfortunately, Minetest doesn't use C++17 yet.
+ *
+ * @tparam T The type to be stored
+ */
+template <typename T>
+class Optional
+{
+ bool m_has_value = false;
+ T m_value;
+
+public:
+ Optional() noexcept {}
+ Optional(nullopt_t) noexcept {}
+ Optional(const T &value) noexcept : m_has_value(true), m_value(value) {}
+ Optional(const Optional<T> &other) noexcept :
+ m_has_value(other.m_has_value), m_value(other.m_value)
+ {
+ }
+
+ void operator=(nullopt_t) noexcept { m_has_value = false; }
+
+ void operator=(const Optional<T> &other) noexcept
+ {
+ m_has_value = other.m_has_value;
+ m_value = other.m_value;
+ }
+
+ T &value()
+ {
+ FATAL_ERROR_IF(!m_has_value, "optional doesn't have value");
+ return m_value;
+ }
+
+ const T &value() const
+ {
+ FATAL_ERROR_IF(!m_has_value, "optional doesn't have value");
+ return m_value;
+ }
+
+ const T &value_or(const T &def) const { return m_has_value ? m_value : def; }
+
+ bool has_value() const noexcept { return m_has_value; }
+
+ explicit operator bool() const { return m_has_value; }
+};
diff --git a/src/util/base64.cpp b/src/util/base64.cpp
index c75f98598..6e1584410 100644
--- a/src/util/base64.cpp
+++ b/src/util/base64.cpp
@@ -34,8 +34,9 @@ static const std::string base64_chars =
"0123456789+/";
-static inline bool is_base64(unsigned char c) {
- return (isalnum(c) || (c == '+') || (c == '/'));
+static inline bool is_base64(unsigned char c)
+{
+ return isalnum(c) || c == '+' || c == '/' || c == '=';
}
bool base64_is_valid(std::string const& s)
diff --git a/src/util/md32_common.h b/src/util/md32_common.h
index a4c2099c9..2c050b72a 100644
--- a/src/util/md32_common.h
+++ b/src/util/md32_common.h
@@ -301,7 +301,7 @@
int HASH_UPDATE(HASH_CTX *c, const void *data_, size_t len)
{
- const unsigned char *data = data_;
+ const unsigned char *data = (const unsigned char *)data_;
unsigned char *p;
HASH_LONG l;
size_t n;
diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp
index 5b276668d..d770101f2 100644
--- a/src/util/serialize.cpp
+++ b/src/util/serialize.cpp
@@ -30,86 +30,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
FloatType g_serialize_f32_type = FLOATTYPE_UNKNOWN;
-////
-//// BufReader
-////
-
-bool BufReader::getStringNoEx(std::string *val)
-{
- u16 num_chars;
- if (!getU16NoEx(&num_chars))
- return false;
-
- if (pos + num_chars > size) {
- pos -= sizeof(num_chars);
- return false;
- }
-
- val->assign((const char *)data + pos, num_chars);
- pos += num_chars;
-
- return true;
-}
-
-bool BufReader::getWideStringNoEx(std::wstring *val)
-{
- u16 num_chars;
- if (!getU16NoEx(&num_chars))
- return false;
-
- if (pos + num_chars * 2 > size) {
- pos -= sizeof(num_chars);
- return false;
- }
-
- for (size_t i = 0; i != num_chars; i++) {
- val->push_back(readU16(data + pos));
- pos += 2;
- }
-
- return true;
-}
-
-bool BufReader::getLongStringNoEx(std::string *val)
-{
- u32 num_chars;
- if (!getU32NoEx(&num_chars))
- return false;
-
- if (pos + num_chars > size) {
- pos -= sizeof(num_chars);
- return false;
- }
-
- val->assign((const char *)data + pos, num_chars);
- pos += num_chars;
-
- return true;
-}
-
-bool BufReader::getRawDataNoEx(void *val, size_t len)
-{
- if (pos + len > size)
- return false;
-
- memcpy(val, data + pos, len);
- pos += len;
-
- return true;
-}
-
////
//// String
////
-std::string serializeString(const std::string &plain)
+std::string serializeString16(const std::string &plain)
{
std::string s;
char buf[2];
if (plain.size() > STRING_MAX_LEN)
- throw SerializationError("String too long for serializeString");
+ throw SerializationError("String too long for serializeString16");
s.reserve(2 + plain.size());
writeU16((u8 *)&buf[0], plain.size());
@@ -119,14 +51,14 @@ std::string serializeString(const std::string &plain)
return s;
}
-std::string deSerializeString(std::istream &is)
+std::string deSerializeString16(std::istream &is)
{
std::string s;
char buf[2];
is.read(buf, 2);
if (is.gcount() != 2)
- throw SerializationError("deSerializeString: size not read");
+ throw SerializationError("deSerializeString16: size not read");
u16 s_size = readU16((u8 *)buf);
if (s_size == 0)
@@ -135,66 +67,17 @@ std::string deSerializeString(std::istream &is)
s.resize(s_size);
is.read(&s[0], s_size);
if (is.gcount() != s_size)
- throw SerializationError("deSerializeString: couldn't read all chars");
+ throw SerializationError("deSerializeString16: couldn't read all chars");
return s;
}
-////
-//// Wide String
-////
-
-std::string serializeWideString(const std::wstring &plain)
-{
- std::string s;
- char buf[2];
-
- if (plain.size() > WIDE_STRING_MAX_LEN)
- throw SerializationError("String too long for serializeWideString");
- s.reserve(2 + 2 * plain.size());
-
- writeU16((u8 *)buf, plain.size());
- s.append(buf, 2);
-
- for (wchar_t i : plain) {
- writeU16((u8 *)buf, i);
- s.append(buf, 2);
- }
- return s;
-}
-
-std::wstring deSerializeWideString(std::istream &is)
-{
- std::wstring s;
- char buf[2];
-
- is.read(buf, 2);
- if (is.gcount() != 2)
- throw SerializationError("deSerializeWideString: size not read");
-
- u16 s_size = readU16((u8 *)buf);
- if (s_size == 0)
- return s;
-
- s.reserve(s_size);
- for (u32 i = 0; i < s_size; i++) {
- is.read(&buf[0], 2);
- if (is.gcount() != 2) {
- throw SerializationError(
- "deSerializeWideString: couldn't read all chars");
- }
-
- wchar_t c16 = readU16((u8 *)buf);
- s.append(&c16, 1);
- }
- return s;
-}
////
//// Long String
////
-std::string serializeLongString(const std::string &plain)
+std::string serializeString32(const std::string &plain)
{
std::string s;
char buf[4];
@@ -209,7 +92,7 @@ std::string serializeLongString(const std::string &plain)
return s;
}
-std::string deSerializeLongString(std::istream &is)
+std::string deSerializeString32(std::istream &is)
{
std::string s;
char buf[4];
@@ -404,284 +287,3 @@ std::string deSerializeJsonStringIfNeeded(std::istream &is)
return tmp_os.str();
}
-////
-//// String/Struct conversions
-////
-
-bool deSerializeStringToStruct(std::string valstr,
- std::string format, void *out, size_t olen)
-{
- size_t len = olen;
- std::vector<std::string *> strs_alloced;
- std::string *str;
- char *f, *snext;
- size_t pos;
-
- char *s = &valstr[0];
- char *buf = new char[len];
- char *bufpos = buf;
-
- char *fmtpos, *fmt = &format[0];
- while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
- fmt = nullptr;
-
- bool is_unsigned = false;
- int width = 0;
- char valtype = *f;
-
- width = (int)strtol(f + 1, &f, 10);
- if (width && valtype == 's')
- valtype = 'i';
-
- switch (valtype) {
- case 'u':
- is_unsigned = true;
- /* FALLTHROUGH */
- case 'i':
- if (width == 16) {
- bufpos += PADDING(bufpos, u16);
- if ((bufpos - buf) + sizeof(u16) <= len) {
- if (is_unsigned)
- *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
- else
- *(s16 *)bufpos = (s16)strtol(s, &s, 10);
- }
- bufpos += sizeof(u16);
- } else if (width == 32) {
- bufpos += PADDING(bufpos, u32);
- if ((bufpos - buf) + sizeof(u32) <= len) {
- if (is_unsigned)
- *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
- else
- *(s32 *)bufpos = (s32)strtol(s, &s, 10);
- }
- bufpos += sizeof(u32);
- } else if (width == 64) {
- bufpos += PADDING(bufpos, u64);
- if ((bufpos - buf) + sizeof(u64) <= len) {
- if (is_unsigned)
- *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
- else
- *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
- }
- bufpos += sizeof(u64);
- }
- s = strchr(s, ',');
- break;
- case 'b':
- snext = strchr(s, ',');
- if (snext)
- *snext++ = 0;
-
- bufpos += PADDING(bufpos, bool);
- if ((bufpos - buf) + sizeof(bool) <= len)
- *(bool *)bufpos = is_yes(std::string(s));
- bufpos += sizeof(bool);
-
- s = snext;
- break;
- case 'f':
- bufpos += PADDING(bufpos, float);
- if ((bufpos - buf) + sizeof(float) <= len)
- *(float *)bufpos = strtof(s, &s);
- bufpos += sizeof(float);
-
- s = strchr(s, ',');
- break;
- case 's':
- while (*s == ' ' || *s == '\t')
- s++;
- if (*s++ != '"') //error, expected string
- goto fail;
- snext = s;
-
- while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
- snext++;
- *snext++ = 0;
-
- bufpos += PADDING(bufpos, std::string *);
-
- str = new std::string(s);
- pos = 0;
- while ((pos = str->find("\\\"", pos)) != std::string::npos)
- str->erase(pos, 1);
-
- if ((bufpos - buf) + sizeof(std::string *) <= len)
- *(std::string **)bufpos = str;
- bufpos += sizeof(std::string *);
- strs_alloced.push_back(str);
-
- s = *snext ? snext + 1 : nullptr;
- break;
- case 'v':
- while (*s == ' ' || *s == '\t')
- s++;
- if (*s++ != '(') //error, expected vector
- goto fail;
-
- if (width == 2) {
- bufpos += PADDING(bufpos, v2f);
-
- if ((bufpos - buf) + sizeof(v2f) <= len) {
- v2f *v = (v2f *)bufpos;
- v->X = strtof(s, &s);
- s++;
- v->Y = strtof(s, &s);
- }
-
- bufpos += sizeof(v2f);
- } else if (width == 3) {
- bufpos += PADDING(bufpos, v3f);
- if ((bufpos - buf) + sizeof(v3f) <= len) {
- v3f *v = (v3f *)bufpos;
- v->X = strtof(s, &s);
- s++;
- v->Y = strtof(s, &s);
- s++;
- v->Z = strtof(s, &s);
- }
-
- bufpos += sizeof(v3f);
- }
- s = strchr(s, ',');
- break;
- default: //error, invalid format specifier
- goto fail;
- }
-
- if (s && *s == ',')
- s++;
-
- if ((size_t)(bufpos - buf) > len) //error, buffer too small
- goto fail;
- }
-
- if (f && *f) { //error, mismatched number of fields and values
-fail:
- for (size_t i = 0; i != strs_alloced.size(); i++)
- delete strs_alloced[i];
- delete[] buf;
- return false;
- }
-
- memcpy(out, buf, olen);
- delete[] buf;
- return true;
-}
-
-// Casts *buf to a signed or unsigned fixed-width integer of 'w' width
-#define SIGN_CAST(w, buf) (is_unsigned ? *((u##w *) buf) : *((s##w *) buf))
-
-bool serializeStructToString(std::string *out,
- std::string format, void *value)
-{
- std::ostringstream os;
- std::string str;
- char *f;
- size_t strpos;
-
- char *bufpos = (char *) value;
- char *fmtpos, *fmt = &format[0];
- while ((f = strtok_r(fmt, ",", &fmtpos))) {
- fmt = nullptr;
- bool is_unsigned = false;
- int width = 0;
- char valtype = *f;
-
- width = (int)strtol(f + 1, &f, 10);
- if (width && valtype == 's')
- valtype = 'i';
-
- switch (valtype) {
- case 'u':
- is_unsigned = true;
- /* FALLTHROUGH */
- case 'i':
- if (width == 16) {
- bufpos += PADDING(bufpos, u16);
- os << SIGN_CAST(16, bufpos);
- bufpos += sizeof(u16);
- } else if (width == 32) {
- bufpos += PADDING(bufpos, u32);
- os << SIGN_CAST(32, bufpos);
- bufpos += sizeof(u32);
- } else if (width == 64) {
- bufpos += PADDING(bufpos, u64);
- os << SIGN_CAST(64, bufpos);
- bufpos += sizeof(u64);
- }
- break;
- case 'b':
- bufpos += PADDING(bufpos, bool);
- os << std::boolalpha << *((bool *) bufpos);
- bufpos += sizeof(bool);
- break;
- case 'f':
- bufpos += PADDING(bufpos, float);
- os << *((float *) bufpos);
- bufpos += sizeof(float);
- break;
- case 's':
- bufpos += PADDING(bufpos, std::string *);
- str = **((std::string **) bufpos);
-
- strpos = 0;
- while ((strpos = str.find('"', strpos)) != std::string::npos) {
- str.insert(strpos, 1, '\\');
- strpos += 2;
- }
-
- os << str;
- bufpos += sizeof(std::string *);
- break;
- case 'v':
- if (width == 2) {
- bufpos += PADDING(bufpos, v2f);
- v2f *v = (v2f *) bufpos;
- os << '(' << v->X << ", " << v->Y << ')';
- bufpos += sizeof(v2f);
- } else {
- bufpos += PADDING(bufpos, v3f);
- v3f *v = (v3f *) bufpos;
- os << '(' << v->X << ", " << v->Y << ", " << v->Z << ')';
- bufpos += sizeof(v3f);
- }
- break;
- default:
- return false;
- }
- os << ", ";
- }
- *out = os.str();
-
- // Trim off the trailing comma and space
- if (out->size() >= 2)
- out->resize(out->size() - 2);
-
- return true;
-}
-
-#undef SIGN_CAST
-
-////
-//// Other
-////
-
-std::string serializeHexString(const std::string &data, bool insert_spaces)
-{
- std::string result;
- result.reserve(data.size() * (2 + insert_spaces));
-
- static const char hex_chars[] = "0123456789abcdef";
-
- const size_t len = data.size();
- for (size_t i = 0; i != len; i++) {
- u8 byte = data[i];
- result.push_back(hex_chars[(byte >> 4) & 0x0F]);
- result.push_back(hex_chars[(byte >> 0) & 0x0F]);
- if (insert_spaces && i != len - 1)
- result.push_back(' ');
- }
-
- return result;
-}
diff --git a/src/util/serialize.h b/src/util/serialize.h
index a4b5a234a..15bdd050d 100644
--- a/src/util/serialize.h
+++ b/src/util/serialize.h
@@ -290,7 +290,7 @@ inline void writeS8(u8 *data, s8 i)
inline void writeS16(u8 *data, s16 i)
{
- writeU16(data, (u16)i);
+ writeU16(data, (u16)i);
}
inline void writeS32(u8 *data, s32 i)
@@ -440,22 +440,16 @@ MAKE_STREAM_WRITE_FXN(video::SColor, ARGB8, 4);
////
// Creates a string with the length as the first two bytes
-std::string serializeString(const std::string &plain);
-
-// Creates a string with the length as the first two bytes from wide string
-std::string serializeWideString(const std::wstring &plain);
+std::string serializeString16(const std::string &plain);
// Reads a string with the length as the first two bytes
-std::string deSerializeString(std::istream &is);
-
-// Reads a wide string with the length as the first two bytes
-std::wstring deSerializeWideString(std::istream &is);
+std::string deSerializeString16(std::istream &is);
// Creates a string with the length as the first four bytes
-std::string serializeLongString(const std::string &plain);
+std::string serializeString32(const std::string &plain);
// Reads a string with the length as the first four bytes
-std::string deSerializeLongString(std::istream &is);
+std::string deSerializeString32(std::istream &is);
// Creates a string encoded in JSON format (almost equivalent to a C string literal)
std::string serializeJsonString(const std::string &plain);
@@ -469,239 +463,3 @@ std::string serializeJsonStringIfNeeded(const std::string &s);
// Parses a string serialized by serializeJsonStringIfNeeded.
std::string deSerializeJsonStringIfNeeded(std::istream &is);
-
-// Creates a string consisting of the hexadecimal representation of `data`
-std::string serializeHexString(const std::string &data, bool insert_spaces=false);
-
-// Creates a string containing comma delimited values of a struct whose layout is
-// described by the parameter format
-bool serializeStructToString(std::string *out,
- std::string format, void *value);
-
-// Reads a comma delimited string of values into a struct whose layout is
-// decribed by the parameter format
-bool deSerializeStringToStruct(std::string valstr,
- std::string format, void *out, size_t olen);
-
-////
-//// BufReader
-////
-
-#define MAKE_BUFREADER_GETNOEX_FXN(T, N, S) \
- inline bool get ## N ## NoEx(T *val) \
- { \
- if (pos + S > size) \
- return false; \
- *val = read ## N(data + pos); \
- pos += S; \
- return true; \
- }
-
-#define MAKE_BUFREADER_GET_FXN(T, N) \
- inline T get ## N() \
- { \
- T val; \
- if (!get ## N ## NoEx(&val)) \
- throw SerializationError("Attempted read past end of data"); \
- return val; \
- }
-
-class BufReader {
-public:
- BufReader(const u8 *data_, size_t size_) :
- data(data_),
- size(size_)
- {
- }
-
- MAKE_BUFREADER_GETNOEX_FXN(u8, U8, 1);
- MAKE_BUFREADER_GETNOEX_FXN(u16, U16, 2);
- MAKE_BUFREADER_GETNOEX_FXN(u32, U32, 4);
- MAKE_BUFREADER_GETNOEX_FXN(u64, U64, 8);
- MAKE_BUFREADER_GETNOEX_FXN(s8, S8, 1);
- MAKE_BUFREADER_GETNOEX_FXN(s16, S16, 2);
- MAKE_BUFREADER_GETNOEX_FXN(s32, S32, 4);
- MAKE_BUFREADER_GETNOEX_FXN(s64, S64, 8);
- MAKE_BUFREADER_GETNOEX_FXN(f32, F1000, 4);
- MAKE_BUFREADER_GETNOEX_FXN(v2s16, V2S16, 4);
- MAKE_BUFREADER_GETNOEX_FXN(v3s16, V3S16, 6);
- MAKE_BUFREADER_GETNOEX_FXN(v2s32, V2S32, 8);
- MAKE_BUFREADER_GETNOEX_FXN(v3s32, V3S32, 12);
- MAKE_BUFREADER_GETNOEX_FXN(v3f, V3F1000, 12);
- MAKE_BUFREADER_GETNOEX_FXN(video::SColor, ARGB8, 4);
-
- bool getStringNoEx(std::string *val);
- bool getWideStringNoEx(std::wstring *val);
- bool getLongStringNoEx(std::string *val);
- bool getRawDataNoEx(void *data, size_t len);
-
- MAKE_BUFREADER_GET_FXN(u8, U8);
- MAKE_BUFREADER_GET_FXN(u16, U16);
- MAKE_BUFREADER_GET_FXN(u32, U32);
- MAKE_BUFREADER_GET_FXN(u64, U64);
- MAKE_BUFREADER_GET_FXN(s8, S8);
- MAKE_BUFREADER_GET_FXN(s16, S16);
- MAKE_BUFREADER_GET_FXN(s32, S32);
- MAKE_BUFREADER_GET_FXN(s64, S64);
- MAKE_BUFREADER_GET_FXN(f32, F1000);
- MAKE_BUFREADER_GET_FXN(v2s16, V2S16);
- MAKE_BUFREADER_GET_FXN(v3s16, V3S16);
- MAKE_BUFREADER_GET_FXN(v2s32, V2S32);
- MAKE_BUFREADER_GET_FXN(v3s32, V3S32);
- MAKE_BUFREADER_GET_FXN(v3f, V3F1000);
- MAKE_BUFREADER_GET_FXN(video::SColor, ARGB8);
- MAKE_BUFREADER_GET_FXN(std::string, String);
- MAKE_BUFREADER_GET_FXN(std::wstring, WideString);
- MAKE_BUFREADER_GET_FXN(std::string, LongString);
-
- inline void getRawData(void *val, size_t len)
- {
- if (!getRawDataNoEx(val, len))
- throw SerializationError("Attempted read past end of data");
- }
-
- inline size_t remaining()
- {
- assert(pos <= size);
- return size - pos;
- }
-
- const u8 *data;
- size_t size;
- size_t pos = 0;
-};
-
-#undef MAKE_BUFREADER_GET_FXN
-#undef MAKE_BUFREADER_GETNOEX_FXN
-
-
-////
-//// Vector-based write routines
-////
-
-inline void putU8(std::vector<u8> *dest, u8 val)
-{
- dest->push_back((val >> 0) & 0xFF);
-}
-
-inline void putU16(std::vector<u8> *dest, u16 val)
-{
- dest->push_back((val >> 8) & 0xFF);
- dest->push_back((val >> 0) & 0xFF);
-}
-
-inline void putU32(std::vector<u8> *dest, u32 val)
-{
- dest->push_back((val >> 24) & 0xFF);
- dest->push_back((val >> 16) & 0xFF);
- dest->push_back((val >> 8) & 0xFF);
- dest->push_back((val >> 0) & 0xFF);
-}
-
-inline void putU64(std::vector<u8> *dest, u64 val)
-{
- dest->push_back((val >> 56) & 0xFF);
- dest->push_back((val >> 48) & 0xFF);
- dest->push_back((val >> 40) & 0xFF);
- dest->push_back((val >> 32) & 0xFF);
- dest->push_back((val >> 24) & 0xFF);
- dest->push_back((val >> 16) & 0xFF);
- dest->push_back((val >> 8) & 0xFF);
- dest->push_back((val >> 0) & 0xFF);
-}
-
-inline void putS8(std::vector<u8> *dest, s8 val)
-{
- putU8(dest, val);
-}
-
-inline void putS16(std::vector<u8> *dest, s16 val)
-{
- putU16(dest, val);
-}
-
-inline void putS32(std::vector<u8> *dest, s32 val)
-{
- putU32(dest, val);
-}
-
-inline void putS64(std::vector<u8> *dest, s64 val)
-{
- putU64(dest, val);
-}
-
-inline void putF1000(std::vector<u8> *dest, f32 val)
-{
- putS32(dest, val * FIXEDPOINT_FACTOR);
-}
-
-inline void putV2S16(std::vector<u8> *dest, v2s16 val)
-{
- putS16(dest, val.X);
- putS16(dest, val.Y);
-}
-
-inline void putV3S16(std::vector<u8> *dest, v3s16 val)
-{
- putS16(dest, val.X);
- putS16(dest, val.Y);
- putS16(dest, val.Z);
-}
-
-inline void putV2S32(std::vector<u8> *dest, v2s32 val)
-{
- putS32(dest, val.X);
- putS32(dest, val.Y);
-}
-
-inline void putV3S32(std::vector<u8> *dest, v3s32 val)
-{
- putS32(dest, val.X);
- putS32(dest, val.Y);
- putS32(dest, val.Z);
-}
-
-inline void putV3F1000(std::vector<u8> *dest, v3f val)
-{
- putF1000(dest, val.X);
- putF1000(dest, val.Y);
- putF1000(dest, val.Z);
-}
-
-inline void putARGB8(std::vector<u8> *dest, video::SColor val)
-{
- putU32(dest, val.color);
-}
-
-inline void putString(std::vector<u8> *dest, const std::string &val)
-{
- if (val.size() > STRING_MAX_LEN)
- throw SerializationError("String too long");
-
- putU16(dest, val.size());
- dest->insert(dest->end(), val.begin(), val.end());
-}
-
-inline void putWideString(std::vector<u8> *dest, const std::wstring &val)
-{
- if (val.size() > WIDE_STRING_MAX_LEN)
- throw SerializationError("String too long");
-
- putU16(dest, val.size());
- for (size_t i = 0; i != val.size(); i++)
- putU16(dest, val[i]);
-}
-
-inline void putLongString(std::vector<u8> *dest, const std::string &val)
-{
- if (val.size() > LONG_STRING_MAX_LEN)
- throw SerializationError("String too long");
-
- putU32(dest, val.size());
- dest->insert(dest->end(), val.begin(), val.end());
-}
-
-inline void putRawData(std::vector<u8> *dest, const void *src, size_t len)
-{
- dest->insert(dest->end(), (u8 *)src, (u8 *)src + len);
-}
diff --git a/src/util/sha256.c b/src/util/sha256.c
index 4241f31f3..5c8266f9a 100644
--- a/src/util/sha256.c
+++ b/src/util/sha256.c
@@ -18,13 +18,13 @@ const char SHA256_version[] = "SHA-256" OPENSSL_VERSION_PTEXT;
unsigned static char cleanse_ctr = 0;
static void OPENSSL_cleanse(void *ptr, size_t len)
{
- unsigned char *p = ptr;
+ unsigned char *p = (unsigned char *)ptr;
size_t loop = len, ctr = cleanse_ctr;
while (loop--) {
*(p++) = (unsigned char)ctr;
ctr += (17 + ((size_t)p & 0xF));
}
- p = memchr(ptr, (unsigned char)ctr, len);
+ p = (unsigned char *)memchr(ptr, (unsigned char)ctr, len);
if (p)
ctr += (63 + (size_t)p);
cleanse_ctr = (unsigned char)ctr;
@@ -262,7 +262,7 @@ static void sha256_block_data_order(SHA256_CTX *ctx, const void *in,
unsigned MD32_REG_T a, b, c, d, e, f, g, h, s0, s1, T1;
SHA_LONG X[16];
int i;
- const unsigned char *data = in;
+ const unsigned char *data = (const unsigned char *)in;
const union {
long one;
char little;
diff --git a/src/util/srp.cpp b/src/util/srp.cpp
index f4d369d68..ceb2fef9e 100644
--- a/src/util/srp.cpp
+++ b/src/util/srp.cpp
@@ -1015,10 +1015,10 @@ void srp_user_process_challenge(struct SRPUser *usr,
goto cleanup_and_exit;
*bytes_M = usr->M;
- if (len_M) *len_M = hash_length(usr->hash_alg);
+ *len_M = hash_length(usr->hash_alg);
} else {
*bytes_M = NULL;
- if (len_M) *len_M = 0;
+ *len_M = 0;
}
cleanup_and_exit:
diff --git a/src/util/string.cpp b/src/util/string.cpp
index 6e1db798c..611ad35cb 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "translation.h"
#include <algorithm>
+#include <array>
#include <sstream>
#include <iomanip>
#include <map>
@@ -49,8 +50,8 @@ static bool parseNamedColorString(const std::string &value, video::SColor &color
#ifndef _WIN32
-bool convert(const char *to, const char *from, char *outbuf,
- size_t outbuf_size, char *inbuf, size_t inbuf_size)
+static bool convert(const char *to, const char *from, char *outbuf,
+ size_t *outbuf_size, char *inbuf, size_t inbuf_size)
{
iconv_t cd = iconv_open(to, from);
@@ -59,15 +60,14 @@ bool convert(const char *to, const char *from, char *outbuf,
#else
char *inbuf_ptr = inbuf;
#endif
-
char *outbuf_ptr = outbuf;
size_t *inbuf_left_ptr = &inbuf_size;
- size_t *outbuf_left_ptr = &outbuf_size;
+ const size_t old_outbuf_size = *outbuf_size;
size_t old_size = inbuf_size;
while (inbuf_size > 0) {
- iconv(cd, &inbuf_ptr, inbuf_left_ptr, &outbuf_ptr, outbuf_left_ptr);
+ iconv(cd, &inbuf_ptr, inbuf_left_ptr, &outbuf_ptr, outbuf_size);
if (inbuf_size == old_size) {
iconv_close(cd);
return false;
@@ -76,11 +76,12 @@ bool convert(const char *to, const char *from, char *outbuf,
}
iconv_close(cd);
+ *outbuf_size = old_outbuf_size - *outbuf_size;
return true;
}
#ifdef __ANDROID__
-// Android need manual caring to support the full character set possible with wchar_t
+// On Android iconv disagrees how big a wchar_t is for whatever reason
const char *DEFAULT_ENCODING = "UTF-32LE";
#else
const char *DEFAULT_ENCODING = "WCHAR_T";
@@ -88,58 +89,52 @@ const char *DEFAULT_ENCODING = "WCHAR_T";
std::wstring utf8_to_wide(const std::string &input)
{
- size_t inbuf_size = input.length() + 1;
+ const size_t inbuf_size = input.length();
// maximum possible size, every character is sizeof(wchar_t) bytes
- size_t outbuf_size = (input.length() + 1) * sizeof(wchar_t);
+ size_t outbuf_size = input.length() * sizeof(wchar_t);
- char *inbuf = new char[inbuf_size];
+ char *inbuf = new char[inbuf_size]; // intentionally NOT null-terminated
memcpy(inbuf, input.c_str(), inbuf_size);
- char *outbuf = new char[outbuf_size];
- memset(outbuf, 0, outbuf_size);
+ std::wstring out;
+ out.resize(outbuf_size / sizeof(wchar_t));
#ifdef __ANDROID__
- // Android need manual caring to support the full character set possible with wchar_t
SANITY_CHECK(sizeof(wchar_t) == 4);
#endif
- if (!convert(DEFAULT_ENCODING, "UTF-8", outbuf, outbuf_size, inbuf, inbuf_size)) {
+ char *outbuf = reinterpret_cast<char*>(&out[0]);
+ if (!convert(DEFAULT_ENCODING, "UTF-8", outbuf, &outbuf_size, inbuf, inbuf_size)) {
infostream << "Couldn't convert UTF-8 string 0x" << hex_encode(input)
<< " into wstring" << std::endl;
delete[] inbuf;
- delete[] outbuf;
return L"<invalid UTF-8 string>";
}
- std::wstring out((wchar_t *)outbuf);
-
delete[] inbuf;
- delete[] outbuf;
+ out.resize(outbuf_size / sizeof(wchar_t));
return out;
}
std::string wide_to_utf8(const std::wstring &input)
{
- size_t inbuf_size = (input.length() + 1) * sizeof(wchar_t);
- // maximum possible size: utf-8 encodes codepoints using 1 up to 6 bytes
- size_t outbuf_size = (input.length() + 1) * 6;
+ const size_t inbuf_size = input.length() * sizeof(wchar_t);
+ // maximum possible size: utf-8 encodes codepoints using 1 up to 4 bytes
+ size_t outbuf_size = input.length() * 4;
- char *inbuf = new char[inbuf_size];
+ char *inbuf = new char[inbuf_size]; // intentionally NOT null-terminated
memcpy(inbuf, input.c_str(), inbuf_size);
- char *outbuf = new char[outbuf_size];
- memset(outbuf, 0, outbuf_size);
+ std::string out;
+ out.resize(outbuf_size);
- if (!convert("UTF-8", DEFAULT_ENCODING, outbuf, outbuf_size, inbuf, inbuf_size)) {
+ if (!convert("UTF-8", DEFAULT_ENCODING, &out[0], &outbuf_size, inbuf, inbuf_size)) {
infostream << "Couldn't convert wstring 0x" << hex_encode(inbuf, inbuf_size)
<< " into UTF-8 string" << std::endl;
delete[] inbuf;
- delete[] outbuf;
- return "<invalid wstring>";
+ return "<invalid wide string>";
}
- std::string out(outbuf);
-
delete[] inbuf;
- delete[] outbuf;
+ out.resize(outbuf_size);
return out;
}
@@ -171,74 +166,15 @@ std::string wide_to_utf8(const std::wstring &input)
#endif // _WIN32
-// You must free the returned string!
-// The returned string is allocated using new
wchar_t *utf8_to_wide_c(const char *str)
{
std::wstring ret = utf8_to_wide(std::string(str));
size_t len = ret.length();
wchar_t *ret_c = new wchar_t[len + 1];
- memset(ret_c, 0, (len + 1) * sizeof(wchar_t));
- memcpy(ret_c, ret.c_str(), len * sizeof(wchar_t));
+ memcpy(ret_c, ret.c_str(), (len + 1) * sizeof(wchar_t));
return ret_c;
}
-// You must free the returned string!
-// The returned string is allocated using new
-wchar_t *narrow_to_wide_c(const char *str)
-{
- wchar_t *nstr = nullptr;
-#if defined(_WIN32)
- int nResult = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) str, -1, 0, 0);
- if (nResult == 0) {
- errorstream<<"gettext: MultiByteToWideChar returned null"<<std::endl;
- } else {
- nstr = new wchar_t[nResult];
- MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) str, -1, (WCHAR *) nstr, nResult);
- }
-#else
- size_t len = strlen(str);
- nstr = new wchar_t[len + 1];
-
- std::wstring intermediate = narrow_to_wide(str);
- memset(nstr, 0, (len + 1) * sizeof(wchar_t));
- memcpy(nstr, intermediate.c_str(), len * sizeof(wchar_t));
-#endif
-
- return nstr;
-}
-
-std::wstring narrow_to_wide(const std::string &mbs) {
-#ifdef __ANDROID__
- return utf8_to_wide(mbs);
-#else
- size_t wcl = mbs.size();
- Buffer<wchar_t> wcs(wcl + 1);
- size_t len = mbstowcs(*wcs, mbs.c_str(), wcl);
- if (len == (size_t)(-1))
- return L"<invalid multibyte string>";
- wcs[len] = 0;
- return *wcs;
-#endif
-}
-
-
-std::string wide_to_narrow(const std::wstring &wcs)
-{
-#ifdef __ANDROID__
- return wide_to_utf8(wcs);
-#else
- size_t mbl = wcs.size() * 4;
- SharedBuffer<char> mbs(mbl+1);
- size_t len = wcstombs(*mbs, wcs.c_str(), mbl);
- if (len == (size_t)(-1))
- return "Character conversion failed!";
-
- mbs[len] = 0;
- return *mbs;
-#endif
-}
-
std::string urlencode(const std::string &str)
{
@@ -632,7 +568,7 @@ static bool parseNamedColorString(const std::string &value, video::SColor &color
color_name = value;
}
- color_name = lowercase(value);
+ color_name = lowercase(color_name);
std::map<const std::string, unsigned>::const_iterator it;
it = named_colors.colors.find(color_name);
@@ -765,7 +701,8 @@ void translate_string(const std::wstring &s, Translations *translations,
} else {
// This is an escape sequence *inside* the template string to translate itself.
// This should not happen, show an error message.
- errorstream << "Ignoring escape sequence '" << wide_to_narrow(escape_sequence) << "' in translation" << std::endl;
+ errorstream << "Ignoring escape sequence '"
+ << wide_to_utf8(escape_sequence) << "' in translation" << std::endl;
}
}
@@ -889,3 +826,70 @@ std::wstring translate_string(const std::wstring &s)
return translate_string(s, g_client_translations);
#endif
}
+
+static const std::array<std::wstring, 22> disallowed_dir_names = {
+ // Problematic filenames from here:
+ // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#file-and-directory-names
+ L"CON",
+ L"PRN",
+ L"AUX",
+ L"NUL",
+ L"COM1",
+ L"COM2",
+ L"COM3",
+ L"COM4",
+ L"COM5",
+ L"COM6",
+ L"COM7",
+ L"COM8",
+ L"COM9",
+ L"LPT1",
+ L"LPT2",
+ L"LPT3",
+ L"LPT4",
+ L"LPT5",
+ L"LPT6",
+ L"LPT7",
+ L"LPT8",
+ L"LPT9",
+};
+
+/**
+ * List of characters that are blacklisted from created directories
+ */
+static const std::wstring disallowed_path_chars = L"<>:\"/\\|?*.";
+
+/**
+ * Sanitize the name of a new directory. This consists of two stages:
+ * 1. Check for 'reserved filenames' that can't be used on some filesystems
+ * and add a prefix to them
+ * 2. Remove 'unsafe' characters from the name by replacing them with '_'
+ */
+std::string sanitizeDirName(const std::string &str, const std::string &optional_prefix)
+{
+ std::wstring safe_name = utf8_to_wide(str);
+
+ for (std::wstring disallowed_name : disallowed_dir_names) {
+ if (str_equal(safe_name, disallowed_name, true)) {
+ safe_name = utf8_to_wide(optional_prefix) + safe_name;
+ break;
+ }
+ }
+
+ for (unsigned long i = 0; i < safe_name.length(); i++) {
+ bool is_valid = true;
+
+ // Unlikely, but control characters should always be blacklisted
+ if (safe_name[i] < 32) {
+ is_valid = false;
+ } else if (safe_name[i] < 128) {
+ is_valid = disallowed_path_chars.find_first_of(safe_name[i])
+ == std::wstring::npos;
+ }
+
+ if (!is_valid)
+ safe_name[i] = '_';
+ }
+
+ return wide_to_utf8(safe_name);
+}
diff --git a/src/util/string.h b/src/util/string.h
index 185fb55e2..d4afcaec8 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -64,22 +64,14 @@ struct FlagDesc {
u32 flag;
};
-// try not to convert between wide/utf8 encodings; this can result in data loss
-// try to only convert between them when you need to input/output stuff via Irrlicht
+// Try to avoid converting between wide and UTF-8 unless you need to
+// input/output stuff via Irrlicht
std::wstring utf8_to_wide(const std::string &input);
std::string wide_to_utf8(const std::wstring &input);
-wchar_t *utf8_to_wide_c(const char *str);
-
-// NEVER use those two functions unless you have a VERY GOOD reason to
-// they just convert between wide and multibyte encoding
-// multibyte encoding depends on current locale, this is no good, especially on Windows
-
// You must free the returned string!
-// The returned string is allocated using new
-wchar_t *narrow_to_wide_c(const char *str);
-std::wstring narrow_to_wide(const std::string &mbs);
-std::string wide_to_narrow(const std::wstring &wcs);
+// The returned string is allocated using new[]
+wchar_t *utf8_to_wide_c(const char *str);
std::string urlencode(const std::string &str);
std::string urldecode(const std::string &str);
@@ -353,11 +345,6 @@ inline s32 mystoi(const std::string &str, s32 min, s32 max)
return i;
}
-
-// MSVC2010 includes it's own versions of these
-//#if !defined(_MSC_VER) || _MSC_VER < 1600
-
-
/**
* Returns a 32-bit value reprensented by the string \p str (decimal).
* @see atoi(3) for further limitations
@@ -367,17 +354,6 @@ inline s32 mystoi(const std::string &str)
return atoi(str.c_str());
}
-
-/**
- * Returns s 32-bit value represented by the wide string \p str (decimal).
- * @see atoi(3) for further limitations
- */
-inline s32 mystoi(const std::wstring &str)
-{
- return mystoi(wide_to_narrow(str));
-}
-
-
/**
* Returns a float reprensented by the string \p str (decimal).
* @see atof(3)
@@ -387,8 +363,6 @@ inline float mystof(const std::string &str)
return atof(str.c_str());
}
-//#endif
-
#define stoi mystoi
#define stof mystof
@@ -746,3 +720,11 @@ inline irr::core::stringw utf8_to_stringw(const std::string &input)
std::wstring str = utf8_to_wide(input);
return irr::core::stringw(str.c_str());
}
+
+/**
+ * Sanitize the name of a new directory. This consists of two stages:
+ * 1. Check for 'reserved filenames' that can't be used on some filesystems
+ * and prefix them
+ * 2. Remove 'unsafe' characters from the name by replacing them with '_'
+ */
+std::string sanitizeDirName(const std::string &str, const std::string &optional_prefix);