Merge pull request #3971 from lightmare/fix-topojson-empty

Accept TopoJSON with no objects
This commit is contained in:
lightmare 2018-08-14 15:10:07 +02:00 committed by GitHub
commit 9275ca9373
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 5 deletions

View file

@ -276,7 +276,7 @@ using x3::lit;
using x3::double_;
using x3::int_;
using x3::omit;
using x3::char_;
namespace
{
// import unicode string rule
@ -360,9 +360,13 @@ auto const bbox_def = lit("\"bbox\"") > lit(':')
;
// A topology must have an “objects” member whose value is an object.
// This object may have any number of members, whose value must be a geometry object.
auto const objects_def = lit("\"objects\"") > lit(':')
> lit('{')
> ((omit[*~char_(':')] > lit(':') > ((geometry_collection[push_collection] | geometry[push_geometry]))) % lit(','))
> -((omit[json_string] > ':' > ( geometry_collection[push_collection]
| geometry[push_geometry]
)) % ',')
> lit('}')
;
@ -375,7 +379,7 @@ auto const geometry_tuple_def =
|
properties[assign_properties]
|
omit[json_string] > lit(':') > omit[json_value]) % lit(',')
(omit[json_string] > lit(':') > omit[json_value])) % lit(',')
;
auto const geometry_def = lit("{") > geometry_tuple[create_geometry] > lit("}");

View file

@ -29,8 +29,12 @@
#include <mapnik/json/topojson_grammar_x3.hpp>
#include <mapnik/json/topojson_utils.hpp>
#define HEREDOC(...) #__VA_ARGS__
namespace {
bool parse_topology_string(std::string const& buffer, mapnik::topojson::topology & topo);
bool parse_topology(std::string const& filename, mapnik::topojson::topology & topo)
{
mapnik::util::file file(filename);
@ -38,6 +42,17 @@ bool parse_topology(std::string const& filename, mapnik::topojson::topology & to
buffer.resize(file.size());
std::fread(&buffer[0], buffer.size(), 1, file.get());
if (!file) return false;
return parse_topology_string(buffer, topo);
}
bool parse_topology_string(std::string const& buffer)
{
mapnik::topojson::topology topo;
return parse_topology_string(buffer, topo);
}
bool parse_topology_string(std::string const& buffer, mapnik::topojson::topology & topo)
{
using space_type = boost::spirit::x3::standard::space_type;
char const* itr = buffer.c_str();
char const* end = itr + buffer.length();
@ -50,7 +65,17 @@ bool parse_topology(std::string const& filename, mapnik::topojson::topology & to
std::cerr << "failed to parse TopoJSON..." << std::endl;
std::cerr << ex.what() << std::endl;
std::cerr << "Expected: " << ex.which();
std::cerr << " Got: \"" << std::string(ex.where(), ex.where() + 200) << "...\"" << std::endl;
std::cerr << "\nGot: \"";
auto ctx = ex.where();
std::streamsize len = 0;
// stop before NUL terminator or after 200 bytes, whichever comes first
for (; ctx[len] && len < 200; ++len)
;
// extend to UTF-8 character boundary or 210 bytes, whichever comes first
for (; len < 210 && ((unsigned char)ctx[len] & 0xC0) == 0x80; ++len)
;
std::cerr.write(ctx, len);
std::cerr << (ctx[len] ? "..." : "") << '"' << std::endl;
return false;
}
return (itr == end);
@ -58,8 +83,44 @@ bool parse_topology(std::string const& filename, mapnik::topojson::topology & to
}
TEST_CASE("topojson")
TEST_CASE("TopoJSON")
{
SECTION("Minimal Topology")
{
// + A topology must have a member with the name “objects” whose value is another object.
// + A topology must have a member with the name “arcs” whose value is an array of arcs.
CHECK(parse_topology_string(HEREDOC(
{
"type": "Topology", "objects": {}, "arcs": []
}
)));
CHECK(parse_topology_string(HEREDOC(
{
"type": "Topology", "arcs": [], "objects": {}
}
)));
CHECK(parse_topology_string(HEREDOC(
{
"objects": {}, "type": "Topology", "arcs": []
}
)));
CHECK(parse_topology_string(HEREDOC(
{
"objects": {}, "arcs": [], "type": "Topology"
}
)));
CHECK(parse_topology_string(HEREDOC(
{
"arcs": [], "type": "Topology", "objects": {}
}
)));
CHECK(parse_topology_string(HEREDOC(
{
"arcs": [], "objects": {}, "type": "Topology"
}
)));
}
SECTION("geometry parsing")
{
mapnik::value_integer feature_id = 0;