summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/CMakeLists.txt1
-rw-r--r--src/util/Optional.h32
-rw-r--r--src/util/base64.cpp29
-rw-r--r--src/util/numeric.cpp19
-rw-r--r--src/util/numeric.h4
-rwxr-xr-xsrc/util/png.cpp68
-rwxr-xr-xsrc/util/png.h27
-rw-r--r--src/util/pointer.h58
-rw-r--r--src/util/serialize.cpp5
-rw-r--r--src/util/string.cpp450
-rw-r--r--src/util/string.h43
11 files changed, 467 insertions, 269 deletions
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index cd2e468d1..6bc97915f 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -15,4 +15,5 @@ set(UTIL_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/string.cpp
${CMAKE_CURRENT_SOURCE_DIR}/srp.cpp
${CMAKE_CURRENT_SOURCE_DIR}/timetaker.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/png.cpp
PARENT_SCOPE)
diff --git a/src/util/Optional.h b/src/util/Optional.h
index 9c2842b43..eda7fff89 100644
--- a/src/util/Optional.h
+++ b/src/util/Optional.h
@@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
+#include <utility>
#include "debug.h"
struct nullopt_t
@@ -43,18 +44,38 @@ class Optional
public:
Optional() noexcept {}
Optional(nullopt_t) noexcept {}
+
Optional(const T &value) noexcept : m_has_value(true), m_value(value) {}
+ Optional(T &&value) noexcept : m_has_value(true), m_value(std::move(value)) {}
+
Optional(const Optional<T> &other) noexcept :
m_has_value(other.m_has_value), m_value(other.m_value)
+ {}
+ Optional(Optional<T> &&other) noexcept :
+ m_has_value(other.m_has_value), m_value(std::move(other.m_value))
{
+ other.m_has_value = false;
}
- void operator=(nullopt_t) noexcept { m_has_value = false; }
+ Optional<T> &operator=(nullopt_t) noexcept { m_has_value = false; return *this; }
- void operator=(const Optional<T> &other) noexcept
+ Optional<T> &operator=(const Optional<T> &other) noexcept
{
+ if (&other == this)
+ return *this;
m_has_value = other.m_has_value;
m_value = other.m_value;
+ return *this;
+ }
+
+ Optional<T> &operator=(Optional<T> &&other) noexcept
+ {
+ if (&other == this)
+ return *this;
+ m_has_value = other.m_has_value;
+ m_value = std::move(other.m_value);
+ other.m_has_value = false;
+ return *this;
}
T &value()
@@ -71,6 +92,13 @@ public:
const T &value_or(const T &def) const { return m_has_value ? m_value : def; }
+ // Unchecked access consistent with std::optional
+ T* operator->() { return &m_value; }
+ const T* operator->() const { return &m_value; }
+
+ T& operator*() { return m_value; }
+ const T& operator*() const { return m_value; }
+
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 6e1584410..0c2455222 100644
--- a/src/util/base64.cpp
+++ b/src/util/base64.cpp
@@ -33,18 +33,39 @@ static const std::string base64_chars =
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
+static const std::string base64_chars_padding_1 = "AEIMQUYcgkosw048";
+static const std::string base64_chars_padding_2 = "AQgw";
static inline bool is_base64(unsigned char c)
{
- return isalnum(c) || c == '+' || c == '/' || c == '=';
+ return (c >= '0' && c <= '9')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= 'a' && c <= 'z')
+ || c == '+' || c == '/';
}
bool base64_is_valid(std::string const& s)
{
- for (char i : s)
- if (!is_base64(i))
+ size_t i = 0;
+ for (; i < s.size(); ++i)
+ if (!is_base64(s[i]))
+ break;
+ unsigned char padding = 3 - ((i + 3) % 4);
+ if ((padding == 1 && base64_chars_padding_1.find(s[i - 1]) == std::string::npos)
+ || (padding == 2 && base64_chars_padding_2.find(s[i - 1]) == std::string::npos)
+ || padding == 3)
+ return false;
+ int actual_padding = s.size() - i;
+ // omission of padding characters is allowed
+ if (actual_padding == 0)
+ return true;
+
+ // remaining characters (max. 2) may only be padding
+ for (; i < s.size(); ++i)
+ if (s[i] != '=')
return false;
- return true;
+ // number of padding characters needs to match
+ return padding == actual_padding;
}
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp
index 1af3f66be..702ddce95 100644
--- a/src/util/numeric.cpp
+++ b/src/util/numeric.cpp
@@ -106,10 +106,6 @@ u64 murmur_hash_64_ua(const void *key, int len, unsigned int seed)
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
f32 camera_fov, f32 range, f32 *distance_ptr)
{
- // Maximum radius of a block. The magic number is
- // sqrt(3.0) / 2.0 in literal form.
- static constexpr const f32 block_max_radius = 0.866025403784f * MAP_BLOCKSIZE * BS;
-
v3s16 blockpos_nodes = blockpos_b * MAP_BLOCKSIZE;
// Block center position
@@ -123,7 +119,7 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
v3f blockpos_relative = blockpos - camera_pos;
// Total distance
- f32 d = MYMAX(0, blockpos_relative.getLength() - block_max_radius);
+ f32 d = MYMAX(0, blockpos_relative.getLength() - BLOCK_MAX_RADIUS);
if (distance_ptr)
*distance_ptr = d;
@@ -141,7 +137,7 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
// such that a block that has any portion visible with the
// current camera position will have the center visible at the
// adjusted postion
- f32 adjdist = block_max_radius / cos((M_PI - camera_fov) / 2);
+ f32 adjdist = BLOCK_MAX_RADIUS / cos((M_PI - camera_fov) / 2);
// Block position relative to adjusted camera
v3f blockpos_adj = blockpos - (camera_pos - camera_dir * adjdist);
@@ -163,7 +159,7 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
return true;
}
-s16 adjustDist(s16 dist, float zoom_fov)
+inline float adjustDist(float dist, float zoom_fov)
{
// 1.775 ~= 72 * PI / 180 * 1.4, the default FOV on the client.
// The heuristic threshold for zooming is half of that.
@@ -171,8 +167,13 @@ s16 adjustDist(s16 dist, float zoom_fov)
if (zoom_fov < 0.001f || zoom_fov > threshold_fov)
return dist;
- return std::round(dist * std::cbrt((1.0f - std::cos(threshold_fov)) /
- (1.0f - std::cos(zoom_fov / 2.0f))));
+ return dist * std::cbrt((1.0f - std::cos(threshold_fov)) /
+ (1.0f - std::cos(zoom_fov / 2.0f)));
+}
+
+s16 adjustDist(s16 dist, float zoom_fov)
+{
+ return std::round(adjustDist((float)dist, zoom_fov));
}
void setPitchYawRollRad(core::matrix4 &m, const v3f &rot)
diff --git a/src/util/numeric.h b/src/util/numeric.h
index 864ab7543..32a6f4312 100644
--- a/src/util/numeric.h
+++ b/src/util/numeric.h
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
#include "basic_macros.h"
+#include "constants.h"
#include "irrlichttypes.h"
#include "irr_v2d.h"
#include "irr_v3d.h"
@@ -36,6 +37,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
y = temp; \
} while (0)
+// Maximum radius of a block. The magic number is
+// sqrt(3.0) / 2.0 in literal form.
+static constexpr const f32 BLOCK_MAX_RADIUS = 0.866025403784f * MAP_BLOCKSIZE * BS;
inline s16 getContainerPos(s16 p, s16 d)
{
diff --git a/src/util/png.cpp b/src/util/png.cpp
new file mode 100755
index 000000000..698cbc9a5
--- /dev/null
+++ b/src/util/png.cpp
@@ -0,0 +1,68 @@
+/*
+Minetest
+Copyright (C) 2021 hecks
+
+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.
+*/
+
+#include "png.h"
+#include <string>
+#include <sstream>
+#include <zlib.h>
+#include <cassert>
+#include "util/serialize.h"
+#include "serialization.h"
+#include "irrlichttypes.h"
+
+static void writeChunk(std::ostringstream &target, const std::string &chunk_str)
+{
+ assert(chunk_str.size() >= 4);
+ assert(chunk_str.size() - 4 < U32_MAX);
+ writeU32(target, chunk_str.size() - 4); // Write length minus the identifier
+ target << chunk_str;
+ writeU32(target, crc32(0,(const u8*)chunk_str.data(), chunk_str.size()));
+}
+
+std::string encodePNG(const u8 *data, u32 width, u32 height, s32 compression)
+{
+ std::ostringstream file(std::ios::binary);
+ file << "\x89PNG\r\n\x1a\n";
+
+ {
+ std::ostringstream IHDR(std::ios::binary);
+ IHDR << "IHDR";
+ writeU32(IHDR, width);
+ writeU32(IHDR, height);
+ // 8 bpp, color type 6 (RGBA)
+ IHDR.write("\x08\x06\x00\x00\x00", 5);
+ writeChunk(file, IHDR.str());
+ }
+
+ {
+ std::ostringstream IDAT(std::ios::binary);
+ IDAT << "IDAT";
+ std::ostringstream scanlines(std::ios::binary);
+ for(u32 i = 0; i < height; i++) {
+ scanlines.write("\x00", 1); // Null predictor
+ scanlines.write((const char*) data + width * 4 * i, width * 4);
+ }
+ compressZlib(scanlines.str(), IDAT, compression);
+ writeChunk(file, IDAT.str());
+ }
+
+ file.write("\x00\x00\x00\x00IEND\xae\x42\x60\x82", 12);
+
+ return file.str();
+}
diff --git a/src/util/png.h b/src/util/png.h
new file mode 100755
index 000000000..92387aef0
--- /dev/null
+++ b/src/util/png.h
@@ -0,0 +1,27 @@
+/*
+Minetest
+Copyright (C) 2021 hecks
+
+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 <string>
+#include "irrlichttypes.h"
+
+/* Simple PNG encoder. Encodes an RGBA image with no predictors.
+ Returns a binary string. */
+std::string encodePNG(const u8 *data, u32 width, u32 height, s32 compression);
diff --git a/src/util/pointer.h b/src/util/pointer.h
index 7fc5de551..245ac85bf 100644
--- a/src/util/pointer.h
+++ b/src/util/pointer.h
@@ -22,6 +22,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h"
#include "debug.h" // For assert()
#include <cstring>
+#include <memory> // std::shared_ptr
+
+
+template<typename T> class ConstSharedPtr {
+public:
+ ConstSharedPtr(T *ptr) : ptr(ptr) {}
+ ConstSharedPtr(const std::shared_ptr<T> &ptr) : ptr(ptr) {}
+
+ const T* get() const noexcept { return ptr.get(); }
+ const T& operator*() const noexcept { return *ptr.get(); }
+ const T* operator->() const noexcept { return ptr.get(); }
+
+private:
+ std::shared_ptr<T> ptr;
+};
template <typename T>
class Buffer
@@ -40,17 +55,11 @@ public:
else
data = NULL;
}
- Buffer(const Buffer &buffer)
- {
- m_size = buffer.m_size;
- if(m_size != 0)
- {
- data = new T[buffer.m_size];
- memcpy(data, buffer.data, buffer.m_size);
- }
- else
- data = NULL;
- }
+
+ // Disable class copy
+ Buffer(const Buffer &) = delete;
+ Buffer &operator=(const Buffer &) = delete;
+
Buffer(Buffer &&buffer)
{
m_size = buffer.m_size;
@@ -81,21 +90,6 @@ public:
drop();
}
- Buffer& operator=(const Buffer &buffer)
- {
- if(this == &buffer)
- return *this;
- drop();
- m_size = buffer.m_size;
- if(m_size != 0)
- {
- data = new T[buffer.m_size];
- memcpy(data, buffer.data, buffer.m_size);
- }
- else
- data = NULL;
- return *this;
- }
Buffer& operator=(Buffer &&buffer)
{
if(this == &buffer)
@@ -113,6 +107,18 @@ public:
return *this;
}
+ void copyTo(Buffer &buffer) const
+ {
+ buffer.drop();
+ buffer.m_size = m_size;
+ if (m_size != 0) {
+ buffer.data = new T[m_size];
+ memcpy(buffer.data, data, m_size);
+ } else {
+ buffer.data = nullptr;
+ }
+ }
+
T & operator[](unsigned int i) const
{
return data[i];
diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp
index d770101f2..281061229 100644
--- a/src/util/serialize.cpp
+++ b/src/util/serialize.cpp
@@ -248,7 +248,7 @@ std::string serializeJsonStringIfNeeded(const std::string &s)
std::string deSerializeJsonStringIfNeeded(std::istream &is)
{
- std::ostringstream tmp_os;
+ std::stringstream tmp_os(std::ios_base::binary | std::ios_base::in | std::ios_base::out);
bool expect_initial_quote = true;
bool is_json = false;
bool was_backslash = false;
@@ -280,8 +280,7 @@ std::string deSerializeJsonStringIfNeeded(std::istream &is)
expect_initial_quote = false;
}
if (is_json) {
- std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
- return deSerializeJsonString(tmp_is);
+ return deSerializeJsonString(tmp_os);
}
return tmp_os.str();
diff --git a/src/util/string.cpp b/src/util/string.cpp
index 611ad35cb..bc4664997 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <array>
#include <sstream>
#include <iomanip>
-#include <map>
+#include <unordered_map>
#ifndef _WIN32
#include <iconv.h>
@@ -39,15 +39,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <windows.h>
#endif
-#if defined(_ICONV_H_) && (defined(__FreeBSD__) || defined(__NetBSD__) || \
- defined(__OpenBSD__) || defined(__DragonFly__))
+#ifdef __NetBSD__
+ #include <sys/param.h>
+ #if __NetBSD_Version__ <= 999001500
+ #define BSD_ICONV_USED
+ #endif
+#elif defined(_ICONV_H_) && (defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__DragonFly__))
#define BSD_ICONV_USED
#endif
-static bool parseHexColorString(const std::string &value, video::SColor &color,
- unsigned char default_alpha = 0xff);
-static bool parseNamedColorString(const std::string &value, video::SColor &color);
-
#ifndef _WIN32
static bool convert(const char *to, const char *from, char *outbuf,
@@ -83,6 +84,14 @@ static bool convert(const char *to, const char *from, char *outbuf,
#ifdef __ANDROID__
// On Android iconv disagrees how big a wchar_t is for whatever reason
const char *DEFAULT_ENCODING = "UTF-32LE";
+#elif defined(__NetBSD__)
+ // NetBSD does not allow "WCHAR_T" as a charset input to iconv.
+ #include <sys/endian.h>
+ #if BYTE_ORDER == BIG_ENDIAN
+ const char *DEFAULT_ENCODING = "UTF-32BE";
+ #else
+ const char *DEFAULT_ENCODING = "UTF-32LE";
+ #endif
#else
const char *DEFAULT_ENCODING = "WCHAR_T";
#endif
@@ -98,7 +107,7 @@ std::wstring utf8_to_wide(const std::string &input)
std::wstring out;
out.resize(outbuf_size / sizeof(wchar_t));
-#ifdef __ANDROID__
+#if defined(__ANDROID__) || defined(__NetBSD__)
SANITY_CHECK(sizeof(wchar_t) == 4);
#endif
@@ -324,29 +333,10 @@ u64 read_seed(const char *str)
return num;
}
-bool parseColorString(const std::string &value, video::SColor &color, bool quiet,
- unsigned char default_alpha)
-{
- bool success;
-
- if (value[0] == '#')
- success = parseHexColorString(value, color, default_alpha);
- else
- success = parseNamedColorString(value, color);
-
- if (!success && !quiet)
- errorstream << "Invalid color: \"" << value << "\"" << std::endl;
-
- return success;
-}
-
static bool parseHexColorString(const std::string &value, video::SColor &color,
unsigned char default_alpha)
{
- unsigned char components[] = { 0x00, 0x00, 0x00, default_alpha }; // R,G,B,A
-
- if (value[0] != '#')
- return false;
+ u8 components[] = {0x00, 0x00, 0x00, default_alpha}; // R,G,B,A
size_t len = value.size();
bool short_form;
@@ -358,198 +348,182 @@ static bool parseHexColorString(const std::string &value, video::SColor &color,
else
return false;
- bool success = true;
-
for (size_t pos = 1, cc = 0; pos < len; pos++, cc++) {
- assert(cc < sizeof components / sizeof components[0]);
if (short_form) {
- unsigned char d;
- if (!hex_digit_decode(value[pos], d)) {
- success = false;
- break;
- }
+ u8 d;
+ if (!hex_digit_decode(value[pos], d))
+ return false;
+
components[cc] = (d & 0xf) << 4 | (d & 0xf);
} else {
- unsigned char d1, d2;
+ u8 d1, d2;
if (!hex_digit_decode(value[pos], d1) ||
- !hex_digit_decode(value[pos+1], d2)) {
- success = false;
- break;
- }
+ !hex_digit_decode(value[pos+1], d2))
+ return false;
+
components[cc] = (d1 & 0xf) << 4 | (d2 & 0xf);
- pos++; // skip the second digit -- it's already used
+ pos++; // skip the second digit -- it's already used
}
}
- if (success) {
- color.setRed(components[0]);
- color.setGreen(components[1]);
- color.setBlue(components[2]);
- color.setAlpha(components[3]);
- }
+ color.setRed(components[0]);
+ color.setGreen(components[1]);
+ color.setBlue(components[2]);
+ color.setAlpha(components[3]);
- return success;
+ return true;
}
-struct ColorContainer {
- ColorContainer();
- std::map<const std::string, u32> colors;
+const static std::unordered_map<std::string, u32> s_named_colors = {
+ {"aliceblue", 0xf0f8ff},
+ {"antiquewhite", 0xfaebd7},
+ {"aqua", 0x00ffff},
+ {"aquamarine", 0x7fffd4},
+ {"azure", 0xf0ffff},
+ {"beige", 0xf5f5dc},
+ {"bisque", 0xffe4c4},
+ {"black", 00000000},
+ {"blanchedalmond", 0xffebcd},
+ {"blue", 0x0000ff},
+ {"blueviolet", 0x8a2be2},
+ {"brown", 0xa52a2a},
+ {"burlywood", 0xdeb887},
+ {"cadetblue", 0x5f9ea0},
+ {"chartreuse", 0x7fff00},
+ {"chocolate", 0xd2691e},
+ {"coral", 0xff7f50},
+ {"cornflowerblue", 0x6495ed},
+ {"cornsilk", 0xfff8dc},
+ {"crimson", 0xdc143c},
+ {"cyan", 0x00ffff},
+ {"darkblue", 0x00008b},
+ {"darkcyan", 0x008b8b},
+ {"darkgoldenrod", 0xb8860b},
+ {"darkgray", 0xa9a9a9},
+ {"darkgreen", 0x006400},
+ {"darkgrey", 0xa9a9a9},
+ {"darkkhaki", 0xbdb76b},
+ {"darkmagenta", 0x8b008b},
+ {"darkolivegreen", 0x556b2f},
+ {"darkorange", 0xff8c00},
+ {"darkorchid", 0x9932cc},
+ {"darkred", 0x8b0000},
+ {"darksalmon", 0xe9967a},
+ {"darkseagreen", 0x8fbc8f},
+ {"darkslateblue", 0x483d8b},
+ {"darkslategray", 0x2f4f4f},
+ {"darkslategrey", 0x2f4f4f},
+ {"darkturquoise", 0x00ced1},
+ {"darkviolet", 0x9400d3},
+ {"deeppink", 0xff1493},
+ {"deepskyblue", 0x00bfff},
+ {"dimgray", 0x696969},
+ {"dimgrey", 0x696969},
+ {"dodgerblue", 0x1e90ff},
+ {"firebrick", 0xb22222},
+ {"floralwhite", 0xfffaf0},
+ {"forestgreen", 0x228b22},
+ {"fuchsia", 0xff00ff},
+ {"gainsboro", 0xdcdcdc},
+ {"ghostwhite", 0xf8f8ff},
+ {"gold", 0xffd700},
+ {"goldenrod", 0xdaa520},
+ {"gray", 0x808080},
+ {"green", 0x008000},
+ {"greenyellow", 0xadff2f},
+ {"grey", 0x808080},
+ {"honeydew", 0xf0fff0},
+ {"hotpink", 0xff69b4},
+ {"indianred", 0xcd5c5c},
+ {"indigo", 0x4b0082},
+ {"ivory", 0xfffff0},
+ {"khaki", 0xf0e68c},
+ {"lavender", 0xe6e6fa},
+ {"lavenderblush", 0xfff0f5},
+ {"lawngreen", 0x7cfc00},
+ {"lemonchiffon", 0xfffacd},
+ {"lightblue", 0xadd8e6},
+ {"lightcoral", 0xf08080},
+ {"lightcyan", 0xe0ffff},
+ {"lightgoldenrodyellow", 0xfafad2},
+ {"lightgray", 0xd3d3d3},
+ {"lightgreen", 0x90ee90},
+ {"lightgrey", 0xd3d3d3},
+ {"lightpink", 0xffb6c1},
+ {"lightsalmon", 0xffa07a},
+ {"lightseagreen", 0x20b2aa},
+ {"lightskyblue", 0x87cefa},
+ {"lightslategray", 0x778899},
+ {"lightslategrey", 0x778899},
+ {"lightsteelblue", 0xb0c4de},
+ {"lightyellow", 0xffffe0},
+ {"lime", 0x00ff00},
+ {"limegreen", 0x32cd32},
+ {"linen", 0xfaf0e6},
+ {"magenta", 0xff00ff},
+ {"maroon", 0x800000},
+ {"mediumaquamarine", 0x66cdaa},
+ {"mediumblue", 0x0000cd},
+ {"mediumorchid", 0xba55d3},
+ {"mediumpurple", 0x9370db},
+ {"mediumseagreen", 0x3cb371},
+ {"mediumslateblue", 0x7b68ee},
+ {"mediumspringgreen", 0x00fa9a},
+ {"mediumturquoise", 0x48d1cc},
+ {"mediumvioletred", 0xc71585},
+ {"midnightblue", 0x191970},
+ {"mintcream", 0xf5fffa},
+ {"mistyrose", 0xffe4e1},
+ {"moccasin", 0xffe4b5},
+ {"navajowhite", 0xffdead},
+ {"navy", 0x000080},
+ {"oldlace", 0xfdf5e6},
+ {"olive", 0x808000},
+ {"olivedrab", 0x6b8e23},
+ {"orange", 0xffa500},
+ {"orangered", 0xff4500},
+ {"orchid", 0xda70d6},
+ {"palegoldenrod", 0xeee8aa},
+ {"palegreen", 0x98fb98},
+ {"paleturquoise", 0xafeeee},
+ {"palevioletred", 0xdb7093},
+ {"papayawhip", 0xffefd5},
+ {"peachpuff", 0xffdab9},
+ {"peru", 0xcd853f},
+ {"pink", 0xffc0cb},
+ {"plum", 0xdda0dd},
+ {"powderblue", 0xb0e0e6},
+ {"purple", 0x800080},
+ {"red", 0xff0000},
+ {"rosybrown", 0xbc8f8f},
+ {"royalblue", 0x4169e1},
+ {"saddlebrown", 0x8b4513},
+ {"salmon", 0xfa8072},
+ {"sandybrown", 0xf4a460},
+ {"seagreen", 0x2e8b57},
+ {"seashell", 0xfff5ee},
+ {"sienna", 0xa0522d},
+ {"silver", 0xc0c0c0},
+ {"skyblue", 0x87ceeb},
+ {"slateblue", 0x6a5acd},
+ {"slategray", 0x708090},
+ {"slategrey", 0x708090},
+ {"snow", 0xfffafa},
+ {"springgreen", 0x00ff7f},
+ {"steelblue", 0x4682b4},
+ {"tan", 0xd2b48c},
+ {"teal", 0x008080},
+ {"thistle", 0xd8bfd8},
+ {"tomato", 0xff6347},
+ {"turquoise", 0x40e0d0},
+ {"violet", 0xee82ee},
+ {"wheat", 0xf5deb3},
+ {"white", 0xffffff},
+ {"whitesmoke", 0xf5f5f5},
+ {"yellow", 0xffff00},
+ {"yellowgreen", 0x9acd32}
};
-ColorContainer::ColorContainer()
-{
- colors["aliceblue"] = 0xf0f8ff;
- colors["antiquewhite"] = 0xfaebd7;
- colors["aqua"] = 0x00ffff;
- colors["aquamarine"] = 0x7fffd4;
- colors["azure"] = 0xf0ffff;
- colors["beige"] = 0xf5f5dc;
- colors["bisque"] = 0xffe4c4;
- colors["black"] = 00000000;
- colors["blanchedalmond"] = 0xffebcd;
- colors["blue"] = 0x0000ff;
- colors["blueviolet"] = 0x8a2be2;
- colors["brown"] = 0xa52a2a;
- colors["burlywood"] = 0xdeb887;
- colors["cadetblue"] = 0x5f9ea0;
- colors["chartreuse"] = 0x7fff00;
- colors["chocolate"] = 0xd2691e;
- colors["coral"] = 0xff7f50;
- colors["cornflowerblue"] = 0x6495ed;
- colors["cornsilk"] = 0xfff8dc;
- colors["crimson"] = 0xdc143c;
- colors["cyan"] = 0x00ffff;
- colors["darkblue"] = 0x00008b;
- colors["darkcyan"] = 0x008b8b;
- colors["darkgoldenrod"] = 0xb8860b;
- colors["darkgray"] = 0xa9a9a9;
- colors["darkgreen"] = 0x006400;
- colors["darkgrey"] = 0xa9a9a9;
- colors["darkkhaki"] = 0xbdb76b;
- colors["darkmagenta"] = 0x8b008b;
- colors["darkolivegreen"] = 0x556b2f;
- colors["darkorange"] = 0xff8c00;
- colors["darkorchid"] = 0x9932cc;
- colors["darkred"] = 0x8b0000;
- colors["darksalmon"] = 0xe9967a;
- colors["darkseagreen"] = 0x8fbc8f;
- colors["darkslateblue"] = 0x483d8b;
- colors["darkslategray"] = 0x2f4f4f;
- colors["darkslategrey"] = 0x2f4f4f;
- colors["darkturquoise"] = 0x00ced1;
- colors["darkviolet"] = 0x9400d3;
- colors["deeppink"] = 0xff1493;
- colors["deepskyblue"] = 0x00bfff;
- colors["dimgray"] = 0x696969;
- colors["dimgrey"] = 0x696969;
- colors["dodgerblue"] = 0x1e90ff;
- colors["firebrick"] = 0xb22222;
- colors["floralwhite"] = 0xfffaf0;
- colors["forestgreen"] = 0x228b22;
- colors["fuchsia"] = 0xff00ff;
- colors["gainsboro"] = 0xdcdcdc;
- colors["ghostwhite"] = 0xf8f8ff;
- colors["gold"] = 0xffd700;
- colors["goldenrod"] = 0xdaa520;
- colors["gray"] = 0x808080;
- colors["green"] = 0x008000;
- colors["greenyellow"] = 0xadff2f;
- colors["grey"] = 0x808080;
- colors["honeydew"] = 0xf0fff0;
- colors["hotpink"] = 0xff69b4;
- colors["indianred"] = 0xcd5c5c;
- colors["indigo"] = 0x4b0082;
- colors["ivory"] = 0xfffff0;
- colors["khaki"] = 0xf0e68c;
- colors["lavender"] = 0xe6e6fa;
- colors["lavenderblush"] = 0xfff0f5;
- colors["lawngreen"] = 0x7cfc00;
- colors["lemonchiffon"] = 0xfffacd;
- colors["lightblue"] = 0xadd8e6;
- colors["lightcoral"] = 0xf08080;
- colors["lightcyan"] = 0xe0ffff;
- colors["lightgoldenrodyellow"] = 0xfafad2;
- colors["lightgray"] = 0xd3d3d3;
- colors["lightgreen"] = 0x90ee90;
- colors["lightgrey"] = 0xd3d3d3;
- colors["lightpink"] = 0xffb6c1;
- colors["lightsalmon"] = 0xffa07a;
- colors["lightseagreen"] = 0x20b2aa;
- colors["lightskyblue"] = 0x87cefa;
- colors["lightslategray"] = 0x778899;
- colors["lightslategrey"] = 0x778899;
- colors["lightsteelblue"] = 0xb0c4de;
- colors["lightyellow"] = 0xffffe0;
- colors["lime"] = 0x00ff00;
- colors["limegreen"] = 0x32cd32;
- colors["linen"] = 0xfaf0e6;
- colors["magenta"] = 0xff00ff;
- colors["maroon"] = 0x800000;
- colors["mediumaquamarine"] = 0x66cdaa;
- colors["mediumblue"] = 0x0000cd;
- colors["mediumorchid"] = 0xba55d3;
- colors["mediumpurple"] = 0x9370db;
- colors["mediumseagreen"] = 0x3cb371;
- colors["mediumslateblue"] = 0x7b68ee;
- colors["mediumspringgreen"] = 0x00fa9a;
- colors["mediumturquoise"] = 0x48d1cc;
- colors["mediumvioletred"] = 0xc71585;
- colors["midnightblue"] = 0x191970;
- colors["mintcream"] = 0xf5fffa;
- colors["mistyrose"] = 0xffe4e1;
- colors["moccasin"] = 0xffe4b5;
- colors["navajowhite"] = 0xffdead;
- colors["navy"] = 0x000080;
- colors["oldlace"] = 0xfdf5e6;
- colors["olive"] = 0x808000;
- colors["olivedrab"] = 0x6b8e23;
- colors["orange"] = 0xffa500;
- colors["orangered"] = 0xff4500;
- colors["orchid"] = 0xda70d6;
- colors["palegoldenrod"] = 0xeee8aa;
- colors["palegreen"] = 0x98fb98;
- colors["paleturquoise"] = 0xafeeee;
- colors["palevioletred"] = 0xdb7093;
- colors["papayawhip"] = 0xffefd5;
- colors["peachpuff"] = 0xffdab9;
- colors["peru"] = 0xcd853f;
- colors["pink"] = 0xffc0cb;
- colors["plum"] = 0xdda0dd;
- colors["powderblue"] = 0xb0e0e6;
- colors["purple"] = 0x800080;
- colors["red"] = 0xff0000;
- colors["rosybrown"] = 0xbc8f8f;
- colors["royalblue"] = 0x4169e1;
- colors["saddlebrown"] = 0x8b4513;
- colors["salmon"] = 0xfa8072;
- colors["sandybrown"] = 0xf4a460;
- colors["seagreen"] = 0x2e8b57;
- colors["seashell"] = 0xfff5ee;
- colors["sienna"] = 0xa0522d;
- colors["silver"] = 0xc0c0c0;
- colors["skyblue"] = 0x87ceeb;
- colors["slateblue"] = 0x6a5acd;
- colors["slategray"] = 0x708090;
- colors["slategrey"] = 0x708090;
- colors["snow"] = 0xfffafa;
- colors["springgreen"] = 0x00ff7f;
- colors["steelblue"] = 0x4682b4;
- colors["tan"] = 0xd2b48c;
- colors["teal"] = 0x008080;
- colors["thistle"] = 0xd8bfd8;
- colors["tomato"] = 0xff6347;
- colors["turquoise"] = 0x40e0d0;
- colors["violet"] = 0xee82ee;
- colors["wheat"] = 0xf5deb3;
- colors["white"] = 0xffffff;
- colors["whitesmoke"] = 0xf5f5f5;
- colors["yellow"] = 0xffff00;
- colors["yellowgreen"] = 0x9acd32;
-
-}
-
-static const ColorContainer named_colors;
-
static bool parseNamedColorString(const std::string &value, video::SColor &color)
{
std::string color_name;
@@ -570,9 +544,8 @@ static bool parseNamedColorString(const std::string &value, video::SColor &color
color_name = lowercase(color_name);
- std::map<const std::string, unsigned>::const_iterator it;
- it = named_colors.colors.find(color_name);
- if (it == named_colors.colors.end())
+ auto it = s_named_colors.find(color_name);
+ if (it == s_named_colors.end())
return false;
u32 color_temp = it->second;
@@ -580,21 +553,26 @@ static bool parseNamedColorString(const std::string &value, video::SColor &color
/* An empty string for alpha is ok (none of the color table entries
* have an alpha value either). Color strings without an alpha specified
* are interpreted as fully opaque
- *
- * For named colors the supplied alpha string (representing a hex value)
- * must be exactly two digits. For example: colorname#08
*/
if (!alpha_string.empty()) {
- if (alpha_string.length() != 2)
- return false;
-
- unsigned char d1, d2;
- if (!hex_digit_decode(alpha_string.at(0), d1)
- || !hex_digit_decode(alpha_string.at(1), d2))
+ if (alpha_string.size() == 1) {
+ u8 d;
+ if (!hex_digit_decode(alpha_string[0], d))
+ return false;
+
+ color_temp |= ((d & 0xf) << 4 | (d & 0xf)) << 24;
+ } else if (alpha_string.size() == 2) {
+ u8 d1, d2;
+ if (!hex_digit_decode(alpha_string[0], d1)
+ || !hex_digit_decode(alpha_string[1], d2))
+ return false;
+
+ color_temp |= ((d1 & 0xf) << 4 | (d2 & 0xf)) << 24;
+ } else {
return false;
- color_temp |= ((d1 & 0xf) << 4 | (d2 & 0xf)) << 24;
+ }
} else {
- color_temp |= 0xff << 24; // Fully opaque
+ color_temp |= 0xff << 24; // Fully opaque
}
color = video::SColor(color_temp);
@@ -602,6 +580,22 @@ static bool parseNamedColorString(const std::string &value, video::SColor &color
return true;
}
+bool parseColorString(const std::string &value, video::SColor &color, bool quiet,
+ unsigned char default_alpha)
+{
+ bool success;
+
+ if (value[0] == '#')
+ success = parseHexColorString(value, color, default_alpha);
+ else
+ success = parseNamedColorString(value, color);
+
+ if (!success && !quiet)
+ errorstream << "Invalid color: \"" << value << "\"" << std::endl;
+
+ return success;
+}
+
void str_replace(std::string &str, char from, char to)
{
std::replace(str.begin(), str.end(), from, to);
@@ -893,3 +887,19 @@ std::string sanitizeDirName(const std::string &str, const std::string &optional_
return wide_to_utf8(safe_name);
}
+
+
+void safe_print_string(std::ostream &os, const std::string &str)
+{
+ std::ostream::fmtflags flags = os.flags();
+ os << std::hex;
+ for (const char c : str) {
+ if (IS_ASCII_PRINTABLE_CHAR(c) || IS_UTF8_MULTB_START(c) ||
+ IS_UTF8_MULTB_INNER(c) || c == '\n' || c == '\t') {
+ os << c;
+ } else {
+ os << '<' << std::setw(2) << (int)c << '>';
+ }
+ }
+ os.setf(flags);
+}
diff --git a/src/util/string.h b/src/util/string.h
index d4afcaec8..8a9e83f22 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -661,24 +661,49 @@ inline const char *bool_to_cstr(bool val)
return val ? "true" : "false";
}
+/**
+ * Converts a duration in seconds to a pretty-printed duration in
+ * days, hours, minutes and seconds.
+ *
+ * @param sec duration in seconds
+ * @return pretty-printed duration
+ */
inline const std::string duration_to_string(int sec)
{
+ std::ostringstream ss;
+ const char *neg = "";
+ if (sec < 0) {
+ sec = -sec;
+ neg = "-";
+ }
+ int total_sec = sec;
int min = sec / 60;
sec %= 60;
int hour = min / 60;
min %= 60;
+ int day = hour / 24;
+ hour %= 24;
+
+ if (day > 0) {
+ ss << neg << day << "d";
+ if (hour > 0 || min > 0 || sec > 0)
+ ss << " ";
+ }
- std::stringstream ss;
if (hour > 0) {
- ss << hour << "h ";
+ ss << neg << hour << "h";
+ if (min > 0 || sec > 0)
+ ss << " ";
}
if (min > 0) {
- ss << min << "m ";
+ ss << neg << min << "min";
+ if (sec > 0)
+ ss << " ";
}
- if (sec > 0) {
- ss << sec << "s ";
+ if (sec > 0 || total_sec == 0) {
+ ss << neg << sec << "s";
}
return ss.str();
@@ -728,3 +753,11 @@ inline irr::core::stringw utf8_to_stringw(const std::string &input)
* 2. Remove 'unsafe' characters from the name by replacing them with '_'
*/
std::string sanitizeDirName(const std::string &str, const std::string &optional_prefix);
+
+/**
+ * Prints a sanitized version of a string without control characters.
+ * '\t' and '\n' are allowed, as are UTF-8 control characters (e.g. RTL).
+ * ASCII control characters are replaced with their hex encoding in angle
+ * brackets (e.g. "a\x1eb" -> "a<1e>b").
+ */
+void safe_print_string(std::ostream &os, const std::string &str);