summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/basic_macros.h8
-rw-r--r--src/util/enriched_string.cpp2
-rw-r--r--src/util/enriched_string.h2
-rw-r--r--src/util/ieee_float.cpp2
-rw-r--r--src/util/metricsbackend.cpp96
-rw-r--r--src/util/metricsbackend.h84
-rw-r--r--src/util/numeric.cpp11
-rw-r--r--src/util/numeric.h23
-rw-r--r--src/util/pointer.h13
-rw-r--r--src/util/serialize.cpp220
-rw-r--r--src/util/serialize.h10
-rw-r--r--src/util/srp.cpp4
-rw-r--r--src/util/stream.h70
-rw-r--r--src/util/string.cpp55
-rw-r--r--src/util/string.h4
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);