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/lexical_cast.hpp>
32 #include <boost/iterator/iterator_facade.hpp>
38 struct ptree_exception : virtual user_error { };
40 static std::string to_xpath(std::string path)
42 path.insert(path.begin(), '/');
43 boost::replace_all(path, "<xmlattr>.", "@");
44 boost::replace_all(path, ".", "/");
48 template <typename T, typename Ptree>
49 T ptree_get(const Ptree& ptree, const typename Ptree::key_type& path)
53 return ptree.template get<T>(path);
55 catch (boost::property_tree::ptree_bad_path&)
57 CASPAR_THROW_EXCEPTION(ptree_exception() << msg_info("No such element: " + to_xpath(u8(path))));
59 catch (const boost::property_tree::ptree_bad_data& e)
61 CASPAR_SCOPED_CONTEXT_MSG(to_xpath(u8(path)))
62 CASPAR_THROW_EXCEPTION(ptree_exception() << msg_info(e.what()));
66 template <typename T, typename Ptree>
67 T ptree_get_value(const Ptree& ptree)
71 return ptree.template get_value<T>();
73 catch (const boost::property_tree::ptree_bad_data& e)
75 CASPAR_THROW_EXCEPTION(ptree_exception() << msg_info(e.what()));
79 template <typename Ptree>
80 const Ptree& ptree_get_child(const Ptree& ptree, const typename Ptree::key_type& path)
84 return ptree.get_child(path);
86 catch (boost::property_tree::ptree_bad_path&)
88 CASPAR_THROW_EXCEPTION(ptree_exception() << msg_info("No such element: " + to_xpath(u8(path))));
92 template <typename Ptree>
93 class scope_aware_ptree_child_range
96 spl::shared_ptr<scoped_context> ctx_;
98 typedef std::pair<const typename Ptree::key_type, Ptree> type;
100 class scoped_const_iterator : public boost::iterator_facade<scoped_const_iterator, type const, boost::forward_traversal_tag>
102 spl::shared_ptr<scoped_context> ctx_;
103 typename Ptree::const_iterator wrapped_;
105 scoped_const_iterator(spl::shared_ptr<scoped_context> ctx, typename Ptree::const_iterator it)
106 : ctx_(std::move(ctx))
107 , wrapped_(std::move(it))
116 bool equal(const scoped_const_iterator& other) const
118 return wrapped_ == other.wrapped_;
121 const type& dereference() const
127 typedef scoped_const_iterator iterator;
128 typedef scoped_const_iterator const_iterator;
130 scope_aware_ptree_child_range(const Ptree& parent, const typename Ptree::key_type& path)
131 : child_(ptree_get_child(parent, path))
132 , ctx_(spl::make_shared<scoped_context>(to_xpath(u8(path))))
136 scoped_const_iterator begin() const
138 return scoped_const_iterator(ctx_, child_.begin());
141 scoped_const_iterator end() const
143 return scoped_const_iterator(ctx_, child_.end());
147 template <typename Key>
148 struct iterate_children_tag
152 iterate_children_tag(Key val_)
153 : val(std::move(val_))
158 typedef iterate_children_tag<std::wstring> witerate_children;
159 typedef iterate_children_tag<std::string> iterate_children;
161 template <typename Ptree>
162 scope_aware_ptree_child_range<Ptree> operator|(const Ptree& ptree, iterate_children_tag<typename Ptree::key_type> path)
164 return scope_aware_ptree_child_range<Ptree>(ptree, path.val);
167 template<typename Ptree>
168 struct basic_scoped_element_translator
170 mutable std::shared_ptr<scoped_context> ctx;
171 mutable std::map<typename Ptree::key_type, int> by_name;
173 typedef const std::pair<const typename Ptree::key_type, Ptree>& result_type;
175 result_type operator()(result_type pair) const
178 ctx.reset(new scoped_context);
180 ctx->replace_msg("/" + u8(pair.first) + "[" + boost::lexical_cast<std::string>(++by_name[pair.first]) + "]");
185 template <typename Ptree> struct element_context_iteration_tag { };
186 static element_context_iteration_tag<typename boost::property_tree::wptree> welement_context_iteration;
187 static element_context_iteration_tag<typename boost::property_tree::ptree> element_context_iteration;
189 template <typename Range, typename Ptree>
190 auto operator|(const Range& rng, element_context_iteration_tag<Ptree> tag) -> decltype(rng | boost::adaptors::transformed(basic_scoped_element_translator<Ptree>()))
192 return rng | boost::adaptors::transformed(basic_scoped_element_translator<Ptree>());
195 template <typename Key, typename Ptree, typename Str>
196 void ptree_verify_element_name(const std::pair<const Key, Ptree>& elem, const Str& expected)
198 if (elem.first != expected)
199 CASPAR_THROW_EXCEPTION(ptree_exception() << msg_info("Expected element named " + u8(expected)));