Add ItemStack key-value meta storage

This commit is contained in:
rubenwardy 2017-01-31 19:49:01 +00:00
parent c2e7b1f579
commit f2aa2c6a98
21 changed files with 459 additions and 123 deletions

@ -164,6 +164,7 @@ LOCAL_SRC_FILES := \
jni/src/inventory.cpp \
jni/src/inventorymanager.cpp \
jni/src/itemdef.cpp \
jni/src/itemstackmetadata.cpp \
jni/src/keycode.cpp \
jni/src/light.cpp \
jni/src/localplayer.cpp \
@ -305,6 +306,7 @@ LOCAL_SRC_FILES += \
jni/src/script/lua_api/l_env.cpp \
jni/src/script/lua_api/l_inventory.cpp \
jni/src/script/lua_api/l_item.cpp \
jni/src/script/lua_api/l_itemstackmeta.cpp\
jni/src/script/lua_api/l_mainmenu.cpp \
jni/src/script/lua_api/l_mapgen.cpp \
jni/src/script/lua_api/l_metadata.cpp \

@ -1427,9 +1427,9 @@ Node Metadata
-------------
The instance of a node in the world normally only contains the three values
mentioned in "Nodes". However, it is possible to insert extra data into a
node. It is called "node metadata"; See "`NodeMetaRef`".
node. It is called "node metadata"; See `NodeMetaRef`.
Metadata contains two things:
Node metadata contains two things:
* A key-value store
* An inventory
@ -1467,6 +1467,18 @@ Example stuff:
}
})
Item Metadata
-------------
Item stacks can store metadata too. See `ItemStackMetaRef`.
Item metadata only contains a key-value store.
Example stuff:
local meta = stack:get_meta()
meta:set_string("key", "value")
print(dump(meta:to_table()))
Formspec
--------
Formspec defines a menu. Currently not much else than inventories are
@ -2774,9 +2786,8 @@ These functions return the leftover itemstack.
Class reference
---------------
### `NodeMetaRef`
Node metadata: reference extra data and functionality stored in a node.
Can be gotten via `minetest.get_meta(pos)`.
### `MetaDataRef`
See `NodeMetaRef` and `ItemStackMetaRef`.
#### Methods
* `set_string(name, value)`
@ -2785,13 +2796,29 @@ Can be gotten via `minetest.get_meta(pos)`.
* `get_int(name)`
* `set_float(name, value)`
* `get_float(name)`
* `get_inventory()`: returns `InvRef`
* `to_table()`: returns `nil` or `{fields = {...}, inventory = {list1 = {}, ...}}`
* `to_table()`: returns `nil` or a table with keys:
* `fields`: key-value storage
* `inventory`: `{list1 = {}, ...}}` (NodeMetaRef only)
* `from_table(nil or {})`
* Any non-table value will clear the metadata
* See "Node Metadata"
* See "Node Metadata" for an example
* returns `true` on success
### `NodeMetaRef`
Node metadata: reference extra data and functionality stored in a node.
Can be gotten via `minetest.get_meta(pos)`.
#### Methods
* All methods in MetaDataRef
* `get_inventory()`: returns `InvRef`
### `ItemStackMetaRef`
ItemStack metadata: reference extra data and functionality stored in a stack.
Can be gotten via `item:get_meta()`.
#### Methods
* All methods in MetaDataRef
### `NodeTimerRef`
Node Timers: a high resolution persistent per-node timer.
Can be gotten via `minetest.get_node_timer(pos)`.

@ -415,6 +415,7 @@ set(common_SRCS
inventory.cpp
inventorymanager.cpp
itemdef.cpp
itemstackmetadata.cpp
light.cpp
log.cpp
map.cpp

@ -938,7 +938,7 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr,
if(m_prop.textures.size() >= 1){
infostream<<"textures[0]: "<<m_prop.textures[0]<<std::endl;
IItemDefManager *idef = m_client->idef();
ItemStack item(m_prop.textures[0], 1, 0, "", idef);
ItemStack item(m_prop.textures[0], 1, 0, idef);
m_wield_meshnode = new WieldMeshSceneNode(
smgr->getRootSceneNode(), smgr, -1);

@ -139,7 +139,7 @@ static std::vector<ItemStack> craftGetItems(
for (std::vector<std::string>::size_type i = 0;
i < items.size(); i++) {
result.push_back(ItemStack(std::string(items[i]), (u16)1,
(u16)0, "", gamedef->getItemDefManager()));
(u16)0, gamedef->getItemDefManager()));
}
return result;
}
@ -1126,4 +1126,3 @@ IWritableCraftDefManager* createCraftDefManager()
{
return new CCraftDefManager();
}

