Seismo-VLAB  1.3
An Open-Source Finite Element Software for Meso-Scale Simulations
RSJparser.hpp
Go to the documentation of this file.
1 /* **************************************************************************************
2 * *
3 * A Ridiculously Simple JSON Parser for C++ (RSJp-cpp) *
4 * Version 2.x *
5 * ---------------------------------------------------------- *
6 * Copyright (C) 2018 Subhrajit Bhattacharya *
7 * *
8 * This program is free software: you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation, either version 3 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details <http://www.gnu.org/licenses/>. *
17 * *
18 * *
19 * Contact: subhrajit@gmail.com *
20 * https://www.lehigh.edu/~sub216/ , http://subhrajit.net/ *
21 * *
22 * *
23 *************************************************************************************** */
24 
25 #ifndef __RSJPARSE_HPP__
26 #define __RSJPARSE_HPP__
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string>
31 #include <vector>
32 #include <unordered_map>
33 #include <utility>
34 #include <iostream>
35 #include <climits>
36 
39 
45 
46 
47 static char const* RSJobjectbrackets = "{}";
48 static char const* RSJarraybrackets = "[]";
49 static char RSJobjectassignment = ':';
50 static char RSJarraydelimiter = ',';
51 
52 static std::vector<char const*> RSJbrackets = {RSJobjectbrackets, RSJarraybrackets};
53 static std::vector<char const*> RSJstringquotes = {"\"\"", "''"};
54 static char RSJcharescape = '\\';
55 static std::string RSJlinecommentstart = "//";
56 
57 static std::string RSJprinttab = " ";
58 
60 
61 // ============================================================
62 // Direct string manipulation functions
63 
64 inline
65 std::string to_string (RSJresourceType rt) {
66  switch (rt) {
67  case RSJ_UNINITIATED: return("RSJ_UNINITIATED");
68  case RSJ_UNKNOWN: return("RSJ_UNKNOWN");
69  case RSJ_OBJECT: return("RSJ_OBJECT");
70  case RSJ_ARRAY: return("RSJ_ARRAY");
71  case RSJ_LEAF: return("RSJ_LEAF");
72  default: return("");
73  }
74 }
75 
77 
78 inline
79 std::string strtrim (std::string str, std::string chars=" \t\n\r", int max_count=-1, StrTrimDir dirs=STRTRIM_LR) {
80  if (str.empty()) return(str);
81  if (max_count<0) max_count = str.length();
82 
83  if (dirs & STRTRIM_L) { // left trim
84  int p;
85  for (p=0; p<max_count; ++p)
86  if (chars.find(str[p])==std::string::npos) break;
87  str.erase (0, p);
88  }
89 
90  if (dirs & STRTRIM_R) { // right trim
91  int q, strlenm1=str.length()-1;
92  for (q=0; q<max_count; ++q)
93  if (chars.find(str[strlenm1-q])==std::string::npos) break;
94  str.erase (str.length()-q, q);
95  }
96 
97  return (str);
98 }
99 
100 inline
101 std::string strip_outer_quotes (std::string str, char* qq=NULL) {
102  str = strtrim (str);
103 
104  std::string ret = strtrim (str, "\"");
105  if (ret==str) {
106  ret = strtrim (str, "'");
107  if (qq && ret!=str) *qq = '\'';
108  }
109  else if (qq)
110  *qq = '"';
111 
112  return (ret);
113 }
114 
115 // ----------------
116 
117 inline
118 int is_bracket (char c, std::vector<char const*>& bracks, int indx=0) {
119  for (unsigned int b = 0; b < bracks.size(); ++b)
120  if (c==bracks[b][indx])
121  return (b);
122  return (-1);
123 }
124 
125 inline
126 std::vector<std::string> split_RSJ_array (const std::string& str) { // TODO: Make efficient. This function is speed bottleneck.
127  // splits, while respecting brackets and escapes
128  std::vector<std::string> ret;
129 
130  std::string current;
131  std::vector<int> bracket_stack;
132  std::vector<int> quote_stack;
133  bool escape_active = false;
134  int bi;
135 
136  for (unsigned int a = 0; a < str.length(); ++a) { // *
137 
138  // delimiter
139  if ( bracket_stack.size()==0 && quote_stack.size()==0 && str[a]==RSJarraydelimiter ) {
140  ret.push_back (current);
141  current.clear(); bracket_stack.clear(); quote_stack.clear(); escape_active = false;
142  continue; // to *
143  }
144 
145  // ------------------------------------
146  // checks for string
147 
148  if (quote_stack.size() > 0) { // already inside string
149  if (str[a]==RSJcharescape) // an escape character
150  escape_active = !escape_active;
151  else if (!escape_active && str[a]==RSJstringquotes[quote_stack.back()][1] ) { // close quote
152  quote_stack.pop_back();
153  escape_active = false;
154  }
155  else
156  escape_active = false;
157 
158  current.push_back (str[a]);
159  continue; // to *
160  }
161 
162  if (quote_stack.size()==0) { // check for start of string
163  if ((bi = is_bracket (str[a], RSJstringquotes)) >= 0) {
164  quote_stack.push_back (bi);
165  current.push_back (str[a]);
166  continue; // to *
167  }
168  }
169 
170  // ------------------------------------
171  // checks for comments
172 
173  if (quote_stack.size()==0) { // comment cannot start inside string
174 
175  // single-line commenst
176  if (str.compare (a, RSJlinecommentstart.length(), RSJlinecommentstart) == 0) {
177  // ignore until end of line
178  size_t newline_pos = str.find ("\n", a);
179  if (newline_pos == std::string::npos)
180  newline_pos = str.find ("\r", a);
181 
182  if (newline_pos != std::string::npos)
183  a = newline_pos; // point to the newline character (a will be incremented)
184  else // the comment continues until EOF
185  a = str.length();
186  continue;
187  }
188  }
189 
190  // ------------------------------------
191  // checks for brackets
192 
193  if ( bracket_stack.size()>0 && str[a]==RSJbrackets[bracket_stack.back()][1] ) { // check for closing bracket
194  bracket_stack.pop_back();
195  current.push_back (str[a]);
196  continue;
197  }
198 
199  if ((bi = is_bracket (str[a], RSJbrackets)) >= 0) {
200  bracket_stack.push_back (bi);
201  current.push_back (str[a]);
202  continue; // to *
203  }
204 
205  // ------------------------------------
206  // otherwise
207  current.push_back (str[a]);
208  }
209 
210  if (current.length() > 0)
211  ret.push_back (current);
212 
213  return (ret);
214 }
215 
216 inline
217 std::string insert_tab_after_newlines (std::string str) {
218  for (unsigned int a=0; a < str.length(); ++a)
219  if (str[a]=='\n') {
220  str.insert (a+1, RSJprinttab);
221  a += RSJprinttab.length();
222  }
223  return (str);
224 }
225 
226 
227 // ============================================================
228 
229 // forward declarations
230 class RSJparsedData;
232 
233 // Objet and array typedefs
234 typedef std::unordered_map <std::string,RSJresource> RSJobject;
235 typedef std::vector <RSJresource> RSJarray;
236 
237 // ------------------------------------
238 // Main classes
239 
240 class RSJresource {
241 /* Use: RSJresource("RSJ_string_data").as<RSJobject>()["keyName"].as<RSJarray>()[2].as<int>()
242  RSJresource("RSJ_string_data")["keyName"][2].as<int>() */
243 private:
244  // main data
245  std::string data; // can be object, vector or leaf data
246  bool _exists; // whether the RSJ resource exists.
247 
248  // parsed data
250 
251 public:
252  // constructor
253  RSJresource () : _exists (false), parsed_data_p (NULL) { } // no data field.
254 
255  RSJresource (std::string str) : data (str), _exists (true), parsed_data_p (NULL) { }
256  RSJresource (const char* str) : RSJresource(std::string(str)) { }
257 
258  // other convertion
259  template <class dataType>
260  RSJresource (dataType d) : RSJresource(std::to_string(d)) { }
261 
262  // read from file and stream
263  RSJresource (std::istream& is) : _exists (true), parsed_data_p (NULL) {
264  data = std::string ( (std::istreambuf_iterator<char>(is)), (std::istreambuf_iterator<char>()) );
265  }
266  RSJresource (std::ifstream& ifs) : _exists (true), parsed_data_p (NULL) {
267  std::istream& is = ifs;
268  data = std::string ( (std::istreambuf_iterator<char>(is)), (std::istreambuf_iterator<char>()) );
269  }
270 
271  // free allocated memory for parsed data
272  ~RSJresource();
273 
274  // deep copy
275  RSJresource (const RSJresource& r);
277 
278  // ------------------------------------
279  // parsers (old)
280  RSJresourceType parse (bool force=false);
281  void parse_full (bool force=false, int max_depth=INT_MAX, int* parse_count_for_verbose_p=NULL); // recursively parse the entire JSON text
282  // parser (new)
283  void fast_parse (std::string* str_p=NULL, bool copy_string=false, int max_depth=INT_MAX, size_t* parse_start_str_pos=NULL); // TODO: finish.
284 
285  RSJobject& as_object (bool force=false);
286  RSJarray& as_array (bool force=false);
287 
288  // ------------------------------------
289 
290  // access raw data and other attributes
291  int size(void);
292  std::string& raw_data (void) { return (data); }
293  bool exists (void) { return (_exists); }
294  bool is_parsed (void) { return (parsed_data_p!=NULL); }
295  RSJresourceType type (void);
296  // emitter
297  std::string as_str (bool print_comments=false, bool update_data=true);
298  void print (bool print_comments=false, bool update_data=true)
299  { std::cout << as_str(print_comments,update_data) << std::endl; }
300 
301  // opertor[]
302  RSJresource& operator[] (std::string key); // object
303  RSJresource& operator[] (unsigned int indx); // array
304 
305  // ------------------------------------
306 
307  // as
308  template <class dataType>
309  dataType as (const dataType& def = dataType()) { // specialized outside class declaration
310  if (!exists()) return (def);
311  return dataType (data); // default behavior for unknown types: invoke 'dataType(std::string)'
312  }
313 
314  // as_vector
315  template <class dataType, class vectorType=std::vector<dataType> > // vectorType should have push_back method
316  vectorType as_vector (const vectorType& def = vectorType());
317 
318  // as_map
319  template <class dataType, class mapType=std::unordered_map<std::string,dataType> > // mapType should have operator[] defined
320  mapType as_map (const mapType& def = mapType());
321 };
322 
323 // ------------------------------------------------------------
324 
326 public:
329 
332 
333  // parser
334  void parse (const std::string& data, RSJresourceType typ = RSJ_UNKNOWN) {
335  std::string content = strtrim(data);
336 
337  if (typ==RSJ_OBJECT || typ==RSJ_UNKNOWN) {
338  // parse as object:
339  content = strtrim (strtrim (content, "{", 1, STRTRIM_L ), "}", 1, STRTRIM_R );
340  if (content.length() != data.length()) { // a valid object
341  std::vector<std::string> nvPairs = split_RSJ_array (content);
342  for (unsigned int a=0; a<nvPairs.size(); ++a) {
343  std::size_t assignmentPos = nvPairs[a].find (RSJobjectassignment);
344  object.insert (make_pair(
345  strip_outer_quotes (nvPairs[a].substr (0,assignmentPos) ) ,
346  RSJresource (strtrim (nvPairs[a].substr (assignmentPos+1) ) )
347  ) );
348  }
349  if (object.size() > 0) {
350  type = RSJ_OBJECT;
351  return;
352  }
353  }
354  }
355 
356  if (typ==RSJ_ARRAY || typ==RSJ_UNKNOWN) {
357  // parse as array
358  content = strtrim (strtrim (content, "[", 1, STRTRIM_L ), "]", 1, STRTRIM_R );
359  if (content.length() != data.length()) { // a valid array
360  std::vector<std::string> nvPairs = split_RSJ_array (content);
361  for (unsigned int a=0; a<nvPairs.size(); ++a)
362  array.push_back (RSJresource (strtrim (nvPairs[a]) ) );
363  if (array.size() > 0) {
364  type = RSJ_ARRAY;
365  return;
366  }
367  }
368  }
369 
370  if (typ==RSJ_UNKNOWN)
371  type = RSJ_LEAF;
372  }
373 
374 
375  // remove non-existing items inserted due to accessing
376  int cleanup(void) {
377 
378  if (type==RSJ_OBJECT) {
379  bool found = true;
380  while (found) {
381  found = false;
382  for (auto it=object.begin(); it!=object.end(); ++it)
383  if (!(it->second.exists())) {
384  object.erase(it);
385  found = true;
386  break; // break for loop since it is now invalid
387  }
388  }
389  return (object.size());
390  }
391 
392  if (type==RSJ_ARRAY) { // erases only the non-existent elements at the tail
393  while (!(array[array.size()-1].exists()))
394  array.pop_back();
395  return (array.size());
396  }
397 
398  if (type==RSJ_LEAF)
399  return (1);
400 
401  return (0);
402  }
403 
404  // size
405  int size(void) { return (cleanup()); }
406 };
407 
408 
409 // ------------------------------------------------------------
410 // RSJresource member functions
411 
413  if (parsed_data_p) delete parsed_data_p;
414 }
415 
417  data=r.data;
418  _exists = r._exists;
419  if(r.parsed_data_p) parsed_data_p = new RSJparsedData(*(r.parsed_data_p));
420  else parsed_data_p = NULL;
421 }
422 
424  data=r.data;
425  _exists = r._exists;
426  if(r.parsed_data_p) parsed_data_p = new RSJparsedData(*(r.parsed_data_p));
427  else parsed_data_p = NULL;
428  return *this;
429 }
430 
431 int RSJresource::size (void) {
432  parse();
433  return (parsed_data_p->size());
434 }
435 
437  if (!exists()) return (RSJ_UNINITIATED);
438  parse(); // parse if not parsed
439  return (parsed_data_p->type);
440 }
441 
442 std::string RSJresource::as_str (bool print_comments, bool update_data) {
443  if (exists()) {
444  std::string ret;
445  parse(); // parse if not parsed
446  parsed_data_p->cleanup();
447 
448  if (parsed_data_p->type==RSJ_OBJECT) {
449  ret = "{\n";
450  for (auto it=parsed_data_p->object.begin(); it!=parsed_data_p->object.end(); ++it) {
451  ret += RSJprinttab + "'" + it->first + "': " + insert_tab_after_newlines( it->second.as_str (print_comments, update_data) );
452  if (std::next(it) != parsed_data_p->object.end()) ret += ",";
453  if (print_comments)
454  ret += " // " + to_string(it->second.type());
455  ret += "\n";
456  }
457  ret += "}";
458  }
459  else if (parsed_data_p->type==RSJ_ARRAY) {
460  ret = "[\n";
461  for (auto it=parsed_data_p->array.begin(); it!=parsed_data_p->array.end(); ++it) {
462  ret += RSJprinttab + insert_tab_after_newlines( it->as_str (print_comments, update_data) );
463  if (std::next(it) != parsed_data_p->array.end()) ret += ",";
464  if (print_comments)
465  ret += " // " + to_string(it->type());
466  ret += "\n";
467  }
468  ret += "]";
469  }
470  else // RSJ_LEAF or RSJ_UNKNOWN
471  ret = strtrim (data);
472 
473  if (update_data) data = ret;
474  return (ret);
475  }
476  else
477  return ("");
478 }
479 
480 // Parsers
481 
483  if (!parsed_data_p) parsed_data_p = new RSJparsedData;
484  if (parsed_data_p->type==RSJ_UNKNOWN || force) parsed_data_p->parse (data, RSJ_UNKNOWN);
485  return (parsed_data_p->type);
486 }
487 
488 void RSJresource::parse_full (bool force, int max_depth, int* parse_count_for_verbose_p) { // recursive parsing (slow)
489  if (max_depth==0) return;
490  if (!parsed_data_p) parsed_data_p = new RSJparsedData;
491  if (parsed_data_p->type==RSJ_UNKNOWN || force) parsed_data_p->parse (data, RSJ_UNKNOWN);
492  // verbose
493  if (parse_count_for_verbose_p) {
494  (*parse_count_for_verbose_p)++;
495  if ( (*parse_count_for_verbose_p) % 100 == 0)
496  std::cout << "parse_full: " << (*parse_count_for_verbose_p) << " calls." << std::endl;
497  }
498  // recursive parse children if not already parsed
499  if (parsed_data_p->type==RSJ_OBJECT)
500  for (auto it=parsed_data_p->object.begin(); it!=parsed_data_p->object.end(); ++it)
501  it->second.parse_full (force, max_depth-1, parse_count_for_verbose_p);
502  else if (parsed_data_p->type==RSJ_ARRAY)
503  for (auto it=parsed_data_p->array.begin(); it!=parsed_data_p->array.end(); ++it)
504  it->parse_full (force, max_depth-1, parse_count_for_verbose_p);
505 }
506 
507 // ------------------------------------------------------------
508 // ============================================================
509 // FAST PARSER (Under construction. DO NOT use the following functions in your application.)
510 
511 inline
512 int seek_next (std::string* str_p, int start_pos, char character) {
513  (void)str_p;
514  (void)start_pos;
515  (void)character;
516  return 0;
517 }
518 
519 
520 void RSJresource::fast_parse (std::string* str_p, bool copy_string, int max_depth, size_t* parse_start_str_pos) {
521  // TODO: UNDER CONSTRUCTION...
522  (void)max_depth;
523  (void)copy_string;
524 
525  if (!str_p)
526  str_p = &data;
527  std::string& str = *str_p;
528 
529  // splits, while respecting brackets and escapes
530  //std::vector<std::string> ret;
531 
532  //std::string current;
533  std::vector<int> bracket_stack;
534  std::vector<int> quote_stack;
535  bool escape_active = false;
536  int bi;
537 
538  bool initial_whitespaces = true;
539  bool isroot = false;
540 
541  if (!parse_start_str_pos) {
542  parse_start_str_pos = new size_t;
543  *parse_start_str_pos = 0;
544  isroot = true;
545  }
546 
547  size_t a = *parse_start_str_pos;
548 
549  while (*parse_start_str_pos < str_p->length()) { // *
550 
551  // initial whitespace characters
552  if (initial_whitespaces) {
553  if (str[a] == ' ' || str[a] == '\n' || str[a] == '\r' || str[a] == '\t' ) {
554  ++a;
555  continue;
556  }
557  else {
558  if (str[a] == '{') // start of object
559  // ... TODO: seek_next ':'
560 
561  initial_whitespaces = false;
562  }
563  }
564 
565 
566  // delimiter
567  if ( bracket_stack.size()==0 && quote_stack.size()==0 && str[a]==RSJarraydelimiter ) {
568  //ret.push_back (current);
569 
570  //current.clear();
571  bracket_stack.clear(); quote_stack.clear(); escape_active = false;
572  continue; // to *
573  }
574 
575  // ------------------------------------
576  // checks for string
577 
578  if (quote_stack.size() > 0) { // already inside string
579  if (str[a]==RSJcharescape) // an escape character
580  escape_active = !escape_active;
581  else if (!escape_active && str[a]==RSJstringquotes[quote_stack.back()][1] ) { // close quote
582  quote_stack.pop_back();
583  escape_active = false;
584  }
585  else
586  escape_active = false;
587 
588  //current.push_back (str[a]);
589  continue; // to *
590  }
591 
592  if (quote_stack.size()==0) { // check for start of string
593  if ((bi = is_bracket (str[a], RSJstringquotes)) >= 0) {
594  quote_stack.push_back (bi);
595  //current.push_back (str[a]);
596  continue; // to *
597  }
598  }
599 
600  // ------------------------------------
601  // checks for comments
602 
603  if (quote_stack.size()==0) { // comment cannot start inside string
604 
605  // single-line commenst
606  if (str.compare (a, RSJlinecommentstart.length(), RSJlinecommentstart) == 0) {
607  // ignore until end of line
608  size_t newline_pos = str.find ("\n", a);
609  if (newline_pos == std::string::npos)
610  newline_pos = str.find ("\r", a);
611 
612  if (newline_pos != std::string::npos)
613  a = newline_pos; // point to the newline character (a will be incremented)
614  else // the comment continues until EOF
615  a = str.length();
616  continue;
617  }
618  }
619 
620  // ------------------------------------
621  // checks for brackets
622 
623  if ( bracket_stack.size()>0 && str[a]==RSJbrackets[bracket_stack.back()][1] ) { // check for closing bracket
624  bracket_stack.pop_back();
625  //current.push_back (str[a]);
626  continue;
627  }
628 
629  if ((bi = is_bracket (str[a], RSJbrackets)) >= 0) {
630  bracket_stack.push_back (bi);
631  //current.push_back (str[a]);
632  continue; // to *
633  }
634 
635  // ------------------------------------
636  // otherwise
637  //current.push_back (str[a]);
638  }
639 
640  /*if (current.length() > 0)
641  ret.push_back (current); */
642 
643  if (isroot)
644  delete parse_start_str_pos;
645 
646  // return (ret);
647 }
648 
649 // ============================================================
650 
651 // ------------------------------------------------------------
652 
654  if (!parsed_data_p) parsed_data_p = new RSJparsedData;
655  if (parsed_data_p->type==RSJ_UNKNOWN || force) parsed_data_p->parse (data, RSJ_OBJECT);
656  return (parsed_data_p->object);
657 }
658 
659 RSJresource& RSJresource::operator[] (std::string key) { // returns reference
660  return ( (as_object())[key] ); // will return empty resource (with _exists==false) if
661  // either this resource does not exist, is not an object, or the key does not exist
662 }
663 
665  if (!parsed_data_p) parsed_data_p = new RSJparsedData;
666  if (parsed_data_p->type==RSJ_UNKNOWN || force) parsed_data_p->parse (data, RSJ_ARRAY);
667  return (parsed_data_p->array);
668 }
669 
670 RSJresource& RSJresource::operator[] (unsigned int indx) { // returns reference
671  as_array();
672  if (indx >= parsed_data_p->array.size())
673  parsed_data_p->array.resize(indx+1); // insert empty resources
674  return (parsed_data_p->array[indx]); // will return empty resource (with _exists==false) if
675  // either this resource does not exist, is not an object, or the key does not exist
676 }
677 
678 // ------------------------------------------------------------
679 // special 'as':
680 
681 template <class dataType, class vectorType>
682 vectorType RSJresource::as_vector (const vectorType& def) { // returns copy -- for being consistent with other 'as' specializations
683  if (!exists()) return (def);
684  vectorType ret;
685  as_array();
686  for (auto it=parsed_data_p->array.begin(); it!=parsed_data_p->array.end(); ++it)
687  ret.push_back (it->as<dataType>());
688  return (ret);
689 }
690 
691 template <class dataType, class mapType>
692 mapType RSJresource::as_map (const mapType& def) { // returns copy -- for being consistent with other 'as' specializations
693  if (!exists()) return (def);
694  mapType ret;
695  as_object();
696  for (auto it=parsed_data_p->object.begin(); it!=parsed_data_p->object.end(); ++it)
697  ret[it->first] = it->second.as<dataType>();
698  return (ret);
699 }
700 
701 // ============================================================
702 // Specialized .as() member functions
703 
704 // Helper preprocessor directives
705 #define rsjObject as<RSJobject>()
706 #define rsjArray as<RSJarray>()
707 #define rsjAs(t) as<t>()
708 
709 
710 // RSJobject
711 template <> inline
712 RSJobject RSJresource::as<RSJobject> (const RSJobject& def) { // returns copy -- for being consistent with other 'as' specializations
713  if (!exists()) return (def);
714  return (as_object());
715 }
716 
717 // RSJarray
718 template <> inline
719 RSJarray RSJresource::as<RSJarray> (const RSJarray& def) { // returns copy -- for being consistent with other 'as' specializations
720  if (!exists()) return (def);
721  return (as_array());
722 }
723 
724 // ------------------------------------
725 // Elementary types
726 
727 // String
728 template <> inline
729 std::string RSJresource::as<std::string> (const std::string& def) {
730  if (!exists()) return (def);
731 
732  char qq = '\0';
733  std::string ret = strip_outer_quotes (data, &qq);
734 
735  std::vector< std::vector<std::string> > escapes = { {"\\n","\n"}, {"\\r","\r"}, {"\\t","\t"}, {"\\\\","\\"} };
736  if (qq=='"')
737  escapes.push_back ({"\\\"","\""});
738  else if (qq=='\'')
739  escapes.push_back ({"\\'","'"});
740 
741  for (unsigned int a=0; a < escapes.size(); ++a)
742  for ( std::size_t start_pos=ret.find(escapes[a][0]); start_pos!=std::string::npos; start_pos=ret.find(escapes[a][0],start_pos) ) {
743  ret.replace (start_pos, escapes[a][0].length(), escapes[a][1]);
744  start_pos += escapes[a][1].length();
745  }
746 
747  return (ret);
748 }
749 
750 // integer
751 template <> inline
752 int RSJresource::as<int> (const int& def) {
753  if (!exists()) return (def);
754  return (atoi (strip_outer_quotes(data).c_str() ) );
755 }
756 
757 // double
758 template <> inline
759 double RSJresource::as<double> (const double& def) {
760  if (!exists()) return (def);
761  return (atof (strip_outer_quotes(data).c_str() ) );
762 }
763 
764 // bool
765 template <> inline
766 bool RSJresource::as<bool> (const bool& def) {
767  if (!exists()) return (def);
768  std::string cleanData = strip_outer_quotes (data);
769  if (cleanData=="true" || cleanData=="TRUE" || cleanData=="True" || atoi(cleanData.c_str())!=0) return (true);
770  return (false);
771 }
772 
773 // ------------------------------------
774 // Other types
775 
776 
777 
778 #endif
std::vector< std::string > split_RSJ_array(const std::string &str)
Definition: RSJparser.hpp:126
RSJobject & as_object(bool force=false)
Definition: RSJparser.hpp:653
vectorType as_vector(const vectorType &def=vectorType())
Definition: RSJparser.hpp:682
int size(void)
Definition: RSJparser.hpp:405
RSJparsedData()
Definition: RSJparser.hpp:331
static std::string RSJlinecommentstart
Definition: RSJparser.hpp:55
mapType as_map(const mapType &def=mapType())
Definition: RSJparser.hpp:692
static char RSJobjectassignment
Definition: RSJparser.hpp:49
bool exists(void)
Definition: RSJparser.hpp:293
RSJresourceType
Definition: RSJparser.hpp:59
RSJresourceType type(void)
Definition: RSJparser.hpp:436
std::string data
Definition: RSJparser.hpp:245
Definition: RSJparser.hpp:59
RSJresource(dataType d)
Definition: RSJparser.hpp:260
Definition: RSJparser.hpp:59
Definition: RSJparser.hpp:76
STL namespace.
Definition: RSJparser.hpp:59
std::string as_str(bool print_comments=false, bool update_data=true)
Definition: RSJparser.hpp:442
RSJresource(std::istream &is)
Definition: RSJparser.hpp:263
RSJresourceType type
Definition: RSJparser.hpp:330
RSJresource & operator=(const RSJresource &r)
Definition: RSJparser.hpp:423
RSJarray & as_array(bool force=false)
Definition: RSJparser.hpp:664
static std::vector< char const * > RSJbrackets
Definition: RSJparser.hpp:52
static char RSJarraydelimiter
Definition: RSJparser.hpp:50
std::vector< RSJresource > RSJarray
Definition: RSJparser.hpp:235
int seek_next(std::string *str_p, int start_pos, char character)
Definition: RSJparser.hpp:512
std::string & raw_data(void)
Definition: RSJparser.hpp:292
Definition: RSJparser.hpp:59
static std::vector< char const * > RSJstringquotes
Definition: RSJparser.hpp:53
static std::string RSJprinttab
Definition: RSJparser.hpp:57
int size(void)
Definition: RSJparser.hpp:431
RSJresourceType parse(bool force=false)
Definition: RSJparser.hpp:482
bool _exists
Definition: RSJparser.hpp:246
Definition: RSJparser.hpp:240
int cleanup(void)
Definition: RSJparser.hpp:376
bool is_parsed(void)
Definition: RSJparser.hpp:294
RSJobject object
Definition: RSJparser.hpp:327
dataType as(const dataType &def=dataType())
Definition: RSJparser.hpp:309
std::string strtrim(std::string str, std::string chars=" \\, int max_count=-1, StrTrimDir dirs=STRTRIM_LR)
Definition: RSJparser.hpp:79
std::string to_string(RSJresourceType rt)
Definition: RSJparser.hpp:65
std::string strip_outer_quotes(std::string str, char *qq=NULL)
Definition: RSJparser.hpp:101
int is_bracket(char c, std::vector< char const *> &bracks, int indx=0)
Definition: RSJparser.hpp:118
RSJresource(std::string str)
Definition: RSJparser.hpp:255
std::string insert_tab_after_newlines(std::string str)
Definition: RSJparser.hpp:217
StrTrimDir
Definition: RSJparser.hpp:76
RSJresource()
Definition: RSJparser.hpp:253
~RSJresource()
Definition: RSJparser.hpp:412
std::unordered_map< std::string, RSJresource > RSJobject
Definition: RSJparser.hpp:231
RSJparsedData * parsed_data_p
Definition: RSJparser.hpp:249
static char RSJcharescape
Definition: RSJparser.hpp:54
static char const * RSJarraybrackets
Definition: RSJparser.hpp:48
void parse_full(bool force=false, int max_depth=INT_MAX, int *parse_count_for_verbose_p=NULL)
Definition: RSJparser.hpp:488
Definition: RSJparser.hpp:76
RSJresource & operator[](std::string key)
Definition: RSJparser.hpp:659
Definition: RSJparser.hpp:325
static char const * RSJobjectbrackets
Definition: RSJparser.hpp:47
RSJarray array
Definition: RSJparser.hpp:328
void fast_parse(std::string *str_p=NULL, bool copy_string=false, int max_depth=INT_MAX, size_t *parse_start_str_pos=NULL)
Definition: RSJparser.hpp:520
RSJresource(std::ifstream &ifs)
Definition: RSJparser.hpp:266
void print(bool print_comments=false, bool update_data=true)
Definition: RSJparser.hpp:298
Definition: RSJparser.hpp:59
Definition: RSJparser.hpp:76
void parse(const std::string &data, RSJresourceType typ=RSJ_UNKNOWN)
Definition: RSJparser.hpp:334
RSJresource(const char *str)
Definition: RSJparser.hpp:256