Flow123d  release_2.1.0-87-gfbc1563
path_json.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file path_json.cc
15  * @brief
16  */
17 
18 #include "input/path_json.hh"
20 #include "input/comment_filter.hh"
21 #include "system/system.hh"
22 
24 #include <boost/iostreams/device/file.hpp>
25 #include <boost/iostreams/filtering_stream.hpp>
26 #include <boost/algorithm/string.hpp>
27 
28 
29 namespace Input {
30 using namespace std;
31 
32 
33 PathJSON::PathJSON(istream &in)
34 : PathJSON()
35 {
36  io::filtering_istream filter_in;
37 
38  filter_in.push(uncommenting_filter());
39  filter_in.push(in);
40 
41  root_node_ = std::make_shared<Node>();
42 
43  try {
44  json_spirit::read_or_throw( filter_in, *root_node_);
45  } catch (json_spirit::Error_position &e ) {
46  THROW( ReaderToStorage::ExcNotJSONFormat() << ReaderToStorage::EI_JSONLine(e.line_) << ReaderToStorage::EI_JSONColumn(e.column_)
47  << ReaderToStorage::EI_JSONReason(e.reason_));
48  }
49 
50  nodes_.push_back( root_node_.get() );
51 }
52 
53 
55 : PathBase()
56 {
57  /* from json_spirit_value.hh:
58  * enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type };
59  */
60  json_type_names.push_back("JSON object");
61  json_type_names.push_back("JSON array");
62  json_type_names.push_back("JSON string");
63  json_type_names.push_back("JSON bool");
64  json_type_names.push_back("JSON int");
65  json_type_names.push_back("JSON real");
66  json_type_names.push_back("JSON null");
67  json_type_names.push_back(""); //scalar type
68  json_type_names.push_back(""); //undefined type
69 }
70 
71 
73 {
74  this->go_to_root();
75 }
76 
77 bool PathJSON::down(unsigned int index)
78 {
79  const Node * head_node = nodes_.back();
80  const json_spirit::mArray &array = head_node->get_array(); // the type should be checked in make_storage
81 
82  if ( index >= array.size()) return false;
83  path_.push_back( make_pair( index, string("") ) );
84  nodes_.push_back( &( array[index] ) );
85  return true;
86 }
87 
88 
89 bool PathJSON::down(const string& key)
90 {
91  const Node * head_node = nodes_.back();
92  const json_spirit::mObject &obj = head_node->get_obj(); // the type should be checked in make_storage
93 
94  json_spirit::mObject::const_iterator it = obj.find(key);
95  if (it == obj.end()) {
96  return false;
97  } else {
98  path_.push_back( make_pair( (int)(-1), key) );
99  nodes_.push_back( &( it->second ) );
100  }
101  return true;
102 }
103 
104 
106 {
107  if (path_.size() > 1) {
108  path_.pop_back();
109  nodes_.pop_back();
110  }
111 }
112 
113 
114 /**
115  * This returns path to reference given by address in ref_address.
116  *
117  */
119 {
120  namespace ba = boost::algorithm;
121 
122  const Node * head_node = nodes_.back();
123  if (head_node->type() != json_spirit::obj_type) return NULL;
124  const json_spirit::mObject &obj = head_node->get_obj();
125  if (obj.size() != 1) return NULL;
126  if (obj.begin()->first != "REF") return NULL;
127 
128  const Node &ref_node = obj.begin()->second;
129  if (ref_node.type() != json_spirit::str_type) {
130  THROW( ExcRefOfWrongType() << EI_ErrorAddress(this->as_string()) );
131 
132  }
133  string ref_address = ref_node.get_str();
134 
135  PathJSON * ref_path = this->clone();
136  string::size_type pos = 0;
137  string::size_type new_pos = 0;
138  string address = ref_address + '/';
139  string tmp_str;
140  bool relative_ref = false;
141 
142  std::set<string>::iterator it = previous_references_.find(ref_address);
143  if (it == previous_references_.end()) {
144  ref_path->previous_references_.insert(ref_address);
145  } else {
146  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
147  << EI_Specification("cannot follow reference") );
148  }
149 
150  while ( ( new_pos=address.find('/',pos) ) != string::npos ) {
151  tmp_str = address.substr(pos, new_pos - pos);
152  if (pos==0 && tmp_str == "") {
153  // absolute path
154  ref_path->go_to_root();
155 
156  } else if ( ba::all( tmp_str, ba::is_digit()) ) {
157  // integer == index in array
158  if ( !ref_path->is_array_type() ) {
159  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
160  << EI_Specification("there should be Array") );
161  }
162 
163  if ( !ref_path->down( atoi(tmp_str.c_str()) ) ) {
164  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
165  << EI_Specification("index out of size of Array") );
166  }
167 
168  } else if (tmp_str == "..") {
169  relative_ref = true;
170  if (ref_path->level() <= 0 ) {
171  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
172  << EI_Specification("can not go up from root") );
173  }
174  ref_path->up();
175 
176  } else {
177  if ( !ref_path->is_record_type() )
178  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
179  << EI_Specification("there should be Record") );
180  if ( !ref_path->down(tmp_str) )
181  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
182  << EI_Specification("key '"+tmp_str+"' not found") );
183  }
184  pos = new_pos+1;
185  }
186  if (relative_ref) {
187  MessageOut() << "Referencing '" << this->as_string() << "' to '" << ref_path->as_string() << "'." << std::endl;
188  }
189  return ref_path;
190 }
191 
192 
193 
195  return head()->type() == json_spirit::null_type;
196 }
197 
198 
200  if (head()->type() == json_spirit::bool_type) {
201  return head()->get_bool();
202  } else {
203  THROW( ReaderToStorage::ExcInputError() );
204  }
205  return false;
206 }
207 
208 
209 
210 std::int64_t PathJSON::get_int_value() const {
211  if (head()->type() == json_spirit::int_type) {
212  return head()->get_int64();
213  } else {
214  THROW( ReaderToStorage::ExcInputError() );
215  }
216  return 0;
217 }
218 
219 
220 
222  auto value_type = head()->type();
223  if ( value_type== json_spirit::real_type
224  || value_type == json_spirit::int_type) {
225  return head()->get_real();
226  } else {
227  THROW( ReaderToStorage::ExcInputError() );
228  }
229  return 0.0;
230 }
231 
232 
233 
234 std::string PathJSON::get_string_value() const {
235  if (head()->type() == json_spirit::str_type) {
236  return head()->get_str();
237  } else {
238  THROW( ReaderToStorage::ExcInputError() );
239  }
240  return "";
241 }
242 
243 
244 
245 unsigned int PathJSON::get_node_type_index() const {
246  return head()->type();
247 }
248 
249 
250 
251 bool PathJSON::get_record_key_set(std::set<std::string> &keys_list) const {
252  if ( this->is_record_type() ) {
253  const json_spirit::mObject & j_map = head()->get_obj();
254  json_spirit::mObject::const_iterator map_it;
255  std::set<string>::iterator set_it;
256 
257  for( map_it = j_map.begin(); map_it != j_map.end(); ++map_it) {
258  keys_list.insert(map_it->first);
259  }
260 
261  return true;
262  }
263 
264  return false;
265 }
266 
267 
268 
270  if (head()->type() == json_spirit::array_type) {
271  const json_spirit::mArray & j_array = head()->get_array();
272  return j_array.size();
273  }
274 
275  return -1;
276 }
277 
278 
279 
281  return head()->type() == json_spirit::obj_type;
282 }
283 
284 
285 
287  return head()->type() == json_spirit::array_type;
288 }
289 
290 
291 
293  return new PathJSON(*this);
294 }
295 
296 
297 
298 std::string PathJSON::get_record_name() const {
299  std::string desc_name = "";
300  if ( this->is_record_type() ) {
301  PathJSON type_path(*this);
302  if ( type_path.down("TYPE") ) {
303  //check if TYPE key is reference
304  PathBase * ref_path = type_path.find_ref_node();
305  if (ref_path) {
306  desc_name = ref_path->get_string_value();
307  delete ref_path;
308  } else {
309  desc_name = type_path.get_string_value();
310  }
311  }
312  }
313 
314  return desc_name;
315 }
316 
317 
318 
321 }
322 
323 
324 
326  return false;
327 }
328 
329 
330 
331 std::ostream& operator<<(std::ostream& stream, const PathJSON& path) {
332  path.output(stream);
333  return stream;
334 }
335 
336 
337 } // namespace Input
bool is_array_type() const override
Implements PathBase::is_array_type.
Definition: path_json.cc:286
boost::int64_t get_int64() const
bool is_null_type() const override
Implements PathBase::is_null_type.
Definition: path_json.cc:194
io::finite_state_filter< uncommenting_fsm > uncommenting_filter
Class used by ReaderToStorage class to iterate over the JSON tree provided by json_spirit library...
Definition: path_json.hh:40
std::ostream & operator<<(std::ostream &stream, const Address &address)
Definition: accessors.hh:247
Base abstract class used by ReaderToStorage class to iterate over the input tree. ...
Definition: path_base.hh:39
#define MessageOut()
Macro defining &#39;message&#39; record of log.
Definition: logger.hh:231
std::string as_string() const
Returns string address of current position.
Definition: path_base.cc:48
PathBase * find_ref_node() override
Implements reading of reference keys, and check of cyclic references.
Definition: path_json.cc:118
std::vector< std::string > json_type_names
Names of all possible node types in parsed input tree.
Definition: path_base.hh:173
const Node * head() const
Pointer to JSON Value object at current path.
Definition: path_json.hh:116
std::vector< const Node * > nodes_
Definition: path_json.hh:130
bool down(unsigned int index) override
Dive into json_spirit hierarchy.
Definition: path_json.cc:77
bool is_record_type() const override
Implements PathBase::is_record_type.
Definition: path_json.cc:280
double get_double_value() const override
Implements PathBase::get_double_value.
Definition: path_json.cc:221
void go_to_root()
Move to root node.
Definition: path_base.cc:56
void up() override
Return one level up in the hierarchy.
Definition: path_json.cc:105
void read_or_throw(const std::string &s, mValue &value)
std::int64_t get_int_value() const override
Implements PathBase::get_int_value.
Definition: path_json.cc:210
const String_type & get_str() const
std::vector< std::pair< int, std::string > > path_
One level of the path_ is either index (nonnegative int) in array or string key in a json object...
Definition: path_base.hh:164
void remember_reference()
Put address of actual reference to previous_references_ set.
Definition: path_json.cc:319
~PathJSON() override
Destructor.
Definition: path_json.cc:72
int level() const
Implements PathBase::level.
Definition: path_json.hh:77
unsigned int get_node_type_index() const override
Implements PathBase::get_node_type_index.
Definition: path_json.cc:245
std::string get_string_value() const override
Implements PathBase::get_string_value.
Definition: path_json.cc:234
Value_type type() const
virtual std::string get_string_value() const =0
Get string value of head node or throw exception.
const Array & get_array() const
bool get_record_key_set(std::set< std::string > &) const override
Implements PathBase::get_record_key_set.
Definition: path_json.cc:251
bool is_effectively_null() const override
Implements PathBase::is_effectively_null.
Definition: path_json.cc:325
void output(std::ostream &stream) const
Output to the given stream.
Definition: path_base.cc:31
std::string get_record_name() const override
Implements PathBase::get_record_name.
Definition: path_json.cc:298
const Object & get_obj() const
PathJSON()
Default constructor.
Definition: path_json.cc:54
int get_array_size() const override
Implements PathBase::get_array_size.
Definition: path_json.cc:269
std::set< std::string > previous_references_
Remember used references in order to avoid detect cyclic references.
Definition: path_json.hh:124
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:45
PathJSON * clone() const override
Implements PathBase::clone.
Definition: path_json.cc:292
bool get_bool_value() const override
Implements PathBase::get_bool_value.
Definition: path_json.cc:199