@ -45,78 +45,12 @@ static content_t content_translate_from_19_to_internal(content_t c_from)
return c_from;
}
// If the string contains spaces, quotes or control characters, encodes as JSON.
// Else returns the string unmodified.
static std::string serializeJsonStringIfNeeded(const std::string &s)
{
for(size_t i = 0; i < s.size(); ++i)
{
if(s[i] <= 0x1f || s[i] >= 0x7f || s[i] == ' ' || s[i] == '\"')
return serializeJsonString(s);
}
return s;
}
// Parses a string serialized by serializeJsonStringIfNeeded.
static std::string deSerializeJsonStringIfNeeded(std::istream &is)
{
std::ostringstream tmp_os;
bool expect_initial_quote = true;
bool is_json = false;
bool was_backslash = false;
for(;;)
{
char c = is.get();
if(is.eof())
break;
if(expect_initial_quote && c == '"')
{
tmp_os << c;
is_json = true;
}
else if(is_json)
{
tmp_os << c;
if(was_backslash)
was_backslash = false;
else if(c == '\\')
was_backslash = true;
else if(c == '"')
break; // Found end of string
}
else
{
if(c == ' ')
{
// Found end of word
is.unget();
break;
}
else
{
tmp_os << c;
}
}
expect_initial_quote = false;
}
if(is_json)
{
std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
return deSerializeJsonString(tmp_is);
}
else
return tmp_os.str();
}
ItemStack::ItemStack(std::string name_, u16 count_,
u16 wear_, std::string metadata_,
IItemDefManager *itemdef)
ItemStack::ItemStack(const std::string &name_, u16 count_,
u16 wear_, IItemDefManager *itemdef)
{
name = itemdef->getAlias(name_);
count = count_;
wear = wear_;
metadata = metadata_;
if (name.empty() || count == 0)
clear();
@ -137,7 +71,7 @@ void ItemStack::serialize(std::ostream &os) const
parts = 2;
if(wear != 0)
parts = 3;
if(metadata != "")
if (!metadata.empty())
parts = 4;
os<<serializeJsonStringIfNeeded(name);
@ -145,8 +79,10 @@ void ItemStack::serialize(std::ostream &os) const
os<<" "<<count;
if(parts >= 3)
os<<" "<<wear;
if(parts >= 4)
os<<" "<<serializeJsonStringIfNeeded(metadata);
if (parts >= 4) {
os << " ";
metadata.serialize(os);
}
}
void ItemStack::deSerialize(std::istream &is, IItemDefManager *itemdef)
@ -289,7 +225,7 @@ void ItemStack::deSerialize(std::istream &is, IItemDefManager *itemdef)
wear = stoi(wear_str);
// Read metadata
metadata = deSerializeJsonStringIfNeeded(is);
metadata.deSerialize(is);
// In case fields are added after metadata, skip space here:
//std::getline(is, tmp, ' ');

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h"
#include "itemdef.h"
#include "irrlichttypes.h"
#include "itemstackmetadata.h"
#include <istream>
#include <ostream>
#include <string>
@ -32,10 +33,10 @@ struct ToolCapabilities;
struct ItemStack
{
ItemStack(): name(""), count(0), wear(0), metadata("") {}
ItemStack(std::string name_, u16 count_,
u16 wear, std::string metadata_,
IItemDefManager *itemdef);
ItemStack(): name(""), count(0), wear(0) {}
ItemStack(const std::string &name_, u16 count_,
u16 wear, IItemDefManager *itemdef);
~ItemStack() {}
// Serialization
@ -61,7 +62,7 @@ struct ItemStack
name = "";
count = 0;
wear = 0;
metadata = "";
metadata.clear();
}
void add(u16 n)
@ -166,7 +167,7 @@ struct ItemStack
std::string name;
u16 count;
u16 wear;
std::string metadata;
ItemStackMetadata metadata;
};
class InventoryList
@ -313,4 +314,3 @@ private:
};
#endif

43
src/itemstackmetadata.cpp Normal file

