Electroneum
Loading...
Searching...
No Matches
portable_storage_from_json.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#pragma once
28#include <boost/lexical_cast.hpp>
29#include <boost/algorithm/string/predicate.hpp>
30#include "parserse_base_utils.h"
31#include "file_io_utils.h"
32
33#define EPEE_JSON_RECURSION_LIMIT_INTERNAL 100
34
35namespace epee
36{
37 using namespace misc_utils::parse;
38 namespace serialization
39 {
40 namespace json
41 {
42#define CHECK_ISSPACE() if(!epee::misc_utils::parse::isspace(*it)){ ASSERT_MES_AND_THROW("Wrong JSON character at: " << std::string(it, buf_end));}
43
44 /*inline void parse_error()
45 {
46 ASSERT_MES_AND_THROW("json parse error");
47 }*/
48 template<class t_storage>
49 inline void run_handler(typename t_storage::hsection current_section, std::string::const_iterator& sec_buf_begin, std::string::const_iterator buf_end, t_storage& stg, unsigned int recursion)
50 {
51 CHECK_AND_ASSERT_THROW_MES(recursion < EPEE_JSON_RECURSION_LIMIT_INTERNAL, "Wrong JSON data: recursion limitation (" << EPEE_JSON_RECURSION_LIMIT_INTERNAL << ") exceeded");
52
53 std::string::const_iterator sub_element_start;
54 std::string name;
55 typename t_storage::harray h_array = nullptr;
56 enum match_state
57 {
58 match_state_lookup_for_section_start,
59 match_state_lookup_for_name,
60 match_state_waiting_separator,
61 match_state_wonder_after_separator,
62 match_state_wonder_after_value,
63 match_state_wonder_array,
64 match_state_array_after_value,
65 match_state_array_waiting_value,
66 match_state_error
67 };
68
69 enum array_mode
70 {
71 array_mode_undifined = 0,
72 array_mode_sections,
73 array_mode_string,
74 array_mode_numbers,
75 array_mode_booleans
76 };
77
78 match_state state = match_state_lookup_for_section_start;
79 array_mode array_md = array_mode_undifined;
80 std::string::const_iterator it = sec_buf_begin;
81 for(;it != buf_end;it++)
82 {
83 switch (state)
84 {
85 case match_state_lookup_for_section_start:
86 if(*it == '{')
87 state = match_state_lookup_for_name;
88 else CHECK_ISSPACE();
89 break;
90 case match_state_lookup_for_name:
91 switch(*it)
92 {
93 case '"':
94 match_string2(it, buf_end, name);
95 state = match_state_waiting_separator;
96 break;
97 case '}':
98 //this is it! section ends here.
99 //seems that it is empty section
100 sec_buf_begin = it;
101 return;
102 default:
104 }
105 break;
106 case match_state_waiting_separator:
107 if(*it == ':')
108 state = match_state_wonder_after_separator;
109 else CHECK_ISSPACE();
110 break;
111 case match_state_wonder_after_separator:
112 if(*it == '"')
113 {//just a named string value started
114 std::string val;
115 match_string2(it, buf_end, val);
116 //insert text value
117 stg.set_value(name, std::move(val), current_section);
118 state = match_state_wonder_after_value;
119 }else if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
120 {//just a named number value started
121 boost::string_ref val;
122 bool is_v_float = false;bool is_signed = false;
123 match_number2(it, buf_end, val, is_v_float, is_signed);
124 if(!is_v_float)
125 {
126 if(is_signed)
127 {
128 errno = 0;
129 int64_t nval = strtoll(val.data(), NULL, 10);
130 if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
131 stg.set_value(name, nval, current_section);
132 }else
133 {
134 errno = 0;
135 uint64_t nval = strtoull(val.data(), NULL, 10);
136 if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
137 stg.set_value(name, nval, current_section);
138 }
139 }else
140 {
141 errno = 0;
142 double nval = strtod(val.data(), NULL);
143 if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
144 stg.set_value(name, nval, current_section);
145 }
146 state = match_state_wonder_after_value;
147 }else if(isalpha(*it) )
148 {// could be null, true or false
149 boost::string_ref word;
150 match_word2(it, buf_end, word);
151 if(boost::iequals(word, "null"))
152 {
153 state = match_state_wonder_after_value;
154 //just skip this,
155 }else if(boost::iequals(word, "true"))
156 {
157 stg.set_value(name, true, current_section);
158 state = match_state_wonder_after_value;
159 }else if(boost::iequals(word, "false"))
160 {
161 stg.set_value(name, false, current_section);
162 state = match_state_wonder_after_value;
163 }else ASSERT_MES_AND_THROW("Unknown value keyword " << word);
164 }else if(*it == '{')
165 {
166 //sub section here
167 typename t_storage::hsection new_sec = stg.open_section(name, current_section, true);
168 CHECK_AND_ASSERT_THROW_MES(new_sec, "Failed to insert new section in json: " << std::string(it, buf_end));
169 run_handler(new_sec, it, buf_end, stg, recursion + 1);
170 state = match_state_wonder_after_value;
171 }else if(*it == '[')
172 {//array of something
173 state = match_state_wonder_array;
174 }else CHECK_ISSPACE();
175 break;
176 case match_state_wonder_after_value:
177 if(*it == ',')
178 state = match_state_lookup_for_name;
179 else if(*it == '}')
180 {
181 //this is it! section ends here.
182 sec_buf_begin = it;
183 return;
184 }else CHECK_ISSPACE();
185 break;
186 case match_state_wonder_array:
187 if(*it == '[')
188 {
189 ASSERT_MES_AND_THROW("array of array not suppoerted yet :( sorry");
190 //mean array of array
191 }
192 if(*it == '{')
193 {
194 //mean array of sections
195 typename t_storage::hsection new_sec = nullptr;
196 h_array = stg.insert_first_section(name, new_sec, current_section);
197 CHECK_AND_ASSERT_THROW_MES(h_array&&new_sec, "failed to create new section");
198 run_handler(new_sec, it, buf_end, stg, recursion + 1);
199 state = match_state_array_after_value;
200 array_md = array_mode_sections;
201 }else if(*it == '"')
202 {
203 //mean array of strings
204 std::string val;
205 match_string2(it, buf_end, val);
206 h_array = stg.insert_first_value(name, std::move(val), current_section);
207 CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values entry");
208 state = match_state_array_after_value;
209 array_md = array_mode_string;
210 }else if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
211 {//array of numbers value started
212 boost::string_ref val;
213 bool is_v_float = false;bool is_signed_val = false;
214 match_number2(it, buf_end, val, is_v_float, is_signed_val);
215 if(!is_v_float)
216 {
217 if (is_signed_val)
218 {
219 errno = 0;
220 int64_t nval = strtoll(val.data(), NULL, 10);
221 if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
222 h_array = stg.insert_first_value(name, nval, current_section);
223 }else
224 {
225 errno = 0;
226 uint64_t nval = strtoull(val.data(), NULL, 10);
227 if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
228 h_array = stg.insert_first_value(name, nval, current_section);
229 }
230 CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
231 }else
232 {
233 errno = 0;
234 double nval = strtod(val.data(), NULL);
235 if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
236 h_array = stg.insert_first_value(name, nval, current_section);
237 CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
238 }
239
240 state = match_state_array_after_value;
241 array_md = array_mode_numbers;
242 }else if(*it == ']')//empty array
243 {
244 array_md = array_mode_undifined;
245 state = match_state_wonder_after_value;
246 }else if(isalpha(*it) )
247 {// array of booleans
248 boost::string_ref word;
249 match_word2(it, buf_end, word);
250 if(boost::iequals(word, "true"))
251 {
252 h_array = stg.insert_first_value(name, true, current_section);
253 CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
254 state = match_state_array_after_value;
255 array_md = array_mode_booleans;
256 }else if(boost::iequals(word, "false"))
257 {
258 h_array = stg.insert_first_value(name, false, current_section);
259 CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
260 state = match_state_array_after_value;
261 array_md = array_mode_booleans;
262
263 }else ASSERT_MES_AND_THROW("Unknown value keyword " << word)
264 }else CHECK_ISSPACE();
265 break;
266 case match_state_array_after_value:
267 if(*it == ',')
268 state = match_state_array_waiting_value;
269 else if(*it == ']')
270 {
271 h_array = nullptr;
272 array_md = array_mode_undifined;
273 state = match_state_wonder_after_value;
274 }else CHECK_ISSPACE();
275 break;
276 case match_state_array_waiting_value:
277 switch(array_md)
278 {
279 case array_mode_sections:
280 if(*it == '{')
281 {
282 typename t_storage::hsection new_sec = NULL;
283 bool res = stg.insert_next_section(h_array, new_sec);
284 CHECK_AND_ASSERT_THROW_MES(res&&new_sec, "failed to insert next section");
285 run_handler(new_sec, it, buf_end, stg, recursion + 1);
286 state = match_state_array_after_value;
287 }else CHECK_ISSPACE();
288 break;
289 case array_mode_string:
290 if(*it == '"')
291 {
292 std::string val;
293 match_string2(it, buf_end, val);
294 bool res = stg.insert_next_value(h_array, std::move(val));
295 CHECK_AND_ASSERT_THROW_MES(res, "failed to insert values");
296 state = match_state_array_after_value;
297 }else CHECK_ISSPACE();
298 break;
299 case array_mode_numbers:
300 if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
301 {//array of numbers value started
302 boost::string_ref val;
303 bool is_v_float = false;bool is_signed_val = false;
304 match_number2(it, buf_end, val, is_v_float, is_signed_val);
305 bool insert_res = false;
306 if(!is_v_float)
307 {
308 if (is_signed_val)
309 {
310 errno = 0;
311 int64_t nval = strtoll(val.data(), NULL, 10);
312 if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
313 insert_res = stg.insert_next_value(h_array, nval);
314 }else
315 {
316 errno = 0;
317 uint64_t nval = strtoull(val.data(), NULL, 10);
318 if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
319 insert_res = stg.insert_next_value(h_array, nval);
320 }
321 }else
322 {
323 errno = 0;
324 double nval = strtod(val.data(), NULL);
325 if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
326 insert_res = stg.insert_next_value(h_array, nval);
327 }
328 CHECK_AND_ASSERT_THROW_MES(insert_res, "Failed to insert next value");
329 state = match_state_array_after_value;
330 array_md = array_mode_numbers;
331 }else CHECK_ISSPACE();
332 break;
333 case array_mode_booleans:
334 if(isalpha(*it) )
335 {// array of booleans
336 boost::string_ref word;
337 match_word2(it, buf_end, word);
338 if(boost::iequals(word, "true"))
339 {
340 bool r = stg.insert_next_value(h_array, true);
341 CHECK_AND_ASSERT_THROW_MES(r, " failed to insert values section entry");
342 state = match_state_array_after_value;
343 }else if(boost::iequals(word, "false"))
344 {
345 bool r = stg.insert_next_value(h_array, false);
346 CHECK_AND_ASSERT_THROW_MES(r, " failed to insert values section entry");
347 state = match_state_array_after_value;
348 }
349 else ASSERT_MES_AND_THROW("Unknown value keyword " << word);
350 }else CHECK_ISSPACE();
351 break;
352 case array_mode_undifined:
353 default:
354 ASSERT_MES_AND_THROW("Bad array state");
355 }
356 break;
357 case match_state_error:
358 default:
359 ASSERT_MES_AND_THROW("WRONG JSON STATE");
360 }
361 }
362 }
363/*
364{
365 "firstName": "John",
366 "lastName": "Smith",
367 "age": 25,
368 "address": {
369 "streetAddress": "21 2nd Street",
370 "city": "New York",
371 "state": "NY",
372 "postalCode": -10021,
373 "have_boobs": true,
374 "have_balls": false
375 },
376 "phoneNumber": [
377 {
378 "type": "home",
379 "number": "212 555-1234"
380 },
381 {
382 "type": "fax",
383 "number": "646 555-4567"
384 }
385 ],
386 "phoneNumbers": [
387 "812 123-1234",
388 "916 123-4567"
389 ]
390}
391*/
392 template<class t_storage>
393 inline bool load_from_json(const std::string& buff_json, t_storage& stg)
394 {
395 std::string::const_iterator sec_buf_begin = buff_json.begin();
396 try
397 {
398 run_handler(nullptr, sec_buf_begin, buff_json.end(), stg, 0);
399 return true;
400 }
401 catch(const std::exception& ex)
402 {
403 MERROR("Failed to parse json, what: " << ex.what());
404 return false;
405 }
406 catch(...)
407 {
408 MERROR("Failed to parse json");
409 return false;
410 }
411 }
412 }
413 }
414}
const char * res
#define MERROR(x)
Definition misc_log_ex.h:73
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
#define ASSERT_MES_AND_THROW(message)
void match_string2(std::string::const_iterator &star_end_string, std::string::const_iterator buf_end, std::string &val)
void match_number2(std::string::const_iterator &star_end_string, std::string::const_iterator buf_end, boost::string_ref &val, bool &is_float_val, bool &is_signed_val)
void match_word2(std::string::const_iterator &star_end_string, std::string::const_iterator buf_end, boost::string_ref &val)
bool load_from_json(const std::string &buff_json, t_storage &stg)
void run_handler(typename t_storage::hsection current_section, std::string::const_iterator &sec_buf_begin, std::string::const_iterator buf_end, t_storage &stg, unsigned int recursion)
#define EPEE_JSON_RECURSION_LIMIT_INTERNAL
#define CHECK_ISSPACE()
signed __int64 int64_t
Definition stdint.h:135
unsigned __int64 uint64_t
Definition stdint.h:136