diff --git a/include/mapnik/marker_cache.hpp b/include/mapnik/marker_cache.hpp index d7a191f35..dec837ca9 100644 --- a/include/mapnik/marker_cache.hpp +++ b/include/mapnik/marker_cache.hpp @@ -55,7 +55,7 @@ public: inline bool is_uri(std::string const& path) { return is_svg_uri(path) || is_image_uri(path); } bool is_svg_uri(std::string const& path); bool is_image_uri(std::string const& path); - std::shared_ptr find(std::string const& key, bool update_cache = false); + std::shared_ptr find(std::string const& key, bool update_cache = false, bool strict = false); void clear(); }; diff --git a/include/mapnik/svg/svg_parser.hpp b/include/mapnik/svg/svg_parser.hpp index 87a0f5c4b..0aac82578 100644 --- a/include/mapnik/svg/svg_parser.hpp +++ b/include/mapnik/svg/svg_parser.hpp @@ -40,13 +40,14 @@ namespace mapnik { namespace svg { { using error_message_container = std::vector ; public: - explicit svg_parser(svg_converter_type & path); + explicit svg_parser(svg_converter_type & path, bool strict = false); ~svg_parser(); error_message_container const& error_messages() const; bool parse(std::string const& filename); bool parse_from_string(std::string const& svg); svg_converter_type & path_; bool is_defs_; + bool strict_; std::map gradient_map_; std::pair temporary_gradient_; error_message_container error_messages_; diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index 4f00acf2c..cdf3c2b6a 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -141,7 +141,7 @@ struct visitor_create_marker } // end detail ns std::shared_ptr marker_cache::find(std::string const& uri, - bool update_cache) + bool update_cache, bool strict) { if (uri.empty()) { @@ -174,15 +174,15 @@ std::shared_ptr marker_cache::find(std::string const& uri, vertex_stl_adapter stl_storage(marker_path->source()); svg_path_adapter svg_path(stl_storage); svg_converter_type svg(svg_path, marker_path->attributes()); - svg_parser p(svg); + svg_parser p(svg, strict); - if (!p.parse_from_string(known_svg_string)) + if (!p.parse_from_string(known_svg_string) && !strict) { for (auto const& msg : p.error_messages()) { MAPNIK_LOG_ERROR(marker_cache) << "SVG PARSING ERROR:\"" << msg << "\""; } - return std::make_shared(mapnik::marker_null()); + //return std::make_shared(mapnik::marker_null()); } //svg.arrange_orientations(); double lox,loy,hix,hiy; @@ -214,16 +214,16 @@ std::shared_ptr marker_cache::find(std::string const& uri, vertex_stl_adapter stl_storage(marker_path->source()); svg_path_adapter svg_path(stl_storage); svg_converter_type svg(svg_path, marker_path->attributes()); - svg_parser p(svg); + svg_parser p(svg, strict); - if (!p.parse(uri)) + if (!p.parse(uri) && !strict) { for (auto const& msg : p.error_messages()) { MAPNIK_LOG_ERROR(marker_cache) << "SVG PARSING ERROR:\"" << msg << "\""; } - return std::make_shared(mapnik::marker_null()); + //return std::make_shared(mapnik::marker_null()); } //svg.arrange_orientations(); double lox,loy,hix,hiy; diff --git a/src/svg/svg_parser.cpp b/src/svg/svg_parser.cpp index b2fa9544a..52718e799 100644 --- a/src/svg/svg_parser.cpp +++ b/src/svg/svg_parser.cpp @@ -115,6 +115,15 @@ BOOST_SPIRIT_DEFINE(key, value, key_value, key_value_sequence_ordered); }} +namespace { +template +void on_error(T & error_messages, std::string const& msg, bool strict) +{ + if (strict) throw std::runtime_error(msg); + else error_messages.emplace_back(msg); +} +} + template mapnik::color parse_color(T & error_messages, const char* str) { @@ -125,7 +134,7 @@ mapnik::color parse_color(T & error_messages, const char* str) } catch (mapnik::config_error const& ex) { - error_messages.emplace_back(ex.what()); + on_error(error_messages, ex.what(), false); } return c; } @@ -144,7 +153,7 @@ double parse_double(T & error_messages, const char* str) double val = 0.0; if (!parse(str, str + std::strlen(str), double_, val)) { - error_messages.emplace_back("Failed to parse double: \"" + std::string(str) + "\""); + on_error(error_messages,"Failed to parse double: \"" + std::string(str) + "\"", false); } return val; } @@ -178,12 +187,12 @@ double parse_svg_value(T & error_messages, const char* str, bool & is_percent) x3::lit('%')[apply_percent]), x3::space)) { - error_messages.emplace_back("Failed to parse SVG value: '" + std::string(str) + "'"); + on_error(error_messages,"Failed to parse SVG value: '" + std::string(str) + "'", false); } else if (cur != end) { - error_messages.emplace_back("Failed to parse SVG value: '" + std::string(str) + - "', trailing garbage: '" + cur + "'"); + on_error(error_messages,"Failed to parse SVG value: '" + std::string(str) + + "', trailing garbage: '" + cur + "'", false); } return val; } @@ -198,7 +207,7 @@ bool parse_viewbox(T & error_messages, const char* str, V & viewbox) x3::double_ > -x3::lit(',') > x3::double_, x3::space, viewbox)) { - error_messages.emplace_back("failed to parse SVG viewbox from " + std::string(str)); + on_error(error_messages,"failed to parse SVG viewbox from " + std::string(str), false); return false; } return true; @@ -261,7 +270,7 @@ bool traverse_tree(svg_parser & parser, rapidxml::xml_node const* node) else { parser.path_.push_attr(); - parse_attr(parser, node); + //parse_attr(parser, node); if (parser.path_.display()) { if (std::strcmp(name, "path") == 0) @@ -299,6 +308,7 @@ bool traverse_tree(svg_parser & parser, rapidxml::xml_node const* node) else { //std::cerr << "unprocessed node <--[" << node->name() << "]\n"; + on_error(parser.error_messages_, std::string("Unsupported element:\"") + node->name(), parser.strict_); } } parser.path_.pop_attr(); @@ -387,7 +397,7 @@ void parse_attr(svg_parser & parser, char const* name, char const* value ) { std::stringstream ss; ss << "Failed to find gradient fill: " << id; - parser.error_messages_.push_back(ss.str()); + on_error(parser.error_messages_, ss.str(), parser.strict_); } } else @@ -424,7 +434,7 @@ void parse_attr(svg_parser & parser, char const* name, char const* value ) { std::stringstream ss; ss << "Failed to find gradient stroke: " << id; - parser.error_messages_.push_back(ss.str()); + on_error(parser.error_messages_, ss.str(), parser.strict_); } } else @@ -489,6 +499,10 @@ void parse_attr(svg_parser & parser, char const* name, char const* value ) { parser.path_.display(false); } + else + { + on_error(parser.error_messages_, std::string("Unsupported attribute:\"") + name, parser.strict_); + } } void parse_attr(svg_parser & parser, rapidxml::xml_node const* node) @@ -576,12 +590,12 @@ void parse_path(svg_parser & parser, rapidxml::xml_node const* node) if (id_attr == nullptr) id_attr = node->first_attribute("id"); if (id_attr) { - parser.error_messages_.push_back(std::string("unable to parse invalid svg with id '") - + id_attr->value() + "'"); + on_error(parser.error_messages_, std::string("unable to parse invalid svg with id '") + + id_attr->value() + "'", parser.strict_); } else { - parser.error_messages_.push_back(std::string("unable to parse invalid svg ")); + on_error(parser.error_messages_, std::string("unable to parse invalid svg "), parser.strict_); } } parser.path_.end_path(); @@ -597,7 +611,7 @@ void parse_polygon(svg_parser & parser, rapidxml::xml_node const* node) parser.path_.begin_path(); if (!mapnik::svg::parse_points(attr->value(), parser.path_)) { - parser.error_messages_.push_back(std::string("Failed to parse 'points'")); + on_error(parser.error_messages_, std::string("Failed to parse 'points'"), parser.strict_); } parser.path_.close_subpath(); parser.path_.end_path(); @@ -612,7 +626,7 @@ void parse_polyline(svg_parser & parser, rapidxml::xml_node const* node) parser.path_.begin_path(); if (!mapnik::svg::parse_points(attr->value(), parser.path_)) { - parser.error_messages_.push_back(std::string("Failed to parse 'points'")); + on_error(parser.error_messages_, std::string("Failed to parse 'points'"), parser.strict_); } parser.path_.end_path(); } @@ -917,7 +931,7 @@ bool parse_common_gradient(svg_parser & parser, rapidxml::xml_node const* { std::stringstream ss; ss << "Failed to find linked gradient " << linkid; - parser.error_messages_.push_back(ss.str()); + on_error(parser.error_messages_, ss.str(), parser.strict_); return false; } } @@ -981,8 +995,7 @@ void parse_radial_gradient(svg_parser & parser, rapidxml::xml_node const* { fy = parse_svg_value(parser.error_messages_, attr->value(), has_percent); } - else - fy = cy; + else fy = cy; attr = node->first_attribute("r"); if (attr != nullptr) @@ -1049,9 +1062,10 @@ void parse_linear_gradient(svg_parser & parser, rapidxml::xml_node const* } svg_parser::svg_parser(svg_converter > & path) + agg::pod_bvector > & path, bool strict) : path_(path), - is_defs_(false) {} + is_defs_(false), + strict_(strict) {} svg_parser::~svg_parser() {} diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index 9afbb77a9..44a84e33d 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -144,6 +144,7 @@ int main (int argc,char** argv) bool verbose = false; bool auto_open = false; + bool strict = false; int status = 0; std::vector svg_files; mapnik::logger::instance().set_severity(mapnik::logger::error); @@ -156,18 +157,19 @@ int main (int argc,char** argv) ("version,V","print version string") ("verbose,v","verbose output") ("open","automatically open the file after rendering (os x only)") + ("strict","enables strict SVG parsing") ("svg",po::value >(),"svg file to read") ; po::positional_options_description p; - p.add("svg",-1); + p.add("svg", -1); po::variables_map vm; po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm); po::notify(vm); if (vm.count("version")) { - std::clog <<"version " << MAPNIK_VERSION_STRING << std::endl; + std::clog << "version " << MAPNIK_VERSION_STRING << std::endl; return 1; } @@ -187,6 +189,11 @@ int main (int argc,char** argv) auto_open = true; } + if (vm.count("strict")) + { + strict = true; + } + if (vm.count("svg")) { svg_files=vm["svg"].as< std::vector >(); @@ -211,8 +218,7 @@ int main (int argc,char** argv) { std::clog << "found: " << svg_name << "\n"; } - - std::shared_ptr marker = mapnik::marker_cache::instance().find(svg_name, false); + std::shared_ptr marker = mapnik::marker_cache::instance().find(svg_name, false, strict); main_marker_visitor visitor(svg_name, verbose, auto_open); status = mapnik::util::apply_visitor(visitor, *marker); }