]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_STANDARD_CALLBACKS_HPP |
2 | #define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_STANDARD_CALLBACKS_HPP | |
3 | ||
4 | #include <boost/assert.hpp> | |
5 | #include <boost/property_tree/ptree.hpp> | |
6 | #include <vector> | |
7 | ||
8 | namespace boost { namespace property_tree { | |
9 | namespace json_parser { namespace detail | |
10 | { | |
11 | ||
12 | namespace constants | |
13 | { | |
14 | template <typename Ch> const Ch* null_value(); | |
15 | template <> inline const char* null_value() { return "null"; } | |
16 | template <> inline const wchar_t* null_value() { return L"null"; } | |
17 | ||
18 | template <typename Ch> const Ch* true_value(); | |
19 | template <> inline const char* true_value() { return "true"; } | |
20 | template <> inline const wchar_t* true_value() { return L"true"; } | |
21 | ||
22 | template <typename Ch> const Ch* false_value(); | |
23 | template <> inline const char* false_value() { return "false"; } | |
24 | template <> inline const wchar_t* false_value() { return L"false"; } | |
25 | } | |
26 | ||
27 | template <typename Ptree> | |
28 | class standard_callbacks { | |
29 | public: | |
30 | typedef typename Ptree::data_type string; | |
31 | typedef typename string::value_type char_type; | |
32 | ||
33 | void on_null() { | |
34 | new_value() = constants::null_value<char_type>(); | |
35 | } | |
36 | ||
37 | void on_boolean(bool b) { | |
38 | new_value() = b ? constants::true_value<char_type>() | |
39 | : constants::false_value<char_type>(); | |
40 | } | |
41 | ||
42 | template <typename Range> | |
43 | void on_number(Range code_units) { | |
44 | new_value().assign(code_units.begin(), code_units.end()); | |
45 | } | |
46 | void on_begin_number() { | |
47 | new_value(); | |
48 | } | |
49 | void on_digit(char_type d) { | |
50 | current_value() += d; | |
51 | } | |
52 | void on_end_number() {} | |
53 | ||
54 | void on_begin_string() { | |
55 | new_value(); | |
56 | } | |
57 | template <typename Range> | |
58 | void on_code_units(Range code_units) { | |
59 | current_value().append(code_units.begin(), code_units.end()); | |
60 | } | |
61 | void on_code_unit(char_type c) { | |
62 | current_value() += c; | |
63 | } | |
64 | void on_end_string() {} | |
65 | ||
66 | void on_begin_array() { | |
67 | new_tree(); | |
68 | stack.back().k = array; | |
69 | } | |
70 | void on_end_array() { | |
71 | if (stack.back().k == leaf) stack.pop_back(); | |
72 | stack.pop_back(); | |
73 | } | |
74 | ||
75 | void on_begin_object() { | |
76 | new_tree(); | |
77 | stack.back().k = object; | |
78 | } | |
79 | void on_end_object() { | |
80 | if (stack.back().k == leaf) stack.pop_back(); | |
81 | stack.pop_back(); | |
82 | } | |
83 | ||
84 | Ptree& output() { return root; } | |
85 | ||
86 | protected: | |
87 | bool is_key() const { | |
88 | return stack.back().k == key; | |
89 | } | |
90 | string& current_value() { | |
91 | layer& l = stack.back(); | |
92 | switch (l.k) { | |
93 | case key: return key_buffer; | |
94 | default: return l.t->data(); | |
95 | } | |
96 | } | |
97 | ||
98 | private: | |
99 | Ptree root; | |
100 | string key_buffer; | |
101 | enum kind { array, object, key, leaf }; | |
102 | struct layer { kind k; Ptree* t; }; | |
103 | std::vector<layer> stack; | |
104 | ||
105 | Ptree& new_tree() { | |
106 | if (stack.empty()) { | |
107 | layer l = {leaf, &root}; | |
108 | stack.push_back(l); | |
109 | return root; | |
110 | } | |
111 | layer& l = stack.back(); | |
112 | switch (l.k) { | |
113 | case array: { | |
114 | l.t->push_back(std::make_pair(string(), Ptree())); | |
115 | layer nl = {leaf, &l.t->back().second}; | |
116 | stack.push_back(nl); | |
117 | return *stack.back().t; | |
118 | } | |
119 | case object: | |
120 | default: | |
121 | BOOST_ASSERT(false); // must start with string, i.e. call new_value | |
122 | case key: { | |
123 | l.t->push_back(std::make_pair(key_buffer, Ptree())); | |
124 | l.k = object; | |
125 | layer nl = {leaf, &l.t->back().second}; | |
126 | stack.push_back(nl); | |
127 | return *stack.back().t; | |
128 | } | |
129 | case leaf: | |
130 | stack.pop_back(); | |
131 | return new_tree(); | |
132 | } | |
133 | } | |
134 | string& new_value() { | |
135 | if (stack.empty()) return new_tree().data(); | |
136 | layer& l = stack.back(); | |
137 | switch (l.k) { | |
138 | case leaf: | |
139 | stack.pop_back(); | |
140 | return new_value(); | |
141 | case object: | |
142 | l.k = key; | |
143 | key_buffer.clear(); | |
144 | return key_buffer; | |
145 | default: | |
146 | return new_tree().data(); | |
147 | } | |
148 | } | |
149 | }; | |
150 | ||
151 | }}}} | |
152 | ||
153 | #endif |