@ -0,0 +1,43 @@
#include "itemstackmetadata.h"
#include "util/serialize.h"
#include "util/strfnd.h"
#define DESERIALIZE_START '\x01'
#define DESERIALIZE_KV_DELIM '\x02'
#define DESERIALIZE_PAIR_DELIM '\x03'
#define DESERIALIZE_START_STR "\x01"
#define DESERIALIZE_KV_DELIM_STR "\x02"
#define DESERIALIZE_PAIR_DELIM_STR "\x03"
void ItemStackMetadata::serialize(std::ostream &os) const
{
std::ostringstream os2;
os2 << DESERIALIZE_START;
for (StringMap::const_iterator
it = m_stringvars.begin();
it != m_stringvars.end(); ++it) {
os2 << it->first << DESERIALIZE_KV_DELIM
<< it->second << DESERIALIZE_PAIR_DELIM;
}
os << serializeJsonStringIfNeeded(os2.str());
}
void ItemStackMetadata::deSerialize(std::istream &is)
{
std::string in = deSerializeJsonStringIfNeeded(is);
m_stringvars.clear();
if (!in.empty() && in[0] == DESERIALIZE_START) {
Strfnd fnd(in);
fnd.to(1);
while (!fnd.at_end()) {
std::string name = fnd.next(DESERIALIZE_KV_DELIM_STR);
std::string var = fnd.next(DESERIALIZE_PAIR_DELIM_STR);
m_stringvars[name] = var;
}
} else {
// BACKWARDS COMPATIBILITY
m_stringvars[""] = in;
}
}

35
src/itemstackmetadata.h Normal file

@ -0,0 +1,35 @@
/*
Minetest
Copyright (C) 2010-2013 rubenwardy <rubenwardy@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef ITEMSTACKMETADATA_HEADER
#define ITEMSTACKMETADATA_HEADER
#include "metadata.h"
class Inventory;
class IItemDefManager;
class ItemStackMetadata : public Metadata
{
public:
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
};
#endif

@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gamedef.h"
#include "log.h"
#include <sstream>
#include "constants.h" // MAP_BLOCKSIZE
#include <sstream>
/*
Metadata

@ -25,35 +25,37 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <vector>
#include "util/string.h"
/*
NodeMetadata stores arbitary amounts of data for special blocks.
Used for furnaces, chests and signs.
There are two interaction methods: inventory menu and text input.
Only one can be used for a single metadata, thus only inventory OR
text input should exist in a metadata.
*/
class Inventory;
class IItemDefManager;
class Metadata
{
public:
void clear();
bool empty() const;
virtual ~Metadata() {}
// Generic key/value store
virtual void clear();
virtual bool empty() const;
bool operator==(const Metadata &other) const;
inline bool operator!=(const Metadata &other) const
{
return !(*this == other);
}
//
// Key-value related
//
size_t size() const;
bool contains(const std::string &name) const;
const std::string &getString(const std::string &name, u16 recursion = 0) const;
void setString(const std::string &name, const std::string &var);
// Support variable names in values
const std::string &resolveString(const std::string &str, u16 recursion = 0) const;
const StringMap &getStrings() const
{
return m_stringvars;
}
private:
// Add support for variable names in values
const std::string &resolveString(const std::string &str, u16 recursion = 0) const;
protected:
StringMap m_stringvars;
};
#endif

@ -824,11 +824,32 @@ ItemStack read_item(lua_State* L, int index,Server* srv)
std::string name = getstringfield_default(L, index, "name", "");
int count = getintfield_default(L, index, "count", 1);
int wear = getintfield_default(L, index, "wear", 0);
std::string metadata = getstringfield_default(L, index, "metadata", "");
return ItemStack(name, count, wear, metadata, idef);
ItemStack istack(name, count, wear, idef);
lua_getfield(L, index, "metadata");
// Support old metadata format by checking type
int fieldstable = lua_gettop(L);
if (lua_istable(L, fieldstable)) {
lua_pushnil(L);
while (lua_next(L, fieldstable) != 0) {
// key at index -2 and value at index -1
std::string key = lua_tostring(L, -2);
size_t value_len;
const char *value_cs = lua_tolstring(L, -1, &value_len);
std::string value(value_cs, value_len);
istack.metadata.setString(name, value);
lua_pop(L, 1); // removes value, keeps key for next iteration
}
else
{
} else {
// BACKWARDS COMPATIBLITY
std::string value = getstringfield_default(L, index, "metadata", "");
istack.metadata.setString("", value);
}
return istack;
} else {
throw LuaError("Expecting itemstack, itemstring, table or nil");
}
}

@ -5,6 +5,7 @@ set(common_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_env.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_inventory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_item.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_itemstackmeta.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_mapgen.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_metadata.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_nodemeta.cpp

@ -284,7 +284,7 @@ int ModApiEnvMod::l_place_node(lua_State *L)
return 1;
}
// Create item to place
ItemStack item(ndef->get(n).name, 1, 0, "", idef);
ItemStack item(ndef->get(n).name, 1, 0, idef);
// Make pointed position
PointedThing pointed;
pointed.type = POINTEDTHING_NODE;

