/***************************************************************************** * * This file is part of Mapnik (c++ mapping toolkit) * * Copyright (C) 2012 Artem Pavlenko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ //mapnik #include #include #include #include #include #include #include #include #include #include #include #include #include #include // stl #include namespace mapnik { class boolean_type; template struct name_trait { static std::string name() { return ""; } // missing name_trait for type ... // if you get here you are probably using a new type // in the XML file. Just add a name trait for the new // type below. static_assert( sizeof(T) == 0, "missing name_trait for the type"); }; #define DEFINE_NAME_TRAIT( type, type_name ) \ template <> \ struct name_trait \ { \ static std::string name() { return std::string("type ") + type_name; } \ }; DEFINE_NAME_TRAIT( double, "double") DEFINE_NAME_TRAIT( float, "float") DEFINE_NAME_TRAIT( unsigned, "unsigned") DEFINE_NAME_TRAIT( boolean_type, "boolean_type") #ifdef BIGINT DEFINE_NAME_TRAIT( mapnik::value_integer, "long long" ) #else DEFINE_NAME_TRAIT( mapnik::value_integer, "int" ) #endif DEFINE_NAME_TRAIT( std::string, "string" ) DEFINE_NAME_TRAIT( color, "color" ) DEFINE_NAME_TRAIT( expression_ptr, "expression_ptr" ) DEFINE_NAME_TRAIT( font_feature_settings, "font-feature-settings" ) template struct name_trait< mapnik::enumeration > { using Enum = enumeration; static std::string name() { std::string value_list("one of ["); for (unsigned i = 0; i < Enum::MAX; ++i) { value_list += Enum::get_string( i ); if ( i + 1 < Enum::MAX ) value_list += ", "; } value_list += "]"; return value_list; } }; xml_tree::xml_tree(std::string const& encoding) : node_(*this, ""), file_() { node_.set_processed(true); //root node is always processed } void xml_tree::set_filename(std::string const& fn) { file_ = fn; } std::string const& xml_tree::filename() const { return file_; } xml_node & xml_tree::root() { return node_; } const xml_node & xml_tree::root() const { return node_; } xml_attribute::xml_attribute(const char * value_) : value(value_), processed(false) {} node_not_found::node_not_found(std::string const& node_name) : node_name_(node_name), msg_() {} const char* node_not_found::what() const throw() { msg_ = std::string("Node "+node_name_+ "not found"); return msg_.c_str(); } node_not_found::~node_not_found() throw() {} attribute_not_found::attribute_not_found(std::string const& node_name, std::string const& attribute_name) : node_name_(node_name), attribute_name_(attribute_name), msg_() {} const char* attribute_not_found::what() const throw() { msg_ = std::string("Attribute '" + attribute_name_ +"' not found in node '"+node_name_+ "'"); return msg_.c_str(); } attribute_not_found::~attribute_not_found() throw() {} more_than_one_child::more_than_one_child(std::string const& node_name) : node_name_(node_name), msg_() {} const char* more_than_one_child::what() const throw() { msg_ = std::string("More than one child node in node '" + node_name_ +"'"); return msg_.c_str(); } more_than_one_child::~more_than_one_child() throw() {} xml_node::xml_node(xml_tree &tree, std::string && name, unsigned line, bool is_text) : tree_(tree), name_(std::move(name)), is_text_(is_text), line_(line), processed_(false), ignore_(false) {} std::string xml_node::xml_text = ""; std::string const& xml_node::name() const { if (!is_text_) { return name_; } else { return xml_text; } } std::string const& xml_node::text() const { if (is_text_) { processed_ = true; return name_; } else { throw config_error("text() called on non-text node", *this); } } std::string const& xml_node::filename() const { return tree_.filename(); } bool xml_node::is_text() const { return is_text_; } bool xml_node::is(std::string const& name) const { if (name_ == name) { processed_ = true; return true; } return false; } xml_node & xml_node::add_child(const char * name, unsigned line, bool is_text) { children_.emplace_back(tree_, name, line, is_text); return children_.back(); } void xml_node::add_attribute(const char * name, const char * value) { auto result = attributes_.emplace(name,xml_attribute(value)); if (!result.second) { MAPNIK_LOG_ERROR(xml_tree) << "ignoring duplicate attribute '" << name << "'"; } } xml_node::attribute_map const& xml_node::get_attributes() const { return attributes_; } void xml_node::set_processed(bool processed) const { processed_ = processed; } bool xml_node::processed() const { return processed_; } void xml_node::set_ignore(bool ignore) const { ignore_ = ignore; } bool xml_node::ignore() const { return ignore_; } std::size_t xml_node::size() const { return children_.size(); } xml_node::const_iterator xml_node::begin() const { return children_.begin(); } xml_node::const_iterator xml_node::end() const { return children_.end(); } xml_node & xml_node::get_child(std::string const& name) { std::list::iterator itr = children_.begin(); std::list::iterator end = children_.end(); for (; itr != end; ++itr) { if (!(itr->is_text_) && itr->name_ == name) { itr->set_processed(true); return *itr; } } throw node_not_found(name); } xml_node const& xml_node::get_child(std::string const& name) const { xml_node const* node = get_opt_child(name); if (!node) throw node_not_found(name); return *node; } xml_node const* xml_node::get_opt_child(std::string const& name) const { const_iterator itr = children_.begin(); const_iterator end = children_.end(); for (; itr != end; itr++) { if (!(itr->is_text_) && itr->name_ == name) { itr->set_processed(true); return &(*itr); } } return 0; } bool xml_node::has_child(std::string const& name) const { return get_opt_child(name) != 0; } bool xml_node::has_attribute(std::string const& name) const { return attributes_.count(name) == 1 ? true : false; } template boost::optional xml_node::get_opt_attr(std::string const& name) const { if (attributes_.empty()) return boost::optional(); std::map::const_iterator itr = attributes_.find(name); if (itr == attributes_.end()) return boost::optional(); itr->second.processed = true; boost::optional result = xml_attribute_cast(tree_, std::string(itr->second.value)); if (!result) { throw config_error(std::string("Failed to parse attribute '") + name + "'. Expected " + name_trait::name() + " but got '" + itr->second.value + "'", *this); } return result; } template T xml_node::get_attr(std::string const& name, T const& default_opt_value) const { boost::optional value = get_opt_attr(name); if (value) return *value; return default_opt_value; } template T xml_node::get_attr(std::string const& name) const { boost::optional value = get_opt_attr(name); if (value) return *value; throw attribute_not_found(name_, name); } std::string const& xml_node::get_text() const { // FIXME : return boost::optional if (children_.empty()) { if (is_text_) { return name_; } else { const static std::string empty; return empty; } } if (children_.size() == 1) { return children_.front().text(); } throw more_than_one_child(name_); } template T xml_node::get_value() const { boost::optional result = xml_attribute_cast(tree_, get_text()); if (!result) { throw config_error(std::string("Failed to parse value. Expected ") + name_trait::name() + " but got '" + get_text() + "'", *this); } return *result; } unsigned xml_node::line() const { return line_; } std::string xml_node::line_to_string() const { std::string number; util::to_string(number,line_); return number; } #define compile_get_opt_attr(T) template boost::optional xml_node::get_opt_attr(std::string const&) const #define compile_get_attr(T) template T xml_node::get_attr(std::string const&) const; template T xml_node::get_attr(std::string const&, T const&) const #define compile_get_value(T) template T xml_node::get_value() const compile_get_opt_attr(boolean_type); compile_get_opt_attr(std::string); compile_get_opt_attr(unsigned); compile_get_opt_attr(mapnik::value_integer); compile_get_opt_attr(float); compile_get_opt_attr(double); compile_get_opt_attr(color); compile_get_opt_attr(gamma_method_e); compile_get_opt_attr(line_join_e); compile_get_opt_attr(line_cap_e); compile_get_opt_attr(text_transform_e); compile_get_opt_attr(label_placement_e); compile_get_opt_attr(vertical_alignment_e); compile_get_opt_attr(horizontal_alignment_e); compile_get_opt_attr(justify_alignment_e); compile_get_opt_attr(text_upright_e); compile_get_opt_attr(halo_rasterizer_e); compile_get_opt_attr(expression_ptr); compile_get_opt_attr(font_feature_settings); compile_get_attr(std::string); compile_get_attr(filter_mode_e); compile_get_attr(point_placement_e); compile_get_attr(debug_symbolizer_mode_e); compile_get_attr(marker_placement_e); compile_get_attr(marker_multi_policy_e); compile_get_attr(pattern_alignment_e); compile_get_attr(line_rasterizer_e); compile_get_attr(colorizer_mode); compile_get_attr(double); compile_get_value(value_integer); compile_get_value(double); compile_get_value(expression_ptr); } //ns mapnik