mirror of https://github.com/oxen-io/oxen-core.git
205 lines
7.0 KiB
C++
205 lines
7.0 KiB
C++
#include "epee/storages/portable_storage_to_json.h"
|
|
#include "epee/storages/portable_storage.h"
|
|
#include <lokimq/variant.h>
|
|
|
|
namespace epee {
|
|
namespace serialization {
|
|
|
|
void dump_as_json(std::ostream& strm, const array_entry& ae, size_t indent, bool pretty)
|
|
{
|
|
var::visit([&](const auto& a) {
|
|
strm << '[';
|
|
for (auto it = a.begin(); it != a.end(); ++it)
|
|
{
|
|
if (it != a.begin()) strm << ',';
|
|
dump_as_json(strm, *it, indent, pretty);
|
|
}
|
|
strm << ']';
|
|
}, ae);
|
|
}
|
|
|
|
void dump_as_json(std::ostream& strm, const storage_entry& se, size_t indent, bool pretty)
|
|
{
|
|
var::visit([&](const auto& v) {
|
|
dump_as_json(strm, v, indent, pretty);
|
|
}, se);
|
|
}
|
|
|
|
void dump_as_json(std::ostream& s, const std::string& v, size_t, bool)
|
|
{
|
|
s.put('"');
|
|
// JSON strings may only contain 0x20 and above, except for " and \\ which must be escaped.
|
|
// For values below 0x20 we can use \u00XX escapes, except for the really common \n and \t (we
|
|
// could also use \b, \f, \r, but it really isn't worth the bother.
|
|
for (char c : v) {
|
|
switch(c) {
|
|
case '"':
|
|
case '\\':
|
|
s.put('\\'); s.put(c);
|
|
break;
|
|
case '\n': s.write("\\n", 2); break;
|
|
case '\t': s.write("\\t", 2); break;
|
|
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
|
|
case 0x08: /*\t=0x09: \n=0x0a*/ case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
|
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
|
|
case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
|
|
s.write("\\u00", 4);
|
|
s.put(c >= 0x10 ? '1' : '0');
|
|
c &= 0xf;
|
|
s.put(c < 0xa ? '0' + c : ('a' - 10) + c);
|
|
break;
|
|
default:
|
|
s.put(c);
|
|
}
|
|
}
|
|
s.put('"');
|
|
}
|
|
|
|
|
|
void dump_as_json(std::ostream& strm, const section& sec, size_t indent, bool pretty)
|
|
{
|
|
strm << '{';
|
|
if(sec.m_entries.empty())
|
|
strm << '}';
|
|
else
|
|
{
|
|
size_t local_indent = indent + 1;
|
|
std::string line_sep(pretty * (1 + 2*local_indent), ' ');
|
|
if (pretty) line_sep[0] = '\n';
|
|
|
|
for (auto it = sec.m_entries.begin(); it != sec.m_entries.end(); ++it)
|
|
{
|
|
if (it != sec.m_entries.begin()) strm << ',';
|
|
strm << line_sep;
|
|
dump_as_json(strm, it->first, local_indent, pretty);
|
|
strm << ':';
|
|
if (pretty) strm << ' ';
|
|
dump_as_json(strm, it->second, local_indent, pretty);
|
|
}
|
|
if (pretty)
|
|
line_sep.resize(line_sep.size() - 2);
|
|
strm << line_sep << '}';
|
|
}
|
|
}
|
|
|
|
bool portable_storage::dump_as_json(std::string& buff, size_t indent, bool insert_newlines)
|
|
{
|
|
TRY_ENTRY();
|
|
std::stringstream ss;
|
|
epee::serialization::dump_as_json(ss, m_root, indent, insert_newlines);
|
|
buff = ss.str();
|
|
return true;
|
|
CATCH_ENTRY("portable_storage::dump_as_json", false)
|
|
}
|
|
|
|
bool portable_storage::load_from_json(std::string_view source)
|
|
{
|
|
TRY_ENTRY();
|
|
return json::load_from_json(source, *this);
|
|
CATCH_ENTRY("portable_storage::load_from_json", false)
|
|
}
|
|
|
|
bool portable_storage::store_to_binary(std::string& target)
|
|
{
|
|
TRY_ENTRY();
|
|
std::stringstream ss;
|
|
storage_block_header sbh{};
|
|
sbh.m_signature_a = PORTABLE_STORAGE_SIGNATUREA;
|
|
sbh.m_signature_b = PORTABLE_STORAGE_SIGNATUREB;
|
|
sbh.m_ver = PORTABLE_STORAGE_FORMAT_VER;
|
|
ss.write(reinterpret_cast<const char*>(&sbh), sizeof(storage_block_header));
|
|
pack_entry_to_buff(ss, m_root);
|
|
target = ss.str();
|
|
return true;
|
|
CATCH_ENTRY("portable_storage::store_to_binary", false)
|
|
}
|
|
|
|
bool portable_storage::load_from_binary(const epee::span<const uint8_t> source)
|
|
{
|
|
m_root.m_entries.clear();
|
|
if(source.size() < sizeof(storage_block_header))
|
|
{
|
|
LOG_ERROR("portable_storage: wrong binary format, packet size = " << source.size() << " less than expected sizeof(storage_block_header)=" << sizeof(storage_block_header));
|
|
return false;
|
|
}
|
|
storage_block_header* pbuff = (storage_block_header*)source.data();
|
|
if(pbuff->m_signature_a != PORTABLE_STORAGE_SIGNATUREA ||
|
|
pbuff->m_signature_b != PORTABLE_STORAGE_SIGNATUREB
|
|
)
|
|
{
|
|
LOG_ERROR("portable_storage: wrong binary format - signature mismatch");
|
|
return false;
|
|
}
|
|
if(pbuff->m_ver != PORTABLE_STORAGE_FORMAT_VER)
|
|
{
|
|
LOG_ERROR("portable_storage: wrong binary format - unknown format ver = " << pbuff->m_ver);
|
|
return false;
|
|
}
|
|
TRY_ENTRY();
|
|
throwable_buffer_reader buf_reader(source.data()+sizeof(storage_block_header), source.size()-sizeof(storage_block_header));
|
|
buf_reader.read(m_root);
|
|
return true;//TODO:
|
|
CATCH_ENTRY("portable_storage::load_from_binary", false);
|
|
}
|
|
|
|
section* portable_storage::open_section(const std::string& section_name, section* parent_section, bool create_if_notexist)
|
|
{
|
|
TRY_ENTRY();
|
|
if (!parent_section) parent_section = &m_root;
|
|
|
|
storage_entry* pentry = find_storage_entry(section_name, parent_section);
|
|
if(!pentry)
|
|
{
|
|
if(!create_if_notexist)
|
|
return nullptr;
|
|
return insert_new_section(section_name, parent_section);
|
|
}
|
|
CHECK_AND_ASSERT(pentry , nullptr);
|
|
//check that section_entry we find is real "CSSection"
|
|
if (!std::holds_alternative<section>(*pentry))
|
|
{
|
|
if(create_if_notexist)
|
|
*pentry = section();//replace
|
|
else
|
|
return nullptr;
|
|
}
|
|
return &var::get<section>(*pentry);
|
|
CATCH_ENTRY("portable_storage::open_section", nullptr);
|
|
}
|
|
|
|
bool portable_storage::get_value(const std::string& value_name, storage_entry& val, section* parent_section)
|
|
{
|
|
//TRY_ENTRY();
|
|
if(!parent_section) parent_section = &m_root;
|
|
storage_entry* pentry = find_storage_entry(value_name, parent_section);
|
|
if(!pentry)
|
|
return false;
|
|
|
|
val = *pentry;
|
|
return true;
|
|
//CATCH_ENTRY("portable_storage::template<>get_value", false);
|
|
}
|
|
|
|
storage_entry* portable_storage::find_storage_entry(const std::string& pentry_name, section* psection)
|
|
{
|
|
TRY_ENTRY();
|
|
CHECK_AND_ASSERT(psection, nullptr);
|
|
auto it = psection->m_entries.find(pentry_name);
|
|
if(it == psection->m_entries.end())
|
|
return nullptr;
|
|
|
|
return &it->second;
|
|
CATCH_ENTRY("portable_storage::find_storage_entry", nullptr);
|
|
}
|
|
|
|
section* portable_storage::insert_new_section(const std::string& pentry_name, section* psection)
|
|
{
|
|
TRY_ENTRY();
|
|
storage_entry* pse = insert_new_entry_get_storage_entry(pentry_name, psection, section());
|
|
if(!pse) return nullptr;
|
|
return &var::get<section>(*pse);
|
|
CATCH_ENTRY("portable_storage::insert_new_section", nullptr);
|
|
}
|
|
}
|
|
}
|