@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "lua_api/l_item.h"
#include "lua_api/l_itemstackmeta.h"
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
@ -137,16 +138,28 @@ int LuaItemStack::l_set_wear(lua_State *L)
return 1;
}
// get_meta(self) -> string
int LuaItemStack::l_get_meta(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStackMetaRef::create(L, &o->m_stack);
return 1;
}
// DEPRECATED
// get_metadata(self) -> string
int LuaItemStack::l_get_metadata(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
const std::string &value = item.metadata.getString("");
lua_pushlstring(L, value.c_str(), value.size());
return 1;
}
// DEPRECATED
// set_metadata(self, string)
int LuaItemStack::l_set_metadata(lua_State *L)
{
@ -156,7 +169,7 @@ int LuaItemStack::l_set_metadata(lua_State *L)
size_t len = 0;
const char *ptr = luaL_checklstring(L, 2, &len);
item.metadata.assign(ptr, len);
item.metadata.setString("", std::string(ptr, len));
lua_pushboolean(L, true);
return 1;
@ -211,8 +224,24 @@ int LuaItemStack::l_to_table(lua_State *L)
lua_setfield(L, -2, "count");
lua_pushinteger(L, item.wear);
lua_setfield(L, -2, "wear");
lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
if (item.metadata.size() == 1 && item.metadata.contains("")) {
const std::string &value = item.metadata.getString("");
lua_pushlstring(L, value.c_str(), value.size());
lua_setfield(L, -2, "metadata");
} else {
lua_newtable(L);
const StringMap &fields = item.metadata.getStrings();
for (StringMap::const_iterator it = fields.begin();
it != fields.end(); ++it) {
const std::string &name = it->first;
const std::string &value = it->second;
lua_pushlstring(L, name.c_str(), name.size());
lua_pushlstring(L, value.c_str(), value.size());
lua_settable(L, -3);
}
lua_setfield(L, -2, "metadata");
}
}
return 1;
}
@ -443,6 +472,7 @@ const luaL_reg LuaItemStack::methods[] = {
luamethod(LuaItemStack, set_count),
luamethod(LuaItemStack, get_wear),
luamethod(LuaItemStack, set_wear),
luamethod(LuaItemStack, get_meta),
luamethod(LuaItemStack, get_metadata),
luamethod(LuaItemStack, set_metadata),
luamethod(LuaItemStack, clear),

@ -56,9 +56,14 @@ private:
// set_wear(self, number)
static int l_set_wear(lua_State *L);
// get_meta(self) -> string
static int l_get_meta(lua_State *L);
// DEPRECATED
// get_metadata(self) -> string
static int l_get_metadata(lua_State *L);
// DEPRECATED
// set_metadata(self, string)
static int l_set_metadata(lua_State *L);

@ -0,0 +1,115 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "lua_api/l_itemstackmeta.h"
#include "lua_api/l_internal.h"
#include "common/c_content.h"
/*
NodeMetaRef
*/
ItemStackMetaRef* ItemStackMetaRef::checkobject(lua_State *L, int narg)
{
luaL_checktype(L, narg, LUA_TUSERDATA);
void *ud = luaL_checkudata(L, narg, className);
if (!ud)
luaL_typerror(L, narg, className);
return *(ItemStackMetaRef**)ud; // unbox pointer
}
Metadata* ItemStackMetaRef::getmeta(bool auto_create)
{
return &istack->metadata;
}
void ItemStackMetaRef::clearMeta()
{
istack->metadata.clear();
}
void ItemStackMetaRef::reportMetadataChange()
{
// TODO
}
// Exported functions
// garbage collector
int ItemStackMetaRef::gc_object(lua_State *L) {
ItemStackMetaRef *o = *(ItemStackMetaRef **)(lua_touserdata(L, 1));
delete o;
return 0;
}
// Creates an NodeMetaRef and leaves it on top of stack
// Not callable from Lua; all references are created on the C side.
void ItemStackMetaRef::create(lua_State *L, ItemStack *istack)
{
ItemStackMetaRef *o = new ItemStackMetaRef(istack);
//infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
}
void ItemStackMetaRef::Register(lua_State *L)
{
lua_newtable(L);
int methodtable = lua_gettop(L);
luaL_newmetatable(L, className);
int metatable = lua_gettop(L);
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, methodtable);
lua_settable(L, metatable); // hide metatable from Lua getmetatable()
lua_pushliteral(L, "metadata_class");
lua_pushlstring(L, className, strlen(className));
lua_settable(L, metatable);
lua_pushliteral(L, "__index");
lua_pushvalue(L, methodtable);
lua_settable(L, metatable);
lua_pushliteral(L, "__gc");
lua_pushcfunction(L, gc_object);
lua_settable(L, metatable);
lua_pop(L, 1); // drop metatable
luaL_openlib(L, 0, methods, 0); // fill methodtable
lua_pop(L, 1); // drop methodtable
// Cannot be created from Lua
//lua_register(L, className, create_object);
}
const char ItemStackMetaRef::className[] = "ItemStackMetaRef";
const luaL_reg ItemStackMetaRef::methods[] = {
luamethod(MetaDataRef, get_string),
luamethod(MetaDataRef, set_string),
luamethod(MetaDataRef, get_int),
luamethod(MetaDataRef, set_int),
luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, set_float),
luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table),
{0,0}
};

