1    	#include "common/ceph_json.h"
2    	#include "include/utime.h"
3    	
4    	// for testing DELETE ME
5    	#include <fstream>
6    	#include <include/types.h>
7    	
8    	#include <boost/algorithm/string.hpp>
9    	#include <boost/tokenizer.hpp>
10   	#include <boost/lexical_cast.hpp>
11   	
12   	#include "json_spirit/json_spirit_writer_template.h"
13   	
14   	using namespace json_spirit;
15   	
16   	#define dout_subsys ceph_subsys_rgw
17   	
18   	
19   	static JSONFormattable default_formattable;
20   	
21   	
22   	void encode_json(const char *name, const JSONObj::data_val& v, Formatter *f)
23   	{
24   	  if (v.quoted) {
25   	    encode_json(name, v.str, f);
26   	  } else {
27   	    f->dump_format_unquoted(name, "%s", v.str.c_str());
28   	  }
29   	}
30   	
31   	JSONObjIter::JSONObjIter()
32   	{
33   	}
34   	
35   	JSONObjIter::~JSONObjIter()
36   	{
37   	}
38   	
39   	void JSONObjIter::set(const JSONObjIter::map_iter_t &_cur, const JSONObjIter::map_iter_t &_last)
40   	{
41   	  cur = _cur;
42   	  last = _last;
43   	}
44   	
45   	void JSONObjIter::operator++()
46   	{
47   	  if (cur != last)
48   	    ++cur;
49   	}
50   	
51   	JSONObj *JSONObjIter::operator*()
52   	{
53   	  return cur->second;
54   	}
55   	
56   	// does not work, FIXME
57   	ostream& operator<<(ostream &out, const JSONObj &obj) {
58   	   out << obj.name << ": " << obj.val;
59   	   return out;
60   	}
61   	
62   	JSONObj::~JSONObj()
63   	{
64   	  multimap<string, JSONObj *>::iterator iter;
65   	  for (iter = children.begin(); iter != children.end(); ++iter) {
66   	    JSONObj *obj = iter->second;
67   	    delete obj;
68   	  }
69   	}
70   	
71   	
72   	void JSONObj::add_child(string el, JSONObj *obj)
73   	{
74   	  children.insert(pair<string, JSONObj *>(el, obj));
75   	}
76   	
77   	bool JSONObj::get_attr(string name, data_val& attr)
78   	{
79   	  auto iter = attr_map.find(name);
80   	  if (iter == attr_map.end())
81   	    return false;
82   	  attr = iter->second;
83   	  return true;
84   	}
85   	
86   	JSONObjIter JSONObj::find(const string& name)
87   	{
88   	  JSONObjIter iter;
89   	  map<string, JSONObj *>::iterator first;
90   	  map<string, JSONObj *>::iterator last;
91   	  first = children.find(name);
92   	  if (first != children.end()) {
93   	    last = children.upper_bound(name);
94   	    iter.set(first, last);
95   	  }
96   	  return iter;
97   	}
98   	
99   	JSONObjIter JSONObj::find_first()
100  	{
101  	  JSONObjIter iter;
102  	  iter.set(children.begin(), children.end());
103  	  return iter;
104  	}
105  	
106  	JSONObjIter JSONObj::find_first(const string& name)
107  	{
108  	  JSONObjIter iter;
109  	  map<string, JSONObj *>::iterator first;
110  	  first = children.find(name);
111  	  iter.set(first, children.end());
112  	  return iter;
113  	}
114  	
115  	JSONObj *JSONObj::find_obj(const string& name)
116  	{
117  	  JSONObjIter iter = find(name);
118  	  if (iter.end())
119  	    return NULL;
120  	
121  	  return *iter;
122  	}
123  	
124  	bool JSONObj::get_data(const string& key, data_val *dest)
125  	{
126  	  JSONObj *obj = find_obj(key);
127  	  if (!obj)
128  	    return false;
129  	
130  	  *dest = obj->get_data_val();
131  	
132  	  return true;
133  	}
134  	
135  	/* accepts a JSON Array or JSON Object contained in
136  	 * a JSON Spirit Value, v,  and creates a JSONObj for each
137  	 * child contained in v
138  	 */
139  	void JSONObj::handle_value(Value v)
140  	{
141  	  if (v.type() == obj_type) {
142  	    Object temp_obj = v.get_obj();
143  	    for (Object::size_type i = 0; i < temp_obj.size(); i++) {
144  	      Pair temp_pair = temp_obj[i];
145  	      string temp_name = temp_pair.name_;
146  	      Value temp_value = temp_pair.value_;
147  	      JSONObj *child = new JSONObj;
148  	      child->init(this, temp_value, temp_name);
149  	      add_child(temp_name, child);
150  	    }
151  	  } else if (v.type() == array_type) {
152  	    Array temp_array = v.get_array();
153  	    Value value;
154  	
155  	    for (unsigned j = 0; j < temp_array.size(); j++) {
156  	      Value cur = temp_array[j];
157  	      string temp_name;
158  	
159  	      JSONObj *child = new JSONObj;
160  	      child->init(this, cur, temp_name);
161  	      add_child(child->get_name(), child);
162  	    }
163  	  }
164  	}
165  	
166  	void JSONObj::init(JSONObj *p, Value v, string n)
167  	{
168  	  name = n;
169  	  parent = p;
170  	  data = v;
171  	
172  	  handle_value(v);
173  	  if (v.type() == str_type) {
174  	    val.set(v.get_str(), true);
175  	  } else {
176  	    val.set(json_spirit::write_string(v), false);
177  	  }
178  	  attr_map.insert(pair<string,data_val>(name, val));
179  	}
180  	
181  	JSONObj *JSONObj::get_parent()
182  	{
183  	  return parent;
184  	}
185  	
186  	bool JSONObj::is_object()
187  	{
188  	  return (data.type() == obj_type);
189  	}
190  	
191  	bool JSONObj::is_array()
192  	{
193  	  return (data.type() == array_type);
194  	}
195  	
196  	vector<string> JSONObj::get_array_elements()
197  	{
198  	  vector<string> elements;
199  	  Array temp_array;
200  	
201  	  if (data.type() == array_type)
202  	    temp_array = data.get_array();
203  	
204  	  int array_size = temp_array.size();
205  	  if (array_size > 0)
206  	    for (int i = 0; i < array_size; i++) {
207  	      Value temp_value = temp_array[i];
208  	      string temp_string;
209  	      temp_string = write(temp_value, raw_utf8);
210  	      elements.push_back(temp_string);
211  	    }
212  	
213  	  return elements;
214  	}
215  	
216  	JSONParser::JSONParser() : buf_len(0), success(true)
217  	{
218  	}
219  	
220  	JSONParser::~JSONParser()
221  	{
222  	}
223  	
224  	
225  	
226  	void JSONParser::handle_data(const char *s, int len)
227  	{
228  	  json_buffer.append(s, len); // check for problems with null termination FIXME
229  	  buf_len += len;
230  	}
231  	
232  	// parse a supplied JSON fragment
233  	bool JSONParser::parse(const char *buf_, int len)
234  	{
235  	  if (!buf_) {
236  	    set_failure();
237  	    return false;
238  	  }
239  	
240  	  string json_string(buf_, len);
241  	  success = read(json_string, data);
242  	  if (success) {
243  	    handle_value(data);
244  	    if (data.type() != obj_type &&
245  	        data.type() != array_type) {
246  	      if (data.type() == str_type) {
247  	        val.set(data.get_str(), true);
248  	      } else {
249  	        val.set(json_spirit::write_string(data), false);
250  	      }
251  	    }
252  	  } else {
253  	    set_failure();
254  	  }
255  	
256  	  return success;
257  	}
258  	
259  	// parse the internal json_buffer up to len
260  	bool JSONParser::parse(int len)
261  	{
262  	  string json_string = json_buffer.substr(0, len);
263  	  success = read(json_string, data);
264  	  if (success)
265  	    handle_value(data);
266  	  else
267  	    set_failure();
268  	
269  	  return success;
270  	}
271  	
272  	// parse the complete internal json_buffer
273  	bool JSONParser::parse()
274  	{
275  	  success = read(json_buffer, data);
276  	  if (success)
277  	    handle_value(data);
278  	  else
279  	    set_failure();
280  	
281  	  return success;
282  	}
283  	
284  	// parse a supplied ifstream, for testing. DELETE ME
285  	bool JSONParser::parse(const char *file_name)
286  	{
287  	  ifstream is(file_name);
288  	  success = read(is, data);
289  	  if (success)
290  	    handle_value(data);
291  	  else
292  	    set_failure();
293  	
294  	  return success;
295  	}
296  	
297  	
298  	void decode_json_obj(long& val, JSONObj *obj)
299  	{
300  	  string s = obj->get_data();
301  	  const char *start = s.c_str();
302  	  char *p;
303  	
304  	  errno = 0;
305  	  val = strtol(start, &p, 10);
306  	
307  	  /* Check for various possible errors */
308  	
309  	 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
310  	     (errno != 0 && val == 0)) {
311  	   throw JSONDecoder::err("failed to parse number");
312  	 }
313  	
314  	 if (p == start) {
315  	   throw JSONDecoder::err("failed to parse number");
316  	 }
317  	
318  	 while (*p != '\0') {
319  	   if (!isspace(*p)) {
320  	     throw JSONDecoder::err("failed to parse number");
321  	   }
322  	   p++;
323  	 }
324  	}
325  	
326  	void decode_json_obj(unsigned long& val, JSONObj *obj)
327  	{
328  	  string s = obj->get_data();
329  	  const char *start = s.c_str();
330  	  char *p;
331  	
332  	  errno = 0;
333  	  val = strtoul(start, &p, 10);
334  	
335  	  /* Check for various possible errors */
336  	
337  	 if ((errno == ERANGE && val == ULONG_MAX) ||
338  	     (errno != 0 && val == 0)) {
339  	   throw JSONDecoder::err("failed to number");
340  	 }
341  	
342  	 if (p == start) {
343  	   throw JSONDecoder::err("failed to parse number");
344  	 }
345  	
346  	 while (*p != '\0') {
347  	   if (!isspace(*p)) {
348  	     throw JSONDecoder::err("failed to parse number");
349  	   }
350  	   p++;
351  	 }
352  	}
353  	
354  	void decode_json_obj(long long& val, JSONObj *obj)
355  	{
356  	  string s = obj->get_data();
357  	  const char *start = s.c_str();
358  	  char *p;
359  	
360  	  errno = 0;
361  	  val = strtoll(start, &p, 10);
362  	
363  	  /* Check for various possible errors */
364  	
365  	 if ((errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) ||
366  	     (errno != 0 && val == 0)) {
367  	   throw JSONDecoder::err("failed to parse number");
368  	 }
369  	
370  	 if (p == start) {
371  	   throw JSONDecoder::err("failed to parse number");
372  	 }
373  	
374  	 while (*p != '\0') {
375  	   if (!isspace(*p)) {
376  	     throw JSONDecoder::err("failed to parse number");
377  	   }
378  	   p++;
379  	 }
380  	}
381  	
382  	void decode_json_obj(unsigned long long& val, JSONObj *obj)
383  	{
384  	  string s = obj->get_data();
385  	  const char *start = s.c_str();
386  	  char *p;
387  	
388  	  errno = 0;
389  	  val = strtoull(start, &p, 10);
390  	
391  	  /* Check for various possible errors */
392  	
393  	 if ((errno == ERANGE && val == ULLONG_MAX) ||
394  	     (errno != 0 && val == 0)) {
395  	   throw JSONDecoder::err("failed to number");
396  	 }
397  	
398  	 if (p == start) {
399  	   throw JSONDecoder::err("failed to parse number");
400  	 }
401  	
402  	 while (*p != '\0') {
403  	   if (!isspace(*p)) {
404  	     throw JSONDecoder::err("failed to parse number");
405  	   }
406  	   p++;
407  	 }
408  	}
409  	
410  	void decode_json_obj(int& val, JSONObj *obj)
411  	{
412  	  long l;
413  	  decode_json_obj(l, obj);
414  	#if LONG_MAX > INT_MAX
415  	  if (l > INT_MAX || l < INT_MIN) {
416  	    throw JSONDecoder::err("integer out of range");
417  	  }
418  	#endif
419  	
420  	  val = (int)l;
421  	}
422  	
423  	void decode_json_obj(unsigned& val, JSONObj *obj)
424  	{
425  	  unsigned long l;
426  	  decode_json_obj(l, obj);
427  	#if ULONG_MAX > UINT_MAX
428  	  if (l > UINT_MAX) {
429  	    throw JSONDecoder::err("unsigned integer out of range");
430  	  }
431  	#endif
432  	
433  	  val = (unsigned)l;
434  	}
435  	
436  	void decode_json_obj(bool& val, JSONObj *obj)
437  	{
438  	  string s = obj->get_data();
439  	  if (strcasecmp(s.c_str(), "true") == 0) {
440  	    val = true;
441  	    return;
442  	  }
443  	  if (strcasecmp(s.c_str(), "false") == 0) {
444  	    val = false;
445  	    return;
446  	  }
447  	  int i;
448  	  decode_json_obj(i, obj);
449  	  val = (bool)i;
450  	}
451  	
452  	void decode_json_obj(bufferlist& val, JSONObj *obj)
453  	{
454  	  string s = obj->get_data();
455  	
456  	  bufferlist bl;
457  	  bl.append(s.c_str(), s.size());
458  	  try {
459  	    val.decode_base64(bl);
460  	  } catch (buffer::error& err) {
461  	   throw JSONDecoder::err("failed to decode base64");
462  	  }
463  	}
464  	
465  	void decode_json_obj(utime_t& val, JSONObj *obj)
466  	{
467  	  string s = obj->get_data();
468  	  uint64_t epoch;
469  	  uint64_t nsec;
470  	  int r = utime_t::parse_date(s, &epoch, &nsec);
471  	  if (r == 0) {
472  	    val = utime_t(epoch, nsec);
473  	  } else {
474  	    throw JSONDecoder::err("failed to decode utime_t");
475  	  }
476  	}
477  	
478  	void encode_json(const char *name, const string& val, Formatter *f)
479  	{
480  	  f->dump_string(name, val);
481  	}
482  	
483  	void encode_json(const char *name, const char *val, Formatter *f)
484  	{
485  	  f->dump_string(name, val);
486  	}
487  	
488  	void encode_json(const char *name, bool val, Formatter *f)
489  	{
490  	  string s;
491  	  if (val)
492  	    s = "true";
493  	  else
494  	    s = "false";
495  	
496  	  f->dump_string(name, s);
497  	}
498  	
499  	void encode_json(const char *name, int val, Formatter *f)
500  	{
501  	  f->dump_int(name, val);
502  	}
503  	
504  	void encode_json(const char *name, long val, Formatter *f)
505  	{
506  	  f->dump_int(name, val);
507  	}
508  	
509  	void encode_json(const char *name, unsigned val, Formatter *f)
510  	{
511  	  f->dump_unsigned(name, val);
512  	}
513  	
514  	void encode_json(const char *name, unsigned long val, Formatter *f)
515  	{
516  	  f->dump_unsigned(name, val);
517  	}
518  	
519  	void encode_json(const char *name, unsigned long long val, Formatter *f)
520  	{
521  	  f->dump_unsigned(name, val);
522  	}
523  	
524  	void encode_json(const char *name, long long val, Formatter *f)
525  	{
526  	  f->dump_int(name, val);
527  	}
528  	
529  	void encode_json(const char *name, const utime_t& val, Formatter *f)
530  	{
531  	  val.gmtime(f->dump_stream(name));
532  	}
533  	
534  	void encode_json(const char *name, const bufferlist& bl, Formatter *f)
535  	{
536  	  /* need to copy data from bl, as it is const bufferlist */
537  	  bufferlist src = bl;
538  	
539  	  bufferlist b64;
540  	  src.encode_base64(b64);
541  	
542  	  string s(b64.c_str(), b64.length());
543  	
544  	  encode_json(name, s, f);
545  	}
546  	
547  	
548  	
549  	/* JSONFormattable */
550  	
551  	const JSONFormattable& JSONFormattable::operator[](const string& name) const
552  	{
553  	  auto i = obj.find(name);
554  	  if (i == obj.end()) {
555  	    return default_formattable;
556  	  }
557  	  return i->second;
558  	}
559  	
560  	const JSONFormattable& JSONFormattable::operator[](size_t index) const
561  	{
562  	  if (index >= arr.size()) {
563  	    return default_formattable;
564  	  }
565  	  return arr[index];
566  	}
567  	
568  	JSONFormattable& JSONFormattable::operator[](const string& name)
569  	{
570  	  auto i = obj.find(name);
571  	  if (i == obj.end()) {
572  	    return default_formattable;
573  	  }
574  	  return i->second;
575  	}
576  	
577  	JSONFormattable& JSONFormattable::operator[](size_t index)
578  	{
579  	  if (index >= arr.size()) {
580  	    return default_formattable;
581  	  }
582  	  return arr[index];
583  	}
584  	
585  	bool JSONFormattable::exists(const string& name) const
586  	{
587  	  auto i = obj.find(name);
588  	  return (i != obj.end());
589  	}
590  	
591  	bool JSONFormattable::exists(size_t index) const
592  	{
593  	  return (index < arr.size());
594  	}
595  	
596  	bool JSONFormattable::find(const string& name, string *val) const
597  	{
598  	  auto i = obj.find(name);
599  	  if (i == obj.end()) {
600  	    return false;
601  	  }
602  	  *val = i->second.val();
603  	  return true;
604  	}
605  	
606  	int JSONFormattable::val_int() const {
607  	  return atoi(value.str.c_str());
608  	}
609  	
610  	long JSONFormattable::val_long() const {
611  	  return atol(value.str.c_str());
612  	}
613  	
614  	long long JSONFormattable::val_long_long() const {
615  	  return atoll(value.str.c_str());
616  	}
617  	
618  	bool JSONFormattable::val_bool() const {
619  	  return (boost::iequals(value.str, "true") ||
620  	          boost::iequals(value.str, "on") ||
621  	          boost::iequals(value.str, "yes") ||
622  	          boost::iequals(value.str, "1"));
623  	}
624  	
625  	string JSONFormattable::def(const string& def_val) const {
626  	  if (type == FMT_NONE) {
627  	    return def_val;
628  	  }
629  	  return val();
630  	}
631  	
632  	int JSONFormattable::def(int def_val) const {
633  	  if (type == FMT_NONE) {
634  	    return def_val;
635  	  }
636  	  return val_int();
637  	}
638  	
639  	bool JSONFormattable::def(bool def_val) const {
640  	  if (type == FMT_NONE) {
641  	    return def_val;
642  	  }
643  	  return val_bool();
644  	}
645  	
646  	string JSONFormattable::get(const string& name, const string& def_val) const
647  	{
648  	  return (*this)[name].def(def_val);
649  	}
650  	
651  	int JSONFormattable::get_int(const string& name, int def_val) const
652  	{
653  	  return (*this)[name].def(def_val);
654  	}
655  	
656  	bool JSONFormattable::get_bool(const string& name, bool def_val) const
657  	{
658  	  return (*this)[name].def(def_val);
659  	}
660  	
661  	struct field_entity {
662  	  bool is_obj{false}; /* either obj field or array entity */
663  	  string name; /* if obj */
664  	  int index{0}; /* if array */
665  	  bool append{false};
666  	
667  	  field_entity() {}
668  	  explicit field_entity(const string& n) : is_obj(true), name(n) {}
669  	  explicit field_entity(int i) : is_obj(false), index(i) {}
670  	};
671  	
672  	static int parse_entity(const string& s, vector<field_entity> *result)
673  	{
674  	  size_t ofs = 0;
675  	
676  	  while (ofs < s.size()) {
677  	    size_t next_arr = s.find('[', ofs);
678  	    if (next_arr == string::npos) {
679  	      if (ofs != 0) {
680  	        return -EINVAL;
681  	      }
682  	      result->push_back(field_entity(s));
683  	      return 0;
684  	    }
685  	    if (next_arr > ofs) {
686  	      string field = s.substr(ofs, next_arr - ofs);
687  	      result->push_back(field_entity(field));
(2) Event assigned_value: Assigning value from "next_arr" to "ofs" here, but that stored value is overwritten before it can be used.
Also see events: [value_overwrite]
688  	      ofs = next_arr;
689  	    }
690  	    size_t end_arr = s.find(']', next_arr + 1);
691  	    if (end_arr == string::npos) {
692  	      return -EINVAL;
693  	    }
694  	
695  	    string index_str = s.substr(next_arr + 1, end_arr - next_arr - 1);
696  	
(1) Event value_overwrite: Overwriting previous write to "ofs" with value from "end_arr + 1UL".
Also see events: [assigned_value]
697  	    ofs = end_arr + 1;
698  	
699  	    if (!index_str.empty()) {
700  	      result->push_back(field_entity(atoi(index_str.c_str())));
701  	    } else {
702  	      field_entity f;
703  	      f.append = true;
704  	      result->push_back(f);
705  	    }
706  	  }
707  	  return 0;
708  	}
709  	
710  	static bool is_numeric(const string& val)
711  	{
712  	  try {
713  	    boost::lexical_cast<double>(val);
714  	  } catch (const boost::bad_lexical_cast& e) {
715  	    return false;
716  	  }
717  	  return true;
718  	}
719  	
720  	int JSONFormattable::set(const string& name, const string& val)
721  	{
722  	  boost::escaped_list_separator<char> els('\\', '.', '"');
723  	  boost::tokenizer<boost::escaped_list_separator<char> > tok(name, els);
724  	
725  	  JSONFormattable *f = this;
726  	
727  	  JSONParser jp;
728  	
729  	  bool is_valid_json = jp.parse(val.c_str(), val.size());
730  	
731  	  for (const auto& i : tok) {
732  	    vector<field_entity> v;
733  	    int ret = parse_entity(i, &v);
734  	    if (ret < 0) {
735  	      return ret;
736  	    }
737  	    for (const auto& vi : v) {
738  	      if (f->type == FMT_NONE) {
739  	        if (vi.is_obj) {
740  	          f->type = FMT_OBJ;
741  	        } else {
742  	          f->type = FMT_ARRAY;
743  	        }
744  	      }
745  	
746  	      if (f->type == FMT_OBJ) {
747  	        if (!vi.is_obj) {
748  	          return -EINVAL;
749  	        }
750  	        f = &f->obj[vi.name];
751  	      } else if (f->type == FMT_ARRAY) {
752  	        if (vi.is_obj) {
753  	          return -EINVAL;
754  	        }
755  	        int index = vi.index;
756  	        if (vi.append) {
757  	          index = f->arr.size();
758  	        } else if (index < 0) {
759  	          index = f->arr.size() + index;
760  	          if (index < 0) {
761  	            return -EINVAL; /* out of bounds */
762  	          }
763  	        }
764  	        if ((size_t)index >= f->arr.size()) {
765  	          f->arr.resize(index + 1);
766  	        }
767  	        f = &f->arr[index];
768  	      }
769  	    }
770  	  }
771  	
772  	  if (is_valid_json) {
773  	    f->decode_json(&jp);
774  	  } else {
775  	    f->type = FMT_VALUE;
776  	    f->value.set(val, !is_numeric(val));
777  	  }
778  	
779  	  return 0;
780  	}
781  	
782  	int JSONFormattable::erase(const string& name)
783  	{
784  	  boost::escaped_list_separator<char> els('\\', '.', '"');
785  	  boost::tokenizer<boost::escaped_list_separator<char> > tok(name, els);
786  	
787  	  JSONFormattable *f = this;
788  	  JSONFormattable *parent = nullptr;
789  	  field_entity last_entity;
790  	
791  	  for (auto& i : tok) {
792  	    vector<field_entity> v;
793  	    int ret = parse_entity(i, &v);
794  	    if (ret < 0) {
795  	      return ret;
796  	    }
797  	    for (const auto& vi : v) {
798  	      if (f->type == FMT_NONE ||
799  	          f->type == FMT_VALUE) {
800  	        if (vi.is_obj) {
801  	          f->type = FMT_OBJ;
802  	        } else {
803  	          f->type = FMT_ARRAY;
804  	        }
805  	      }
806  	
807  	      parent = f;
808  	
809  	      if (f->type == FMT_OBJ) {
810  	        if (!vi.is_obj) {
811  	          return -EINVAL;
812  	        }
813  	        auto iter = f->obj.find(vi.name);
814  	        if (iter == f->obj.end()) {
815  	          return 0; /* nothing to erase */
816  	        }
817  	        f = &iter->second;
818  	      } else if (f->type == FMT_ARRAY) {
819  	        if (vi.is_obj) {
820  	          return -EINVAL;
821  	        }
822  	        int index = vi.index;
823  	        if (index < 0) {
824  	          index = f->arr.size() + index;
825  	          if (index < 0) { /* out of bounds, nothing to remove */
826  	            return 0;
827  	          }
828  	        }
829  	        if ((size_t)index >= f->arr.size()) {
830  	          return 0; /* index beyond array boundaries */
831  	        }
832  	        f = &f->arr[index];
833  	      }
834  	      last_entity = vi;
835  	    }
836  	  }
837  	
838  	  if (!parent) {
839  	    *this = JSONFormattable(); /* erase everything */
840  	  } else {
841  	    if (last_entity.is_obj) {
842  	      parent->obj.erase(last_entity.name);
843  	    } else {
844  	      int index = (last_entity.index >= 0 ? last_entity.index : parent->arr.size() + last_entity.index);
845  	      if (index < 0 || (size_t)index >= parent->arr.size()) {
846  	        return 0;
847  	      }
848  	      parent->arr.erase(parent->arr.begin() + index);
849  	    }
850  	  }
851  	
852  	  return 0;
853  	}
854  	
855  	void JSONFormattable::derive_from(const JSONFormattable& parent)
856  	{
857  	  for (auto& o : parent.obj) {
858  	    if (obj.find(o.first) == obj.end()) {
859  	      obj[o.first] = o.second;
860  	    }
861  	  }
862  	}
863  	
864  	void encode_json(const char *name, const JSONFormattable& v, Formatter *f)
865  	{
866  	  v.encode_json(name, f);
867  	}
868  	
869  	void JSONFormattable::encode_json(const char *name, Formatter *f) const
870  	{
871  	  switch (type) {
872  	    case JSONFormattable::FMT_VALUE:
873  	      ::encode_json(name, value, f);
874  	      break;
875  	    case JSONFormattable::FMT_ARRAY:
876  	      ::encode_json(name, arr, f);
877  	      break;
878  	    case JSONFormattable::FMT_OBJ:
879  	      f->open_object_section(name);
880  	      for (auto iter : obj) {
881  	        ::encode_json(iter.first.c_str(), iter.second, f);
882  	      }
883  	      f->close_section();
884  	      break;
885  	    case JSONFormattable::FMT_NONE:
886  	      break;
887  	  }
888  	}
889  	
890  	bool JSONFormattable::handle_value(const char *name, std::string_view s, bool quoted) {
891  	  JSONFormattable *new_val;
892  	  if (cur_enc->is_array()) {
893  	    cur_enc->arr.push_back(JSONFormattable());
894  	    new_val = &cur_enc->arr.back();
895  	  } else {
896  	    cur_enc->set_type(JSONFormattable::FMT_OBJ);
897  	    new_val  = &cur_enc->obj[name];
898  	  }
899  	  new_val->set_type(JSONFormattable::FMT_VALUE);
900  	  new_val->value.set(s, quoted);
901  	
902  	  return false;
903  	}
904  	bool JSONFormattable::handle_open_section(const char *name, const char *ns, bool section_is_array) {
905  	  if (cur_enc->is_array()) {
906  	    cur_enc->arr.push_back(JSONFormattable());
907  	    cur_enc = &cur_enc->arr.back();
908  	  } else if (enc_stack.size() > 1) {
909  	      /* only open a new section if already nested,
910  	       * otherwise root is the container
911  	       */
912  	      cur_enc = &cur_enc->obj[name];
913  	  }
914  	  enc_stack.push_back(cur_enc);
915  	
916  	  if (section_is_array) {
917  	    cur_enc->set_type(JSONFormattable::FMT_ARRAY);
918  	  } else {
919  	    cur_enc->set_type(JSONFormattable::FMT_OBJ);
920  	  }
921  	
922  	  return false; /* continue processing */
923  	}
924  	
925  	bool JSONFormattable::handle_close_section() {
926  	  if (enc_stack.size() <= 1) {
927  	    return false;
928  	  }
929  	
930  	  enc_stack.pop_back();
931  	  cur_enc = enc_stack.back();
932  	  return false; /* continue processing */
933  	}
934  	
935