Electroneum
Loading...
Searching...
No Matches
portable_storage.h
Go to the documentation of this file.
1// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above copyright
9// notice, this list of conditions and the following disclaimer in the
10// documentation and/or other materials provided with the distribution.
11// * Neither the name of the Andrey N. Sabelnikov nor the
12// names of its contributors may be used to endorse or promote products
13// derived from this software without specific prior written permission.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
19// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25//
26
27
28
29#pragma once
30
31#include "misc_language.h"
38#include "span.h"
39#include "int-util.h"
40
41#include <boost/mpl/contains.hpp>
42
43namespace epee
44{
45 namespace serialization
46 {
47 /************************************************************************/
48 /* */
49 /************************************************************************/
51 {
52 public:
56
59 hsection open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist = false);
60 template<class t_value>
61 bool get_value(const std::string& value_name, t_value& val, hsection hparent_section);
62 bool get_value(const std::string& value_name, storage_entry& val, hsection hparent_section);
63 template<class t_value>
64 bool set_value(const std::string& value_name, const t_value& target, hsection hparent_section);
65
66 //serial access for arrays of values --------------------------------------
67 //values
68 template<class t_value>
69 harray get_first_value(const std::string& value_name, t_value& target, hsection hparent_section);
70 template<class t_value>
71 bool get_next_value(harray hval_array, t_value& target);
72 template<class t_value>
73 harray insert_first_value(const std::string& value_name, const t_value& target, hsection hparent_section);
74 template<class t_value>
75 bool insert_next_value(harray hval_array, const t_value& target);
76 //sections
77 harray get_first_section(const std::string& pSectionName, hsection& h_child_section, hsection hparent_section);
78 bool get_next_section(harray hSecArray, hsection& h_child_section);
79 harray insert_first_section(const std::string& pSectionName, hsection& hinserted_childsection, hsection hparent_section);
80 bool insert_next_section(harray hSecArray, hsection& hinserted_childsection);
81 //------------------------------------------------------------------------
82 //delete entry (section, value or array)
83 bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr);
84
85 //-------------------------------------------------------------------------------
86 bool store_to_binary(binarybuffer& target);
88 bool load_from_binary(const std::string& target) { return load_from_binary(epee::strspan<uint8_t>(target)); }
89 template<class trace_policy>
90 bool dump_as_xml(std::string& targetObj, const std::string& root_name = "");
91 bool dump_as_json(std::string& targetObj, size_t indent = 0, bool insert_newlines = true);
92 bool load_from_json(const std::string& source);
93
94 private:
95 section m_root;
96 hsection get_root_section() {return &m_root;}
97 storage_entry* find_storage_entry(const std::string& pentry_name, hsection psection);
98 template<class entry_type>
99 storage_entry* insert_new_entry_get_storage_entry(const std::string& pentry_name, hsection psection, const entry_type& entry);
100
101 hsection insert_new_section(const std::string& pentry_name, hsection psection);
102
103#pragma pack(push)
104#pragma pack(1)
105 struct storage_block_header
106 {
107 uint32_t m_signature_a;
108 uint32_t m_signature_b;
109 uint8_t m_ver;
110 };
111#pragma pack(pop)
112 };
113 inline
114 bool portable_storage::dump_as_json(std::string& buff, size_t indent, bool insert_newlines)
115 {
116 TRY_ENTRY();
117 std::stringstream ss;
118 epee::serialization::dump_as_json(ss, m_root, indent, insert_newlines);
119 buff = ss.str();
120 return true;
121 CATCH_ENTRY("portable_storage::dump_as_json", false)
122 }
123 inline
125 {
126 TRY_ENTRY();
127 return json::load_from_json(source, *this);
128 CATCH_ENTRY("portable_storage::load_from_json", false)
129 }
130
131 template<class trace_policy>
132 bool portable_storage::dump_as_xml(std::string& targetObj, const std::string& root_name)
133 {
134 return false;//TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
135 }
136
137 inline
139 {
140 TRY_ENTRY();
141 std::stringstream ss;
142 storage_block_header sbh = AUTO_VAL_INIT(sbh);
143 sbh.m_signature_a = SWAP32LE(PORTABLE_STORAGE_SIGNATUREA);
144 sbh.m_signature_b = SWAP32LE(PORTABLE_STORAGE_SIGNATUREB);
145 sbh.m_ver = PORTABLE_STORAGE_FORMAT_VER;
146 ss.write((const char*)&sbh, sizeof(storage_block_header));
147 pack_entry_to_buff(ss, m_root);
148 target = ss.str();
149 return true;
150 CATCH_ENTRY("portable_storage::store_to_binary", false)
151 }
152 inline
154 {
155 m_root.m_entries.clear();
156 if(source.size() < sizeof(storage_block_header))
157 {
158 LOG_ERROR("portable_storage: wrong binary format, packet size = " << source.size() << " less than expected sizeof(storage_block_header)=" << sizeof(storage_block_header));
159 return false;
160 }
161 storage_block_header* pbuff = (storage_block_header*)source.data();
162 if(pbuff->m_signature_a != SWAP32LE(PORTABLE_STORAGE_SIGNATUREA) ||
163 pbuff->m_signature_b != SWAP32LE(PORTABLE_STORAGE_SIGNATUREB)
164 )
165 {
166 LOG_ERROR("portable_storage: wrong binary format - signature mismatch");
167 return false;
168 }
169 if(pbuff->m_ver != PORTABLE_STORAGE_FORMAT_VER)
170 {
171 LOG_ERROR("portable_storage: wrong binary format - unknown format ver = " << pbuff->m_ver);
172 return false;
173 }
174 TRY_ENTRY();
175 throwable_buffer_reader buf_reader(source.data()+sizeof(storage_block_header), source.size()-sizeof(storage_block_header));
176 buf_reader.read(m_root);
177 return true;//TODO:
178 CATCH_ENTRY("portable_storage::load_from_binary", false);
179 }
180 //---------------------------------------------------------------------------------------------------------------
181 inline
182 hsection portable_storage::open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist)
183 {
184 TRY_ENTRY();
185 hparent_section = hparent_section ? hparent_section:&m_root;
186 storage_entry* pentry = find_storage_entry(section_name, hparent_section);
187 if(!pentry)
188 {
189 if(!create_if_notexist)
190 return nullptr;
191 return insert_new_section(section_name, hparent_section);
192 }
193 CHECK_AND_ASSERT(pentry , nullptr);
194 //check that section_entry we find is real "CSSection"
195 if(pentry->type() != typeid(section))
196 {
197 if(create_if_notexist)
198 *pentry = storage_entry(section());//replace
199 else
200 return nullptr;
201 }
202 return &boost::get<section>(*pentry);
203 CATCH_ENTRY("portable_storage::open_section", nullptr);
204 }
205 //---------------------------------------------------------------------------------------------------------------
206 template<class to_type>
207 struct get_value_visitor: boost::static_visitor<void>
208 {
209 to_type& m_target;
210 get_value_visitor(to_type& target):m_target(target){}
211 template<class from_type>
212 void operator()(const from_type& v){convert_t(v, m_target);}
213 };
214
215 template<class t_value>
216 bool portable_storage::get_value(const std::string& value_name, t_value& val, hsection hparent_section)
217 {
218 BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
219 //TRY_ENTRY();
220 if(!hparent_section) hparent_section = &m_root;
221 storage_entry* pentry = find_storage_entry(value_name, hparent_section);
222 if(!pentry)
223 return false;
224
226 boost::apply_visitor(gvv, *pentry);
227 return true;
228 //CATCH_ENTRY("portable_storage::template<>get_value", false);
229 }
230 //---------------------------------------------------------------------------------------------------------------
231 inline
232 bool portable_storage::get_value(const std::string& value_name, storage_entry& val, hsection hparent_section)
233 {
234 //TRY_ENTRY();
235 if(!hparent_section) hparent_section = &m_root;
236 storage_entry* pentry = find_storage_entry(value_name, hparent_section);
237 if(!pentry)
238 return false;
239
240 val = *pentry;
241 return true;
242 //CATCH_ENTRY("portable_storage::template<>get_value", false);
243 }
244 //---------------------------------------------------------------------------------------------------------------
245 template<class t_value>
246 bool portable_storage::set_value(const std::string& value_name, const t_value& v, hsection hparent_section)
247 {
248 BOOST_MPL_ASSERT(( boost::mpl::contains<boost::mpl::push_front<storage_entry::types, storage_entry>::type, t_value> ));
249 TRY_ENTRY();
250 if(!hparent_section)
251 hparent_section = &m_root;
252 storage_entry* pentry = find_storage_entry(value_name, hparent_section);
253 if(!pentry)
254 {
255 pentry = insert_new_entry_get_storage_entry(value_name, hparent_section, v);
256 if(!pentry)
257 return false;
258 return true;
259 }
260 *pentry = storage_entry(v);
261 return true;
262 CATCH_ENTRY("portable_storage::template<>set_value", false);
263 }
264 //---------------------------------------------------------------------------------------------------------------
265 inline
266 storage_entry* portable_storage::find_storage_entry(const std::string& pentry_name, hsection psection)
267 {
268 TRY_ENTRY();
269 CHECK_AND_ASSERT(psection, nullptr);
270 auto it = psection->m_entries.find(pentry_name);
271 if(it == psection->m_entries.end())
272 return nullptr;
273
274 return &it->second;
275 CATCH_ENTRY("portable_storage::find_storage_entry", nullptr);
276 }
277 //---------------------------------------------------------------------------------------------------------------
278 template<class entry_type>
279 storage_entry* portable_storage::insert_new_entry_get_storage_entry(const std::string& pentry_name, hsection psection, const entry_type& entry)
280 {
281 TRY_ENTRY();
282 CHECK_AND_ASSERT(psection, nullptr);
283 auto ins_res = psection->m_entries.insert(std::pair<std::string, storage_entry>(pentry_name, entry));
284 return &ins_res.first->second;
285 CATCH_ENTRY("portable_storage::insert_new_entry_get_storage_entry", nullptr);
286 }
287 //---------------------------------------------------------------------------------------------------------------
288 inline
289 hsection portable_storage::insert_new_section(const std::string& pentry_name, hsection psection)
290 {
291 TRY_ENTRY();
292 storage_entry* pse = insert_new_entry_get_storage_entry(pentry_name, psection, section());
293 if(!pse) return nullptr;
294 return &boost::get<section>(*pse);
295 CATCH_ENTRY("portable_storage::insert_new_section", nullptr);
296 }
297 //---------------------------------------------------------------------------------------------------------------
298 template<class to_type>
299 struct get_first_value_visitor: boost::static_visitor<bool>
300 {
301 to_type& m_target;
302 get_first_value_visitor(to_type& target):m_target(target){}
303 template<class from_type>
305 {
306 const from_type* pv = a.get_first_val();
307 if(!pv)
308 return false;
309 convert_t(*pv, m_target);
310 return true;
311 }
312 };
313 //---------------------------------------------------------------------------------------------------------------
314 template<class t_value>
315 harray portable_storage::get_first_value(const std::string& value_name, t_value& target, hsection hparent_section)
316 {
317 BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
318 //TRY_ENTRY();
319 if(!hparent_section) hparent_section = &m_root;
320 storage_entry* pentry = find_storage_entry(value_name, hparent_section);
321 if(!pentry)
322 return nullptr;
323 if(pentry->type() != typeid(array_entry))
324 return nullptr;
325 array_entry& ar_entry = boost::get<array_entry>(*pentry);
326
328 if(!boost::apply_visitor(gfv, ar_entry))
329 return nullptr;
330 return &ar_entry;
331 //CATCH_ENTRY("portable_storage::get_first_value", nullptr);
332 }
333 //---------------------------------------------------------------------------------------------------------------
334 template<class to_type>
335 struct get_next_value_visitor: boost::static_visitor<bool>
336 {
337 to_type& m_target;
338 get_next_value_visitor(to_type& target):m_target(target){}
339 template<class from_type>
341 {
342 //TODO: optimize code here: work without get_next_val function
343 const from_type* pv = a.get_next_val();
344 if(!pv)
345 return false;
346 convert_t(*pv, m_target);
347 return true;
348 }
349 };
350
351
352 template<class t_value>
353 bool portable_storage::get_next_value(harray hval_array, t_value& target)
354 {
355 BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
356 //TRY_ENTRY();
357 CHECK_AND_ASSERT(hval_array, false);
358 array_entry& ar_entry = *hval_array;
360 if(!boost::apply_visitor(gnv, ar_entry))
361 return false;
362 return true;
363 //CATCH_ENTRY("portable_storage::get_next_value", false);
364 }
365 //---------------------------------------------------------------------------------------------------------------
366 template<class t_value>
367 harray portable_storage::insert_first_value(const std::string& value_name, const t_value& target, hsection hparent_section)
368 {
369 TRY_ENTRY();
370 if(!hparent_section) hparent_section = &m_root;
371 storage_entry* pentry = find_storage_entry(value_name, hparent_section);
372 if(!pentry)
373 {
374 pentry = insert_new_entry_get_storage_entry(value_name, hparent_section, array_entry(array_entry_t<t_value>()));
375 if(!pentry)
376 return nullptr;
377 }
378 if(pentry->type() != typeid(array_entry))
380
381 array_entry& arr = boost::get<array_entry>(*pentry);
382 if(arr.type() != typeid(array_entry_t<t_value>))
384
385 array_entry_t<t_value>& arr_typed = boost::get<array_entry_t<t_value> >(arr);
386 arr_typed.insert_first_val(target);
387 return &arr;
388 CATCH_ENTRY("portable_storage::insert_first_value", nullptr);
389 }
390 //---------------------------------------------------------------------------------------------------------------
391 template<class t_value>
392 bool portable_storage::insert_next_value(harray hval_array, const t_value& target)
393 {
394 TRY_ENTRY();
395 CHECK_AND_ASSERT(hval_array, false);
396
397 CHECK_AND_ASSERT_MES(hval_array->type() == typeid(array_entry_t<t_value>),
398 false, "unexpected type in insert_next_value: " << typeid(array_entry_t<t_value>).name());
399
400 array_entry_t<t_value>& arr_typed = boost::get<array_entry_t<t_value> >(*hval_array);
401 arr_typed.insert_next_value(target);
402 return true;
403 CATCH_ENTRY("portable_storage::insert_next_value", false);
404 }
405 //---------------------------------------------------------------------------------------------------------------
406 //sections
407 inline
408 harray portable_storage::get_first_section(const std::string& sec_name, hsection& h_child_section, hsection hparent_section)
409 {
410 TRY_ENTRY();
411 if(!hparent_section) hparent_section = &m_root;
412 storage_entry* pentry = find_storage_entry(sec_name, hparent_section);
413 if(!pentry)
414 return nullptr;
415 if(pentry->type() != typeid(array_entry))
416 return nullptr;
417 array_entry& ar_entry = boost::get<array_entry>(*pentry);
418 if(ar_entry.type() != typeid(array_entry_t<section>))
419 return nullptr;
420 array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(ar_entry);
421 section* psec = sec_array.get_first_val();
422 if(!psec)
423 return nullptr;
424 h_child_section = psec;
425 return &ar_entry;
426 CATCH_ENTRY("portable_storage::get_first_section", nullptr);
427 }
428 //---------------------------------------------------------------------------------------------------------------
429 inline
430 bool portable_storage::get_next_section(harray hsec_array, hsection& h_child_section)
431 {
432 TRY_ENTRY();
433 CHECK_AND_ASSERT(hsec_array, false);
434 if(hsec_array->type() != typeid(array_entry_t<section>))
435 return false;
436 array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(*hsec_array);
437 h_child_section = sec_array.get_next_val();
438 if(!h_child_section)
439 return false;
440 return true;
441 CATCH_ENTRY("portable_storage::get_next_section", false);
442 }
443 //---------------------------------------------------------------------------------------------------------------
444 inline
445 harray portable_storage::insert_first_section(const std::string& sec_name, hsection& hinserted_childsection, hsection hparent_section)
446 {
447 TRY_ENTRY();
448 if(!hparent_section) hparent_section = &m_root;
449 storage_entry* pentry = find_storage_entry(sec_name, hparent_section);
450 if(!pentry)
451 {
452 pentry = insert_new_entry_get_storage_entry(sec_name, hparent_section, array_entry(array_entry_t<section>()));
453 if(!pentry)
454 return nullptr;
455 }
456 if(pentry->type() != typeid(array_entry))
458
459 array_entry& ar_entry = boost::get<array_entry>(*pentry);
460 if(ar_entry.type() != typeid(array_entry_t<section>))
462
463 array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(ar_entry);
464 hinserted_childsection = &sec_array.insert_first_val(section());
465 return &ar_entry;
466 CATCH_ENTRY("portable_storage::insert_first_section", nullptr);
467 }
468 //---------------------------------------------------------------------------------------------------------------
469 inline
470 bool portable_storage::insert_next_section(harray hsec_array, hsection& hinserted_childsection)
471 {
472 TRY_ENTRY();
473 CHECK_AND_ASSERT(hsec_array, false);
474 CHECK_AND_ASSERT_MES(hsec_array->type() == typeid(array_entry_t<section>),
475 false, "unexpected type(not 'section') in insert_next_section, type: " << hsec_array->type().name());
476
477 array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(*hsec_array);
478 hinserted_childsection = &sec_array.insert_next_value(section());
479 return true;
480 CATCH_ENTRY("portable_storage::insert_next_section", false);
481 }
482 //---------------------------------------------------------------------------------------------------------------
483 }
484}
bool get_value(const std::string &value_name, t_value &val, hsection hparent_section)
epee::serialization::hsection hsection
bool delete_entry(const std::string &pentry_name, hsection hparent_section=nullptr)
harray get_first_value(const std::string &value_name, t_value &target, hsection hparent_section)
harray insert_first_value(const std::string &value_name, const t_value &target, hsection hparent_section)
harray insert_first_section(const std::string &pSectionName, hsection &hinserted_childsection, hsection hparent_section)
harray get_first_section(const std::string &pSectionName, hsection &h_child_section, hsection hparent_section)
bool insert_next_value(harray hval_array, const t_value &target)
bool insert_next_section(harray hSecArray, hsection &hinserted_childsection)
bool dump_as_xml(std::string &targetObj, const std::string &root_name="")
hsection open_section(const std::string &section_name, hsection hparent_section, bool create_if_notexist=false)
bool store_to_binary(binarybuffer &target)
bool get_next_value(harray hval_array, t_value &target)
bool dump_as_json(std::string &targetObj, size_t indent=0, bool insert_newlines=true)
epee::serialization::harray harray
bool load_from_json(const std::string &source)
bool load_from_binary(const std::string &target)
bool get_next_section(harray hSecArray, hsection &h_child_section)
bool set_value(const std::string &value_name, const t_value &target, hsection hparent_section)
bool load_from_binary(const epee::span< const uint8_t > target)
Non-owning sequence of data. Does not deep copy.
Definition span.h:57
#define SWAP32LE
Definition int-util.h:224
#define AUTO_VAL_INIT(v)
#define CATCH_ENTRY(location, return_val)
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
#define LOG_ERROR(x)
Definition misc_log_ex.h:98
#define CHECK_AND_ASSERT(expr, fail_ret_val)
#define TRY_ENTRY()
void convert_t(const from_type &from, to_type &to)
void dump_as_json(t_stream &strm, const array_entry &ae, size_t indent, bool insert_newlines)
boost::variant< uint64_t, uint32_t, uint16_t, uint8_t, int64_t, int32_t, int16_t, int8_t, double, bool, std::string, section, array_entry > storage_entry
bool pack_entry_to_buff(t_stream &strm, const array_entry &ae)
boost::make_recursive_variant< array_entry_t< section >, array_entry_t< uint64_t >, array_entry_t< uint32_t >, array_entry_t< uint16_t >, array_entry_t< uint8_t >, array_entry_t< int64_t >, array_entry_t< int32_t >, array_entry_t< int16_t >, array_entry_t< int8_t >, array_entry_t< double >, array_entry_t< bool >, array_entry_t< std::string >, array_entry_t< section >, array_entry_t< boost::recursive_variant_ > >::type array_entry
span< const T > strspan(const std::string &s) noexcept
make a span from a std::string
Definition span.h:171
const CharType(& source)[N]
Definition pointer.h:1147
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1124
#define PORTABLE_STORAGE_SIGNATUREA
#define PORTABLE_STORAGE_SIGNATUREB
#define PORTABLE_STORAGE_FORMAT_VER
unsigned int uint32_t
Definition stdint.h:126
unsigned char uint8_t
Definition stdint.h:124
t_entry_type & insert_next_value(const t_entry_type &v)
const t_entry_type * get_first_val() const
t_entry_type & insert_first_val(const t_entry_type &v)
const t_entry_type * get_next_val() const
bool operator()(const array_entry_t< from_type > &a)
bool operator()(const array_entry_t< from_type > &a)
std::map< std::string, storage_entry > m_entries