Electroneum
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"
32 #include "portable_storage_base.h"
38 #include "span.h"
39 #include "int-util.h"
40 
41 #include <boost/mpl/contains.hpp>
42 
43 namespace epee
44 {
45  namespace serialization
46  {
47  /************************************************************************/
48  /* */
49  /************************************************************************/
51  {
52  public:
56 
58  virtual ~portable_storage(){}
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>))
461  ar_entry = array_entry(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 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)
const CharType(& source)[N]
Definition: pointer.h:1147
hsection open_section(const std::string &section_name, hsection hparent_section, bool create_if_notexist=false)
bool operator()(const array_entry_t< from_type > &a)
bool get_value(const std::string &value_name, t_value &val, hsection hparent_section)
::std::string string
Definition: gtest-port.h:1097
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
#define CATCH_ENTRY(location, return_val)
Definition: misc_log_ex.h:152
t_entry_type & insert_first_val(const t_entry_type &v)
bool dump_as_xml(std::string &targetObj, const std::string &root_name="")
#define PORTABLE_STORAGE_SIGNATUREA
epee::serialization::hsection hsection
bool get_next_value(harray hval_array, t_value &target)
const t_entry_type * get_next_val() const
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
Non-owning sequence of data. Does not deep copy.
Definition: span.h:56
void convert_t(const from_type &from, to_type &to)
unsigned char uint8_t
Definition: stdint.h:124
bool load_from_binary(const epee::span< const uint8_t > target)
bool operator()(const array_entry_t< from_type > &a)
harray insert_first_value(const std::string &value_name, const t_value &target, hsection hparent_section)
bool dump_as_json(std::string &targetObj, size_t indent=0, bool insert_newlines=true)
void dump_as_json(t_stream &strm, const array_entry &ae, size_t indent, bool insert_newlines)
bool get_next_section(harray hSecArray, hsection &h_child_section)
harray insert_first_section(const std::string &pSectionName, hsection &hinserted_childsection, hsection hparent_section)
bool load_from_json(const std::string &buff_json, t_storage &stg)
#define PORTABLE_STORAGE_SIGNATUREB
#define TRY_ENTRY()
Definition: misc_log_ex.h:151
unsigned int uint32_t
Definition: stdint.h:126
#define CHECK_AND_ASSERT(expr, fail_ret_val)
Definition: misc_log_ex.h:177
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
bool pack_entry_to_buff(t_stream &strm, const array_entry &ae)
bool load_from_json(const std::string &source)
epee::serialization::harray harray
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
bool insert_next_value(harray hval_array, const t_value &target)
t_entry_type & insert_next_value(const t_entry_type &v)
#define LOG_ERROR(x)
Definition: misc_log_ex.h:98
const t_entry_type * get_first_val() const
bool load_from_binary(const std::string &target)
bool store_to_binary(binarybuffer &target)
#define AUTO_VAL_INIT(v)
Definition: misc_language.h:53
bool insert_next_section(harray hSecArray, hsection &hinserted_childsection)
harray get_first_section(const std::string &pSectionName, hsection &h_child_section, hsection hparent_section)
std::map< std::string, storage_entry > m_entries
#define SWAP32LE
Definition: int-util.h:244
#define PORTABLE_STORAGE_FORMAT_VER
bool set_value(const std::string &value_name, const t_value &target, hsection hparent_section)