3D Repo Bouncer  1.4
json_parser_write.h
1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2002-2006 Marcin Kalicinski
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // For more information, see www.boost.org
9 // ----------------------------------------------------------------------------
10 
11 //This is a modified version of json_parser_write.h from boost v1_58 for the purpose
12 //of achieving a json writer that conforms to json standards (i.e. type enforcement)
13 //Altered for the purpose of 3D Repo Bouncer, not designed to work in a general case
14 //see http://stackoverflow.com/questions/2855741/why-boost-property-tree-write-json-saves-everything-as-string-is-it-possible-to
15 
16 #ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
17 #define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
18 
19 #include <boost/property_tree/ptree.hpp>
20 #include <boost/next_prior.hpp>
21 #include <boost/type_traits/make_unsigned.hpp>
22 #include <string>
23 #include <ostream>
24 #include <iomanip>
25 
26 namespace boost {
27  namespace property_tree {
28  namespace json_parser
29  {
30  // Create necessary escape sequences from illegal characters
31  template<class Ch>
32  std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s)
33  {
34  std::basic_string<Ch> result;
35  typename std::basic_string<Ch>::const_iterator b = s.begin();
36  typename std::basic_string<Ch>::const_iterator e = s.end();
37  while (b != e)
38  {
39  typedef typename make_unsigned<Ch>::type UCh;
40  UCh c(*b);
41  // This assumes an ASCII superset. But so does everything in PTree.
42  // We escape everything outside ASCII, because this code can't
43  // handle high unicode characters.
44  if (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x2E) ||
45  (c >= 0x30 && c <= 0x5B) || (c >= 0x5D && c <= 0xFF) || *b == Ch('"'))
46  result += *b;
47  else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b');
48  else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f');
49  else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n');
50  else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r');
51  else if (*b == Ch('\t')) result += Ch('\\'), result += Ch('t');
52  else if (*b == Ch('/')) result += Ch('\\'), result += Ch('/');
53  //else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
54  else if (*b == Ch('\\')) result += Ch('\\')/*, result += Ch('\\')*/;
55  else
56  {
57  const char *hexdigits = "0123456789ABCDEF";
58  unsigned long u = (std::min)(static_cast<unsigned long>(
59  static_cast<UCh>(*b)),
60  0xFFFFul);
61  int d1 = u / 4096; u -= d1 * 4096;
62  int d2 = u / 256; u -= d2 * 256;
63  int d3 = u / 16; u -= d3 * 16;
64  int d4 = u;
65  result += Ch('\\'); result += Ch('u');
66  result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
67  result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
68  }
69  ++b;
70  }
71  return result;
72  }
73 
74  template<class Ptree>
75  void write_json_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
76  const Ptree &pt,
77  int indent, bool pretty)
78  {
79  typedef typename Ptree::key_type::value_type Ch;
80  typedef typename std::basic_string<Ch> Str;
81 
82  // Value or object or array
83  if (indent > 0 && pt.empty())
84  {
85  // Write value
86  Str data = create_escapes(pt.template get_value<Str>());
87  //stream << Ch('"') << data << Ch('"');
88  stream << data;
89  }
90  else if (indent > 0 && pt.count(Str()) == pt.size())
91  {
92  // Write array
93  stream << Ch('[');
94  if (pretty) stream << Ch('\n');
95  typename Ptree::const_iterator it = pt.begin();
96  for (; it != pt.end(); ++it)
97  {
98  if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
99  write_json_helper(stream, it->second, indent + 1, pretty);
100  if (boost::next(it) != pt.end())
101  stream << Ch(',');
102  if (pretty) stream << Ch('\n');
103  }
104  if (pretty) stream << Str(4 * indent, Ch(' '));
105  stream << Ch(']');
106  }
107  else
108  {
109  // Write object
110  stream << Ch('{');
111  if (pretty) stream << Ch('\n');
112  typename Ptree::const_iterator it = pt.begin();
113  for (; it != pt.end(); ++it)
114  {
115  if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
116  stream << Ch('"') << create_escapes(it->first) << Ch('"') << Ch(':');
117  if (pretty) stream << Ch(' ');
118  write_json_helper(stream, it->second, indent + 1, pretty);
119  if (boost::next(it) != pt.end())
120  stream << Ch(',');
121  if (pretty) stream << Ch('\n');
122  }
123  if (pretty) stream << Str(4 * indent, Ch(' '));
124  stream << Ch('}');
125  }
126  }
127 
128  // Verify if ptree does not contain information that cannot be written to json
129  template<class Ptree>
130  bool verify_json(const Ptree &pt, int depth)
131  {
132  typedef typename Ptree::key_type::value_type Ch;
133  typedef typename std::basic_string<Ch> Str;
134 
135  // Root ptree cannot have data
136  if (depth == 0 && !pt.template get_value<Str>().empty())
137  return false;
138 
139  // Ptree cannot have both children and data
140  if (!pt.template get_value<Str>().empty() && !pt.empty())
141  return false;
142 
143  // Check children
144  typename Ptree::const_iterator it = pt.begin();
145  for (; it != pt.end(); ++it)
146  if (!verify_json(it->second, depth + 1))
147  return false;
148 
149  // Success
150  return true;
151  }
152 
153  // Write ptree to json stream
154  template<class Ptree>
155  void write_json_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
156  const Ptree &pt,
157  const std::string &filename,
158  bool pretty)
159  {
160  if (!verify_json(pt, 0))
161  BOOST_PROPERTY_TREE_THROW(json_parser_error("ptree contains data that cannot be represented in JSON format", filename, 0));
162  write_json_helper(stream, pt, 0, pretty);
163  stream << std::endl;
164  if (!stream.good())
165  BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0));
166  }
167  }
168  }
169 }
170 
171 #endif
Definition: json_parser.h:30