2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
19 * Author: Helge Norberg, helge.norberg@svt.se
28 #include <boost/property_tree/ptree.hpp>
29 #include <boost/algorithm/string/replace.hpp>
30 #include <boost/range/adaptor/transformed.hpp>
31 #include <boost/iterator/iterator_facade.hpp>
37 struct ptree_exception : virtual user_error { };
39 static std::string to_xpath(std::string path)
41 path.insert(path.begin(), '/');
42 boost::replace_all(path, "<xmlattr>.", "@");
43 boost::replace_all(path, ".", "/");
47 template <typename T, typename Ptree>
48 T ptree_get(const Ptree& ptree, const typename Ptree::key_type& path)
52 return ptree.template get<T>(path);
54 catch (boost::property_tree::ptree_bad_path&)
56 CASPAR_THROW_EXCEPTION(ptree_exception() << msg_info("No such element: " + to_xpath(u8(path))));
58 catch (const boost::property_tree::ptree_bad_data& e)
60 CASPAR_SCOPED_CONTEXT_MSG(to_xpath(u8(path)))
61 CASPAR_THROW_EXCEPTION(ptree_exception() << msg_info(e.what()));
65 template <typename T, typename Ptree>
66 T ptree_get_value(const Ptree& ptree)
70 return ptree.template get_value<T>();
72 catch (const boost::property_tree::ptree_bad_data& e)
74 CASPAR_THROW_EXCEPTION(ptree_exception() << msg_info(e.what()));
78 template <typename Ptree>
79 const Ptree& ptree_get_child(const Ptree& ptree, const typename Ptree::key_type& path)
83 return ptree.get_child(path);
85 catch (boost::property_tree::ptree_bad_path&)
87 CASPAR_THROW_EXCEPTION(ptree_exception() << msg_info("No such element: " + to_xpath(u8(path))));
91 template <typename Ptree>
92 class scope_aware_ptree_child_range
95 spl::shared_ptr<scoped_context> ctx_;
97 typedef std::pair<const typename Ptree::key_type, Ptree> type;
99 class scoped_const_iterator : public boost::iterator_facade<scoped_const_iterator, type const, boost::forward_traversal_tag>
101 spl::shared_ptr<scoped_context> ctx_;
102 typename Ptree::const_iterator wrapped_;
104 scoped_const_iterator(spl::shared_ptr<scoped_context> ctx, typename Ptree::const_iterator it)
105 : ctx_(std::move(ctx))
106 , wrapped_(std::move(it))
115 bool equal(const scoped_const_iterator& other) const
117 return wrapped_ == other.wrapped_;
120 const type& dereference() const
126 typedef scoped_const_iterator iterator;
127 typedef scoped_const_iterator const_iterator;
129 scope_aware_ptree_child_range(const Ptree& parent, const typename Ptree::key_type& path)
130 : child_(ptree_get_child(parent, path))
131 , ctx_(spl::make_shared<scoped_context>(to_xpath(u8(path))))
135 scoped_const_iterator begin() const
137 return scoped_const_iterator(ctx_, child_.begin());
140 scoped_const_iterator end() const
142 return scoped_const_iterator(ctx_, child_.end());
146 template <typename Key>
147 struct iterate_children_tag
151 iterate_children_tag(Key val_)
152 : val(std::move(val_))
157 typedef iterate_children_tag<std::wstring> witerate_children;
158 typedef iterate_children_tag<std::string> iterate_children;
160 template <typename Ptree>
161 scope_aware_ptree_child_range<Ptree> operator|(const Ptree& ptree, iterate_children_tag<typename Ptree::key_type> path)
163 return scope_aware_ptree_child_range<Ptree>(ptree, path.val);
166 template<typename Ptree>
167 struct basic_scoped_element_translator
169 mutable std::shared_ptr<scoped_context> ctx;
170 mutable std::map<typename Ptree::key_type, int> by_name;
172 typedef const std::pair<const typename Ptree::key_type, Ptree>& result_type;
174 result_type operator()(result_type pair) const
177 ctx.reset(new scoped_context);
179 ctx->replace_msg("/" + u8(pair.first) + "[" + std::to_string(++by_name[pair.first]) + "]");
184 template <typename Ptree> struct element_context_iteration_tag { };
185 static element_context_iteration_tag<typename boost::property_tree::wptree> welement_context_iteration;
186 static element_context_iteration_tag<typename boost::property_tree::ptree> element_context_iteration;
188 template <typename Range, typename Ptree>
189 auto operator|(const Range& rng, element_context_iteration_tag<Ptree> tag) -> decltype(rng | boost::adaptors::transformed(basic_scoped_element_translator<Ptree>()))
191 return rng | boost::adaptors::transformed(basic_scoped_element_translator<Ptree>());
194 template <typename Key, typename Ptree, typename Str>
195 void ptree_verify_element_name(const std::pair<const Key, Ptree>& elem, const Str& expected)
197 if (elem.first != expected)
198 CASPAR_THROW_EXCEPTION(ptree_exception() << msg_info("Expected element named " + u8(expected) + ". Was " + u8(elem.first)));