#ifndef SERVER_API_BASE_PARAMETERS_GRAMMAR_HPP #define SERVER_API_BASE_PARAMETERS_GRAMMAR_HPP #include "engine/api/base_parameters.hpp" #include "engine/bearing.hpp" #include "engine/hint.hpp" #include "engine/polyline_compressor.hpp" #include #include #include #include #include namespace osrm { namespace server { namespace api { namespace { namespace ph = boost::phoenix; namespace qi = boost::spirit::qi; } template struct no_trailing_dot_policy : qi::real_policies { template static bool parse_dot(Iterator &first, Iterator const &last) { if (first == last || *first != '.') return false; static const constexpr char fmt[sizeof...(Fmt)] = {Fmt...}; if (first + sizeof(fmt) < last && std::equal(fmt, fmt + sizeof(fmt), first + 1u)) return false; ++first; return true; } template static bool parse_exp(Iterator &, const Iterator &) { return false; } template static bool parse_exp_n(Iterator &, const Iterator &, Attribute &) { return false; } template static bool parse_nan(Iterator &, const Iterator &, Attribute &) { return false; } template static bool parse_inf(Iterator &, const Iterator &, Attribute &) { return false; } }; template struct BaseParametersGrammar : boost::spirit::qi::grammar { using json_policy = no_trailing_dot_policy; BaseParametersGrammar(qi::rule &root_rule) : BaseParametersGrammar::base_type(root_rule) { const auto add_hint = [](engine::api::BaseParameters &base_parameters, const boost::optional &hint_string) { if (hint_string) { base_parameters.hints.emplace_back(engine::Hint::FromBase64(hint_string.get())); } else { base_parameters.hints.emplace_back(boost::none); } }; const auto add_bearing = [](engine::api::BaseParameters &base_parameters, boost::optional> bearing_range) { boost::optional bearing; if (bearing_range) { bearing = engine::Bearing{boost::fusion::at_c<0>(*bearing_range), boost::fusion::at_c<1>(*bearing_range)}; } base_parameters.bearings.push_back(std::move(bearing)); }; polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^"); base64_char = qi::char_("a-zA-Z0-9--_="); unlimited_rule = qi::lit("unlimited")[qi::_val = std::numeric_limits::infinity()]; bearing_rule = (qi::short_ > ',' > qi::short_)[qi::_val = ph::bind( [](short bearing, short range) { return osrm::engine::Bearing{bearing, range}; }, qi::_1, qi::_2)]; location_rule = (double_ > qi::lit(',') > double_)[qi::_val = ph::bind( [](double lon, double lat) { return util::Coordinate( util::toFixed(util::UnsafeFloatLongitude{lon}), util::toFixed(util::UnsafeFloatLatitude{lat})); }, qi::_1, qi::_2)]; polyline_rule = qi::as_string[qi::lit("polyline(") > +polyline_chars > ')'] [qi::_val = ph::bind( [](const std::string &polyline) { return engine::decodePolyline(polyline); }, qi::_1)]; polyline6_rule = qi::as_string[qi::lit("polyline6(") > +polyline_chars > ')'] [qi::_val = ph::bind( [](const std::string &polyline) { return engine::decodePolyline<1000000>(polyline); }, qi::_1)]; query_rule = ((location_rule % ';') | polyline_rule | polyline6_rule)[ph::bind(&engine::api::BaseParameters::coordinates, qi::_r1) = qi::_1]; radiuses_rule = qi::lit("radiuses=") > (-(qi::double_ | unlimited_rule) % ';')[ph::bind(&engine::api::BaseParameters::radiuses, qi::_r1) = qi::_1]; hints_rule = qi::lit("hints=") > (-qi::as_string[qi::repeat(engine::ENCODED_HINT_SIZE)[base64_char]])[ph::bind( add_hint, qi::_r1, qi::_1)] % ';'; generate_hints_rule = qi::lit("generate_hints=") > qi::bool_[ph::bind(&engine::api::BaseParameters::generate_hints, qi::_r1) = qi::_1]; skip_waypoints_rule = qi::lit("skip_waypoints=") > qi::bool_[ph::bind(&engine::api::BaseParameters::skip_waypoints, qi::_r1) = qi::_1]; bearings_rule = qi::lit("bearings=") > (-(qi::short_ > ',' > qi::short_))[ph::bind(add_bearing, qi::_r1, qi::_1)] % ';'; approach_type.add("unrestricted", engine::Approach::UNRESTRICTED)("curb", engine::Approach::CURB); approach_rule = qi::lit("approaches=") > (-approach_type % ';')[ph::bind(&engine::api::BaseParameters::approaches, qi::_r1) = qi::_1]; snapping_type.add("default", engine::api::BaseParameters::SnappingType::Default)( "any", engine::api::BaseParameters::SnappingType::Any); snapping_rule = qi::lit("snapping=") > snapping_type[ph::bind(&engine::api::BaseParameters::snapping, qi::_r1) = qi::_1]; format_type.add(".json", engine::api::BaseParameters::OutputFormatType::JSON)( ".flatbuffers", engine::api::BaseParameters::OutputFormatType::FLATBUFFERS); format_rule = -format_type[ph::bind(&engine::api::BaseParameters::format, qi::_r1) = qi::_1]; exclude_rule = qi::lit("exclude=") > (qi::as_string[+qi::char_("a-zA-Z0-9")] % ',')[ph::bind(&engine::api::BaseParameters::exclude, qi::_r1) = qi::_1]; base_rule = radiuses_rule(qi::_r1) // | hints_rule(qi::_r1) // | bearings_rule(qi::_r1) // | generate_hints_rule(qi::_r1) // | skip_waypoints_rule(qi::_r1) // | approach_rule(qi::_r1) // | exclude_rule(qi::_r1) // | snapping_rule(qi::_r1); } protected: qi::rule base_rule; qi::rule query_rule; qi::rule format_rule; qi::symbols format_type; qi::real_parser double_; private: qi::rule bearings_rule; qi::rule radiuses_rule; qi::rule hints_rule; qi::rule generate_hints_rule; qi::rule skip_waypoints_rule; qi::rule approach_rule; qi::rule exclude_rule; qi::rule bearing_rule; qi::rule location_rule; qi::rule()> polyline_rule; qi::rule()> polyline6_rule; qi::rule base64_char; qi::rule polyline_chars; qi::rule unlimited_rule; qi::rule snapping_rule; qi::symbols approach_type; qi::symbols snapping_type; }; } } } #endif