diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/basic_macros.h | 8 | ||||
-rw-r--r-- | src/util/enriched_string.cpp | 2 | ||||
-rw-r--r-- | src/util/enriched_string.h | 2 | ||||
-rw-r--r-- | src/util/ieee_float.cpp | 2 | ||||
-rw-r--r-- | src/util/metricsbackend.cpp | 96 | ||||
-rw-r--r-- | src/util/metricsbackend.h | 84 | ||||
-rw-r--r-- | src/util/numeric.cpp | 11 | ||||
-rw-r--r-- | src/util/numeric.h | 23 | ||||
-rw-r--r-- | src/util/pointer.h | 13 | ||||
-rw-r--r-- | src/util/serialize.cpp | 220 | ||||
-rw-r--r-- | src/util/serialize.h | 10 | ||||
-rw-r--r-- | src/util/srp.cpp | 4 | ||||
-rw-r--r-- | src/util/stream.h | 70 | ||||
-rw-r--r-- | src/util/string.cpp | 55 | ||||
-rw-r--r-- | src/util/string.h | 4 |
15 files changed, 365 insertions, 239 deletions
diff --git a/src/util/basic_macros.h b/src/util/basic_macros.h index 334e342e0..3910c6185 100644 --- a/src/util/basic_macros.h +++ b/src/util/basic_macros.h @@ -29,13 +29,19 @@ with this program; if not, write to the Free Software Foundation, Inc., #define CONTAINS(c, v) (std::find((c).begin(), (c).end(), (v)) != (c).end()) // To disable copy constructors and assignment operations for some class -// 'Foobar', add the macro DISABLE_CLASS_COPY(Foobar) as a private member. +// 'Foobar', add the macro DISABLE_CLASS_COPY(Foobar) in the class definition. // Note this also disables copying for any classes derived from 'Foobar' as well // as classes having a 'Foobar' member. #define DISABLE_CLASS_COPY(C) \ C(const C &) = delete; \ C &operator=(const C &) = delete; +// If you have used DISABLE_CLASS_COPY with a class but still want to permit moving +// use this macro to add the default move constructors back. +#define ALLOW_CLASS_MOVE(C) \ + C(C &&other) = default; \ + C &operator=(C &&) = default; + #ifndef _MSC_VER #define UNUSED_ATTRIBUTE __attribute__ ((unused)) #else diff --git a/src/util/enriched_string.cpp b/src/util/enriched_string.cpp index b1f95215e..941f8b08d 100644 --- a/src/util/enriched_string.cpp +++ b/src/util/enriched_string.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2013 xyz, Ilya Zhuravlev <whatever@xyz.is> -Copyright (C) 2016 Nore, Nathanaël Courant <nore@mesecons.net> +Copyright (C) 2016 Nore, Nathanaëlle Courant <nore@mesecons.net> 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 diff --git a/src/util/enriched_string.h b/src/util/enriched_string.h index 16a0eef74..4e249eac5 100644 --- a/src/util/enriched_string.h +++ b/src/util/enriched_string.h @@ -1,6 +1,6 @@ /* Copyright (C) 2013 xyz, Ilya Zhuravlev <whatever@xyz.is> -Copyright (C) 2016 Nore, Nathanaël Courant <nore@mesecons.net> +Copyright (C) 2016 Nore, Nathanaëlle Courant <nore@mesecons.net> 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 diff --git a/src/util/ieee_float.cpp b/src/util/ieee_float.cpp index 887258921..b73763c55 100644 --- a/src/util/ieee_float.cpp +++ b/src/util/ieee_float.cpp @@ -39,7 +39,7 @@ f32 u32Tof32Slow(u32 i) if (exp == 0xFF) { // Inf/NaN if (imant == 0) { - if (std::numeric_limits<f32>::has_infinity) + if (std::numeric_limits<f32>::has_infinity) return sign ? -std::numeric_limits<f32>::infinity() : std::numeric_limits<f32>::infinity(); return sign ? std::numeric_limits<f32>::max() : diff --git a/src/util/metricsbackend.cpp b/src/util/metricsbackend.cpp index 4454557a3..63b49ac0a 100644 --- a/src/util/metricsbackend.cpp +++ b/src/util/metricsbackend.cpp @@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "metricsbackend.h" +#include "util/thread.h" #if USE_PROMETHEUS #include <prometheus/exposer.h> #include <prometheus/registry.h> @@ -27,18 +28,78 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #endif +/* Plain implementation */ + +class SimpleMetricCounter : public MetricCounter +{ +public: + SimpleMetricCounter() : MetricCounter(), m_counter(0.0) {} + + virtual ~SimpleMetricCounter() {} + + void increment(double number) override + { + MutexAutoLock lock(m_mutex); + m_counter += number; + } + double get() const override + { + MutexAutoLock lock(m_mutex); + return m_counter; + } + +private: + mutable std::mutex m_mutex; + double m_counter; +}; + +class SimpleMetricGauge : public MetricGauge +{ +public: + SimpleMetricGauge() : MetricGauge(), m_gauge(0.0) {} + + virtual ~SimpleMetricGauge() {} + + void increment(double number) override + { + MutexAutoLock lock(m_mutex); + m_gauge += number; + } + void decrement(double number) override + { + MutexAutoLock lock(m_mutex); + m_gauge -= number; + } + void set(double number) override + { + MutexAutoLock lock(m_mutex); + m_gauge = number; + } + double get() const override + { + MutexAutoLock lock(m_mutex); + return m_gauge; + } + +private: + mutable std::mutex m_mutex; + double m_gauge; +}; + MetricCounterPtr MetricsBackend::addCounter( - const std::string &name, const std::string &help_str) + const std::string &name, const std::string &help_str, Labels labels) { - return std::make_shared<SimpleMetricCounter>(name, help_str); + return std::make_shared<SimpleMetricCounter>(); } MetricGaugePtr MetricsBackend::addGauge( - const std::string &name, const std::string &help_str) + const std::string &name, const std::string &help_str, Labels labels) { - return std::make_shared<SimpleMetricGauge>(name, help_str); + return std::make_shared<SimpleMetricGauge>(); } +/* Prometheus backend */ + #if USE_PROMETHEUS class PrometheusMetricCounter : public MetricCounter @@ -47,13 +108,14 @@ public: PrometheusMetricCounter() = delete; PrometheusMetricCounter(const std::string &name, const std::string &help_str, + MetricsBackend::Labels labels, std::shared_ptr<prometheus::Registry> registry) : MetricCounter(), m_family(prometheus::BuildCounter() .Name(name) .Help(help_str) .Register(*registry)), - m_counter(m_family.Add({})) + m_counter(m_family.Add(labels)) { } @@ -73,13 +135,14 @@ public: PrometheusMetricGauge() = delete; PrometheusMetricGauge(const std::string &name, const std::string &help_str, + MetricsBackend::Labels labels, std::shared_ptr<prometheus::Registry> registry) : MetricGauge(), m_family(prometheus::BuildGauge() .Name(name) .Help(help_str) .Register(*registry)), - m_gauge(m_family.Add({})) + m_gauge(m_family.Add(labels)) { } @@ -99,8 +162,7 @@ class PrometheusMetricsBackend : public MetricsBackend { public: PrometheusMetricsBackend(const std::string &addr) : - MetricsBackend(), m_exposer(std::unique_ptr<prometheus::Exposer>( - new prometheus::Exposer(addr))), + MetricsBackend(), m_exposer(std::make_unique<prometheus::Exposer>(addr)), m_registry(std::make_shared<prometheus::Registry>()) { m_exposer->RegisterCollectable(m_registry); @@ -108,10 +170,12 @@ public: virtual ~PrometheusMetricsBackend() {} - virtual MetricCounterPtr addCounter( - const std::string &name, const std::string &help_str); - virtual MetricGaugePtr addGauge( - const std::string &name, const std::string &help_str); + MetricCounterPtr addCounter( + const std::string &name, const std::string &help_str, + Labels labels = {}) override; + MetricGaugePtr addGauge( + const std::string &name, const std::string &help_str, + Labels labels = {}) override; private: std::unique_ptr<prometheus::Exposer> m_exposer; @@ -119,15 +183,15 @@ private: }; MetricCounterPtr PrometheusMetricsBackend::addCounter( - const std::string &name, const std::string &help_str) + const std::string &name, const std::string &help_str, Labels labels) { - return std::make_shared<PrometheusMetricCounter>(name, help_str, m_registry); + return std::make_shared<PrometheusMetricCounter>(name, help_str, labels, m_registry); } MetricGaugePtr PrometheusMetricsBackend::addGauge( - const std::string &name, const std::string &help_str) + const std::string &name, const std::string &help_str, Labels labels) { - return std::make_shared<PrometheusMetricGauge>(name, help_str, m_registry); + return std::make_shared<PrometheusMetricGauge>(name, help_str, labels, m_registry); } MetricsBackend *createPrometheusMetricsBackend() diff --git a/src/util/metricsbackend.h b/src/util/metricsbackend.h index c37306392..644c73325 100644 --- a/src/util/metricsbackend.h +++ b/src/util/metricsbackend.h @@ -19,8 +19,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #include <memory> +#include <string> +#include <utility> #include "config.h" -#include "util/thread.h" class MetricCounter { @@ -35,38 +36,6 @@ public: typedef std::shared_ptr<MetricCounter> MetricCounterPtr; -class SimpleMetricCounter : public MetricCounter -{ -public: - SimpleMetricCounter() = delete; - - virtual ~SimpleMetricCounter() {} - - SimpleMetricCounter(const std::string &name, const std::string &help_str) : - MetricCounter(), m_name(name), m_help_str(help_str), - m_counter(0.0) - { - } - - virtual void increment(double number) - { - MutexAutoLock lock(m_mutex); - m_counter += number; - } - virtual double get() const - { - MutexAutoLock lock(m_mutex); - return m_counter; - } - -private: - std::string m_name; - std::string m_help_str; - - mutable std::mutex m_mutex; - double m_counter; -}; - class MetricGauge { public: @@ -81,47 +50,6 @@ public: typedef std::shared_ptr<MetricGauge> MetricGaugePtr; -class SimpleMetricGauge : public MetricGauge -{ -public: - SimpleMetricGauge() = delete; - - SimpleMetricGauge(const std::string &name, const std::string &help_str) : - MetricGauge(), m_name(name), m_help_str(help_str), m_gauge(0.0) - { - } - - virtual ~SimpleMetricGauge() {} - - virtual void increment(double number) - { - MutexAutoLock lock(m_mutex); - m_gauge += number; - } - virtual void decrement(double number) - { - MutexAutoLock lock(m_mutex); - m_gauge -= number; - } - virtual void set(double number) - { - MutexAutoLock lock(m_mutex); - m_gauge = number; - } - virtual double get() const - { - MutexAutoLock lock(m_mutex); - return m_gauge; - } - -private: - std::string m_name; - std::string m_help_str; - - mutable std::mutex m_mutex; - double m_gauge; -}; - class MetricsBackend { public: @@ -129,10 +57,14 @@ public: virtual ~MetricsBackend() {} + typedef std::initializer_list<std::pair<const std::string, std::string>> Labels; + virtual MetricCounterPtr addCounter( - const std::string &name, const std::string &help_str); + const std::string &name, const std::string &help_str, + Labels labels = {}); virtual MetricGaugePtr addGauge( - const std::string &name, const std::string &help_str); + const std::string &name, const std::string &help_str, + Labels labels = {}); }; #if USE_PROMETHEUS diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp index 702ddce95..aa3bb843d 100644 --- a/src/util/numeric.cpp +++ b/src/util/numeric.cpp @@ -46,11 +46,22 @@ void myrand_bytes(void *out, size_t len) g_pcgrand.bytes(out, len); } +float myrand_float() +{ + u32 uv = g_pcgrand.next(); + return (float)uv / (float)U32_MAX; +} + int myrand_range(int min, int max) { return g_pcgrand.range(min, max); } +float myrand_range(float min, float max) +{ + return (max-min) * myrand_float() + min; +} + /* 64-bit unaligned version of MurmurHash diff --git a/src/util/numeric.h b/src/util/numeric.h index 32a6f4312..265046a63 100644 --- a/src/util/numeric.h +++ b/src/util/numeric.h @@ -223,6 +223,8 @@ u32 myrand(); void mysrand(unsigned int seed); void myrand_bytes(void *out, size_t len); int myrand_range(int min, int max); +float myrand_range(float min, float max); +float myrand_float(); /* Miscellaneous functions @@ -446,3 +448,24 @@ inline irr::video::SColor multiplyColorValue(const irr::video::SColor &color, fl core::clamp<u32>(color.getGreen() * mod, 0, 255), core::clamp<u32>(color.getBlue() * mod, 0, 255)); } + +template <typename T> inline T numericAbsolute(T v) { return v < 0 ? T(-v) : v; } +template <typename T> inline T numericSign(T v) { return T(v < 0 ? -1 : (v == 0 ? 0 : 1)); } + +inline v3f vecAbsolute(v3f v) +{ + return v3f( + numericAbsolute(v.X), + numericAbsolute(v.Y), + numericAbsolute(v.Z) + ); +} + +inline v3f vecSign(v3f v) +{ + return v3f( + numericSign(v.X), + numericSign(v.Y), + numericSign(v.Z) + ); +} diff --git a/src/util/pointer.h b/src/util/pointer.h index 245ac85bf..b659cea0e 100644 --- a/src/util/pointer.h +++ b/src/util/pointer.h @@ -45,7 +45,7 @@ public: Buffer() { m_size = 0; - data = NULL; + data = nullptr; } Buffer(unsigned int size) { @@ -53,7 +53,7 @@ public: if(size != 0) data = new T[size]; else - data = NULL; + data = nullptr; } // Disable class copy @@ -82,7 +82,7 @@ public: memcpy(data, t, size); } else - data = NULL; + data = nullptr; } ~Buffer() @@ -166,7 +166,7 @@ public: if(m_size != 0) data = new T[m_size]; else - data = NULL; + data = nullptr; refcount = new unsigned int; memset(data,0,sizeof(T)*m_size); (*refcount) = 1; @@ -201,7 +201,7 @@ public: memcpy(data, t, m_size); } else - data = NULL; + data = nullptr; refcount = new unsigned int; (*refcount) = 1; } @@ -216,7 +216,7 @@ public: memcpy(data, *buffer, buffer.getSize()); } else - data = NULL; + data = nullptr; refcount = new unsigned int; (*refcount) = 1; } @@ -256,3 +256,4 @@ private: unsigned int m_size; unsigned int *refcount; }; + diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp index 281061229..ee46fd941 100644 --- a/src/util/serialize.cpp +++ b/src/util/serialize.cpp @@ -18,15 +18,14 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "serialize.h" -#include "pointer.h" #include "porting.h" #include "util/string.h" +#include "util/hex.h" #include "exceptions.h" #include "irrlichttypes.h" -#include <sstream> -#include <iomanip> -#include <vector> +#include <iostream> +#include <cassert> FloatType g_serialize_f32_type = FLOATTYPE_UNKNOWN; @@ -120,121 +119,148 @@ std::string deSerializeString32(std::istream &is) } //// -//// JSON +//// JSON-like strings //// std::string serializeJsonString(const std::string &plain) { - std::ostringstream os(std::ios::binary); - os << "\""; + std::string tmp; + + tmp.reserve(plain.size() + 2); + tmp.push_back('"'); for (char c : plain) { switch (c) { case '"': - os << "\\\""; + tmp.append("\\\""); break; case '\\': - os << "\\\\"; - break; - case '/': - os << "\\/"; + tmp.append("\\\\"); break; case '\b': - os << "\\b"; + tmp.append("\\b"); break; case '\f': - os << "\\f"; + tmp.append("\\f"); break; case '\n': - os << "\\n"; + tmp.append("\\n"); break; case '\r': - os << "\\r"; + tmp.append("\\r"); break; case '\t': - os << "\\t"; + tmp.append("\\t"); break; default: { if (c >= 32 && c <= 126) { - os << c; + tmp.push_back(c); } else { - u32 cnum = (u8)c; - os << "\\u" << std::hex << std::setw(4) - << std::setfill('0') << cnum; + // We pretend that Unicode codepoints map to bytes (they don't) + u8 cnum = static_cast<u8>(c); + tmp.append("\\u00"); + tmp.push_back(hex_chars[cnum >> 4]); + tmp.push_back(hex_chars[cnum & 0xf]); } break; } } } - os << "\""; - return os.str(); + tmp.push_back('"'); + return tmp; +} + +static void deSerializeJsonString(std::string &s) +{ + assert(s.size() >= 2); + assert(s.front() == '"' && s.back() == '"'); + + size_t w = 0; // write index + size_t i = 1; // read index + const size_t len = s.size() - 1; // string length with trailing quote removed + + while (i < len) { + char c = s[i++]; + assert(c != '"'); + + if (c != '\\') { + s[w++] = c; + continue; + } + + if (i >= len) + throw SerializationError("JSON string ended prematurely"); + char c2 = s[i++]; + switch (c2) { + case 'b': + s[w++] = '\b'; + break; + case 'f': + s[w++] = '\f'; + break; + case 'n': + s[w++] = '\n'; + break; + case 'r': + s[w++] = '\r'; + break; + case 't': + s[w++] = '\t'; + break; + case 'u': { + if (i + 3 >= len) + throw SerializationError("JSON string ended prematurely"); + unsigned char v[4] = {}; + for (int j = 0; j < 4; j++) + hex_digit_decode(s[i+j], v[j]); + i += 4; + u32 hexnumber = (v[0] << 12) | (v[1] << 8) | (v[2] << 4) | v[3]; + // Note that this does not work for anything other than ASCII + // but these functions do not actually interact with real JSON input. + s[w++] = (int) hexnumber; + break; + } + default: + s[w++] = c2; + break; + } + } + + assert(w <= i && i <= len); + // Truncate string to current write index + s.resize(w); } std::string deSerializeJsonString(std::istream &is) { - std::ostringstream os(std::ios::binary); - char c, c2; + std::string tmp; + char c; + bool was_backslash = false; // Parse initial doublequote - is >> c; + c = is.get(); if (c != '"') throw SerializationError("JSON string must start with doublequote"); + tmp.push_back(c); - // Parse characters + // Grab the entire json string for (;;) { c = is.get(); if (is.eof()) throw SerializationError("JSON string ended prematurely"); - if (c == '"') { - return os.str(); - } - - if (c == '\\') { - c2 = is.get(); - if (is.eof()) - throw SerializationError("JSON string ended prematurely"); - switch (c2) { - case 'b': - os << '\b'; - break; - case 'f': - os << '\f'; - break; - case 'n': - os << '\n'; - break; - case 'r': - os << '\r'; - break; - case 't': - os << '\t'; - break; - case 'u': { - int hexnumber; - char hexdigits[4 + 1]; - - is.read(hexdigits, 4); - if (is.eof()) - throw SerializationError("JSON string ended prematurely"); - hexdigits[4] = 0; - - std::istringstream tmp_is(hexdigits, std::ios::binary); - tmp_is >> std::hex >> hexnumber; - os << (char)hexnumber; - break; - } - default: - os << c2; - break; - } - } else { - os << c; - } + tmp.push_back(c); + if (was_backslash) + was_backslash = false; + else if (c == '\\') + was_backslash = true; + else if (c == '"') + break; // found end of string } - return os.str(); + deSerializeJsonString(tmp); + return tmp; } std::string serializeJsonStringIfNeeded(const std::string &s) @@ -248,41 +274,21 @@ std::string serializeJsonStringIfNeeded(const std::string &s) std::string deSerializeJsonStringIfNeeded(std::istream &is) { - 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; - for (;;) { - char c = is.get(); - if (is.eof()) - break; - - if (expect_initial_quote && c == '"') { - tmp_os << c; - is_json = true; - } else if(is_json) { - tmp_os << c; - if (was_backslash) - was_backslash = false; - else if (c == '\\') - was_backslash = true; - else if (c == '"') - break; // Found end of string - } else { - if (c == ' ') { - // Found end of word - is.unget(); - break; - } - - tmp_os << c; - } - expect_initial_quote = false; - } - if (is_json) { - return deSerializeJsonString(tmp_os); + // Check for initial quote + char c = is.peek(); + if (is.eof()) + return ""; + + if (c == '"') { + // json string: defer to the right implementation + return deSerializeJsonString(is); } - return tmp_os.str(); + // not a json string: + std::string tmp; + std::getline(is, tmp, ' '); + if (!is.eof()) + is.unget(); // we hit a space, put it back + return tmp; } diff --git a/src/util/serialize.h b/src/util/serialize.h index 15bdd050d..4dc1a54c6 100644 --- a/src/util/serialize.h +++ b/src/util/serialize.h @@ -439,6 +439,16 @@ MAKE_STREAM_WRITE_FXN(video::SColor, ARGB8, 4); //// More serialization stuff //// +inline float clampToF1000(float v) +{ + return core::clamp(v, F1000_MIN, F1000_MAX); +} + +inline v3f clampToF1000(v3f v) +{ + return {clampToF1000(v.X), clampToF1000(v.Y), clampToF1000(v.Z)}; +} + // Creates a string with the length as the first two bytes std::string serializeString16(const std::string &plain); diff --git a/src/util/srp.cpp b/src/util/srp.cpp index ceb2fef9e..daa7f332b 100644 --- a/src/util/srp.cpp +++ b/src/util/srp.cpp @@ -354,7 +354,7 @@ static size_t hash_length(SRP_HashAlgorithm alg) case SRP_SHA384: return SHA384_DIGEST_LENGTH; case SRP_SHA512: return SHA512_DIGEST_LENGTH; */ - default: return -1; + default: return 0; }; } // clang-format on @@ -422,7 +422,7 @@ static SRP_Result H_nn( } static SRP_Result H_ns(mpz_t result, SRP_HashAlgorithm alg, const unsigned char *n, - size_t len_n, const unsigned char *bytes, uint32_t len_bytes) + size_t len_n, const unsigned char *bytes, size_t len_bytes) { unsigned char buff[SHA512_DIGEST_LENGTH]; size_t nbytes = len_n + len_bytes; diff --git a/src/util/stream.h b/src/util/stream.h new file mode 100644 index 000000000..2e61b46d2 --- /dev/null +++ b/src/util/stream.h @@ -0,0 +1,70 @@ +/* +Minetest +Copyright (C) 2022 Minetest Authors + +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 <iostream> +#include <string> +#include <functional> + +template<int BufferLength, typename Emitter = std::function<void(const std::string &)> > +class StringStreamBuffer : public std::streambuf { +public: + StringStreamBuffer(Emitter emitter) : m_emitter(emitter) { + buffer_index = 0; + } + + int overflow(int c) { + push_back(c); + return c; + } + + void push_back(char c) { + if (c == '\n' || c == '\r') { + if (buffer_index) + m_emitter(std::string(buffer, buffer_index)); + buffer_index = 0; + } else { + buffer[buffer_index++] = c; + if (buffer_index >= BufferLength) { + m_emitter(std::string(buffer, buffer_index)); + buffer_index = 0; + } + } + } + + std::streamsize xsputn(const char *s, std::streamsize n) { + for (int i = 0; i < n; ++i) + push_back(s[i]); + return n; + } +private: + Emitter m_emitter; + char buffer[BufferLength]; + int buffer_index; +}; + +class DummyStreamBuffer : public std::streambuf { + int overflow(int c) { + return c; + } + std::streamsize xsputn(const char *s, std::streamsize n) { + return n; + } +}; diff --git a/src/util/string.cpp b/src/util/string.cpp index bc4664997..778e4d1e1 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -39,16 +39,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <windows.h> #endif -#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 - #ifndef _WIN32 static bool convert(const char *to, const char *from, char *outbuf, @@ -56,11 +46,7 @@ static bool convert(const char *to, const char *from, char *outbuf, { iconv_t cd = iconv_open(to, from); -#ifdef BSD_ICONV_USED - const char *inbuf_ptr = inbuf; -#else char *inbuf_ptr = inbuf; -#endif char *outbuf_ptr = outbuf; size_t *inbuf_left_ptr = &inbuf_size; @@ -84,7 +70,7 @@ 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__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) // NetBSD does not allow "WCHAR_T" as a charset input to iconv. #include <sys/endian.h> #if BYTE_ORDER == BIG_ENDIAN @@ -107,8 +93,8 @@ std::wstring utf8_to_wide(const std::string &input) std::wstring out; out.resize(outbuf_size / sizeof(wchar_t)); -#if defined(__ANDROID__) || defined(__NetBSD__) - SANITY_CHECK(sizeof(wchar_t) == 4); +#if defined(__ANDROID__) || defined(__NetBSD__) || defined(__OpenBSD__) + static_assert(sizeof(wchar_t) == 4, "Unexpected wide char size"); #endif char *outbuf = reinterpret_cast<char*>(&out[0]); @@ -494,6 +480,7 @@ const static std::unordered_map<std::string, u32> s_named_colors = { {"plum", 0xdda0dd}, {"powderblue", 0xb0e0e6}, {"purple", 0x800080}, + {"rebeccapurple", 0x663399}, {"red", 0xff0000}, {"rosybrown", 0xbc8f8f}, {"royalblue", 0x4169e1}, @@ -821,9 +808,11 @@ std::wstring translate_string(const std::wstring &s) #endif } -static const std::array<std::wstring, 22> disallowed_dir_names = { +static const std::array<std::wstring, 30> disallowed_dir_names = { // Problematic filenames from here: // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#file-and-directory-names + // Plus undocumented values from here: + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html L"CON", L"PRN", L"AUX", @@ -837,6 +826,9 @@ static const std::array<std::wstring, 22> disallowed_dir_names = { L"COM7", L"COM8", L"COM9", + L"COM\u00B2", + L"COM\u00B3", + L"COM\u00B9", L"LPT1", L"LPT2", L"LPT3", @@ -846,6 +838,11 @@ static const std::array<std::wstring, 22> disallowed_dir_names = { L"LPT7", L"LPT8", L"LPT9", + L"LPT\u00B2", + L"LPT\u00B3", + L"LPT\u00B9", + L"CONIN$", + L"CONOUT$", }; /** @@ -853,12 +850,7 @@ static const std::array<std::wstring, 22> disallowed_dir_names = { */ 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); @@ -870,7 +862,18 @@ std::string sanitizeDirName(const std::string &str, const std::string &optional_ } } - for (unsigned long i = 0; i < safe_name.length(); i++) { + // Replace leading and trailing spaces with underscores. + size_t start = safe_name.find_first_not_of(L' '); + size_t end = safe_name.find_last_not_of(L' '); + if (start == std::wstring::npos || end == std::wstring::npos) + start = end = safe_name.size(); + for (size_t i = 0; i < start; i++) + safe_name[i] = L'_'; + for (size_t i = end + 1; i < safe_name.size(); i++) + safe_name[i] = L'_'; + + // Replace other disallowed characters with underscores + for (size_t i = 0; i < safe_name.length(); i++) { bool is_valid = true; // Unlikely, but control characters should always be blacklisted @@ -882,7 +885,7 @@ std::string sanitizeDirName(const std::string &str, const std::string &optional_ } if (!is_valid) - safe_name[i] = '_'; + safe_name[i] = L'_'; } return wide_to_utf8(safe_name); diff --git a/src/util/string.h b/src/util/string.h index d73540ceb..aa4329f2f 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -410,7 +410,7 @@ DEFINE_STD_TOSTRING_FLOATINGPOINT(long double) template <typename T> inline wstring to_wstring(T val) { - return utf8_to_wide(to_string(val)); + return utf8_to_wide(to_string(val)); } } #endif @@ -749,7 +749,7 @@ inline irr::core::stringw utf8_to_stringw(const std::string &input) /** * 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 + * 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); |