write.hpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. #ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
  11. #define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
  12. #include <boost/property_tree/ptree.hpp>
  13. #include <boost/next_prior.hpp>
  14. #include <boost/type_traits/make_unsigned.hpp>
  15. #include <string>
  16. #include <ostream>
  17. #include <iomanip>
  18. namespace boost { namespace property_tree { namespace json_parser
  19. {
  20. // Create necessary escape sequences from illegal characters
  21. template<class Ch>
  22. std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s)
  23. {
  24. std::basic_string<Ch> result;
  25. typename std::basic_string<Ch>::const_iterator b = s.begin();
  26. typename std::basic_string<Ch>::const_iterator e = s.end();
  27. while (b != e)
  28. {
  29. typedef typename make_unsigned<Ch>::type UCh;
  30. UCh c(*b);
  31. // This assumes an ASCII superset. But so does everything in PTree.
  32. // We escape everything outside ASCII, because this code can't
  33. // handle high unicode characters.
  34. if (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x2E) ||
  35. (c >= 0x30 && c <= 0x5B) || (c >= 0x5D && c <= 0xFF))
  36. result += *b;
  37. else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b');
  38. else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f');
  39. else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n');
  40. else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r');
  41. else if (*b == Ch('\t')) result += Ch('\\'), result += Ch('t');
  42. else if (*b == Ch('/')) result += Ch('\\'), result += Ch('/');
  43. else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
  44. else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\');
  45. else
  46. {
  47. const char *hexdigits = "0123456789ABCDEF";
  48. unsigned long u = (std::min)(static_cast<unsigned long>(
  49. static_cast<UCh>(*b)),
  50. 0xFFFFul);
  51. unsigned long d1 = u / 4096; u -= d1 * 4096;
  52. unsigned long d2 = u / 256; u -= d2 * 256;
  53. unsigned long d3 = u / 16; u -= d3 * 16;
  54. unsigned long d4 = u;
  55. result += Ch('\\'); result += Ch('u');
  56. result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
  57. result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
  58. }
  59. ++b;
  60. }
  61. return result;
  62. }
  63. template<class Ptree>
  64. void write_json_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
  65. const Ptree &pt,
  66. int indent, bool pretty)
  67. {
  68. typedef typename Ptree::key_type::value_type Ch;
  69. typedef typename std::basic_string<Ch> Str;
  70. // Value or object or array
  71. if (indent > 0 && pt.empty())
  72. {
  73. // Write value
  74. Str data = create_escapes(pt.template get_value<Str>());
  75. stream << Ch('"') << data << Ch('"');
  76. }
  77. else if (indent > 0 && pt.count(Str()) == pt.size())
  78. {
  79. // Write array
  80. stream << Ch('[');
  81. if (pretty) stream << Ch('\n');
  82. typename Ptree::const_iterator it = pt.begin();
  83. for (; it != pt.end(); ++it)
  84. {
  85. if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
  86. write_json_helper(stream, it->second, indent + 1, pretty);
  87. if (boost::next(it) != pt.end())
  88. stream << Ch(',');
  89. if (pretty) stream << Ch('\n');
  90. }
  91. if (pretty) stream << Str(4 * indent, Ch(' '));
  92. stream << Ch(']');
  93. }
  94. else
  95. {
  96. // Write object
  97. stream << Ch('{');
  98. if (pretty) stream << Ch('\n');
  99. typename Ptree::const_iterator it = pt.begin();
  100. for (; it != pt.end(); ++it)
  101. {
  102. if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
  103. stream << Ch('"') << create_escapes(it->first) << Ch('"') << Ch(':');
  104. if (pretty) stream << Ch(' ');
  105. write_json_helper(stream, it->second, indent + 1, pretty);
  106. if (boost::next(it) != pt.end())
  107. stream << Ch(',');
  108. if (pretty) stream << Ch('\n');
  109. }
  110. if (pretty) stream << Str(4 * indent, Ch(' '));
  111. stream << Ch('}');
  112. }
  113. }
  114. // Verify if ptree does not contain information that cannot be written to json
  115. template<class Ptree>
  116. bool verify_json(const Ptree &pt, int depth)
  117. {
  118. typedef typename Ptree::key_type::value_type Ch;
  119. typedef typename std::basic_string<Ch> Str;
  120. // Root ptree cannot have data
  121. if (depth == 0 && !pt.template get_value<Str>().empty())
  122. return false;
  123. // Ptree cannot have both children and data
  124. if (!pt.template get_value<Str>().empty() && !pt.empty())
  125. return false;
  126. // Check children
  127. typename Ptree::const_iterator it = pt.begin();
  128. for (; it != pt.end(); ++it)
  129. if (!verify_json(it->second, depth + 1))
  130. return false;
  131. // Success
  132. return true;
  133. }
  134. // Write ptree to json stream
  135. template<class Ptree>
  136. void write_json_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
  137. const Ptree &pt,
  138. const std::string &filename,
  139. bool pretty)
  140. {
  141. if (!verify_json(pt, 0))
  142. BOOST_PROPERTY_TREE_THROW(json_parser_error("ptree contains data that cannot be represented in JSON format", filename, 0));
  143. write_json_helper(stream, pt, 0, pretty);
  144. stream << std::endl;
  145. if (!stream.good())
  146. BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0));
  147. }
  148. } } }
  149. #endif