1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2002-2006 Marcin Kalicinski
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)
8 // For more information, see www.boost.org
9 // ----------------------------------------------------------------------------
10 #ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_READ_HPP_INCLUDED
11 #define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_READ_HPP_INCLUDED
13 //#define BOOST_SPIRIT_DEBUG
15 #include <boost/property_tree/ptree.hpp>
16 #include <boost/property_tree/detail/ptree_utils.hpp>
17 #include <boost/property_tree/detail/json_parser_error.hpp>
18 #include <boost/spirit.hpp>
19 #include <boost/limits.hpp>
26 namespace boost
{ namespace property_tree
{ namespace json_parser
29 ///////////////////////////////////////////////////////////////////////
30 // Json parser context
36 typedef typename
Ptree::key_type::value_type Ch
;
37 typedef std::basic_string
<Ch
> Str
;
38 typedef typename
std::vector
<Ch
>::iterator It
;
43 std::vector
<Ptree
*> stack
;
48 a_object_s(context
&c
): c(c
) { }
49 void operator()(Ch
) const
52 c
.stack
.push_back(&c
.root
);
55 Ptree
*parent
= c
.stack
.back();
56 Ptree
*child
= &parent
->push_back(std::make_pair(c
.name
, Ptree()))->second
;
57 c
.stack
.push_back(child
);
66 a_object_e(context
&c
): c(c
) { }
67 void operator()(Ch
) const
69 BOOST_ASSERT(c
.stack
.size() >= 1);
77 a_name(context
&c
): c(c
) { }
78 void operator()(It
, It
) const
80 c
.name
.swap(c
.string
);
88 a_string_val(context
&c
): c(c
) { }
89 void operator()(It
, It
) const
91 BOOST_ASSERT(c
.stack
.size() >= 1);
92 c
.stack
.back()->push_back(std::make_pair(c
.name
, Ptree(c
.string
)));
101 a_literal_val(context
&c
): c(c
) { }
102 void operator()(It b
, It e
) const
104 BOOST_ASSERT(c
.stack
.size() >= 1);
105 c
.stack
.back()->push_back(std::make_pair(c
.name
, Str(b
, e
)));
114 a_char(context
&c
): c(c
) { }
115 void operator()(It b
, It e
) const
124 a_escape(context
&c
): c(c
) { }
125 void operator()(Ch ch
) const
129 case Ch('\"'): c
.string
+= Ch('\"'); break;
130 case Ch('\\'): c
.string
+= Ch('\\'); break;
131 case Ch('0'): c
.string
+= Ch('\0'); break;
132 case Ch('b'): c
.string
+= Ch('\b'); break;
133 case Ch('f'): c
.string
+= Ch('\f'); break;
134 case Ch('n'): c
.string
+= Ch('\n'); break;
135 case Ch('r'): c
.string
+= Ch('\r'); break;
136 case Ch('t'): c
.string
+= Ch('\t'); break;
137 default: BOOST_ASSERT(0);
145 a_unicode(context
&c
): c(c
) { }
146 void operator()(unsigned long u
) const
148 u
= (std::min
)(u
, static_cast<unsigned long>((std::numeric_limits
<Ch
>::max
)()));
155 ///////////////////////////////////////////////////////////////////////
158 template<class Ptree
>
159 struct json_grammar
: public boost::spirit::grammar
<json_grammar
<Ptree
> >
162 typedef context
<Ptree
> Context
;
163 typedef typename
Ptree::key_type::value_type Ch
;
167 template<class Scanner
>
171 boost::spirit::rule
<Scanner
> root
, object
, member
, array
, item
, value
, string
, number
;
172 boost::spirit::rule
<typename
boost::spirit::lexeme_scanner
<Scanner
>::type
> character
, escape
;
174 definition(const json_grammar
&self
)
177 using namespace boost::spirit
;
180 assertion
<std::string
> expect_object("expected object");
181 assertion
<std::string
> expect_eoi("expected end of input");
182 assertion
<std::string
> expect_objclose("expected ',' or '}'");
183 assertion
<std::string
> expect_arrclose("expected ',' or ']'");
184 assertion
<std::string
> expect_name("expected object name");
185 assertion
<std::string
> expect_colon("expected ':'");
186 assertion
<std::string
> expect_value("expected value");
187 assertion
<std::string
> expect_escape("invalid escape sequence");
189 // JSON grammar rules
191 = expect_object(object
)
196 = ch_p('{')[typename
Context::a_object_s(self
.c
)]
197 >> (ch_p('}')[typename
Context::a_object_e(self
.c
)]
198 | (list_p(member
, ch_p(','))
199 >> expect_objclose(ch_p('}')[typename
Context::a_object_e(self
.c
)])
205 = expect_name(string
[typename
Context::a_name(self
.c
)])
206 >> expect_colon(ch_p(':'))
207 >> expect_value(value
)
211 = ch_p('[')[typename
Context::a_object_s(self
.c
)]
212 >> (ch_p(']')[typename
Context::a_object_e(self
.c
)]
213 | (list_p(item
, ch_p(','))
214 >> expect_arrclose(ch_p(']')[typename
Context::a_object_e(self
.c
)])
220 = expect_value(value
)
224 = string
[typename
Context::a_string_val(self
.c
)]
225 | (number
| str_p("true") | "false" | "null")[typename
Context::a_literal_val(self
.c
)]
236 = +(lexeme_d
[confix_p('\"', *character
, '\"')])
240 = (anychar_p
- "\\" - "\"")[typename
Context::a_char(self
.c
)]
241 | ch_p("\\") >> expect_escape(escape
)
245 = chset_p(detail::widen
<Ch
>("\"\\0bfnrt").c_str())[typename
Context::a_escape(self
.c
)]
246 | 'u' >> uint_parser
<unsigned long, 16, 4, 4>()[typename
Context::a_unicode(self
.c
)]
250 BOOST_SPIRIT_DEBUG_RULE(root
);
251 BOOST_SPIRIT_DEBUG_RULE(object
);
252 BOOST_SPIRIT_DEBUG_RULE(member
);
253 BOOST_SPIRIT_DEBUG_RULE(array
);
254 BOOST_SPIRIT_DEBUG_RULE(item
);
255 BOOST_SPIRIT_DEBUG_RULE(value
);
256 BOOST_SPIRIT_DEBUG_RULE(string
);
257 BOOST_SPIRIT_DEBUG_RULE(number
);
258 BOOST_SPIRIT_DEBUG_RULE(escape
);
259 BOOST_SPIRIT_DEBUG_RULE(character
);
263 const boost::spirit::rule
<Scanner
> &start() const
272 template<class It
, class Ch
>
273 unsigned long count_lines(It begin
, It end
)
275 return static_cast<unsigned long>(std::count(begin
, end
, Ch('\n')) + 1);
278 template<class Ptree
>
279 void read_json_internal(std::basic_istream
<typename
Ptree::key_type::value_type
> &stream
,
281 const std::string
&filename
)
284 using namespace boost::spirit
;
285 typedef typename
Ptree::key_type::value_type Ch
;
286 typedef typename
std::vector
<Ch
>::iterator It
;
288 // Load data into vector
289 std::vector
<Ch
> v(std::istreambuf_iterator
<Ch
>(stream
.rdbuf()),
290 std::istreambuf_iterator
<Ch
>());
292 BOOST_PROPERTY_TREE_THROW(json_parser_error("read error", filename
, 0));
295 json_grammar
<Ptree
> g
;
300 parse_info
<It
> pi
= parse(v
.begin(), v
.end(), g
,
301 space_p
| comment_p("//") | comment_p("/*", "*/"));
302 if (!pi
.hit
|| !pi
.full
)
303 BOOST_PROPERTY_TREE_THROW((parser_error
<std::string
, It
>(v
.begin(), "syntax error")));
305 catch (parser_error
<std::string
, It
> &e
)
307 BOOST_PROPERTY_TREE_THROW(json_parser_error(e
.descriptor
, filename
, count_lines
<It
, Ch
>(v
.begin(), e
.where
)));
310 // Swap grammar context root and pt