@ -0,0 +1,59 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef L_ITEMSTACKMETA_H_
#define L_ITEMSTACKMETA_H_
#include "lua_api/l_base.h"
#include "lua_api/l_metadata.h"
#include "irrlichttypes_bloated.h"
#include "inventory.h"
class ItemStackMetaRef : public MetaDataRef
{
private:
ItemStack *istack;
static const char className[];
static const luaL_reg methods[];
static ItemStackMetaRef *checkobject(lua_State *L, int narg);
virtual Metadata* getmeta(bool auto_create);
virtual void clearMeta();
virtual void reportMetadataChange();
// Exported functions
// garbage collector
static int gc_object(lua_State *L);
public:
ItemStackMetaRef(ItemStack *istack): istack(istack) {}
~ItemStackMetaRef() {}
// Creates an ItemStackMetaRef and leaves it on top of stack
// Not callable from Lua; all references are created on the C side.
static void create(lua_State *L, ItemStack *istack);
static void Register(lua_State *L);
};
#endif

@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_env.h"
#include "lua_api/l_inventory.h"
#include "lua_api/l_item.h"
#include "lua_api/l_itemstackmeta.h"
#include "lua_api/l_mapgen.h"
#include "lua_api/l_nodemeta.h"
#include "lua_api/l_nodetimer.h"
@ -94,6 +95,7 @@ void GameScripting::InitializeModApi(lua_State *L, int top)
// Register reference classes (userdata)
InvRef::Register(L);
ItemStackMetaRef::Register(L);
LuaAreaStore::Register(L);
LuaItemStack::Register(L);
LuaPerlinNoise::Register(L);

@ -354,6 +354,55 @@ std::string deSerializeJsonString(std::istream &is)
return os.str();
}
std::string serializeJsonStringIfNeeded(const std::string &s)
{
for (size_t i = 0; i < s.size(); ++i) {
if (s[i] <= 0x1f || s[i] >= 0x7f || s[i] == ' ' || s[i] == '\"')
return serializeJsonString(s);
}
return s;
}
std::string deSerializeJsonStringIfNeeded(std::istream &is)
{
std::ostringstream tmp_os;
bool expect_initial_quote = true;
bool is_json = false;
bool was_backslash = false;
for (;;) {
char c = is.get();
if (is.eof())
break;
if (expect_initial_quote && c == '"') {
tmp_os << c;
is_json = true;
} else if(is_json) {
tmp_os << c;
if (was_backslash)
was_backslash = false;
else if (c == '\\')
was_backslash = true;
else if (c == '"')
break; // Found end of string
} else {
if (c == ' ') {
// Found end of word
is.unget();
break;
} else {
tmp_os << c;
}
}
expect_initial_quote = false;
}
if (is_json) {
std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
return deSerializeJsonString(tmp_is);
} else
return tmp_os.str();
}
////
//// String/Struct conversions
////

@ -405,6 +405,13 @@ std::string serializeJsonString(const std::string &plain);
// Reads a string encoded in JSON format
std::string deSerializeJsonString(std::istream &is);
// If the string contains spaces, quotes or control characters, encodes as JSON.
// Else returns the string unmodified.
std::string serializeJsonStringIfNeeded(const std::string &s);
// Parses a string serialized by serializeJsonStringIfNeeded.
std::string deSerializeJsonStringIfNeeded(std::istream &is);
// Creates a string consisting of the hexadecimal representation of `data`
std::string serializeHexString(const std::string &data, bool insert_spaces=false);