Introduce std::string_view into wider use (#14368)

This commit is contained in:
sfan5 2024-02-17 15:35:33 +01:00 committed by GitHub
parent fa47af737f
commit 6ca214fefc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
74 changed files with 501 additions and 456 deletions

@ -5459,7 +5459,7 @@ Utilities
You can use `colorspec_to_bytes` to generate raw RGBA values. You can use `colorspec_to_bytes` to generate raw RGBA values.
Palettes are not supported at the moment. Palettes are not supported at the moment.
You may use this to procedurally generate textures during server init. You may use this to procedurally generate textures during server init.
* `minetest.urlencode(str)`: Encodes non-unreserved URI characters by a * `minetest.urlencode(str)`: Encodes reserved URI characters by a
percent sign followed by two hex digits. See percent sign followed by two hex digits. See
[RFC 3986, section 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3). [RFC 3986, section 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3).

@ -133,6 +133,12 @@ local function test_compress()
end end
unittests.register("test_compress", test_compress) unittests.register("test_compress", test_compress)
local function test_urlencode()
-- checks that API code handles null bytes
assert(core.urlencode("foo\000bar!") == "foo%00bar%21")
end
unittests.register("test_urlencode", test_urlencode)
local function test_game_info() local function test_game_info()
local info = minetest.get_game_info() local info = minetest.get_game_info()
local game_conf = Settings(info.path .. "/game.conf") local game_conf = Settings(info.path .. "/game.conf")

@ -46,7 +46,7 @@ enum ActiveObjectType {
struct ActiveObjectMessage struct ActiveObjectMessage
{ {
ActiveObjectMessage(u16 id_, bool reliable_=true, const std::string &data_ = "") : ActiveObjectMessage(u16 id_, bool reliable_=true, std::string_view data_ = "") :
id(id_), id(id_),
reliable(reliable_), reliable(reliable_),
datastring(data_) datastring(data_)

@ -577,6 +577,7 @@ void ChatPrompt::historyNext()
void ChatPrompt::nickCompletion(const std::set<std::string> &names, bool backwards) void ChatPrompt::nickCompletion(const std::set<std::string> &names, bool backwards)
{ {
const std::wstring_view line(getLineRef());
// Two cases: // Two cases:
// (a) m_nick_completion_start == m_nick_completion_end == 0 // (a) m_nick_completion_start == m_nick_completion_end == 0
// Then no previous nick completion is active. // Then no previous nick completion is active.
@ -586,7 +587,6 @@ void ChatPrompt::nickCompletion(const std::set<std::string> &names, bool backwar
// m_nick_completion_start..m_nick_completion_end are the // m_nick_completion_start..m_nick_completion_end are the
// interval where the originally used prefix was. Cycle // interval where the originally used prefix was. Cycle
// through the list of completions of that prefix. // through the list of completions of that prefix.
const std::wstring &line = getLineRef();
u32 prefix_start = m_nick_completion_start; u32 prefix_start = m_nick_completion_start;
u32 prefix_end = m_nick_completion_end; u32 prefix_end = m_nick_completion_end;
bool initial = (prefix_end == 0); bool initial = (prefix_end == 0);
@ -601,7 +601,7 @@ void ChatPrompt::nickCompletion(const std::set<std::string> &names, bool backwar
if (prefix_start == prefix_end) if (prefix_start == prefix_end)
return; return;
} }
std::wstring prefix = line.substr(prefix_start, prefix_end - prefix_start); auto prefix = line.substr(prefix_start, prefix_end - prefix_start);
// find all names that start with the selected prefix // find all names that start with the selected prefix
std::vector<std::wstring> completions; std::vector<std::wstring> completions;
@ -624,7 +624,7 @@ void ChatPrompt::nickCompletion(const std::set<std::string> &names, bool backwar
{ {
while (word_end < line.size() && !iswspace(line[word_end])) while (word_end < line.size() && !iswspace(line[word_end]))
++word_end; ++word_end;
std::wstring word = line.substr(prefix_start, word_end - prefix_start); auto word = line.substr(prefix_start, word_end - prefix_start);
// cycle through completions // cycle through completions
for (u32 i = 0; i < completions.size(); ++i) for (u32 i = 0; i < completions.size(); ++i)
@ -640,7 +640,7 @@ void ChatPrompt::nickCompletion(const std::set<std::string> &names, bool backwar
} }
} }
} }
std::wstring replacement = completions[replacement_index]; const auto &replacement = completions[replacement_index];
if (word_end < line.size() && iswspace(line[word_end])) if (word_end < line.size() && iswspace(line[word_end]))
++word_end; ++word_end;

@ -541,11 +541,9 @@ bool IClientMediaDownloader::checkAndLoad(
// Compute actual checksum of data // Compute actual checksum of data
std::string data_sha1; std::string data_sha1;
{ {
SHA1 data_sha1_calculator; SHA1 ctx;
data_sha1_calculator.addBytes(data.c_str(), data.size()); ctx.addBytes(data);
unsigned char *data_tmpdigest = data_sha1_calculator.getDigest(); data_sha1 = ctx.getDigest();
data_sha1.assign((char*) data_tmpdigest, 20);
free(data_tmpdigest);
} }
// Check that received file matches announced checksum // Check that received file matches announced checksum

@ -67,7 +67,7 @@ bool FileCache::loadByPath(const std::string &path, std::ostream &os)
return !bad; return !bad;
} }
bool FileCache::updateByPath(const std::string &path, const std::string &data) bool FileCache::updateByPath(const std::string &path, std::string_view data)
{ {
createDir(); createDir();
std::ofstream file(path.c_str(), std::ios_base::binary | std::ofstream file(path.c_str(), std::ios_base::binary |
@ -80,13 +80,13 @@ bool FileCache::updateByPath(const std::string &path, const std::string &data)
return false; return false;
} }
file.write(data.c_str(), data.length()); file << data;
file.close(); file.close();
return !file.fail(); return !file.fail();
} }
bool FileCache::update(const std::string &name, const std::string &data) bool FileCache::update(const std::string &name, std::string_view data)
{ {
std::string path = m_dir + DIR_DELIM + name; std::string path = m_dir + DIR_DELIM + name;
return updateByPath(path, data); return updateByPath(path, data);

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <string_view>
class FileCache class FileCache
{ {
@ -31,7 +32,7 @@ public:
*/ */
FileCache(const std::string &dir) : m_dir(dir) {} FileCache(const std::string &dir) : m_dir(dir) {}
bool update(const std::string &name, const std::string &data); bool update(const std::string &name, std::string_view data);
bool load(const std::string &name, std::ostream &os); bool load(const std::string &name, std::ostream &os);
bool exists(const std::string &name); bool exists(const std::string &name);
@ -43,5 +44,5 @@ private:
void createDir(); void createDir();
bool loadByPath(const std::string &path, std::ostream &os); bool loadByPath(const std::string &path, std::ostream &os);
bool updateByPath(const std::string &path, const std::string &data); bool updateByPath(const std::string &path, std::string_view data);
}; };

@ -804,7 +804,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
} }
void dumpShaderProgram(std::ostream &output_stream, void dumpShaderProgram(std::ostream &output_stream,
const std::string &program_type, const std::string &program) const std::string &program_type, std::string_view program)
{ {
output_stream << program_type << " shader program:" << std::endl << output_stream << program_type << " shader program:" << std::endl <<
"----------------------------------" << std::endl; "----------------------------------" << std::endl;

@ -192,4 +192,4 @@ public:
IWritableShaderSource *createShaderSource(); IWritableShaderSource *createShaderSource();
void dumpShaderProgram(std::ostream &output_stream, void dumpShaderProgram(std::ostream &output_stream,
const std::string &program_type, const std::string &program); const std::string &program_type, std::string_view program);

@ -404,7 +404,7 @@ private:
// Generate image based on a string like "stone.png" or "[crack:1:0". // Generate image based on a string like "stone.png" or "[crack:1:0".
// if baseimg is NULL, it is created. Otherwise stuff is made on it. // if baseimg is NULL, it is created. Otherwise stuff is made on it.
// source_image_names is important to determine when to flush the image from a cache (dynamic media) // source_image_names is important to determine when to flush the image from a cache (dynamic media)
bool generateImagePart(std::string part_of_name, video::IImage *& baseimg, std::set<std::string> &source_image_names); bool generateImagePart(std::string_view part_of_name, video::IImage *& baseimg, std::set<std::string> &source_image_names);
/*! Generates an image from a full string like /*! Generates an image from a full string like
* "stone.png^mineral_coal.png^[crack:1:0". * "stone.png^mineral_coal.png^[crack:1:0".
@ -412,7 +412,7 @@ private:
* The returned Image should be dropped. * The returned Image should be dropped.
* source_image_names is important to determine when to flush the image from a cache (dynamic media) * source_image_names is important to determine when to flush the image from a cache (dynamic media)
*/ */
video::IImage* generateImage(const std::string &name, std::set<std::string> &source_image_names); video::IImage* generateImage(std::string_view name, std::set<std::string> &source_image_names);
// Thread-safe cache of what source images are known (true = known) // Thread-safe cache of what source images are known (true = known)
MutexedMap<std::string, bool> m_source_image_existence; MutexedMap<std::string, bool> m_source_image_existence;
@ -593,7 +593,7 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
// Brighten image // Brighten image
void brighten(video::IImage *image); void brighten(video::IImage *image);
// Parse a transform name // Parse a transform name
u32 parseImageTransform(const std::string& s); u32 parseImageTransform(std::string_view s);
// Apply transform to image dimension // Apply transform to image dimension
core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<u32> dim); core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<u32> dim);
// Apply transform to image data // Apply transform to image data
@ -963,7 +963,8 @@ static video::IImage *createInventoryCubeImage(
return result; return result;
} }
video::IImage* TextureSource::generateImage(const std::string &name, std::set<std::string> &source_image_names) video::IImage* TextureSource::generateImage(std::string_view name,
std::set<std::string> &source_image_names)
{ {
// Get the base image // Get the base image
@ -1024,15 +1025,15 @@ video::IImage* TextureSource::generateImage(const std::string &name, std::set<st
according to it according to it
*/ */
std::string last_part_of_name = name.substr(last_separator_pos + 1); auto last_part_of_name = name.substr(last_separator_pos + 1);
/* /*
If this name is enclosed in parentheses, generate it If this name is enclosed in parentheses, generate it
and blit it onto the base image and blit it onto the base image
*/ */
if (last_part_of_name[0] == paren_open if (last_part_of_name[0] == paren_open
&& last_part_of_name[last_part_of_name.size() - 1] == paren_close) { && last_part_of_name.back() == paren_close) {
std::string name2 = last_part_of_name.substr(1, auto name2 = last_part_of_name.substr(1,
last_part_of_name.size() - 2); last_part_of_name.size() - 2);
video::IImage *tmp = generateImage(name2, source_image_names); video::IImage *tmp = generateImage(name2, source_image_names);
if (!tmp) { if (!tmp) {
@ -1199,7 +1200,7 @@ void blitBaseImage(video::IImage* &src, video::IImage* &dst)
} \ } \
} while(0) } while(0)
bool TextureSource::generateImagePart(std::string part_of_name, bool TextureSource::generateImagePart(std::string_view part_of_name,
video::IImage *& baseimg, std::set<std::string> &source_image_names) video::IImage *& baseimg, std::set<std::string> &source_image_names)
{ {
const char escape = '\\'; // same as in generateImage() const char escape = '\\'; // same as in generateImage()
@ -1216,8 +1217,9 @@ bool TextureSource::generateImagePart(std::string part_of_name,
// Stuff starting with [ are special commands // Stuff starting with [ are special commands
if (part_of_name.empty() || part_of_name[0] != '[') { if (part_of_name.empty() || part_of_name[0] != '[') {
source_image_names.insert(part_of_name); std::string part_s(part_of_name);
video::IImage *image = m_sourcecache.getOrLoad(part_of_name); source_image_names.insert(part_s);
video::IImage *image = m_sourcecache.getOrLoad(part_s);
if (!image) { if (!image) {
// Do not create the dummy texture // Do not create the dummy texture
if (part_of_name.empty()) if (part_of_name.empty())
@ -1516,8 +1518,10 @@ bool TextureSource::generateImagePart(std::string part_of_name,
return false; return false;
} }
str_replace(part_of_name, '&', '^'); std::string part_s(part_of_name);
Strfnd sf(part_of_name); str_replace(part_s, '&', '^');
Strfnd sf(part_s);
sf.next("{"); sf.next("{");
std::string imagename_top = sf.next("{"); std::string imagename_top = sf.next("{");
std::string imagename_left = sf.next("{"); std::string imagename_left = sf.next("{");
@ -1873,7 +1877,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
else if (str_starts_with(part_of_name, "[png:")) { else if (str_starts_with(part_of_name, "[png:")) {
std::string png; std::string png;
{ {
std::string blob = part_of_name.substr(5); auto blob = part_of_name.substr(5);
if (!base64_is_valid(blob)) { if (!base64_is_valid(blob)) {
errorstream << "generateImagePart(): " errorstream << "generateImagePart(): "
<< "malformed base64 in [png" << std::endl; << "malformed base64 in [png" << std::endl;
@ -2433,7 +2437,7 @@ void brighten(video::IImage *image)
} }
} }
u32 parseImageTransform(const std::string& s) u32 parseImageTransform(std::string_view s)
{ {
int total_transform = 0; int total_transform = 0;

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h" #include "settings.h"
#include "filesys.h" #include "filesys.h"
#include "gettext.h" #include "gettext.h"
#include "exceptions.h"
std::string ModConfiguration::getUnsatisfiedModsError() const std::string ModConfiguration::getUnsatisfiedModsError() const

@ -228,7 +228,7 @@ bool ModStorage::contains(const std::string &name) const
return m_database->hasModEntry(m_mod_name, name); return m_database->hasModEntry(m_mod_name, name);
} }
bool ModStorage::setString(const std::string &name, const std::string &var) bool ModStorage::setString(const std::string &name, std::string_view var)
{ {
if (var.empty()) if (var.empty())
return m_database->removeModEntry(m_mod_name, name); return m_database->removeModEntry(m_mod_name, name);

@ -123,7 +123,7 @@ public:
bool contains(const std::string &name) const override; bool contains(const std::string &name) const override;
bool setString(const std::string &name, const std::string &var) override; bool setString(const std::string &name, std::string_view var) override;
const StringMap &getStrings(StringMap *place) const override; const StringMap &getStrings(StringMap *place) const override;

@ -239,9 +239,9 @@ std::set<std::string> getAvailableGameIds()
// Add it to result // Add it to result
const char *ends[] = {"_game", NULL}; const char *ends[] = {"_game", NULL};
std::string shorter = removeStringEnd(dln.name, ends); auto shorter = removeStringEnd(dln.name, ends);
if (!shorter.empty()) if (!shorter.empty())
gameids.insert(shorter); gameids.emplace(shorter);
else else
gameids.insert(dln.name); gameids.insert(dln.name);
} }

@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
inline bool isGroupRecipeStr(const std::string &rec_name) inline bool isGroupRecipeStr(const std::string &rec_name)
{ {
return str_starts_with(rec_name, std::string("group:")); return str_starts_with(rec_name, "group:");
} }
static bool hasGroupItem(const std::vector<std::string> &recipe) static bool hasGroupItem(const std::vector<std::string> &recipe)

@ -25,7 +25,7 @@ Dummy database class
#include "remoteplayer.h" #include "remoteplayer.h"
bool Database_Dummy::saveBlock(const v3s16 &pos, const std::string &data) bool Database_Dummy::saveBlock(const v3s16 &pos, std::string_view data)
{ {
m_database[getBlockAsInteger(pos)] = data; m_database[getBlockAsInteger(pos)] = data;
return true; return true;
@ -128,11 +128,12 @@ bool Database_Dummy::hasModEntry(const std::string &modname, const std::string &
} }
bool Database_Dummy::setModEntry(const std::string &modname, bool Database_Dummy::setModEntry(const std::string &modname,
const std::string &key, const std::string &value) const std::string &key, std::string_view value)
{ {
auto mod_pair = m_mod_storage_database.find(modname); auto mod_pair = m_mod_storage_database.find(modname);
if (mod_pair == m_mod_storage_database.end()) { if (mod_pair == m_mod_storage_database.end()) {
m_mod_storage_database[modname] = StringMap({{key, value}}); auto &map = m_mod_storage_database[modname];
map[key] = value;
} else { } else {
mod_pair->second[key] = value; mod_pair->second[key] = value;
} }

@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once #pragma once
#include <map> #include <map>
#include <set>
#include <string> #include <string>
#include "database.h" #include "database.h"
#include "irrlichttypes.h" #include "irrlichttypes.h"
@ -27,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Database_Dummy : public MapDatabase, public PlayerDatabase, public ModStorageDatabase class Database_Dummy : public MapDatabase, public PlayerDatabase, public ModStorageDatabase
{ {
public: public:
bool saveBlock(const v3s16 &pos, const std::string &data); bool saveBlock(const v3s16 &pos, std::string_view data);
void loadBlock(const v3s16 &pos, std::string *block); void loadBlock(const v3s16 &pos, std::string *block);
bool deleteBlock(const v3s16 &pos); bool deleteBlock(const v3s16 &pos);
void listAllLoadableBlocks(std::vector<v3s16> &dst); void listAllLoadableBlocks(std::vector<v3s16> &dst);
@ -43,7 +44,7 @@ public:
const std::string &key, std::string *value); const std::string &key, std::string *value);
bool hasModEntry(const std::string &modname, const std::string &key); bool hasModEntry(const std::string &modname, const std::string &key);
bool setModEntry(const std::string &modname, bool setModEntry(const std::string &modname,
const std::string &key, const std::string &value); const std::string &key,std::string_view value);
bool removeModEntry(const std::string &modname, const std::string &key); bool removeModEntry(const std::string &modname, const std::string &key);
bool removeModEntries(const std::string &modname); bool removeModEntries(const std::string &modname);
void listMods(std::vector<std::string> *res); void listMods(std::vector<std::string> *res);

@ -428,13 +428,14 @@ bool ModStorageDatabaseFiles::hasModEntry(const std::string &modname, const std:
} }
bool ModStorageDatabaseFiles::setModEntry(const std::string &modname, bool ModStorageDatabaseFiles::setModEntry(const std::string &modname,
const std::string &key, const std::string &value) const std::string &key, std::string_view value)
{ {
Json::Value *meta = getOrCreateJson(modname); Json::Value *meta = getOrCreateJson(modname);
if (!meta) if (!meta)
return false; return false;
(*meta)[key] = Json::Value(value); Json::Value value_v(value.data(), value.data() + value.size());
(*meta)[key] = std::move(value_v);
m_modified.insert(modname); m_modified.insert(modname);
return true; return true;

@ -84,7 +84,7 @@ public:
const std::string &key, std::string *value); const std::string &key, std::string *value);
virtual bool hasModEntry(const std::string &modname, const std::string &key); virtual bool hasModEntry(const std::string &modname, const std::string &key);
virtual bool setModEntry(const std::string &modname, virtual bool setModEntry(const std::string &modname,
const std::string &key, const std::string &value); const std::string &key, std::string_view value);
virtual bool removeModEntry(const std::string &modname, const std::string &key); virtual bool removeModEntry(const std::string &modname, const std::string &key);
virtual bool removeModEntries(const std::string &modname); virtual bool removeModEntries(const std::string &modname);
virtual void listMods(std::vector<std::string> *res); virtual void listMods(std::vector<std::string> *res);

@ -53,10 +53,11 @@ Database_LevelDB::Database_LevelDB(const std::string &savedir)
m_database.reset(db); m_database.reset(db);
} }
bool Database_LevelDB::saveBlock(const v3s16 &pos, const std::string &data) bool Database_LevelDB::saveBlock(const v3s16 &pos, std::string_view data)
{ {
leveldb::Slice data_s(data.data(), data.size());
leveldb::Status status = m_database->Put(leveldb::WriteOptions(), leveldb::Status status = m_database->Put(leveldb::WriteOptions(),
i64tos(getBlockAsInteger(pos)), data); i64tos(getBlockAsInteger(pos)), data_s);
if (!status.ok()) { if (!status.ok()) {
warningstream << "saveBlock: LevelDB error saving block " warningstream << "saveBlock: LevelDB error saving block "
<< pos << ": " << status.ToString() << std::endl; << pos << ": " << status.ToString() << std::endl;

@ -34,7 +34,7 @@ public:
Database_LevelDB(const std::string &savedir); Database_LevelDB(const std::string &savedir);
~Database_LevelDB() = default; ~Database_LevelDB() = default;
bool saveBlock(const v3s16 &pos, const std::string &data); bool saveBlock(const v3s16 &pos, std::string_view data);
void loadBlock(const v3s16 &pos, std::string *block); void loadBlock(const v3s16 &pos, std::string *block);
bool deleteBlock(const v3s16 &pos); bool deleteBlock(const v3s16 &pos);
void listAllLoadableBlocks(std::vector<v3s16> &dst); void listAllLoadableBlocks(std::vector<v3s16> &dst);

@ -223,7 +223,7 @@ void MapDatabasePostgreSQL::initStatements()
"SELECT posX, posY, posZ FROM blocks"); "SELECT posX, posY, posZ FROM blocks");
} }
bool MapDatabasePostgreSQL::saveBlock(const v3s16 &pos, const std::string &data) bool MapDatabasePostgreSQL::saveBlock(const v3s16 &pos, std::string_view data)
{ {
// Verify if we don't overflow the platform integer with the mapblock size // Verify if we don't overflow the platform integer with the mapblock size
if (data.size() > INT_MAX) { if (data.size() > INT_MAX) {
@ -240,7 +240,7 @@ bool MapDatabasePostgreSQL::saveBlock(const v3s16 &pos, const std::string &data)
y = htonl(pos.Y); y = htonl(pos.Y);
z = htonl(pos.Z); z = htonl(pos.Z);
const void *args[] = { &x, &y, &z, data.c_str() }; const void *args[] = { &x, &y, &z, data.data() };
const int argLen[] = { const int argLen[] = {
sizeof(x), sizeof(y), sizeof(z), (int)data.size() sizeof(x), sizeof(y), sizeof(z), (int)data.size()
}; };
@ -940,11 +940,11 @@ bool ModStorageDatabasePostgreSQL::hasModEntry(const std::string &modname,
} }
bool ModStorageDatabasePostgreSQL::setModEntry(const std::string &modname, bool ModStorageDatabasePostgreSQL::setModEntry(const std::string &modname,
const std::string &key, const std::string &value) const std::string &key, std::string_view value)
{ {
verifyDatabase(); verifyDatabase();
const void *args[] = { modname.c_str(), key.c_str(), value.c_str() }; const void *args[] = { modname.c_str(), key.c_str(), value.data() };
const int argLen[] = { const int argLen[] = {
-1, -1,
(int)MYMIN(key.size(), INT_MAX), (int)MYMIN(key.size(), INT_MAX),

@ -120,7 +120,7 @@ public:
MapDatabasePostgreSQL(const std::string &connect_string); MapDatabasePostgreSQL(const std::string &connect_string);
virtual ~MapDatabasePostgreSQL() = default; virtual ~MapDatabasePostgreSQL() = default;
bool saveBlock(const v3s16 &pos, const std::string &data); bool saveBlock(const v3s16 &pos, std::string_view data);
void loadBlock(const v3s16 &pos, std::string *block); void loadBlock(const v3s16 &pos, std::string *block);
bool deleteBlock(const v3s16 &pos); bool deleteBlock(const v3s16 &pos);
void listAllLoadableBlocks(std::vector<v3s16> &dst); void listAllLoadableBlocks(std::vector<v3s16> &dst);
@ -186,7 +186,7 @@ public:
bool getModEntry(const std::string &modname, const std::string &key, std::string *value); bool getModEntry(const std::string &modname, const std::string &key, std::string *value);
bool hasModEntry(const std::string &modname, const std::string &key); bool hasModEntry(const std::string &modname, const std::string &key);
bool setModEntry(const std::string &modname, bool setModEntry(const std::string &modname,
const std::string &key, const std::string &value); const std::string &key, std::string_view value);
bool removeModEntry(const std::string &modname, const std::string &key); bool removeModEntry(const std::string &modname, const std::string &key);
bool removeModEntries(const std::string &modname); bool removeModEntries(const std::string &modname);
void listMods(std::vector<std::string> *res); void listMods(std::vector<std::string> *res);

@ -91,12 +91,12 @@ void Database_Redis::endSave() {
freeReplyObject(reply); freeReplyObject(reply);
} }
bool Database_Redis::saveBlock(const v3s16 &pos, const std::string &data) bool Database_Redis::saveBlock(const v3s16 &pos, std::string_view data)
{ {
std::string tmp = i64tos(getBlockAsInteger(pos)); std::string tmp = i64tos(getBlockAsInteger(pos));
redisReply *reply = static_cast<redisReply *>(redisCommand(ctx, "HSET %s %s %b", redisReply *reply = static_cast<redisReply *>(redisCommand(ctx, "HSET %s %s %b",
hash.c_str(), tmp.c_str(), data.c_str(), data.size())); hash.c_str(), tmp.c_str(), data.data(), data.size()));
if (!reply) { if (!reply) {
warningstream << "saveBlock: redis command 'HSET' failed on " warningstream << "saveBlock: redis command 'HSET' failed on "
"block " << pos << ": " << ctx->errstr << std::endl; "block " << pos << ": " << ctx->errstr << std::endl;

@ -38,7 +38,7 @@ public:
void beginSave(); void beginSave();
void endSave(); void endSave();
bool saveBlock(const v3s16 &pos, const std::string &data); bool saveBlock(const v3s16 &pos, std::string_view data);
void loadBlock(const v3s16 &pos, std::string *block); void loadBlock(const v3s16 &pos, std::string *block);
bool deleteBlock(const v3s16 &pos); bool deleteBlock(const v3s16 &pos);
void listAllLoadableBlocks(std::vector<v3s16> &dst); void listAllLoadableBlocks(std::vector<v3s16> &dst);

@ -258,7 +258,7 @@ bool MapDatabaseSQLite3::deleteBlock(const v3s16 &pos)
return good; return good;
} }
bool MapDatabaseSQLite3::saveBlock(const v3s16 &pos, const std::string &data) bool MapDatabaseSQLite3::saveBlock(const v3s16 &pos, std::string_view data)
{ {
verifyDatabase(); verifyDatabase();
@ -283,13 +283,8 @@ void MapDatabaseSQLite3::loadBlock(const v3s16 &pos, std::string *block)
return; return;
} }
const char *data = (const char *) sqlite3_column_blob(m_stmt_read, 0); auto data = sqlite_to_blob(m_stmt_read, 0);
size_t len = sqlite3_column_bytes(m_stmt_read, 0); block->assign(data);
if (data)
block->assign(data, len);
else
block->clear();
sqlite3_step(m_stmt_read); sqlite3_step(m_stmt_read);
// We should never get more than 1 row, so ok to reset // We should never get more than 1 row, so ok to reset
@ -553,7 +548,7 @@ bool PlayerDatabaseSQLite3::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
int_to_sqlite(m_stmt_player_load_inventory_items, 2, invId); int_to_sqlite(m_stmt_player_load_inventory_items, 2, invId);
while (sqlite3_step(m_stmt_player_load_inventory_items) == SQLITE_ROW) { while (sqlite3_step(m_stmt_player_load_inventory_items) == SQLITE_ROW) {
const std::string itemStr = sqlite_to_string(m_stmt_player_load_inventory_items, 1); const std::string itemStr = sqlite_to_string(m_stmt_player_load_inventory_items, 1);
if (itemStr.length() > 0) { if (!itemStr.empty()) {
ItemStack stack; ItemStack stack;
stack.deSerialize(itemStr); stack.deSerialize(itemStr);
invList->changeItem(sqlite_to_uint(m_stmt_player_load_inventory_items, 0), stack); invList->changeItem(sqlite_to_uint(m_stmt_player_load_inventory_items, 0), stack);
@ -567,7 +562,7 @@ bool PlayerDatabaseSQLite3::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
str_to_sqlite(m_stmt_player_metadata_load, 1, sao->getPlayer()->getName()); str_to_sqlite(m_stmt_player_metadata_load, 1, sao->getPlayer()->getName());
while (sqlite3_step(m_stmt_player_metadata_load) == SQLITE_ROW) { while (sqlite3_step(m_stmt_player_metadata_load) == SQLITE_ROW) {
std::string attr = sqlite_to_string(m_stmt_player_metadata_load, 0); std::string attr = sqlite_to_string(m_stmt_player_metadata_load, 0);
std::string value = sqlite_to_string(m_stmt_player_metadata_load, 1); auto value = sqlite_to_string_view(m_stmt_player_metadata_load, 1);
sao->getMeta().setString(attr, value); sao->getMeta().setString(attr, value);
} }
@ -592,7 +587,7 @@ void PlayerDatabaseSQLite3::listPlayers(std::vector<std::string> &res)
verifyDatabase(); verifyDatabase();
while (sqlite3_step(m_stmt_player_list) == SQLITE_ROW) while (sqlite3_step(m_stmt_player_list) == SQLITE_ROW)
res.push_back(sqlite_to_string(m_stmt_player_list, 0)); res.emplace_back(sqlite_to_string_view(m_stmt_player_list, 0));
sqlite3_reset(m_stmt_player_list); sqlite3_reset(m_stmt_player_list);
} }
@ -669,14 +664,14 @@ bool AuthDatabaseSQLite3::getAuth(const std::string &name, AuthEntry &res)
return false; return false;
} }
res.id = sqlite_to_uint(m_stmt_read, 0); res.id = sqlite_to_uint(m_stmt_read, 0);
res.name = sqlite_to_string(m_stmt_read, 1); res.name = sqlite_to_string_view(m_stmt_read, 1);
res.password = sqlite_to_string(m_stmt_read, 2); res.password = sqlite_to_string_view(m_stmt_read, 2);
res.last_login = sqlite_to_int64(m_stmt_read, 3); res.last_login = sqlite_to_int64(m_stmt_read, 3);
sqlite3_reset(m_stmt_read); sqlite3_reset(m_stmt_read);
int64_to_sqlite(m_stmt_read_privs, 1, res.id); int64_to_sqlite(m_stmt_read_privs, 1, res.id);
while (sqlite3_step(m_stmt_read_privs) == SQLITE_ROW) { while (sqlite3_step(m_stmt_read_privs) == SQLITE_ROW) {
res.privileges.emplace_back(sqlite_to_string(m_stmt_read_privs, 0)); res.privileges.emplace_back(sqlite_to_string_view(m_stmt_read_privs, 0));
} }
sqlite3_reset(m_stmt_read_privs); sqlite3_reset(m_stmt_read_privs);
@ -741,7 +736,7 @@ void AuthDatabaseSQLite3::listNames(std::vector<std::string> &res)
verifyDatabase(); verifyDatabase();
while (sqlite3_step(m_stmt_list_names) == SQLITE_ROW) { while (sqlite3_step(m_stmt_list_names) == SQLITE_ROW) {
res.push_back(sqlite_to_string(m_stmt_list_names, 0)); res.emplace_back(sqlite_to_string_view(m_stmt_list_names, 0));
} }
sqlite3_reset(m_stmt_list_names); sqlite3_reset(m_stmt_list_names);
} }
@ -815,11 +810,9 @@ void ModStorageDatabaseSQLite3::getModEntries(const std::string &modname, String
str_to_sqlite(m_stmt_get_all, 1, modname); str_to_sqlite(m_stmt_get_all, 1, modname);
while (sqlite3_step(m_stmt_get_all) == SQLITE_ROW) { while (sqlite3_step(m_stmt_get_all) == SQLITE_ROW) {
const char *key_data = (const char *) sqlite3_column_blob(m_stmt_get_all, 0); auto key = sqlite_to_blob(m_stmt_get_all, 0);
size_t key_len = sqlite3_column_bytes(m_stmt_get_all, 0); auto value = sqlite_to_blob(m_stmt_get_all, 1);
const char *value_data = (const char *) sqlite3_column_blob(m_stmt_get_all, 1); (*storage)[std::string(key)].assign(value);
size_t value_len = sqlite3_column_bytes(m_stmt_get_all, 1);
(*storage)[std::string(key_data, key_len)] = std::string(value_data, value_len);
} }
sqlite3_vrfy(sqlite3_errcode(m_database), SQLITE_DONE); sqlite3_vrfy(sqlite3_errcode(m_database), SQLITE_DONE);
@ -833,9 +826,8 @@ void ModStorageDatabaseSQLite3::getModKeys(const std::string &modname,
str_to_sqlite(m_stmt_get_keys, 1, modname); str_to_sqlite(m_stmt_get_keys, 1, modname);
while (sqlite3_step(m_stmt_get_keys) == SQLITE_ROW) { while (sqlite3_step(m_stmt_get_keys) == SQLITE_ROW) {
const char *key_data = (const char *) sqlite3_column_blob(m_stmt_get_keys, 0); auto key = sqlite_to_blob(m_stmt_get_keys, 0);
size_t key_len = sqlite3_column_bytes(m_stmt_get_keys, 0); storage->emplace_back(key);
storage->emplace_back(key_data, key_len);
} }
sqlite3_vrfy(sqlite3_errcode(m_database), SQLITE_DONE); sqlite3_vrfy(sqlite3_errcode(m_database), SQLITE_DONE);
@ -852,9 +844,8 @@ bool ModStorageDatabaseSQLite3::getModEntry(const std::string &modname,
"Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__)); "Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__));
bool found = sqlite3_step(m_stmt_get) == SQLITE_ROW; bool found = sqlite3_step(m_stmt_get) == SQLITE_ROW;
if (found) { if (found) {
const char *value_data = (const char *) sqlite3_column_blob(m_stmt_get, 0); auto sv = sqlite_to_blob(m_stmt_get, 0);
size_t value_len = sqlite3_column_bytes(m_stmt_get, 0); value->assign(sv);
value->assign(value_data, value_len);
sqlite3_step(m_stmt_get); sqlite3_step(m_stmt_get);
} }
@ -881,7 +872,7 @@ bool ModStorageDatabaseSQLite3::hasModEntry(const std::string &modname,
} }
bool ModStorageDatabaseSQLite3::setModEntry(const std::string &modname, bool ModStorageDatabaseSQLite3::setModEntry(const std::string &modname,
const std::string &key, const std::string &value) const std::string &key, std::string_view value)
{ {
verifyDatabase(); verifyDatabase();

@ -44,14 +44,9 @@ protected:
void verifyDatabase(); void verifyDatabase();
// Convertors // Convertors
inline void str_to_sqlite(sqlite3_stmt *s, int iCol, const std::string &str) const inline void str_to_sqlite(sqlite3_stmt *s, int iCol, std::string_view str) const
{ {
sqlite3_vrfy(sqlite3_bind_text(s, iCol, str.c_str(), str.size(), NULL)); sqlite3_vrfy(sqlite3_bind_text(s, iCol, str.data(), str.size(), NULL));
}
inline void str_to_sqlite(sqlite3_stmt *s, int iCol, const char *str) const
{
sqlite3_vrfy(sqlite3_bind_text(s, iCol, str, strlen(str), NULL));
} }
inline void int_to_sqlite(sqlite3_stmt *s, int iCol, int val) const inline void int_to_sqlite(sqlite3_stmt *s, int iCol, int val) const
@ -69,10 +64,28 @@ protected:
sqlite3_vrfy(sqlite3_bind_double(s, iCol, val)); sqlite3_vrfy(sqlite3_bind_double(s, iCol, val));
} }
inline std::string sqlite_to_string(sqlite3_stmt *s, int iCol) // Note that the return value is only valid until the statement is stepped or reset.
inline std::string_view sqlite_to_string_view(sqlite3_stmt *s, int iCol)
{ {
const char* text = reinterpret_cast<const char*>(sqlite3_column_text(s, iCol)); const char* text = reinterpret_cast<const char*>(sqlite3_column_text(s, iCol));
return std::string(text ? text : ""); return text ? std::string_view(text) : std::string_view();
}
// Avoid using this in favor of `sqlite_to_string_view`.
inline std::string sqlite_to_string(sqlite3_stmt *s, int iCol)
{
return std::string(sqlite_to_string_view(s, iCol));
}
// Converts a BLOB-type column into a string_view (null byte safe).
// Note that the return value is only valid until the statement is stepped or reset.
inline std::string_view sqlite_to_blob(sqlite3_stmt *s, int iCol)
{
const char *data = reinterpret_cast<const char*>(sqlite3_column_blob(s, iCol));
if (!data)
return std::string_view();
size_t len = sqlite3_column_bytes(s, iCol);
return std::string_view(data, len);
} }
inline s32 sqlite_to_int(sqlite3_stmt *s, int iCol) inline s32 sqlite_to_int(sqlite3_stmt *s, int iCol)
@ -107,13 +120,16 @@ protected:
} }
// Query verifiers helpers // Query verifiers helpers
inline void sqlite3_vrfy(int s, const std::string &m = "", int r = SQLITE_OK) const inline void sqlite3_vrfy(int s, std::string_view m = "", int r = SQLITE_OK) const
{ {
if (s != r) if (s != r) {
throw DatabaseException(m + ": " + sqlite3_errmsg(m_database)); std::string msg(m);
msg.append(": ").append(sqlite3_errmsg(m_database));
throw DatabaseException(msg);
}
} }
inline void sqlite3_vrfy(const int s, const int r, const std::string &m = "") const inline void sqlite3_vrfy(const int s, const int r, std::string_view m = "") const
{ {
sqlite3_vrfy(s, m, r); sqlite3_vrfy(s, m, r);
} }
@ -146,7 +162,7 @@ public:
MapDatabaseSQLite3(const std::string &savedir); MapDatabaseSQLite3(const std::string &savedir);
virtual ~MapDatabaseSQLite3(); virtual ~MapDatabaseSQLite3();
bool saveBlock(const v3s16 &pos, const std::string &data); bool saveBlock(const v3s16 &pos, std::string_view data);
void loadBlock(const v3s16 &pos, std::string *block); void loadBlock(const v3s16 &pos, std::string *block);
bool deleteBlock(const v3s16 &pos); bool deleteBlock(const v3s16 &pos);
void listAllLoadableBlocks(std::vector<v3s16> &dst); void listAllLoadableBlocks(std::vector<v3s16> &dst);
@ -245,7 +261,7 @@ public:
const std::string &key, std::string *value); const std::string &key, std::string *value);
virtual bool hasModEntry(const std::string &modname, const std::string &key); virtual bool hasModEntry(const std::string &modname, const std::string &key);
virtual bool setModEntry(const std::string &modname, virtual bool setModEntry(const std::string &modname,
const std::string &key, const std::string &value); const std::string &key,std::string_view value);
virtual bool removeModEntry(const std::string &modname, const std::string &key); virtual bool removeModEntry(const std::string &modname, const std::string &key);
virtual bool removeModEntries(const std::string &modname); virtual bool removeModEntries(const std::string &modname);
virtual void listMods(std::vector<std::string> *res); virtual void listMods(std::vector<std::string> *res);

@ -19,12 +19,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once #pragma once
#include <set>
#include <string> #include <string>
#include <string_view>
#include <vector> #include <vector>
#include "irr_v3d.h" #include "irr_v3d.h"
#include "irrlichttypes.h" #include "irrlichttypes.h"
#include "util/basic_macros.h"
#include "util/string.h" #include "util/string.h"
class Database class Database
@ -40,7 +39,7 @@ class MapDatabase : public Database
public: public:
virtual ~MapDatabase() = default; virtual ~MapDatabase() = default;
virtual bool saveBlock(const v3s16 &pos, const std::string &data) = 0; virtual bool saveBlock(const v3s16 &pos, std::string_view data) = 0;
virtual void loadBlock(const v3s16 &pos, std::string *block) = 0; virtual void loadBlock(const v3s16 &pos, std::string *block) = 0;
virtual bool deleteBlock(const v3s16 &pos) = 0; virtual bool deleteBlock(const v3s16 &pos) = 0;
@ -97,7 +96,7 @@ public:
virtual bool getModEntry(const std::string &modname, virtual bool getModEntry(const std::string &modname,
const std::string &key, std::string *value) = 0; const std::string &key, std::string *value) = 0;
virtual bool setModEntry(const std::string &modname, virtual bool setModEntry(const std::string &modname,
const std::string &key, const std::string &value) = 0; const std::string &key, std::string_view value) = 0;
virtual bool removeModEntry(const std::string &modname, const std::string &key) = 0; virtual bool removeModEntry(const std::string &modname, const std::string &key) = 0;
virtual bool removeModEntries(const std::string &modname) = 0; virtual bool removeModEntries(const std::string &modname) = 0;
virtual void listMods(std::vector<std::string> *res) = 0; virtual void listMods(std::vector<std::string> *res) = 0;

@ -828,7 +828,7 @@ const char *GetFilenameFromPath(const char *path)
return filename ? filename + 1 : path; return filename ? filename + 1 : path;
} }
bool safeWriteToFile(const std::string &path, const std::string &content) bool safeWriteToFile(const std::string &path, std::string_view content)
{ {
std::string tmp_file = path + ".~mt"; std::string tmp_file = path + ".~mt";
@ -844,7 +844,7 @@ bool safeWriteToFile(const std::string &path, const std::string &content)
return false; return false;
} }
DWORD bytes_written; DWORD bytes_written;
tmp_success = (WriteFile(tmp_handle, content.c_str(), content.size(), &bytes_written, nullptr) && tmp_success = (WriteFile(tmp_handle, content.data(), content.size(), &bytes_written, nullptr) &&
FlushFileBuffers(tmp_handle)); FlushFileBuffers(tmp_handle));
CloseHandle(tmp_handle); CloseHandle(tmp_handle);
#else #else

@ -21,8 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <set> #include <set>
#include <string> #include <string>
#include <string_view>
#include <vector> #include <vector>
#include "exceptions.h"
#ifdef _WIN32 #ifdef _WIN32
#define DIR_DELIM "\\" #define DIR_DELIM "\\"
@ -142,7 +142,7 @@ std::string AbsolutePath(const std::string &path);
// delimiter is found. // delimiter is found.
const char *GetFilenameFromPath(const char *path); const char *GetFilenameFromPath(const char *path);
bool safeWriteToFile(const std::string &path, const std::string &content); bool safeWriteToFile(const std::string &path, std::string_view content);
#ifndef SERVER #ifndef SERVER
bool extractZipFile(irr::io::IFileSystem *fs, const char *filename, const std::string &destination); bool extractZipFile(irr::io::IFileSystem *fs, const char *filename, const std::string &destination);

@ -755,7 +755,7 @@ void GUIFormSpecMenu::parseScrollBarOptions(parserData* data, const std::string
data->scrollbar_options.thumb_size = value <= 0 ? 1 : value; data->scrollbar_options.thumb_size = value <= 0 ? 1 : value;
continue; continue;
} else if (options[0] == "arrows") { } else if (options[0] == "arrows") {
std::string value = trim(options[1]); auto value = trim(options[1]);
if (value == "hide") if (value == "hide")
data->scrollbar_options.arrow_visiblity = GUIScrollBar::HIDE; data->scrollbar_options.arrow_visiblity = GUIScrollBar::HIDE;
else if (value == "show") else if (value == "show")
@ -2449,8 +2449,8 @@ bool GUIFormSpecMenu::parseSizeDirect(parserData* data, const std::string &eleme
if (parts.size() < 2) if (parts.size() < 2)
return false; return false;
std::string type = trim(parts[0]); auto type = trim(parts[0]);
std::string description = trim(parts[1]); std::string description(trim(parts[1]));
if (type != "size" && type != "invsize") if (type != "size" && type != "invsize")
return false; return false;
@ -2473,8 +2473,8 @@ bool GUIFormSpecMenu::parsePositionDirect(parserData *data, const std::string &e
if (parts.size() != 2) if (parts.size() != 2)
return false; return false;
std::string type = trim(parts[0]); auto type = trim(parts[0]);
std::string description = trim(parts[1]); std::string description(trim(parts[1]));
if (type != "position") if (type != "position")
return false; return false;
@ -2512,8 +2512,8 @@ bool GUIFormSpecMenu::parseAnchorDirect(parserData *data, const std::string &ele
if (parts.size() != 2) if (parts.size() != 2)
return false; return false;
std::string type = trim(parts[0]); auto type = trim(parts[0]);
std::string description = trim(parts[1]); std::string description(trim(parts[1]));
if (type != "anchor") if (type != "anchor")
return false; return false;
@ -2552,8 +2552,8 @@ bool GUIFormSpecMenu::parsePaddingDirect(parserData *data, const std::string &el
if (parts.size() != 2) if (parts.size() != 2)
return false; return false;
std::string type = trim(parts[0]); auto type = trim(parts[0]);
std::string description = trim(parts[1]); std::string description(trim(parts[1]));
if (type != "padding") if (type != "padding")
return false; return false;
@ -2624,7 +2624,7 @@ bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, b
std::vector<std::string> selectors = split(parts[0], ','); std::vector<std::string> selectors = split(parts[0], ',');
for (size_t sel = 0; sel < selectors.size(); sel++) { for (size_t sel = 0; sel < selectors.size(); sel++) {
std::string selector = trim(selectors[sel]); std::string selector(trim(selectors[sel]));
// Copy the style properties to a new StyleSpec // Copy the style properties to a new StyleSpec
// This allows a separate state mask per-selector // This allows a separate state mask per-selector
@ -3216,7 +3216,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
mydata.real_coordinates = m_formspec_version >= 2; mydata.real_coordinates = m_formspec_version >= 2;
for (; i < elements.size(); i++) { for (; i < elements.size(); i++) {
std::vector<std::string> parts = split(elements[i], '['); std::vector<std::string> parts = split(elements[i], '[');
std::string name = trim(parts[0]); auto name = trim(parts[0]);
if (name != "real_coordinates" || parts.size() != 2) if (name != "real_coordinates" || parts.size() != 2)
break; // Invalid format break; // Invalid format

@ -49,10 +49,10 @@ static void sanitize_string(std::string &str)
str.erase(std::remove(str.begin(), str.end(), DESERIALIZE_PAIR_DELIM), str.end()); str.erase(std::remove(str.begin(), str.end(), DESERIALIZE_PAIR_DELIM), str.end());
} }
bool ItemStackMetadata::setString(const std::string &name, const std::string &var) bool ItemStackMetadata::setString(const std::string &name, std::string_view var)
{ {
std::string clean_name = name; std::string clean_name = name;
std::string clean_var = var; std::string clean_var(var);
sanitize_string(clean_name); sanitize_string(clean_name);
sanitize_string(clean_var); sanitize_string(clean_var);

@ -36,7 +36,7 @@ public:
// Overrides // Overrides
void clear() override; void clear() override;
bool setString(const std::string &name, const std::string &var) override; bool setString(const std::string &name, std::string_view var) override;
void serialize(std::ostream &os) const; void serialize(std::ostream &os) const;
void deSerialize(std::istream &is); void deSerialize(std::istream &is);

@ -1798,6 +1798,7 @@ bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db, int compression_leve
o.write((char*) &version, 1); o.write((char*) &version, 1);
block->serialize(o, version, true, compression_level); block->serialize(o, version, true, compression_level);
// FIXME: zero copy possible in c++20 or with custom rdbuf
bool ret = db->saveBlock(p3d, o.str()); bool ret = db->saveBlock(p3d, o.str());
if (ret) { if (ret) {
// We just wrote it to the disk so clear modified flag // We just wrote it to the disk so clear modified flag

@ -382,7 +382,7 @@ void MapBlock::serialize(std::ostream &os_compressed, u8 version, bool disk, int
Bulk node data Bulk node data
*/ */
NameIdMapping nimap; NameIdMapping nimap;
SharedBuffer<u8> buf; Buffer<u8> buf;
const u8 content_width = 2; const u8 content_width = 2;
const u8 params_width = 2; const u8 params_width = 2;
if(disk) if(disk)
@ -653,7 +653,7 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
// Make a temporary buffer // Make a temporary buffer
u32 ser_length = MapNode::serializedLength(version); u32 ser_length = MapNode::serializedLength(version);
SharedBuffer<u8> databuf_nodelist(nodecount * ser_length); Buffer<u8> databuf_nodelist(nodecount * ser_length);
// These have no compression // These have no compression
if (version <= 3 || version == 5 || version == 6) { if (version <= 3 || version == 5 || version == 6) {

@ -384,7 +384,7 @@ bool Schematic::serializeToMts(std::ostream *os) const
} }
// compressed bulk node data // compressed bulk node data
SharedBuffer<u8> buf = MapNode::serializeBulk(MTSCHEM_MAPNODE_SER_FMT_VER, auto buf = MapNode::serializeBulk(MTSCHEM_MAPNODE_SER_FMT_VER,
schemdata, size.X * size.Y * size.Z, 2, 2); schemdata, size.X * size.Y * size.Z, 2, 2);
compress(buf, ss, MTSCHEM_MAPNODE_SER_FMT_VER); compress(buf, ss, MTSCHEM_MAPNODE_SER_FMT_VER);

@ -690,7 +690,7 @@ void MapNode::deSerialize(u8 *source, u8 version)
} }
} }
SharedBuffer<u8> MapNode::serializeBulk(int version, Buffer<u8> MapNode::serializeBulk(int version,
const MapNode *nodes, u32 nodecount, const MapNode *nodes, u32 nodecount,
u8 content_width, u8 params_width) u8 content_width, u8 params_width)
{ {
@ -706,7 +706,7 @@ SharedBuffer<u8> MapNode::serializeBulk(int version,
throw SerializationError("MapNode::serializeBulk: serialization to " throw SerializationError("MapNode::serializeBulk: serialization to "
"version < 24 not possible"); "version < 24 not possible");
SharedBuffer<u8> databuf(nodecount * (content_width + params_width)); Buffer<u8> databuf(nodecount * (content_width + params_width));
u32 start1 = content_width * nodecount; u32 start1 = content_width * nodecount;
u32 start2 = (content_width + 1) * nodecount; u32 start2 = (content_width + 1) * nodecount;

@ -316,7 +316,7 @@ struct alignas(u32) MapNode
// content_width = the number of bytes of content per node // content_width = the number of bytes of content per node
// params_width = the number of bytes of params per node // params_width = the number of bytes of params per node
// compressed = true to zlib-compress output // compressed = true to zlib-compress output
static SharedBuffer<u8> serializeBulk(int version, static Buffer<u8> serializeBulk(int version,
const MapNode *nodes, u32 nodecount, const MapNode *nodes, u32 nodecount,
u8 content_width, u8 params_width); u8 content_width, u8 params_width);
static void deSerializeBulk(std::istream &is, int version, static void deSerializeBulk(std::istream &is, int version,

@ -70,7 +70,7 @@ bool IMetadata::getStringToRef(const std::string &name,
const std::string &IMetadata::resolveString(const std::string &str, std::string *place, const std::string &IMetadata::resolveString(const std::string &str, std::string *place,
u16 recursion, bool deprecated) const u16 recursion, bool deprecated) const
{ {
if (recursion <= 1 && str.substr(0, 2) == "${" && str[str.length() - 1] == '}') { if (recursion <= 1 && str_starts_with(str, "${") && str.back() == '}') {
if (deprecated) { if (deprecated) {
warningstream << "Deprecated use of recursive resolution syntax in metadata: "; warningstream << "Deprecated use of recursive resolution syntax in metadata: ";
safe_print_string(warningstream, str); safe_print_string(warningstream, str);
@ -128,7 +128,7 @@ const std::string *SimpleMetadata::getStringRaw(const std::string &name, std::st
return found != m_stringvars.cend() ? &found->second : nullptr; return found != m_stringvars.cend() ? &found->second : nullptr;
} }
bool SimpleMetadata::setString(const std::string &name, const std::string &var) bool SimpleMetadata::setString(const std::string &name, std::string_view var)
{ {
if (var.empty()) { if (var.empty()) {
if (m_stringvars.erase(name) == 0) if (m_stringvars.erase(name) == 0)
@ -137,7 +137,7 @@ bool SimpleMetadata::setString(const std::string &name, const std::string &var)
StringMap::iterator it = m_stringvars.find(name); StringMap::iterator it = m_stringvars.find(name);
if (it != m_stringvars.end() && it->second == var) if (it != m_stringvars.end() && it->second == var)
return false; return false;
m_stringvars[name] = var; m_stringvars[name].assign(var);
} }
m_modified = true; m_modified = true;
return true; return true;

@ -53,7 +53,7 @@ public:
bool getStringToRef(const std::string &name, std::string &str, u16 recursion = 0) const; bool getStringToRef(const std::string &name, std::string &str, u16 recursion = 0) const;
// Returns whether the metadata was (potentially) changed. // Returns whether the metadata was (potentially) changed.
virtual bool setString(const std::string &name, const std::string &var) = 0; virtual bool setString(const std::string &name, std::string_view var) = 0;
inline bool removeString(const std::string &name) { return setString(name, ""); } inline bool removeString(const std::string &name) { return setString(name, ""); }
@ -89,7 +89,7 @@ public:
size_t size() const; size_t size() const;
bool contains(const std::string &name) const override; bool contains(const std::string &name) const override;
virtual bool setString(const std::string &name, const std::string &var) override; virtual bool setString(const std::string &name, std::string_view var) override;
const StringMap &getStrings(StringMap *) const override final; const StringMap &getStrings(StringMap *) const override final;
const std::vector<std::string> &getKeys(std::vector<std::string> *place) const std::vector<std::string> &getKeys(std::vector<std::string> *place)
const override final; const override final;

@ -1651,10 +1651,8 @@ void Client::handleCommand_MediaPush(NetworkPacket *pkt)
std::string computed_hash; std::string computed_hash;
{ {
SHA1 ctx; SHA1 ctx;
ctx.addBytes(filedata.c_str(), filedata.size()); ctx.addBytes(filedata);
unsigned char *buf = ctx.getDigest(); computed_hash = ctx.getDigest();
computed_hash.assign((char*) buf, 20);
free(buf);
} }
if (raw_hash != computed_hash) { if (raw_hash != computed_hash) {
verbosestream << "Hash of file data mismatches, ignoring." << std::endl; verbosestream << "Hash of file data mismatches, ignoring." << std::endl;

@ -99,7 +99,7 @@ NetworkPacket& NetworkPacket::operator>>(std::string& dst)
return *this; return *this;
} }
NetworkPacket& NetworkPacket::operator<<(const std::string &src) NetworkPacket& NetworkPacket::operator<<(std::string_view src)
{ {
if (src.size() > STRING_MAX_LEN) { if (src.size() > STRING_MAX_LEN) {
throw PacketError("String too long"); throw PacketError("String too long");
@ -109,12 +109,12 @@ NetworkPacket& NetworkPacket::operator<<(const std::string &src)
*this << msgsize; *this << msgsize;
putRawString(src.c_str(), (u32)msgsize); putRawString(src.data(), (u32)msgsize);
return *this; return *this;
} }
void NetworkPacket::putLongString(const std::string &src) void NetworkPacket::putLongString(std::string_view src)
{ {
if (src.size() > LONG_STRING_MAX_LEN) { if (src.size() > LONG_STRING_MAX_LEN) {
throw PacketError("String too long"); throw PacketError("String too long");
@ -124,7 +124,7 @@ void NetworkPacket::putLongString(const std::string &src)
*this << msgsize; *this << msgsize;
putRawString(src.c_str(), msgsize); putRawString(src.data(), msgsize);
} }
static constexpr bool NEED_SURROGATE_CODING = sizeof(wchar_t) > 2; static constexpr bool NEED_SURROGATE_CODING = sizeof(wchar_t) > 2;
@ -160,7 +160,7 @@ NetworkPacket& NetworkPacket::operator>>(std::wstring& dst)
return *this; return *this;
} }
NetworkPacket& NetworkPacket::operator<<(const std::wstring &src) NetworkPacket& NetworkPacket::operator<<(std::wstring_view src)
{ {
if (src.size() > WIDE_STRING_MAX_LEN) { if (src.size() > WIDE_STRING_MAX_LEN) {
throw PacketError("String too long"); throw PacketError("String too long");

@ -55,18 +55,18 @@ public:
const char *getString(u32 from_offset) const; const char *getString(u32 from_offset) const;
// major difference to putCString(): doesn't write len into the buffer // major difference to putCString(): doesn't write len into the buffer
void putRawString(const char *src, u32 len); void putRawString(const char *src, u32 len);
void putRawString(const std::string &src) void putRawString(std::string_view src)
{ {
putRawString(src.c_str(), src.size()); putRawString(src.data(), src.size());
} }
NetworkPacket &operator>>(std::string &dst); NetworkPacket &operator>>(std::string &dst);
NetworkPacket &operator<<(const std::string &src); NetworkPacket &operator<<(std::string_view src);
void putLongString(const std::string &src); void putLongString(std::string_view src);
NetworkPacket &operator>>(std::wstring &dst); NetworkPacket &operator>>(std::wstring &dst);
NetworkPacket &operator<<(const std::wstring &src); NetworkPacket &operator<<(std::wstring_view src);
std::string readLongString(); std::string readLongString();

@ -1142,17 +1142,16 @@ bool NodeDefManager::getIds(const std::string &name,
std::vector<content_t> &result) const std::vector<content_t> &result) const
{ {
//TimeTaker t("getIds", NULL, PRECISION_MICRO); //TimeTaker t("getIds", NULL, PRECISION_MICRO);
if (name.substr(0,6) != "group:") { if (!str_starts_with(name, "group:")) {
content_t id = CONTENT_IGNORE; content_t id = CONTENT_IGNORE;
bool exists = getId(name, id); bool exists = getId(name, id);
if (exists) if (exists)
result.push_back(id); result.push_back(id);
return exists; return exists;
} }
std::string group = name.substr(6);
std::unordered_map<std::string, std::vector<content_t>>::const_iterator std::string group = name.substr(6);
i = m_group_to_items.find(group); auto i = m_group_to_items.find(group);
if (i == m_group_to_items.end()) if (i == m_group_to_items.end())
return true; return true;
@ -1847,7 +1846,7 @@ bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
content_t c; content_t c;
std::string &name = m_nodenames[m_nodenames_idx++]; std::string &name = m_nodenames[m_nodenames_idx++];
if (name.substr(0,6) != "group:") { if (!str_starts_with(name, "group:")) {
if (m_ndef->getId(name, c)) { if (m_ndef->getId(name, c)) {
result_out->push_back(c); result_out->push_back(c);
} else if (all_required) { } else if (all_required) {

@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once #pragma once
#include <unordered_set> #include <unordered_set>
#include <map>
#include "metadata.h" #include "metadata.h"
/* /*

@ -832,7 +832,7 @@ static bool open_uri(const std::string &uri)
bool open_url(const std::string &url) bool open_url(const std::string &url)
{ {
if (url.substr(0, 7) != "http://" && url.substr(0, 8) != "https://") { if (!str_starts_with(url, "http://") && !str_starts_with(url, "https://")) {
errorstream << "Unable to open browser as URL is missing schema: " << url << std::endl; errorstream << "Unable to open browser as URL is missing schema: " << url << std::endl;
return false; return false;
} }

@ -1664,7 +1664,7 @@ Pointabilities read_pointabilities(lua_State *L, int index)
std::string name = luaL_checkstring(L, -2); std::string name = luaL_checkstring(L, -2);
// handle groups // handle groups
if(std::string_view(name).substr(0,6)=="group:") { if (str_starts_with(name, "group:")) {
pointabilities.node_groups[name.substr(6)] = read_pointability_type(L, -1); pointabilities.node_groups[name.substr(6)] = read_pointability_type(L, -1);
} else { } else {
pointabilities.nodes[name] = read_pointability_type(L, -1); pointabilities.nodes[name] = read_pointability_type(L, -1);
@ -1685,7 +1685,7 @@ Pointabilities read_pointabilities(lua_State *L, int index)
std::string name = luaL_checkstring(L, -2); std::string name = luaL_checkstring(L, -2);
// handle groups // handle groups
if(std::string_view(name).substr(0,6)=="group:") { if (str_starts_with(name, "group:")) {
pointabilities.object_groups[name.substr(6)] = read_pointability_type(L, -1); pointabilities.object_groups[name.substr(6)] = read_pointability_type(L, -1);
} else { } else {
pointabilities.objects[name] = read_pointability_type(L, -1); pointabilities.objects[name] = read_pointability_type(L, -1);

@ -25,6 +25,7 @@ extern "C" {
#include <cmath> #include <cmath>
#include <irr_v2d.h> #include <irr_v2d.h>
#include <irr_v3d.h> #include <irr_v3d.h>
#include <string_view>
#include "c_converter.h" #include "c_converter.h"
#include "c_types.h" #include "c_types.h"
@ -78,11 +79,16 @@ v3f LuaHelper::readParam(lua_State *L, int index)
} }
template <> template <>
std::string LuaHelper::readParam(lua_State *L, int index) std::string_view LuaHelper::readParam(lua_State *L, int index)
{ {
size_t length; size_t length;
std::string result;
const char *str = luaL_checklstring(L, index, &length); const char *str = luaL_checklstring(L, index, &length);
result.assign(str, length); return std::string_view(str, length);
return result; }
template <>
std::string LuaHelper::readParam(lua_State *L, int index)
{
auto sv = readParam<std::string_view>(L, index);
return std::string(sv); // a copy
} }

@ -19,6 +19,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once #pragma once
#include <string_view>
extern "C" { extern "C" {
#include <lua.h> #include <lua.h>
} }
@ -27,23 +29,22 @@ class LuaHelper
{ {
protected: protected:
/** /**
* Read a value using a template type T from Lua State L and index * Read a value using a template type T from Lua state L at index
*
* *
* @tparam T type to read from Lua * @tparam T type to read from Lua
* @param L Lua state * @param L Lua state
* @param index Lua Index to read * @param index Lua index to read
* @return read value from Lua * @return read value from Lua
*/ */
template <typename T> template <typename T>
static T readParam(lua_State *L, int index); static T readParam(lua_State *L, int index);
/** /**
* Read a value using a template type T from Lua State L and index * Read a value using a template type T from Lua state L at index
* *
* @tparam T type to read from Lua * @tparam T type to read from Lua
* @param L Lua state * @param L Lua state
* @param index Lua Index to read * @param index Lua index to read
* @param default_value default value to apply if nil * @param default_value default value to apply if nil
* @return read value from Lua or default value if nil * @return read value from Lua or default value if nil
*/ */
@ -53,3 +54,18 @@ protected:
return lua_isnoneornil(L, index) ? default_value : readParam<T>(L, index); return lua_isnoneornil(L, index) ? default_value : readParam<T>(L, index);
} }
}; };
// (only declared for documentation purposes:)
/**
* Read a string from Lua state L at index without copying it.
*
* Note that the returned string view is only valid as long as the value is on
* the stack and has not been modified. Be careful.
*
* @param L Lua state
* @param index Lua index to read
* @return string view
*/
template <>
std::string_view LuaHelper::readParam(lua_State *L, int index);

@ -163,6 +163,9 @@ int LuaItemStack::l_get_metadata(lua_State *L)
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkObject<LuaItemStack>(L, 1); LuaItemStack *o = checkObject<LuaItemStack>(L, 1);
ItemStack &item = o->m_stack; ItemStack &item = o->m_stack;
log_deprecated(L, "ItemStack:get_metadata is deprecated", 1, true);
const std::string &value = item.metadata.getString(""); const std::string &value = item.metadata.getString("");
lua_pushlstring(L, value.c_str(), value.size()); lua_pushlstring(L, value.c_str(), value.size());
return 1; return 1;
@ -176,6 +179,8 @@ int LuaItemStack::l_set_metadata(lua_State *L)
LuaItemStack *o = checkObject<LuaItemStack>(L, 1); LuaItemStack *o = checkObject<LuaItemStack>(L, 1);
ItemStack &item = o->m_stack; ItemStack &item = o->m_stack;
log_deprecated(L, "ItemStack:set_metadata is deprecated", 1, true);
size_t len = 0; size_t len = 0;
const char *ptr = luaL_checklstring(L, 2, &len); const char *ptr = luaL_checklstring(L, 2, &len);
item.metadata.setString("", std::string(ptr, len)); item.metadata.setString("", std::string(ptr, len));

@ -115,9 +115,7 @@ int MetaDataRef::l_set_string(lua_State *L)
MetaDataRef *ref = checkAnyMetadata(L, 1); MetaDataRef *ref = checkAnyMetadata(L, 1);
std::string name = luaL_checkstring(L, 2); std::string name = luaL_checkstring(L, 2);
size_t len = 0; auto str = readParam<std::string_view>(L, 3);
const char *s = lua_tolstring(L, 3, &len);
std::string str(s, len);
IMetadata *meta = ref->getmeta(!str.empty()); IMetadata *meta = ref->getmeta(!str.empty());
if (meta != NULL && meta->setString(name, str)) if (meta != NULL && meta->setString(name, str))
@ -300,9 +298,8 @@ bool MetaDataRef::handleFromTable(lua_State *L, int table, IMetadata *meta)
while (lua_next(L, fieldstable) != 0) { while (lua_next(L, fieldstable) != 0) {
// key at index -2 and value at index -1 // key at index -2 and value at index -1
std::string name = readParam<std::string>(L, -2); std::string name = readParam<std::string>(L, -2);
size_t cl; auto value = readParam<std::string_view>(L, -1);
const char *cs = lua_tolstring(L, -1, &cl); meta->setString(name, value);
meta->setString(name, std::string(cs, cl));
lua_pop(L, 1); // Remove value, keep key for next iteration lua_pop(L, 1); // Remove value, keep key for next iteration
} }
lua_pop(L, 1); lua_pop(L, 1);

@ -318,8 +318,7 @@ int ModApiUtil::l_compress(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
size_t size; auto data = readParam<std::string_view>(L, 1);
const char *data = luaL_checklstring(L, 1, &size);
LuaCompressMethod method = get_compress_method(L, 2); LuaCompressMethod method = get_compress_method(L, 2);
@ -330,13 +329,13 @@ int ModApiUtil::l_compress(lua_State *L)
if (!lua_isnoneornil(L, 3)) if (!lua_isnoneornil(L, 3))
level = readParam<int>(L, 3); level = readParam<int>(L, 3);
compressZlib(reinterpret_cast<const u8 *>(data), size, os, level); compressZlib(data, os, level);
} else if (method == LUA_COMPRESS_METHOD_ZSTD) { } else if (method == LUA_COMPRESS_METHOD_ZSTD) {
int level = ZSTD_CLEVEL_DEFAULT; int level = ZSTD_CLEVEL_DEFAULT;
if (!lua_isnoneornil(L, 3)) if (!lua_isnoneornil(L, 3))
level = readParam<int>(L, 3); level = readParam<int>(L, 3);
compressZstd(reinterpret_cast<const u8 *>(data), size, os, level); compressZstd(data, os, level);
} }
std::string out = os.str(); std::string out = os.str();
@ -350,12 +349,12 @@ int ModApiUtil::l_decompress(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
size_t size; auto data = readParam<std::string_view>(L, 1);
const char *data = luaL_checklstring(L, 1, &size);
LuaCompressMethod method = get_compress_method(L, 2); LuaCompressMethod method = get_compress_method(L, 2);
std::istringstream is(std::string(data, size), std::ios_base::binary); // FIXME: zero copy possible in c++26 or with custom rdbuf
std::istringstream is(std::string(data), std::ios_base::binary);
std::ostringstream os(std::ios_base::binary); std::ostringstream os(std::ios_base::binary);
if (method == LUA_COMPRESS_METHOD_DEFLATE) { if (method == LUA_COMPRESS_METHOD_DEFLATE) {
@ -375,10 +374,9 @@ int ModApiUtil::l_encode_base64(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
size_t size; auto data = readParam<std::string_view>(L, 1);
const char *data = luaL_checklstring(L, 1, &size);
std::string out = base64_encode((const unsigned char *)(data), size); std::string out = base64_encode(data);
lua_pushlstring(L, out.data(), out.size()); lua_pushlstring(L, out.data(), out.size());
return 1; return 1;
@ -389,9 +387,7 @@ int ModApiUtil::l_decode_base64(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
size_t size; auto data = readParam<std::string_view>(L, 1);
const char *d = luaL_checklstring(L, 1, &size);
const std::string data = std::string(d, size);
if (!base64_is_valid(data)) { if (!base64_is_valid(data)) {
lua_pushnil(L); lua_pushnil(L);
@ -487,12 +483,11 @@ int ModApiUtil::l_safe_file_write(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
const char *path = luaL_checkstring(L, 1); const char *path = luaL_checkstring(L, 1);
size_t size; auto content = readParam<std::string_view>(L, 2);
const char *content = luaL_checklstring(L, 2, &size);
CHECK_SECURE_PATH(L, path, true); CHECK_SECURE_PATH(L, path, true);
bool ret = fs::safeWriteToFile(path, std::string(content, size)); bool ret = fs::safeWriteToFile(path, content);
lua_pushboolean(L, ret); lua_pushboolean(L, ret);
return 1; return 1;
@ -549,18 +544,16 @@ int ModApiUtil::l_get_version(lua_State *L)
int ModApiUtil::l_sha1(lua_State *L) int ModApiUtil::l_sha1(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
size_t size;
const char *data = luaL_checklstring(L, 1, &size); auto data = readParam<std::string_view>(L, 1);
bool hex = !lua_isboolean(L, 2) || !readParam<bool>(L, 2); bool hex = !lua_isboolean(L, 2) || !readParam<bool>(L, 2);
// Compute actual checksum of data // Compute actual checksum of data
std::string data_sha1; std::string data_sha1;
{ {
SHA1 ctx; SHA1 ctx;
ctx.addBytes(data, size); ctx.addBytes(data);
unsigned char *data_tmpdigest = ctx.getDigest(); data_sha1 = ctx.getDigest();
data_sha1.assign((char*) data_tmpdigest, 20);
free(data_tmpdigest);
} }
if (hex) { if (hex) {
@ -654,8 +647,8 @@ int ModApiUtil::l_urlencode(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
const char *value = luaL_checkstring(L, 1); auto s = readParam<std::string_view>(L, 1);
lua_pushstring(L, urlencode(value).c_str()); lua_pushstring(L, urlencode(s).c_str());
return 1; return 1;
} }

@ -106,11 +106,6 @@ void compressZlib(const u8 *data, size_t data_size, std::ostream &os, int level)
} }
} }
void compressZlib(const std::string &data, std::ostream &os, int level)
{
compressZlib((u8*)data.c_str(), data.size(), os, level);
}
void decompressZlib(std::istream &is, std::ostream &os, size_t limit) void decompressZlib(std::istream &is, std::ostream &os, size_t limit)
{ {
z_stream z; z_stream z;
@ -211,7 +206,6 @@ void compressZstd(const u8 *data, size_t data_size, std::ostream &os, int level)
// it will be destroyed when the thread ends // it will be destroyed when the thread ends
thread_local std::unique_ptr<ZSTD_CStream, ZSTD_Deleter> stream(ZSTD_createCStream()); thread_local std::unique_ptr<ZSTD_CStream, ZSTD_Deleter> stream(ZSTD_createCStream());
ZSTD_initCStream(stream.get(), level); ZSTD_initCStream(stream.get(), level);
const size_t bufsize = 16384; const size_t bufsize = 16384;
@ -247,11 +241,6 @@ void compressZstd(const u8 *data, size_t data_size, std::ostream &os, int level)
} }
void compressZstd(const std::string &data, std::ostream &os, int level)
{
compressZstd((u8*)data.c_str(), data.size(), os, level);
}
void decompressZstd(std::istream &is, std::ostream &os) void decompressZstd(std::istream &is, std::ostream &os)
{ {
// reusing the context is recommended for performance // reusing the context is recommended for performance
@ -295,7 +284,7 @@ void decompressZstd(std::istream &is, std::ostream &os)
} }
} }
void compress(u8 *data, u32 size, std::ostream &os, u8 version, int level) void compress(const u8 *data, u32 size, std::ostream &os, u8 version, int level)
{ {
if(version >= 29) if(version >= 29)
{ {
@ -345,16 +334,6 @@ void compress(u8 *data, u32 size, std::ostream &os, u8 version, int level)
os.write((char*)&current_byte, 1); os.write((char*)&current_byte, 1);
} }
void compress(const SharedBuffer<u8> &data, std::ostream &os, u8 version, int level)
{
compress(*data, data.getSize(), os, version, level);
}
void compress(const std::string &data, std::ostream &os, u8 version, int level)
{
compress((u8*)data.c_str(), data.size(), os, version, level);
}
void decompress(std::istream &is, std::ostream &os, u8 version) void decompress(std::istream &is, std::ostream &os, u8 version)
{ {
if(version >= 29) if(version >= 29)

@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h" #include "irrlichttypes.h"
#include "exceptions.h" #include "exceptions.h"
#include <iostream> #include <iostream>
#include "util/pointer.h" #include <string_view>
/* /*
Map format serialization version Map format serialization version
@ -83,19 +83,27 @@ inline bool ser_ver_supported(s32 v) {
} }
/* /*
Misc. serialization functions Compression functions
*/ */
void compressZlib(const u8 *data, size_t data_size, std::ostream &os, int level = -1); void compressZlib(const u8 *data, size_t data_size, std::ostream &os, int level = -1);
void compressZlib(const std::string &data, std::ostream &os, int level = -1); inline void compressZlib(std::string_view data, std::ostream &os, int level = -1)
{
compressZlib(reinterpret_cast<const u8*>(data.data()), data.size(), os, level);
}
void decompressZlib(std::istream &is, std::ostream &os, size_t limit = 0); void decompressZlib(std::istream &is, std::ostream &os, size_t limit = 0);
void compressZstd(const u8 *data, size_t data_size, std::ostream &os, int level = 0); void compressZstd(const u8 *data, size_t data_size, std::ostream &os, int level = 0);
void compressZstd(const std::string &data, std::ostream &os, int level = 0); inline void compressZstd(std::string_view data, std::ostream &os, int level = 0)
{
compressZstd(reinterpret_cast<const u8*>(data.data()), data.size(), os, level);
}
void decompressZstd(std::istream &is, std::ostream &os); void decompressZstd(std::istream &is, std::ostream &os);
// These choose between zlib and a self-made one according to version // These choose between zstd, zlib and a self-made one according to version
void compress(const SharedBuffer<u8> &data, std::ostream &os, u8 version, int level = -1); void compress(const u8 *data, u32 size, std::ostream &os, u8 version, int level = -1);
void compress(const std::string &data, std::ostream &os, u8 version, int level = -1); inline void compress(std::string_view data, std::ostream &os, u8 version, int level = -1)
void compress(u8 *data, u32 size, std::ostream &os, u8 version, int level = -1); {
compress(reinterpret_cast<const u8*>(data.data()), data.size(), os, version, level);
}
void decompress(std::istream &is, std::ostream &os, u8 version); void decompress(std::istream &is, std::ostream &os, u8 version);

@ -2534,14 +2534,13 @@ bool Server::addMediaFile(const std::string &filename,
} }
SHA1 sha1; SHA1 sha1;
sha1.addBytes(filedata.c_str(), filedata.length()); sha1.addBytes(filedata);
unsigned char *digest = sha1.getDigest(); std::string digest = sha1.getDigest();
std::string sha1_base64 = base64_encode(digest, 20); std::string sha1_base64 = base64_encode(digest);
std::string sha1_hex = hex_encode((char*) digest, 20); std::string sha1_hex = hex_encode(digest);
if (digest_to) if (digest_to)
*digest_to = std::string((char*) digest, 20); *digest_to = digest;
free(digest);
// Put in list // Put in list
m_media[filename] = MediaInfo(filepath, sha1_base64); m_media[filename] = MediaInfo(filepath, sha1_base64);

@ -93,8 +93,8 @@ struct MediaInfo
// does what it says. used by some cases of dynamic media. // does what it says. used by some cases of dynamic media.
bool delete_at_shutdown; bool delete_at_shutdown;
MediaInfo(const std::string &path_="", MediaInfo(std::string_view path_ = "",
const std::string &sha1_digest_=""): std::string_view sha1_digest_ = ""):
path(path_), path(path_),
sha1_digest(sha1_digest_), sha1_digest(sha1_digest_),
no_announce(false), no_announce(false),

@ -97,7 +97,7 @@ void SettingsHierarchy::onLayerRemoved(int layer)
/* Settings implementation */ /* Settings implementation */
Settings *Settings::createLayer(SettingsLayer sl, const std::string &end_tag) Settings *Settings::createLayer(SettingsLayer sl, std::string_view end_tag)
{ {
return new Settings(end_tag, &g_hierarchy, (int)sl); return new Settings(end_tag, &g_hierarchy, (int)sl);
} }
@ -109,7 +109,7 @@ Settings *Settings::getLayer(SettingsLayer sl)
} }
Settings::Settings(const std::string &end_tag, SettingsHierarchy *h, Settings::Settings(std::string_view end_tag, SettingsHierarchy *h,
int settings_layer) : int settings_layer) :
m_end_tag(end_tag), m_end_tag(end_tag),
m_hierarchy(h), m_hierarchy(h),
@ -131,7 +131,7 @@ Settings::~Settings()
} }
Settings & Settings::operator = (const Settings &other) Settings & Settings::operator=(const Settings &other)
{ {
if (&other == this) if (&other == this)
return *this; return *this;
@ -151,7 +151,7 @@ Settings & Settings::operator = (const Settings &other)
} }
bool Settings::checkNameValid(const std::string &name) bool Settings::checkNameValid(std::string_view name)
{ {
bool valid = name.find_first_of("=\"{}#") == std::string::npos; bool valid = name.find_first_of("=\"{}#") == std::string::npos;
if (valid) if (valid)
@ -166,7 +166,7 @@ bool Settings::checkNameValid(const std::string &name)
} }
bool Settings::checkValueValid(const std::string &value) bool Settings::checkValueValid(std::string_view value)
{ {
if (value.substr(0, 3) == "\"\"\"" || if (value.substr(0, 3) == "\"\"\"" ||
value.find("\n\"\"\"") != std::string::npos) { value.find("\n\"\"\"") != std::string::npos) {
@ -407,13 +407,13 @@ bool Settings::parseCommandLine(int argc, char *argv[],
{ {
int nonopt_index = 0; int nonopt_index = 0;
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
std::string arg_name = argv[i]; std::string_view arg_name(argv[i]);
if (arg_name.substr(0, 2) != "--") { if (arg_name.substr(0, 2) != "--") {
// If option doesn't start with -, read it in as nonoptX // If option doesn't start with -, read it in as nonoptX
if (arg_name[0] != '-'){ if (arg_name[0] != '-') {
std::string name = "nonopt"; std::string name = "nonopt";
name += itos(nonopt_index); name += itos(nonopt_index);
set(name, arg_name); set(name, std::string(arg_name));
nonopt_index++; nonopt_index++;
continue; continue;
} }
@ -422,7 +422,7 @@ bool Settings::parseCommandLine(int argc, char *argv[],
return false; return false;
} }
std::string name = arg_name.substr(2); std::string name(arg_name.substr(2));
auto n = allowed_options.find(name); auto n = allowed_options.find(name);
if (n == allowed_options.end()) { if (n == allowed_options.end()) {
@ -997,7 +997,7 @@ bool Settings::remove(const std::string &name)
SettingsParseEvent Settings::parseConfigObject(const std::string &line, SettingsParseEvent Settings::parseConfigObject(const std::string &line,
std::string &name, std::string &value) std::string &name, std::string &value)
{ {
std::string trimmed_line = trim(line); auto trimmed_line = trim(line);
if (trimmed_line.empty()) if (trimmed_line.empty())
return SPE_NONE; return SPE_NONE;

@ -23,8 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h" #include "util/string.h"
#include "util/basic_macros.h" #include "util/basic_macros.h"
#include <string> #include <string>
#include <list>
#include <set> #include <set>
#include <map>
#include <mutex> #include <mutex>
class Settings; class Settings;
@ -124,18 +124,17 @@ typedef std::unordered_map<std::string, SettingsEntry> SettingEntries;
class Settings { class Settings {
public: public:
/* These functions operate on the global hierarchy! */ /* These functions operate on the global hierarchy! */
static Settings *createLayer(SettingsLayer sl, const std::string &end_tag = ""); static Settings *createLayer(SettingsLayer sl, std::string_view end_tag = "");
static Settings *getLayer(SettingsLayer sl); static Settings *getLayer(SettingsLayer sl);
/**/ /**/
Settings(const std::string &end_tag = "") : Settings(std::string_view end_tag = "") :
m_end_tag(end_tag) m_end_tag(end_tag)
{} {}
Settings(const std::string &end_tag, SettingsHierarchy *h, int settings_layer); Settings(std::string_view end_tag, SettingsHierarchy *h, int settings_layer);
~Settings(); ~Settings();
Settings & operator += (const Settings &other); Settings & operator=(const Settings &other);
Settings & operator = (const Settings &other);
/*********************** /***********************
* Reading and writing * * Reading and writing *
@ -258,8 +257,8 @@ private:
bool updateConfigObject(std::istream &is, std::ostream &os, bool updateConfigObject(std::istream &is, std::ostream &os,
u32 tab_depth=0); u32 tab_depth=0);
static bool checkNameValid(const std::string &name); static bool checkNameValid(std::string_view name);
static bool checkValueValid(const std::string &value); static bool checkValueValid(std::string_view value);
static std::string getMultiline(std::istream &is, size_t *num_lines=NULL); static std::string getMultiline(std::istream &is, size_t *num_lines=NULL);
static void printEntry(std::ostream &os, const std::string &name, static void printEntry(std::ostream &os, const std::string &name,
const SettingsEntry &entry, u32 tab_depth=0); const SettingsEntry &entry, u32 tab_depth=0);
@ -276,9 +275,7 @@ private:
// For sane mutex locking when iterating // For sane mutex locking when iterating
friend class LuaSettings; friend class LuaSettings;
void updateNoLock(const Settings &other);
void clearNoLock(); void clearNoLock();
void clearDefaultsNoLock();
void doCallbacks(const std::string &name) const; void doCallbacks(const std::string &name) const;

@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
struct SoundSpec struct SoundSpec
{ {
SoundSpec(const std::string &name = "", float gain = 1.0f, SoundSpec(std::string_view name = "", float gain = 1.0f,
bool loop = false, float fade = 0.0f, float pitch = 1.0f, bool loop = false, float fade = 0.0f, float pitch = 1.0f,
float start_time = 0.0f) : float start_time = 0.0f) :
name(name), gain(gain), fade(fade), pitch(pitch), start_time(start_time), name(name), gain(gain), fade(fade), pitch(pitch), start_time(start_time),

@ -57,7 +57,7 @@ void TestCompression::runTests(IGameDef *gamedef)
void TestCompression::testRLECompression() void TestCompression::testRLECompression()
{ {
SharedBuffer<u8> fromdata(4); Buffer<u8> fromdata(4);
fromdata[0]=1; fromdata[0]=1;
fromdata[1]=5; fromdata[1]=5;
fromdata[2]=5; fromdata[2]=5;
@ -106,7 +106,7 @@ void TestCompression::testRLECompression()
void TestCompression::testZlibCompression() void TestCompression::testZlibCompression()
{ {
SharedBuffer<u8> fromdata(4); Buffer<u8> fromdata(4);
fromdata[0]=1; fromdata[0]=1;
fromdata[1]=5; fromdata[1]=5;
fromdata[2]=5; fromdata[2]=5;

@ -189,10 +189,9 @@ void TestMapSettingsManager::testMapSettingsManager()
SHA1 ctx; SHA1 ctx;
std::string metafile_contents; std::string metafile_contents;
UASSERT(fs::ReadFile(test_mapmeta_path, metafile_contents)); UASSERT(fs::ReadFile(test_mapmeta_path, metafile_contents));
ctx.addBytes(&metafile_contents[0], metafile_contents.size()); ctx.addBytes(metafile_contents);
unsigned char *sha1_result = ctx.getDigest(); std::string sha1_result = ctx.getDigest();
int resultdiff = memcmp(sha1_result, expected_contents_hash, 20); int resultdiff = memcmp(sha1_result.data(), expected_contents_hash, 20);
free(sha1_result);
UASSERT(!resultdiff); UASSERT(!resultdiff);
#endif #endif

@ -240,20 +240,26 @@ void TestUtilities::testPadString()
void TestUtilities::testStartsWith() void TestUtilities::testStartsWith()
{ {
UASSERT(str_starts_with(std::string(), std::string()) == true); std::string the("the");
UASSERT(str_starts_with(std::string(), "") == true);
UASSERT(str_starts_with(std::string("the sharp pickaxe"), UASSERT(str_starts_with(std::string("the sharp pickaxe"),
std::string()) == true); std::string()) == true);
UASSERT(str_starts_with(std::string("the sharp pickaxe"), UASSERT(str_starts_with(std::string("the sharp pickaxe"),
std::string("the")) == true); std::string_view(the)) == true);
UASSERT(str_starts_with(std::string("the sharp pickaxe"), UASSERT(str_starts_with(std::string("the sharp pickaxe"),
std::string("The")) == false); std::string("The")) == false);
UASSERT(str_starts_with(std::string("the sharp pickaxe"), UASSERT(str_starts_with(std::string("the sharp pickaxe"),
std::string("The"), true) == true); std::string("The"), true) == true);
UASSERT(str_starts_with(std::string("T"), std::string("The")) == false); UASSERT(str_starts_with(std::string("T"), "The") == false);
} }
void TestUtilities::testStrEqual() void TestUtilities::testStrEqual()
{ {
std::string foo("foo");
UASSERT(str_equal(foo, std::string_view(foo)));
UASSERT(!str_equal(foo, std::string("bar")));
UASSERT(str_equal(std::string_view(foo), std::string_view(foo)));
UASSERT(str_equal(std::wstring(L"FOO"), std::wstring(L"foo"), true));
UASSERT(str_equal(utf8_to_wide("abc"), utf8_to_wide("abc"))); UASSERT(str_equal(utf8_to_wide("abc"), utf8_to_wide("abc")));
UASSERT(str_equal(utf8_to_wide("ABC"), utf8_to_wide("abc"), true)); UASSERT(str_equal(utf8_to_wide("ABC"), utf8_to_wide("abc"), true));
} }
@ -629,14 +635,14 @@ void TestUtilities::testBase64()
void TestUtilities::testSanitizeDirName() void TestUtilities::testSanitizeDirName()
{ {
UASSERT(sanitizeDirName("a", "~") == "a"); UASSERTEQ(auto, sanitizeDirName("a", "~"), "a");
UASSERT(sanitizeDirName(" ", "~") == "__"); UASSERTEQ(auto, sanitizeDirName(" ", "~"), "__");
UASSERT(sanitizeDirName(" a ", "~") == "_a_"); UASSERTEQ(auto, sanitizeDirName(" a ", "~"), "_a_");
UASSERT(sanitizeDirName("COM1", "~") == "~COM1"); UASSERTEQ(auto, sanitizeDirName("COM1", "~"), "~COM1");
UASSERT(sanitizeDirName("COM1", ":") == "_COM1"); UASSERTEQ(auto, sanitizeDirName("COM1", ":"), "_COM1");
UASSERT(sanitizeDirName("cOm\u00B2", "~") == "~cOm\u00B2"); UASSERTEQ(auto, sanitizeDirName("cOm\u00B2", "~"), "~cOm\u00B2");
UASSERT(sanitizeDirName("cOnIn$", "~") == "~cOnIn$"); UASSERTEQ(auto, sanitizeDirName("cOnIn$", "~"), "~cOnIn$");
UASSERT(sanitizeDirName(" cOnIn$ ", "~") == "_cOnIn$_"); UASSERTEQ(auto, sanitizeDirName(" cOnIn$ ", "~"), "_cOnIn$_");
} }
template <typename F, typename C> template <typename F, typename C>

@ -39,10 +39,9 @@ std::string translate_password(const std::string &name,
std::string slt = name + password; std::string slt = name + password;
SHA1 sha1; SHA1 sha1;
sha1.addBytes(slt.c_str(), slt.length()); sha1.addBytes(slt);
unsigned char *digest = sha1.getDigest(); std::string digest = sha1.getDigest();
std::string pwd = base64_encode(digest, 20); std::string pwd = base64_encode(digest);
free(digest);
return pwd; return pwd;
} }
@ -112,8 +111,8 @@ std::string encode_srp_verifier(const std::string &verifier,
{ {
std::ostringstream ret_str; std::ostringstream ret_str;
ret_str << "#1#" ret_str << "#1#"
<< base64_encode((unsigned char *)salt.c_str(), salt.size()) << "#" << base64_encode(salt) << "#"
<< base64_encode((unsigned char *)verifier.c_str(), verifier.size()); << base64_encode(verifier);
return ret_str.str(); return ret_str.str();
} }

@ -45,15 +45,15 @@ static inline bool is_base64(unsigned char c)
|| c == '+' || c == '/'; || c == '+' || c == '/';
} }
bool base64_is_valid(std::string const& s) bool base64_is_valid(std::string_view s)
{ {
size_t i = 0; size_t i = 0;
for (; i < s.size(); ++i) for (; i < s.size(); ++i)
if (!is_base64(s[i])) if (!is_base64(s[i]))
break; break;
unsigned char padding = 3 - ((i + 3) % 4); unsigned char padding = 3 - ((i + 3) % 4);
if ((padding == 1 && base64_chars_padding_1.find(s[i - 1]) == std::string::npos) if ((padding == 1 && base64_chars_padding_1.find(s[i - 1]) == s.npos)
|| (padding == 2 && base64_chars_padding_2.find(s[i - 1]) == std::string::npos) || (padding == 2 && base64_chars_padding_2.find(s[i - 1]) == s.npos)
|| padding == 3) || padding == 3)
return false; return false;
int actual_padding = s.size() - i; int actual_padding = s.size() - i;
@ -69,8 +69,14 @@ bool base64_is_valid(std::string const& s)
return padding == actual_padding; return padding == actual_padding;
} }
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { std::string base64_encode(std::string_view s)
{
const unsigned char *bytes_to_encode = reinterpret_cast<const unsigned char*>(s.data());
size_t in_len = s.size();
std::string ret; std::string ret;
ret.reserve(in_len + in_len / 3);
int i = 0; int i = 0;
int j = 0; int j = 0;
unsigned char char_array_3[3]; unsigned char char_array_3[3];
@ -110,16 +116,17 @@ std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_
} }
return ret; return ret;
} }
std::string base64_decode(std::string const& encoded_string) { std::string base64_decode(std::string_view encoded_string)
{
int in_len = encoded_string.size(); int in_len = encoded_string.size();
int i = 0; int i = 0;
int j = 0; int j = 0;
int in_ = 0; int in_ = 0;
unsigned char char_array_4[4], char_array_3[3]; unsigned char char_array_4[4], char_array_3[3];
std::string ret; std::string ret;
ret.reserve(in_len / 4 * 3);
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++; char_array_4[i++] = encoded_string[in_]; in_++;

@ -29,7 +29,8 @@ René Nyffenegger rene.nyffenegger@adp-gmbh.ch
#pragma once #pragma once
#include <string> #include <string>
#include <string_view>
bool base64_is_valid(std::string const& s); bool base64_is_valid(std::string_view s);
std::string base64_encode(unsigned char const* , unsigned int len); std::string base64_encode(std::string_view s);
std::string base64_decode(std::string const& s); std::string base64_decode(std::string_view s);

@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once #pragma once
#include <string> #include <string>
#include <string_view>
static const char hex_chars[] = "0123456789abcdef"; static const char hex_chars[] = "0123456789abcdef";
@ -41,9 +42,9 @@ static inline std::string hex_encode(const char *data, unsigned int data_size)
return ret; return ret;
} }
static inline std::string hex_encode(const std::string &data) static inline std::string hex_encode(std::string_view data)
{ {
return hex_encode(data.c_str(), data.size()); return hex_encode(data.data(), data.size());
} }
static inline bool hex_digit_decode(char hexdigit, unsigned char &value) static inline bool hex_digit_decode(char hexdigit, unsigned char &value)

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h" // For assert() #include "debug.h" // For assert()
#include <cstring> #include <cstring>
#include <memory> // std::shared_ptr #include <memory> // std::shared_ptr
#include <string_view>
template<typename T> class ConstSharedPtr { template<typename T> class ConstSharedPtr {
@ -133,6 +134,13 @@ public:
return m_size; return m_size;
} }
operator std::string_view() const
{
if (!data)
return std::string_view();
return std::string_view(reinterpret_cast<char*>(data), m_size);
}
private: private:
void drop() void drop()
{ {

@ -34,7 +34,7 @@ FloatType g_serialize_f32_type = FLOATTYPE_UNKNOWN;
//// String //// String
//// ////
std::string serializeString16(const std::string &plain) std::string serializeString16(std::string_view plain)
{ {
std::string s; std::string s;
char buf[2]; char buf[2];
@ -76,7 +76,7 @@ std::string deSerializeString16(std::istream &is)
//// Long String //// Long String
//// ////
std::string serializeString32(const std::string &plain) std::string serializeString32(std::string_view plain)
{ {
std::string s; std::string s;
char buf[4]; char buf[4];
@ -122,7 +122,7 @@ std::string deSerializeString32(std::istream &is)
//// JSON-like strings //// JSON-like strings
//// ////
std::string serializeJsonString(const std::string &plain) std::string serializeJsonString(std::string_view plain)
{ {
std::string tmp; std::string tmp;
@ -263,13 +263,13 @@ std::string deSerializeJsonString(std::istream &is)
return tmp; return tmp;
} }
std::string serializeJsonStringIfNeeded(const std::string &s) std::string serializeJsonStringIfNeeded(std::string_view s)
{ {
for (size_t i = 0; i < s.size(); ++i) { for (size_t i = 0; i < s.size(); ++i) {
if (s[i] <= 0x1f || s[i] >= 0x7f || s[i] == ' ' || s[i] == '\"') if (s[i] <= 0x1f || s[i] >= 0x7f || s[i] == ' ' || s[i] == '\"')
return serializeJsonString(s); return serializeJsonString(s);
} }
return s; return std::string(s);
} }
std::string deSerializeJsonStringIfNeeded(std::istream &is) std::string deSerializeJsonStringIfNeeded(std::istream &is)

@ -41,7 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <cstring> // for memcpy #include <cstring> // for memcpy
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <vector> #include <string_view>
#define FIXEDPOINT_FACTOR 1000.0f #define FIXEDPOINT_FACTOR 1000.0f
@ -450,26 +450,26 @@ inline v3f clampToF1000(v3f v)
} }
// Creates a string with the length as the first two bytes // Creates a string with the length as the first two bytes
std::string serializeString16(const std::string &plain); std::string serializeString16(std::string_view plain);
// Reads a string with the length as the first two bytes // Reads a string with the length as the first two bytes
std::string deSerializeString16(std::istream &is); std::string deSerializeString16(std::istream &is);
// Creates a string with the length as the first four bytes // Creates a string with the length as the first four bytes
std::string serializeString32(const std::string &plain); std::string serializeString32(std::string_view plain);
// Reads a string with the length as the first four bytes // Reads a string with the length as the first four bytes
std::string deSerializeString32(std::istream &is); std::string deSerializeString32(std::istream &is);
// Creates a string encoded in JSON format (almost equivalent to a C string literal) // Creates a string encoded in JSON format (almost equivalent to a C string literal)
std::string serializeJsonString(const std::string &plain); std::string serializeJsonString(std::string_view plain);
// Reads a string encoded in JSON format // Reads a string encoded in JSON format
std::string deSerializeJsonString(std::istream &is); std::string deSerializeJsonString(std::istream &is);
// If the string contains spaces, quotes or control characters, encodes as JSON. // If the string contains spaces, quotes or control characters, encodes as JSON.
// Else returns the string unmodified. // Else returns the string unmodified.
std::string serializeJsonStringIfNeeded(const std::string &s); std::string serializeJsonStringIfNeeded(std::string_view s);
// Parses a string serialized by serializeJsonStringIfNeeded. // Parses a string serialized by serializeJsonStringIfNeeded.
std::string deSerializeJsonStringIfNeeded(std::istream &is); std::string deSerializeJsonStringIfNeeded(std::istream &is);

@ -65,7 +65,7 @@ void SHA1::storeBigEndianUint32( unsigned char* byte, Uint32 num )
SHA1::SHA1() SHA1::SHA1()
{ {
// make sure that the data type is the right size // make sure that the data type is the right size
assert( sizeof( Uint32 ) * 5 == 20 ); static_assert( sizeof( Uint32 ) * 5 == 20 );
} }
// Destructor ******************************************************** // Destructor ********************************************************
@ -134,20 +134,19 @@ void SHA1::process()
} }
// addBytes ********************************************************** // addBytes **********************************************************
void SHA1::addBytes( const char* data, int num ) void SHA1::addBytes( const char* data, Uint32 num )
{ {
assert( data ); assert( data );
assert( num >= 0 );
// add these bytes to the running total // add these bytes to the running total
size += num; size += num;
// repeat until all data is processed // repeat until all data is processed
while( num > 0 ) while( num > 0 )
{ {
// number of bytes required to complete block // number of bytes required to complete block
int needed = 64 - unprocessedBytes; Uint32 needed = 64 - unprocessedBytes;
assert( needed > 0 ); assert( needed <= 64 );
// number of bytes to copy (use smaller of two) // number of bytes to copy (use smaller of two)
int toCopy = (num < needed) ? num : needed; Uint32 toCopy = (num < needed) ? num : needed;
// Copy the bytes // Copy the bytes
memcpy( bytes + unprocessedBytes, data, toCopy ); memcpy( bytes + unprocessedBytes, data, toCopy );
// Bytes have been copied // Bytes have been copied
@ -161,7 +160,7 @@ void SHA1::addBytes( const char* data, int num )
} }
// digest ************************************************************ // digest ************************************************************
unsigned char* SHA1::getDigest() void SHA1::getDigest(unsigned char *digest)
{ {
// save the message size // save the message size
Uint32 totalBitsL = size << 3; Uint32 totalBitsL = size << 3;
@ -179,20 +178,16 @@ unsigned char* SHA1::getDigest()
addBytes( (char*)footer, 64 - unprocessedBytes); addBytes( (char*)footer, 64 - unprocessedBytes);
assert( unprocessedBytes <= 56 ); assert( unprocessedBytes <= 56 );
// how many zeros do we need // how many zeros do we need
int neededZeros = 56 - unprocessedBytes; Uint32 neededZeros = 56 - unprocessedBytes;
// store file size (in bits) in big-endian format // store file size (in bits) in big-endian format
storeBigEndianUint32( footer + neededZeros , totalBitsH ); storeBigEndianUint32( footer + neededZeros , totalBitsH );
storeBigEndianUint32( footer + neededZeros + 4, totalBitsL ); storeBigEndianUint32( footer + neededZeros + 4, totalBitsL );
// finish the final block // finish the final block
addBytes( (char*)footer, neededZeros + 8 ); addBytes( (char*)footer, neededZeros + 8 );
// allocate memory for the digest bytes
unsigned char* digest = (unsigned char*)malloc( 20 );
// copy the digest bytes // copy the digest bytes
storeBigEndianUint32( digest, H0 ); storeBigEndianUint32( digest, H0 );
storeBigEndianUint32( digest + 4, H1 ); storeBigEndianUint32( digest + 4, H1 );
storeBigEndianUint32( digest + 8, H2 ); storeBigEndianUint32( digest + 8, H2 );
storeBigEndianUint32( digest + 12, H3 ); storeBigEndianUint32( digest + 12, H3 );
storeBigEndianUint32( digest + 16, H4 ); storeBigEndianUint32( digest + 16, H4 );
// return the digest
return digest;
} }

@ -26,7 +26,11 @@ SOFTWARE.
#pragma once #pragma once
typedef unsigned int Uint32; #include <cstdint>
#include <string>
#include <string_view>
typedef uint32_t Uint32;
class SHA1 class SHA1
{ {
@ -38,15 +42,24 @@ private:
Uint32 H3 = 0x10325476; Uint32 H3 = 0x10325476;
Uint32 H4 = 0xc3d2e1f0; Uint32 H4 = 0xc3d2e1f0;
unsigned char bytes[64]; unsigned char bytes[64];
int unprocessedBytes = 0; Uint32 unprocessedBytes = 0;
Uint32 size = 0; Uint32 size = 0;
void process(); void process();
public: public:
SHA1(); SHA1();
~SHA1(); ~SHA1();
void addBytes(const char *data, int num); void addBytes(const char *data, Uint32 num);
unsigned char *getDigest(); inline void addBytes(std::string_view data) {
addBytes(data.data(), data.size());
}
void getDigest(unsigned char *to);
inline std::string getDigest() {
std::string ret(20, '\000');
getDigest(reinterpret_cast<unsigned char*>(ret.data()));
return ret;
}
// utility methods // utility methods
static Uint32 lrot(Uint32 x, int bits); static Uint32 lrot(Uint32 x, int bits);
static void storeBigEndianUint32(unsigned char *byte, Uint32 num); static void storeBigEndianUint32(unsigned char *byte, Uint32 num);

@ -20,14 +20,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once #pragma once
#include <string> #include <string>
#include <string_view>
// FIXME: convert this class to string_view
template <typename T> template <typename T>
class BasicStrfnd { class BasicStrfnd {
typedef std::basic_string<T> String; typedef std::basic_string<T> String;
String str; String str;
size_t pos; size_t pos;
public: public:
BasicStrfnd(const String &s) : str(s), pos(0) {} BasicStrfnd(const String &s) { start(s); }
BasicStrfnd(const T *ptr) { str = ptr; pos = 0; }
BasicStrfnd(std::basic_string_view<T> sv) { str = sv; pos = 0; }
void start(const String &s) { str = s; pos = 0; } void start(const String &s) { str = s; pos = 0; }
size_t where() { return pos; } size_t where() { return pos; }
void to(size_t i) { pos = i; } void to(size_t i) { pos = i; }

@ -82,14 +82,14 @@ const char *DEFAULT_ENCODING = "UTF-32LE";
const char *DEFAULT_ENCODING = "WCHAR_T"; const char *DEFAULT_ENCODING = "WCHAR_T";
#endif #endif
std::wstring utf8_to_wide(const std::string &input) std::wstring utf8_to_wide(std::string_view input)
{ {
const size_t inbuf_size = input.length(); const size_t inbuf_size = input.length();
// maximum possible size, every character is sizeof(wchar_t) bytes // maximum possible size, every character is sizeof(wchar_t) bytes
size_t outbuf_size = input.length() * sizeof(wchar_t); size_t outbuf_size = input.length() * sizeof(wchar_t);
char *inbuf = new char[inbuf_size]; // intentionally NOT null-terminated char *inbuf = new char[inbuf_size]; // intentionally NOT null-terminated
memcpy(inbuf, input.c_str(), inbuf_size); memcpy(inbuf, input.data(), inbuf_size);
std::wstring out; std::wstring out;
out.resize(outbuf_size / sizeof(wchar_t)); out.resize(outbuf_size / sizeof(wchar_t));
@ -110,14 +110,14 @@ std::wstring utf8_to_wide(const std::string &input)
return out; return out;
} }
std::string wide_to_utf8(const std::wstring &input) std::string wide_to_utf8(std::wstring_view input)
{ {
const size_t inbuf_size = input.length() * sizeof(wchar_t); const size_t inbuf_size = input.length() * sizeof(wchar_t);
// maximum possible size: utf-8 encodes codepoints using 1 up to 4 bytes // maximum possible size: utf-8 encodes codepoints using 1 up to 4 bytes
size_t outbuf_size = input.length() * 4; size_t outbuf_size = input.length() * 4;
char *inbuf = new char[inbuf_size]; // intentionally NOT null-terminated char *inbuf = new char[inbuf_size]; // intentionally NOT null-terminated
memcpy(inbuf, input.c_str(), inbuf_size); memcpy(inbuf, input.data(), inbuf_size);
std::string out; std::string out;
out.resize(outbuf_size); out.resize(outbuf_size);
@ -135,24 +135,24 @@ std::string wide_to_utf8(const std::wstring &input)
#else // _WIN32 #else // _WIN32
std::wstring utf8_to_wide(const std::string &input) std::wstring utf8_to_wide(std::string_view input)
{ {
size_t outbuf_size = input.size() + 1; size_t outbuf_size = input.size() + 1;
wchar_t *outbuf = new wchar_t[outbuf_size]; wchar_t *outbuf = new wchar_t[outbuf_size];
memset(outbuf, 0, outbuf_size * sizeof(wchar_t)); memset(outbuf, 0, outbuf_size * sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, input.c_str(), input.size(), MultiByteToWideChar(CP_UTF8, 0, input.data(), input.size(),
outbuf, outbuf_size); outbuf, outbuf_size);
std::wstring out(outbuf); std::wstring out(outbuf);
delete[] outbuf; delete[] outbuf;
return out; return out;
} }
std::string wide_to_utf8(const std::wstring &input) std::string wide_to_utf8(std::wstring_view input)
{ {
size_t outbuf_size = (input.size() + 1) * 6; size_t outbuf_size = (input.size() + 1) * 6;
char *outbuf = new char[outbuf_size]; char *outbuf = new char[outbuf_size];
memset(outbuf, 0, outbuf_size); memset(outbuf, 0, outbuf_size);
WideCharToMultiByte(CP_UTF8, 0, input.c_str(), input.size(), WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(),
outbuf, outbuf_size, NULL, NULL); outbuf, outbuf_size, NULL, NULL);
std::string out(outbuf); std::string out(outbuf);
delete[] outbuf; delete[] outbuf;
@ -162,9 +162,9 @@ std::string wide_to_utf8(const std::wstring &input)
#endif // _WIN32 #endif // _WIN32
std::string urlencode(const std::string &str) std::string urlencode(std::string_view str)
{ {
// Encodes non-unreserved URI characters by a percent sign // Encodes reserved URI characters by a percent sign
// followed by two hex digits. See RFC 3986, section 2.3. // followed by two hex digits. See RFC 3986, section 2.3.
static const char url_hex_chars[] = "0123456789ABCDEF"; static const char url_hex_chars[] = "0123456789ABCDEF";
std::ostringstream oss(std::ios::binary); std::ostringstream oss(std::ios::binary);
@ -180,7 +180,7 @@ std::string urlencode(const std::string &str)
return oss.str(); return oss.str();
} }
std::string urldecode(const std::string &str) std::string urldecode(std::string_view str)
{ {
// Inverse of urlencode // Inverse of urlencode
std::ostringstream oss(std::ios::binary); std::ostringstream oss(std::ios::binary);
@ -615,10 +615,10 @@ void str_replace(std::string &str, char from, char to)
* before filling it again. * before filling it again.
*/ */
void translate_all(const std::wstring &s, size_t &i, static void translate_all(const std::wstring &s, size_t &i,
Translations *translations, std::wstring &res); Translations *translations, std::wstring &res);
void translate_string(const std::wstring &s, Translations *translations, static void translate_string(const std::wstring &s, Translations *translations,
const std::wstring &textdomain, size_t &i, std::wstring &res) const std::wstring &textdomain, size_t &i, std::wstring &res)
{ {
std::wostringstream output; std::wostringstream output;
@ -732,14 +732,15 @@ void translate_string(const std::wstring &s, Translations *translations,
res = result.str(); res = result.str();
} }
void translate_all(const std::wstring &s, size_t &i, static void translate_all(const std::wstring &s, size_t &i,
Translations *translations, std::wstring &res) Translations *translations, std::wstring &res)
{ {
std::wostringstream output; res.clear();
res.reserve(s.length());
while (i < s.length()) { while (i < s.length()) {
// Not an escape sequence: just add the character. // Not an escape sequence: just add the character.
if (s[i] != '\x1b') { if (s[i] != '\x1b') {
output.put(s[i]); res.append(1, s[i]);
++i; ++i;
continue; continue;
} }
@ -747,7 +748,7 @@ void translate_all(const std::wstring &s, size_t &i,
// We have an escape sequence: locate it and its data // We have an escape sequence: locate it and its data
// It is either a single character, or it begins with '(' // It is either a single character, or it begins with '('
// and extends up to the following ')', with '\' as an escape character. // and extends up to the following ')', with '\' as an escape character.
size_t escape_start = i; const size_t escape_start = i;
++i; ++i;
size_t start_index = i; size_t start_index = i;
size_t length; size_t length;
@ -784,14 +785,12 @@ void translate_all(const std::wstring &s, size_t &i,
textdomain = parts[1]; textdomain = parts[1];
std::wstring translated; std::wstring translated;
translate_string(s, translations, textdomain, i, translated); translate_string(s, translations, textdomain, i, translated);
output << translated; res.append(translated);
} else { } else {
// Another escape sequence, such as colors. Preserve it. // Another escape sequence, such as colors. Preserve it.
output << std::wstring(s, escape_start, i - escape_start); res.append(&s[escape_start], i - escape_start);
} }
} }
res = output.str();
} }
// Translate string server side // Translate string server side
@ -813,7 +812,7 @@ std::wstring translate_string(const std::wstring &s)
#endif #endif
} }
static const std::array<std::wstring, 30> disallowed_dir_names = { static const std::array<std::wstring_view, 30> disallowed_dir_names = {
// Problematic filenames from here: // Problematic filenames from here:
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#file-and-directory-names // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#file-and-directory-names
// Plus undocumented values from here: // Plus undocumented values from here:
@ -853,10 +852,10 @@ static const std::array<std::wstring, 30> disallowed_dir_names = {
/** /**
* List of characters that are blacklisted from created directories * List of characters that are blacklisted from created directories
*/ */
static const std::wstring disallowed_path_chars = L"<>:\"/\\|?*."; static const std::wstring_view disallowed_path_chars = L"<>:\"/\\|?*.";
std::string sanitizeDirName(const std::string &str, const std::string &optional_prefix) std::string sanitizeDirName(std::string_view str, std::string_view optional_prefix)
{ {
std::wstring safe_name = utf8_to_wide(str); std::wstring safe_name = utf8_to_wide(str);
@ -897,7 +896,7 @@ std::string sanitizeDirName(const std::string &str, const std::string &optional_
} }
void safe_print_string(std::ostream &os, const std::string &str) void safe_print_string(std::ostream &os, std::string_view str)
{ {
std::ostream::fmtflags flags = os.flags(); std::ostream::fmtflags flags = os.flags();
os << std::hex; os << std::hex;
@ -913,7 +912,7 @@ void safe_print_string(std::ostream &os, const std::string &str)
} }
v3f str_to_v3f(const std::string &str) v3f str_to_v3f(std::string_view str)
{ {
v3f value; v3f value;
Strfnd f(str); Strfnd f(str);

@ -23,10 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrString.h" #include "irrString.h"
#include <cstdlib> #include <cstdlib>
#include <string> #include <string>
#include <string_view>
#include <cstring> #include <cstring>
#include <vector> #include <vector>
#include <limits> #include <limits>
#include <map>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <cctype> #include <cctype>
@ -76,15 +76,18 @@ struct FlagDesc {
// Try to avoid converting between wide and UTF-8 unless you need to // Try to avoid converting between wide and UTF-8 unless you need to
// input/output stuff via Irrlicht // input/output stuff via Irrlicht
std::wstring utf8_to_wide(const std::string &input); std::wstring utf8_to_wide(std::string_view input);
std::string wide_to_utf8(const std::wstring &input); std::string wide_to_utf8(std::wstring_view input);
std::string urlencode(std::string_view str);
std::string urldecode(std::string_view str);
std::string urlencode(const std::string &str);
std::string urldecode(const std::string &str);
u32 readFlagString(std::string str, const FlagDesc *flagdesc, u32 *flagmask); u32 readFlagString(std::string str, const FlagDesc *flagdesc, u32 *flagmask);
std::string writeFlagString(u32 flags, const FlagDesc *flagdesc, u32 flagmask); std::string writeFlagString(u32 flags, const FlagDesc *flagdesc, u32 flagmask);
size_t mystrlcpy(char *dst, const char *src, size_t size) noexcept; size_t mystrlcpy(char *dst, const char *src, size_t size) noexcept;
char *mystrtok_r(char *s, const char *sep, char **lasts) noexcept; char *mystrtok_r(char *s, const char *sep, char **lasts) noexcept;
u64 read_seed(const char *str); u64 read_seed(const char *str);
bool parseColorString(const std::string &value, video::SColor &color, bool quiet, bool parseColorString(const std::string &value, video::SColor &color, bool quiet,
unsigned char default_alpha = 0xff); unsigned char default_alpha = 0xff);
@ -115,23 +118,32 @@ inline std::string padStringRight(std::string str, size_t len)
* *
* @return If no end could be removed then "" is returned. * @return If no end could be removed then "" is returned.
*/ */
inline std::string removeStringEnd(const std::string &str, inline std::string_view removeStringEnd(std::string_view str,
const char *ends[]) const char *ends[])
{ {
const char **p = ends; const char **p = ends;
for (; *p && (*p)[0] != '\0'; p++) { for (; *p && (*p)[0] != '\0'; p++) {
std::string end = *p; std::string_view end(*p);
if (str.size() < end.size()) if (str.size() < end.size())
continue; continue;
if (str.compare(str.size() - end.size(), end.size(), end) == 0) if (str.compare(str.size() - end.size(), end.size(), end) == 0)
return str.substr(0, str.size() - end.size()); return str.substr(0, str.size() - end.size());
} }
return ""; return std::string_view();
} }
#define MAKE_VARIANT(_name, _t0, _t1) \
template <typename T, typename... Args> \
inline auto _name(_t0 arg1, _t1 arg2, Args&&... args) \
{ \
return (_name)(std::basic_string_view<T>(arg1), std::basic_string_view<T>(arg2), \
std::forward<Args>(args)...); \
}
/** /**
* Check two strings for equivalence. If \p case_insensitive is true * Check two strings for equivalence. If \p case_insensitive is true
* then the case of the strings is ignored (default is false). * then the case of the strings is ignored (default is false).
@ -142,8 +154,8 @@ inline std::string removeStringEnd(const std::string &str,
* @return true if the strings match * @return true if the strings match
*/ */
template <typename T> template <typename T>
inline bool str_equal(const std::basic_string<T> &s1, inline bool str_equal(std::basic_string_view<T> s1,
const std::basic_string<T> &s2, std::basic_string_view<T> s2,
bool case_insensitive = false) bool case_insensitive = false)
{ {
if (!case_insensitive) if (!case_insensitive)
@ -159,6 +171,16 @@ inline bool str_equal(const std::basic_string<T> &s1,
return true; return true;
} }
// For some reason an std::string will not implicitly get converted
// to an std::basic_string_view<char> in the template case above, so we need
// these three wrappers. It works if you take out the template parameters.
// see also <https://stackoverflow.com/questions/68380141/>
MAKE_VARIANT(str_equal, const std::basic_string<T> &, const std::basic_string<T> &)
MAKE_VARIANT(str_equal, std::basic_string_view<T>, const std::basic_string<T> &)
MAKE_VARIANT(str_equal, const std::basic_string<T> &, std::basic_string_view<T>)
/** /**
* Check whether \p str begins with the string prefix. If \p case_insensitive * Check whether \p str begins with the string prefix. If \p case_insensitive
@ -171,8 +193,8 @@ inline bool str_equal(const std::basic_string<T> &s1,
* @return true if the str begins with prefix * @return true if the str begins with prefix
*/ */
template <typename T> template <typename T>
inline bool str_starts_with(const std::basic_string<T> &str, inline bool str_starts_with(std::basic_string_view<T> str,
const std::basic_string<T> &prefix, std::basic_string_view<T> prefix,
bool case_insensitive = false) bool case_insensitive = false)
{ {
if (str.size() < prefix.size()) if (str.size() < prefix.size())
@ -187,24 +209,17 @@ inline bool str_starts_with(const std::basic_string<T> &str,
return true; return true;
} }
/** // (same conversion issue here)
* Check whether \p str begins with the string prefix. If \p case_insensitive MAKE_VARIANT(str_starts_with, const std::basic_string<T> &, const std::basic_string<T> &)
* is true then the check is case insensitve (default is false; i.e. case is
* significant). MAKE_VARIANT(str_starts_with, std::basic_string_view<T>, const std::basic_string<T> &)
*
* @param str MAKE_VARIANT(str_starts_with, const std::basic_string<T> &, std::basic_string_view<T>)
* @param prefix
* @param case_insensitive // (the same but with char pointers, only for the prefix argument)
* @return true if the str begins with prefix MAKE_VARIANT(str_starts_with, const std::basic_string<T> &, const T*)
*/
template <typename T> MAKE_VARIANT(str_starts_with, std::basic_string_view<T>, const T*)
inline bool str_starts_with(const std::basic_string<T> &str,
const T *prefix,
bool case_insensitive = false)
{
return str_starts_with(str, std::basic_string<T>(prefix),
case_insensitive);
}
/** /**
@ -218,8 +233,8 @@ inline bool str_starts_with(const std::basic_string<T> &str,
* @return true if the str begins with suffix * @return true if the str begins with suffix
*/ */
template <typename T> template <typename T>
inline bool str_ends_with(const std::basic_string<T> &str, inline bool str_ends_with(std::basic_string_view<T> str,
const std::basic_string<T> &suffix, std::basic_string_view<T> suffix,
bool case_insensitive = false) bool case_insensitive = false)
{ {
if (str.size() < suffix.size()) if (str.size() < suffix.size())
@ -235,25 +250,20 @@ inline bool str_ends_with(const std::basic_string<T> &str,
return true; return true;
} }
// (same conversion issue here)
MAKE_VARIANT(str_ends_with, const std::basic_string<T> &, const std::basic_string<T> &)
/** MAKE_VARIANT(str_ends_with, std::basic_string_view<T>, const std::basic_string<T> &)
* Check whether \p str ends with the string suffix. If \p case_insensitive
* is true then the check is case insensitve (default is false; i.e. case is MAKE_VARIANT(str_ends_with, const std::basic_string<T> &, std::basic_string_view<T>)
* significant).
* // (the same but with char pointers, only for the suffix argument)
* @param str MAKE_VARIANT(str_ends_with, const std::basic_string<T> &, const T*)
* @param suffix
* @param case_insensitive MAKE_VARIANT(str_ends_with, std::basic_string_view<T>, const T*)
* @return true if the str begins with suffix
*/
template <typename T> #undef MAKE_VARIANT
inline bool str_ends_with(const std::basic_string<T> &str,
const T *suffix,
bool case_insensitive = false)
{
return str_ends_with(str, std::basic_string<T>(suffix),
case_insensitive);
}
/** /**
@ -282,24 +292,21 @@ inline std::vector<std::basic_string<T> > str_split(
* @param str * @param str
* @return A copy of \p str converted to all lowercase characters. * @return A copy of \p str converted to all lowercase characters.
*/ */
inline std::string lowercase(const std::string &str) inline std::string lowercase(std::string_view str)
{ {
std::string s2; std::string s2;
s2.resize(str.size());
s2.reserve(str.size()); for (size_t i = 0; i < str.size(); i++)
s2[i] = tolower(str[i]);
for (char i : str)
s2 += tolower(i);
return s2; return s2;
} }
/** /**
* @param str * @param str
* @return A copy of \p str with leading and trailing whitespace removed. * @return A view of \p str with leading and trailing whitespace removed.
*/ */
inline std::string trim(const std::string &str) inline std::string_view trim(std::string_view str)
{ {
size_t front = 0; size_t front = 0;
size_t back = str.size(); size_t back = str.size();
@ -313,6 +320,26 @@ inline std::string trim(const std::string &str)
return str.substr(front, back - front); return str.substr(front, back - front);
} }
// If input was a temporary string keep it one to make sure patterns like
// trim(func_that_returns_str()) are predictable regarding memory allocation
// and don't lead to UAF. ↓ ↓ ↓
/**
* @param str
* @return A copy of \p str with leading and trailing whitespace removed.
*/
inline std::string trim(std::string &&str)
{
std::string ret(trim(std::string_view(str)));
return ret;
}
// The above declaration causes ambiguity with char pointers so we have to fix that:
inline std::string_view trim(const char *str)
{
return trim(std::string_view(str));
}
/** /**
* Returns whether \p str should be regarded as (bool) true. Case and leading * Returns whether \p str should be regarded as (bool) true. Case and leading
@ -320,7 +347,7 @@ inline std::string trim(const std::string &str)
* true are "y", "yes", "true" and any number that is not 0. * true are "y", "yes", "true" and any number that is not 0.
* @param str * @param str
*/ */
inline bool is_yes(const std::string &str) inline bool is_yes(std::string_view str)
{ {
std::string s2 = lowercase(trim(str)); std::string s2 = lowercase(trim(str));
@ -377,7 +404,7 @@ inline float mystof(const std::string &str)
template <typename T> template <typename T>
inline T from_string(const std::string &str) inline T from_string(const std::string &str)
{ {
std::stringstream tmp(str); std::istringstream tmp(str);
T t; T t;
tmp >> t; tmp >> t;
return t; return t;
@ -386,42 +413,6 @@ inline T from_string(const std::string &str)
/// Returns a 64-bit signed value represented by the string \p str (decimal). /// Returns a 64-bit signed value represented by the string \p str (decimal).
inline s64 stoi64(const std::string &str) { return from_string<s64>(str); } inline s64 stoi64(const std::string &str) { return from_string<s64>(str); }
#if __cplusplus < 201103L
namespace std {
/// Returns a string representing the value \p val.
template <typename T>
inline string to_string(T val)
{
ostringstream oss;
oss << val;
return oss.str();
}
#define DEFINE_STD_TOSTRING_FLOATINGPOINT(T) \
template <> \
inline string to_string<T>(T val) \
{ \
ostringstream oss; \
oss << std::fixed \
<< std::setprecision(6) \
<< val; \
return oss.str(); \
}
DEFINE_STD_TOSTRING_FLOATINGPOINT(float)
DEFINE_STD_TOSTRING_FLOATINGPOINT(double)
DEFINE_STD_TOSTRING_FLOATINGPOINT(long double)
#undef DEFINE_STD_TOSTRING_FLOATINGPOINT
/// Returns a wide string representing the value \p val
template <typename T>
inline wstring to_wstring(T val)
{
return utf8_to_wide(to_string(val));
}
}
#endif
/// Returns a string representing the decimal value of the 32-bit value \p i. /// Returns a string representing the decimal value of the 32-bit value \p i.
inline std::string itos(s32 i) { return std::to_string(i); } inline std::string itos(s32 i) { return std::to_string(i); }
/// Returns a string representing the decimal value of the 64-bit value \p i. /// Returns a string representing the decimal value of the 64-bit value \p i.
@ -443,8 +434,8 @@ inline std::string ftos(float f)
* @param pattern The pattern to replace. * @param pattern The pattern to replace.
* @param replacement What to replace the pattern with. * @param replacement What to replace the pattern with.
*/ */
inline void str_replace(std::string &str, const std::string &pattern, inline void str_replace(std::string &str, std::string_view pattern,
const std::string &replacement) std::string_view replacement)
{ {
std::string::size_type start = str.find(pattern, 0); std::string::size_type start = str.find(pattern, 0);
while (start != str.npos) { while (start != str.npos) {
@ -454,7 +445,7 @@ inline void str_replace(std::string &str, const std::string &pattern,
} }
/** /**
* Escapes characters [ ] \ , ; that cannot be used in formspecs * Escapes characters that cannot be used in formspecs
*/ */
inline void str_formspec_escape(std::string &str) inline void str_formspec_escape(std::string &str)
{ {
@ -486,7 +477,7 @@ void str_replace(std::string &str, char from, char to);
* *
* @see string_allowed_blacklist() * @see string_allowed_blacklist()
*/ */
inline bool string_allowed(const std::string &str, const std::string &allowed_chars) inline bool string_allowed(std::string_view str, std::string_view allowed_chars)
{ {
return str.find_first_not_of(allowed_chars) == str.npos; return str.find_first_not_of(allowed_chars) == str.npos;
} }
@ -502,8 +493,8 @@ inline bool string_allowed(const std::string &str, const std::string &allowed_ch
* @see string_allowed() * @see string_allowed()
*/ */
inline bool string_allowed_blacklist(const std::string &str, inline bool string_allowed_blacklist(std::string_view str,
const std::string &blacklisted_chars) std::string_view blacklisted_chars)
{ {
return str.find_first_of(blacklisted_chars) == str.npos; return str.find_first_of(blacklisted_chars) == str.npos;
} }
@ -524,12 +515,12 @@ inline bool string_allowed_blacklist(const std::string &str,
* @param row_len The row length (in characters). * @param row_len The row length (in characters).
* @return A new string with the wrapping applied. * @return A new string with the wrapping applied.
*/ */
inline std::string wrap_rows(const std::string &from, inline std::string wrap_rows(std::string_view from, unsigned row_len)
unsigned row_len)
{ {
std::string to; std::string to;
to.reserve(from.size());
size_t character_idx = 0; unsigned character_idx = 0;
for (size_t i = 0; i < from.size(); i++) { for (size_t i = 0; i < from.size(); i++) {
if (!IS_UTF8_MULTB_INNER(from[i])) { if (!IS_UTF8_MULTB_INNER(from[i])) {
// Wrap string after last inner byte of char // Wrap string after last inner byte of char
@ -551,6 +542,7 @@ template <typename T>
inline std::basic_string<T> unescape_string(const std::basic_string<T> &s) inline std::basic_string<T> unescape_string(const std::basic_string<T> &s)
{ {
std::basic_string<T> res; std::basic_string<T> res;
res.reserve(s.size());
for (size_t i = 0; i < s.length(); i++) { for (size_t i = 0; i < s.length(); i++) {
if (s[i] == '\\') { if (s[i] == '\\') {
@ -574,6 +566,7 @@ template <typename T>
std::basic_string<T> unescape_enriched(const std::basic_string<T> &s) std::basic_string<T> unescape_enriched(const std::basic_string<T> &s)
{ {
std::basic_string<T> output; std::basic_string<T> output;
output.reserve(s.size());
size_t i = 0; size_t i = 0;
while (i < s.length()) { while (i < s.length()) {
if (s[i] == '\x1b') { if (s[i] == '\x1b') {
@ -646,7 +639,7 @@ inline std::wstring unescape_translate(const std::wstring &s) {
* @return true if to_check is not empty and all characters in to_check are * @return true if to_check is not empty and all characters in to_check are
* decimal digits, otherwise false * decimal digits, otherwise false
*/ */
inline bool is_number(const std::string &to_check) inline bool is_number(std::string_view to_check)
{ {
for (char i : to_check) for (char i : to_check)
if (!std::isdigit(i)) if (!std::isdigit(i))
@ -720,7 +713,7 @@ inline const std::string duration_to_string(int sec)
* @return A std::string * @return A std::string
*/ */
inline std::string str_join(const std::vector<std::string> &list, inline std::string str_join(const std::vector<std::string> &list,
const std::string &delimiter) std::string_view delimiter)
{ {
std::ostringstream oss; std::ostringstream oss;
bool first = true; bool first = true;
@ -738,17 +731,17 @@ inline std::string str_join(const std::vector<std::string> &list,
*/ */
inline std::string stringw_to_utf8(const irr::core::stringw &input) inline std::string stringw_to_utf8(const irr::core::stringw &input)
{ {
std::wstring str(input.c_str()); std::wstring_view sv(input.c_str(), input.size());
return wide_to_utf8(str); return wide_to_utf8(sv);
} }
/** /**
* Create an irr::core:stringw from a UTF8 std::string. * Create an irr::core:stringw from a UTF8 std::string.
*/ */
inline irr::core::stringw utf8_to_stringw(const std::string &input) inline irr::core::stringw utf8_to_stringw(std::string_view input)
{ {
std::wstring str = utf8_to_wide(input); std::wstring str = utf8_to_wide(input);
return irr::core::stringw(str.c_str()); return irr::core::stringw(str.c_str(), str.size());
} }
/** /**
@ -757,7 +750,7 @@ inline irr::core::stringw utf8_to_stringw(const std::string &input)
* and add a prefix to them * and add a prefix to them
* 2. Remove 'unsafe' characters from the name by replacing them with '_' * 2. Remove 'unsafe' characters from the name by replacing them with '_'
*/ */
std::string sanitizeDirName(const std::string &str, const std::string &optional_prefix); std::string sanitizeDirName(std::string_view str, std::string_view optional_prefix);
/** /**
* Prints a sanitized version of a string without control characters. * Prints a sanitized version of a string without control characters.
@ -765,12 +758,12 @@ std::string sanitizeDirName(const std::string &str, const std::string &optional_
* ASCII control characters are replaced with their hex encoding in angle * ASCII control characters are replaced with their hex encoding in angle
* brackets (e.g. "a\x1eb" -> "a<1e>b"). * brackets (e.g. "a\x1eb" -> "a<1e>b").
*/ */
void safe_print_string(std::ostream &os, const std::string &str); void safe_print_string(std::ostream &os, std::string_view str);
/** /**
* Parses a string of form `(1, 2, 3)` to a v3f * Parses a string of form `(1, 2, 3)` to a v3f
* *
* @param str String * @param str string
* @return * @return float vector
*/ */
v3f str_to_v3f(const std::string &str); v3f str_to_v3f(std::string_view str);