From 863ae6a8b34f5bfd0e158d4d95bfc3b889f2962c Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 27 Jan 2015 15:51:11 +0100 Subject: [PATCH] geobuf.input - initial barebones implementation --- SConstruct | 2 +- plugins/input/geobuf/build.py | 64 +++ plugins/input/geobuf/geobuf.hpp | 484 +++++++++++++++++++++ plugins/input/geobuf/geobuf_datasource.cpp | 155 +++++++ plugins/input/geobuf/geobuf_datasource.hpp | 112 +++++ plugins/input/geobuf/geobuf_featureset.cpp | 55 +++ plugins/input/geobuf/geobuf_featureset.hpp | 48 ++ plugins/input/geobuf/pbf.hpp | 206 +++++++++ src/save_map.cpp | 1 + 9 files changed, 1126 insertions(+), 1 deletion(-) create mode 100644 plugins/input/geobuf/build.py create mode 100644 plugins/input/geobuf/geobuf.hpp create mode 100644 plugins/input/geobuf/geobuf_datasource.cpp create mode 100644 plugins/input/geobuf/geobuf_datasource.hpp create mode 100644 plugins/input/geobuf/geobuf_featureset.cpp create mode 100644 plugins/input/geobuf/geobuf_featureset.hpp create mode 100644 plugins/input/geobuf/pbf.hpp diff --git a/SConstruct b/SConstruct index a83807525..2667e6318 100644 --- a/SConstruct +++ b/SConstruct @@ -120,7 +120,7 @@ PLUGINS = { # plugins with external dependencies 'csv': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'raster': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'geojson': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, - 'large_geojson': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, + 'geobuf': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'topojson':{'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'python': {'default':False,'path':None,'inc':None,'lib':None,'lang':'C++'}, } diff --git a/plugins/input/geobuf/build.py b/plugins/input/geobuf/build.py new file mode 100644 index 000000000..5e1eba2db --- /dev/null +++ b/plugins/input/geobuf/build.py @@ -0,0 +1,64 @@ +# +# This file is part of Mapnik (c++ mapping toolkit) +# +# Copyright (C) 2013 Artem Pavlenko +# +# Mapnik 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 +# +# + +Import ('env') + +Import ('plugin_base') + +PLUGIN_NAME = 'geobuf' + +plugin_env = plugin_base.Clone() + +plugin_sources = Split( + """ + %(PLUGIN_NAME)s_datasource.cpp + %(PLUGIN_NAME)s_featureset.cpp + """ % locals() +) + +# Link Library to Dependencies +libraries = [] +libraries.append(env['ICU_LIB_NAME']) +libraries.append('boost_system%s' % env['BOOST_APPEND']) +libraries.append('mapnik-json') + +if env['PLUGIN_LINKING'] == 'shared': + libraries.append(env['MAPNIK_NAME']) + + TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME, + SHLIBPREFIX='', + SHLIBSUFFIX='.input', + source=plugin_sources, + LIBS=libraries) + + # if the plugin links to libmapnik ensure it is built first + Depends(TARGET, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME'])) + + if 'uninstall' not in COMMAND_LINE_TARGETS: + env.Install(env['MAPNIK_INPUT_PLUGINS_DEST'], TARGET) + env.Alias('install', env['MAPNIK_INPUT_PLUGINS_DEST']) + +plugin_obj = { + 'LIBS': libraries, + 'SOURCES': plugin_sources, +} + +Return('plugin_obj') diff --git a/plugins/input/geobuf/geobuf.hpp b/plugins/input/geobuf/geobuf.hpp new file mode 100644 index 000000000..c2e1a5711 --- /dev/null +++ b/plugins/input/geobuf/geobuf.hpp @@ -0,0 +1,484 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_UTIL_GEOBUF_HPP +#define MAPNIK_UTIL_GEOBUF_HPP + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "pbf.hpp" + +namespace mapnik { namespace util { + +enum geometry_type_e +{ + Unknown = -1, + Point = 0, + MultiPoint = 1, + LineString = 2, + MultiLineString = 3, + Polygon = 4, + MultiPolygon = 5, + GeometryCollection = 6 +}; + +namespace detail { +struct value_visitor +{ + value_visitor(mapnik::feature_impl & feature, mapnik::transcoder const& tr, std::string const& name) + : feature_(feature), + tr_(tr), + name_(name) {} + + void operator() (std::string const& val) // unicode + { + feature_.put_new(name_, tr_.transcode(val.c_str())); + } + + template + void operator() (T val) + { + feature_.put_new(name_, val); + } + + mapnik::feature_impl & feature_; + mapnik::transcoder const& tr_; + std::string const& name_; +}; +} + +struct geobuf +{ + using value_type = mapnik::util::variant; + unsigned dim = 2; + unsigned precision = std::pow(10,6); + bool is_topo = false; + bool transformed = false; + std::size_t lengths = 0; + std::vector keys_; + std::vector values_; + mbgl::pbf pbf_; + mapnik::context_ptr ctx_; + const std::unique_ptr tr_; +public: + //ctor + geobuf (unsigned char const* buf, std::size_t size) + : pbf_(buf, size), + ctx_(std::make_shared()), + tr_(new mapnik::transcoder("utf8")) {} + + template + void read(T & features) + { + //using feature_container_type = T; + while (pbf_.next()) + { + switch (pbf_.tag) + { + case 1: // keys + { + keys_.push_back(pbf_.string()); + break; + } + case 2: + { + dim = pbf_.varint(); + break; + } + case 3: + { + precision = std::pow(10,pbf_.varint()); + break; + } + case 4: + { + auto feature_collection = pbf_.message(); + read_feature_collection(feature_collection, features); + break; + } + case 6: + { + std::cerr << "FIXME" << std::endl; + //auto geometry = pbf_.message(); + //read_geometry(geometry); + } + default: + std::cerr << "FIXME tag=" << pbf_.tag << std::endl; + break; + } + } + } + +private: + + template + void read_value(T & pbf) + { + while (pbf.next()) + { + switch (pbf.tag) + { + case 1: + { + values_.emplace_back(pbf.string()); + break; + } + case 2: + { + values_.emplace_back(pbf.float64()); + break; + } + case 3: + { + values_.emplace_back(static_cast(pbf.varint())); + break; + } + case 4: + { + values_.emplace_back(-static_cast(pbf.varint())); + break; + } + case 5: + { + values_.emplace_back(pbf.boolean()); + break; + } + case 6: + { + values_.emplace_back(pbf.string()); // JSON value + break; + } + default: + break; + } + } + } + + template + void read_props(T & pbf, Feature & feature) + { + uint8_t const* end = pbf.data + pbf.varint(); + while (pbf.data < end) + { + auto key_index = pbf.varint(); + auto value_index = pbf.varint(); + assert(key_index < keys_.size()); + assert(value_index < values_.size()); + std::string const& name = keys_[key_index]; + mapnik::util::apply_visitor(detail::value_visitor(feature, *tr_, name), values_[value_index]); + } + values_.clear(); + } + + template + void read_feature (T & pbf, Features & features) + { + using feature_type = typename Features::value_type; + feature_type feature(feature_factory::create(ctx_,1)); + while (pbf.next()) + { + switch (pbf.tag) + { + case 1: + { + auto message = pbf.message(); + read_geometry(message, feature->paths()); + break; + } + case 11: + { + auto feature_id = pbf.string(); + break; + } + case 12: + { + feature->set_id(pbf.svarint()); + break; + } + case 13: + { + auto message = pbf.message(); + read_value(message); + break; + } + case 14: + { + // feature props + read_props(pbf, *feature); + break; + } + case 15: + { + // generic props + read_props(pbf, *feature); + break; + } + default: + std::cerr << "FAIL tag=" << pbf.tag << std::endl; + break; + } + } + features.push_back(feature); + } + + template + void read_feature_collection(T & pbf, Features & features) + { + while (pbf.next()) + { + switch (pbf.tag) + { + case 1: + { + auto message = pbf.message(); + read_feature(message, features); + break; + } + case 13: + { + auto message = pbf.message(); + read_value(message); + break; + } + case 15: + { + pbf.skipBytes(pbf.varint()); + break; + } + default: + break; + } + } + } + + template + void read_point(T & pbf, GeometryContainer & paths) + { + auto size = pbf.varint(); + std::unique_ptr point(new geometry_type(mapnik::geometry_type::types::Point)); + + uint8_t const* end = pbf.data + size; + std::size_t count = 0; + int x, y; + while (pbf.data < end) + { + auto p = pbf.svarint(); + auto index = count % dim; + if ( index == 0) + { + x = p; + } + else if (index == 1) + { + y = p; + point->move_to(x, y); + } + ++count; + } + paths.push_back(point.release()); + } + + template + void read_coords(T & pbf, geometry_type_e type, boost::optional> const& lengths, GeometryContainer & paths) + { + switch (type) + { + case Point: + { + read_point(pbf, paths); + break; + } + case Polygon: + { + read_polygon(pbf, lengths, paths); + break; + } + case LineString: + { + read_line_string(pbf, paths); + break; + } + case MultiPolygon: + { + read_multipolygon(pbf, lengths, paths); + break; + } + default: + { + //std::cout << "read coord FAIL type=" << type << std::endl; + break; + } + } + } + + template + std::vector read_lengths(T & pbf) + { + std::vector lengths; + auto size = pbf.varint(); + uint8_t const* end = pbf.data + size; + while (pbf.data < end) + { + lengths.push_back(pbf.varint()); + } + return lengths; + } + + template + void read_linear_ring(T & pbf, int len, std::size_t size, Geometry & geom, bool polygon = false) + { + int i = 0; + int x = 0.0; + int y = 0.0; + uint8_t const* end = pbf.data + size; + while ( (len > 0) ? i++ < len : pbf.data < end) + { + for (int d = 0; d < dim; ++d) + { + if (d == 0) x += pbf.svarint(); + else if (d == 1) y += pbf.svarint(); + } + if (i == 1) geom.move_to(x, y); + else geom.line_to(x, y); + } + if (polygon) geom.close_path(); + } + + template + void read_line_string(T & pbf, GeometryContainer & paths) + { + std::unique_ptr line(new geometry_type(mapnik::geometry_type::types::LineString)); + auto size = pbf.varint(); + read_linear_ring(pbf, 0, size, *line); + paths.push_back(line.release()); + } + + template + void read_polygon(T & pbf, boost::optional> const& lengths, GeometryContainer & paths) + { + std::unique_ptr poly(new geometry_type(mapnik::geometry_type::types::Polygon)); + + auto size = pbf.varint(); + if (!lengths) + { + read_linear_ring(pbf, 0, size, *poly, true); + } + else + { + for (auto len : *lengths) + { + read_linear_ring(pbf, len, size, *poly, true); + } + } + paths.push_back(poly.release()); + } + + template + void read_multipolygon(T & pbf, boost::optional> const& lengths, GeometryContainer & paths) + { + auto size = pbf.varint(); + if (!lengths) + { + std::unique_ptr poly(new geometry_type(mapnik::geometry_type::types::Polygon)); + read_linear_ring(pbf, 0, size, *poly, true); + paths.push_back(poly.release()); + } + else if ((*lengths).size() > 0) + { + int j = 1; + for (int i = 0; i < (*lengths)[0]; ++i) + { + std::unique_ptr poly(new geometry_type(mapnik::geometry_type::types::Polygon)); + for (int k = 0; k < (*lengths)[j]; ++k) + { + read_linear_ring(pbf, (*lengths)[j + 1 + k], size, *poly, true); + } + paths.push_back(poly.release()); + j += (*lengths)[j] + 1; + } + } + } + + template + void read_geometry(T & pbf, GeometryContainer & paths) + { + geometry_type_e type = Unknown; + boost::optional> lengths; + while (pbf.next()) + { + switch (pbf.tag) + { + case 1: // type + { + type = static_cast(pbf.varint()); + break; + } + case 2: + lengths = std::move(read_lengths(pbf)); + break; + case 3: + { + read_coords(pbf, type, lengths, paths); + break; + } + case 4: + std::cerr << "read geometry=?" << std::endl; + break; + case 11: + pbf.string(); + std::cerr << "geom_id=" << pbf.string() << std::endl; + break; + case 12: + pbf.varint(); + std::cerr << "geom_id=" << pbf.varint() << std::endl; + break; + case 13: + { + auto value = pbf.message(); + read_value(value); + break; + } + case 14: + case 15: + { + pbf.skipBytes(pbf.varint()); + break; + } + default: + break; + } + } + } +}; + +}} + +#endif // MAPNIK_UTIL_GEOBUF_HPP diff --git a/plugins/input/geobuf/geobuf_datasource.cpp b/plugins/input/geobuf/geobuf_datasource.cpp new file mode 100644 index 000000000..f172ad5de --- /dev/null +++ b/plugins/input/geobuf/geobuf_datasource.cpp @@ -0,0 +1,155 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + * + *****************************************************************************/ + +#include "geobuf_datasource.hpp" +#include "geobuf_featureset.hpp" +#include "geobuf.hpp" + +#include +#include +#include + +// boost + +#include + +// mapnik +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using mapnik::datasource; +using mapnik::parameters; + +DATASOURCE_PLUGIN(geobuf_datasource) + +geobuf_datasource::geobuf_datasource(parameters const& params) + : datasource(params), + type_(datasource::Vector), + desc_(geobuf_datasource::name(), + *params.get("encoding","utf-8")), + filename_(), + extent_(), + features_(), + tree_(nullptr) +{ + boost::optional file = params.get("file"); + if (!file) throw mapnik::datasource_exception("GeoJSON Plugin: missing parameter"); + + boost::optional base = params.get("base"); + if (base) + filename_ = *base + "/" + *file; + else + filename_ = *file; + + + mapnik::util::file in(filename_); + if (!in.open()) + { + throw mapnik::datasource_exception("Geobuf Plugin: could not open: '" + filename_ + "'"); + } + std::vector geobuf; + geobuf.resize(in.size()); + std::fread(geobuf.data(), in.size(), 1, in.get()); + parse_geobuf(geobuf.data(), geobuf.size()); +} + +void geobuf_datasource::parse_geobuf(std::uint8_t const* data, std::size_t size) +{ + mapnik::util::geobuf buf(data, size); + buf.read(features_); + std::cerr << "Num of features = " << features_.size() << std::endl; +} + +geobuf_datasource::~geobuf_datasource() {} + +const char * geobuf_datasource::name() +{ + return "geobuf"; +} + +boost::optional geobuf_datasource::get_geometry_type() const +{ + boost::optional result; + int multi_type = 0; + unsigned num_features = features_.size(); + for (unsigned i = 0; i < num_features && i < 5; ++i) + { + mapnik::util::to_ds_type(features_[i]->paths(),result); + if (result) + { + int type = static_cast(*result); + if (multi_type > 0 && multi_type != type) + { + result.reset(mapnik::datasource::Collection); + return result; + } + multi_type = type; + } + } + return result; +} + +mapnik::datasource::datasource_t geobuf_datasource::type() const +{ + return type_; +} + +mapnik::box2d geobuf_datasource::envelope() const +{ + return extent_; +} + +mapnik::layer_descriptor geobuf_datasource::get_descriptor() const +{ + return desc_; +} + +mapnik::featureset_ptr geobuf_datasource::features(mapnik::query const& q) const +{ + return mapnik::featureset_ptr(); +} + +mapnik::featureset_ptr geobuf_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const +{ + mapnik::box2d query_bbox(pt, pt); + query_bbox.pad(tol); + mapnik::query q(query_bbox); + std::vector const& desc = desc_.get_descriptors(); + std::vector::const_iterator itr = desc.begin(); + std::vector::const_iterator end = desc.end(); + for ( ;itr!=end;++itr) + { + q.add_property_name(itr->get_name()); + } + return features(q); +} diff --git a/plugins/input/geobuf/geobuf_datasource.hpp b/plugins/input/geobuf/geobuf_datasource.hpp new file mode 100644 index 000000000..bde28c060 --- /dev/null +++ b/plugins/input/geobuf/geobuf_datasource.hpp @@ -0,0 +1,112 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + * + *****************************************************************************/ + +#ifndef GEOBUF_DATASOURCE_HPP +#define GEOBUF_DATASOURCE_HPP + +// mapnik +#include +#include +#include +#include +#include +#include +#include +#include +#include +// boost +#include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-local-typedef" +#include +#include +#if BOOST_VERSION >= 105600 +#include +#else +#include +#endif +#pragma GCC diagnostic pop + +// stl +#include +#include +#include +#include +#include + +#if BOOST_VERSION >= 105600 +template +struct geojson_linear : boost::geometry::index::linear {}; + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { + +template +struct options_type > +{ + using type = options, + insert_default_tag, + choose_by_content_diff_tag, + split_default_tag, + linear_tag, +#if BOOST_VERSION >= 105700 + node_variant_static_tag>; +#else + node_s_mem_static_tag>; + +#endif +}; + +}}}}} + +#endif //BOOST_VERSION >= 105600 + +class geobuf_datasource : public mapnik::datasource +{ +public: + using box_type = mapnik::box2d; + using item_type = std::pair>; + using spatial_index_type = boost::geometry::index::rtree >; + + // constructor + geobuf_datasource(mapnik::parameters const& params); + virtual ~geobuf_datasource (); + mapnik::datasource::datasource_t type() const; + static const char * name(); + mapnik::featureset_ptr features(mapnik::query const& q) const; + mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const; + mapnik::box2d envelope() const; + mapnik::layer_descriptor get_descriptor() const; + boost::optional get_geometry_type() const; + void parse_geobuf(std::uint8_t const* buffer, std::size_t size); +private: + mapnik::datasource::datasource_t type_; + mapnik::layer_descriptor desc_; + std::string filename_; + mapnik::box2d extent_; + std::vector features_; + std::unique_ptr tree_; +}; + + +#endif // GEOBUF_DATASOURCE_HPP diff --git a/plugins/input/geobuf/geobuf_featureset.cpp b/plugins/input/geobuf/geobuf_featureset.cpp new file mode 100644 index 000000000..70ec4c298 --- /dev/null +++ b/plugins/input/geobuf/geobuf_featureset.cpp @@ -0,0 +1,55 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 +// stl +#include +#include +#include + +#include "geobuf_featureset.hpp" + +geobuf_featureset::geobuf_featureset(array_type && index_array) + : index_array_(std::move(index_array)), + index_itr_(index_array_.begin()), + index_end_(index_array_.end()), + ctx_(std::make_shared()) {} + +geobuf_featureset::~geobuf_featureset() {} + +mapnik::feature_ptr geobuf_featureset::next() +{ + if (index_itr_ != index_end_) + { +#if BOOST_VERSION >= 105600 + geobuf_datasource::item_type const& item = *index_itr_++; + std::size_t file_offset = item.second.first; + std::size_t size = item.second.second; + //std::cerr << file_offset << " (" << size << ") " << item.first << std::endl; +#else + std::size_t index = *index_itr_++; +#endif + } + return mapnik::feature_ptr(); +} diff --git a/plugins/input/geobuf/geobuf_featureset.hpp b/plugins/input/geobuf/geobuf_featureset.hpp new file mode 100644 index 000000000..1c8f9407e --- /dev/null +++ b/plugins/input/geobuf/geobuf_featureset.hpp @@ -0,0 +1,48 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + * + *****************************************************************************/ + +#ifndef GEOBUF_FEATURESET_HPP +#define GEOBUF_FEATURESET_HPP + +#include +#include "geobuf_datasource.hpp" + +#include +#include +#include + +class geobuf_featureset : public mapnik::Featureset +{ +public: + typedef std::deque array_type; + geobuf_featureset(array_type && index_array); + virtual ~geobuf_featureset(); + mapnik::feature_ptr next(); + +private: + const array_type index_array_; + array_type::const_iterator index_itr_; + array_type::const_iterator index_end_; + mapnik::context_ptr ctx_; +}; + +#endif // GEOBUF_FEATURESET_HPP diff --git a/plugins/input/geobuf/pbf.hpp b/plugins/input/geobuf/pbf.hpp new file mode 100644 index 000000000..c8deab2a7 --- /dev/null +++ b/plugins/input/geobuf/pbf.hpp @@ -0,0 +1,206 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + * + *****************************************************************************/ + +#ifndef MBGL_UTIL_PBF +#define MBGL_UTIL_PBF + +/* + * Some parts are from upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2008-2011 Google Inc. See LICENSE for details. + * Author: Josh Haberman + */ + +#include +#include + +namespace mbgl { + +struct pbf { + struct exception : std::exception { const char *what() const noexcept { return "pbf exception"; } }; + struct unterminated_varint_exception : exception { const char *what() const noexcept { return "pbf unterminated varint exception"; } }; + struct varint_too_long_exception : exception { const char *what() const noexcept { return "pbf varint too long exception"; } }; + struct unknown_field_type_exception : exception { const char *what() const noexcept { return "pbf unknown field type exception"; } }; + struct end_of_buffer_exception : exception { const char *what() const noexcept { return "pbf end of buffer exception"; } }; + + inline pbf(const unsigned char *data, size_t length); + inline pbf(); + + inline operator bool() const; + + inline bool next(); + inline bool next(uint32_t tag); + template inline T varint(); + template inline T svarint(); + + template inline T fixed(); + inline float float32(); + inline double float64(); + + inline std::string string(); + inline bool boolean(); + + inline pbf message(); + + inline void skip(); + inline void skipValue(uint32_t val); + inline void skipBytes(uint32_t bytes); + + const uint8_t *data = nullptr; + const uint8_t *end = nullptr; + uint32_t value = 0; + uint32_t tag = 0; +}; + +pbf::pbf(const unsigned char *data_, size_t length) + : data(data_), + end(data_ + length), + value(0), + tag(0) { +} + +pbf::pbf() + : data(nullptr), + end(nullptr), + value(0), + tag(0) { +} + + +pbf::operator bool() const { + return data < end; +} + +bool pbf::next() { + if (data < end) { + value = static_cast(varint()); + tag = value >> 3; + return true; + } + return false; +} + +bool pbf::next(uint32_t requested_tag) { + while (next()) { + if (tag == requested_tag) { + return true; + } else { + skip(); + } + } + return false; +} + +template +T pbf::varint() { + uint8_t byte = 0x80; + T result = 0; + int bitpos; + for (bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) { + if (data >= end) { + throw unterminated_varint_exception(); + } + result |= ((T)(byte = *data) & 0x7F) << bitpos; + + data++; + } + if (bitpos == 70 && (byte & 0x80)) { + throw varint_too_long_exception(); + } + + return result; +} + +template +T pbf::svarint() { + T n = varint(); + return (n >> 1) ^ -(T)(n & 1); +} + +template +T pbf::fixed() { + skipBytes(bytes); + T result; + memcpy(&result, data - bytes, bytes); + return result; +} + +float pbf::float32() { + return fixed(); +} + +double pbf::float64() { + return fixed(); +} + +std::string pbf::string() { + uint32_t bytes = static_cast(varint()); + const char *string_data = reinterpret_cast(data); + skipBytes(bytes); + return std::string(string_data, bytes); +} + +bool pbf::boolean() { + skipBytes(1); + return *(bool *)(data - 1); +} + +pbf pbf::message() { + uint32_t bytes = static_cast(varint()); + const uint8_t *pos = data; + skipBytes(bytes); + return pbf(pos, bytes); +} + +void pbf::skip() { + skipValue(value); +} + +void pbf::skipValue(uint32_t val) { + switch (val & 0x7) { + case 0: // varint + varint(); + break; + case 1: // 64 bit + skipBytes(8); + break; + case 2: // string/message + skipBytes(static_cast(varint())); + break; + case 5: // 32 bit + skipBytes(4); + break; + default: + throw unknown_field_type_exception(); + } +} + +void pbf::skipBytes(uint32_t bytes) { + if (data + bytes > end) { + throw end_of_buffer_exception(); + } + data += bytes; +} + +} // end namespace mbgl + +#endif diff --git a/src/save_map.cpp b/src/save_map.cpp index 31fe20718..620f4ab13 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -46,6 +46,7 @@ #include #include #include +#include // boost #pragma GCC diagnostic push