// Copyright (c) 2016, 2024, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, // as published by the Free Software Foundation. // // This program is designed to work with certain software (including // but not limited to OpenSSL) that is licensed under separate terms, // as designated in a particular file or component or in included license // documentation. The authors of MySQL hereby grant you an additional // permission to link the program and your derivative works with the // separately licensed software that they have either included with // the program or referenced in the documentation. // // This program 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 General Public License, version 2.0, for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. #include "sql/gis/srs/wkt_parser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "my_inttypes.h" #include "my_sys.h" #include "mysqld_error.h" // ER_* #include "sql/gis/srs/srs.h" BOOST_FUSION_ADAPT_STRUCT(gis::srs::wkt_parser::Authority, (bool, valid)(gis::srs::wkt_parser::String, name)(gis::srs::wkt_parser::String, code)) BOOST_FUSION_ADAPT_STRUCT(gis::srs::wkt_parser::Spheroid, (gis::srs::wkt_parser::String, name)(double, semi_major_axis)(double, inverse_flattening)( gis::srs::wkt_parser::Authority, authority)) BOOST_FUSION_ADAPT_STRUCT(gis::srs::wkt_parser::Towgs84, (bool, valid)(double, dx)(double, dy)(double, dz)( double, ex)(double, ey)(double, ez)(double, ppm)) BOOST_FUSION_ADAPT_STRUCT( gis::srs::wkt_parser::Datum, (gis::srs::wkt_parser::String, name)(gis::srs::wkt_parser::Spheroid, spheroid)(gis::srs::wkt_parser::Towgs84, towgs84)(gis::srs::wkt_parser::Authority, authority)) BOOST_FUSION_ADAPT_STRUCT(gis::srs::wkt_parser::Prime_meridian, (gis::srs::wkt_parser::String, name)(double, longitude)(gis::srs::wkt_parser::Authority, authority)) BOOST_FUSION_ADAPT_STRUCT(gis::srs::wkt_parser::Unit, (gis::srs::wkt_parser::String, name)(double, conversion_factor)( gis::srs::wkt_parser::Authority, authority)) BOOST_FUSION_ADAPT_STRUCT(gis::srs::wkt_parser::Axis, (gis::srs::wkt_parser::String, name)(gis::srs::Axis_direction, direction)) BOOST_FUSION_ADAPT_STRUCT(gis::srs::wkt_parser::Twin_axes, (bool, valid)(gis::srs::wkt_parser::Axis, x)(gis::srs::wkt_parser::Axis, y)) BOOST_FUSION_ADAPT_STRUCT( gis::srs::wkt_parser::Geographic_cs, (gis::srs::wkt_parser::String, name)(gis::srs::wkt_parser::Datum, datum)( gis::srs::wkt_parser::Prime_meridian, prime_meridian)(gis::srs::wkt_parser::Unit, angular_unit)(gis::srs::wkt_parser::Twin_axes, axes)(gis::srs::wkt_parser::Authority, authority)) BOOST_FUSION_ADAPT_STRUCT(gis::srs::wkt_parser::Projection, (gis::srs::wkt_parser::String, name)(gis::srs::wkt_parser::Authority, authority)) BOOST_FUSION_ADAPT_STRUCT(gis::srs::wkt_parser::Projection_parameter, (gis::srs::wkt_parser::String, name), (double, value), (gis::srs::wkt_parser::Authority, authority)) BOOST_FUSION_ADAPT_STRUCT( gis::srs::wkt_parser::Projected_cs, (gis::srs::wkt_parser::String, name)(gis::srs::wkt_parser::Geographic_cs, geographic_cs)(gis::srs::wkt_parser::Projection, projection)( gis::srs::wkt_parser::Projection_parameters, parameters)(gis::srs::wkt_parser::Unit, linear_unit)(gis::srs::wkt_parser::Twin_axes, axes)(gis::srs::wkt_parser::Authority, authority)) namespace gis { namespace srs { namespace wkt_parser { /// @cond DOXYGEN_DOESNT_UNDERSTAND_THIS_LINE namespace qi = boost::spirit::qi; /// @endcond template struct number_policies : qi::real_policies { template static bool parse_nan(Iterator &, Iterator const &, Attribute &) { return false; } template static bool parse_inf(Iterator &, Iterator const &, Attribute &) { return false; } }; template struct Grammar : qi::grammar { Grammar(char right_delimiter_char) : Grammar::base_type(start) { if (right_delimiter_char == ')') { left_delimiter = qi::lit('('); right_delimiter = qi::lit(')'); } else { left_delimiter = qi::lit('['); right_delimiter = qi::lit(']'); } quoted_string = qi::lexeme['"' >> +(qi::char_ - '"') >> '"']; authority = qi::no_case[qi::lit("AUTHORITY")] >> qi::attr(true) >> left_delimiter >> quoted_string >> qi::lit(',') >> quoted_string >> right_delimiter; number = qi::real_parser>(); unit = qi::no_case[qi::lit("UNIT")] >> left_delimiter >> quoted_string >> qi::lit(',') >> number >> -(qi::lit(',') >> authority) >> right_delimiter; linear_unit = unit; angular_unit = unit; spheroid = qi::no_case[qi::lit("SPHEROID")] >> left_delimiter >> quoted_string >> qi::lit(',') >> number >> qi::lit(',') >> number >> -(qi::lit(',') >> authority) >> right_delimiter; to_wgs84 = qi::no_case[qi::lit("TOWGS84")] >> qi::attr(true) >> left_delimiter >> number >> // dx qi::lit(',') >> number >> // dy qi::lit(',') >> number >> // dz qi::lit(',') >> number >> // ex qi::lit(',') >> number >> // ey qi::lit(',') >> number >> // ez qi::lit(',') >> number >> // ppm right_delimiter; datum = qi::no_case[qi::lit("DATUM")] >> left_delimiter >> quoted_string >> qi::lit(',') >> spheroid >> -(qi::lit(',') >> to_wgs84) >> -(qi::lit(',') >> authority) >> right_delimiter; prime_meridian = qi::no_case[qi::lit("PRIMEM")] >> left_delimiter >> quoted_string >> qi::lit(',') >> number >> -(qi::lit(',') >> authority) >> right_delimiter; axis_direction.add // All values must be lower case to achieve case insensitive // matching. ("north", Axis_direction::NORTH)("south", Axis_direction::SOUTH)( "east", Axis_direction::EAST)("west", Axis_direction::WEST)( "other", Axis_direction::OTHER); axis = qi::no_case[qi::lit("AXIS")] >> left_delimiter >> quoted_string >> qi::lit(',') >> qi::no_case[axis_direction] >> right_delimiter; twin_axes = qi::attr(true) >> axis >> qi::lit(',') >> axis; geographic_cs = qi::no_case[qi::lit("GEOGCS")] >> left_delimiter >> quoted_string >> qi::lit(',') >> datum >> qi::lit(',') >> prime_meridian >> qi::lit(',') >> angular_unit >> qi::lit(',') >> twin_axes >> -(qi::lit(',') >> authority) >> right_delimiter; parameter = qi::no_case[qi::lit("PARAMETER")] >> left_delimiter >> quoted_string >> qi::lit(',') >> number >> -(qi::lit(',') >> authority) >> right_delimiter; parameters = parameter % qi::lit(','); projection = qi::no_case[qi::lit("PROJECTION")] >> left_delimiter >> quoted_string >> -(qi::lit(',') >> authority) >> right_delimiter; projected_cs = qi::no_case[qi::lit("PROJCS")] >> left_delimiter >> quoted_string >> qi::lit(',') >> geographic_cs >> qi::lit(',') >> projection >> -(qi::lit(',') >> parameters) >> qi::lit(',') >> linear_unit >> -(qi::lit(',') >> twin_axes) >> -(qi::lit(',') >> authority) >> right_delimiter; horz_cs = projected_cs | geographic_cs; coordinate_system = horz_cs; start = coordinate_system; } qi::rule left_delimiter; qi::rule right_delimiter; qi::rule quoted_string; qi::rule authority; qi::rule number; qi::rule unit; qi::rule linear_unit; qi::rule angular_unit; qi::rule spheroid; qi::rule to_wgs84; qi::rule datum; qi::rule prime_meridian; qi::symbols axis_direction; qi::rule axis; qi::rule twin_axes; qi::rule geographic_cs; qi::rule parameter; qi::rule parameters; qi::rule projection; qi::rule projected_cs; qi::rule horz_cs; qi::rule coordinate_system; qi::rule start; }; } // namespace wkt_parser } // namespace srs } // namespace gis bool gis::srs::wkt_parser::parse_wkt( srid_t srid, const char *begin, const char *end, gis::srs::wkt_parser::Coordinate_system *cs) { // gis::srs::parse_wkt() should have filtered these out already assert(begin != nullptr && begin < (end - 1)); namespace wp = gis::srs::wkt_parser; bool res = false; const char *it = begin; const char *delimiter = end; delimiter--; while (delimiter > begin && std::isspace(*delimiter)) delimiter--; wp::Grammar g( *delimiter); try { res = !boost::spirit::qi::phrase_parse(it, end, g, boost::spirit::ascii::space, *cs); if (it != end || res) { my_error(ER_SRS_PARSE_ERROR, MYF(0), srid); res = true; } } catch (...) { my_error(ER_SRS_PARSE_ERROR, MYF(0), srid); res = true; } return res; }